@particle-academy/fancy-cms-ui 0.7.0 → 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-YOAZRQKN.js → chunk-IOMIYI45.js} +6 -4
- package/dist/{chunk-YOAZRQKN.js.map → chunk-IOMIYI45.js.map} +1 -1
- package/dist/{chunk-IWQQINCF.js → chunk-SJYKJ6SG.js} +300 -83
- package/dist/chunk-SJYKJ6SG.js.map +1 -0
- package/dist/{chunk-BWGAUTKG.js → chunk-V6QIOJI7.js} +3 -3
- package/dist/{chunk-BWGAUTKG.js.map → chunk-V6QIOJI7.js.map} +1 -1
- package/dist/editor.cjs +313 -94
- 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 +301 -81
- 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 +288 -62
- 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-CiPir27w.d.cts → registry-B4FaQDip.d.cts} +31 -1
- package/dist/{registry-CiPir27w.d.ts → registry-B4FaQDip.d.ts} +31 -1
- package/dist/{useEditor-CoxNeC53.d.cts → useEditor-CIRm2oi-.d.cts} +1 -1
- package/dist/{useEditor-DAE36OYU.d.ts → useEditor-DZDD9qpS.d.ts} +1 -1
- package/package.json +107 -105
- package/dist/chunk-IWQQINCF.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var fancyDocCommons = require('@particle-academy/fancy-doc-commons');
|
|
4
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
5
4
|
var react = require('react');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
|
|
7
7
|
// src/document/types.ts
|
|
8
8
|
function isBinding(v) {
|
|
9
9
|
return typeof v === "object" && v !== null && typeof v.$bind === "string";
|
|
10
10
|
}
|
|
11
|
+
function hasNodeMap(value) {
|
|
12
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
13
|
+
const nodes = value.nodes;
|
|
14
|
+
return typeof nodes === "object" && nodes !== null && !Array.isArray(nodes);
|
|
15
|
+
}
|
|
11
16
|
var DEFAULT_BREAKPOINTS = {
|
|
12
17
|
base: 0,
|
|
13
18
|
md: 768,
|
|
@@ -56,10 +61,22 @@ function bindingSources(doc) {
|
|
|
56
61
|
}
|
|
57
62
|
return [...seen.values()];
|
|
58
63
|
}
|
|
64
|
+
|
|
65
|
+
// src/document/own.ts
|
|
66
|
+
var has = Object.prototype.hasOwnProperty;
|
|
67
|
+
function own(map, key) {
|
|
68
|
+
return map != null && has.call(map, key) ? map[key] : void 0;
|
|
69
|
+
}
|
|
70
|
+
function setOwn(map, key, value) {
|
|
71
|
+
Object.defineProperty(map, key, { value, writable: true, enumerable: true, configurable: true });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/document/reduce.ts
|
|
59
75
|
function childrenOf(doc, parent) {
|
|
60
76
|
return fancyDocCommons.childrenOf(doc, parent);
|
|
61
77
|
}
|
|
62
78
|
function rootIds(doc) {
|
|
79
|
+
if (!hasNodeMap(doc)) return [];
|
|
63
80
|
return childrenOf(doc, null).map((n) => n.id);
|
|
64
81
|
}
|
|
65
82
|
function lastRootId(doc) {
|
|
@@ -70,7 +87,7 @@ function descendantIds(doc, id) {
|
|
|
70
87
|
return fancyDocCommons.descendantsOf(doc, id);
|
|
71
88
|
}
|
|
72
89
|
function patchNode(doc, id, patch) {
|
|
73
|
-
const node = doc.nodes
|
|
90
|
+
const node = own(doc.nodes, id);
|
|
74
91
|
return {
|
|
75
92
|
...doc,
|
|
76
93
|
nodes: { ...doc.nodes, [id]: { ...node, ...patch } },
|
|
@@ -84,8 +101,8 @@ function reduce(doc, op, opts = {}) {
|
|
|
84
101
|
};
|
|
85
102
|
switch (op.t) {
|
|
86
103
|
case "insert_node": {
|
|
87
|
-
if (doc.nodes
|
|
88
|
-
if (op.node.parent !== null && !doc.nodes
|
|
104
|
+
if (own(doc.nodes, op.node.id)) return invalid("node id already exists");
|
|
105
|
+
if (op.node.parent !== null && !own(doc.nodes, op.node.parent)) return invalid("parent not found");
|
|
89
106
|
return {
|
|
90
107
|
...doc,
|
|
91
108
|
nodes: { ...doc.nodes, [op.node.id]: op.node },
|
|
@@ -93,11 +110,11 @@ function reduce(doc, op, opts = {}) {
|
|
|
93
110
|
};
|
|
94
111
|
}
|
|
95
112
|
case "remove_node": {
|
|
96
|
-
if (!doc.nodes
|
|
113
|
+
if (!own(doc.nodes, op.id)) return invalid("node not found");
|
|
97
114
|
const dead = /* @__PURE__ */ new Set([op.id, ...descendantIds(doc, op.id)]);
|
|
98
115
|
const nodes = {};
|
|
99
116
|
for (const id of Object.keys(doc.nodes)) {
|
|
100
|
-
if (!dead.has(id)) nodes
|
|
117
|
+
if (!dead.has(id)) setOwn(nodes, id, own(doc.nodes, id));
|
|
101
118
|
}
|
|
102
119
|
return {
|
|
103
120
|
...doc,
|
|
@@ -106,10 +123,10 @@ function reduce(doc, op, opts = {}) {
|
|
|
106
123
|
};
|
|
107
124
|
}
|
|
108
125
|
case "move_node": {
|
|
109
|
-
const node = doc.nodes
|
|
126
|
+
const node = own(doc.nodes, op.id);
|
|
110
127
|
if (!node) return invalid("node not found");
|
|
111
128
|
if (op.parent === op.id) return invalid("cannot parent a node to itself");
|
|
112
|
-
if (op.parent !== null && !doc.nodes
|
|
129
|
+
if (op.parent !== null && !own(doc.nodes, op.parent)) return invalid("new parent not found");
|
|
113
130
|
if (op.parent !== null && descendantIds(doc, op.id).includes(op.parent)) {
|
|
114
131
|
return invalid("move would create a cycle");
|
|
115
132
|
}
|
|
@@ -120,34 +137,35 @@ function reduce(doc, op, opts = {}) {
|
|
|
120
137
|
};
|
|
121
138
|
}
|
|
122
139
|
case "set_node_props": {
|
|
123
|
-
|
|
140
|
+
const node = own(doc.nodes, op.id);
|
|
141
|
+
if (!node) return invalid("node not found");
|
|
124
142
|
return patchNode(doc, op.id, {
|
|
125
|
-
props: { ...
|
|
143
|
+
props: { ...node.props, ...op.patch }
|
|
126
144
|
});
|
|
127
145
|
}
|
|
128
146
|
case "set_layout": {
|
|
129
|
-
if (!doc.nodes
|
|
147
|
+
if (!own(doc.nodes, op.id)) return invalid("node not found");
|
|
130
148
|
return patchNode(doc, op.id, { layout: op.layout });
|
|
131
149
|
}
|
|
132
150
|
case "set_style": {
|
|
133
|
-
const node = doc.nodes
|
|
151
|
+
const node = own(doc.nodes, op.id);
|
|
134
152
|
if (!node) return invalid("node not found");
|
|
135
|
-
const prev = node.style
|
|
153
|
+
const prev = own(node.style, op.breakpoint) ?? {};
|
|
136
154
|
return patchNode(doc, op.id, {
|
|
137
155
|
style: { ...node.style, [op.breakpoint]: { ...prev, ...op.patch } }
|
|
138
156
|
});
|
|
139
157
|
}
|
|
140
158
|
case "set_constraints": {
|
|
141
|
-
const node = doc.nodes
|
|
159
|
+
const node = own(doc.nodes, op.id);
|
|
142
160
|
if (!node) return invalid("node not found");
|
|
143
161
|
const base = node.constraints ?? { base: { width: "hug", height: "hug" } };
|
|
144
|
-
const prev = base
|
|
162
|
+
const prev = own(base, op.breakpoint) ?? {};
|
|
145
163
|
return patchNode(doc, op.id, {
|
|
146
164
|
constraints: { ...base, [op.breakpoint]: { ...prev, ...op.patch } }
|
|
147
165
|
});
|
|
148
166
|
}
|
|
149
167
|
case "set_animation": {
|
|
150
|
-
const node = doc.nodes
|
|
168
|
+
const node = own(doc.nodes, op.id);
|
|
151
169
|
if (!node) return invalid("node not found");
|
|
152
170
|
const list = node.animations ?? [];
|
|
153
171
|
const idx = list.findIndex((a) => a.id === op.anim.id);
|
|
@@ -156,14 +174,14 @@ function reduce(doc, op, opts = {}) {
|
|
|
156
174
|
});
|
|
157
175
|
}
|
|
158
176
|
case "remove_animation": {
|
|
159
|
-
const node = doc.nodes
|
|
177
|
+
const node = own(doc.nodes, op.id);
|
|
160
178
|
if (!node) return invalid("node not found");
|
|
161
179
|
return patchNode(doc, op.id, {
|
|
162
180
|
animations: (node.animations ?? []).filter((a) => a.id !== op.animId)
|
|
163
181
|
});
|
|
164
182
|
}
|
|
165
183
|
case "set_action": {
|
|
166
|
-
const node = doc.nodes
|
|
184
|
+
const node = own(doc.nodes, op.id);
|
|
167
185
|
if (!node) return invalid("node not found");
|
|
168
186
|
const list = node.actions ?? [];
|
|
169
187
|
let actions;
|
|
@@ -179,13 +197,13 @@ function reduce(doc, op, opts = {}) {
|
|
|
179
197
|
case "reorder_roots": {
|
|
180
198
|
const currentRoots = childrenOf(doc, null);
|
|
181
199
|
const current = new Set(currentRoots.map((n) => n.id));
|
|
182
|
-
const same = op.order.length === currentRoots.length && op.order.every((id) => current.has(id));
|
|
200
|
+
const same = op.order.length === currentRoots.length && new Set(op.order).size === op.order.length && op.order.every((id) => current.has(id));
|
|
183
201
|
if (!same) return invalid("reorder must be a permutation of the current roots");
|
|
184
202
|
const nodes = { ...doc.nodes };
|
|
185
203
|
let prev = null;
|
|
186
204
|
for (const id of op.order) {
|
|
187
205
|
prev = fancyDocCommons.fractionalKey(prev, null);
|
|
188
|
-
nodes
|
|
206
|
+
setOwn(nodes, id, { ...own(nodes, id), order: prev });
|
|
189
207
|
}
|
|
190
208
|
return { ...doc, nodes, seq: doc.seq + 1 };
|
|
191
209
|
}
|
|
@@ -201,17 +219,17 @@ function invert(doc, op) {
|
|
|
201
219
|
case "insert_node":
|
|
202
220
|
return [{ t: "remove_node", id: op.node.id }];
|
|
203
221
|
case "remove_node": {
|
|
204
|
-
const node = doc.nodes
|
|
222
|
+
const node = own(doc.nodes, op.id);
|
|
205
223
|
if (!node) return [];
|
|
206
224
|
const ids = [op.id, ...descendantIds(doc, op.id)];
|
|
207
|
-
const inserts = ids.map((id) => ({ t: "insert_node", node: doc.nodes
|
|
225
|
+
const inserts = ids.map((id) => ({ t: "insert_node", node: own(doc.nodes, id) }));
|
|
208
226
|
if (node.parent === null) {
|
|
209
227
|
inserts.push({ t: "reorder_roots", order: childrenOf(doc, null).map((n) => n.id) });
|
|
210
228
|
}
|
|
211
229
|
return inserts;
|
|
212
230
|
}
|
|
213
231
|
case "move_node": {
|
|
214
|
-
const node = doc.nodes
|
|
232
|
+
const node = own(doc.nodes, op.id);
|
|
215
233
|
if (!node) return [];
|
|
216
234
|
const back = [{ t: "move_node", id: op.id, parent: node.parent, order: node.order }];
|
|
217
235
|
if (node.parent === null) {
|
|
@@ -220,19 +238,19 @@ function invert(doc, op) {
|
|
|
220
238
|
return back;
|
|
221
239
|
}
|
|
222
240
|
case "set_node_props": {
|
|
223
|
-
const node = doc.nodes
|
|
241
|
+
const node = own(doc.nodes, op.id);
|
|
224
242
|
if (!node) return [];
|
|
225
243
|
const prev = {};
|
|
226
244
|
for (const k of Object.keys(op.patch)) prev[k] = node.props[k];
|
|
227
245
|
return [{ t: "set_node_props", id: op.id, patch: prev }];
|
|
228
246
|
}
|
|
229
247
|
case "set_layout": {
|
|
230
|
-
const node = doc.nodes
|
|
248
|
+
const node = own(doc.nodes, op.id);
|
|
231
249
|
if (!node) return [];
|
|
232
250
|
return [{ t: "set_layout", id: op.id, layout: node.layout }];
|
|
233
251
|
}
|
|
234
252
|
case "set_style": {
|
|
235
|
-
const node = doc.nodes
|
|
253
|
+
const node = own(doc.nodes, op.id);
|
|
236
254
|
if (!node) return [];
|
|
237
255
|
const prevBp = node.style[op.breakpoint] ?? {};
|
|
238
256
|
const prev = {};
|
|
@@ -254,17 +272,23 @@ function pick(obj, keys) {
|
|
|
254
272
|
for (const k of keys) out[k] = obj[k];
|
|
255
273
|
return out;
|
|
256
274
|
}
|
|
275
|
+
function normalizeDoc(input2) {
|
|
276
|
+
if (hasNodeMap(input2)) return input2;
|
|
277
|
+
const id = typeof input2 === "object" && input2 !== null && !Array.isArray(input2) && typeof input2.id === "string" ? input2.id : "malformed";
|
|
278
|
+
return emptyDoc(id);
|
|
279
|
+
}
|
|
257
280
|
function migrateDocVerbose(input2) {
|
|
258
|
-
const
|
|
281
|
+
const normalized = normalizeDoc(input2);
|
|
282
|
+
const legacy = normalized;
|
|
259
283
|
const sections = legacy.sections;
|
|
260
284
|
if (!Array.isArray(sections)) {
|
|
261
|
-
return { doc:
|
|
285
|
+
return { doc: normalized, migrated: false, danglingIds: [], unlistedRootIds: [] };
|
|
262
286
|
}
|
|
263
287
|
const danglingIds = [];
|
|
264
288
|
const ordered = [];
|
|
265
289
|
const seen = /* @__PURE__ */ new Set();
|
|
266
290
|
for (const id of sections) {
|
|
267
|
-
if (!
|
|
291
|
+
if (!own(normalized.nodes, id)) {
|
|
268
292
|
danglingIds.push(id);
|
|
269
293
|
continue;
|
|
270
294
|
}
|
|
@@ -272,13 +296,13 @@ function migrateDocVerbose(input2) {
|
|
|
272
296
|
seen.add(id);
|
|
273
297
|
ordered.push(id);
|
|
274
298
|
}
|
|
275
|
-
const unlistedRootIds = Object.values(
|
|
299
|
+
const unlistedRootIds = Object.values(normalized.nodes).filter((n) => n.parent === null && !seen.has(n.id)).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0).map((n) => n.id);
|
|
276
300
|
const finalOrder = [...ordered, ...unlistedRootIds];
|
|
277
|
-
const nodes = { ...
|
|
301
|
+
const nodes = { ...normalized.nodes };
|
|
278
302
|
let prev = null;
|
|
279
303
|
for (const id of finalOrder) {
|
|
280
304
|
const key = fancyDocCommons.fractionalKey(prev, null);
|
|
281
|
-
nodes
|
|
305
|
+
setOwn(nodes, id, { ...own(nodes, id), order: key });
|
|
282
306
|
prev = key;
|
|
283
307
|
}
|
|
284
308
|
const { sections: _dropped, ...rest } = legacy;
|
|
@@ -297,15 +321,36 @@ function needsMigration(input2) {
|
|
|
297
321
|
}
|
|
298
322
|
|
|
299
323
|
// src/render/css.ts
|
|
300
|
-
|
|
324
|
+
function cssString(value) {
|
|
325
|
+
let out = "";
|
|
326
|
+
for (const ch of value) {
|
|
327
|
+
const code = ch.codePointAt(0);
|
|
328
|
+
if (ch === "\\" || ch === '"') out += `\\${ch}`;
|
|
329
|
+
else if (code < 32 || code === 127 || ch === "<") out += `\\${code.toString(16)} `;
|
|
330
|
+
else out += ch;
|
|
331
|
+
}
|
|
332
|
+
return out;
|
|
333
|
+
}
|
|
334
|
+
var selectorFor = (id) => `[data-cms="${cssString(id)}"]`;
|
|
335
|
+
var UNITS = /* @__PURE__ */ new Set(["px", "%", "vw", "vh", "rem", "fr"]);
|
|
301
336
|
function lengthToCss(len) {
|
|
302
|
-
|
|
337
|
+
if (typeof len !== "object" || len === null) return null;
|
|
338
|
+
const { value, unit } = len;
|
|
339
|
+
if (typeof value !== "number" || !Number.isFinite(value) || typeof unit !== "string" || !UNITS.has(unit)) return null;
|
|
340
|
+
return `${value}${unit}`;
|
|
303
341
|
}
|
|
304
342
|
function sizeToCss(size) {
|
|
305
343
|
if (size === "fill") return "100%";
|
|
306
344
|
if (size === "hug") return "auto";
|
|
307
345
|
return lengthToCss(size);
|
|
308
346
|
}
|
|
347
|
+
function numberToCss(value) {
|
|
348
|
+
return typeof value === "number" && Number.isFinite(value) ? String(value) : null;
|
|
349
|
+
}
|
|
350
|
+
function putLen(d, props, len) {
|
|
351
|
+
const css = lengthToCss(len);
|
|
352
|
+
if (css !== null) for (const p of props) d[p] = css;
|
|
353
|
+
}
|
|
309
354
|
var ALIGN = {
|
|
310
355
|
start: "flex-start",
|
|
311
356
|
center: "center",
|
|
@@ -319,51 +364,150 @@ var JUSTIFY = {
|
|
|
319
364
|
between: "space-between",
|
|
320
365
|
around: "space-around"
|
|
321
366
|
};
|
|
367
|
+
function safeCssValue(value) {
|
|
368
|
+
if (/[{}<]/.test(value)) return null;
|
|
369
|
+
let depth = 0;
|
|
370
|
+
let quote = null;
|
|
371
|
+
for (const ch of value) {
|
|
372
|
+
if (quote) {
|
|
373
|
+
if (ch === quote) quote = null;
|
|
374
|
+
} else if (ch === '"' || ch === "'") {
|
|
375
|
+
quote = ch;
|
|
376
|
+
} else if (ch === "(") {
|
|
377
|
+
depth++;
|
|
378
|
+
} else if (ch === ")") {
|
|
379
|
+
depth = Math.max(0, depth - 1);
|
|
380
|
+
} else if (ch === ";" && depth === 0) {
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return value;
|
|
385
|
+
}
|
|
386
|
+
function put(d, prop, value) {
|
|
387
|
+
if (value === void 0) return;
|
|
388
|
+
const safe = safeCssValue(value);
|
|
389
|
+
if (safe !== null) d[prop] = safe;
|
|
390
|
+
}
|
|
391
|
+
var OVERFLOW = /* @__PURE__ */ new Set(["visible", "hidden", "auto"]);
|
|
392
|
+
var TEXT_TRANSFORM = /* @__PURE__ */ new Set(["none", "uppercase", "lowercase", "capitalize"]);
|
|
393
|
+
var BACKGROUND_SIZE = /* @__PURE__ */ new Set(["cover", "contain", "auto"]);
|
|
394
|
+
var TEXT_ALIGN = /* @__PURE__ */ new Set(["left", "center", "right", "justify"]);
|
|
395
|
+
var DIRECTIONS = /* @__PURE__ */ new Set(["row", "column"]);
|
|
396
|
+
function keyword(map, value) {
|
|
397
|
+
return typeof value === "string" && Object.prototype.hasOwnProperty.call(map, value) ? map[value] : null;
|
|
398
|
+
}
|
|
399
|
+
function inSet(set, value) {
|
|
400
|
+
return typeof value === "string" && set.has(value) ? value : null;
|
|
401
|
+
}
|
|
322
402
|
function styleDecls(style) {
|
|
323
403
|
const d = {};
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (style.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
if (style.
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
if (style.
|
|
340
|
-
|
|
341
|
-
if (
|
|
342
|
-
|
|
404
|
+
putLen(d, ["padding"], style.padding);
|
|
405
|
+
putLen(d, ["padding-left", "padding-right"], style.paddingX);
|
|
406
|
+
putLen(d, ["padding-top", "padding-bottom"], style.paddingY);
|
|
407
|
+
putLen(d, ["margin"], style.margin);
|
|
408
|
+
if (style.marginX === "auto") d["margin-left"] = d["margin-right"] = "auto";
|
|
409
|
+
else putLen(d, ["margin-left", "margin-right"], style.marginX);
|
|
410
|
+
putLen(d, ["margin-top", "margin-bottom"], style.marginY);
|
|
411
|
+
putLen(d, ["border-radius"], style.radius);
|
|
412
|
+
putLen(d, ["max-width"], style.maxWidth);
|
|
413
|
+
putLen(d, ["min-height"], style.minHeight);
|
|
414
|
+
put(d, "aspect-ratio", typeof style.aspectRatio === "string" ? style.aspectRatio : void 0);
|
|
415
|
+
if (style.sticky === true) {
|
|
416
|
+
d["position"] = "sticky";
|
|
417
|
+
d["top"] = "0";
|
|
418
|
+
}
|
|
419
|
+
if (typeof style.zIndex === "number" && Number.isFinite(style.zIndex)) d["z-index"] = String(Math.trunc(style.zIndex));
|
|
420
|
+
const overflow = inSet(OVERFLOW, style.overflow);
|
|
421
|
+
if (overflow) d["overflow"] = overflow;
|
|
422
|
+
put(d, "background", typeof style.background === "string" ? style.background : void 0);
|
|
423
|
+
const backgroundSize = inSet(BACKGROUND_SIZE, style.backgroundSize);
|
|
424
|
+
if (backgroundSize) d["background-size"] = backgroundSize;
|
|
425
|
+
put(d, "background-position", typeof style.backgroundPosition === "string" ? style.backgroundPosition : void 0);
|
|
426
|
+
put(d, "color", typeof style.color === "string" ? style.color : void 0);
|
|
427
|
+
const opacity = numberToCss(style.opacity);
|
|
428
|
+
if (opacity !== null) d["opacity"] = opacity;
|
|
429
|
+
put(d, "font-family", typeof style.fontFamily === "string" ? style.fontFamily : void 0);
|
|
430
|
+
putLen(d, ["font-size"], style.fontSize);
|
|
431
|
+
const fontWeight = numberToCss(style.fontWeight);
|
|
432
|
+
if (fontWeight !== null) d["font-weight"] = fontWeight;
|
|
433
|
+
const lineHeight = numberToCss(style.lineHeight);
|
|
434
|
+
if (lineHeight !== null) d["line-height"] = lineHeight;
|
|
435
|
+
const textAlign = inSet(TEXT_ALIGN, style.textAlign);
|
|
436
|
+
if (textAlign) d["text-align"] = textAlign;
|
|
437
|
+
putLen(d, ["letter-spacing"], style.letterSpacing);
|
|
438
|
+
const textTransform = inSet(TEXT_TRANSFORM, style.textTransform);
|
|
439
|
+
if (textTransform) d["text-transform"] = textTransform;
|
|
440
|
+
put(d, "border", typeof style.border === "string" ? style.border : void 0);
|
|
441
|
+
put(d, "box-shadow", typeof style.boxShadow === "string" ? style.boxShadow : void 0);
|
|
442
|
+
put(d, "transform", typeof style.transform === "string" ? style.transform : void 0);
|
|
443
|
+
put(d, "filter", typeof style.filter === "string" ? style.filter : void 0);
|
|
444
|
+
putLen(d, ["gap"], style.gap);
|
|
445
|
+
const align = keyword(ALIGN, style.align);
|
|
446
|
+
if (align) d["align-items"] = align;
|
|
447
|
+
const justify = keyword(JUSTIFY, style.justify);
|
|
448
|
+
if (justify) d["justify-content"] = justify;
|
|
343
449
|
return d;
|
|
344
450
|
}
|
|
345
|
-
function
|
|
451
|
+
function shownDisplay(node) {
|
|
452
|
+
if (node.layout === "stack") return "flex";
|
|
453
|
+
if (node.layout === "grid") return "grid";
|
|
454
|
+
return "block";
|
|
455
|
+
}
|
|
456
|
+
function gridColumns(style) {
|
|
457
|
+
const min = lengthToCss(style.columnMin);
|
|
458
|
+
if (min !== null) return `repeat(auto-fit, minmax(min(${min}, 100%), 1fr))`;
|
|
459
|
+
if (typeof style.columns === "number" && Number.isFinite(style.columns)) return `repeat(${Math.max(1, Math.trunc(style.columns))}, 1fr)`;
|
|
460
|
+
return void 0;
|
|
461
|
+
}
|
|
462
|
+
function containerDecls(node, style, isBase) {
|
|
346
463
|
const d = {};
|
|
347
464
|
if (node.layout === "stack") {
|
|
348
|
-
d["display"] = "flex";
|
|
349
|
-
|
|
465
|
+
if (isBase) d["display"] = "flex";
|
|
466
|
+
const direction = inSet(DIRECTIONS, style.direction);
|
|
467
|
+
if (isBase || direction) d["flex-direction"] = direction ?? "column";
|
|
468
|
+
if (style.wrap !== void 0) d["flex-wrap"] = style.wrap ? "wrap" : "nowrap";
|
|
350
469
|
} else if (node.layout === "grid") {
|
|
351
|
-
d["display"] = "grid";
|
|
352
|
-
|
|
353
|
-
|
|
470
|
+
if (isBase) d["display"] = "grid";
|
|
471
|
+
const cols = gridColumns(style);
|
|
472
|
+
if (isBase || cols !== void 0) d["grid-template-columns"] = cols ?? "repeat(1, 1fr)";
|
|
473
|
+
} else if (node.layout === "free" && isBase) {
|
|
354
474
|
d["position"] = "relative";
|
|
355
475
|
}
|
|
356
476
|
return d;
|
|
357
477
|
}
|
|
478
|
+
function visibilityDecls(node, style, isBase) {
|
|
479
|
+
if (style.hidden === true) return { display: "none" };
|
|
480
|
+
if (style.hidden === false && !isBase) return { display: shownDisplay(node) };
|
|
481
|
+
return {};
|
|
482
|
+
}
|
|
483
|
+
function themeDecls(theme) {
|
|
484
|
+
const d = {};
|
|
485
|
+
const walk = (value, path) => {
|
|
486
|
+
if (typeof value === "string" || typeof value === "number" && Number.isFinite(value)) {
|
|
487
|
+
const key = path.map((p) => p.toLowerCase().replace(/[^a-z0-9-]/g, "")).filter(Boolean).join("-");
|
|
488
|
+
if (key) put(d, `--cms-${key}`, String(value));
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
492
|
+
for (const [k, v] of Object.entries(value)) walk(v, [...path, k]);
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
if (typeof theme === "object" && theme !== null && !Array.isArray(theme)) {
|
|
496
|
+
for (const [k, v] of Object.entries(theme)) {
|
|
497
|
+
if (k !== "name") walk(v, [k]);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return d;
|
|
501
|
+
}
|
|
358
502
|
function constraintDecls(c, parentFree) {
|
|
359
503
|
const d = {};
|
|
360
504
|
const transforms = [];
|
|
361
505
|
if (parentFree) {
|
|
362
506
|
d["position"] = "absolute";
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
507
|
+
putLen(d, ["left"], c.left);
|
|
508
|
+
putLen(d, ["right"], c.right);
|
|
509
|
+
putLen(d, ["top"], c.top);
|
|
510
|
+
putLen(d, ["bottom"], c.bottom);
|
|
367
511
|
if (c.centerX) {
|
|
368
512
|
d["left"] = "50%";
|
|
369
513
|
transforms.push("translateX(-50%)");
|
|
@@ -374,13 +518,15 @@ function constraintDecls(c, parentFree) {
|
|
|
374
518
|
}
|
|
375
519
|
if (transforms.length) d["transform"] = transforms.join(" ");
|
|
376
520
|
}
|
|
377
|
-
|
|
378
|
-
if (
|
|
521
|
+
const width = sizeToCss(c.width);
|
|
522
|
+
if (width !== null) d["width"] = width;
|
|
523
|
+
const height = sizeToCss(c.height);
|
|
524
|
+
if (height !== null) d["height"] = height;
|
|
379
525
|
return d;
|
|
380
526
|
}
|
|
381
527
|
function isParentFree(doc, node) {
|
|
382
528
|
if (node.parent === null) return false;
|
|
383
|
-
const parent = doc.nodes
|
|
529
|
+
const parent = own(doc.nodes, node.parent);
|
|
384
530
|
return !parent || parent.layout === void 0 || parent.layout === "free";
|
|
385
531
|
}
|
|
386
532
|
function serializeRule(selector, decls, indent) {
|
|
@@ -392,16 +538,20 @@ ${body}
|
|
|
392
538
|
${indent}}`;
|
|
393
539
|
}
|
|
394
540
|
function emitDocCss(doc) {
|
|
541
|
+
if (!hasNodeMap(doc)) return "";
|
|
395
542
|
const breakpointPx = DEFAULT_BREAKPOINTS;
|
|
396
543
|
const blocks = [];
|
|
544
|
+
const themeRule = serializeRule(":root", themeDecls(doc.theme), "");
|
|
545
|
+
if (themeRule) blocks.push(themeRule);
|
|
397
546
|
for (const id of Object.keys(doc.nodes).sort()) {
|
|
398
547
|
const node = doc.nodes[id];
|
|
399
548
|
const selector = selectorFor(id);
|
|
400
549
|
const parentFree = isParentFree(doc, node);
|
|
401
550
|
const base = {
|
|
402
|
-
...
|
|
551
|
+
...containerDecls(node, node.style.base, true),
|
|
403
552
|
...node.constraints ? constraintDecls(node.constraints.base, parentFree) : {},
|
|
404
|
-
...styleDecls(node.style.base)
|
|
553
|
+
...styleDecls(node.style.base),
|
|
554
|
+
...visibilityDecls(node, node.style.base, true)
|
|
405
555
|
};
|
|
406
556
|
const baseRule = serializeRule(selector, base, "");
|
|
407
557
|
if (baseRule) blocks.push(baseRule);
|
|
@@ -409,9 +559,12 @@ function emitDocCss(doc) {
|
|
|
409
559
|
if (bp === "base") continue;
|
|
410
560
|
const px = breakpointPx[bp];
|
|
411
561
|
if (px === void 0) continue;
|
|
562
|
+
const bpStyle = node.style[bp];
|
|
412
563
|
const decls = {
|
|
564
|
+
...bpStyle ? containerDecls(node, bpStyle, false) : {},
|
|
413
565
|
...node.constraints?.[bp] ? constraintDecls(node.constraints[bp], parentFree) : {},
|
|
414
|
-
...
|
|
566
|
+
...bpStyle ? styleDecls(bpStyle) : {},
|
|
567
|
+
...bpStyle ? visibilityDecls(node, bpStyle, false) : {}
|
|
415
568
|
};
|
|
416
569
|
const inner = serializeRule(selector, decls, " ");
|
|
417
570
|
if (inner) blocks.push(`@media (min-width: ${px}px) {
|
|
@@ -429,6 +582,48 @@ function resolveValue(v, data) {
|
|
|
429
582
|
if (isBinding(v)) return getPath(data, v.$bind);
|
|
430
583
|
return v;
|
|
431
584
|
}
|
|
585
|
+
var LANDMARK_TAGS = ["section", "header", "nav", "main", "footer", "article", "aside", "div"];
|
|
586
|
+
var LANDMARKS = new Set(LANDMARK_TAGS);
|
|
587
|
+
var CONTAINERS = /* @__PURE__ */ new Set(["stack", "grid", "frame", "shape", "card"]);
|
|
588
|
+
var SAFE_SCHEMES = /* @__PURE__ */ new Set(["http", "https", "mailto", "tel"]);
|
|
589
|
+
function safeHref(raw) {
|
|
590
|
+
const href = raw.trim();
|
|
591
|
+
if (!href) return null;
|
|
592
|
+
const probe = href.replace(/[\u0000- \u007f]+/g, "");
|
|
593
|
+
const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(probe);
|
|
594
|
+
if (scheme && !SAFE_SCHEMES.has(scheme[1].toLowerCase())) return null;
|
|
595
|
+
return href;
|
|
596
|
+
}
|
|
597
|
+
var ANCHOR_PATTERN = /^[a-z][a-z0-9-]{0,63}$/;
|
|
598
|
+
function anchorFor(node, text) {
|
|
599
|
+
const anchor = text(node.props.anchor);
|
|
600
|
+
return ANCHOR_PATTERN.test(anchor) ? anchor : null;
|
|
601
|
+
}
|
|
602
|
+
function elementFor(node, text) {
|
|
603
|
+
const as = text(node.props.as);
|
|
604
|
+
switch (node.type) {
|
|
605
|
+
case "heading": {
|
|
606
|
+
const level = Number(text(node.props.level) || 2);
|
|
607
|
+
return { tag: Number.isInteger(level) && level >= 1 && level <= 6 ? `h${level}` : "h2" };
|
|
608
|
+
}
|
|
609
|
+
case "text":
|
|
610
|
+
return { tag: "p" };
|
|
611
|
+
case "section":
|
|
612
|
+
return { tag: LANDMARKS.has(as) ? as : "section" };
|
|
613
|
+
case "list":
|
|
614
|
+
return { tag: text(node.props.ordered) === "true" ? "ol" : "ul" };
|
|
615
|
+
case "button":
|
|
616
|
+
case "link": {
|
|
617
|
+
const href = safeHref(text(node.props.href));
|
|
618
|
+
if (href === null) return { tag: node.type === "link" ? "span" : "div" };
|
|
619
|
+
const attrs = { href };
|
|
620
|
+
if (/^https?:\/\//i.test(href)) attrs.rel = "noopener noreferrer";
|
|
621
|
+
return { tag: "a", attrs };
|
|
622
|
+
}
|
|
623
|
+
default:
|
|
624
|
+
return { tag: CONTAINERS.has(node.type) && LANDMARKS.has(as) ? as : "div" };
|
|
625
|
+
}
|
|
626
|
+
}
|
|
432
627
|
var defaultRegistry = {
|
|
433
628
|
section: ({ children }) => children,
|
|
434
629
|
stack: ({ children }) => children,
|
|
@@ -441,7 +636,12 @@ var defaultRegistry = {
|
|
|
441
636
|
// Rich text — inline-formatted HTML (gradient spans, links, <code>, …) that
|
|
442
637
|
// plain `text` can't express. The author owns the markup (it's their content).
|
|
443
638
|
richtext: ({ node, text }) => /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: text(node.props.html) } }),
|
|
444
|
-
|
|
639
|
+
// The [data-cms] element is already the <a> (see elementFor), so a link renders its label only.
|
|
640
|
+
link: ({ node, text }) => text(node.props.content) || "link",
|
|
641
|
+
list: ({ node, resolve }) => {
|
|
642
|
+
const items = resolve(node.props.items);
|
|
643
|
+
return Array.isArray(items) ? items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: item === null || item === void 0 ? "" : String(item) }, i)) : null;
|
|
644
|
+
},
|
|
445
645
|
divider: () => /* @__PURE__ */ jsxRuntime.jsx("hr", { style: { border: "none", borderTop: "1px solid #e2e8f0", margin: 0 } }),
|
|
446
646
|
callout: ({ node, text }) => {
|
|
447
647
|
const tone = { info: "#3b82f6", success: "#10b981", warning: "#f59e0b", danger: "#ef4444" }[text(node.props.variant)] ?? "#3b82f6";
|
|
@@ -453,15 +653,20 @@ var defaultRegistry = {
|
|
|
453
653
|
const variant = text(node.props.variant) || "primary";
|
|
454
654
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cms-button": variant, style: buttonStyle(variant), children: label2 });
|
|
455
655
|
},
|
|
456
|
-
image: ({ node, text }) =>
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
656
|
+
image: ({ node, text }) => {
|
|
657
|
+
const fit = text(node.props.fit);
|
|
658
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
659
|
+
"img",
|
|
660
|
+
{
|
|
661
|
+
src: text(node.props.src),
|
|
662
|
+
alt: text(node.props.alt),
|
|
663
|
+
loading: text(node.props.loading) === "eager" ? "eager" : "lazy",
|
|
664
|
+
style: { width: "100%", height: "100%", objectFit: IMAGE_FITS.has(fit) ? fit : "cover", display: "block" }
|
|
665
|
+
}
|
|
666
|
+
);
|
|
667
|
+
}
|
|
464
668
|
};
|
|
669
|
+
var IMAGE_FITS = /* @__PURE__ */ new Set(["cover", "contain", "fill", "none", "scale-down"]);
|
|
465
670
|
function buttonStyle(variant) {
|
|
466
671
|
const base = {
|
|
467
672
|
display: "inline-flex",
|
|
@@ -480,7 +685,7 @@ function buttonStyle(variant) {
|
|
|
480
685
|
return { ...base, background: "#7c3aed", color: "#fff", border: "1px solid #7c3aed" };
|
|
481
686
|
}
|
|
482
687
|
function RenderNode({ doc, id, registry = defaultRegistry, data }) {
|
|
483
|
-
const node = doc.nodes
|
|
688
|
+
const node = own(doc.nodes, id);
|
|
484
689
|
if (!node) return null;
|
|
485
690
|
if (node.type === "repeater") {
|
|
486
691
|
const arr = resolveValue(node.props.items, data);
|
|
@@ -496,7 +701,19 @@ function RenderNode({ doc, id, registry = defaultRegistry, data }) {
|
|
|
496
701
|
};
|
|
497
702
|
const renderer = registry[node.type];
|
|
498
703
|
const inner = renderer ? renderer({ node, doc, children: kids, data, resolve, text }) : node.island ? null : kids;
|
|
499
|
-
|
|
704
|
+
const { tag, attrs } = elementFor(node, text);
|
|
705
|
+
const anchor = anchorFor(node, text);
|
|
706
|
+
return react.createElement(
|
|
707
|
+
tag,
|
|
708
|
+
{
|
|
709
|
+
"data-cms": node.id,
|
|
710
|
+
"data-cms-island": node.island ? node.type : void 0,
|
|
711
|
+
className: node.className,
|
|
712
|
+
...anchor ? { id: anchor } : {},
|
|
713
|
+
...attrs
|
|
714
|
+
},
|
|
715
|
+
inner
|
|
716
|
+
);
|
|
500
717
|
}
|
|
501
718
|
function CmsPage({
|
|
502
719
|
doc: input2,
|
|
@@ -898,7 +1115,8 @@ var ADD_DEFAULTS = {
|
|
|
898
1115
|
divider: { type: "divider", props: {}, style: {} },
|
|
899
1116
|
code: { type: "code", props: { content: "npm install @particle-academy/react-fancy", lang: "bash" }, style: {} },
|
|
900
1117
|
richtext: { type: "richtext", props: { html: "<p>Rich <strong>text</strong> with <em>inline</em> formatting.</p>" }, style: {} },
|
|
901
|
-
repeater: { type: "repeater", props: { items: "" }, style: { gap: { value: 12, unit: "px" } }, layout: "stack" }
|
|
1118
|
+
repeater: { type: "repeater", props: { items: "" }, style: { gap: { value: 12, unit: "px" } }, layout: "stack" },
|
|
1119
|
+
list: { type: "list", props: { items: ["First point", "Second point"], ordered: false }, style: {} }
|
|
902
1120
|
};
|
|
903
1121
|
var ADD_MENU = [
|
|
904
1122
|
{ kind: "heading", label: "Heading" },
|
|
@@ -914,6 +1132,7 @@ var ADD_MENU = [
|
|
|
914
1132
|
{ kind: "divider", label: "Divider" },
|
|
915
1133
|
{ kind: "code", label: "Code" },
|
|
916
1134
|
{ kind: "richtext", label: "Rich text" },
|
|
1135
|
+
{ kind: "list", label: "List" },
|
|
917
1136
|
{ kind: "repeater", label: "Repeater" }
|
|
918
1137
|
];
|
|
919
1138
|
function resolveInsertParent(doc, selectedId) {
|
|
@@ -1121,6 +1340,7 @@ exports.editorReduce = editorReduce;
|
|
|
1121
1340
|
exports.emitDocCss = emitDocCss;
|
|
1122
1341
|
exports.emptyDoc = emptyDoc;
|
|
1123
1342
|
exports.getPath = getPath;
|
|
1343
|
+
exports.hasNodeMap = hasNodeMap;
|
|
1124
1344
|
exports.initEditor = initEditor;
|
|
1125
1345
|
exports.invert = invert;
|
|
1126
1346
|
exports.isBinding = isBinding;
|