From 8bfd1cdb8824dbd95930ffa50286dd53110b46d0 Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Thu, 21 Jul 2022 17:33:50 +0530 Subject: [PATCH 01/16] Add renderSuggestion prop to SuggestionsList component --- .../src/form-token-field/suggestions-list.tsx | 33 ++++++++++++------- .../components/src/form-token-field/types.ts | 7 +++- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/packages/components/src/form-token-field/suggestions-list.tsx b/packages/components/src/form-token-field/suggestions-list.tsx index 3828feef5dfab2..959367da8021b6 100644 --- a/packages/components/src/form-token-field/suggestions-list.tsx +++ b/packages/components/src/form-token-field/suggestions-list.tsx @@ -4,7 +4,7 @@ import { map } from 'lodash'; import scrollView from 'dom-scroll-into-view'; import classnames from 'classnames'; -import type { MouseEventHandler } from 'react'; +import type { MouseEventHandler, ReactNode } from 'react'; /** * WordPress dependencies @@ -31,6 +31,7 @@ export function SuggestionsList< T extends string | { value: string } >( { suggestions = [], displayTransform, instanceId, + renderSuggestion, }: SuggestionsListProps< T > ) { const [ scrollingIntoView, setScrollingIntoView ] = useState( false ); @@ -122,6 +123,24 @@ export function SuggestionsList< T extends string | { value: string } >( { } ); + let output: ReactNode; + + if ( typeof renderSuggestion === 'function' ) { + output = renderSuggestion( suggestion ); + } else if ( matchText ) { + output = ( + <span aria-label={ displayTransform( suggestion ) }> + { matchText.suggestionBeforeMatch } + <strong className="components-form-token-field__suggestion-match"> + { matchText.suggestionMatch } + </strong> + { matchText.suggestionAfterMatch } + </span> + ); + } else { + output = displayTransform( suggestion ); + } + /* eslint-disable jsx-a11y/click-events-have-key-events */ return ( <li @@ -139,17 +158,7 @@ export function SuggestionsList< T extends string | { value: string } >( { onMouseEnter={ handleHover( suggestion ) } aria-selected={ index === selectedIndex } > - { matchText ? ( - <span aria-label={ displayTransform( suggestion ) }> - { matchText.suggestionBeforeMatch } - <strong className="components-form-token-field__suggestion-match"> - { matchText.suggestionMatch } - </strong> - { matchText.suggestionAfterMatch } - </span> - ) : ( - displayTransform( suggestion ) - ) } + { output } </li> ); /* eslint-enable jsx-a11y/click-events-have-key-events */ diff --git a/packages/components/src/form-token-field/types.ts b/packages/components/src/form-token-field/types.ts index f7e0a11e0e4140..996ba9fc31743a 100644 --- a/packages/components/src/form-token-field/types.ts +++ b/packages/components/src/form-token-field/types.ts @@ -1,7 +1,11 @@ /** * External dependencies */ -import type { ComponentPropsWithRef, MouseEventHandler } from 'react'; +import type { + ComponentPropsWithRef, + MouseEventHandler, + ReactNode, +} from 'react'; type Messages = { /** @@ -165,6 +169,7 @@ export interface SuggestionsListProps< T = string | { value: string } > { suggestions: T[]; displayTransform: ( value: T ) => string; instanceId: string | number; + renderSuggestion?: ( suggestion: T ) => ReactNode; } export interface TokenProps extends TokenItem { From 3f236c0b4ccd082102f4c613dc320a838629c581 Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Thu, 21 Jul 2022 17:34:50 +0530 Subject: [PATCH 02/16] Add renderOption prop to ComboboxControl component --- packages/components/src/combobox-control/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/components/src/combobox-control/index.js b/packages/components/src/combobox-control/index.js index 2440296865c746..4d35c121f47d15 100644 --- a/packages/components/src/combobox-control/index.js +++ b/packages/components/src/combobox-control/index.js @@ -58,6 +58,7 @@ function ComboboxControl( { messages = { selected: __( 'Item selected.' ), }, + renderOption, } ) { const currentOption = options.find( ( option ) => option.value === value ); const currentLabel = currentOption?.label ?? ''; @@ -279,6 +280,7 @@ function ComboboxControl( { onHover={ setSelectedSuggestion } onSelect={ onSuggestionSelected } scrollIntoView + renderSuggestion={ renderOption } /> ) } </div> From 97195ecb5934dbe126835f2f516a41012b6da3fd Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Thu, 21 Jul 2022 17:35:39 +0530 Subject: [PATCH 03/16] Add story to ComboboxControl component --- .../src/combobox-control/stories/index.js | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/packages/components/src/combobox-control/stories/index.js b/packages/components/src/combobox-control/stories/index.js index 3ba34f74dc8a95..ba4efdc687b546 100644 --- a/packages/components/src/combobox-control/stories/index.js +++ b/packages/components/src/combobox-control/stories/index.js @@ -287,3 +287,69 @@ _default.args = { __next36pxDefaultSize: false, allowReset: false, }; + +const authors = [ + { + name: 'Hermann P. Schnitzel', + age: 45, + country: 'Germany', + }, + { + name: 'Shequondolisa Bivouac', + age: 43, + country: 'France', + }, + { + name: 'Bodrum Salvador', + age: 42, + country: 'Spain', + }, + { + name: 'Parsley Montana', + age: 48, + country: 'Germany', + }, + { + name: 'Cabbage New York', + age: 44, + country: 'France', + }, + { + name: 'Jake Weary', + age: 41, + country: 'United Kingdom', + }, +]; + +const authorOptions = authors.map( ( { name, ...details } ) => ( { + value: name, + label: name, + ...details, +} ) ); + +export const WithRenderOption = ( args ) => { + const [ value, setValue ] = useState( '' ); + + return ( + <> + <ComboboxControl + { ...args } + value={ value } + onChange={ setValue } + label="Select an author" + options={ authorOptions } + renderOption={ ( { label, age, country } ) => ( + <div> + <div style={ { marginBottom: '0.2rem' } }> + { label } + </div> + <small> + Age: { age }, Country: { country } + </small> + </div> + ) } + /> + <p>Selected author: { value }</p> + </> + ); +}; From c1d08eb6d41343f6965bf40eadb582da25496646 Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Mon, 25 Jul 2022 11:31:26 +0530 Subject: [PATCH 04/16] Improve renderSuggestion and renderOption signature --- .../components/src/combobox-control/index.js | 4 +++- .../src/combobox-control/stories/index.js | 21 +++++++++++-------- .../src/form-token-field/suggestions-list.tsx | 2 +- .../components/src/form-token-field/types.ts | 2 +- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/packages/components/src/combobox-control/index.js b/packages/components/src/combobox-control/index.js index 4d35c121f47d15..bb2546f6e658bb 100644 --- a/packages/components/src/combobox-control/index.js +++ b/packages/components/src/combobox-control/index.js @@ -280,7 +280,9 @@ function ComboboxControl( { onHover={ setSelectedSuggestion } onSelect={ onSuggestionSelected } scrollIntoView - renderSuggestion={ renderOption } + renderSuggestion={ ( { suggestion } ) => + renderOption( { option: suggestion } ) + } /> ) } </div> diff --git a/packages/components/src/combobox-control/stories/index.js b/packages/components/src/combobox-control/stories/index.js index ba4efdc687b546..583cadf9783467 100644 --- a/packages/components/src/combobox-control/stories/index.js +++ b/packages/components/src/combobox-control/stories/index.js @@ -338,16 +338,19 @@ export const WithRenderOption = ( args ) => { onChange={ setValue } label="Select an author" options={ authorOptions } - renderOption={ ( { label, age, country } ) => ( - <div> - <div style={ { marginBottom: '0.2rem' } }> - { label } + renderOption={ ( { option } ) => { + const { label, age, country } = option; + return ( + <div> + <div style={ { marginBottom: '0.2rem' } }> + { label } + </div> + <small> + Age: { age }, Country: { country } + </small> </div> - <small> - Age: { age }, Country: { country } - </small> - </div> - ) } + ); + } } /> <p>Selected author: { value }</p> </> diff --git a/packages/components/src/form-token-field/suggestions-list.tsx b/packages/components/src/form-token-field/suggestions-list.tsx index 959367da8021b6..34f5203d63595b 100644 --- a/packages/components/src/form-token-field/suggestions-list.tsx +++ b/packages/components/src/form-token-field/suggestions-list.tsx @@ -126,7 +126,7 @@ export function SuggestionsList< T extends string | { value: string } >( { let output: ReactNode; if ( typeof renderSuggestion === 'function' ) { - output = renderSuggestion( suggestion ); + output = renderSuggestion( { suggestion } ); } else if ( matchText ) { output = ( <span aria-label={ displayTransform( suggestion ) }> diff --git a/packages/components/src/form-token-field/types.ts b/packages/components/src/form-token-field/types.ts index 996ba9fc31743a..862927c30c5cc5 100644 --- a/packages/components/src/form-token-field/types.ts +++ b/packages/components/src/form-token-field/types.ts @@ -169,7 +169,7 @@ export interface SuggestionsListProps< T = string | { value: string } > { suggestions: T[]; displayTransform: ( value: T ) => string; instanceId: string | number; - renderSuggestion?: ( suggestion: T ) => ReactNode; + renderSuggestion?: ( props: { suggestion: T } ) => ReactNode; } export interface TokenProps extends TokenItem { From 458371c4d23efb04c3742d053205615402ca85d7 Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Mon, 25 Jul 2022 11:33:58 +0530 Subject: [PATCH 05/16] Add renderSuggestion prop to FormTokenField --- packages/components/src/form-token-field/index.tsx | 2 ++ packages/components/src/form-token-field/types.ts | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/components/src/form-token-field/index.tsx b/packages/components/src/form-token-field/index.tsx index eb96daa8fd6f24..cbd9c9d120c5bd 100644 --- a/packages/components/src/form-token-field/index.tsx +++ b/packages/components/src/form-token-field/index.tsx @@ -72,6 +72,7 @@ export function FormTokenField( props: FormTokenFieldProps ) { remove: __( 'Remove item' ), __experimentalInvalid: __( 'Invalid item' ), }, + renderSuggestion, __experimentalExpandOnFocus = false, __experimentalValidateInput = () => true, __experimentalShowHowTo = true, @@ -692,6 +693,7 @@ export function FormTokenField( props: FormTokenFieldProps ) { scrollIntoView={ selectedSuggestionScroll } onHover={ onSuggestionHovered } onSelect={ onSuggestionSelected } + renderSuggestion={ renderSuggestion } /> ) } </div> diff --git a/packages/components/src/form-token-field/types.ts b/packages/components/src/form-token-field/types.ts index 862927c30c5cc5..b2319eb5eb125b 100644 --- a/packages/components/src/form-token-field/types.ts +++ b/packages/components/src/form-token-field/types.ts @@ -158,6 +158,10 @@ export interface FormTokenFieldProps * @default false */ __next36pxDefaultSize?: boolean; + /** + * Custom renderer for the token suggestions. + */ + renderSuggestion?: ( args: { suggestion: string } ) => ReactNode; } export interface SuggestionsListProps< T = string | { value: string } > { @@ -169,7 +173,7 @@ export interface SuggestionsListProps< T = string | { value: string } > { suggestions: T[]; displayTransform: ( value: T ) => string; instanceId: string | number; - renderSuggestion?: ( props: { suggestion: T } ) => ReactNode; + renderSuggestion?: ( args: { suggestion: T } ) => ReactNode; } export interface TokenProps extends TokenItem { From cc5d7dadf33e64501dddec7e77fd4a54785f7d3c Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Mon, 25 Jul 2022 11:42:43 +0530 Subject: [PATCH 06/16] Add props to README --- packages/components/src/combobox-control/README.md | 7 +++++++ packages/components/src/form-token-field/README.md | 3 ++- packages/components/src/form-token-field/types.ts | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/components/src/combobox-control/README.md b/packages/components/src/combobox-control/README.md index e0d5a71ab14152..c4ec026271a295 100644 --- a/packages/components/src/combobox-control/README.md +++ b/packages/components/src/combobox-control/README.md @@ -116,6 +116,13 @@ The current value of the input. - Type: `mixed` - Required: Yes +#### renderOption + +Custom renderer for options in suggestion list. + +- Type: `Function` - `( args: { option: object } ) => ReactNode` +- Required: No + ## Related components - Like this component, but without a search input, the `CustomSelectControl` component. diff --git a/packages/components/src/form-token-field/README.md b/packages/components/src/form-token-field/README.md index e24f2f2ed7d8c4..8ddde047221d1c 100644 --- a/packages/components/src/form-token-field/README.md +++ b/packages/components/src/form-token-field/README.md @@ -56,6 +56,7 @@ The `value` property is handled in a manner similar to controlled form component - `removed` - The user removed an existing token. - `remove` - The user focused the button to remove the token. - `__experimentalInvalid` - The user tried to add a token that didn't pass the validation. +- `renderSuggestion` - Custom renderer for suggestions. - `__experimentalExpandOnFocus` - If true, the suggestions list will be always expanded when the input field has the focus. - `__experimentalShowHowTo` - If false, the text on how to use the select (ie: _Separate with commas or the Enter key._) will be hidden. - `__experimentalValidateInput` - If passed, all introduced values will be validated before being added as tokens. @@ -78,7 +79,7 @@ const continents = [ const MyFormTokenField = () => { const [ selectedContinents, setSelectedContinents ] = useState( [] ); - return( + return ( <FormTokenField value={ selectedContinents } suggestions={ continents } diff --git a/packages/components/src/form-token-field/types.ts b/packages/components/src/form-token-field/types.ts index b2319eb5eb125b..68301762f9db4f 100644 --- a/packages/components/src/form-token-field/types.ts +++ b/packages/components/src/form-token-field/types.ts @@ -159,7 +159,7 @@ export interface FormTokenFieldProps */ __next36pxDefaultSize?: boolean; /** - * Custom renderer for the token suggestions. + * Custom renderer for suggestions. */ renderSuggestion?: ( args: { suggestion: string } ) => ReactNode; } From 3229289cd992840e808fe24e0d9b430bcdd8f492 Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Mon, 25 Jul 2022 11:46:01 +0530 Subject: [PATCH 07/16] Update changelog --- packages/components/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 5f8a7d95afd863..91c7a1f4a407c5 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -23,6 +23,7 @@ - `BorderControl`: Render dropdown as prefix within its `UnitControl` ([#42212](https://github.com/WordPress/gutenberg/pull/42212/)) - `UnitControl`: Update prop types to allow ReactNode as prefix ([#42212](https://github.com/WordPress/gutenberg/pull/42212/)) - `ToolsPanel`: Updated README with panel layout information and more expansive usage example ([#42615](https://github.com/WordPress/gutenberg/pull/42615)). +- `ComboboxControl`, `FormTokenField`: Add custom render callback for options in suggestions list ([#42597](https://github.com/WordPress/gutenberg/pull/42597/)). ### Internal From b602ccede0ca22d5c574e3fbfe19253f44fd9a67 Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Mon, 25 Jul 2022 12:24:08 +0530 Subject: [PATCH 08/16] Fix fatal error --- packages/components/src/combobox-control/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/combobox-control/index.js b/packages/components/src/combobox-control/index.js index bb2546f6e658bb..6b7addb6304c3d 100644 --- a/packages/components/src/combobox-control/index.js +++ b/packages/components/src/combobox-control/index.js @@ -281,7 +281,7 @@ function ComboboxControl( { onSelect={ onSuggestionSelected } scrollIntoView renderSuggestion={ ( { suggestion } ) => - renderOption( { option: suggestion } ) + renderOption?.( { option: suggestion } ) } /> ) } From 901b40cbd3c67a55184be879070e8ef9318983ca Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Wed, 27 Jul 2022 10:16:35 +0530 Subject: [PATCH 09/16] Fix backward compatibility --- packages/components/src/combobox-control/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/components/src/combobox-control/index.js b/packages/components/src/combobox-control/index.js index 6b7addb6304c3d..b8ee8dd5d6d507 100644 --- a/packages/components/src/combobox-control/index.js +++ b/packages/components/src/combobox-control/index.js @@ -280,8 +280,14 @@ function ComboboxControl( { onHover={ setSelectedSuggestion } onSelect={ onSuggestionSelected } scrollIntoView - renderSuggestion={ ( { suggestion } ) => - renderOption?.( { option: suggestion } ) + renderSuggestion={ + typeof renderOption === 'function' + ? ( { suggestion } ) => { + renderOption( { + option: suggestion, + } ); + } + : null } /> ) } From 26e3ce440a3fc94c73a17ef4ea7ce2077cc8bc6a Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Wed, 27 Jul 2022 21:01:08 +0530 Subject: [PATCH 10/16] Update packages/components/src/combobox-control/index.js Co-authored-by: Renzo Canepa <rcanepag@gmail.com> --- packages/components/src/combobox-control/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/combobox-control/index.js b/packages/components/src/combobox-control/index.js index b8ee8dd5d6d507..7316f85b0d7955 100644 --- a/packages/components/src/combobox-control/index.js +++ b/packages/components/src/combobox-control/index.js @@ -283,7 +283,7 @@ function ComboboxControl( { renderSuggestion={ typeof renderOption === 'function' ? ( { suggestion } ) => { - renderOption( { + return renderOption( { option: suggestion, } ); } From b9ffdfed76bd0cd1f62a31a3b40325cae9dc5968 Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Wed, 3 Aug 2022 10:37:35 +0530 Subject: [PATCH 11/16] Add __experimental prefix to render callbacks --- packages/components/src/combobox-control/index.js | 12 +++--------- .../components/src/combobox-control/stories/index.js | 8 ++++++-- packages/components/src/form-token-field/index.tsx | 4 ++-- .../src/form-token-field/suggestions-list.tsx | 6 +++--- packages/components/src/form-token-field/types.ts | 4 ++-- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/packages/components/src/combobox-control/index.js b/packages/components/src/combobox-control/index.js index 7316f85b0d7955..f982735387aee0 100644 --- a/packages/components/src/combobox-control/index.js +++ b/packages/components/src/combobox-control/index.js @@ -58,7 +58,7 @@ function ComboboxControl( { messages = { selected: __( 'Item selected.' ), }, - renderOption, + __experimentalRenderItem, } ) { const currentOption = options.find( ( option ) => option.value === value ); const currentLabel = currentOption?.label ?? ''; @@ -280,14 +280,8 @@ function ComboboxControl( { onHover={ setSelectedSuggestion } onSelect={ onSuggestionSelected } scrollIntoView - renderSuggestion={ - typeof renderOption === 'function' - ? ( { suggestion } ) => { - return renderOption( { - option: suggestion, - } ); - } - : null + __experimentalRenderItem={ + __experimentalRenderItem } /> ) } diff --git a/packages/components/src/combobox-control/stories/index.js b/packages/components/src/combobox-control/stories/index.js index 583cadf9783467..b713456e981286 100644 --- a/packages/components/src/combobox-control/stories/index.js +++ b/packages/components/src/combobox-control/stories/index.js @@ -338,8 +338,8 @@ export const WithRenderOption = ( args ) => { onChange={ setValue } label="Select an author" options={ authorOptions } - renderOption={ ( { option } ) => { - const { label, age, country } = option; + __experimentalRenderItem={ ( { item } ) => { + const { label, age, country } = item; return ( <div> <div style={ { marginBottom: '0.2rem' } }> @@ -356,3 +356,7 @@ export const WithRenderOption = ( args ) => { </> ); }; + +WithRenderOption.args = { + allowReset: false, +}; diff --git a/packages/components/src/form-token-field/index.tsx b/packages/components/src/form-token-field/index.tsx index cbd9c9d120c5bd..2dde11ba9627be 100644 --- a/packages/components/src/form-token-field/index.tsx +++ b/packages/components/src/form-token-field/index.tsx @@ -72,7 +72,7 @@ export function FormTokenField( props: FormTokenFieldProps ) { remove: __( 'Remove item' ), __experimentalInvalid: __( 'Invalid item' ), }, - renderSuggestion, + __experimentalRenderItem, __experimentalExpandOnFocus = false, __experimentalValidateInput = () => true, __experimentalShowHowTo = true, @@ -693,7 +693,7 @@ export function FormTokenField( props: FormTokenFieldProps ) { scrollIntoView={ selectedSuggestionScroll } onHover={ onSuggestionHovered } onSelect={ onSuggestionSelected } - renderSuggestion={ renderSuggestion } + __experimentalRenderItem={ __experimentalRenderItem } /> ) } </div> diff --git a/packages/components/src/form-token-field/suggestions-list.tsx b/packages/components/src/form-token-field/suggestions-list.tsx index 34f5203d63595b..cb3f8299c935f7 100644 --- a/packages/components/src/form-token-field/suggestions-list.tsx +++ b/packages/components/src/form-token-field/suggestions-list.tsx @@ -31,7 +31,7 @@ export function SuggestionsList< T extends string | { value: string } >( { suggestions = [], displayTransform, instanceId, - renderSuggestion, + __experimentalRenderItem, }: SuggestionsListProps< T > ) { const [ scrollingIntoView, setScrollingIntoView ] = useState( false ); @@ -125,8 +125,8 @@ export function SuggestionsList< T extends string | { value: string } >( { let output: ReactNode; - if ( typeof renderSuggestion === 'function' ) { - output = renderSuggestion( { suggestion } ); + if ( typeof __experimentalRenderItem === 'function' ) { + output = __experimentalRenderItem( { item: suggestion } ); } else if ( matchText ) { output = ( <span aria-label={ displayTransform( suggestion ) }> diff --git a/packages/components/src/form-token-field/types.ts b/packages/components/src/form-token-field/types.ts index 68301762f9db4f..269d7670feaec0 100644 --- a/packages/components/src/form-token-field/types.ts +++ b/packages/components/src/form-token-field/types.ts @@ -161,7 +161,7 @@ export interface FormTokenFieldProps /** * Custom renderer for suggestions. */ - renderSuggestion?: ( args: { suggestion: string } ) => ReactNode; + __experimentalRenderItem?: ( args: { item: string } ) => ReactNode; } export interface SuggestionsListProps< T = string | { value: string } > { @@ -173,7 +173,7 @@ export interface SuggestionsListProps< T = string | { value: string } > { suggestions: T[]; displayTransform: ( value: T ) => string; instanceId: string | number; - renderSuggestion?: ( args: { suggestion: T } ) => ReactNode; + __experimentalRenderItem?: ( args: { item: T } ) => ReactNode; } export interface TokenProps extends TokenItem { From f60149135814e94c13dcfe609cc3c25fba42eb2b Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Wed, 3 Aug 2022 17:38:51 +0530 Subject: [PATCH 12/16] Update packages/components/src/form-token-field/types.ts Co-authored-by: Lena Morita <lena@jaguchi.com> --- packages/components/src/form-token-field/types.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/components/src/form-token-field/types.ts b/packages/components/src/form-token-field/types.ts index 269d7670feaec0..a979aab45dd2c9 100644 --- a/packages/components/src/form-token-field/types.ts +++ b/packages/components/src/form-token-field/types.ts @@ -164,7 +164,9 @@ export interface FormTokenFieldProps __experimentalRenderItem?: ( args: { item: string } ) => ReactNode; } -export interface SuggestionsListProps< T = string | { value: string } > { +export interface SuggestionsListProps< + T = string | ( Record< string, unknown > & { value: string } ) +> { selectedIndex: number; scrollIntoView: boolean; match: T; From 444c735a70ae67d77a7adb8cbe6b66d2ccfe9740 Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Wed, 3 Aug 2022 17:48:24 +0530 Subject: [PATCH 13/16] Improve and clean up story --- .../src/combobox-control/stories/index.js | 95 +++++++------------ 1 file changed, 33 insertions(+), 62 deletions(-) diff --git a/packages/components/src/combobox-control/stories/index.js b/packages/components/src/combobox-control/stories/index.js index b713456e981286..3c6974e954afa6 100644 --- a/packages/components/src/combobox-control/stories/index.js +++ b/packages/components/src/combobox-control/stories/index.js @@ -266,7 +266,7 @@ const mapCountryOption = ( country ) => ( { const countryOptions = countries.map( mapCountryOption ); -function CountryCodeComboboxControl( args ) { +function Template( args ) { const [ value, setValue ] = useState( null ); return ( @@ -275,88 +275,59 @@ function CountryCodeComboboxControl( args ) { { ...args } value={ value } onChange={ setValue } - label="Select a country" - options={ countryOptions } /> <p>Value: { value }</p> </> ); } -export const _default = CountryCodeComboboxControl.bind( {} ); -_default.args = { +export const Default = Template.bind( {} ); +Default.args = { __next36pxDefaultSize: false, allowReset: false, + label: 'Select a country', + options: countryOptions, }; -const authors = [ +const authorOptions = [ { - name: 'Hermann P. Schnitzel', - age: 45, - country: 'Germany', - }, - { - name: 'Shequondolisa Bivouac', - age: 43, - country: 'France', - }, - { - name: 'Bodrum Salvador', - age: 42, - country: 'Spain', - }, - { - name: 'Parsley Montana', + value: 'parsley', + label: 'Parsley Montana', age: 48, country: 'Germany', }, { - name: 'Cabbage New York', + value: 'cabbage', + label: 'Cabbage New York', age: 44, country: 'France', }, { - name: 'Jake Weary', + value: 'jake', + label: 'Jake Weary', age: 41, country: 'United Kingdom', }, ]; -const authorOptions = authors.map( ( { name, ...details } ) => ( { - value: name, - label: name, - ...details, -} ) ); - -export const WithRenderOption = ( args ) => { - const [ value, setValue ] = useState( '' ); - - return ( - <> - <ComboboxControl - { ...args } - value={ value } - onChange={ setValue } - label="Select an author" - options={ authorOptions } - __experimentalRenderItem={ ( { item } ) => { - const { label, age, country } = item; - return ( - <div> - <div style={ { marginBottom: '0.2rem' } }> - { label } - </div> - <small> - Age: { age }, Country: { country } - </small> - </div> - ); - } } - /> - <p>Selected author: { value }</p> - </> - ); -}; - -WithRenderOption.args = { - allowReset: false, +/** + * The rendered output of each suggestion can be customized by passing a + * render function to the `__experimentalRenderItem` prop. (This is still an experimental feature + * and is subject to change.) + */ +export const WithCustomRenderItem = Template.bind( {} ); +WithCustomRenderItem.args = { + ...Default.args, + label: 'Select an author', + options: authorOptions, + __experimentalRenderItem: ( { item } ) => { + const { label, age, country } = item; + return ( + <div> + <div style={ { marginBottom: '0.2rem' } }>{ label }</div> + <small> + Age: { age }, Country: { country } + </small> + </div> + ); + }, }; From 763dafff4855922d0382dd06ff6f0b6c5c53cd4a Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Wed, 3 Aug 2022 17:48:43 +0530 Subject: [PATCH 14/16] Update docs --- packages/components/src/combobox-control/README.md | 2 +- packages/components/src/form-token-field/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/combobox-control/README.md b/packages/components/src/combobox-control/README.md index c4ec026271a295..68dc4012e407a8 100644 --- a/packages/components/src/combobox-control/README.md +++ b/packages/components/src/combobox-control/README.md @@ -116,7 +116,7 @@ The current value of the input. - Type: `mixed` - Required: Yes -#### renderOption +#### \_\_experimentalRenderItem Custom renderer for options in suggestion list. diff --git a/packages/components/src/form-token-field/README.md b/packages/components/src/form-token-field/README.md index 8ddde047221d1c..9c6ec50e3d14c6 100644 --- a/packages/components/src/form-token-field/README.md +++ b/packages/components/src/form-token-field/README.md @@ -56,7 +56,7 @@ The `value` property is handled in a manner similar to controlled form component - `removed` - The user removed an existing token. - `remove` - The user focused the button to remove the token. - `__experimentalInvalid` - The user tried to add a token that didn't pass the validation. -- `renderSuggestion` - Custom renderer for suggestions. +- `__experimentalRenderItem` - Custom renderer for suggestions. - `__experimentalExpandOnFocus` - If true, the suggestions list will be always expanded when the input field has the focus. - `__experimentalShowHowTo` - If false, the text on how to use the select (ie: _Separate with commas or the Enter key._) will be hidden. - `__experimentalValidateInput` - If passed, all introduced values will be validated before being added as tokens. From 21746dccbbf1a35ba293a5f10657306a1c4a823b Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Wed, 3 Aug 2022 17:51:46 +0530 Subject: [PATCH 15/16] Update form-token-field story --- .../src/form-token-field/stories/index.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/components/src/form-token-field/stories/index.tsx b/packages/components/src/form-token-field/stories/index.tsx index 0d7fcad6564be0..54a4467a791eb5 100644 --- a/packages/components/src/form-token-field/stories/index.tsx +++ b/packages/components/src/form-token-field/stories/index.tsx @@ -101,3 +101,17 @@ Async.args = { label: 'Type a continent', suggestions: continents, }; + +/** + * The rendered output of each suggestion can be customized by passing a + * render function to the `__experimentalRenderItem` prop. (This is still an experimental feature + * and is subject to change.) + */ +export const WithCustomRenderItem: ComponentStory< typeof FormTokenField > = + DefaultTemplate.bind( {} ); +WithCustomRenderItem.args = { + ...Default.args, + __experimentalRenderItem: ( { item } ) => ( + <div>{ `${ item } — a nice place to visit` }</div> + ), +}; From 49ebc8730ae59f72a3c5cf36573cf766abc34e41 Mon Sep 17 00:00:00 2001 From: Manzoor Wani <manzoorwani.jk@gmail.com> Date: Tue, 9 Aug 2022 20:21:49 +0530 Subject: [PATCH 16/16] Improve docs --- packages/components/src/combobox-control/README.md | 6 +++--- packages/components/src/form-token-field/README.md | 2 +- packages/components/src/form-token-field/types.ts | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/components/src/combobox-control/README.md b/packages/components/src/combobox-control/README.md index 68dc4012e407a8..f6e81d2cff3513 100644 --- a/packages/components/src/combobox-control/README.md +++ b/packages/components/src/combobox-control/README.md @@ -116,11 +116,11 @@ The current value of the input. - Type: `mixed` - Required: Yes -#### \_\_experimentalRenderItem +#### __experimentalRenderItem -Custom renderer for options in suggestion list. +Custom renderer invoked for each option in the suggestion list. The render prop receives as its argument an object containing, under the `item` key, the single option's data (directly from the array of data passed to the `options` prop). -- Type: `Function` - `( args: { option: object } ) => ReactNode` +- Type: `Function` - `( args: { item: object } ) => ReactNode` - Required: No ## Related components diff --git a/packages/components/src/form-token-field/README.md b/packages/components/src/form-token-field/README.md index 9c6ec50e3d14c6..2df2ad3c501759 100644 --- a/packages/components/src/form-token-field/README.md +++ b/packages/components/src/form-token-field/README.md @@ -56,7 +56,7 @@ The `value` property is handled in a manner similar to controlled form component - `removed` - The user removed an existing token. - `remove` - The user focused the button to remove the token. - `__experimentalInvalid` - The user tried to add a token that didn't pass the validation. -- `__experimentalRenderItem` - Custom renderer for suggestions. +- `__experimentalRenderItem` - Custom renderer invoked for each option in the suggestion list. The render prop receives as its argument an object containing, under the `item` key, the single option's data (directly from the array of data passed to the `options` prop). - `__experimentalExpandOnFocus` - If true, the suggestions list will be always expanded when the input field has the focus. - `__experimentalShowHowTo` - If false, the text on how to use the select (ie: _Separate with commas or the Enter key._) will be hidden. - `__experimentalValidateInput` - If passed, all introduced values will be validated before being added as tokens. diff --git a/packages/components/src/form-token-field/types.ts b/packages/components/src/form-token-field/types.ts index a979aab45dd2c9..8a032700b411a1 100644 --- a/packages/components/src/form-token-field/types.ts +++ b/packages/components/src/form-token-field/types.ts @@ -164,6 +164,9 @@ export interface FormTokenFieldProps __experimentalRenderItem?: ( args: { item: string } ) => ReactNode; } +/** + * `T` can be either a `string` or an object which must have a `value` prop as a string. + */ export interface SuggestionsListProps< T = string | ( Record< string, unknown > & { value: string } ) > {