UNPKG

@wordpress/block-editor

Version:
180 lines (152 loc) 6.03 kB
import { createElement, Fragment } from "@wordpress/element"; /** * External dependencies */ import { capitalize, get, has, omit, omitBy, startsWith } from 'lodash'; /** * WordPress dependencies */ import { addFilter } from '@wordpress/hooks'; import { getBlockSupport, hasBlockSupport, __EXPERIMENTAL_STYLE_PROPERTY as STYLE_PROPERTY } from '@wordpress/blocks'; import { createHigherOrderComponent } from '@wordpress/compose'; /** * Internal dependencies */ import { BORDER_SUPPORT_KEY, BorderPanel } from './border'; import { COLOR_SUPPORT_KEY, ColorEdit } from './color'; import { FONT_SIZE_SUPPORT_KEY } from './font-size'; import { TypographyPanel, TYPOGRAPHY_SUPPORT_KEYS } from './typography'; import { SPACING_SUPPORT_KEY, SpacingPanel } from './spacing'; import useDisplayBlockControls from '../components/use-display-block-controls'; const styleSupportKeys = [...TYPOGRAPHY_SUPPORT_KEYS, BORDER_SUPPORT_KEY, COLOR_SUPPORT_KEY, SPACING_SUPPORT_KEY]; const hasStyleSupport = blockType => styleSupportKeys.some(key => hasBlockSupport(blockType, key)); const VARIABLE_REFERENCE_PREFIX = 'var:'; const VARIABLE_PATH_SEPARATOR_TOKEN_ATTRIBUTE = '|'; const VARIABLE_PATH_SEPARATOR_TOKEN_STYLE = '--'; function compileStyleValue(uncompiledValue) { if (startsWith(uncompiledValue, VARIABLE_REFERENCE_PREFIX)) { const variable = uncompiledValue.slice(VARIABLE_REFERENCE_PREFIX.length).split(VARIABLE_PATH_SEPARATOR_TOKEN_ATTRIBUTE).join(VARIABLE_PATH_SEPARATOR_TOKEN_STYLE); return `var(--wp--${variable})`; } return uncompiledValue; } /** * Returns the inline styles to add depending on the style object * * @param {Object} styles Styles configuration * @return {Object} Flattened CSS variables declaration */ export function getInlineStyles(styles = {}) { const output = {}; Object.keys(STYLE_PROPERTY).forEach(propKey => { const path = STYLE_PROPERTY[propKey].value; const subPaths = STYLE_PROPERTY[propKey].properties; if (has(styles, path)) { if (!!subPaths) { subPaths.forEach(suffix => { output[propKey + capitalize(suffix)] = compileStyleValue(get(styles, [...path, suffix])); }); } else { output[propKey] = compileStyleValue(get(styles, path)); } } }); return output; } /** * Filters registered block settings, extending attributes to include `style` attribute. * * @param {Object} settings Original block settings * @return {Object} Filtered block settings */ function addAttribute(settings) { if (!hasStyleSupport(settings)) { return settings; } // allow blocks to specify their own attribute definition with default values if needed. if (!settings.attributes.style) { Object.assign(settings.attributes, { style: { type: 'object' } }); } return settings; } /** * Filters a style object returning only the keys * that are serializable for a given block. * * @param {Object} style Input style object to filter. * @param {Object} blockSupports Info about block supports. * @return {Object} Filtered style. */ export function omitKeysNotToSerialize(style, blockSupports) { return omitBy(style, (value, key) => { var _blockSupports$key; return !!((_blockSupports$key = blockSupports[key]) !== null && _blockSupports$key !== void 0 && _blockSupports$key.__experimentalSkipSerialization); }); } /** * Override props assigned to save component to inject the CSS variables definition. * * @param {Object} props Additional props applied to save element * @param {Object} blockType Block type * @param {Object} attributes Block attributes * @return {Object} Filtered props applied to save element */ export function addSaveProps(props, blockType, attributes) { if (!hasStyleSupport(blockType)) { return props; } const { style } = attributes; let filteredStyle = omitKeysNotToSerialize(style, { border: getBlockSupport(blockType, BORDER_SUPPORT_KEY), [COLOR_SUPPORT_KEY]: getBlockSupport(blockType, COLOR_SUPPORT_KEY) }); if (getBlockSupport(blockType, '__experimentalSkipFontSizeSerialization')) { filteredStyle = omit(filteredStyle, [['typography', FONT_SIZE_SUPPORT_KEY]]); } props.style = { ...getInlineStyles(filteredStyle), ...props.style }; return props; } /** * Filters registered block settings to extend the block edit wrapper * to apply the desired styles and classnames properly. * * @param {Object} settings Original block settings * @return {Object} Filtered block settings */ export function addEditProps(settings) { if (!hasStyleSupport(settings)) { return settings; } const existingGetEditWrapperProps = settings.getEditWrapperProps; settings.getEditWrapperProps = attributes => { let props = {}; if (existingGetEditWrapperProps) { props = existingGetEditWrapperProps(attributes); } return addSaveProps(props, settings, attributes); }; return settings; } /** * Override the default edit UI to include new inspector controls for * all the custom styles configs. * * @param {Function} BlockEdit Original component * @return {Function} Wrapped component */ export const withBlockControls = createHigherOrderComponent(BlockEdit => props => { const shouldDisplayControls = useDisplayBlockControls(); return createElement(Fragment, null, shouldDisplayControls && createElement(Fragment, null, createElement(TypographyPanel, props), createElement(BorderPanel, props), createElement(ColorEdit, props), createElement(SpacingPanel, props)), createElement(BlockEdit, props)); }, 'withToolbarControls'); addFilter('blocks.registerBlockType', 'core/style/addAttribute', addAttribute); addFilter('blocks.getSaveContent.extraProps', 'core/style/addSaveProps', addSaveProps); addFilter('blocks.registerBlockType', 'core/style/addEditProps', addEditProps); addFilter('editor.BlockEdit', 'core/style/with-block-controls', withBlockControls); //# sourceMappingURL=style.js.map