Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add <Input> type variants url, email, and number #279

Merged
merged 6 commits into from
Oct 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Added

- [`<DateTimePicker>` interactive component](https://github.com/yhatt/jsx-slack/blob/main/docs/block-elements.md#user-content-date-time-picker) ([#276](https://github.com/yhatt/jsx-slack/issues/276), [#278](https://github.com/yhatt/jsx-slack/pull/278))
- New `type` variants for [`<Input>`](https://github.com/yhatt/jsx-slack/blob/main/docs/block-elements.md#user-content-input): `url`, `email`, and `number` ([#277](https://github.com/yhatt/jsx-slack/issues/277), [#279](https://github.com/yhatt/jsx-slack/pull/279))

## v5.1.0 - 2022-07-16

Expand Down
14 changes: 12 additions & 2 deletions demo/js/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,18 @@ const schema = {
...inputComponentAttrs,
name: null,
actionId: null,
type: ['text', 'hidden', 'submit'],
type: ['text', 'url', 'email', 'number', 'hidden', 'submit'],
placeholder: null,
value: null,
maxLength: null,
minLength: null,
autoFocus: [],
dispatchAction: ['onCharacterEntered', 'onEnterPressed'],

// <Input type="number" />
decimal: [],
min: null,
max: null,
},
children: [
'Select',
Expand All @@ -230,13 +235,18 @@ const schema = {
attrs: {
...inputIntrinsicAttrs,
name: null,
type: ['text', 'hidden', 'submit'],
type: ['text', 'url', 'email', 'number', 'hidden', 'submit'],
placeholder: null,
value: null,
maxLength: null,
minLength: null,
autofocus: [],
dispatchAction: ['onCharacterEntered', 'onEnterPressed'],

// <input type="number" />
decimal: [],
min: null,
max: null,
},
children: [
'Select',
Expand Down
26 changes: 19 additions & 7 deletions docs/block-elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -908,36 +908,48 @@ The list of input components is following:
- [`<CheckboxGroup>`](#checkbox-group)
- [`<RadioButtonGroup>`](#radio-button-group)

### <a name="user-content-input" id="input"></a> [`<Input>`: Plain-text input element](https://api.slack.com/reference/block-kit/block-elements#input)
### <a name="user-content-input" id="input"></a> [`<Input>`: Text input element](https://api.slack.com/reference/block-kit/block-elements#input)

`<Input>` component is for placing a single-line input form within supported container. It can place as children of the container component directly.

It has an interface similar to `<input>` HTML element and `<input>` intrinsic HTML element also works as well, but must be defined `label` prop as mentioned above.

```jsx
<Modal title="My App">
<Input label="Title" name="title" maxLength={80} required />
<Input label="Title" type="text" name="title" maxLength={80} required />
<Input label="URL" type="url" name="url" placeholder="https://..." />
<Input label="Email" type="email" name="email" required />
<Input label="Number" type="number" name="num" required min={1} max={100} />
</Modal>
```

[<img src="./preview-btn.svg" width="240" />](https://jsx-slack.netlify.app/#bkb:jsx:eJyz8c1PScxRKMksyUm1VfKtVHAsKFCy41JQsPHMKygtUchJTErNsVUKAckrKeQl5gJVlUA4uYkVPql56SUZtkoWBkoKRamFpZlFqSkK-nZcNvpgY-0AosweLg==)
[<img src="./preview-btn.svg" width="240" />](https://jsx-slack.netlify.app/#bkb:jsx:eJx9kMEKgzAMhu97itAHUHcbwwo77DDQHcb2AHWGKbS16yIo4ruvWguDjZ2Snz__R5K0aCshgRqSyFkxwMEYlm0A0pM2HYEUJUrOrrPPgAbjpgh7YqCFmntvKNHnqB9U83GXTGDx2TUWK4i_UbdLHkCdlYGztEaKO9atrNByVhOZ1z6OoyhivzhHJRoZSOiFZ63i3xLnTpVoQ1qvysed-girRvNxO80Xupq44xwujZe3ZW-e62eJ)

#### <a name="user-content-input-props" id="input-props"></a> Props

- `label` (**required**): The label string for the element.
- `id` / `blockId` (optional): A string of unique identifier for [`<Input>` layout block](layout-blocks.md#user-content-input).
- `name` / `actionId` (optional): A string of unique identifier for the action.
- `type` (optional): `text` by default.
- `type` (optional): Choose the type of input element from `text`, `url`, `email`, and `number`. `text` by default.
- `title`/ `hint` (optional): Specify a helpful text appears under the element.
- `placeholder` (optional): Specify a text string appears within the content of input is empty. (150 characters maximum)
- `required` (optional): A boolean prop to specify whether any value must be filled when user confirms modal.
- `dispatchAction` (optional): By setting `true`, the input element will dispatch [`block_actions` payload](https://api.slack.com/reference/interaction-payloads/block-actions) when used this. By defining interaction type(s) as space-separated string or array, [you can determine when `<Input>` will return the payload.](https://api.slack.com/reference/block-kit/composition-objects#dispatch_action_config)
- `onEnterPressed`: Payload is dispatched when hitting Enter key while focusing to the input component.
- `onCharacterEntered`: Payload is dispatched when changing input characters.
- `value` (optional): An initial value for plain-text input.
- `value` (optional): An initial value for the input. It should be a valid string for the input type.
- `autoFocus` (optional): Set whether the element will be set the focus automatically within the modal/home container.

#### <a name="user-content-input-text-props" id="input-text-props"></a> Props for `<Input type="text">`

- `maxLength` (optional): The maximum number of characters allowed for the input element. It must up to 3000 character.
- `minLength` (optional): The minimum number of characters allowed for the input element.
- `autoFocus` (optional): Set whether the element will be set the focus automatically within the modal/home container.

#### <a name="user-content-input-number-props" id="input-number-props"></a> Props for `<Input type="number">`

- `decimal` (optional): Set whether the number input element accepts decimal fractions. `false` by default (only accepts integer).
- `max` (optional): The maximum value to accept for the number input.
- `min` (optional): The minimum value to accept for the number input.

### <a name="user-content-input-hidden" id="input-hidden"></a> `<Input type="hidden">`: Store hidden values to the parent `<Modal>` and `<Home>`

Expand Down Expand Up @@ -1053,7 +1065,7 @@ The transformer takes an argument: JSON object of hidden values or `undefined` w

#### Props

It's exactly same as [`<Input>` component](#input-props), except `type` prop.
It accepts exactly same props as for [`<Input type="text">` component](#input-props).

---

Expand Down
2 changes: 1 addition & 1 deletion docs/jsx-components-for-block-kit.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@

### **[Input components](block-elements.md#user-content-input-components)**

- [**`<Input>`**: Plain-text input element](block-elements.md#user-content-input)
- [**`<Input>`**: Text input element](block-elements.md#user-content-input)
- [**`<Input type="hidden">`**: Store hidden values to `<Modal>` and `<Home>`](block-elements.md#user-content-input-hidden)
- [**`<Input type="submit">`**: Set submit button text of modal](block-elements.md#user-content-input-submit)
- [**`<Textarea>`**: Plain-text input element with multiline](block-elements.md#user-content-textarea)
Expand Down
5 changes: 2 additions & 3 deletions src/block-kit/composition/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ export interface DispatchActionConfigComposition {

export interface InputDispatchActionProps {
/**
* @doc-plain-text-input
* @doc-input-dispatch-action
* If defined interaction type(s) as space-separated string or array, you can
* determine when the plain-text input component will return the payload, as
* same as
* determine when the text input component will return the payload, as same as
* [defining `dispatch_action_config` in Slack API](https://api.slack.com/reference/block-kit/composition-objects#dispatch_action_config).
*
* - `onEnterPressed`: Payload is dispatched when hitting Enter key while
Expand Down
41 changes: 41 additions & 0 deletions src/block-kit/elements/EmailTextInput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
PlainTextInput as SlackPlainTextInput,
DispatchActionConfig,
} from '@slack/types'
import { createComponent } from '../../jsx-internals'
import { plainText } from '../composition/utils'

// TODO: Use official type when it was available in `@slack/types`
interface SlackEmailTextInput
extends Omit<
SlackPlainTextInput,
'max_length' | 'min_length' | 'multiline' | 'type'
> {
type: 'email_text_input'
}

export interface EmailTextInputProps {
children?: never
actionId?: string
initialValue?: string
placeholder?: string
dispatchActionConfig?: DispatchActionConfig
focusOnLoad?: boolean
}

// NOTE: <EmailTextInput> is not public component
export const EmailTextInput = createComponent<
EmailTextInputProps,
SlackEmailTextInput
>('EmailTextInput', (props) => ({
type: 'email_text_input',
action_id: props.actionId,
placeholder:
// Placeholder for input HTML element should disable emoji conversion
props.placeholder
? plainText(props.placeholder, { emoji: false })
: undefined,
initial_value: props.initialValue,
dispatch_action_config: props.dispatchActionConfig,
focus_on_load: props.focusOnLoad,
}))
50 changes: 50 additions & 0 deletions src/block-kit/elements/NumberTextInput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
PlainTextInput as SlackPlainTextInput,
DispatchActionConfig,
} from '@slack/types'
import { createComponent } from '../../jsx-internals'
import { plainText } from '../composition/utils'

// TODO: Use official type when it was available in `@slack/types`
interface SlackNumberTextInput
extends Omit<
SlackPlainTextInput,
'max_length' | 'min_length' | 'multiline' | 'type'
> {
type: 'number_input'
is_decimal_allowed: boolean
max_value?: string
min_value?: string
}

export interface NumberTextInputProps {
children?: never
actionId?: string
initialValue?: string
placeholder?: string
isDecimalAllowed?: boolean
maxValue?: string
minValue?: string
dispatchActionConfig?: DispatchActionConfig
focusOnLoad?: boolean
}

// NOTE: <NumberTextInput> is not public component
export const NumberTextInput = createComponent<
NumberTextInputProps,
SlackNumberTextInput
>('NumberTextInput', (props) => ({
type: 'number_input',
action_id: props.actionId,
placeholder:
// Placeholder for input HTML element should disable emoji conversion
props.placeholder
? plainText(props.placeholder, { emoji: false })
: undefined,
is_decimal_allowed: props.isDecimalAllowed ?? false,
min_value: props.minValue,
max_value: props.maxValue,
initial_value: props.initialValue,
dispatch_action_config: props.dispatchActionConfig,
focus_on_load: props.focusOnLoad,
}))
41 changes: 41 additions & 0 deletions src/block-kit/elements/UrlTextInput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
PlainTextInput as SlackPlainTextInput,
DispatchActionConfig,
} from '@slack/types'
import { createComponent } from '../../jsx-internals'
import { plainText } from '../composition/utils'

// TODO: Use official type when it was available in `@slack/types`
interface SlackUrlTextInput
extends Omit<
SlackPlainTextInput,
'max_length' | 'min_length' | 'multiline' | 'type'
> {
type: 'url_text_input'
}

export interface UrlTextInputProps {
children?: never
actionId?: string
initialValue?: string
placeholder?: string
dispatchActionConfig?: DispatchActionConfig
focusOnLoad?: boolean
}

// NOTE: <UrlTextInput> is not public component
export const UrlTextInput = createComponent<
UrlTextInputProps,
SlackUrlTextInput
>('UrlTextInput', (props) => ({
type: 'url_text_input',
action_id: props.actionId,
placeholder:
// Placeholder for input HTML element should disable emoji conversion
props.placeholder
? plainText(props.placeholder, { emoji: false })
: undefined,
initial_value: props.initialValue,
dispatch_action_config: props.dispatchActionConfig,
focus_on_load: props.focusOnLoad,
}))
Loading