[Product Block Editor]: introduce TextArea field block (#44104)

* introduce TextAreaBlockEdit block

* reglister text area block

* use text-area block in the summary block

* changelog

* changelog

* fix whitespace lint issue

* remove unused types

* intrduce placehholder attribute

* property is the only required attribute

* tidy block attributes

* use useProductEntityProp()

* define fallback value

* remove unused CSS class

* organize attrs

* do not implement tooltip yet

* fix eslint error

* update text-area keywords
This commit is contained in:
Damián Suárez 2024-01-29 17:14:17 -03:00 committed by GitHub
parent 8e79cfa3ea
commit 74d0b39bb0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 388 additions and 1 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: add
[Product Block Editor]: introduce TextArea field block

View File

@ -0,0 +1,63 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "woocommerce/product-text-area-field",
"title": "Product textarea block",
"category": "woocommerce",
"description": "A text-area field for use in the product editor.",
"keywords": [ "textarea", "rich-text" ],
"textdomain": "default",
"attributes": {
"property": {
"type": "string"
},
"label": {
"type": "string",
"__experimentalRole": "content"
},
"placeholder": {
"type": "string"
},
"help": {
"type": "string"
},
"required": {
"type": "string"
},
"disabled": {
"type": "boolean"
},
"align": {
"type": "string",
"enum": [ "left", "center", "right", "justify" ]
},
"allowedFormats": {
"type": "array",
"default": [
"core/bold",
"core/code",
"core/italic",
"core/link",
"core/strikethrough",
"core/underline",
"core/text-color",
"core/subscript",
"core/superscript",
"core/unknown"
]
},
"direction": {
"type": "string",
"enum": [ "ltr", "rtl" ]
}
},
"supports": {
"align": false,
"html": false,
"multiple": true,
"reusable": false,
"inserter": false,
"lock": false,
"__experimentalToolbar": true
}
}

View File

@ -0,0 +1,111 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { useWooBlockProps } from '@woocommerce/block-templates';
import { createElement } from '@wordpress/element';
import { BaseControl } from '@wordpress/components';
import { useInstanceId } from '@wordpress/compose';
import { BlockControls, RichText } from '@wordpress/block-editor';
import classNames from 'classnames';
/**
* Internal dependencies
*/
import { RTLToolbarButton } from './toolbar/toolbar-button-rtl';
import type {
TextAreaBlockEditAttributes,
TextAreaBlockEditProps,
} from './types';
import AligmentToolbarButton from './toolbar/toolbar-button-alignment';
import useProductEntityProp from '../../../hooks/use-product-entity-prop';
export function TextAreaBlockEdit( {
attributes,
setAttributes,
context: { postType },
}: TextAreaBlockEditProps ) {
const {
property,
label,
placeholder,
help,
required,
disabled,
align,
allowedFormats,
direction,
} = attributes;
const blockProps = useWooBlockProps( attributes, {
style: { direction },
} );
const contentId = useInstanceId(
TextAreaBlockEdit,
'wp-block-woocommerce-product-content-field__content'
);
// `property` attribute is required.
if ( ! property ) {
throw new Error(
__( 'Property attribute is required.', 'woocommerce' )
);
}
const [ content, setContent ] = useProductEntityProp< string >( property, {
postType,
} );
function setAlignment( value: TextAreaBlockEditAttributes[ 'align' ] ) {
setAttributes( { align: value } );
}
function changeDirection(
value: TextAreaBlockEditAttributes[ 'direction' ]
) {
setAttributes( { direction: value } );
}
const blockControlsProps = { group: 'block' };
return (
<div className={ 'wp-block-woocommerce-product-text-area-field' }>
<BlockControls { ...blockControlsProps }>
<AligmentToolbarButton
align={ align }
setAlignment={ setAlignment }
/>
<RTLToolbarButton
direction={ direction }
onChange={ changeDirection }
/>
</BlockControls>
<BaseControl
id={ contentId.toString() }
label={ label }
help={ help }
>
<div { ...blockProps }>
<RichText
id={ contentId.toString() }
identifier="content"
tagName="p"
value={ content || '' }
onChange={ setContent }
data-empty={ Boolean( content ) }
className={ classNames( {
[ `has-text-align-${ align }` ]: align,
} ) }
dir={ direction }
allowedFormats={ allowedFormats }
placeholder={ placeholder }
required={ required }
disabled={ disabled }
/>
</div>
</BaseControl>
</div>
);
}

View File

@ -0,0 +1,32 @@
.wp-block-woocommerce-product-text-area-field {
.rich-text {
width: 100%;
min-height: calc($gap-larger * 3);
background-color: $white;
box-sizing: border-box;
border: 1px solid #757575;
border-radius: 2px;
padding: $gap-smaller;
margin: 0;
appearance: textarea;
resize: vertical;
overflow: hidden;
&.rich-text [data-rich-text-placeholder]:after {
color: $gray-700;
opacity: 1;
}
&:focus {
box-shadow: inset 0 0 0 1px var(--wp-admin-theme-color-darker-10, --wp-admin-theme-color);
border-color: var(--wp-admin-theme-color-darker-10, --wp-admin-theme-color);
}
}
// This alignment class does not exists in
// https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/common.scss
.has-text-align-justify {
/*rtl:ignore*/
text-align: justify;
}
}

