UNPKG

@wordpress/editor

Version:
461 lines (459 loc) 16.2 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // packages/editor/src/hooks/push-changes-to-global-styles/index.js var push_changes_to_global_styles_exports = {}; __export(push_changes_to_global_styles_exports, { getChangesToPush: () => getChangesToPush, getStylesUpdate: () => getStylesUpdate }); module.exports = __toCommonJS(push_changes_to_global_styles_exports); var import_hooks = require("@wordpress/hooks"); var import_compose = require("@wordpress/compose"); var import_block_editor = require("@wordpress/block-editor"); var import_components = require("@wordpress/components"); var import_i18n = require("@wordpress/i18n"); var import_blocks = require("@wordpress/blocks"); var import_element = require("@wordpress/element"); var import_data = require("@wordpress/data"); var import_notices = require("@wordpress/notices"); var import_core_data = require("@wordpress/core-data"); var import_lock_unlock = require("../../lock-unlock.cjs"); var import_set_nested_value = __toESM(require("../../utils/set-nested-value.cjs")); var import_hooks2 = require("../../components/global-styles/hooks.cjs"); var import_apply_globally_modal = __toESM(require("./apply-globally-modal.cjs")); var import_jsx_runtime = require("react/jsx-runtime"); var { cleanEmptyObject } = (0, import_lock_unlock.unlock)(import_block_editor.privateApis); var STYLE_PROPERTY = { ...import_blocks.__EXPERIMENTAL_STYLE_PROPERTY, blockGap: { value: ["spacing", "blockGap"] } }; var STYLE_PATH_TO_CSS_VAR_INFIX = { "border.color": "color", "color.background": "color", "color.text": "color", "elements.link.color.text": "color", "elements.link.:hover.color.text": "color", "elements.link.typography.fontFamily": "font-family", "elements.link.typography.fontSize": "font-size", "elements.button.color.text": "color", "elements.button.color.background": "color", "elements.button.typography.fontFamily": "font-family", "elements.button.typography.fontSize": "font-size", "elements.caption.color.text": "color", "elements.heading.color": "color", "elements.heading.color.background": "color", "elements.heading.typography.fontFamily": "font-family", "elements.heading.gradient": "gradient", "elements.heading.color.gradient": "gradient", "elements.h1.color": "color", "elements.h1.color.background": "color", "elements.h1.typography.fontFamily": "font-family", "elements.h1.color.gradient": "gradient", "elements.h2.color": "color", "elements.h2.color.background": "color", "elements.h2.typography.fontFamily": "font-family", "elements.h2.color.gradient": "gradient", "elements.h3.color": "color", "elements.h3.color.background": "color", "elements.h3.typography.fontFamily": "font-family", "elements.h3.color.gradient": "gradient", "elements.h4.color": "color", "elements.h4.color.background": "color", "elements.h4.typography.fontFamily": "font-family", "elements.h4.color.gradient": "gradient", "elements.h5.color": "color", "elements.h5.color.background": "color", "elements.h5.typography.fontFamily": "font-family", "elements.h5.color.gradient": "gradient", "elements.h6.color": "color", "elements.h6.color.background": "color", "elements.h6.typography.fontFamily": "font-family", "elements.h6.color.gradient": "gradient", "color.gradient": "gradient", blockGap: "spacing", "typography.fontSize": "font-size", "typography.fontFamily": "font-family" }; var STYLE_PATH_TO_PRESET_BLOCK_ATTRIBUTE = { "border.color": "borderColor", "color.background": "backgroundColor", "color.text": "textColor", "color.gradient": "gradient", "typography.fontSize": "fontSize", "typography.fontFamily": "fontFamily" }; var SUPPORTED_STYLES = ["border", "color", "spacing", "typography"]; var getValueFromObjectPath = (object, path) => { let value = object; path.forEach((fieldName) => { value = value?.[fieldName]; }); return value; }; var sides = ["top", "right", "bottom", "left"]; function getBorderRows(supports, attributes, blockUserConfig) { const rows = []; const border = attributes.style?.border; const userBorder = blockUserConfig?.border; const colorSupported = supports.includes("borderColor"); const widthSupported = supports.includes("borderWidth"); const styleSupported = supports.includes("borderStyle"); const presetBorderColor = attributes.borderColor; const flatColor = presetBorderColor ? `var:preset|color|${presetBorderColor}` : border?.color; const flatRow = buildBorderScopeRow({ id: "border", primaryPath: ["border"], side: null, color: colorSupported ? flatColor : void 0, width: widthSupported ? border?.width : void 0, style: styleSupported ? border?.style : void 0, userBorder, presetAttributes: presetBorderColor ? ["borderColor"] : [] }); if (flatRow) { rows.push(flatRow); } sides.forEach((side) => { const sideBorder = border?.[side]; const sideRow = buildBorderScopeRow({ id: `border.${side}`, primaryPath: ["border", side], side, color: colorSupported ? sideBorder?.color : void 0, width: widthSupported ? sideBorder?.width : void 0, style: styleSupported ? sideBorder?.style : void 0, userBorder, presetAttributes: [] }); if (sideRow) { rows.push(sideRow); } }); if (supports.includes("borderRadius") && border?.radius !== void 0 && border?.radius !== "") { rows.push({ id: "border.radius", primaryPath: ["border", "radius"], paths: [{ path: ["border", "radius"], value: border.radius }], presetAttributes: [], newValue: border.radius, format: "borderRadius" }); } return rows; } function buildBorderScopeRow({ id, primaryPath, side, color, width, style, userBorder, presetAttributes }) { if (!color && !width && !style) { return null; } const paths = []; const targetSides = side ? [side] : sides; const addChange = (property, value) => { if (value === void 0) { return; } if (!side) { paths.push({ path: ["border", property], value }); } targetSides.forEach((targetSide) => { paths.push({ path: ["border", targetSide, property], value }); }); }; addChange("color", color); addChange("width", width); addChange("style", style); let effectiveStyle = style; if (!style && (color || width)) { const sideStyles = targetSides.map( (targetSide) => userBorder?.[targetSide]?.style ); targetSides.forEach((targetSide, index) => { if (!sideStyles[index]) { paths.push({ path: ["border", targetSide, "style"], value: "solid" }); } }); const sharedStyle = sideStyles.every( (sideStyle) => sideStyle === sideStyles[0] ) ? sideStyles[0] : void 0; effectiveStyle = sharedStyle || "solid"; } return { id, primaryPath, paths, presetAttributes, newValue: { color, width, style: effectiveStyle }, format: "border" }; } function getChangesToPush(supports, attributes, blockUserConfig) { const rows = []; supports.forEach((key) => { if (!STYLE_PROPERTY[key]) { return; } if (key.startsWith("border")) { return; } if (STYLE_PROPERTY[key].rootOnly) { return; } const { value: path } = STYLE_PROPERTY[key]; const presetAttributeKey = path.join("."); const presetAttributeName = STYLE_PATH_TO_PRESET_BLOCK_ATTRIBUTE[presetAttributeKey]; const presetAttributeValue = presetAttributeName ? attributes[presetAttributeName] : void 0; const value = presetAttributeValue ? `var:preset|${STYLE_PATH_TO_CSS_VAR_INFIX[presetAttributeKey]}|${presetAttributeValue}` : getValueFromObjectPath(attributes.style, path); const presetAttributes = presetAttributeValue ? [presetAttributeName] : []; if (key === "linkColor") { const paths = value ? [{ path, value }] : []; const hoverPath = ["elements", "link", ":hover", "color", "text"]; const hoverValue = getValueFromObjectPath( attributes.style, hoverPath ); if (hoverValue) { paths.push({ path: hoverPath, value: hoverValue }); } if (paths.length === 0) { return; } rows.push({ id: presetAttributeKey, primaryPath: path, paths, presetAttributes, newValue: value ?? hoverValue }); return; } if (value) { let format; if (key === "padding" || key === "margin") { format = "spacing"; } else if (key === "blockGap") { format = "blockGap"; } rows.push({ id: presetAttributeKey, primaryPath: path, paths: [{ path, value }], presetAttributes, newValue: value, format }); } }); rows.push(...getBorderRows(supports, attributes, blockUserConfig)); return rows; } function useChangesToPush(name, attributes, userConfig) { const supports = (0, import_data.useSelect)( (select) => { return (0, import_lock_unlock.unlock)(select(import_blocks.store)).getSupportedStyles(name); }, [name] ); const blockUserConfig = userConfig?.styles?.blocks?.[name]; return (0, import_element.useMemo)( () => getChangesToPush(supports, attributes, blockUserConfig), [supports, attributes, blockUserConfig] ); } function getStylesUpdate({ rowsToPush, attributes, userConfig, name }) { if (!rowsToPush || rowsToPush.length === 0) { return null; } const selectedChanges = rowsToPush.flatMap((row) => row.paths); if (selectedChanges.length === 0) { return null; } const { style: blockStyles } = attributes; const newBlockStyles = structuredClone(blockStyles); const newUserConfig = structuredClone(userConfig); for (const { path, value } of selectedChanges) { (0, import_set_nested_value.default)(newBlockStyles, path, void 0); (0, import_set_nested_value.default)( newUserConfig, ["styles", "blocks", name, ...path], value ); } const newBlockAttributes = { style: cleanEmptyObject(newBlockStyles) }; for (const presetAttribute of rowsToPush.flatMap( (row) => row.presetAttributes )) { newBlockAttributes[presetAttribute] = void 0; } return { newBlockAttributes, newUserConfig }; } function PushChangesToGlobalStylesControl({ name, attributes, setAttributes }) { const { user: userConfig, setUser: setUserConfig } = (0, import_hooks2.useGlobalStyles)(); const rows = useChangesToPush(name, attributes, userConfig); const [isModalOpen, setIsModalOpen] = (0, import_element.useState)(false); const { __unstableMarkNextChangeAsNotPersistent } = (0, import_data.useDispatch)(import_block_editor.store); const { createSuccessNotice } = (0, import_data.useDispatch)(import_notices.store); const pushChanges = (0, import_element.useCallback)( (rowsToPush) => { const update = getStylesUpdate({ rowsToPush, attributes, userConfig, name }); if (!update) { return; } const { newBlockAttributes, newUserConfig } = update; __unstableMarkNextChangeAsNotPersistent(); setAttributes(newBlockAttributes); setUserConfig(newUserConfig, { undoIgnore: true }); createSuccessNotice( (0, import_i18n.sprintf)( // translators: %s: Title of the block e.g. 'Heading'. (0, import_i18n.__)("%s styles applied."), (0, import_blocks.getBlockType)(name).title ), { type: "snackbar", actions: [ { label: (0, import_i18n.__)("Undo"), onClick() { __unstableMarkNextChangeAsNotPersistent(); setAttributes(attributes); setUserConfig(userConfig, { undoIgnore: true }); } } ] } ); }, [ __unstableMarkNextChangeAsNotPersistent, attributes, createSuccessNotice, name, setAttributes, setUserConfig, userConfig ] ); return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( import_components.BaseControl, { className: "editor-push-changes-to-global-styles-control", help: (0, import_i18n.sprintf)( // translators: %s: Title of the block e.g. 'Heading'. (0, import_i18n.__)( "Review and apply this block’s typography, spacing, dimensions, and color styles to all %s blocks." ), (0, import_blocks.getBlockType)(name).title ), children: [ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.BaseControl.VisualLabel, { children: (0, import_i18n.__)("Styles") }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.Button, { __next40pxDefaultSize: true, variant: "secondary", accessibleWhenDisabled: true, disabled: rows.length === 0, onClick: () => setIsModalOpen(true), children: (0, import_i18n.__)("Apply globally") } ), isModalOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_apply_globally_modal.default, { name, rows, onApply: pushChanges, onRequestClose: () => setIsModalOpen(false) } ) ] } ); } function PushChangesToGlobalStyles(props) { const blockEditingMode = (0, import_block_editor.useBlockEditingMode)(); const isBlockBasedTheme = (0, import_data.useSelect)( (select) => select(import_core_data.store).getCurrentTheme()?.is_block_theme, [] ); const supportsStyles = SUPPORTED_STYLES.some( (feature) => (0, import_blocks.hasBlockSupport)(props.name, feature) ); const isDisplayed = blockEditingMode === "default" && supportsStyles && isBlockBasedTheme; if (!isDisplayed) { return null; } return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_block_editor.InspectorAdvancedControls, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PushChangesToGlobalStylesControl, { ...props }) }); } var withPushChangesToGlobalStyles = (0, import_compose.createHigherOrderComponent)( (BlockEdit) => (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BlockEdit, { ...props }, "edit"), props.isSelected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PushChangesToGlobalStyles, { ...props }) ] }) ); (0, import_hooks.addFilter)( "editor.BlockEdit", "core/editor/push-changes-to-global-styles", withPushChangesToGlobalStyles ); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { getChangesToPush, getStylesUpdate }); //# sourceMappingURL=index.cjs.map