PluginProbe
Extendify / trunk
Extendify vtrunk
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 0.6.0 All 127 releases
← All changes | src/Agent/lib/block-patch.js +46 -6 3.2.0 → trunk View file →
@@ -68,9 +68,21 @@
68 68 ];
69 69
70 70 // A known slug maps to a theme preset class; anything else routes to inline
71 71 // style.color.* — so "yellow" (no matching token) never lands on a wrong slug.
72 -const routeColors = (attributes, patch, colorSlugs) => {
72 +// Kept inline, a token's own hex stops the block following the palette.
73 +const slugForValue = (value, colorValues) => {
74 + const wanted = colord(value);
75 + if (!wanted.isValid()) return null;
76 + const hex = wanted.toHex();
77 + const match = Object.entries(colorValues ?? {}).find(([, preset]) => {
78 + const parsed = colord(String(preset));
79 + return parsed.isValid() && parsed.toHex() === hex;
80 + });
81 + return match?.[0] ?? null;
82 +};
83 +
84 +const routeColors = (attributes, patch, colorSlugs, colorValues) => {
73 85 const slugs = new Set(colorSlugs ?? []);
74 86 const stripped = {};
75 87 let out = attributes;
76 88 for (const [named, key] of COLOR_CHANNELS) {
@@ -75,9 +87,13 @@
75 87 let out = attributes;
76 88 for (const [named, key] of COLOR_CHANNELS) {
77 89 const value = patch?.[named];
78 90 if (value == null) continue;
79 - if (slugs.has(value)) {
91 + const named_slug = slugs.has(value)
92 + ? value
93 + : slugForValue(value, colorValues);
94 + if (named_slug) {
95 + if (named_slug !== value) out = setPath(out, named, named_slug);
80 96 out = unsetPath(out, `style.color.${key}`);
81 97 continue;
82 98 }
83 99 const parsed = colord(value);
@@ -175,8 +191,24 @@
175 191 };
176 192
177 193 // Re-serializing runs the block's own save(), which core/button needs to render
178 194 // the color/border styles it marks __experimentalSkipSerialization.
195 +// Merging an empty value leaves a dead key and keeps the preset class.
196 +const emptyLeafPaths = (patch, prefix = '') =>
197 + Object.entries(patch ?? {}).flatMap(([key, value]) => {
198 + const path = prefix ? `${prefix}.${key}` : key;
199 + if (isMergeable(value)) return emptyLeafPaths(value, path);
200 + return value === '' ? [path] : [];
201 + });
202 +
203 +const withoutEmptyLeaves = (patch) =>
204 + Object.fromEntries(
205 + Object.entries(patch ?? {}).flatMap(([key, value]) => {
206 + if (isMergeable(value)) return [[key, withoutEmptyLeaves(value)]];
207 + return value === '' ? [] : [[key, value]];
208 + }),
209 + );
210 +
179 211 export const applyBlockPatch = (
180 212 serializedBlock,
181 213 patch,
182 214 clear = [],
@@ -183,14 +215,22 @@
183 215 presetSlugs = {},
184 216 ) => {
185 217 const blocks = parse(serializedBlock).map((block) => {
186 218 if (!block.name) return block;
187 - const merged = deepMerge(block.attributes, remapText(block, patch));
219 + const remapped = remapText(block, patch);
220 + const filled = withoutEmptyLeaves(remapped);
221 + const merged = deepMerge(block.attributes, filled);
188 222 const routed = routeNamedPresets(
189 - routeColors(merged, patch, presetSlugs.color),
190 - patch,
223 + routeColors(merged, filled, presetSlugs.color, presetSlugs.colorValues),
224 + filled,
191 225 presetSlugs,
192 226 );
193 - return { ...block, attributes: applyClears(routed, clear ?? []) };
227 + return {
228 + ...block,
229 + attributes: applyClears(routed, [
230 + ...(clear ?? []),
231 + ...emptyLeafPaths(remapped),
232 + ]),
233 + };
194 234 });
195 235 return serialize(blocks);
196 236 };