diff --git a/projects/packages/forms/changelog/add-forms-name-variations b/projects/packages/forms/changelog/add-forms-name-variations new file mode 100644 index 0000000000000..ebdd2d3598075 --- /dev/null +++ b/projects/packages/forms/changelog/add-forms-name-variations @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Forms: add first and last name variations. diff --git a/projects/packages/forms/src/blocks/field-name/edit.js b/projects/packages/forms/src/blocks/field-name/edit.js index fb228fd4708a6..749ecb06cdfe9 100644 --- a/projects/packages/forms/src/blocks/field-name/edit.js +++ b/projects/packages/forms/src/blocks/field-name/edit.js @@ -1,10 +1,13 @@ import { __ } from '@wordpress/i18n'; import JetpackField from '../shared/components/jetpack-field'; import useFormWrapper from '../shared/hooks/use-form-wrapper'; +import useNameLabelSync from './hooks/use-name-label-sync'; export default function NameFieldEdit( props ) { useFormWrapper( props ); + useNameLabelSync( { clientId: props.clientId, id: props.attributes?.id } ); + return ( id === FIRST_NAME_ID || id === LAST_NAME_ID; + +const getDefaultLabelForId = id => { + if ( id === FIRST_NAME_ID ) return DEFAULT_FIRST_NAME_LABEL; + if ( id === LAST_NAME_ID ) return DEFAULT_LAST_NAME_LABEL; + return DEFAULT_NAME_LABEL; +}; + +/** + * Sync the nested label text with the Name field's variation id when users transform + * between known variations (first-name/last-name). + * + * @param {object} params - Parameters. + * @param {string} params.clientId - Block clientId for the Name field + * @param {string} params.id - Current variation id (e.g., 'first-name' | 'last-name') + */ +export default function useNameLabelSync( { clientId, id } ) { + const prevIdRef = useRef( id ); + const { updateBlockAttributes } = useDispatch( blockEditorStore ); + + const labelClientId = useSelect( + select => { + const block = select( blockEditorStore ).getBlock( clientId ); + const labelBlock = block?.innerBlocks?.find( b => b.name === 'jetpack/label' ); + return labelBlock?.clientId; + }, + [ clientId ] + ); + + const currentLabel = useSelect( + select => { + return labelClientId + ? select( blockEditorStore ).getBlockAttributes( labelClientId )?.label + : undefined; + }, + [ labelClientId ] + ); + + useEffect( () => { + const newId = id; + const prevId = prevIdRef.current; + + if ( ! labelClientId ) { + prevIdRef.current = newId; + return; + } + + // Handle transforms between known variations. + if ( isKnownId( newId ) && newId !== prevId ) { + const nextDefault = getDefaultLabelForId( newId ); + // Ensure the parent block id matches the variation id. + if ( newId ) { + updateBlockAttributes( clientId, { id: newId } ); + } + // Always set the label to the default for the selected variation. + updateBlockAttributes( labelClientId, { label: nextDefault } ); + } + + // Handle transforms from a known variation back to the base Name (no id). + const becameBase = isKnownId( prevId ) && ( newId === undefined || newId === '' ); + if ( becameBase ) { + // Clear the parent block id when returning to base. + updateBlockAttributes( clientId, { id: '' } ); + // Always set the label back to the base default. + updateBlockAttributes( labelClientId, { label: DEFAULT_NAME_LABEL } ); + } + + prevIdRef.current = newId; + }, [ id, clientId, labelClientId, currentLabel, updateBlockAttributes ] ); +} diff --git a/projects/packages/forms/src/blocks/field-name/index.js b/projects/packages/forms/src/blocks/field-name/index.js index c79f20d40a644..025b559f43cff 100644 --- a/projects/packages/forms/src/blocks/field-name/index.js +++ b/projects/packages/forms/src/blocks/field-name/index.js @@ -2,12 +2,30 @@ import { Path } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import renderMaterialIcon from '../shared/components/render-material-icon'; import defaultSettings from '../shared/settings'; +import transformsSource from '../shared/settings/transforms'; import { getIconColor } from '../shared/util/block-icons'; import deprecated from './deprecated'; import edit from './edit'; import save from './save'; +import variations from './variations'; const name = 'field-name'; + +// We define variations for Name, First name, and Last name. +// For this block only, override transforms to remove the generic self-transform +// to `jetpack/field-name`, so the Transform menu doesn’t show duplicate “Name”. +// Other blocks still use the shared transforms (and can transform to Name/its variations). +function notSelfNameTransform( transform ) { + return ! ( + Array.isArray( transform.blocks ) && transform.blocks.includes( 'jetpack/field-name' ) + ); +} + +const transforms = { + ...transformsSource, + to: transformsSource.to.filter( notSelfNameTransform ), +}; + const settings = { ...defaultSettings, title: __( 'Name field', 'jetpack-forms' ), @@ -18,6 +36,8 @@ const settings = { ), }, + transforms, + variations, edit, deprecated, save, diff --git a/projects/packages/forms/src/blocks/field-name/variations.js b/projects/packages/forms/src/blocks/field-name/variations.js new file mode 100644 index 0000000000000..1f7227af7c723 --- /dev/null +++ b/projects/packages/forms/src/blocks/field-name/variations.js @@ -0,0 +1,67 @@ +import { Path } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import renderMaterialIcon from '../shared/components/render-material-icon'; +import { getIconColor } from '../shared/util/block-icons'; + +const icon = { + foreground: getIconColor(), + src: renderMaterialIcon( + + ), +}; + +export const FIRST_NAME_ID = 'first-name'; +export const LAST_NAME_ID = 'last-name'; + +export const DEFAULT_FIRST_NAME_LABEL = __( 'First name', 'jetpack-forms' ); +export const DEFAULT_LAST_NAME_LABEL = __( 'Last name', 'jetpack-forms' ); +export const DEFAULT_NAME_LABEL = __( 'Name', 'jetpack-forms' ); + +const variations = [ + { + name: 'name', + title: DEFAULT_NAME_LABEL, + description: __( 'Collect the visitor’s name.', 'jetpack-forms' ), + icon, + scope: [ 'transform' ], + attributes: { + id: '', + }, + innerBlocks: [ + [ 'jetpack/label', { label: DEFAULT_NAME_LABEL } ], + [ 'jetpack/input', { type: 'text' } ], + ], + }, + { + name: FIRST_NAME_ID, + title: DEFAULT_FIRST_NAME_LABEL, + description: __( 'Collect the visitor’s first name.', 'jetpack-forms' ), + icon, + scope: [ 'inserter', 'transform' ], + isActive: [ 'id' ], + attributes: { + id: FIRST_NAME_ID, + }, + innerBlocks: [ + [ 'jetpack/label', { label: DEFAULT_FIRST_NAME_LABEL } ], + [ 'jetpack/input', { type: 'text' } ], + ], + }, + { + name: LAST_NAME_ID, + title: DEFAULT_LAST_NAME_LABEL, + description: __( 'Collect the visitor’s last name.', 'jetpack-forms' ), + icon, + scope: [ 'inserter', 'transform' ], + isActive: [ 'id' ], + attributes: { + id: LAST_NAME_ID, + }, + innerBlocks: [ + [ 'jetpack/label', { label: DEFAULT_LAST_NAME_LABEL } ], + [ 'jetpack/input', { type: 'text' } ], + ], + }, +]; + +export default variations; diff --git a/projects/plugins/jetpack/changelog/add-forms-name-variations b/projects/plugins/jetpack/changelog/add-forms-name-variations new file mode 100644 index 0000000000000..388ed2afbf13f --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-forms-name-variations @@ -0,0 +1,4 @@ +Significance: minor +Type: enhancement + +Forms: add first and last name variations.