From 65279cf6c61c130c642ec52f0009937078ebad9b Mon Sep 17 00:00:00 2001 From: Erick Danzer Date: Wed, 15 Oct 2025 15:54:16 -0600 Subject: [PATCH 1/4] Forms: add first and last name variations --- .../forms/src/blocks/field-name/index.js | 2 + .../forms/src/blocks/field-name/variations.js | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 projects/packages/forms/src/blocks/field-name/variations.js diff --git a/projects/packages/forms/src/blocks/field-name/index.js b/projects/packages/forms/src/blocks/field-name/index.js index c79f20d40a644..58e4a6a267aa4 100644 --- a/projects/packages/forms/src/blocks/field-name/index.js +++ b/projects/packages/forms/src/blocks/field-name/index.js @@ -6,6 +6,7 @@ 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'; const settings = { @@ -18,6 +19,7 @@ const settings = { ), }, + 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..79333b4f87221 --- /dev/null +++ b/projects/packages/forms/src/blocks/field-name/variations.js @@ -0,0 +1,46 @@ +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( + + ), +}; + +const variations = [ + { + name: 'first-name', + title: __( 'First name', 'jetpack-forms' ), + description: __( 'Collect the visitor’s first name.', 'jetpack-forms' ), + icon, + scope: [ 'inserter', 'transform' ], + isActive: [ 'id' ], + attributes: { + id: 'first-name', + }, + innerBlocks: [ + [ 'jetpack/label', { label: __( 'First name', 'jetpack-forms' ) } ], + [ 'jetpack/input', { type: 'text' } ], + ], + }, + { + name: 'last-name', + title: __( 'Last name', 'jetpack-forms' ), + description: __( 'Collect the visitor’s last name.', 'jetpack-forms' ), + icon, + scope: [ 'inserter', 'transform' ], + isActive: [ 'id' ], + attributes: { + id: 'last-name', + }, + innerBlocks: [ + [ 'jetpack/label', { label: __( 'Last name', 'jetpack-forms' ) } ], + [ 'jetpack/input', { type: 'text' } ], + ], + }, +]; + +export default variations; From 891a6ecc74947702d7dce6c99c34f49817c6bc70 Mon Sep 17 00:00:00 2001 From: Erick Danzer Date: Wed, 15 Oct 2025 15:55:42 -0600 Subject: [PATCH 2/4] changelog --- projects/packages/forms/changelog/add-forms-name-variations | 4 ++++ projects/plugins/jetpack/changelog/add-forms-name-variations | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 projects/packages/forms/changelog/add-forms-name-variations create mode 100644 projects/plugins/jetpack/changelog/add-forms-name-variations 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/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. From d6ad7ae96df6a6b26ee00d6841051a34ea82b9bc Mon Sep 17 00:00:00 2001 From: Erick Danzer Date: Wed, 22 Oct 2025 13:53:24 -0600 Subject: [PATCH 3/4] Update label/id when transforming --- .../forms/src/blocks/field-name/edit.js | 3 + .../field-name/hooks/use-name-label-sync.js | 81 +++++++++++++++++++ .../forms/src/blocks/field-name/variations.js | 37 +++++++-- 3 files changed, 113 insertions(+), 8 deletions(-) create mode 100644 projects/packages/forms/src/blocks/field-name/hooks/use-name-label-sync.js 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/variations.js b/projects/packages/forms/src/blocks/field-name/variations.js index 79333b4f87221..1f7227af7c723 100644 --- a/projects/packages/forms/src/blocks/field-name/variations.js +++ b/projects/packages/forms/src/blocks/field-name/variations.js @@ -10,34 +10,55 @@ const icon = { ), }; +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: 'first-name', - title: __( 'First name', 'jetpack-forms' ), + 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: FIRST_NAME_ID, }, innerBlocks: [ - [ 'jetpack/label', { label: __( 'First name', 'jetpack-forms' ) } ], + [ 'jetpack/label', { label: DEFAULT_FIRST_NAME_LABEL } ], [ 'jetpack/input', { type: 'text' } ], ], }, { - name: 'last-name', - title: __( 'Last name', 'jetpack-forms' ), + 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: LAST_NAME_ID, }, innerBlocks: [ - [ 'jetpack/label', { label: __( 'Last name', 'jetpack-forms' ) } ], + [ 'jetpack/label', { label: DEFAULT_LAST_NAME_LABEL } ], [ 'jetpack/input', { type: 'text' } ], ], }, From 3bb77da31a77b003183b775559fbdd253b2a49ea Mon Sep 17 00:00:00 2001 From: Erick Danzer Date: Thu, 30 Oct 2025 10:35:29 -0600 Subject: [PATCH 4/4] Remove duplicate 'name' from transform menu --- .../forms/src/blocks/field-name/index.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/projects/packages/forms/src/blocks/field-name/index.js b/projects/packages/forms/src/blocks/field-name/index.js index 58e4a6a267aa4..025b559f43cff 100644 --- a/projects/packages/forms/src/blocks/field-name/index.js +++ b/projects/packages/forms/src/blocks/field-name/index.js @@ -2,6 +2,7 @@ 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'; @@ -9,6 +10,22 @@ 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' ), @@ -19,6 +36,7 @@ const settings = { ), }, + transforms, variations, edit, deprecated,