UNPKG

@gechiui/block-editor

Version:
275 lines (223 loc) 10.1 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.addEditProps = addEditProps; exports.addSaveProps = addSaveProps; exports.getInlineStyles = getInlineStyles; exports.withBlockControls = void 0; var _element = require("@gechiui/element"); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _lodash = require("lodash"); var _classnames = _interopRequireDefault(require("classnames")); var _hooks = require("@gechiui/hooks"); var _blocks = require("@gechiui/blocks"); var _compose = require("@gechiui/compose"); var _blockList = _interopRequireDefault(require("../components/block-list")); var _border = require("./border"); var _color = require("./color"); var _typography = require("./typography"); var _dimensions = require("./dimensions"); var _useDisplayBlockControls = _interopRequireDefault(require("../components/use-display-block-controls")); /** * External dependencies */ /** * GeChiUI dependencies */ /** * Internal dependencies */ const styleSupportKeys = [..._typography.TYPOGRAPHY_SUPPORT_KEYS, _border.BORDER_SUPPORT_KEY, _color.COLOR_SUPPORT_KEY, _dimensions.SPACING_SUPPORT_KEY]; const hasStyleSupport = blockType => styleSupportKeys.some(key => (0, _blocks.hasBlockSupport)(blockType, key)); const VARIABLE_REFERENCE_PREFIX = 'var:'; const VARIABLE_PATH_SEPARATOR_TOKEN_ATTRIBUTE = '|'; const VARIABLE_PATH_SEPARATOR_TOKEN_STYLE = '--'; function compileStyleValue(uncompiledValue) { if ((0, _lodash.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(--gc--${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. */ function getInlineStyles() { let styles = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; const ignoredStyles = ['spacing.blockGap']; const output = {}; Object.keys(_blocks.__EXPERIMENTAL_STYLE_PROPERTY).forEach(propKey => { const path = _blocks.__EXPERIMENTAL_STYLE_PROPERTY[propKey].value; const subPaths = _blocks.__EXPERIMENTAL_STYLE_PROPERTY[propKey].properties; // Ignore styles on elements because they are handled on the server. if ((0, _lodash.has)(styles, path) && 'elements' !== (0, _lodash.first)(path)) { // Checking if style value is a string allows for shorthand css // option and backwards compatibility for border radius support. const styleValue = (0, _lodash.get)(styles, path); if (!!subPaths && !(0, _lodash.isString)(styleValue)) { Object.entries(subPaths).forEach(entry => { const [name, subPath] = entry; const value = (0, _lodash.get)(styleValue, [subPath]); if (value) { output[name] = compileStyleValue(value); } }); } else if (!ignoredStyles.includes(path.join('.'))) { output[propKey] = compileStyleValue((0, _lodash.get)(styles, path)); } } }); return output; } function compileElementsStyles(selector) { let elements = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return (0, _lodash.map)(elements, (styles, element) => { const elementStyles = getInlineStyles(styles); if (!(0, _lodash.isEmpty)(elementStyles)) { return [`.${selector} ${_blocks.__EXPERIMENTAL_ELEMENTS[element]}{`, ...(0, _lodash.map)(elementStyles, (value, property) => `\t${(0, _lodash.kebabCase)(property)}: ${value};`), '}'].join('\n'); } return ''; }).join('\n'); } /** * 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; } /** * A dictionary of paths to flag skipping block support serialization as the key, * with values providing the style paths to be omitted from serialization. * * @constant * @type {Record<string, string[]>} */ const skipSerializationPathsEdit = { [`${_border.BORDER_SUPPORT_KEY}.__experimentalSkipSerialization`]: ['border'], [`${_color.COLOR_SUPPORT_KEY}.__experimentalSkipSerialization`]: [_color.COLOR_SUPPORT_KEY], [`${_typography.TYPOGRAPHY_SUPPORT_KEY}.__experimentalSkipSerialization`]: [_typography.TYPOGRAPHY_SUPPORT_KEY], [`${_dimensions.SPACING_SUPPORT_KEY}.__experimentalSkipSerialization`]: ['spacing'] }; /** * A dictionary of paths to flag skipping block support serialization as the key, * with values providing the style paths to be omitted from serialization. * * Extends the Edit skip paths to enable skipping additional paths in just * the Save component. This allows a block support to be serialized within the * editor, while using an alternate approach, such as server-side rendering, when * the support is saved. * * @constant * @type {Record<string, string[]>} */ const skipSerializationPathsSave = { ...skipSerializationPathsEdit, [`${_dimensions.SPACING_SUPPORT_KEY}`]: ['spacing.blockGap'] }; /** * 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. * @param {?Record<string, string[]>} skipPaths An object of keys and paths to skip serialization. * * @return {Object} Filtered props applied to save element. */ function addSaveProps(props, blockType, attributes) { let skipPaths = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : skipSerializationPathsSave; if (!hasStyleSupport(blockType)) { return props; } let { style } = attributes; (0, _lodash.forEach)(skipPaths, (path, indicator) => { if ((0, _blocks.getBlockSupport)(blockType, indicator)) { style = (0, _lodash.omit)(style, path); } }); props.style = { ...getInlineStyles(style), ...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. */ 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, skipSerializationPathsEdit); }; 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. */ const withBlockControls = (0, _compose.createHigherOrderComponent)(BlockEdit => props => { const shouldDisplayControls = (0, _useDisplayBlockControls.default)(); return (0, _element.createElement)(_element.Fragment, null, shouldDisplayControls && (0, _element.createElement)(_element.Fragment, null, (0, _element.createElement)(_color.ColorEdit, props), (0, _element.createElement)(_typography.TypographyPanel, props), (0, _element.createElement)(_border.BorderPanel, props), (0, _element.createElement)(_dimensions.DimensionsPanel, props)), (0, _element.createElement)(BlockEdit, props)); }, 'withToolbarControls'); /** * Override the default block element to include duotone styles. * * @param {Function} BlockListBlock Original component * @return {Function} Wrapped component */ exports.withBlockControls = withBlockControls; const withElementsStyles = (0, _compose.createHigherOrderComponent)(BlockListBlock => props => { var _props$attributes$sty, _props$attributes$sty2; const elements = (_props$attributes$sty = props.attributes.style) === null || _props$attributes$sty === void 0 ? void 0 : _props$attributes$sty.elements; const blockElementsContainerIdentifier = `gc-elements-${(0, _compose.useInstanceId)(BlockListBlock)}`; const styles = compileElementsStyles(blockElementsContainerIdentifier, (_props$attributes$sty2 = props.attributes.style) === null || _props$attributes$sty2 === void 0 ? void 0 : _props$attributes$sty2.elements); const element = (0, _element.useContext)(_blockList.default.__unstableElementContext); return (0, _element.createElement)(_element.Fragment, null, elements && element && (0, _element.createPortal)((0, _element.createElement)("style", { dangerouslySetInnerHTML: { __html: styles } }), element), (0, _element.createElement)(BlockListBlock, (0, _extends2.default)({}, props, { className: elements ? (0, _classnames.default)(props.className, blockElementsContainerIdentifier) : props.className }))); }); (0, _hooks.addFilter)('blocks.registerBlockType', 'core/style/addAttribute', addAttribute); (0, _hooks.addFilter)('blocks.getSaveContent.extraProps', 'core/style/addSaveProps', addSaveProps); (0, _hooks.addFilter)('blocks.registerBlockType', 'core/style/addEditProps', addEditProps); (0, _hooks.addFilter)('editor.BlockEdit', 'core/style/with-block-controls', withBlockControls); (0, _hooks.addFilter)('editor.BlockListBlock', 'core/editor/with-elements-styles', withElementsStyles); //# sourceMappingURL=style.js.map