@wordpress/block-editor
Version:
262 lines (261 loc) • 8.83 kB
JavaScript
// packages/block-editor/src/hooks/block-style-variation.js
import { getBlockTypes, store as blocksStore } from "@wordpress/blocks";
import { useSelect } from "@wordpress/data";
import { useMemo } from "@wordpress/element";
import { toStyles, getBlockSelectors } from "@wordpress/global-styles-engine";
import { usePrivateStyleOverride } from "./utils";
import { getValueFromObjectPath } from "../utils/object";
import { store as blockEditorStore } from "../store";
import { globalStylesDataKey } from "../store/private-keys";
import { unlock } from "../lock-unlock";
import { Fragment, jsx } from "react/jsx-runtime";
var VARIATION_PREFIX = "is-style-";
function getVariationMatches(className) {
if (!className) {
return [];
}
return className.split(/\s+/).reduce((matches, name) => {
if (name.startsWith(VARIATION_PREFIX)) {
const match = name.slice(VARIATION_PREFIX.length);
if (match !== "default") {
matches.push(match);
}
}
return matches;
}, []);
}
function getVariationNameFromClass(className, registeredStyles = []) {
const matches = getVariationMatches(className);
if (!matches) {
return null;
}
for (const variation of matches) {
if (registeredStyles.some((style) => style.name === variation)) {
return variation;
}
}
return null;
}
function OverrideStyles({ override }) {
usePrivateStyleOverride(override);
}
function __unstableBlockStyleVariationOverridesWithConfig({ config }) {
const { getBlockStyles, overrides } = useSelect(
(select) => ({
getBlockStyles: select(blocksStore).getBlockStyles,
overrides: unlock(select(blockEditorStore)).getStyleOverrides()
}),
[]
);
const { getBlockName } = useSelect(blockEditorStore);
const overridesWithConfig = useMemo(() => {
if (!overrides?.length) {
return;
}
const newOverrides = [];
const overriddenClientIds = [];
for (const [, override] of overrides) {
if (override?.variation && override?.clientId && /*
* Because this component overwrites existing style overrides,
* filter out any overrides that are already present in the store.
*/
!overriddenClientIds.includes(override.clientId)) {
const blockName = getBlockName(override.clientId);
const configStyles = config?.styles?.blocks?.[blockName]?.variations?.[override.variation];
if (configStyles) {
const variationConfig = {
settings: config?.settings,
// The variation style data is all that is needed to generate
// the styles for the current application to a block. The variation
// name is updated to match the instance specific class name.
styles: {
blocks: {
[blockName]: {
variations: {
[`${override.variation}-${override.clientId}`]: configStyles
}
}
}
}
};
const blockSelectors = getBlockSelectors(
getBlockTypes(),
override.clientId
);
const hasBlockGapSupport = false;
const hasFallbackGapSupport = true;
const disableLayoutStyles = true;
const disableRootPadding = true;
const variationStyles = toStyles(
variationConfig,
blockSelectors,
hasBlockGapSupport,
hasFallbackGapSupport,
disableLayoutStyles,
disableRootPadding,
{
blockGap: false,
blockStyles: true,
layoutStyles: false,
marginReset: false,
presets: false,
rootPadding: false,
variationStyles: true
}
);
newOverrides.push({
id: `${override.variation}-${override.clientId}`,
css: variationStyles,
__unstableType: "variation",
variation: override.variation,
// The clientId will be stored with the override and used to ensure
// the order of overrides matches the order of blocks so that the
// correct CSS cascade is maintained.
clientId: override.clientId
});
overriddenClientIds.push(override.clientId);
}
}
}
return newOverrides;
}, [config, overrides, getBlockStyles, getBlockName]);
if (!overridesWithConfig || !overridesWithConfig.length) {
return;
}
return /* @__PURE__ */ jsx(Fragment, { children: overridesWithConfig.map((override) => /* @__PURE__ */ jsx(OverrideStyles, { override }, override.id)) });
}
function getVariationStylesWithRefValues(globalStyles, name, variation) {
if (!globalStyles?.styles?.blocks?.[name]?.variations?.[variation]) {
return;
}
const replaceRefs = (variationStyles) => {
Object.keys(variationStyles).forEach((key) => {
const value = variationStyles[key];
if (typeof value === "object" && value !== null) {
if (value.ref !== void 0) {
if (typeof value.ref !== "string" || value.ref.trim() === "") {
delete variationStyles[key];
} else {
const refValue = getValueFromObjectPath(
globalStyles,
value.ref
);
if (refValue) {
variationStyles[key] = refValue;
} else {
delete variationStyles[key];
}
}
} else {
replaceRefs(value);
if (Object.keys(value).length === 0) {
delete variationStyles[key];
}
}
}
});
};
const styles = JSON.parse(
JSON.stringify(
globalStyles.styles.blocks[name].variations[variation]
)
);
replaceRefs(styles);
return styles;
}
function useBlockStyleVariation(name, variation, clientId) {
const { globalSettings, globalStyles } = useSelect((select) => {
const settings = select(blockEditorStore).getSettings();
return {
globalSettings: settings.__experimentalFeatures,
globalStyles: settings[globalStylesDataKey]
};
}, []);
return useMemo(() => {
const variationStyles = getVariationStylesWithRefValues(
{
settings: globalSettings,
styles: globalStyles
},
name,
variation
);
return {
settings: globalSettings,
// The variation style data is all that is needed to generate
// the styles for the current application to a block. The variation
// name is updated to match the instance specific class name.
styles: {
blocks: {
[name]: {
variations: {
[`${variation}-${clientId}`]: variationStyles
}
}
}
}
};
}, [globalSettings, globalStyles, variation, clientId, name]);
}
function useBlockProps({ name, className, clientId }) {
const { getBlockStyles } = useSelect(blocksStore);
const registeredStyles = getBlockStyles(name);
const variation = getVariationNameFromClass(className, registeredStyles);
const variationClass = `${VARIATION_PREFIX}${variation}-${clientId}`;
const { settings, styles } = useBlockStyleVariation(
name,
variation,
clientId
);
const variationStyles = useMemo(() => {
if (!variation) {
return;
}
const variationConfig = { settings, styles };
const blockSelectors = getBlockSelectors(getBlockTypes(), clientId);
const hasBlockGapSupport = false;
const hasFallbackGapSupport = true;
const disableLayoutStyles = true;
const disableRootPadding = true;
return toStyles(
variationConfig,
blockSelectors,
hasBlockGapSupport,
hasFallbackGapSupport,
disableLayoutStyles,
disableRootPadding,
{
blockGap: false,
blockStyles: true,
layoutStyles: false,
marginReset: false,
presets: false,
rootPadding: false,
variationStyles: true
}
);
}, [variation, settings, styles, clientId]);
usePrivateStyleOverride({
id: `variation-${clientId}`,
css: variationStyles,
__unstableType: "variation",
variation,
// The clientId will be stored with the override and used to ensure
// the order of overrides matches the order of blocks so that the
// correct CSS cascade is maintained.
clientId
});
return variation ? { className: variationClass } : {};
}
var block_style_variation_default = {
hasSupport: () => true,
attributeKeys: ["className"],
isMatch: ({ className }) => getVariationMatches(className).length > 0,
useBlockProps
};
export {
__unstableBlockStyleVariationOverridesWithConfig,
block_style_variation_default as default,
getVariationStylesWithRefValues
};
//# sourceMappingURL=block-style-variation.js.map