@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.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { C as Canvas, a as CanvasProps, E as Editor, b as EditorAction, c as EditorApi, d as EditorProps, e as EditorState, I as Inspector, f as InspectorProps, L as LayersPanel, g as LayersPanelProps, i as editorReduce, j as initEditor, u as useEditor } from './useEditor-
|
|
1
|
+
export { C as Canvas, a as CanvasProps, E as Editor, b as EditorAction, c as EditorApi, d as EditorProps, e as EditorState, I as Inspector, f as InspectorProps, L as LayersPanel, g as LayersPanelProps, i as editorReduce, j as initEditor, u as useEditor } from './useEditor-CIRm2oi-.cjs';
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
|
-
import { P as PageDoc, h as ElementRegistry, g as DataContext, N as Node, q as StyleProps, L as LayoutMode } from './registry-
|
|
3
|
+
import { P as PageDoc, h as ElementRegistry, g as DataContext, N as Node, q as StyleProps, L as LayoutMode } from './registry-B4FaQDip.cjs';
|
|
4
4
|
import '@particle-academy/fancy-doc-commons';
|
|
5
5
|
|
|
6
6
|
/** Animatable per-node transform (mirrors fancy-motion's NodeState, kept local to avoid a hard dep). */
|
package/dist/editor.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { C as Canvas, a as CanvasProps, E as Editor, b as EditorAction, c as EditorApi, d as EditorProps, e as EditorState, I as Inspector, f as InspectorProps, L as LayersPanel, g as LayersPanelProps, i as editorReduce, j as initEditor, u as useEditor } from './useEditor-
|
|
1
|
+
export { C as Canvas, a as CanvasProps, E as Editor, b as EditorAction, c as EditorApi, d as EditorProps, e as EditorState, I as Inspector, f as InspectorProps, L as LayersPanel, g as LayersPanelProps, i as editorReduce, j as initEditor, u as useEditor } from './useEditor-DZDD9qpS.js';
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
|
-
import { P as PageDoc, h as ElementRegistry, g as DataContext, N as Node, q as StyleProps, L as LayoutMode } from './registry-
|
|
3
|
+
import { P as PageDoc, h as ElementRegistry, g as DataContext, N as Node, q as StyleProps, L as LayoutMode } from './registry-B4FaQDip.js';
|
|
4
4
|
import '@particle-academy/fancy-doc-commons';
|
|
5
5
|
|
|
6
6
|
/** Animatable per-node transform (mirrors fancy-motion's NodeState, kept local to avoid a hard dep). */
|
package/dist/editor.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { useEditor, useLatestRef, CONTAINER_TYPES, ADD_DEFAULTS, ADD_MENU } from './chunk-
|
|
2
|
-
export { Canvas, Editor, Inspector, LayersPanel, editorReduce, initEditor, useEditor } from './chunk-
|
|
3
|
-
import { isBinding, lastRootId, childrenOf, CmsPage, defaultRegistry } from './chunk-
|
|
1
|
+
import { useEditor, useLatestRef, CONTAINER_TYPES, ADD_DEFAULTS, ADD_MENU } from './chunk-IOMIYI45.js';
|
|
2
|
+
export { Canvas, Editor, Inspector, LayersPanel, editorReduce, initEditor, useEditor } from './chunk-IOMIYI45.js';
|
|
3
|
+
import { isBinding, lastRootId, childrenOf, CmsPage, defaultRegistry } from './chunk-SJYKJ6SG.js';
|
|
4
4
|
import { useState, useRef, useEffect, useCallback, useLayoutEffect } from 'react';
|
|
5
5
|
import { ContextMenu } from '@particle-academy/react-fancy';
|
|
6
6
|
import { fractionalKey } from '@particle-academy/fancy-doc-commons';
|
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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) {
|
|
@@ -61,6 +61,17 @@ function bindingSources(doc) {
|
|
|
61
61
|
}
|
|
62
62
|
return [...seen.values()];
|
|
63
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
|
|
64
75
|
function childrenOf(doc, parent) {
|
|
65
76
|
return fancyDocCommons.childrenOf(doc, parent);
|
|
66
77
|
}
|
|
@@ -76,7 +87,7 @@ function descendantIds(doc, id) {
|
|
|
76
87
|
return fancyDocCommons.descendantsOf(doc, id);
|
|
77
88
|
}
|
|
78
89
|
function patchNode(doc, id, patch) {
|
|
79
|
-
const node = doc.nodes
|
|
90
|
+
const node = own(doc.nodes, id);
|
|
80
91
|
return {
|
|
81
92
|
...doc,
|
|
82
93
|
nodes: { ...doc.nodes, [id]: { ...node, ...patch } },
|
|
@@ -90,8 +101,8 @@ function reduce(doc, op, opts = {}) {
|
|
|
90
101
|
};
|
|
91
102
|
switch (op.t) {
|
|
92
103
|
case "insert_node": {
|
|
93
|
-
if (doc.nodes
|
|
94
|
-
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");
|
|
95
106
|
return {
|
|
96
107
|
...doc,
|
|
97
108
|
nodes: { ...doc.nodes, [op.node.id]: op.node },
|
|
@@ -99,11 +110,11 @@ function reduce(doc, op, opts = {}) {
|
|
|
99
110
|
};
|
|
100
111
|
}
|
|
101
112
|
case "remove_node": {
|
|
102
|
-
if (!doc.nodes
|
|
113
|
+
if (!own(doc.nodes, op.id)) return invalid("node not found");
|
|
103
114
|
const dead = /* @__PURE__ */ new Set([op.id, ...descendantIds(doc, op.id)]);
|
|
104
115
|
const nodes = {};
|
|
105
116
|
for (const id of Object.keys(doc.nodes)) {
|
|
106
|
-
if (!dead.has(id)) nodes
|
|
117
|
+
if (!dead.has(id)) setOwn(nodes, id, own(doc.nodes, id));
|
|
107
118
|
}
|
|
108
119
|
return {
|
|
109
120
|
...doc,
|
|
@@ -112,10 +123,10 @@ function reduce(doc, op, opts = {}) {
|
|
|
112
123
|
};
|
|
113
124
|
}
|
|
114
125
|
case "move_node": {
|
|
115
|
-
const node = doc.nodes
|
|
126
|
+
const node = own(doc.nodes, op.id);
|
|
116
127
|
if (!node) return invalid("node not found");
|
|
117
128
|
if (op.parent === op.id) return invalid("cannot parent a node to itself");
|
|
118
|
-
if (op.parent !== null && !doc.nodes
|
|
129
|
+
if (op.parent !== null && !own(doc.nodes, op.parent)) return invalid("new parent not found");
|
|
119
130
|
if (op.parent !== null && descendantIds(doc, op.id).includes(op.parent)) {
|
|
120
131
|
return invalid("move would create a cycle");
|
|
121
132
|
}
|
|
@@ -126,34 +137,35 @@ function reduce(doc, op, opts = {}) {
|
|
|
126
137
|
};
|
|
127
138
|
}
|
|
128
139
|
case "set_node_props": {
|
|
129
|
-
|
|
140
|
+
const node = own(doc.nodes, op.id);
|
|
141
|
+
if (!node) return invalid("node not found");
|
|
130
142
|
return patchNode(doc, op.id, {
|
|
131
|
-
props: { ...
|
|
143
|
+
props: { ...node.props, ...op.patch }
|
|
132
144
|
});
|
|
133
145
|
}
|
|
134
146
|
case "set_layout": {
|
|
135
|
-
if (!doc.nodes
|
|
147
|
+
if (!own(doc.nodes, op.id)) return invalid("node not found");
|
|
136
148
|
return patchNode(doc, op.id, { layout: op.layout });
|
|
137
149
|
}
|
|
138
150
|
case "set_style": {
|
|
139
|
-
const node = doc.nodes
|
|
151
|
+
const node = own(doc.nodes, op.id);
|
|
140
152
|
if (!node) return invalid("node not found");
|
|
141
|
-
const prev = node.style
|
|
153
|
+
const prev = own(node.style, op.breakpoint) ?? {};
|
|
142
154
|
return patchNode(doc, op.id, {
|
|
143
155
|
style: { ...node.style, [op.breakpoint]: { ...prev, ...op.patch } }
|
|
144
156
|
});
|
|
145
157
|
}
|
|
146
158
|
case "set_constraints": {
|
|
147
|
-
const node = doc.nodes
|
|
159
|
+
const node = own(doc.nodes, op.id);
|
|
148
160
|
if (!node) return invalid("node not found");
|
|
149
161
|
const base = node.constraints ?? { base: { width: "hug", height: "hug" } };
|
|
150
|
-
const prev = base
|
|
162
|
+
const prev = own(base, op.breakpoint) ?? {};
|
|
151
163
|
return patchNode(doc, op.id, {
|
|
152
164
|
constraints: { ...base, [op.breakpoint]: { ...prev, ...op.patch } }
|
|
153
165
|
});
|
|
154
166
|
}
|
|
155
167
|
case "set_animation": {
|
|
156
|
-
const node = doc.nodes
|
|
168
|
+
const node = own(doc.nodes, op.id);
|
|
157
169
|
if (!node) return invalid("node not found");
|
|
158
170
|
const list = node.animations ?? [];
|
|
159
171
|
const idx = list.findIndex((a) => a.id === op.anim.id);
|
|
@@ -162,14 +174,14 @@ function reduce(doc, op, opts = {}) {
|
|
|
162
174
|
});
|
|
163
175
|
}
|
|
164
176
|
case "remove_animation": {
|
|
165
|
-
const node = doc.nodes
|
|
177
|
+
const node = own(doc.nodes, op.id);
|
|
166
178
|
if (!node) return invalid("node not found");
|
|
167
179
|
return patchNode(doc, op.id, {
|
|
168
180
|
animations: (node.animations ?? []).filter((a) => a.id !== op.animId)
|
|
169
181
|
});
|
|
170
182
|
}
|
|
171
183
|
case "set_action": {
|
|
172
|
-
const node = doc.nodes
|
|
184
|
+
const node = own(doc.nodes, op.id);
|
|
173
185
|
if (!node) return invalid("node not found");
|
|
174
186
|
const list = node.actions ?? [];
|
|
175
187
|
let actions;
|
|
@@ -185,13 +197,13 @@ function reduce(doc, op, opts = {}) {
|
|
|
185
197
|
case "reorder_roots": {
|
|
186
198
|
const currentRoots = childrenOf(doc, null);
|
|
187
199
|
const current = new Set(currentRoots.map((n) => n.id));
|
|
188
|
-
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));
|
|
189
201
|
if (!same) return invalid("reorder must be a permutation of the current roots");
|
|
190
202
|
const nodes = { ...doc.nodes };
|
|
191
203
|
let prev = null;
|
|
192
204
|
for (const id of op.order) {
|
|
193
205
|
prev = fancyDocCommons.fractionalKey(prev, null);
|
|
194
|
-
nodes
|
|
206
|
+
setOwn(nodes, id, { ...own(nodes, id), order: prev });
|
|
195
207
|
}
|
|
196
208
|
return { ...doc, nodes, seq: doc.seq + 1 };
|
|
197
209
|
}
|
|
@@ -207,17 +219,17 @@ function invert(doc, op) {
|
|
|
207
219
|
case "insert_node":
|
|
208
220
|
return [{ t: "remove_node", id: op.node.id }];
|
|
209
221
|
case "remove_node": {
|
|
210
|
-
const node = doc.nodes
|
|
222
|
+
const node = own(doc.nodes, op.id);
|
|
211
223
|
if (!node) return [];
|
|
212
224
|
const ids = [op.id, ...descendantIds(doc, op.id)];
|
|
213
|
-
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) }));
|
|
214
226
|
if (node.parent === null) {
|
|
215
227
|
inserts.push({ t: "reorder_roots", order: childrenOf(doc, null).map((n) => n.id) });
|
|
216
228
|
}
|
|
217
229
|
return inserts;
|
|
218
230
|
}
|
|
219
231
|
case "move_node": {
|
|
220
|
-
const node = doc.nodes
|
|
232
|
+
const node = own(doc.nodes, op.id);
|
|
221
233
|
if (!node) return [];
|
|
222
234
|
const back = [{ t: "move_node", id: op.id, parent: node.parent, order: node.order }];
|
|
223
235
|
if (node.parent === null) {
|
|
@@ -226,19 +238,19 @@ function invert(doc, op) {
|
|
|
226
238
|
return back;
|
|
227
239
|
}
|
|
228
240
|
case "set_node_props": {
|
|
229
|
-
const node = doc.nodes
|
|
241
|
+
const node = own(doc.nodes, op.id);
|
|
230
242
|
if (!node) return [];
|
|
231
243
|
const prev = {};
|
|
232
244
|
for (const k of Object.keys(op.patch)) prev[k] = node.props[k];
|
|
233
245
|
return [{ t: "set_node_props", id: op.id, patch: prev }];
|
|
234
246
|
}
|
|
235
247
|
case "set_layout": {
|
|
236
|
-
const node = doc.nodes
|
|
248
|
+
const node = own(doc.nodes, op.id);
|
|
237
249
|
if (!node) return [];
|
|
238
250
|
return [{ t: "set_layout", id: op.id, layout: node.layout }];
|
|
239
251
|
}
|
|
240
252
|
case "set_style": {
|
|
241
|
-
const node = doc.nodes
|
|
253
|
+
const node = own(doc.nodes, op.id);
|
|
242
254
|
if (!node) return [];
|
|
243
255
|
const prevBp = node.style[op.breakpoint] ?? {};
|
|
244
256
|
const prev = {};
|
|
@@ -276,7 +288,7 @@ function migrateDocVerbose(input2) {
|
|
|
276
288
|
const ordered = [];
|
|
277
289
|
const seen = /* @__PURE__ */ new Set();
|
|
278
290
|
for (const id of sections) {
|
|
279
|
-
if (!normalized.nodes
|
|
291
|
+
if (!own(normalized.nodes, id)) {
|
|
280
292
|
danglingIds.push(id);
|
|
281
293
|
continue;
|
|
282
294
|
}
|
|
@@ -290,7 +302,7 @@ function migrateDocVerbose(input2) {
|
|
|
290
302
|
let prev = null;
|
|
291
303
|
for (const id of finalOrder) {
|
|
292
304
|
const key = fancyDocCommons.fractionalKey(prev, null);
|
|
293
|
-
nodes
|
|
305
|
+
setOwn(nodes, id, { ...own(nodes, id), order: key });
|
|
294
306
|
prev = key;
|
|
295
307
|
}
|
|
296
308
|
const { sections: _dropped, ...rest } = legacy;
|
|
@@ -309,15 +321,36 @@ function needsMigration(input2) {
|
|
|
309
321
|
}
|
|
310
322
|
|
|
311
323
|
// src/render/css.ts
|
|
312
|
-
|
|
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"]);
|
|
313
336
|
function lengthToCss(len) {
|
|
314
|
-
|
|
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}`;
|
|
315
341
|
}
|
|
316
342
|
function sizeToCss(size) {
|
|
317
343
|
if (size === "fill") return "100%";
|
|
318
344
|
if (size === "hug") return "auto";
|
|
319
345
|
return lengthToCss(size);
|
|
320
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
|
+
}
|
|
321
354
|
var ALIGN = {
|
|
322
355
|
start: "flex-start",
|
|
323
356
|
center: "center",
|
|
@@ -331,51 +364,150 @@ var JUSTIFY = {
|
|
|
331
364
|
between: "space-between",
|
|
332
365
|
around: "space-around"
|
|
333
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
|
+
}
|
|
334
402
|
function styleDecls(style) {
|
|
335
403
|
const d = {};
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
if (style.
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
if (style.
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
if (style.
|
|
352
|
-
|
|
353
|
-
if (
|
|
354
|
-
|
|
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;
|
|
355
449
|
return d;
|
|
356
450
|
}
|
|
357
|
-
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) {
|
|
358
463
|
const d = {};
|
|
359
464
|
if (node.layout === "stack") {
|
|
360
|
-
d["display"] = "flex";
|
|
361
|
-
|
|
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";
|
|
362
469
|
} else if (node.layout === "grid") {
|
|
363
|
-
d["display"] = "grid";
|
|
364
|
-
|
|
365
|
-
|
|
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) {
|
|
366
474
|
d["position"] = "relative";
|
|
367
475
|
}
|
|
368
476
|
return d;
|
|
369
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
|
+
}
|
|
370
502
|
function constraintDecls(c, parentFree) {
|
|
371
503
|
const d = {};
|
|
372
504
|
const transforms = [];
|
|
373
505
|
if (parentFree) {
|
|
374
506
|
d["position"] = "absolute";
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
507
|
+
putLen(d, ["left"], c.left);
|
|
508
|
+
putLen(d, ["right"], c.right);
|
|
509
|
+
putLen(d, ["top"], c.top);
|
|
510
|
+
putLen(d, ["bottom"], c.bottom);
|
|
379
511
|
if (c.centerX) {
|
|
380
512
|
d["left"] = "50%";
|
|
381
513
|
transforms.push("translateX(-50%)");
|
|
@@ -386,13 +518,15 @@ function constraintDecls(c, parentFree) {
|
|
|
386
518
|
}
|
|
387
519
|
if (transforms.length) d["transform"] = transforms.join(" ");
|
|
388
520
|
}
|
|
389
|
-
|
|
390
|
-
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;
|
|
391
525
|
return d;
|
|
392
526
|
}
|
|
393
527
|
function isParentFree(doc, node) {
|
|
394
528
|
if (node.parent === null) return false;
|
|
395
|
-
const parent = doc.nodes
|
|
529
|
+
const parent = own(doc.nodes, node.parent);
|
|
396
530
|
return !parent || parent.layout === void 0 || parent.layout === "free";
|
|
397
531
|
}
|
|
398
532
|
function serializeRule(selector, decls, indent) {
|
|
@@ -407,14 +541,17 @@ function emitDocCss(doc) {
|
|
|
407
541
|
if (!hasNodeMap(doc)) return "";
|
|
408
542
|
const breakpointPx = DEFAULT_BREAKPOINTS;
|
|
409
543
|
const blocks = [];
|
|
544
|
+
const themeRule = serializeRule(":root", themeDecls(doc.theme), "");
|
|
545
|
+
if (themeRule) blocks.push(themeRule);
|
|
410
546
|
for (const id of Object.keys(doc.nodes).sort()) {
|
|
411
547
|
const node = doc.nodes[id];
|
|
412
548
|
const selector = selectorFor(id);
|
|
413
549
|
const parentFree = isParentFree(doc, node);
|
|
414
550
|
const base = {
|
|
415
|
-
...
|
|
551
|
+
...containerDecls(node, node.style.base, true),
|
|
416
552
|
...node.constraints ? constraintDecls(node.constraints.base, parentFree) : {},
|
|
417
|
-
...styleDecls(node.style.base)
|
|
553
|
+
...styleDecls(node.style.base),
|
|
554
|
+
...visibilityDecls(node, node.style.base, true)
|
|
418
555
|
};
|
|
419
556
|
const baseRule = serializeRule(selector, base, "");
|
|
420
557
|
if (baseRule) blocks.push(baseRule);
|
|
@@ -422,9 +559,12 @@ function emitDocCss(doc) {
|
|
|
422
559
|
if (bp === "base") continue;
|
|
423
560
|
const px = breakpointPx[bp];
|
|
424
561
|
if (px === void 0) continue;
|
|
562
|
+
const bpStyle = node.style[bp];
|
|
425
563
|
const decls = {
|
|
564
|
+
...bpStyle ? containerDecls(node, bpStyle, false) : {},
|
|
426
565
|
...node.constraints?.[bp] ? constraintDecls(node.constraints[bp], parentFree) : {},
|
|
427
|
-
...
|
|
566
|
+
...bpStyle ? styleDecls(bpStyle) : {},
|
|
567
|
+
...bpStyle ? visibilityDecls(node, bpStyle, false) : {}
|
|
428
568
|
};
|
|
429
569
|
const inner = serializeRule(selector, decls, " ");
|
|
430
570
|
if (inner) blocks.push(`@media (min-width: ${px}px) {
|
|
@@ -442,6 +582,48 @@ function resolveValue(v, data) {
|
|
|
442
582
|
if (isBinding(v)) return getPath(data, v.$bind);
|
|
443
583
|
return v;
|
|
444
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
|
+
}
|
|
445
627
|
var defaultRegistry = {
|
|
446
628
|
section: ({ children }) => children,
|
|
447
629
|
stack: ({ children }) => children,
|
|
@@ -454,7 +636,12 @@ var defaultRegistry = {
|
|
|
454
636
|
// Rich text — inline-formatted HTML (gradient spans, links, <code>, …) that
|
|
455
637
|
// plain `text` can't express. The author owns the markup (it's their content).
|
|
456
638
|
richtext: ({ node, text }) => /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: text(node.props.html) } }),
|
|
457
|
-
|
|
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
|
+
},
|
|
458
645
|
divider: () => /* @__PURE__ */ jsxRuntime.jsx("hr", { style: { border: "none", borderTop: "1px solid #e2e8f0", margin: 0 } }),
|
|
459
646
|
callout: ({ node, text }) => {
|
|
460
647
|
const tone = { info: "#3b82f6", success: "#10b981", warning: "#f59e0b", danger: "#ef4444" }[text(node.props.variant)] ?? "#3b82f6";
|
|
@@ -466,15 +653,20 @@ var defaultRegistry = {
|
|
|
466
653
|
const variant = text(node.props.variant) || "primary";
|
|
467
654
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cms-button": variant, style: buttonStyle(variant), children: label2 });
|
|
468
655
|
},
|
|
469
|
-
image: ({ node, text }) =>
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
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
|
+
}
|
|
477
668
|
};
|
|
669
|
+
var IMAGE_FITS = /* @__PURE__ */ new Set(["cover", "contain", "fill", "none", "scale-down"]);
|
|
478
670
|
function buttonStyle(variant) {
|
|
479
671
|
const base = {
|
|
480
672
|
display: "inline-flex",
|
|
@@ -493,7 +685,7 @@ function buttonStyle(variant) {
|
|
|
493
685
|
return { ...base, background: "#7c3aed", color: "#fff", border: "1px solid #7c3aed" };
|
|
494
686
|
}
|
|
495
687
|
function RenderNode({ doc, id, registry = defaultRegistry, data }) {
|
|
496
|
-
const node = doc.nodes
|
|
688
|
+
const node = own(doc.nodes, id);
|
|
497
689
|
if (!node) return null;
|
|
498
690
|
if (node.type === "repeater") {
|
|
499
691
|
const arr = resolveValue(node.props.items, data);
|
|
@@ -509,7 +701,19 @@ function RenderNode({ doc, id, registry = defaultRegistry, data }) {
|
|
|
509
701
|
};
|
|
510
702
|
const renderer = registry[node.type];
|
|
511
703
|
const inner = renderer ? renderer({ node, doc, children: kids, data, resolve, text }) : node.island ? null : kids;
|
|
512
|
-
|
|
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
|
+
);
|
|
513
717
|
}
|
|
514
718
|
function CmsPage({
|
|
515
719
|
doc: input2,
|
|
@@ -911,7 +1115,8 @@ var ADD_DEFAULTS = {
|
|
|
911
1115
|
divider: { type: "divider", props: {}, style: {} },
|
|
912
1116
|
code: { type: "code", props: { content: "npm install @particle-academy/react-fancy", lang: "bash" }, style: {} },
|
|
913
1117
|
richtext: { type: "richtext", props: { html: "<p>Rich <strong>text</strong> with <em>inline</em> formatting.</p>" }, style: {} },
|
|
914
|
-
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: {} }
|
|
915
1120
|
};
|
|
916
1121
|
var ADD_MENU = [
|
|
917
1122
|
{ kind: "heading", label: "Heading" },
|
|
@@ -927,6 +1132,7 @@ var ADD_MENU = [
|
|
|
927
1132
|
{ kind: "divider", label: "Divider" },
|
|
928
1133
|
{ kind: "code", label: "Code" },
|
|
929
1134
|
{ kind: "richtext", label: "Rich text" },
|
|
1135
|
+
{ kind: "list", label: "List" },
|
|
930
1136
|
{ kind: "repeater", label: "Repeater" }
|
|
931
1137
|
];
|
|
932
1138
|
function resolveInsertParent(doc, selectedId) {
|