[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:
parent
8e79cfa3ea
commit
74d0b39bb0
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: add
|
||||
|
||||
[Product Block Editor]: introduce TextArea field block
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
} );
|
|
@ -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 }
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -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' )
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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 >;
|
|
@ -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';
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: add
|
||||
|
||||
Use the new text area block in the summary field
|
|
@ -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',
|
||||
);
|
||||
|
|
|
@ -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',
|
||||
),
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue