@particle-academy/fancy-cms-ui 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +395 -0
- package/LICENSE +21 -0
- package/agent-guide/professional-pages.md +107 -0
- package/dist/{chunk-SYRU2X45.js → chunk-IOMIYI45.js} +6 -4
- package/dist/{chunk-SYRU2X45.js.map → chunk-IOMIYI45.js.map} +1 -1
- package/dist/{chunk-LY6ID2J2.js → chunk-SJYKJ6SG.js} +282 -78
- package/dist/chunk-SJYKJ6SG.js.map +1 -0
- package/dist/{chunk-R7HDS4VG.js → chunk-V6QIOJI7.js} +3 -3
- package/dist/{chunk-R7HDS4VG.js.map → chunk-V6QIOJI7.js.map} +1 -1
- package/dist/editor.cjs +274 -70
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.d.cts +2 -2
- package/dist/editor.d.ts +2 -2
- package/dist/editor.js +3 -3
- package/dist/index.cjs +283 -77
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -4
- package/dist/react.cjs +253 -52
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +2 -2
- package/dist/{registry-CUNaBqTs.d.cts → registry-B4FaQDip.d.cts} +26 -0
- package/dist/{registry-CUNaBqTs.d.ts → registry-B4FaQDip.d.ts} +26 -0
- package/dist/{useEditor-wdlYQMHg.d.cts → useEditor-CIRm2oi-.d.cts} +1 -1
- package/dist/{useEditor-aPH5falI.d.ts → useEditor-DZDD9qpS.d.ts} +1 -1
- package/package.json +107 -105
- package/dist/chunk-LY6ID2J2.js.map +0 -1
package/dist/editor.cjs
CHANGED
|
@@ -32,6 +32,15 @@ function emptyDoc(id, slug = "/") {
|
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
// src/document/own.ts
|
|
36
|
+
var has = Object.prototype.hasOwnProperty;
|
|
37
|
+
function own(map, key) {
|
|
38
|
+
return map != null && has.call(map, key) ? map[key] : void 0;
|
|
39
|
+
}
|
|
40
|
+
function setOwn(map, key, value) {
|
|
41
|
+
Object.defineProperty(map, key, { value, writable: true, enumerable: true, configurable: true });
|
|
42
|
+
}
|
|
43
|
+
|
|
35
44
|
// src/document/migrate.ts
|
|
36
45
|
function normalizeDoc(input3) {
|
|
37
46
|
if (hasNodeMap(input3)) return input3;
|
|
@@ -49,7 +58,7 @@ function migrateDocVerbose(input3) {
|
|
|
49
58
|
const ordered = [];
|
|
50
59
|
const seen = /* @__PURE__ */ new Set();
|
|
51
60
|
for (const id of sections) {
|
|
52
|
-
if (!normalized.nodes
|
|
61
|
+
if (!own(normalized.nodes, id)) {
|
|
53
62
|
danglingIds.push(id);
|
|
54
63
|
continue;
|
|
55
64
|
}
|
|
@@ -63,7 +72,7 @@ function migrateDocVerbose(input3) {
|
|
|
63
72
|
let prev = null;
|
|
64
73
|
for (const id of finalOrder) {
|
|
65
74
|
const key = fancyDocCommons.fractionalKey(prev, null);
|
|
66
|
-
nodes
|
|
75
|
+
setOwn(nodes, id, { ...own(nodes, id), order: key });
|
|
67
76
|
prev = key;
|
|
68
77
|
}
|
|
69
78
|
const { sections: _dropped, ...rest } = legacy;
|
|
@@ -92,7 +101,7 @@ function descendantIds(doc, id) {
|
|
|
92
101
|
return fancyDocCommons.descendantsOf(doc, id);
|
|
93
102
|
}
|
|
94
103
|
function patchNode(doc, id, patch) {
|
|
95
|
-
const node = doc.nodes
|
|
104
|
+
const node = own(doc.nodes, id);
|
|
96
105
|
return {
|
|
97
106
|
...doc,
|
|
98
107
|
nodes: { ...doc.nodes, [id]: { ...node, ...patch } },
|
|
@@ -106,8 +115,8 @@ function reduce(doc, op, opts = {}) {
|
|
|
106
115
|
};
|
|
107
116
|
switch (op.t) {
|
|
108
117
|
case "insert_node": {
|
|
109
|
-
if (doc.nodes
|
|
110
|
-
if (op.node.parent !== null && !doc.nodes
|
|
118
|
+
if (own(doc.nodes, op.node.id)) return invalid("node id already exists");
|
|
119
|
+
if (op.node.parent !== null && !own(doc.nodes, op.node.parent)) return invalid("parent not found");
|
|
111
120
|
return {
|
|
112
121
|
...doc,
|
|
113
122
|
nodes: { ...doc.nodes, [op.node.id]: op.node },
|
|
@@ -115,11 +124,11 @@ function reduce(doc, op, opts = {}) {
|
|
|
115
124
|
};
|
|
116
125
|
}
|
|
117
126
|
case "remove_node": {
|
|
118
|
-
if (!doc.nodes
|
|
127
|
+
if (!own(doc.nodes, op.id)) return invalid("node not found");
|
|
119
128
|
const dead = /* @__PURE__ */ new Set([op.id, ...descendantIds(doc, op.id)]);
|
|
120
129
|
const nodes = {};
|
|
121
130
|
for (const id of Object.keys(doc.nodes)) {
|
|
122
|
-
if (!dead.has(id)) nodes
|
|
131
|
+
if (!dead.has(id)) setOwn(nodes, id, own(doc.nodes, id));
|
|
123
132
|
}
|
|
124
133
|
return {
|
|
125
134
|
...doc,
|
|
@@ -128,10 +137,10 @@ function reduce(doc, op, opts = {}) {
|
|
|
128
137
|
};
|
|
129
138
|
}
|
|
130
139
|
case "move_node": {
|
|
131
|
-
const node = doc.nodes
|
|
140
|
+
const node = own(doc.nodes, op.id);
|
|
132
141
|
if (!node) return invalid("node not found");
|
|
133
142
|
if (op.parent === op.id) return invalid("cannot parent a node to itself");
|
|
134
|
-
if (op.parent !== null && !doc.nodes
|
|
143
|
+
if (op.parent !== null && !own(doc.nodes, op.parent)) return invalid("new parent not found");
|
|
135
144
|
if (op.parent !== null && descendantIds(doc, op.id).includes(op.parent)) {
|
|
136
145
|
return invalid("move would create a cycle");
|
|
137
146
|
}
|
|
@@ -142,34 +151,35 @@ function reduce(doc, op, opts = {}) {
|
|
|
142
151
|
};
|
|
143
152
|
}
|
|
144
153
|
case "set_node_props": {
|
|
145
|
-
|
|
154
|
+
const node = own(doc.nodes, op.id);
|
|
155
|
+
if (!node) return invalid("node not found");
|
|
146
156
|
return patchNode(doc, op.id, {
|
|
147
|
-
props: { ...
|
|
157
|
+
props: { ...node.props, ...op.patch }
|
|
148
158
|
});
|
|
149
159
|
}
|
|
150
160
|
case "set_layout": {
|
|
151
|
-
if (!doc.nodes
|
|
161
|
+
if (!own(doc.nodes, op.id)) return invalid("node not found");
|
|
152
162
|
return patchNode(doc, op.id, { layout: op.layout });
|
|
153
163
|
}
|
|
154
164
|
case "set_style": {
|
|
155
|
-
const node = doc.nodes
|
|
165
|
+
const node = own(doc.nodes, op.id);
|
|
156
166
|
if (!node) return invalid("node not found");
|
|
157
|
-
const prev = node.style
|
|
167
|
+
const prev = own(node.style, op.breakpoint) ?? {};
|
|
158
168
|
return patchNode(doc, op.id, {
|
|
159
169
|
style: { ...node.style, [op.breakpoint]: { ...prev, ...op.patch } }
|
|
160
170
|
});
|
|
161
171
|
}
|
|
162
172
|
case "set_constraints": {
|
|
163
|
-
const node = doc.nodes
|
|
173
|
+
const node = own(doc.nodes, op.id);
|
|
164
174
|
if (!node) return invalid("node not found");
|
|
165
175
|
const base = node.constraints ?? { base: { width: "hug", height: "hug" } };
|
|
166
|
-
const prev = base
|
|
176
|
+
const prev = own(base, op.breakpoint) ?? {};
|
|
167
177
|
return patchNode(doc, op.id, {
|
|
168
178
|
constraints: { ...base, [op.breakpoint]: { ...prev, ...op.patch } }
|
|
169
179
|
});
|
|
170
180
|
}
|
|
171
181
|
case "set_animation": {
|
|
172
|
-
const node = doc.nodes
|
|
182
|
+
const node = own(doc.nodes, op.id);
|
|
173
183
|
if (!node) return invalid("node not found");
|
|
174
184
|
const list = node.animations ?? [];
|
|
175
185
|
const idx = list.findIndex((a) => a.id === op.anim.id);
|
|
@@ -178,14 +188,14 @@ function reduce(doc, op, opts = {}) {
|
|
|
178
188
|
});
|
|
179
189
|
}
|
|
180
190
|
case "remove_animation": {
|
|
181
|
-
const node = doc.nodes
|
|
191
|
+
const node = own(doc.nodes, op.id);
|
|
182
192
|
if (!node) return invalid("node not found");
|
|
183
193
|
return patchNode(doc, op.id, {
|
|
184
194
|
animations: (node.animations ?? []).filter((a) => a.id !== op.animId)
|
|
185
195
|
});
|
|
186
196
|
}
|
|
187
197
|
case "set_action": {
|
|
188
|
-
const node = doc.nodes
|
|
198
|
+
const node = own(doc.nodes, op.id);
|
|
189
199
|
if (!node) return invalid("node not found");
|
|
190
200
|
const list = node.actions ?? [];
|
|
191
201
|
let actions;
|
|
@@ -201,13 +211,13 @@ function reduce(doc, op, opts = {}) {
|
|
|
201
211
|
case "reorder_roots": {
|
|
202
212
|
const currentRoots = childrenOf(doc, null);
|
|
203
213
|
const current = new Set(currentRoots.map((n) => n.id));
|
|
204
|
-
const same = op.order.length === currentRoots.length && op.order.every((id) => current.has(id));
|
|
214
|
+
const same = op.order.length === currentRoots.length && new Set(op.order).size === op.order.length && op.order.every((id) => current.has(id));
|
|
205
215
|
if (!same) return invalid("reorder must be a permutation of the current roots");
|
|
206
216
|
const nodes = { ...doc.nodes };
|
|
207
217
|
let prev = null;
|
|
208
218
|
for (const id of op.order) {
|
|
209
219
|
prev = fancyDocCommons.fractionalKey(prev, null);
|
|
210
|
-
nodes
|
|
220
|
+
setOwn(nodes, id, { ...own(nodes, id), order: prev });
|
|
211
221
|
}
|
|
212
222
|
return { ...doc, nodes, seq: doc.seq + 1 };
|
|
213
223
|
}
|
|
@@ -290,15 +300,36 @@ function useLatestRef(value) {
|
|
|
290
300
|
}
|
|
291
301
|
|
|
292
302
|
// src/render/css.ts
|
|
293
|
-
|
|
303
|
+
function cssString(value) {
|
|
304
|
+
let out = "";
|
|
305
|
+
for (const ch of value) {
|
|
306
|
+
const code = ch.codePointAt(0);
|
|
307
|
+
if (ch === "\\" || ch === '"') out += `\\${ch}`;
|
|
308
|
+
else if (code < 32 || code === 127 || ch === "<") out += `\\${code.toString(16)} `;
|
|
309
|
+
else out += ch;
|
|
310
|
+
}
|
|
311
|
+
return out;
|
|
312
|
+
}
|
|
313
|
+
var selectorFor = (id) => `[data-cms="${cssString(id)}"]`;
|
|
314
|
+
var UNITS = /* @__PURE__ */ new Set(["px", "%", "vw", "vh", "rem", "fr"]);
|
|
294
315
|
function lengthToCss(len2) {
|
|
295
|
-
|
|
316
|
+
if (typeof len2 !== "object" || len2 === null) return null;
|
|
317
|
+
const { value, unit } = len2;
|
|
318
|
+
if (typeof value !== "number" || !Number.isFinite(value) || typeof unit !== "string" || !UNITS.has(unit)) return null;
|
|
319
|
+
return `${value}${unit}`;
|
|
296
320
|
}
|
|
297
321
|
function sizeToCss(size) {
|
|
298
322
|
if (size === "fill") return "100%";
|
|
299
323
|
if (size === "hug") return "auto";
|
|
300
324
|
return lengthToCss(size);
|
|
301
325
|
}
|
|
326
|
+
function numberToCss(value) {
|
|
327
|
+
return typeof value === "number" && Number.isFinite(value) ? String(value) : null;
|
|
328
|
+
}
|
|
329
|
+
function putLen(d, props, len2) {
|
|
330
|
+
const css = lengthToCss(len2);
|
|
331
|
+
if (css !== null) for (const p of props) d[p] = css;
|
|
332
|
+
}
|
|
302
333
|
var ALIGN = {
|
|
303
334
|
start: "flex-start",
|
|
304
335
|
center: "center",
|
|
@@ -312,51 +343,150 @@ var JUSTIFY = {
|
|
|
312
343
|
between: "space-between",
|
|
313
344
|
around: "space-around"
|
|
314
345
|
};
|
|
346
|
+
function safeCssValue(value) {
|
|
347
|
+
if (/[{}<]/.test(value)) return null;
|
|
348
|
+
let depth = 0;
|
|
349
|
+
let quote = null;
|
|
350
|
+
for (const ch of value) {
|
|
351
|
+
if (quote) {
|
|
352
|
+
if (ch === quote) quote = null;
|
|
353
|
+
} else if (ch === '"' || ch === "'") {
|
|
354
|
+
quote = ch;
|
|
355
|
+
} else if (ch === "(") {
|
|
356
|
+
depth++;
|
|
357
|
+
} else if (ch === ")") {
|
|
358
|
+
depth = Math.max(0, depth - 1);
|
|
359
|
+
} else if (ch === ";" && depth === 0) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return value;
|
|
364
|
+
}
|
|
365
|
+
function put(d, prop, value) {
|
|
366
|
+
if (value === void 0) return;
|
|
367
|
+
const safe = safeCssValue(value);
|
|
368
|
+
if (safe !== null) d[prop] = safe;
|
|
369
|
+
}
|
|
370
|
+
var OVERFLOW = /* @__PURE__ */ new Set(["visible", "hidden", "auto"]);
|
|
371
|
+
var TEXT_TRANSFORM = /* @__PURE__ */ new Set(["none", "uppercase", "lowercase", "capitalize"]);
|
|
372
|
+
var BACKGROUND_SIZE = /* @__PURE__ */ new Set(["cover", "contain", "auto"]);
|
|
373
|
+
var TEXT_ALIGN = /* @__PURE__ */ new Set(["left", "center", "right", "justify"]);
|
|
374
|
+
var DIRECTIONS = /* @__PURE__ */ new Set(["row", "column"]);
|
|
375
|
+
function keyword(map, value) {
|
|
376
|
+
return typeof value === "string" && Object.prototype.hasOwnProperty.call(map, value) ? map[value] : null;
|
|
377
|
+
}
|
|
378
|
+
function inSet(set, value) {
|
|
379
|
+
return typeof value === "string" && set.has(value) ? value : null;
|
|
380
|
+
}
|
|
315
381
|
function styleDecls(style) {
|
|
316
382
|
const d = {};
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (style.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (style.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
if (style.
|
|
333
|
-
|
|
334
|
-
if (
|
|
335
|
-
|
|
383
|
+
putLen(d, ["padding"], style.padding);
|
|
384
|
+
putLen(d, ["padding-left", "padding-right"], style.paddingX);
|
|
385
|
+
putLen(d, ["padding-top", "padding-bottom"], style.paddingY);
|
|
386
|
+
putLen(d, ["margin"], style.margin);
|
|
387
|
+
if (style.marginX === "auto") d["margin-left"] = d["margin-right"] = "auto";
|
|
388
|
+
else putLen(d, ["margin-left", "margin-right"], style.marginX);
|
|
389
|
+
putLen(d, ["margin-top", "margin-bottom"], style.marginY);
|
|
390
|
+
putLen(d, ["border-radius"], style.radius);
|
|
391
|
+
putLen(d, ["max-width"], style.maxWidth);
|
|
392
|
+
putLen(d, ["min-height"], style.minHeight);
|
|
393
|
+
put(d, "aspect-ratio", typeof style.aspectRatio === "string" ? style.aspectRatio : void 0);
|
|
394
|
+
if (style.sticky === true) {
|
|
395
|
+
d["position"] = "sticky";
|
|
396
|
+
d["top"] = "0";
|
|
397
|
+
}
|
|
398
|
+
if (typeof style.zIndex === "number" && Number.isFinite(style.zIndex)) d["z-index"] = String(Math.trunc(style.zIndex));
|
|
399
|
+
const overflow = inSet(OVERFLOW, style.overflow);
|
|
400
|
+
if (overflow) d["overflow"] = overflow;
|
|
401
|
+
put(d, "background", typeof style.background === "string" ? style.background : void 0);
|
|
402
|
+
const backgroundSize = inSet(BACKGROUND_SIZE, style.backgroundSize);
|
|
403
|
+
if (backgroundSize) d["background-size"] = backgroundSize;
|
|
404
|
+
put(d, "background-position", typeof style.backgroundPosition === "string" ? style.backgroundPosition : void 0);
|
|
405
|
+
put(d, "color", typeof style.color === "string" ? style.color : void 0);
|
|
406
|
+
const opacity = numberToCss(style.opacity);
|
|
407
|
+
if (opacity !== null) d["opacity"] = opacity;
|
|
408
|
+
put(d, "font-family", typeof style.fontFamily === "string" ? style.fontFamily : void 0);
|
|
409
|
+
putLen(d, ["font-size"], style.fontSize);
|
|
410
|
+
const fontWeight = numberToCss(style.fontWeight);
|
|
411
|
+
if (fontWeight !== null) d["font-weight"] = fontWeight;
|
|
412
|
+
const lineHeight = numberToCss(style.lineHeight);
|
|
413
|
+
if (lineHeight !== null) d["line-height"] = lineHeight;
|
|
414
|
+
const textAlign = inSet(TEXT_ALIGN, style.textAlign);
|
|
415
|
+
if (textAlign) d["text-align"] = textAlign;
|
|
416
|
+
putLen(d, ["letter-spacing"], style.letterSpacing);
|
|
417
|
+
const textTransform = inSet(TEXT_TRANSFORM, style.textTransform);
|
|
418
|
+
if (textTransform) d["text-transform"] = textTransform;
|
|
419
|
+
put(d, "border", typeof style.border === "string" ? style.border : void 0);
|
|
420
|
+
put(d, "box-shadow", typeof style.boxShadow === "string" ? style.boxShadow : void 0);
|
|
421
|
+
put(d, "transform", typeof style.transform === "string" ? style.transform : void 0);
|
|
422
|
+
put(d, "filter", typeof style.filter === "string" ? style.filter : void 0);
|
|
423
|
+
putLen(d, ["gap"], style.gap);
|
|
424
|
+
const align = keyword(ALIGN, style.align);
|
|
425
|
+
if (align) d["align-items"] = align;
|
|
426
|
+
const justify = keyword(JUSTIFY, style.justify);
|
|
427
|
+
if (justify) d["justify-content"] = justify;
|
|
336
428
|
return d;
|
|
337
429
|
}
|
|
338
|
-
function
|
|
430
|
+
function shownDisplay(node) {
|
|
431
|
+
if (node.layout === "stack") return "flex";
|
|
432
|
+
if (node.layout === "grid") return "grid";
|
|
433
|
+
return "block";
|
|
434
|
+
}
|
|
435
|
+
function gridColumns(style) {
|
|
436
|
+
const min = lengthToCss(style.columnMin);
|
|
437
|
+
if (min !== null) return `repeat(auto-fit, minmax(min(${min}, 100%), 1fr))`;
|
|
438
|
+
if (typeof style.columns === "number" && Number.isFinite(style.columns)) return `repeat(${Math.max(1, Math.trunc(style.columns))}, 1fr)`;
|
|
439
|
+
return void 0;
|
|
440
|
+
}
|
|
441
|
+
function containerDecls(node, style, isBase) {
|
|
339
442
|
const d = {};
|
|
340
443
|
if (node.layout === "stack") {
|
|
341
|
-
d["display"] = "flex";
|
|
342
|
-
|
|
444
|
+
if (isBase) d["display"] = "flex";
|
|
445
|
+
const direction = inSet(DIRECTIONS, style.direction);
|
|
446
|
+
if (isBase || direction) d["flex-direction"] = direction ?? "column";
|
|
447
|
+
if (style.wrap !== void 0) d["flex-wrap"] = style.wrap ? "wrap" : "nowrap";
|
|
343
448
|
} else if (node.layout === "grid") {
|
|
344
|
-
d["display"] = "grid";
|
|
345
|
-
|
|
346
|
-
|
|
449
|
+
if (isBase) d["display"] = "grid";
|
|
450
|
+
const cols = gridColumns(style);
|
|
451
|
+
if (isBase || cols !== void 0) d["grid-template-columns"] = cols ?? "repeat(1, 1fr)";
|
|
452
|
+
} else if (node.layout === "free" && isBase) {
|
|
347
453
|
d["position"] = "relative";
|
|
348
454
|
}
|
|
349
455
|
return d;
|
|
350
456
|
}
|
|
457
|
+
function visibilityDecls(node, style, isBase) {
|
|
458
|
+
if (style.hidden === true) return { display: "none" };
|
|
459
|
+
if (style.hidden === false && !isBase) return { display: shownDisplay(node) };
|
|
460
|
+
return {};
|
|
461
|
+
}
|
|
462
|
+
function themeDecls(theme) {
|
|
463
|
+
const d = {};
|
|
464
|
+
const walk = (value, path) => {
|
|
465
|
+
if (typeof value === "string" || typeof value === "number" && Number.isFinite(value)) {
|
|
466
|
+
const key = path.map((p) => p.toLowerCase().replace(/[^a-z0-9-]/g, "")).filter(Boolean).join("-");
|
|
467
|
+
if (key) put(d, `--cms-${key}`, String(value));
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
471
|
+
for (const [k, v] of Object.entries(value)) walk(v, [...path, k]);
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
if (typeof theme === "object" && theme !== null && !Array.isArray(theme)) {
|
|
475
|
+
for (const [k, v] of Object.entries(theme)) {
|
|
476
|
+
if (k !== "name") walk(v, [k]);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return d;
|
|
480
|
+
}
|
|
351
481
|
function constraintDecls(c, parentFree) {
|
|
352
482
|
const d = {};
|
|
353
483
|
const transforms = [];
|
|
354
484
|
if (parentFree) {
|
|
355
485
|
d["position"] = "absolute";
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
486
|
+
putLen(d, ["left"], c.left);
|
|
487
|
+
putLen(d, ["right"], c.right);
|
|
488
|
+
putLen(d, ["top"], c.top);
|
|
489
|
+
putLen(d, ["bottom"], c.bottom);
|
|
360
490
|
if (c.centerX) {
|
|
361
491
|
d["left"] = "50%";
|
|
362
492
|
transforms.push("translateX(-50%)");
|
|
@@ -367,13 +497,15 @@ function constraintDecls(c, parentFree) {
|
|
|
367
497
|
}
|
|
368
498
|
if (transforms.length) d["transform"] = transforms.join(" ");
|
|
369
499
|
}
|
|
370
|
-
|
|
371
|
-
if (
|
|
500
|
+
const width = sizeToCss(c.width);
|
|
501
|
+
if (width !== null) d["width"] = width;
|
|
502
|
+
const height = sizeToCss(c.height);
|
|
503
|
+
if (height !== null) d["height"] = height;
|
|
372
504
|
return d;
|
|
373
505
|
}
|
|
374
506
|
function isParentFree(doc, node) {
|
|
375
507
|
if (node.parent === null) return false;
|
|
376
|
-
const parent = doc.nodes
|
|
508
|
+
const parent = own(doc.nodes, node.parent);
|
|
377
509
|
return !parent || parent.layout === void 0 || parent.layout === "free";
|
|
378
510
|
}
|
|
379
511
|
function serializeRule(selector, decls, indent) {
|
|
@@ -388,14 +520,17 @@ function emitDocCss(doc) {
|
|
|
388
520
|
if (!hasNodeMap(doc)) return "";
|
|
389
521
|
const breakpointPx = DEFAULT_BREAKPOINTS;
|
|
390
522
|
const blocks = [];
|
|
523
|
+
const themeRule = serializeRule(":root", themeDecls(doc.theme), "");
|
|
524
|
+
if (themeRule) blocks.push(themeRule);
|
|
391
525
|
for (const id of Object.keys(doc.nodes).sort()) {
|
|
392
526
|
const node = doc.nodes[id];
|
|
393
527
|
const selector = selectorFor(id);
|
|
394
528
|
const parentFree = isParentFree(doc, node);
|
|
395
529
|
const base = {
|
|
396
|
-
...
|
|
530
|
+
...containerDecls(node, node.style.base, true),
|
|
397
531
|
...node.constraints ? constraintDecls(node.constraints.base, parentFree) : {},
|
|
398
|
-
...styleDecls(node.style.base)
|
|
532
|
+
...styleDecls(node.style.base),
|
|
533
|
+
...visibilityDecls(node, node.style.base, true)
|
|
399
534
|
};
|
|
400
535
|
const baseRule = serializeRule(selector, base, "");
|
|
401
536
|
if (baseRule) blocks.push(baseRule);
|
|
@@ -403,9 +538,12 @@ function emitDocCss(doc) {
|
|
|
403
538
|
if (bp === "base") continue;
|
|
404
539
|
const px = breakpointPx[bp];
|
|
405
540
|
if (px === void 0) continue;
|
|
541
|
+
const bpStyle = node.style[bp];
|
|
406
542
|
const decls = {
|
|
543
|
+
...bpStyle ? containerDecls(node, bpStyle, false) : {},
|
|
407
544
|
...node.constraints?.[bp] ? constraintDecls(node.constraints[bp], parentFree) : {},
|
|
408
|
-
...
|
|
545
|
+
...bpStyle ? styleDecls(bpStyle) : {},
|
|
546
|
+
...bpStyle ? visibilityDecls(node, bpStyle, false) : {}
|
|
409
547
|
};
|
|
410
548
|
const inner = serializeRule(selector, decls, " ");
|
|
411
549
|
if (inner) blocks.push(`@media (min-width: ${px}px) {
|
|
@@ -423,6 +561,48 @@ function resolveValue(v, data) {
|
|
|
423
561
|
if (isBinding(v)) return getPath(data, v.$bind);
|
|
424
562
|
return v;
|
|
425
563
|
}
|
|
564
|
+
var LANDMARK_TAGS = ["section", "header", "nav", "main", "footer", "article", "aside", "div"];
|
|
565
|
+
var LANDMARKS = new Set(LANDMARK_TAGS);
|
|
566
|
+
var CONTAINERS = /* @__PURE__ */ new Set(["stack", "grid", "frame", "shape", "card"]);
|
|
567
|
+
var SAFE_SCHEMES = /* @__PURE__ */ new Set(["http", "https", "mailto", "tel"]);
|
|
568
|
+
function safeHref(raw) {
|
|
569
|
+
const href = raw.trim();
|
|
570
|
+
if (!href) return null;
|
|
571
|
+
const probe = href.replace(/[\u0000- \u007f]+/g, "");
|
|
572
|
+
const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(probe);
|
|
573
|
+
if (scheme && !SAFE_SCHEMES.has(scheme[1].toLowerCase())) return null;
|
|
574
|
+
return href;
|
|
575
|
+
}
|
|
576
|
+
var ANCHOR_PATTERN = /^[a-z][a-z0-9-]{0,63}$/;
|
|
577
|
+
function anchorFor(node, text) {
|
|
578
|
+
const anchor = text(node.props.anchor);
|
|
579
|
+
return ANCHOR_PATTERN.test(anchor) ? anchor : null;
|
|
580
|
+
}
|
|
581
|
+
function elementFor(node, text) {
|
|
582
|
+
const as = text(node.props.as);
|
|
583
|
+
switch (node.type) {
|
|
584
|
+
case "heading": {
|
|
585
|
+
const level = Number(text(node.props.level) || 2);
|
|
586
|
+
return { tag: Number.isInteger(level) && level >= 1 && level <= 6 ? `h${level}` : "h2" };
|
|
587
|
+
}
|
|
588
|
+
case "text":
|
|
589
|
+
return { tag: "p" };
|
|
590
|
+
case "section":
|
|
591
|
+
return { tag: LANDMARKS.has(as) ? as : "section" };
|
|
592
|
+
case "list":
|
|
593
|
+
return { tag: text(node.props.ordered) === "true" ? "ol" : "ul" };
|
|
594
|
+
case "button":
|
|
595
|
+
case "link": {
|
|
596
|
+
const href = safeHref(text(node.props.href));
|
|
597
|
+
if (href === null) return { tag: node.type === "link" ? "span" : "div" };
|
|
598
|
+
const attrs = { href };
|
|
599
|
+
if (/^https?:\/\//i.test(href)) attrs.rel = "noopener noreferrer";
|
|
600
|
+
return { tag: "a", attrs };
|
|
601
|
+
}
|
|
602
|
+
default:
|
|
603
|
+
return { tag: CONTAINERS.has(node.type) && LANDMARKS.has(as) ? as : "div" };
|
|
604
|
+
}
|
|
605
|
+
}
|
|
426
606
|
var defaultRegistry = {
|
|
427
607
|
section: ({ children }) => children,
|
|
428
608
|
stack: ({ children }) => children,
|
|
@@ -435,7 +615,12 @@ var defaultRegistry = {
|
|
|
435
615
|
// Rich text — inline-formatted HTML (gradient spans, links, <code>, …) that
|
|
436
616
|
// plain `text` can't express. The author owns the markup (it's their content).
|
|
437
617
|
richtext: ({ node, text }) => /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: text(node.props.html) } }),
|
|
438
|
-
|
|
618
|
+
// The [data-cms] element is already the <a> (see elementFor), so a link renders its label only.
|
|
619
|
+
link: ({ node, text }) => text(node.props.content) || "link",
|
|
620
|
+
list: ({ node, resolve }) => {
|
|
621
|
+
const items = resolve(node.props.items);
|
|
622
|
+
return Array.isArray(items) ? items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: item === null || item === void 0 ? "" : String(item) }, i)) : null;
|
|
623
|
+
},
|
|
439
624
|
divider: () => /* @__PURE__ */ jsxRuntime.jsx("hr", { style: { border: "none", borderTop: "1px solid #e2e8f0", margin: 0 } }),
|
|
440
625
|
callout: ({ node, text }) => {
|
|
441
626
|
const tone = { info: "#3b82f6", success: "#10b981", warning: "#f59e0b", danger: "#ef4444" }[text(node.props.variant)] ?? "#3b82f6";
|
|
@@ -447,15 +632,20 @@ var defaultRegistry = {
|
|
|
447
632
|
const variant = text(node.props.variant) || "primary";
|
|
448
633
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cms-button": variant, style: buttonStyle(variant), children: label2 });
|
|
449
634
|
},
|
|
450
|
-
image: ({ node, text }) =>
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
635
|
+
image: ({ node, text }) => {
|
|
636
|
+
const fit = text(node.props.fit);
|
|
637
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
638
|
+
"img",
|
|
639
|
+
{
|
|
640
|
+
src: text(node.props.src),
|
|
641
|
+
alt: text(node.props.alt),
|
|
642
|
+
loading: text(node.props.loading) === "eager" ? "eager" : "lazy",
|
|
643
|
+
style: { width: "100%", height: "100%", objectFit: IMAGE_FITS.has(fit) ? fit : "cover", display: "block" }
|
|
644
|
+
}
|
|
645
|
+
);
|
|
646
|
+
}
|
|
458
647
|
};
|
|
648
|
+
var IMAGE_FITS = /* @__PURE__ */ new Set(["cover", "contain", "fill", "none", "scale-down"]);
|
|
459
649
|
function buttonStyle(variant) {
|
|
460
650
|
const base = {
|
|
461
651
|
display: "inline-flex",
|
|
@@ -474,7 +664,7 @@ function buttonStyle(variant) {
|
|
|
474
664
|
return { ...base, background: "#7c3aed", color: "#fff", border: "1px solid #7c3aed" };
|
|
475
665
|
}
|
|
476
666
|
function RenderNode({ doc, id, registry = defaultRegistry, data }) {
|
|
477
|
-
const node = doc.nodes
|
|
667
|
+
const node = own(doc.nodes, id);
|
|
478
668
|
if (!node) return null;
|
|
479
669
|
if (node.type === "repeater") {
|
|
480
670
|
const arr = resolveValue(node.props.items, data);
|
|
@@ -490,7 +680,19 @@ function RenderNode({ doc, id, registry = defaultRegistry, data }) {
|
|
|
490
680
|
};
|
|
491
681
|
const renderer = registry[node.type];
|
|
492
682
|
const inner = renderer ? renderer({ node, doc, children: kids, data, resolve, text }) : node.island ? null : kids;
|
|
493
|
-
|
|
683
|
+
const { tag, attrs } = elementFor(node, text);
|
|
684
|
+
const anchor = anchorFor(node, text);
|
|
685
|
+
return react.createElement(
|
|
686
|
+
tag,
|
|
687
|
+
{
|
|
688
|
+
"data-cms": node.id,
|
|
689
|
+
"data-cms-island": node.island ? node.type : void 0,
|
|
690
|
+
className: node.className,
|
|
691
|
+
...anchor ? { id: anchor } : {},
|
|
692
|
+
...attrs
|
|
693
|
+
},
|
|
694
|
+
inner
|
|
695
|
+
);
|
|
494
696
|
}
|
|
495
697
|
function CmsPage({
|
|
496
698
|
doc: input3,
|
|
@@ -808,7 +1010,8 @@ var ADD_DEFAULTS = {
|
|
|
808
1010
|
divider: { type: "divider", props: {}, style: {} },
|
|
809
1011
|
code: { type: "code", props: { content: "npm install @particle-academy/react-fancy", lang: "bash" }, style: {} },
|
|
810
1012
|
richtext: { type: "richtext", props: { html: "<p>Rich <strong>text</strong> with <em>inline</em> formatting.</p>" }, style: {} },
|
|
811
|
-
repeater: { type: "repeater", props: { items: "" }, style: { gap: { value: 12, unit: "px" } }, layout: "stack" }
|
|
1013
|
+
repeater: { type: "repeater", props: { items: "" }, style: { gap: { value: 12, unit: "px" } }, layout: "stack" },
|
|
1014
|
+
list: { type: "list", props: { items: ["First point", "Second point"], ordered: false }, style: {} }
|
|
812
1015
|
};
|
|
813
1016
|
var ADD_MENU = [
|
|
814
1017
|
{ kind: "heading", label: "Heading" },
|
|
@@ -824,6 +1027,7 @@ var ADD_MENU = [
|
|
|
824
1027
|
{ kind: "divider", label: "Divider" },
|
|
825
1028
|
{ kind: "code", label: "Code" },
|
|
826
1029
|
{ kind: "richtext", label: "Rich text" },
|
|
1030
|
+
{ kind: "list", label: "List" },
|
|
827
1031
|
{ kind: "repeater", label: "Repeater" }
|
|
828
1032
|
];
|
|
829
1033
|
function resolveInsertParent(doc, selectedId) {
|