diff --git a/projects/packages/forms/changelog/update-forms-text-field-height b/projects/packages/forms/changelog/update-forms-text-field-height new file mode 100644 index 0000000000000..8cae830b15772 --- /dev/null +++ b/projects/packages/forms/changelog/update-forms-text-field-height @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Forms: allow height control for textarea" diff --git a/projects/packages/forms/src/blocks/contact-form/child-blocks.js b/projects/packages/forms/src/blocks/contact-form/child-blocks.js index ef581409aeb10..7b3da6caca90c 100644 --- a/projects/packages/forms/src/blocks/contact-form/child-blocks.js +++ b/projects/packages/forms/src/blocks/contact-form/child-blocks.js @@ -28,6 +28,7 @@ import JetpackStepContainer from '../form-step-container/index.js'; import JetpackStepDivider from '../form-step-divider/index.js'; import JetpackStepNavigation from '../form-step-navigation/index.js'; import JetpackInput from '../input/index.js'; +import JetpackTextarea from '../textarea/index.js'; import JetpackImageOptionInput from '../input-image-option/index.tsx'; import JetpackPhoneInput from '../input-phone/index.js'; import JetpackSliderInput from '../input-range/index.js'; @@ -40,6 +41,7 @@ export const childBlocks = [ JetpackLabel, JetpackDropzone, JetpackInput, + JetpackTextarea, JetpackOption, JetpackOptions, JetpackCheckboxField, diff --git a/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php b/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php index 81b90d613a8f4..1941a27bcbc7b 100644 --- a/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php +++ b/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php @@ -146,6 +146,45 @@ public static function register_child_blocks() { 'uses_context' => array( 'jetpack/field-default-value' ), ) ); + + // Field inner block types. + Blocks::jetpack_register_block( + 'jetpack/textarea', + array( + 'supports' => array( + '__experimentalBorder' => array( + 'color' => true, + 'radius' => true, + 'style' => true, + 'width' => true, + ), + 'color' => array( + 'text' => true, + 'background' => true, + 'gradients' => false, + ), + 'dimensions' => array( + 'minHeight' => true, + ), + 'typography' => array( + 'fontSize' => true, + 'lineHeight' => true, + '__experimentalFontFamily' => true, + '__experimentalFontWeight' => true, + '__experimentalFontStyle' => true, + '__experimentalTextTransform' => true, + '__experimentalTextDecoration' => true, + '__experimentalLetterSpacing' => true, + ), + ), + 'selectors' => array( + 'border' => '.wp-block-jetpack-input, .is-style-outlined .notched-label:has(+ .wp-block-jetpack-input) > *,.is-style-outlined .wp-block-jetpack-input + .notched-label > *, .is-style-outlined .wp-block-jetpack-field-select .notched-label > *', + 'color' => '.wp-block-jetpack-input, .is-style-outlined .notched-label:has(+ .wp-block-jetpack-input) > *,.is-style-outlined .wp-block-jetpack-input + .notched-label > *, .is-style-outlined .wp-block-jetpack-field-select .notched-label > *', + ), + 'uses_context' => array( 'jetpack/field-default-value' ), + ) + ); + Blocks::jetpack_register_block( 'jetpack/label', array( diff --git a/projects/packages/forms/src/blocks/contact-form/variations.js b/projects/packages/forms/src/blocks/contact-form/variations.js index ee870c0bfcaf1..12c4129c9b9e2 100644 --- a/projects/packages/forms/src/blocks/contact-form/variations.js +++ b/projects/packages/forms/src/blocks/contact-form/variations.js @@ -62,7 +62,7 @@ const variations = [ {}, [ [ 'jetpack/label', { label: __( 'Message', 'jetpack-forms' ) } ], - [ 'jetpack/input', { type: 'textarea' } ], + [ 'jetpack/textarea' ], ], ], [ @@ -141,7 +141,7 @@ const variations = [ {}, [ [ 'jetpack/label', { label: __( 'Other details', 'jetpack-forms' ) } ], - [ 'jetpack/input', { type: 'textarea' } ], + [ 'jetpack/textarea' ], ], ], [ @@ -208,7 +208,7 @@ const variations = [ name: 'jetpack/label', attributes: { label: __( 'Other details', 'jetpack-forms' ) }, }, - { name: 'jetpack/input', attributes: { type: 'textarea' } }, + { name: 'jetpack/textarea' }, ], }, { @@ -294,7 +294,7 @@ const variations = [ label: __( 'Other details', 'jetpack-forms' ), }, ], - [ 'jetpack/input', { type: 'textarea' } ], + [ 'jetpack/textarea' ], ], ], [ @@ -481,10 +481,7 @@ const variations = [ [ 'jetpack/field-textarea', {}, - [ - [ 'jetpack/label', { label: __( 'Notes', 'jetpack-forms' ) } ], - [ 'jetpack/input', { type: 'textarea' } ], - ], + [ [ 'jetpack/label', { label: __( 'Notes', 'jetpack-forms' ) } ], [ 'jetpack/textarea' ] ], ], [ 'jetpack/button', @@ -629,7 +626,7 @@ const variations = [ {}, [ [ 'jetpack/label', { label: __( 'How could we improve?', 'jetpack-forms' ) } ], - [ 'jetpack/input', { type: 'textarea' } ], + [ 'jetpack/textarea' ], ], ], [ @@ -803,7 +800,7 @@ const variations = [ 'jetpack/label', { label: __( 'What do you need help with?', 'jetpack-forms' ) }, ], - [ 'jetpack/input', { type: 'textarea' } ], + [ 'jetpack/textarea' ], ], ], [ diff --git a/projects/packages/forms/src/blocks/field-textarea/edit.js b/projects/packages/forms/src/blocks/field-textarea/edit.js index 90b0a13bbe26e..c4151d14a67f0 100644 --- a/projects/packages/forms/src/blocks/field-textarea/edit.js +++ b/projects/packages/forms/src/blocks/field-textarea/edit.js @@ -27,7 +27,7 @@ export default function TextareaFieldEdit( props ) { const template = useMemo( () => { return [ [ 'jetpack/label', { label: __( 'Message', 'jetpack-forms' ), requiredIndicator } ], - [ 'jetpack/input', { type: 'textarea' } ], + [ 'jetpack/textarea' ], ]; }, [ requiredIndicator ] ); diff --git a/projects/packages/forms/src/blocks/field-textarea/index.js b/projects/packages/forms/src/blocks/field-textarea/index.js index b8befb5461fa3..f0f68e5145cea 100644 --- a/projects/packages/forms/src/blocks/field-textarea/index.js +++ b/projects/packages/forms/src/blocks/field-textarea/index.js @@ -33,10 +33,7 @@ const settings = { }, }, { - name: 'jetpack/input', - attributes: { - type: 'textarea', - }, + name: 'jetpack/textarea', }, ], }, diff --git a/projects/packages/forms/src/blocks/textarea/edit.js b/projects/packages/forms/src/blocks/textarea/edit.js new file mode 100644 index 0000000000000..5a8eb3ee07249 --- /dev/null +++ b/projects/packages/forms/src/blocks/textarea/edit.js @@ -0,0 +1,109 @@ +import { store as blockEditorStore, useBlockProps } from '@wordpress/block-editor'; +import { ResizableBox } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { useCallback } from '@wordpress/element'; +import { useSyncedAttributes } from '../shared/hooks/use-synced-attributes.js'; +import useVariationStyleProperties from '../shared/hooks/use-variation-style-properties.js'; + +const SYNCED_ATTRIBUTE_KEYS = [ + 'backgroundColor', + 'borderColor', + 'fontFamily', + 'fontSize', + 'style', + 'textColor', +]; + +const TextareaEdit = ( { + attributes, + clientId, + context, + isSelected, + name, + setAttributes, + toggleSelection, +} ) => { + const { 'jetpack/field-share-attributes': isSynced } = context; + useSyncedAttributes( name, isSynced, SYNCED_ATTRIBUTE_KEYS, attributes, setAttributes ); + const { placeholder, style } = attributes; + + // Get height from style.dimensions.minHeight (global styles) or fallback to height attribute + const minHeightFromStyle = style?.dimensions?.minHeight; + const currentHeight = minHeightFromStyle + ? parseInt( minHeightFromStyle.replace( 'px', '' ), 10 ) || 200 + : attributes.height || 200; + + // Check if the parent block (e.g. textarea-field) is selected + const isParentSelected = useSelect( + select => { + const { getBlockRootClientId, getSelectedBlockClientId } = select( blockEditorStore ); + const parentClientId = getBlockRootClientId( clientId ); + const selectedBlockClientId = getSelectedBlockClientId(); + return parentClientId && parentClientId === selectedBlockClientId; + }, + [ clientId ] + ); + + const variationProps = useVariationStyleProperties( { + clientId, + inputBlockName: name, + inputBlockAttributes: attributes, + } ); + const blockProps = useBlockProps( { + className: 'jetpack-field__textarea', + style: variationProps?.cssVars, + } ); + + const onChange = useCallback( + event => { + setAttributes( { placeholder: event.target.value } ); + }, + [ setAttributes ] + ); + + return ( + { + const newHeight = currentHeight + delta.height; + setAttributes( { + style: { + ...style, + dimensions: { + ...style?.dimensions, + minHeight: `${ newHeight }px`, + }, + }, + } ); + toggleSelection( true ); + } } + onResizeStart={ () => { + toggleSelection( false ); + } } + showHandle={ isSelected || isParentSelected } + > +