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 description prop support to <Option> component #285

Merged
merged 2 commits into from
Dec 11, 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Added

- Add `description` prop support to `<Option>` component ([#284](https://github.com/yhatt/jsx-slack/issues/284), [#285](https://github.com/yhatt/jsx-slack/pull/285))

## v5.2.1 - 2022-11-23

### Fixed
Expand Down
10 changes: 8 additions & 2 deletions demo/js/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,14 @@ const schema = {
},
children: ['Option', 'Optgroup', 'option', 'optgroup'],
},
Option: { attrs: { value: null, selected: [] }, children: [] },
option: { attrs: { value: null, selected: [] }, children: [] },
Option: {
attrs: { value: null, selected: [], description: null },
children: [],
},
option: {
attrs: { value: null, selected: [], description: null },
children: [],
},
Optgroup: { attrs: { label: null }, children: ['Option', 'option'] },
optgroup: { attrs: { label: null }, children: ['Option', 'option'] },

Expand Down
3 changes: 2 additions & 1 deletion docs/block-elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ Define an item for `<Select>`. `<option>` intrinsic HTML element works as well.

- `value` (optional): A string value to send to Slack App when choose item. Use its content string as value if omitted.
- `selected` (optional): A boolean value to indicate initially selected option(s). _It will work only when the parent `<Select>` did not define `value` prop._
- `description` (optional): A string value for the secondary description label of the item. The description appears next to the item label in small gray text. It must up to 75 characters.

### <a name="user-content-optgroup" id="optgroup"></a> `<Optgroup>`: Group of menu items

Expand Down Expand Up @@ -942,7 +943,7 @@ It has an interface similar to `<input>` HTML element and `<input>` intrinsic HT

#### <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.
- `maxLength` (optional): The maximum number of characters allowed for the input element. It must up to 3000 characters.
- `minLength` (optional): The minimum number of characters allowed for the input element.

#### <a name="user-content-input-number-props" id="input-number-props"></a> Props for `<Input type="number">`
Expand Down
17 changes: 15 additions & 2 deletions src/block-kit/composition/Option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,20 @@ export const optionSelectedSymbol = Symbol('jsx-slack-option-selected')
export interface OptionComposition {
text: PlainTextElement
value: string
description?: PlainTextElement
readonly [optionSelectedSymbol]?: boolean
}

export interface OptionProps {
children: JSXSlack.ChildElements

/**
* A string for the secondary description label of the option item.
*
* The description appears next to the item label in small gray text.
*/
description?: string

/**
* A boolean value to indicate an initially selected option.
*
Expand All @@ -40,9 +48,14 @@ export interface OptionProps {
*/
export const Option = createComponent<OptionProps, OptionComposition>(
'Option',
({ children, selected, value }) => {
({ children, description, selected, value }) => {
const text = plainText(children)
const opt: OptionComposition = { text, value: value || text.text }
const opt: OptionComposition = {
text,
value: value || text.text,
description:
description !== undefined ? plainText(description) : undefined,
}

if (selected !== undefined)
Object.defineProperty(opt, optionSelectedSymbol, { value: selected })
Expand Down
38 changes: 37 additions & 1 deletion test/block-kit/block-elements/interactive-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,43 @@ describe('Interactive components', () => {
</Select>
))

it('coercers maxSelectedItems to integer when set with mismatched type', () => {
it('allows including options with description text', () => {
const select = JSXSlack(
<Select>
<Option description="1st">a</Option>
<Option description="2nd" selected>
b
</Option>
<Option description="3rd">c</Option>
</Select>
)

expect(select.options).toStrictEqual([
{
text: { type: 'plain_text', text: 'a', emoji: true },
value: 'a',
description: { type: 'plain_text', text: '1st', emoji: true },
},
{
text: { type: 'plain_text', text: 'b', emoji: true },
value: 'b',
description: { type: 'plain_text', text: '2nd', emoji: true },
},
{
text: { type: 'plain_text', text: 'c', emoji: true },
value: 'c',
description: { type: 'plain_text', text: '3rd', emoji: true },
},
])

expect(select.initial_option).toStrictEqual({
text: { type: 'plain_text', text: 'b', emoji: true },
value: 'b',
description: { type: 'plain_text', text: '2nd', emoji: true },
})
})

it('coerces maxSelectedItems to integer when set with mismatched type', () => {
const stringNum: any = '3'
const invalidNum: any = 'invalid'

Expand Down
26 changes: 22 additions & 4 deletions test/block-kit/builtin-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,11 @@ describe('Built-in components', () => {
{
text: { type: 'plain_text', text: 'C', emoji: true },
value: 'c',
description: {
type: 'plain_text',
text: 'description',
emoji: true,
},
},
],
}
Expand All @@ -327,7 +332,9 @@ describe('Built-in components', () => {
<SelectFragment>
<Option value="a">A</Option>
<Option value="b">B</Option>
<Option value="c">C</Option>
<Option value="c" description="description">
C
</Option>
</SelectFragment>
)
).toStrictEqual(expectedOptions)
Expand All @@ -337,7 +344,9 @@ describe('Built-in components', () => {
<SelectFragment>
<option value="a">A</option>
<option value="b">B</option>
<option value="c">C</option>
<option value="c" description="description">
C
</option>
</SelectFragment>
)
).toStrictEqual(expectedOptions)
Expand Down Expand Up @@ -367,6 +376,11 @@ describe('Built-in components', () => {
{
text: { type: 'plain_text', text: 'four', emoji: true },
value: '4',
description: {
type: 'plain_text',
text: ':smile:',
emoji: true,
},
},
],
},
Expand All @@ -382,7 +396,9 @@ describe('Built-in components', () => {
</Optgroup>
<Optgroup label="B">
<Option value="3">three</Option>
<Option value="4">four</Option>
<Option value="4" description=":smile:">
four
</Option>
</Optgroup>
</SelectFragment>
)
Expand All @@ -397,7 +413,9 @@ describe('Built-in components', () => {
</optgroup>
<optgroup label="B">
<option value="3">three</option>
<option value="4">four</option>
<option value="4" description=":smile:">
four
</option>
</optgroup>
</SelectFragment>
)
Expand Down