PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
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 +51 -9 3.1.63.2.1 View file →
@@ -1,4 +1,5 @@
1 +import { RICH_TEXT_ATTRIBUTES } from '@agent/lib/block-schema';
1 2 import { getBlockType, parse, serialize } from '@wordpress/blocks';
2 3 import { colord } from 'colord';
3 4
4 5 const isMergeable = (value) =>
@@ -67,9 +68,21 @@
67 68 ];
68 69
69 70 // A known slug maps to a theme preset class; anything else routes to inline
70 71 // style.color.* — so "yellow" (no matching token) never lands on a wrong slug.
71 -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) => {
72 85 const slugs = new Set(colorSlugs ?? []);
73 86 const stripped = {};
74 87 let out = attributes;
75 88 for (const [named, key] of COLOR_CHANNELS) {
@@ -74,9 +87,13 @@
74 87 let out = attributes;
75 88 for (const [named, key] of COLOR_CHANNELS) {
76 89 const value = patch?.[named];
77 90 if (value == null) continue;
78 - 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);
79 96 out = unsetPath(out, `style.color.${key}`);
80 97 continue;
81 98 }
82 99 const parsed = colord(value);
@@ -162,19 +179,36 @@
162 179 }
163 180 return out;
164 181 };
165 182
166 -// The model always says `text`; blocks whose rich text is `content` need the remap.
183 +// The model always says `text`; blocks that keep theirs elsewhere need the remap.
167 184 const remapText = (block, patch) => {
168 185 if (patch?.text == null) return patch;
169 186 const attributes = getBlockType(block.name)?.attributes ?? {};
170 - if (attributes.text || !attributes.content) return patch;
187 + const real = RICH_TEXT_ATTRIBUTES.find((name) => attributes[name]);
188 + if (!real || real === 'text') return patch;
171 189 const { text, ...rest } = patch;
172 - return { ...rest, content: text };
190 + return { ...rest, [real]: text };
173 191 };
174 192
175 193 // Re-serializing runs the block's own save(), which core/button needs to render
176 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 +
177 211 export const applyBlockPatch = (
178 212 serializedBlock,
179 213 patch,
180 214 clear = [],
@@ -181,14 +215,22 @@
181 215 presetSlugs = {},
182 216 ) => {
183 217 const blocks = parse(serializedBlock).map((block) => {
184 218 if (!block.name) return block;
185 - 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);
186 222 const routed = routeNamedPresets(
187 - routeColors(merged, patch, presetSlugs.color),
188 - patch,
223 + routeColors(merged, filled, presetSlugs.color, presetSlugs.colorValues),
224 + filled,
189 225 presetSlugs,
190 226 );
191 - return { ...block, attributes: applyClears(routed, clear ?? []) };
227 + return {
228 + ...block,
229 + attributes: applyClears(routed, [
230 + ...(clear ?? []),
231 + ...emptyLeafPaths(remapped),
232 + ]),
233 + };
192 234 });
193 235 return serialize(blocks);
194 236 };