UNPKG

@wordpress/block-editor

Version:
272 lines (271 loc) 7.92 kB
// packages/block-editor/src/hooks/style.js import { useMemo } from "@wordpress/element"; import { addFilter } from "@wordpress/hooks"; import { getBlockSupport, hasBlockSupport, __EXPERIMENTAL_ELEMENTS as ELEMENTS } from "@wordpress/blocks"; import { useInstanceId } from "@wordpress/compose"; import { getCSSRules, compileCSS } from "@wordpress/style-engine"; import { BACKGROUND_SUPPORT_KEY, BackgroundImagePanel } from "./background"; import { BORDER_SUPPORT_KEY, BorderPanel, SHADOW_SUPPORT_KEY } from "./border"; import { COLOR_SUPPORT_KEY, ColorEdit } from "./color"; import { TypographyPanel, TYPOGRAPHY_SUPPORT_KEY, TYPOGRAPHY_SUPPORT_KEYS } from "./typography"; import { DIMENSIONS_SUPPORT_KEY, SPACING_SUPPORT_KEY, DimensionsPanel } from "./dimensions"; import { shouldSkipSerialization, useStyleOverride, useBlockSettings } from "./utils"; import { scopeSelector } from "../components/global-styles/utils"; import { useBlockEditingMode } from "../components/block-editing-mode"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; var styleSupportKeys = [ ...TYPOGRAPHY_SUPPORT_KEYS, BORDER_SUPPORT_KEY, COLOR_SUPPORT_KEY, DIMENSIONS_SUPPORT_KEY, BACKGROUND_SUPPORT_KEY, SPACING_SUPPORT_KEY, SHADOW_SUPPORT_KEY ]; var hasStyleSupport = (nameOrType) => styleSupportKeys.some((key) => hasBlockSupport(nameOrType, key)); function getInlineStyles(styles = {}) { const output = {}; getCSSRules(styles).forEach((rule) => { output[rule.key] = rule.value; }); return output; } function addAttribute(settings) { if (!hasStyleSupport(settings)) { return settings; } if (!settings.attributes.style) { Object.assign(settings.attributes, { style: { type: "object" } }); } return settings; } var skipSerializationPathsEdit = { [`${BORDER_SUPPORT_KEY}.__experimentalSkipSerialization`]: ["border"], [`${COLOR_SUPPORT_KEY}.__experimentalSkipSerialization`]: [ COLOR_SUPPORT_KEY ], [`${TYPOGRAPHY_SUPPORT_KEY}.__experimentalSkipSerialization`]: [ TYPOGRAPHY_SUPPORT_KEY ], [`${DIMENSIONS_SUPPORT_KEY}.__experimentalSkipSerialization`]: [ DIMENSIONS_SUPPORT_KEY ], [`${SPACING_SUPPORT_KEY}.__experimentalSkipSerialization`]: [ SPACING_SUPPORT_KEY ], [`${SHADOW_SUPPORT_KEY}.__experimentalSkipSerialization`]: [ SHADOW_SUPPORT_KEY ] }; var skipSerializationPathsSave = { ...skipSerializationPathsEdit, [`${DIMENSIONS_SUPPORT_KEY}.aspectRatio`]: [ `${DIMENSIONS_SUPPORT_KEY}.aspectRatio` ], // Skip serialization of aspect ratio in save mode. [`${BACKGROUND_SUPPORT_KEY}`]: [BACKGROUND_SUPPORT_KEY] // Skip serialization of background support in save mode. }; var skipSerializationPathsSaveChecks = { [`${DIMENSIONS_SUPPORT_KEY}.aspectRatio`]: true, [`${BACKGROUND_SUPPORT_KEY}`]: true }; var renamedFeatures = { gradients: "gradient" }; function omitStyle(style, paths, preserveReference = false) { if (!style) { return style; } let newStyle = style; if (!preserveReference) { newStyle = JSON.parse(JSON.stringify(style)); } if (!Array.isArray(paths)) { paths = [paths]; } paths.forEach((path) => { if (!Array.isArray(path)) { path = path.split("."); } if (path.length > 1) { const [firstSubpath, ...restPath] = path; omitStyle(newStyle[firstSubpath], [restPath], true); } else if (path.length === 1) { delete newStyle[path[0]]; } }); return newStyle; } function addSaveProps(props, blockNameOrType, attributes, skipPaths = skipSerializationPathsSave) { if (!hasStyleSupport(blockNameOrType)) { return props; } let { style } = attributes; Object.entries(skipPaths).forEach(([indicator, path]) => { const skipSerialization = skipSerializationPathsSaveChecks[indicator] || getBlockSupport(blockNameOrType, indicator); if (skipSerialization === true) { style = omitStyle(style, path); } if (Array.isArray(skipSerialization)) { skipSerialization.forEach((featureName) => { const feature = renamedFeatures[featureName] || featureName; style = omitStyle(style, [[...path, feature]]); }); } }); props.style = { ...getInlineStyles(style), ...props.style }; return props; } function BlockStyleControls({ clientId, name, setAttributes, __unstableParentLayout }) { const settings = useBlockSettings(name, __unstableParentLayout); const blockEditingMode = useBlockEditingMode(); const passedProps = { clientId, name, setAttributes, settings: { ...settings, typography: { ...settings.typography, // The text alignment UI for individual blocks is rendered in // the block toolbar, so disable it here. textAlign: false } } }; if (blockEditingMode !== "default") { return null; } return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(ColorEdit, { ...passedProps }), /* @__PURE__ */ jsx(BackgroundImagePanel, { ...passedProps }), /* @__PURE__ */ jsx(TypographyPanel, { ...passedProps }), /* @__PURE__ */ jsx(BorderPanel, { ...passedProps }), /* @__PURE__ */ jsx(DimensionsPanel, { ...passedProps }) ] }); } var style_default = { edit: BlockStyleControls, hasSupport: hasStyleSupport, addSaveProps, attributeKeys: ["style"], useBlockProps }; var elementTypes = [ { elementType: "button" }, { elementType: "link", pseudo: [":hover"] }, { elementType: "heading", elements: ["h1", "h2", "h3", "h4", "h5", "h6"] } ]; var STYLE_BLOCK_PROPS_REFERENCE = {}; function useBlockProps({ name, style }) { const blockElementsContainerIdentifier = useInstanceId( STYLE_BLOCK_PROPS_REFERENCE, "wp-elements" ); const baseElementSelector = `.${blockElementsContainerIdentifier}`; const blockElementStyles = style?.elements; const styles = useMemo(() => { if (!blockElementStyles) { return; } const elementCSSRules = []; elementTypes.forEach(({ elementType, pseudo, elements }) => { const skipSerialization = shouldSkipSerialization( name, COLOR_SUPPORT_KEY, elementType ); if (skipSerialization) { return; } const elementStyles = blockElementStyles?.[elementType]; if (elementStyles) { const selector = scopeSelector( baseElementSelector, ELEMENTS[elementType] ); elementCSSRules.push( compileCSS(elementStyles, { selector }) ); if (pseudo) { pseudo.forEach((pseudoSelector) => { if (elementStyles[pseudoSelector]) { elementCSSRules.push( compileCSS(elementStyles[pseudoSelector], { selector: scopeSelector( baseElementSelector, `${ELEMENTS[elementType]}${pseudoSelector}` ) }) ); } }); } } if (elements) { elements.forEach((element) => { if (blockElementStyles[element]) { elementCSSRules.push( compileCSS(blockElementStyles[element], { selector: scopeSelector( baseElementSelector, ELEMENTS[element] ) }) ); } }); } }); return elementCSSRules.length > 0 ? elementCSSRules.join("") : void 0; }, [baseElementSelector, blockElementStyles, name]); useStyleOverride({ css: styles }); return addSaveProps( { className: blockElementsContainerIdentifier }, name, { style }, skipSerializationPathsEdit ); } addFilter( "blocks.registerBlockType", "core/style/addAttribute", addAttribute ); export { addSaveProps, style_default as default, getInlineStyles, omitStyle }; //# sourceMappingURL=style.js.map