@wordpress/editor
Version:
Enhanced block editor for WordPress posts.
461 lines (459 loc) • 16.2 kB
JavaScript
;
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