UNPKG

@gechiui/block-editor

Version:
264 lines (232 loc) 6.55 kB
/** * External dependencies */ import classnames from 'classnames'; /** * GeChiUI dependencies */ import { addFilter } from '@gechiui/hooks'; import { __ } from '@gechiui/i18n'; import { createHigherOrderComponent } from '@gechiui/compose'; import { useState } from '@gechiui/element'; /** * Internal dependencies */ import ColorGradientSettingsDropdown from '../components/colors-gradients/dropdown'; import useMultipleOriginColorsAndGradients from '../components/colors-gradients/use-multiple-origin-colors-and-gradients'; import { getColorClassName, getColorObjectByColorValue, getColorObjectByAttributeValues, } from '../components/colors'; import useSetting from '../components/use-setting'; import { hasBorderSupport, shouldSkipSerialization } from './border'; import { cleanEmptyObject } from './utils'; // Defining empty array here instead of inline avoids unnecessary re-renders of // color control. const EMPTY_ARRAY = []; /** * Inspector control panel containing the border color related configuration. * * There is deliberate overlap between the colors and borders block supports * relating to border color. It can be argued the border color controls could * be included within either, or both, the colors and borders panels in the * inspector controls. If they share the same block attributes it should not * matter. * * @param {Object} props Block properties. * * @return {GCElement} Border color edit element. */ export function BorderColorEdit( props ) { const { attributes: { borderColor, style }, setAttributes, } = props; const colorGradientSettings = useMultipleOriginColorsAndGradients(); const availableColors = colorGradientSettings.colors.reduce( ( colors, origin ) => colors.concat( origin.colors ), [] ); const [ colorValue, setColorValue ] = useState( () => getColorObjectByAttributeValues( availableColors, borderColor, style?.border?.color )?.color ); const onChangeColor = ( value ) => { setColorValue( value ); const colorObject = getColorObjectByColorValue( availableColors, value ); const newStyle = { ...style, border: { ...style?.border, color: colorObject?.slug ? undefined : value, }, }; // If empty slug, ensure undefined to remove attribute. const newNamedColor = colorObject?.slug ? colorObject.slug : undefined; setAttributes( { style: cleanEmptyObject( newStyle ), borderColor: newNamedColor, } ); }; const settings = [ { label: __( '颜色' ), onColorChange: onChangeColor, colorValue, clearable: false, }, ]; return ( <ColorGradientSettingsDropdown settings={ settings } disableCustomColors disableCustomGradients __experimentalHasMultipleOrigins __experimentalIsRenderedInSidebar enableAlpha { ...colorGradientSettings } /> ); } /** * Filters registered block settings, extending attributes to include * `borderColor` if needed. * * @param {Object} settings Original block settings. * * @return {Object} Updated block settings. */ function addAttributes( settings ) { if ( ! hasBorderSupport( settings, 'color' ) ) { return settings; } // Allow blocks to specify default value if needed. if ( settings.attributes.borderColor ) { return settings; } // Add new borderColor attribute to block settings. return { ...settings, attributes: { ...settings.attributes, borderColor: { type: 'string', }, }, }; } /** * Override props assigned to save component to inject border color. * * @param {Object} props Additional props applied to save element. * @param {Object} blockType Block type definition. * @param {Object} attributes Block's attributes. * * @return {Object} Filtered props to apply to save element. */ function addSaveProps( props, blockType, attributes ) { if ( ! hasBorderSupport( blockType, 'color' ) || shouldSkipSerialization( blockType ) ) { return props; } const { borderColor, style } = attributes; const borderColorClass = getColorClassName( 'border-color', borderColor ); const newClassName = classnames( props.className, { 'has-border-color': borderColor || style?.border?.color, [ borderColorClass ]: !! borderColorClass, } ); // If we are clearing the last of the previous classes in `className` // set it to `undefined` to avoid rendering empty DOM attributes. props.className = newClassName ? newClassName : undefined; return props; } /** * Filters the registered block settings to apply border color styles and * classnames to the block edit wrapper. * * @param {Object} settings Original block settings. * * @return {Object} Filtered block settings. */ function addEditProps( settings ) { if ( ! hasBorderSupport( settings, 'color' ) || shouldSkipSerialization( settings ) ) { return settings; } const existingGetEditWrapperProps = settings.getEditWrapperProps; settings.getEditWrapperProps = ( attributes ) => { let props = {}; if ( existingGetEditWrapperProps ) { props = existingGetEditWrapperProps( attributes ); } return addSaveProps( props, settings, attributes ); }; return settings; } /** * This adds inline styles for color palette colors. * Ideally, this is not needed and themes should load their palettes on the editor. * * @param {Function} BlockListBlock Original component. * * @return {Function} Wrapped component. */ export const withBorderColorPaletteStyles = createHigherOrderComponent( ( BlockListBlock ) => ( props ) => { const { name, attributes } = props; const { borderColor } = attributes; const colors = useSetting( 'color.palette' ) || EMPTY_ARRAY; if ( ! hasBorderSupport( name, 'color' ) || shouldSkipSerialization( name ) ) { return <BlockListBlock { ...props } />; } const extraStyles = { borderColor: borderColor ? getColorObjectByAttributeValues( colors, borderColor )?.color : undefined, }; let wrapperProps = props.wrapperProps; wrapperProps = { ...props.wrapperProps, style: { ...extraStyles, ...props.wrapperProps?.style, }, }; return <BlockListBlock { ...props } wrapperProps={ wrapperProps } />; } ); addFilter( 'blocks.registerBlockType', 'core/border/addAttributes', addAttributes ); addFilter( 'blocks.getSaveContent.extraProps', 'core/border/addSaveProps', addSaveProps ); addFilter( 'blocks.registerBlockType', 'core/border/addEditProps', addEditProps ); addFilter( 'editor.BlockListBlock', 'core/border/with-border-color-palette-styles', withBorderColorPaletteStyles );