Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: changed

Forms: improve adding, editing and removing options for dropdown field
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
} from '@automattic/jetpack-shared-extension-utils';
import DeprecatedOptionCheckbox from '../deprecated/field-option-checkbox';
import DeprecatedOptionRadio from '../deprecated/field-option-radio';
import JetpackDropdown from '../dropdown';
import JetpackDropdownOption from '../dropdown-option';
import JetpackDropzone from '../dropzone';
import JetpackCheckboxField from '../field-checkbox';
import JetpackConsentField from '../field-consent/';
Expand Down Expand Up @@ -42,6 +44,8 @@ import JetpackOptions from '../options';
export const childBlocks = [
JetpackLabel,
JetpackDropzone,
JetpackDropdown,
JetpackDropdownOption,
JetpackInput,
JetpackOption,
JetpackOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,20 @@ public static function register_child_blocks() {
)
);

Blocks::jetpack_register_block(
'jetpack/dropdown',
array(
'render_callback' => array( Contact_Form_Plugin::class, 'gutenblock_render_dropdown' ),
)
);

Blocks::jetpack_register_block(
'jetpack/dropdown-option',
array(
'render_callback' => array( Contact_Form_Plugin::class, 'gutenblock_render_dropdown_option' ),
)
);

if ( Blocks::get_variation() === 'beta' ) {
Blocks::jetpack_register_block(
'jetpack/field-hidden',
Expand Down
105 changes: 105 additions & 0 deletions projects/packages/forms/src/blocks/dropdown-option/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { RichText, useBlockProps, store as blockEditorStore } from '@wordpress/block-editor';
import { createBlock } from '@wordpress/blocks';
import { Button, Flex, FlexItem } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { close } from '@wordpress/icons';

export default function DropdownOptionEdit( props ) {
const { attributes, clientId, mergeBlocks, setAttributes } = props;
const { option } = attributes;
const className = 'jetpack-field-dropdown__option';
const blockProps = useBlockProps( {
className,
} );
const { removeBlocks, replaceBlocks, insertBlocks } = useDispatch( blockEditorStore );
const {
getBlockIndex,
getBlockRootClientId,
getMultiSelectedBlockClientIds,
getNextBlockClientId,
getPreviousBlockClientId,
} = useSelect( blockEditorStore );

const onPaste = event => {
const pastedText = event.clipboardData.getData( 'text/plain' );

// While pasting, multiple blocks were selected
const multiSelectedBlockClientIds = getMultiSelectedBlockClientIds();
if ( multiSelectedBlockClientIds.length ) {
const lines = pastedText.split( '\n' );
const newOptions = lines.map( line =>
createBlock( 'jetpack/dropdown-option', { option: line } )
);
replaceBlocks( multiSelectedBlockClientIds, newOptions );
return;
}

// Otherwise pasting in a single block…

// Check if the pasted text contains multiple lines
if ( pastedText.includes( '\n' ) ) {
event.preventDefault();

const lines = pastedText.split( '\n' );

// Grab first element of the pasted list as a value for current option block
const firstLine = lines.shift();
setAttributes( { option: `${ option || '' }${ firstLine }` } );

// Append rest of the lines as new option blocks
const newOptions = lines.map( line =>
createBlock( 'jetpack/dropdown-option', { option: line } )
);
const rootClientId = getBlockRootClientId( clientId );
const index = getBlockIndex( clientId );

insertBlocks( newOptions, index + 1, rootClientId );
}
};

const onRemove = () => {
const nextBlockClientId = getNextBlockClientId( clientId );
const previousBlockClientId = getPreviousBlockClientId( clientId );

if ( ! nextBlockClientId && ! previousBlockClientId ) {
// If this is the the only option, remove by emptying value
setAttributes( { option: '' } );
return;
}

return removeBlocks( clientId );
};

return (
<div { ...blockProps }>
<Flex>
<FlexItem isBlock>
<RichText
__unstablePastePlainText
allowedFormats={ [] }
aria-label={ __( 'Dropdown option value', 'jetpack-forms' ) }
identifier="option"
onChange={ value => setAttributes( { option: value } ) }
onMerge={ mergeBlocks }
onPaste={ onPaste }
onRemove={ onRemove }
placeholder={ __( 'Add option…', 'jetpack-forms' ) }
tagName="div"
value={ option || '' }
withoutInteractiveFormatting
/>
</FlexItem>
<FlexItem>
<Button
className="jetpack-field-dropdown__option-remove"
label={ __( 'Remove', 'jetpack-forms' ) }
variant="tertiary"
onClick={ onRemove }
icon={ close }
></Button>
</FlexItem>
</Flex>
</div>
);
}
38 changes: 38 additions & 0 deletions projects/packages/forms/src/blocks/dropdown-option/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { __ } from '@wordpress/i18n';
import { lineSolid } from '@wordpress/icons';
import { getIconColor } from '../shared/util/block-icons';
import edit from './edit';
import save from './save';

const name = 'dropdown-option';
const settings = {
apiVersion: 3,
title: __( 'Option', 'jetpack-forms' ),
description: __( 'Option for dropdown fields.', 'jetpack-forms' ),
parent: [ 'jetpack/dropdown' ],
category: 'contact-form',
icon: {
foreground: getIconColor(),
src: lineSolid,
},
attributes: { option: { type: 'string', default: '' } },
supports: {
anchor: false,
customClassName: false,
html: false,
reusable: false,
splitting: true,
},
merge: ( attributes, { option = '' } ) => ( {
...attributes,
option: ( attributes.option || '' ) + option,
} ),
edit,
save,
__experimentalLabel: ( { option } ) => option,
};

export default {
name,
settings,
};
1 change: 1 addition & 0 deletions projects/packages/forms/src/blocks/dropdown-option/save.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => null;
27 changes: 27 additions & 0 deletions projects/packages/forms/src/blocks/dropdown/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { InnerBlocks, useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';

import './editor.scss';

const DEFAULT_BLOCK = {
name: 'jetpack/dropdown-option',
};

const TEMPLATE = [ [ DEFAULT_BLOCK.name ] ];

export default function DropdownEdit() {
const blockProps = useBlockProps( { className: 'jetpack-field-dropdown__popover' } );
const innerBlocksProps = useInnerBlocksProps( blockProps );

return (
<div { ...innerBlocksProps }>
<InnerBlocks
__experimentalCaptureToolbars={ true }
defaultBlock={ DEFAULT_BLOCK }
directInsert={ true }
template={ TEMPLATE }
templateLock={ false }
templateInsertUpdatesSelection={ true }
/>
</div>
);
}
15 changes: 15 additions & 0 deletions projects/packages/forms/src/blocks/dropdown/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.wp-block-jetpack-dropdown {
display: none;

p {
margin-bottom: 10px;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: use block gap variable?

}
}

.is-selected,
.has-child-selected {

.wp-block-jetpack-dropdown {
display: block;
}
}
31 changes: 31 additions & 0 deletions projects/packages/forms/src/blocks/dropdown/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { __ } from '@wordpress/i18n';
import { menu } from '@wordpress/icons';
import { getIconColor } from '../shared/util/block-icons';
import edit from './edit';
import save from './save';

const name = 'dropdown';
const settings = {
apiVersion: 3,
title: __( 'Dropdown', 'jetpack-forms' ),
description: __( 'Options for dropdown fields.', 'jetpack-forms' ),
parent: [ 'jetpack/field-select' ],
allowedBlocks: [ 'jetpack/dropdown-option' ],
category: 'contact-form',
icon: {
foreground: getIconColor(),
src: menu,
},
supports: {
anchor: false,
reusable: false,
html: false,
},
edit,
save,
};

export default {
name,
settings,
};
7 changes: 7 additions & 0 deletions projects/packages/forms/src/blocks/dropdown/save.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';

export default () => {
const blockProps = useBlockProps.save();
const innerBlocksProps = useInnerBlocksProps.save( blockProps );
return <div { ...innerBlocksProps } />;
};
Loading
Loading