View File

@ -0,0 +1,28 @@
/**
* External dependencies
*/
import { postContent } from '@wordpress/icons';
/**
* Internal dependencies
*/
import blockConfiguration from './block.json';
import { TextAreaBlockEdit } from './edit';
import { registerProductEditorBlockType } from '../../../utils';
const { name, ...metadata } = blockConfiguration;
export { metadata, name };
export const settings = {
example: {},
edit: TextAreaBlockEdit,
icon: postContent,
};
export const init = () =>
registerProductEditorBlockType( {
name,
metadata: metadata as never,
settings: settings as never,
} );

View File

@ -0,0 +1,52 @@
/**
* External dependencies
*/
import { createElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import {
alignCenter,
alignJustify,
alignLeft,
alignRight,
} from '@wordpress/icons';
import {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore No types for this exist yet.
AlignmentControl,
} from '@wordpress/block-editor';
export const ALIGNMENT_CONTROLS = [
{
icon: alignLeft,
title: __( 'Align text left', 'woocommerce' ),
align: 'left',
},
{
icon: alignCenter,
title: __( 'Align text center', 'woocommerce' ),
align: 'center',
},
{
icon: alignRight,
title: __( 'Align text right', 'woocommerce' ),
align: 'right',
},
{
icon: alignJustify,
title: __( 'Align text justify', 'woocommerce' ),
align: 'justify',
},
];
export default function AligmentToolbarButton( {
align,
setAlignment,
}: AlignmentControl ) {
return (
<AlignmentControl
alignmentControls={ ALIGNMENT_CONTROLS }
value={ align }
onChange={ setAlignment }
/>
);
}

View File

@ -0,0 +1,32 @@
/**
* External dependencies
*/
import { createElement } from '@wordpress/element';
import { ToolbarButton } from '@wordpress/components';
import { _x, isRTL } from '@wordpress/i18n';
import { formatLtr } from '@wordpress/icons';
/**
* Internal dependencies
*/
import type { RTLToolbarButtonProps } from './types';
export function RTLToolbarButton( {
direction,
onChange,
}: RTLToolbarButtonProps ) {
if ( ! isRTL() ) {
return null;
}
return (
<ToolbarButton
icon={ formatLtr }
title={ _x( 'Left to right', 'editor button', 'woocommerce' ) }
isActive={ direction === 'ltr' }
onClick={ () =>
onChange?.( direction === 'ltr' ? undefined : 'ltr' )
}
/>
);
}

View File

@ -0,0 +1,18 @@
/**
* Internal dependencies
*/
import type { TextAreaBlockEditAttributes } from '../../types';
type DirectionProp = TextAreaBlockEditAttributes[ 'direction' ];
export type RTLToolbarButtonProps = {
/**
* Current direction.
*/
direction: DirectionProp;
/**
* Callback to update the direction.
*/
onChange( direction?: DirectionProp ): void;
};

View File

@ -0,0 +1,34 @@
/**
* Internal dependencies
*/
import {
ProductEditorBlockAttributes,
ProductEditorBlockEditProps,
} from '../../../types';
type AllowedFormat =
| 'core/bold'
| 'core/code'
| 'core/italic'
| 'core/link'
| 'core/strikethrough'
| 'core/underline'
| 'core/text-color'
| 'core/subscript'
| 'core/superscript'
| 'core/unknown';
export type TextAreaBlockEditAttributes = ProductEditorBlockAttributes & {
property: string;
label?: string;
placeholder?: string;
help?: string;
required?: boolean;
disabled?: boolean;
align?: 'left' | 'center' | 'right' | 'justify';
allowedFormats?: AllowedFormat[];
direction?: 'ltr' | 'rtl';
};
export type TextAreaBlockEditProps =
ProductEditorBlockEditProps< TextAreaBlockEditAttributes >;

View File

@ -35,3 +35,4 @@ export { init as initTaxonomy } from './generic/taxonomy';
export { init as initText } from './generic/text';
export { init as initNumber } from './generic/number';
export { init as initLinkedProductList } from './generic/linked-product-list';
export { init as initTextArea } from './generic/text-area';

View File

@ -25,3 +25,4 @@
@import "generic/toggle/editor.scss";
@import "generic/number/editor.scss";
@import "generic/linked-product-list/editor.scss";
@import "generic/text-area/editor.scss";

View File

@ -0,0 +1,4 @@
Significance: patch
Type: add
Use the new text area block in the summary field

View File

@ -36,6 +36,7 @@ class BlockRegistry {
'woocommerce/product-toggle-field',
'woocommerce/product-taxonomy-field',
'woocommerce/product-text-field',
'woocommerce/product-text-area-field',
'woocommerce/product-number-field',
'woocommerce/product-linked-list-field',
);

View File

@ -215,12 +215,18 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
),
)
);
$basic_details->add_block(
array(
'id' => 'product-summary',
'blockName' => 'woocommerce/product-summary-field',
'blockName' => 'woocommerce/product-text-area-field',
'order' => 20,
'attributes' => array(
'label' => __( 'Summary', 'woocommerce' ),
'help' => __(
"Summarize this product in 1-2 short sentences. We'll show it at the top of the page.",
'woocommerce'
),
'property' => 'short_description',
),
)