-
Notifications
You must be signed in to change notification settings - Fork 4.6k
DataForm: add array control
#71136
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
DataForm: add array control
#71136
Changes from all commits
645cf41
42707cd
d8fabd6
e2f4bc7
416badc
7094494
1d5ab6a
f48d7e0
a1f315f
6a61e46
3ab76c0
14a28cd
3b5aca8
20a5622
306d98c
666a2c1
9c8389a
4be7db6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| /** | ||
| * WordPress dependencies | ||
| */ | ||
| import { FormTokenField } from '@wordpress/components'; | ||
| import { useCallback, useMemo } from '@wordpress/element'; | ||
|
|
||
| /** | ||
| * Internal dependencies | ||
| */ | ||
| import type { DataFormControlProps } from '../types'; | ||
|
|
||
| export default function ArrayControl< Item >( { | ||
| data, | ||
| field, | ||
| onChange, | ||
| hideLabelFromVision, | ||
| }: DataFormControlProps< Item > ) { | ||
| const { id, label, placeholder, elements } = field; | ||
| const value = field.getValue( { item: data } ); | ||
|
|
||
| const findElementByValue = useCallback( | ||
| ( suggestionValue: string ) => { | ||
| return elements?.find( | ||
| ( suggestion ) => suggestion.value === suggestionValue | ||
| ); | ||
| }, | ||
| [ elements ] | ||
| ); | ||
|
|
||
| const findElementByLabel = useCallback( | ||
| ( suggestionLabel: string ) => { | ||
| return elements?.find( | ||
| ( suggestion ) => suggestion.label === suggestionLabel | ||
| ); | ||
| }, | ||
| [ elements ] | ||
| ); | ||
|
|
||
| // Ensure value is an array | ||
| const arrayValue = useMemo( | ||
| () => | ||
| Array.isArray( value ) | ||
| ? value.map( ( token ) => { | ||
| const tokenLabel = findElementByValue( token )?.label; | ||
| return tokenLabel || token; | ||
| } ) | ||
| : [], | ||
| [ value, findElementByValue ] | ||
| ); | ||
|
|
||
| const onChangeControl = useCallback( | ||
| ( tokens: ( string | { value: string } )[] ) => { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm trying to understand when the returned tokens can be an array of objects instead of strings. Unless I'm missing some context, I can't reproduce; every individual token is always a string. Can you confirm this? If so, can we simplify this to only handle strings?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is because the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I missed that. It's all good, thanks for the context. |
||
| // Convert TokenItem objects to strings | ||
| const stringTokens = tokens.map( ( token ) => { | ||
| if ( typeof token !== 'string' ) { | ||
| return token.value; | ||
| } | ||
|
|
||
| const tokenByLabel = findElementByLabel( token ); | ||
|
|
||
| return tokenByLabel?.value || token; | ||
| } ); | ||
|
|
||
| onChange( { | ||
| [ id ]: stringTokens, | ||
| } ); | ||
| }, | ||
| [ id, onChange, findElementByLabel ] | ||
| ); | ||
|
|
||
| return ( | ||
| <FormTokenField | ||
| label={ hideLabelFromVision ? undefined : label } | ||
| value={ arrayValue } | ||
| onChange={ onChangeControl } | ||
| placeholder={ placeholder } | ||
| suggestions={ | ||
| elements?.map( ( suggestion ) => suggestion.label ) ?? [] | ||
| } | ||
| __experimentalExpandOnFocus={ elements && elements.length > 0 } | ||
| __next40pxDefaultSize | ||
| __nextHasNoMarginBottom | ||
| /> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,12 +21,14 @@ import select from './select'; | |
| import text from './text'; | ||
| import toggleGroup from './toggle-group'; | ||
| import boolean from './boolean'; | ||
| import array from './array'; | ||
|
|
||
| interface FormControls { | ||
| [ key: string ]: ComponentType< DataFormControlProps< any > >; | ||
| } | ||
|
|
||
| const FORM_CONTROLS: FormControls = { | ||
| array, | ||
| boolean, | ||
| checkbox, | ||
| datetime, | ||
|
|
@@ -51,7 +53,7 @@ export function getControl< Item >( | |
| return getControlByType( field.Edit ); | ||
| } | ||
|
|
||
| if ( field.elements ) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is okay for now, it's how it's already working. I think a better approach would be to actually remove this from here and make every field definition absorb this (handle how they want to use or not use the |
||
| if ( field.elements && field.type !== 'array' ) { | ||
| return getControlByType( 'select' ); | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.