@particle-academy/fancy-cms-ui 0.0.1-dev.9 → 0.1.1
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/README.md +72 -0
- package/dist/chunk-524NYOHK.js +450 -0
- package/dist/chunk-524NYOHK.js.map +1 -0
- package/dist/{chunk-3YZMELJJ.js → chunk-GOXVGEKU.js} +94 -3
- package/dist/chunk-GOXVGEKU.js.map +1 -0
- package/dist/chunk-QYNWSECG.js +19 -0
- package/dist/chunk-QYNWSECG.js.map +1 -0
- package/dist/editor.cjs +338 -60
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.d.cts +7 -92
- package/dist/editor.d.ts +7 -92
- package/dist/editor.js +318 -459
- package/dist/editor.js.map +1 -1
- package/dist/index.cjs +516 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +3 -2
- package/dist/react.cjs +45 -25
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +13 -6
- package/dist/react.d.ts +13 -6
- package/dist/react.js +2 -19
- package/dist/react.js.map +1 -1
- package/dist/{types-CpfPEq3V.d.cts → registry-D5y5IgCR.d.cts} +30 -1
- package/dist/{types-CpfPEq3V.d.ts → registry-D5y5IgCR.d.ts} +30 -1
- package/dist/useEditor-DLH7hU6G.d.cts +162 -0
- package/dist/useEditor-qmF9n2e6.d.ts +162 -0
- package/package.json +7 -6
- package/dist/chunk-3YZMELJJ.js.map +0 -1
- package/dist/chunk-7YYLYBLI.js +0 -47
- package/dist/chunk-7YYLYBLI.js.map +0 -1
- package/dist/chunk-ZV7CV54P.js +0 -78
- package/dist/chunk-ZV7CV54P.js.map +0 -1
- package/dist/ops-BsM6kZxY.d.ts +0 -75
- package/dist/ops-CdBZarAT.d.cts +0 -75
- package/dist/registry-Bk7GN1rA.d.cts +0 -19
- package/dist/registry-Dht9JBLU.d.ts +0 -19
package/dist/editor.cjs
CHANGED
|
@@ -225,6 +225,13 @@ function useEditor(initialDoc) {
|
|
|
225
225
|
[state, apply, undo, redo, select, replace]
|
|
226
226
|
);
|
|
227
227
|
}
|
|
228
|
+
function useLatestRef(value) {
|
|
229
|
+
const ref = react.useRef(value);
|
|
230
|
+
react.useEffect(() => {
|
|
231
|
+
ref.current = value;
|
|
232
|
+
});
|
|
233
|
+
return ref;
|
|
234
|
+
}
|
|
228
235
|
|
|
229
236
|
// src/document/types.ts
|
|
230
237
|
function isBinding(v) {
|
|
@@ -361,10 +368,13 @@ ${inner}
|
|
|
361
368
|
}
|
|
362
369
|
return blocks.join("\n\n") + (blocks.length ? "\n" : "");
|
|
363
370
|
}
|
|
364
|
-
function
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
371
|
+
function getPath(data, path) {
|
|
372
|
+
return path.split(".").reduce((o, k) => o == null ? void 0 : o[k], data);
|
|
373
|
+
}
|
|
374
|
+
function resolveValue(v, data) {
|
|
375
|
+
if (v === void 0 || v === null) return v;
|
|
376
|
+
if (isBinding(v)) return getPath(data, v.$bind);
|
|
377
|
+
return v;
|
|
368
378
|
}
|
|
369
379
|
var defaultRegistry = {
|
|
370
380
|
section: ({ children }) => children,
|
|
@@ -372,18 +382,29 @@ var defaultRegistry = {
|
|
|
372
382
|
grid: ({ children }) => children,
|
|
373
383
|
frame: ({ children }) => children,
|
|
374
384
|
shape: ({ children }) => children,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
385
|
+
card: ({ children }) => children,
|
|
386
|
+
text: ({ node, text }) => text(node.props.content),
|
|
387
|
+
heading: ({ node, text }) => text(node.props.content) || "Heading",
|
|
388
|
+
// Rich text — inline-formatted HTML (gradient spans, links, <code>, …) that
|
|
389
|
+
// plain `text` can't express. The author owns the markup (it's their content).
|
|
390
|
+
richtext: ({ node, text }) => /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: text(node.props.html) } }),
|
|
391
|
+
link: ({ node, text }) => /* @__PURE__ */ jsxRuntime.jsx("a", { href: text(node.props.href) || "#", style: { color: "inherit", textDecoration: "underline" }, children: text(node.props.content) || "link" }),
|
|
392
|
+
divider: () => /* @__PURE__ */ jsxRuntime.jsx("hr", { style: { border: "none", borderTop: "1px solid #e2e8f0", margin: 0 } }),
|
|
393
|
+
callout: ({ node, text }) => {
|
|
394
|
+
const tone = { info: "#3b82f6", success: "#10b981", warning: "#f59e0b", danger: "#ef4444" }[text(node.props.variant)] ?? "#3b82f6";
|
|
395
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: 10, padding: "12px 14px", borderRadius: 10, background: `${tone}14`, borderLeft: `3px solid ${tone}` }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 13 }, children: text(node.props.content) || "Callout" }) });
|
|
396
|
+
},
|
|
397
|
+
code: ({ node, text }) => /* @__PURE__ */ jsxRuntime.jsx("pre", { style: { margin: 0, padding: "12px 14px", borderRadius: 10, background: "#0b1220", color: "#e2e8f0", fontFamily: "ui-monospace, monospace", fontSize: 13, overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: text(node.props.content) }) }),
|
|
398
|
+
button: ({ node, text }) => {
|
|
399
|
+
const label2 = text(node.props.label) || text(node.props.content) || "Button";
|
|
400
|
+
const variant = text(node.props.variant) || "primary";
|
|
380
401
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cms-button": variant, style: buttonStyle(variant), children: label2 });
|
|
381
402
|
},
|
|
382
|
-
image: ({ node }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
403
|
+
image: ({ node, text }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
383
404
|
"img",
|
|
384
405
|
{
|
|
385
|
-
src:
|
|
386
|
-
alt:
|
|
406
|
+
src: text(node.props.src),
|
|
407
|
+
alt: text(node.props.alt),
|
|
387
408
|
style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
|
|
388
409
|
}
|
|
389
410
|
)
|
|
@@ -405,30 +426,34 @@ function buttonStyle(variant) {
|
|
|
405
426
|
if (variant === "outline") return { ...base, background: "transparent", color: "#7c3aed", border: "1px solid #7c3aed" };
|
|
406
427
|
return { ...base, background: "#7c3aed", color: "#fff", border: "1px solid #7c3aed" };
|
|
407
428
|
}
|
|
408
|
-
function RenderNode({ doc, id, registry = defaultRegistry }) {
|
|
429
|
+
function RenderNode({ doc, id, registry = defaultRegistry, data }) {
|
|
409
430
|
const node = doc.nodes[id];
|
|
410
431
|
if (!node) return null;
|
|
411
|
-
|
|
432
|
+
if (node.type === "repeater") {
|
|
433
|
+
const arr = resolveValue(node.props.items, data);
|
|
434
|
+
const items = Array.isArray(arr) ? arr : [];
|
|
435
|
+
const template = childrenOf(doc, id)[0];
|
|
436
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cms": node.id, className: node.className, children: template ? items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(RenderNode, { doc, id: template.id, registry, data: { ...data, item, index } }, index)) : null });
|
|
437
|
+
}
|
|
438
|
+
const kids = childrenOf(doc, id).map((child) => /* @__PURE__ */ jsxRuntime.jsx(RenderNode, { doc, id: child.id, registry, data }, child.id));
|
|
439
|
+
const resolve = (v) => resolveValue(v, data);
|
|
440
|
+
const text = (v) => {
|
|
441
|
+
const r = resolve(v);
|
|
442
|
+
return r === void 0 || r === null ? "" : String(r);
|
|
443
|
+
};
|
|
412
444
|
const renderer = registry[node.type];
|
|
413
|
-
const inner = renderer ? renderer({ node, doc, children: kids }) : node.island ? null : kids;
|
|
414
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
415
|
-
"div",
|
|
416
|
-
{
|
|
417
|
-
"data-cms": node.id,
|
|
418
|
-
"data-cms-island": node.island ? node.type : void 0,
|
|
419
|
-
className: node.className,
|
|
420
|
-
children: inner
|
|
421
|
-
}
|
|
422
|
-
);
|
|
445
|
+
const inner = renderer ? renderer({ node, doc, children: kids, data, resolve, text }) : node.island ? null : kids;
|
|
446
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cms": node.id, "data-cms-island": node.island ? node.type : void 0, className: node.className, children: inner });
|
|
423
447
|
}
|
|
424
448
|
function CmsPage({
|
|
425
449
|
doc,
|
|
426
450
|
registry = defaultRegistry,
|
|
451
|
+
data,
|
|
427
452
|
includeStyles = true
|
|
428
453
|
}) {
|
|
429
454
|
return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
|
|
430
455
|
includeStyles ? /* @__PURE__ */ jsxRuntime.jsx("style", { "data-cms-styles": "", children: emitDocCss(doc) }) : null,
|
|
431
|
-
doc.sections.map((id) => /* @__PURE__ */ jsxRuntime.jsx(RenderNode, { doc, id, registry }, id))
|
|
456
|
+
doc.sections.map((id) => /* @__PURE__ */ jsxRuntime.jsx(RenderNode, { doc, id, registry, data }, id))
|
|
432
457
|
] });
|
|
433
458
|
}
|
|
434
459
|
function Canvas({ doc, selection, onSelect, apply }) {
|
|
@@ -740,13 +765,14 @@ function Inspector({ doc, selection, apply }) {
|
|
|
740
765
|
function Editor({ defaultValue, onChange }) {
|
|
741
766
|
const ed = useEditor(defaultValue);
|
|
742
767
|
const first = react.useRef(true);
|
|
768
|
+
const onChangeRef = useLatestRef(onChange);
|
|
743
769
|
react.useEffect(() => {
|
|
744
770
|
if (first.current) {
|
|
745
771
|
first.current = false;
|
|
746
772
|
return;
|
|
747
773
|
}
|
|
748
|
-
|
|
749
|
-
}, [ed.state.doc,
|
|
774
|
+
onChangeRef.current?.(ed.state.doc);
|
|
775
|
+
}, [ed.state.doc, onChangeRef]);
|
|
750
776
|
const shell = {
|
|
751
777
|
display: "grid",
|
|
752
778
|
gridTemplateColumns: "220px 1fr 300px",
|
|
@@ -802,7 +828,7 @@ function Toolbar({ ed }) {
|
|
|
802
828
|
}
|
|
803
829
|
);
|
|
804
830
|
}
|
|
805
|
-
var CONTAINER_TYPES = /* @__PURE__ */ new Set(["section", "frame", "stack", "grid", "shape"]);
|
|
831
|
+
var CONTAINER_TYPES = /* @__PURE__ */ new Set(["section", "frame", "stack", "grid", "shape", "card", "device"]);
|
|
806
832
|
function NodeInspector({
|
|
807
833
|
node,
|
|
808
834
|
transform,
|
|
@@ -816,9 +842,9 @@ function NodeInspector({
|
|
|
816
842
|
}) {
|
|
817
843
|
const base = node.style.base ?? {};
|
|
818
844
|
const setT = (patch) => onTransform({ ...transform, ...patch });
|
|
819
|
-
const handled = /* @__PURE__ */ new Set(["content", "label"]);
|
|
845
|
+
const handled = /* @__PURE__ */ new Set(["content", "label", "html"]);
|
|
820
846
|
const extraKeys = Object.keys(node.props).filter(
|
|
821
|
-
(k) => !handled.has(k) && ["string", "number", "boolean"].includes(typeof node.props[k])
|
|
847
|
+
(k) => !handled.has(k) && (["string", "number", "boolean"].includes(typeof node.props[k]) || isBinding(node.props[k]))
|
|
822
848
|
);
|
|
823
849
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: panel, onPointerDown: (e) => e.stopPropagation(), children: [
|
|
824
850
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: headRow, children: [
|
|
@@ -831,14 +857,11 @@ function NodeInspector({
|
|
|
831
857
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: iconBtn, title: "Close", onClick: onClose, children: "\u2715" })
|
|
832
858
|
] }),
|
|
833
859
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: body, children: [
|
|
834
|
-
"content" in node.props ? /* @__PURE__ */ jsxRuntime.
|
|
835
|
-
"
|
|
836
|
-
{
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
onChange: (e) => onProps({ content: e.target.value })
|
|
840
|
-
}
|
|
841
|
-
) }) : null,
|
|
860
|
+
"content" in node.props || node.type === "richtext" ? /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { fontSize: 11, color: "var(--fg-3, #94a3b8)", margin: "0 0 12px", lineHeight: 1.45, paddingBottom: 12, borderBottom: "1px solid #1e293b" }, children: [
|
|
861
|
+
"\u270E Edit the text ",
|
|
862
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: "directly on the page" }),
|
|
863
|
+
" \u2014 click in and type. This panel is for layout, style, and bindings."
|
|
864
|
+
] }) : null,
|
|
842
865
|
"label" in node.props ? /* @__PURE__ */ jsxRuntime.jsx(Group, { label: "Label", children: /* @__PURE__ */ jsxRuntime.jsx("input", { style: input2, value: String(node.props.label ?? ""), onChange: (e) => onProps({ label: e.target.value }) }) }) : null,
|
|
843
866
|
extraKeys.length ? /* @__PURE__ */ jsxRuntime.jsx(Group, { label: "Properties", children: extraKeys.map((k) => /* @__PURE__ */ jsxRuntime.jsx(PropField, { name: k, value: node.props[k], onChange: (v) => onProps({ [k]: v }) }, k)) }) : null,
|
|
844
867
|
/* @__PURE__ */ jsxRuntime.jsxs(Group, { label: "Position & size", children: [
|
|
@@ -943,24 +966,50 @@ function Row({ children }) {
|
|
|
943
966
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: 8 }, children });
|
|
944
967
|
}
|
|
945
968
|
function PropField({ name, value, onChange }) {
|
|
969
|
+
const bound = isBinding(value);
|
|
970
|
+
const link = /* @__PURE__ */ jsxRuntime.jsx(
|
|
971
|
+
"button",
|
|
972
|
+
{
|
|
973
|
+
type: "button",
|
|
974
|
+
title: bound ? "Unbind (use a literal value)" : "Bind to data (e.g. item.name)",
|
|
975
|
+
onClick: () => onChange(bound ? "" : { $bind: "" }),
|
|
976
|
+
style: { background: "none", border: "none", cursor: "pointer", padding: 0, fontSize: 11, color: bound ? "#a78bfa" : "#64748b" },
|
|
977
|
+
children: "\u{1F517}"
|
|
978
|
+
}
|
|
979
|
+
);
|
|
980
|
+
if (bound) {
|
|
981
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("label", { style: field, children: [
|
|
982
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { ...fieldLabel, display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
|
|
983
|
+
name,
|
|
984
|
+
" ",
|
|
985
|
+
link
|
|
986
|
+
] }),
|
|
987
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { style: { ...input2, borderColor: "#7c3aed" }, placeholder: "data path \xB7 e.g. item.name", value: value.$bind, onChange: (e) => onChange({ $bind: e.target.value }) })
|
|
988
|
+
] });
|
|
989
|
+
}
|
|
946
990
|
if (typeof value === "boolean") {
|
|
947
991
|
return /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 8, fontSize: 12 }, children: [
|
|
948
992
|
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: value, onChange: (e) => onChange(e.target.checked) }),
|
|
949
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { textTransform: "capitalize" }, children: name })
|
|
993
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { textTransform: "capitalize", flex: 1 }, children: name }),
|
|
994
|
+
link
|
|
950
995
|
] });
|
|
951
996
|
}
|
|
952
997
|
if (name === "variant") {
|
|
953
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Sel, { label: name, value: String(value), options: [["primary", "Primary"], ["ghost", "Ghost"], ["outline", "Outline"]], onChange });
|
|
998
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Sel, { label: name, value: String(value ?? ""), options: [["primary", "Primary"], ["ghost", "Ghost"], ["outline", "Outline"]], onChange });
|
|
954
999
|
}
|
|
955
1000
|
const isNum = typeof value === "number";
|
|
956
1001
|
return /* @__PURE__ */ jsxRuntime.jsxs("label", { style: field, children: [
|
|
957
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1002
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { ...fieldLabel, display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
|
|
1003
|
+
name,
|
|
1004
|
+
" ",
|
|
1005
|
+
link
|
|
1006
|
+
] }),
|
|
958
1007
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
959
1008
|
"input",
|
|
960
1009
|
{
|
|
961
1010
|
style: input2,
|
|
962
1011
|
type: isNum ? "number" : "text",
|
|
963
|
-
value: String(value),
|
|
1012
|
+
value: String(value ?? ""),
|
|
964
1013
|
onChange: (e) => onChange(isNum ? Number(e.target.value) : e.target.value)
|
|
965
1014
|
}
|
|
966
1015
|
)
|
|
@@ -1144,9 +1193,11 @@ function snapshotSubtree(doc, id) {
|
|
|
1144
1193
|
return { rootId: id, nodes };
|
|
1145
1194
|
}
|
|
1146
1195
|
var Z2 = 2147483e3;
|
|
1196
|
+
var SNAP = 6;
|
|
1147
1197
|
function EditablePage({
|
|
1148
1198
|
doc,
|
|
1149
1199
|
registry = defaultRegistry,
|
|
1200
|
+
data,
|
|
1150
1201
|
timelineDock,
|
|
1151
1202
|
transforms,
|
|
1152
1203
|
onNodeTransform,
|
|
@@ -1163,7 +1214,8 @@ function EditablePage({
|
|
|
1163
1214
|
const [box, setBox] = react.useState(null);
|
|
1164
1215
|
const { selection } = ed.state;
|
|
1165
1216
|
const selNode = selection ? ed.state.doc.nodes[selection] : null;
|
|
1166
|
-
|
|
1217
|
+
const onSelectRef = useLatestRef(onSelect);
|
|
1218
|
+
react.useEffect(() => onSelectRef.current?.(selection), [selection, onSelectRef]);
|
|
1167
1219
|
react.useEffect(() => {
|
|
1168
1220
|
const onKey = (e) => setRevealed(e.ctrlKey && e.shiftKey);
|
|
1169
1221
|
const onBlur = () => setRevealed(false);
|
|
@@ -1185,13 +1237,15 @@ function EditablePage({
|
|
|
1185
1237
|
applyTransform(el, t);
|
|
1186
1238
|
});
|
|
1187
1239
|
}, [transforms, ed.state.doc]);
|
|
1240
|
+
const onProgressRef = useLatestRef(onProgress);
|
|
1241
|
+
const hasProgress = !!onProgress;
|
|
1188
1242
|
react.useEffect(() => {
|
|
1189
1243
|
const spacer = spacerRef.current;
|
|
1190
|
-
if (!spacer || !
|
|
1244
|
+
if (!spacer || !hasProgress) return;
|
|
1191
1245
|
const compute = () => {
|
|
1192
1246
|
const len2 = spacer.offsetHeight - window.innerHeight;
|
|
1193
1247
|
const top = spacer.getBoundingClientRect().top;
|
|
1194
|
-
|
|
1248
|
+
onProgressRef.current?.(len2 > 0 ? Math.min(1, Math.max(0, -top / len2)) : 0);
|
|
1195
1249
|
};
|
|
1196
1250
|
compute();
|
|
1197
1251
|
window.addEventListener("scroll", compute, { passive: true });
|
|
@@ -1200,7 +1254,7 @@ function EditablePage({
|
|
|
1200
1254
|
window.removeEventListener("scroll", compute);
|
|
1201
1255
|
window.removeEventListener("resize", compute);
|
|
1202
1256
|
};
|
|
1203
|
-
}, [
|
|
1257
|
+
}, [hasProgress, onProgressRef, frames]);
|
|
1204
1258
|
const measureBox = react.useCallback(() => {
|
|
1205
1259
|
if (!editing || !selection || !pageRef.current) return setBox(null);
|
|
1206
1260
|
const el = pageRef.current.querySelector(`[data-cms="${cssEscape2(selection)}"]`);
|
|
@@ -1218,13 +1272,17 @@ function EditablePage({
|
|
|
1218
1272
|
};
|
|
1219
1273
|
}, [measureBox, ed.state.doc]);
|
|
1220
1274
|
react.useEffect(() => {
|
|
1221
|
-
|
|
1222
|
-
const
|
|
1223
|
-
if (!
|
|
1275
|
+
const t = selNode?.type;
|
|
1276
|
+
const editable = t === "text" || t === "heading" || t === "richtext";
|
|
1277
|
+
if (!editing || !selection || !pageRef.current || !editable) return;
|
|
1278
|
+
const wrapper = pageRef.current.querySelector(`[data-cms="${cssEscape2(selection)}"]`);
|
|
1279
|
+
if (!wrapper) return;
|
|
1280
|
+
const isRich = t === "richtext";
|
|
1281
|
+
const el = (isRich ? wrapper.firstElementChild : wrapper) ?? wrapper;
|
|
1224
1282
|
el.setAttribute("contenteditable", "true");
|
|
1225
1283
|
el.style.outline = "none";
|
|
1226
1284
|
el.focus();
|
|
1227
|
-
const commit = () => ed.apply({ t: "set_props", id: selection, patch: { content: el.innerText } });
|
|
1285
|
+
const commit = () => ed.apply({ t: "set_props", id: selection, patch: isRich ? { html: el.innerHTML } : { content: el.innerText } });
|
|
1228
1286
|
el.addEventListener("blur", commit);
|
|
1229
1287
|
return () => {
|
|
1230
1288
|
el.removeEventListener("blur", commit);
|
|
@@ -1249,11 +1307,84 @@ function EditablePage({
|
|
|
1249
1307
|
const order = keyBetween(siblings.length ? siblings[siblings.length - 1].order : null, null);
|
|
1250
1308
|
const id = `n${doc2.seq + 1}-${Math.floor(performance.now())}`;
|
|
1251
1309
|
const def = ADD_DEFAULTS[kind];
|
|
1252
|
-
ed.apply({ t: "insert_node", node: { id, type: def.type, parent, order, props: { ...def.props }, style: { base: { ...def.style } } } });
|
|
1310
|
+
ed.apply({ t: "insert_node", node: { id, type: def.type, parent, order, layout: def.layout, props: { ...def.props }, style: { base: { ...def.style } } } });
|
|
1253
1311
|
ed.select(id);
|
|
1254
1312
|
},
|
|
1255
1313
|
[ed, selNode]
|
|
1256
1314
|
);
|
|
1315
|
+
react.useCallback(
|
|
1316
|
+
(kind, targetId) => {
|
|
1317
|
+
const doc2 = ed.state.doc;
|
|
1318
|
+
const target = targetId ? doc2.nodes[targetId] : null;
|
|
1319
|
+
const parent = target ? CONTAINER_TYPES2.has(target.type) ? target.id : target.parent : doc2.sections[doc2.sections.length - 1] ?? null;
|
|
1320
|
+
const siblings = childrenOf(doc2, parent);
|
|
1321
|
+
const order = keyBetween(siblings.length ? siblings[siblings.length - 1].order : null, null);
|
|
1322
|
+
const id = `n${doc2.seq + 1}-${Math.floor(performance.now())}`;
|
|
1323
|
+
const def = ADD_DEFAULTS[kind];
|
|
1324
|
+
ed.apply({ t: "insert_node", node: { id, type: def.type, parent, order, layout: def.layout, props: { ...def.props }, style: { base: { ...def.style } } } });
|
|
1325
|
+
ed.select(id);
|
|
1326
|
+
},
|
|
1327
|
+
[ed]
|
|
1328
|
+
);
|
|
1329
|
+
const [paletteOpen, setPaletteOpen] = react.useState(false);
|
|
1330
|
+
const [draggingEl, setDraggingEl] = react.useState(false);
|
|
1331
|
+
react.useEffect(() => {
|
|
1332
|
+
if (!editing) {
|
|
1333
|
+
setPaletteOpen(false);
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
const onMove = (e) => {
|
|
1337
|
+
if (draggingEl) return;
|
|
1338
|
+
if (e.clientX >= window.innerWidth - 26) setPaletteOpen(true);
|
|
1339
|
+
else if (e.clientX < window.innerWidth - 236) setPaletteOpen(false);
|
|
1340
|
+
};
|
|
1341
|
+
window.addEventListener("mousemove", onMove);
|
|
1342
|
+
return () => window.removeEventListener("mousemove", onMove);
|
|
1343
|
+
}, [editing, draggingEl]);
|
|
1344
|
+
const [dropHint, setDropHint] = react.useState(null);
|
|
1345
|
+
const computeDropTarget = (clientX, clientY) => {
|
|
1346
|
+
const el = document.elementFromPoint(clientX, clientY)?.closest("[data-cms]");
|
|
1347
|
+
if (!el) return { id: null, edge: "inside", rect: null };
|
|
1348
|
+
const id = el.getAttribute("data-cms");
|
|
1349
|
+
const node = ed.state.doc.nodes[id];
|
|
1350
|
+
const r = el.getBoundingClientRect();
|
|
1351
|
+
const rect = { x: r.left, y: r.top, w: r.width, h: r.height };
|
|
1352
|
+
if (node && CONTAINER_TYPES2.has(node.type)) return { id, edge: "inside", rect };
|
|
1353
|
+
return { id, edge: clientY < r.top + r.height / 2 ? "before" : "after", rect };
|
|
1354
|
+
};
|
|
1355
|
+
const onPageDragOver = (e) => {
|
|
1356
|
+
e.preventDefault();
|
|
1357
|
+
e.dataTransfer.dropEffect = "copy";
|
|
1358
|
+
setDropHint(computeDropTarget(e.clientX, e.clientY));
|
|
1359
|
+
};
|
|
1360
|
+
const insertRelative = (kind, hint) => {
|
|
1361
|
+
const doc2 = ed.state.doc;
|
|
1362
|
+
let parent;
|
|
1363
|
+
let order;
|
|
1364
|
+
if (!hint.id || hint.edge === "inside") {
|
|
1365
|
+
parent = hint.id ?? (doc2.sections[doc2.sections.length - 1] ?? null);
|
|
1366
|
+
const sib = childrenOf(doc2, parent);
|
|
1367
|
+
order = keyBetween(sib.length ? sib[sib.length - 1].order : null, null);
|
|
1368
|
+
} else {
|
|
1369
|
+
const target = doc2.nodes[hint.id];
|
|
1370
|
+
parent = target.parent;
|
|
1371
|
+
const sib = childrenOf(doc2, parent);
|
|
1372
|
+
const idx = sib.findIndex((n) => n.id === hint.id);
|
|
1373
|
+
order = hint.edge === "before" ? keyBetween(idx > 0 ? sib[idx - 1].order : null, target.order) : keyBetween(target.order, idx < sib.length - 1 ? sib[idx + 1].order : null);
|
|
1374
|
+
}
|
|
1375
|
+
const id = `n${doc2.seq + 1}-${Math.floor(performance.now())}`;
|
|
1376
|
+
const def = ADD_DEFAULTS[kind];
|
|
1377
|
+
ed.apply({ t: "insert_node", node: { id, type: def.type, parent, order, layout: def.layout, props: { ...def.props }, style: { base: { ...def.style } } } });
|
|
1378
|
+
ed.select(id);
|
|
1379
|
+
};
|
|
1380
|
+
const onPageDrop = (e) => {
|
|
1381
|
+
const kind = e.dataTransfer.getData("application/x-cms-element");
|
|
1382
|
+
if (!kind) return;
|
|
1383
|
+
e.preventDefault();
|
|
1384
|
+
insertRelative(kind, computeDropTarget(e.clientX, e.clientY));
|
|
1385
|
+
setDropHint(null);
|
|
1386
|
+
setDraggingEl(false);
|
|
1387
|
+
};
|
|
1257
1388
|
const setStyle = (patch) => selection && ed.apply({ t: "set_style", id: selection, breakpoint: "base", patch });
|
|
1258
1389
|
const setProps = (patch) => selection && ed.apply({ t: "set_props", id: selection, patch });
|
|
1259
1390
|
const setLayout = (layout) => selection && ed.apply({ t: "set_layout", id: selection, layout });
|
|
@@ -1321,8 +1452,23 @@ function EditablePage({
|
|
|
1321
1452
|
if (el) ed.select(el.getAttribute("data-cms"));
|
|
1322
1453
|
else ed.select(null);
|
|
1323
1454
|
};
|
|
1324
|
-
const page = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1325
|
-
|
|
1455
|
+
const page = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1456
|
+
"div",
|
|
1457
|
+
{
|
|
1458
|
+
ref: pageRef,
|
|
1459
|
+
onClickCapture,
|
|
1460
|
+
onContextMenu: onContextMenuSelect,
|
|
1461
|
+
onDragOver: editing ? onPageDragOver : void 0,
|
|
1462
|
+
onDragLeave: editing ? () => setDropHint(null) : void 0,
|
|
1463
|
+
onDrop: editing ? onPageDrop : void 0,
|
|
1464
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(CmsPage, { doc: ed.state.doc, registry, data })
|
|
1465
|
+
}
|
|
1466
|
+
);
|
|
1467
|
+
const pageShell = pinned ? /* @__PURE__ */ jsxRuntime.jsx("div", { ref: spacerRef, style: { height: `${Math.max(1, frames) * 100}vh` }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "sticky", top: 0, height: "100vh", overflow: "hidden" }, children: page }) }) : frames > 1 ? (
|
|
1468
|
+
// Normal flow, but "expanded" — extra scroll length below the content so a
|
|
1469
|
+
// page can be made longer than its content (the + Frame control).
|
|
1470
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { minHeight: `${frames * 100}vh` }, children: page })
|
|
1471
|
+
) : page;
|
|
1326
1472
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
|
|
1327
1473
|
editing ? /* @__PURE__ */ jsxRuntime.jsxs(reactFancy.ContextMenu, { children: [
|
|
1328
1474
|
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.Trigger, { children: pageShell }),
|
|
@@ -1384,16 +1530,101 @@ function EditablePage({
|
|
|
1384
1530
|
onAdd: addNode
|
|
1385
1531
|
}
|
|
1386
1532
|
) : null,
|
|
1533
|
+
editing && dropHint?.rect ? /* @__PURE__ */ jsxRuntime.jsx(DropIndicator, { hint: dropHint }) : null,
|
|
1534
|
+
editing ? /* @__PURE__ */ jsxRuntime.jsx(ElementPalette, { open: paletteOpen, onDragChange: setDraggingEl }) : null,
|
|
1387
1535
|
editing && timelineDock ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "fixed", left: 0, right: 0, bottom: 0, zIndex: Z2 }, children: timelineDock }) : null
|
|
1388
1536
|
] });
|
|
1389
1537
|
}
|
|
1390
|
-
|
|
1538
|
+
function DropIndicator({
|
|
1539
|
+
hint
|
|
1540
|
+
}) {
|
|
1541
|
+
const r = hint.rect;
|
|
1542
|
+
if (!r) return null;
|
|
1543
|
+
const color = "#ec4899";
|
|
1544
|
+
if (hint.edge === "inside") {
|
|
1545
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "fixed", left: r.x, top: r.y, width: r.w, height: r.h, outline: `2px dashed ${color}`, outlineOffset: -2, borderRadius: 6, pointerEvents: "none", zIndex: Z2 + 4 } });
|
|
1546
|
+
}
|
|
1547
|
+
const y = hint.edge === "before" ? r.y : r.y + r.h;
|
|
1548
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "fixed", left: r.x, top: y - 1.5, width: r.w, height: 3, background: color, borderRadius: 2, boxShadow: "0 0 0 1px #fff", pointerEvents: "none", zIndex: Z2 + 4 } });
|
|
1549
|
+
}
|
|
1550
|
+
function ElementPalette({ open, onDragChange }) {
|
|
1551
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1552
|
+
"div",
|
|
1553
|
+
{
|
|
1554
|
+
style: {
|
|
1555
|
+
position: "fixed",
|
|
1556
|
+
top: 64,
|
|
1557
|
+
bottom: 96,
|
|
1558
|
+
right: 0,
|
|
1559
|
+
width: 216,
|
|
1560
|
+
transform: open ? "translateX(0)" : "translateX(100%)",
|
|
1561
|
+
transition: "transform 0.18s ease",
|
|
1562
|
+
background: "#0b1220",
|
|
1563
|
+
color: "#e2e8f0",
|
|
1564
|
+
borderLeft: "1px solid #1e293b",
|
|
1565
|
+
borderTopLeftRadius: 12,
|
|
1566
|
+
borderBottomLeftRadius: 12,
|
|
1567
|
+
boxShadow: "-18px 0 48px -20px rgba(0,0,0,0.6)",
|
|
1568
|
+
zIndex: Z2 + 2,
|
|
1569
|
+
fontFamily: "system-ui, sans-serif",
|
|
1570
|
+
padding: 12,
|
|
1571
|
+
overflowY: "auto"
|
|
1572
|
+
},
|
|
1573
|
+
children: [
|
|
1574
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, letterSpacing: "0.06em", textTransform: "uppercase", opacity: 0.5, marginBottom: 10 }, children: "Elements" }),
|
|
1575
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }, children: ADD_MENU.map((m) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1576
|
+
"div",
|
|
1577
|
+
{
|
|
1578
|
+
draggable: true,
|
|
1579
|
+
onDragStart: (e) => {
|
|
1580
|
+
e.dataTransfer.setData("application/x-cms-element", m.kind);
|
|
1581
|
+
e.dataTransfer.effectAllowed = "copy";
|
|
1582
|
+
onDragChange(true);
|
|
1583
|
+
},
|
|
1584
|
+
onDragEnd: () => onDragChange(false),
|
|
1585
|
+
title: `Drag "${m.label}" onto the page`,
|
|
1586
|
+
style: {
|
|
1587
|
+
display: "flex",
|
|
1588
|
+
flexDirection: "column",
|
|
1589
|
+
alignItems: "center",
|
|
1590
|
+
justifyContent: "center",
|
|
1591
|
+
gap: 4,
|
|
1592
|
+
height: 56,
|
|
1593
|
+
borderRadius: 8,
|
|
1594
|
+
background: "#0f172a",
|
|
1595
|
+
border: "1px solid #1e293b",
|
|
1596
|
+
cursor: "grab",
|
|
1597
|
+
fontSize: 12,
|
|
1598
|
+
userSelect: "none"
|
|
1599
|
+
},
|
|
1600
|
+
children: [
|
|
1601
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 16, opacity: 0.7 }, children: "\uFF0B" }),
|
|
1602
|
+
m.label
|
|
1603
|
+
]
|
|
1604
|
+
},
|
|
1605
|
+
m.kind
|
|
1606
|
+
)) }),
|
|
1607
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: 10.5, opacity: 0.45, marginTop: 12, lineHeight: 1.4 }, children: "Drag an Element onto the page. It drops into the container you release over." })
|
|
1608
|
+
]
|
|
1609
|
+
}
|
|
1610
|
+
);
|
|
1611
|
+
}
|
|
1612
|
+
var CONTAINER_TYPES2 = /* @__PURE__ */ new Set(["section", "frame", "stack", "grid", "shape", "card", "device", "repeater"]);
|
|
1391
1613
|
var ADD_DEFAULTS = {
|
|
1392
1614
|
text: { type: "text", props: { content: "New text" }, style: { color: "inherit" } },
|
|
1393
1615
|
heading: { type: "heading", props: { content: "New heading" }, style: { fontSize: { value: 28, unit: "px" }, fontWeight: 700 } },
|
|
1394
1616
|
button: { type: "button", props: { label: "Button", href: "#", variant: "primary" }, style: {} },
|
|
1617
|
+
link: { type: "link", props: { content: "link text", href: "#" }, style: { color: "#7c3aed" } },
|
|
1395
1618
|
image: { type: "image", props: { src: "", alt: "" }, style: {} },
|
|
1396
|
-
box: { type: "frame", props: {}, style: { padding: { value: 16, unit: "px" } } }
|
|
1619
|
+
box: { type: "frame", props: {}, style: { padding: { value: 16, unit: "px" } } },
|
|
1620
|
+
stack: { type: "stack", props: {}, style: { gap: { value: 12, unit: "px" } }, layout: "stack" },
|
|
1621
|
+
grid: { type: "grid", props: {}, style: { gap: { value: 12, unit: "px" } }, layout: "grid" },
|
|
1622
|
+
card: { type: "card", props: {}, style: { padding: { value: 16, unit: "px" }, radius: { value: 12, unit: "px" }, border: "1px solid #e2e8f0" } },
|
|
1623
|
+
callout: { type: "callout", props: { content: "Heads up \u2014 this is a callout.", variant: "info" }, style: {} },
|
|
1624
|
+
divider: { type: "divider", props: {}, style: {} },
|
|
1625
|
+
code: { type: "code", props: { content: "npm install @particle-academy/react-fancy", lang: "bash" }, style: {} },
|
|
1626
|
+
richtext: { type: "richtext", props: { html: "<p>Rich <strong>text</strong> with <em>inline</em> formatting.</p>" }, style: {} },
|
|
1627
|
+
repeater: { type: "repeater", props: { items: "" }, style: { gap: { value: 12, unit: "px" } }, layout: "stack" }
|
|
1397
1628
|
};
|
|
1398
1629
|
var GRIPS = [
|
|
1399
1630
|
{ key: "nw", north: true, west: true, cursor: "nwse-resize" },
|
|
@@ -1414,20 +1645,55 @@ function SelectionOverlay({
|
|
|
1414
1645
|
onLive
|
|
1415
1646
|
}) {
|
|
1416
1647
|
const drag = react.useRef(null);
|
|
1648
|
+
const targets = react.useRef({ vx: [], hy: [] });
|
|
1649
|
+
const [guides, setGuides] = react.useState({ x: null, y: null });
|
|
1417
1650
|
const apply = (t) => {
|
|
1418
1651
|
const el = getEl();
|
|
1419
1652
|
if (el) applyTransform(el, t);
|
|
1420
1653
|
};
|
|
1654
|
+
const snap = (cands, lines) => {
|
|
1655
|
+
let best = { delta: 0, at: null, dist: SNAP + 1 };
|
|
1656
|
+
for (const line of lines) {
|
|
1657
|
+
for (const c of cands) {
|
|
1658
|
+
const diff = line - c;
|
|
1659
|
+
if (Math.abs(diff) < best.dist) best = { delta: diff, at: line, dist: Math.abs(diff) };
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
return best.dist <= SNAP ? { delta: best.delta, at: best.at } : { delta: 0, at: null };
|
|
1663
|
+
};
|
|
1421
1664
|
const startMove = (e) => {
|
|
1422
1665
|
e.stopPropagation();
|
|
1423
1666
|
e.preventDefault();
|
|
1424
1667
|
e.currentTarget.setPointerCapture(e.pointerId);
|
|
1425
1668
|
drag.current = { x: e.clientX, y: e.clientY, w: box.w, h: box.h, live: { ...base } };
|
|
1669
|
+
const sel = getEl();
|
|
1670
|
+
const vx = /* @__PURE__ */ new Set();
|
|
1671
|
+
const hy = /* @__PURE__ */ new Set();
|
|
1672
|
+
document.querySelectorAll("[data-cms]").forEach((el) => {
|
|
1673
|
+
if (sel && (el === sel || sel.contains(el) || el.contains(sel))) return;
|
|
1674
|
+
const r = el.getBoundingClientRect();
|
|
1675
|
+
vx.add(r.left).add(r.left + r.width / 2).add(r.right);
|
|
1676
|
+
hy.add(r.top).add(r.top + r.height / 2).add(r.bottom);
|
|
1677
|
+
});
|
|
1678
|
+
targets.current = { vx: [...vx], hy: [...hy] };
|
|
1426
1679
|
};
|
|
1427
1680
|
const moveMove = (e) => {
|
|
1428
1681
|
const d = drag.current;
|
|
1429
1682
|
if (!d) return;
|
|
1430
|
-
|
|
1683
|
+
let dx = e.clientX - d.x;
|
|
1684
|
+
let dy = e.clientY - d.y;
|
|
1685
|
+
if (!e.altKey) {
|
|
1686
|
+
const l = box.x + dx;
|
|
1687
|
+
const t = box.y + dy;
|
|
1688
|
+
const sx = snap([l, l + box.w / 2, l + box.w], targets.current.vx);
|
|
1689
|
+
const sy = snap([t, t + box.h / 2, t + box.h], targets.current.hy);
|
|
1690
|
+
dx += sx.delta;
|
|
1691
|
+
dy += sy.delta;
|
|
1692
|
+
setGuides({ x: sx.at, y: sy.at });
|
|
1693
|
+
} else if (guides.x !== null || guides.y !== null) {
|
|
1694
|
+
setGuides({ x: null, y: null });
|
|
1695
|
+
}
|
|
1696
|
+
d.live = { ...base, x: (base.x ?? 0) + dx, y: (base.y ?? 0) + dy };
|
|
1431
1697
|
apply(d.live);
|
|
1432
1698
|
onLive();
|
|
1433
1699
|
};
|
|
@@ -1462,6 +1728,7 @@ function SelectionOverlay({
|
|
|
1462
1728
|
const d = drag.current;
|
|
1463
1729
|
if (d) onTransform(d.live);
|
|
1464
1730
|
drag.current = null;
|
|
1731
|
+
setGuides({ x: null, y: null });
|
|
1465
1732
|
};
|
|
1466
1733
|
const outline = {
|
|
1467
1734
|
position: "fixed",
|
|
@@ -1491,6 +1758,8 @@ function SelectionOverlay({
|
|
|
1491
1758
|
return { left: cx - 6, top: cy - 6, cursor: g.cursor };
|
|
1492
1759
|
};
|
|
1493
1760
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1761
|
+
guides.x !== null ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "fixed", left: guides.x, top: 0, bottom: 0, width: 1, background: "#ec4899", zIndex: Z2 + 3, pointerEvents: "none" } }) : null,
|
|
1762
|
+
guides.y !== null ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "fixed", top: guides.y, left: 0, right: 0, height: 1, background: "#ec4899", zIndex: Z2 + 3, pointerEvents: "none" } }) : null,
|
|
1494
1763
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: outline }),
|
|
1495
1764
|
movable ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1496
1765
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1555,11 +1824,20 @@ function FloatingToolbar({
|
|
|
1555
1824
|
] });
|
|
1556
1825
|
}
|
|
1557
1826
|
var ADD_MENU = [
|
|
1558
|
-
{ kind: "text", label: "Text" },
|
|
1559
1827
|
{ kind: "heading", label: "Heading" },
|
|
1828
|
+
{ kind: "text", label: "Text" },
|
|
1560
1829
|
{ kind: "button", label: "Button" },
|
|
1830
|
+
{ kind: "link", label: "Link" },
|
|
1561
1831
|
{ kind: "image", label: "Image" },
|
|
1562
|
-
{ kind: "
|
|
1832
|
+
{ kind: "card", label: "Card" },
|
|
1833
|
+
{ kind: "callout", label: "Callout" },
|
|
1834
|
+
{ kind: "stack", label: "Stack" },
|
|
1835
|
+
{ kind: "grid", label: "Grid" },
|
|
1836
|
+
{ kind: "box", label: "Box" },
|
|
1837
|
+
{ kind: "divider", label: "Divider" },
|
|
1838
|
+
{ kind: "code", label: "Code" },
|
|
1839
|
+
{ kind: "richtext", label: "Rich text" },
|
|
1840
|
+
{ kind: "repeater", label: "Repeater" }
|
|
1563
1841
|
];
|
|
1564
1842
|
function EditBar({
|
|
1565
1843
|
editing,
|
|
@@ -1577,7 +1855,7 @@ function EditBar({
|
|
|
1577
1855
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: { ...btn, background: editing ? "#8b5cf6" : "transparent" }, onClick: onToggle, children: editing ? "\u25CF Editing" : "Edit" }),
|
|
1578
1856
|
editing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1579
1857
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
|
|
1580
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: { ...btn, background: open ? "#1e293b" : "transparent" }, onClick: () => setOpen((v) => !v), title: "Add an
|
|
1858
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: { ...btn, background: open ? "#1e293b" : "transparent" }, onClick: () => setOpen((v) => !v), title: "Add an Element (or drag from the right-edge palette)", children: "\uFF0B Element \u25BE" }),
|
|
1581
1859
|
open ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", top: "calc(100% + 6px)", right: 0, background: "#0f172a", border: "1px solid #1e293b", borderRadius: 10, padding: 4, display: "flex", flexDirection: "column", minWidth: 132, boxShadow: "0 12px 32px -10px rgba(0,0,0,0.6)" }, children: ADD_MENU.map((m) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1582
1860
|
"button",
|
|
1583
1861
|
{
|
|
@@ -1615,7 +1893,7 @@ function EditMenuItems({
|
|
|
1615
1893
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1616
1894
|
editable ? /* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.Item, { onClick: onEditText, children: "Edit text" }) : null,
|
|
1617
1895
|
/* @__PURE__ */ jsxRuntime.jsxs(reactFancy.ContextMenu.Sub, { children: [
|
|
1618
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.SubTrigger, { children: isContainer ? "Add inside" : "Add" }),
|
|
1896
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.SubTrigger, { children: isContainer ? "Add Element inside" : "Add Element" }),
|
|
1619
1897
|
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.SubContent, { className: "!z-[2147483647]", children: ADD_MENU.map((m) => /* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.Item, { onClick: () => onAdd(m.kind), children: m.label }, m.kind)) })
|
|
1620
1898
|
] }),
|
|
1621
1899
|
node ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|