PluginProbe
Extendify / 3.2.2
Extendify v3.2.2
3.2.2 3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 All 128 releases
← All changes | src/Shared/lib/vibe-globals.js +21 -89 3.1.6 → 3.2.2 View file →
@@ -1,5 +1,8 @@
1 -import { isObject } from '@shared/lib/utils';
1 +import {
2 + applyOwnedSection,
3 + collectOwnedPaths,
4 +} from '@shared/lib/owned-globals';
2 5
3 6 const ownedSettings = ['layout', 'typography', 'custom'];
4 7 // Per-leaf, so clearing a heading size leaves fontFamily to the fonts layer.
5 8 // WordPress reads duotone per block name, never per variation, so blocks is owned here.
@@ -4,20 +7,8 @@
4 7 // Per-leaf, so clearing a heading size leaves fontFamily to the fonts layer.
5 8 // WordPress reads duotone per block name, never per variation, so blocks is owned here.
6 9 const ownedStyles = ['typography', 'elements', 'blocks'];
7 10
8 -const leafPaths = (value, prefix) => {
9 - // PHP serializes an empty object as []; as a leaf it would purge the branch.
10 - if (Array.isArray(value) && value.length === 0) return [];
11 - if (!isObject(value)) return [prefix];
12 -
13 - const entries = Object.entries(value);
14 - // Vibes ship `elements: {}` to mean none; as a leaf it would purge fonts too.
15 - if (entries.length === 0) return [];
16 -
17 - return entries.flatMap(([key, child]) => leafPaths(child, [...prefix, key]));
18 -};
19 -
20 11 // The fonts and palette layers own these; a declaring payload is ignored.
21 12 const isExcludedPath = (section, path) => {
22 13 if (path[path.length - 1] === 'fontFamily') return true;
23 14 if (section !== 'settings') return false;
@@ -24,89 +15,29 @@
24 15 if (path[0] === 'color') return true;
25 16 return path[0] === 'typography' && path[1] === 'fontFamilies';
26 17 };
27 18
28 -const collectOwnedPaths = (vibes, section, roots) => {
29 - const paths = new Map();
30 -
31 - for (const vibe of Object.values(vibes)) {
32 - const source = vibe?.[section];
33 - if (!isObject(source)) continue;
34 -
35 - for (const key of roots) {
36 - if (!(key in source)) continue;
37 -
38 - for (const path of leafPaths(source[key], [key])) {
39 - if (isExcludedPath(section, path)) continue;
40 - paths.set(path.join('.'), path);
41 - }
42 - }
43 - }
44 -
45 - return [...paths.values()];
46 -};
47 -
48 -const valueAtPath = (source, path) =>
49 - path.reduce(
50 - (value, key) => (isObject(value) ? value[key] : undefined),
51 - source,
52 - );
53 -
54 -const withoutPath = (source, [key, ...rest]) => {
55 - if (!isObject(source) || !(key in source)) return source;
56 -
57 - const updated = { ...source };
58 -
59 - if (rest.length === 0) {
60 - delete updated[key];
61 - return updated;
62 - }
63 -
64 - const child = withoutPath(updated[key], rest);
65 -
66 - if (isObject(child) && Object.keys(child).length === 0) {
67 - delete updated[key];
68 - } else {
69 - updated[key] = child;
70 - }
71 -
72 - return updated;
73 -};
74 -
75 -const withPath = (source, [key, ...rest], value) => {
76 - const updated = isObject(source) ? { ...source } : {};
77 - updated[key] =
78 - rest.length === 0 ? value : withPath(updated[key], rest, value);
79 - return updated;
80 -};
81 -
82 -// Every vibe's leaves are purged first, so a switch leaves none of the last one behind.
83 -// A vibe that declares nothing lets the theme's own theme.json surface again.
84 -const applySection = (current, incoming, ownedPaths) => {
85 - const purged = ownedPaths.reduce(
86 - (section, path) => withoutPath(section, path),
87 - current,
88 - );
89 -
90 - if (!isObject(incoming)) return purged;
91 -
92 - return ownedPaths.reduce((section, path) => {
93 - const value = valueAtPath(incoming, path);
94 - return value === undefined ? section : withPath(section, path, value);
95 - }, purged);
96 -};
97 -
98 19 export const ownedSettingPaths = (vibes) =>
99 - collectOwnedPaths(vibes, 'settings', ownedSettings);
20 + collectOwnedPaths({
21 + payloads: vibes,
22 + section: 'settings',
23 + roots: ownedSettings,
24 + exclude: isExcludedPath,
25 + });
100 26
101 27 export const ownedStylePaths = (vibes) =>
102 - collectOwnedPaths(vibes, 'styles', ownedStyles);
28 + collectOwnedPaths({
29 + payloads: vibes,
30 + section: 'styles',
31 + roots: ownedStyles,
32 + exclude: isExcludedPath,
33 + });
103 34
104 35 export const applyVibeGlobals = ({ currentSettings, vibeSettings, vibes }) =>
105 - applySection(currentSettings, vibeSettings, ownedSettingPaths(vibes));
36 + applyOwnedSection(currentSettings, vibeSettings, ownedSettingPaths(vibes));
106 37
107 38 export const applyVibeStyles = ({ currentStyles, vibeStyles, vibes }) =>
108 - applySection(currentStyles, vibeStyles, ownedStylePaths(vibes));
39 + applyOwnedSection(currentStyles, vibeStyles, ownedStylePaths(vibes));
109 40
110 41 // A fonts or colors write may not move vibe-owned leaves.
111 42 export const preserveVibeSettings = ({
112 43 mergedSettings,
@@ -111,12 +42,13 @@
111 42 export const preserveVibeSettings = ({
112 43 mergedSettings,
113 44 currentSettings,
114 45 vibes,
115 -}) => applySection(mergedSettings, currentSettings, ownedSettingPaths(vibes));
46 +}) =>
47 + applyOwnedSection(mergedSettings, currentSettings, ownedSettingPaths(vibes));
116 48
117 49 export const preserveVibeStyles = ({ mergedStyles, currentStyles, vibes }) =>
118 - applySection(mergedStyles, currentStyles, ownedStylePaths(vibes));
50 + applyOwnedSection(mergedStyles, currentStyles, ownedStylePaths(vibes));
119 51
120 52 // natural-1 is what the theme ships, so writing it would only restate the theme.
121 53 export const vibeGlobalsEntry = (vibes, selectedVibe) =>
122 54 selectedVibe === 'natural-1' ? undefined : vibes?.[selectedVibe];