@particle-academy/fancy-cms-ui 0.1.1 → 0.3.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/dist/editor.cjs CHANGED
@@ -242,6 +242,17 @@ var DEFAULT_BREAKPOINTS = {
242
242
  md: 768,
243
243
  lg: 1024
244
244
  };
245
+ function emptyDoc(id, slug = "/") {
246
+ return {
247
+ id,
248
+ seq: 0,
249
+ meta: { title: "Untitled", slug, scrollMode: "smooth" },
250
+ theme: { name: "default" },
251
+ breakpoints: ["base", "md", "lg"],
252
+ sections: [],
253
+ nodes: {}
254
+ };
255
+ }
245
256
 
246
257
  // src/render/css.ts
247
258
  var selectorFor = (id) => `[data-cms="${id}"]`;
@@ -456,7 +467,7 @@ function CmsPage({
456
467
  doc.sections.map((id) => /* @__PURE__ */ jsxRuntime.jsx(RenderNode, { doc, id, registry, data }, id))
457
468
  ] });
458
469
  }
459
- function Canvas({ doc, selection, onSelect, apply }) {
470
+ function Canvas({ doc, selection, onSelect, apply, registry, data }) {
460
471
  const ref = react.useRef(null);
461
472
  const [box, setBox] = react.useState(null);
462
473
  const drag = react.useRef(null);
@@ -513,7 +524,7 @@ function Canvas({ doc, selection, onSelect, apply }) {
513
524
  position: "relative",
514
525
  overflow: "auto",
515
526
  height: "100%",
516
- background: "#f8fafc"
527
+ background: "var(--fcms-canvas)"
517
528
  };
518
529
  const overlay = box ? {
519
530
  position: "absolute",
@@ -521,13 +532,13 @@ function Canvas({ doc, selection, onSelect, apply }) {
521
532
  top: box.y,
522
533
  width: box.w,
523
534
  height: box.h,
524
- outline: "2px solid #8b5cf6",
535
+ outline: "2px solid var(--fcms-accent, #8b5cf6)",
525
536
  outlineOffset: -1,
526
537
  cursor: "move",
527
538
  touchAction: "none"
528
539
  } : { display: "none" };
529
540
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, onClick: handleClick, style: surface, children: [
530
- /* @__PURE__ */ jsxRuntime.jsx(CmsPage, { doc }),
541
+ /* @__PURE__ */ jsxRuntime.jsx(CmsPage, { doc, registry, data }),
531
542
  /* @__PURE__ */ jsxRuntime.jsx(
532
543
  "div",
533
544
  {
@@ -642,10 +653,10 @@ function LayerRow({ doc, id, depth, selection, onSelect, onMove, overId, setOver
642
653
  cursor: draggable ? "grab" : "pointer",
643
654
  padding: "4px 8px",
644
655
  paddingLeft: 8 + depth * 14,
645
- background: selected ? "#ede9fe" : "transparent",
646
- color: selected ? "#5b21b6" : "#334155",
656
+ background: selected ? "var(--fcms-sel-bg)" : "transparent",
657
+ color: selected ? "var(--fcms-sel-fg)" : "var(--fcms-row-fg)",
647
658
  font: "inherit",
648
- boxShadow: overId === id ? "inset 0 -2px 0 0 #8b5cf6" : "none"
659
+ boxShadow: overId === id ? "inset 0 -2px 0 0 var(--fcms-accent, #8b5cf6)" : "none"
649
660
  },
650
661
  children: [
651
662
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { opacity: 0.6 }, children: node.type }),
@@ -662,7 +673,7 @@ var label = {
662
673
  fontSize: 11,
663
674
  textTransform: "uppercase",
664
675
  letterSpacing: "0.04em",
665
- color: "#94a3b8",
676
+ color: "var(--fcms-muted)",
666
677
  margin: "10px 0 4px"
667
678
  };
668
679
  var input = {
@@ -670,21 +681,23 @@ var input = {
670
681
  boxSizing: "border-box",
671
682
  padding: "6px 8px",
672
683
  borderRadius: 6,
673
- border: "1px solid #e2e8f0",
684
+ border: "1px solid var(--fcms-border)",
685
+ background: "var(--fcms-input-bg)",
686
+ color: "var(--fcms-fg)",
674
687
  font: "inherit",
675
688
  fontSize: 13
676
689
  };
677
690
  function Inspector({ doc, selection, apply }) {
678
691
  const node = selection ? doc.nodes[selection] : null;
679
692
  if (!node) {
680
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 16, color: "#94a3b8", fontFamily: "system-ui, sans-serif", fontSize: 13 }, children: "Select an element to edit." });
693
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 16, color: "var(--fcms-muted)", fontFamily: "system-ui, sans-serif", fontSize: 13 }, children: "Select an element to edit." });
681
694
  }
682
695
  const s = node.style.base;
683
696
  const setStyle = (patch) => apply({ t: "set_style", id: node.id, breakpoint: "base", patch });
684
697
  const setProp = (key, value) => apply({ t: "set_props", id: node.id, patch: { [key]: value } });
685
698
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { overflow: "auto", padding: 16, fontFamily: "system-ui, sans-serif", height: "100%", boxSizing: "border-box" }, children: [
686
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, fontWeight: 600, color: "#0f172a" }, children: node.type }),
687
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "#94a3b8", marginBottom: 8 }, children: node.id }),
699
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, fontWeight: 600, color: "var(--fcms-fg)" }, children: node.type }),
700
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "var(--fcms-muted)", marginBottom: 8 }, children: node.id }),
688
701
  node.type === "text" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
689
702
  /* @__PURE__ */ jsxRuntime.jsx("label", { style: label, children: "Content" }),
690
703
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -762,8 +775,82 @@ function Inspector({ doc, selection, apply }) {
762
775
  )
763
776
  ] });
764
777
  }
765
- function Editor({ defaultValue, onChange }) {
766
- const ed = useEditor(defaultValue);
778
+
779
+ // src/editor/insert.ts
780
+ var CONTAINER_TYPES = /* @__PURE__ */ new Set([
781
+ "section",
782
+ "frame",
783
+ "stack",
784
+ "grid",
785
+ "shape",
786
+ "card",
787
+ "device",
788
+ "repeater"
789
+ ]);
790
+ var ADD_DEFAULTS = {
791
+ text: { type: "text", props: { content: "New text" }, style: { color: "inherit" } },
792
+ heading: { type: "heading", props: { content: "New heading" }, style: { fontSize: { value: 28, unit: "px" }, fontWeight: 700 } },
793
+ button: { type: "button", props: { label: "Button", href: "#", variant: "primary" }, style: {} },
794
+ link: { type: "link", props: { content: "link text", href: "#" }, style: { color: "#7c3aed" } },
795
+ image: { type: "image", props: { src: "", alt: "" }, style: {} },
796
+ box: { type: "frame", props: {}, style: { padding: { value: 16, unit: "px" } } },
797
+ stack: { type: "stack", props: {}, style: { gap: { value: 12, unit: "px" } }, layout: "stack" },
798
+ grid: { type: "grid", props: {}, style: { gap: { value: 12, unit: "px" } }, layout: "grid" },
799
+ card: { type: "card", props: {}, style: { padding: { value: 16, unit: "px" }, radius: { value: 12, unit: "px" }, border: "1px solid #e2e8f0" } },
800
+ callout: { type: "callout", props: { content: "Heads up \u2014 this is a callout.", variant: "info" }, style: {} },
801
+ divider: { type: "divider", props: {}, style: {} },
802
+ code: { type: "code", props: { content: "npm install @particle-academy/react-fancy", lang: "bash" }, style: {} },
803
+ richtext: { type: "richtext", props: { html: "<p>Rich <strong>text</strong> with <em>inline</em> formatting.</p>" }, style: {} },
804
+ repeater: { type: "repeater", props: { items: "" }, style: { gap: { value: 12, unit: "px" } }, layout: "stack" }
805
+ };
806
+ var ADD_MENU = [
807
+ { kind: "heading", label: "Heading" },
808
+ { kind: "text", label: "Text" },
809
+ { kind: "button", label: "Button" },
810
+ { kind: "link", label: "Link" },
811
+ { kind: "image", label: "Image" },
812
+ { kind: "card", label: "Card" },
813
+ { kind: "callout", label: "Callout" },
814
+ { kind: "stack", label: "Stack" },
815
+ { kind: "grid", label: "Grid" },
816
+ { kind: "box", label: "Box" },
817
+ { kind: "divider", label: "Divider" },
818
+ { kind: "code", label: "Code" },
819
+ { kind: "richtext", label: "Rich text" },
820
+ { kind: "repeater", label: "Repeater" }
821
+ ];
822
+ function resolveInsertParent(doc, selectedId) {
823
+ const selected = selectedId ? doc.nodes[selectedId] : null;
824
+ if (selected) {
825
+ return CONTAINER_TYPES.has(selected.type) ? selected.id : selected.parent;
826
+ }
827
+ return doc.sections[doc.sections.length - 1] ?? null;
828
+ }
829
+ function buildInsertOp(doc, kind, selectedId, targetId) {
830
+ const parent = resolveInsertParent(doc, selectedId);
831
+ const siblings = childrenOf(doc, parent);
832
+ const order = keyBetween(siblings.length ? siblings[siblings.length - 1].order : null, null);
833
+ const id = `n${doc.seq + 1}-${Math.floor(performance.now())}`;
834
+ const def = ADD_DEFAULTS[kind];
835
+ return {
836
+ id,
837
+ op: {
838
+ t: "insert_node",
839
+ node: {
840
+ id,
841
+ type: def.type,
842
+ parent,
843
+ order,
844
+ layout: def.layout,
845
+ props: { ...def.props },
846
+ style: { base: { ...def.style } }
847
+ }
848
+ }
849
+ };
850
+ }
851
+ function Editor({ defaultValue, onChange, registry, data }) {
852
+ const initial = react.useMemo(() => defaultValue ?? emptyDoc("untitled"), [defaultValue]);
853
+ const ed = useEditor(initial);
767
854
  const first = react.useRef(true);
768
855
  const onChangeRef = useLatestRef(onChange);
769
856
  react.useEffect(() => {
@@ -778,14 +865,15 @@ function Editor({ defaultValue, onChange }) {
778
865
  gridTemplateColumns: "220px 1fr 300px",
779
866
  height: "100%",
780
867
  minHeight: 0,
781
- background: "#fff",
782
- color: "#0f172a",
783
- border: "1px solid #e2e8f0",
868
+ background: "var(--fcms-bg)",
869
+ color: "var(--fcms-fg)",
870
+ border: "1px solid var(--fcms-border)",
784
871
  borderRadius: 12,
785
872
  overflow: "hidden"
786
873
  };
787
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: shell, children: [
788
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { borderRight: "1px solid #e2e8f0", display: "flex", flexDirection: "column", minHeight: 0 }, children: [
874
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fancy-cms-editor", style: shell, children: [
875
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: CHROME_CSS }),
876
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { borderRight: "1px solid var(--fcms-border)", display: "flex", flexDirection: "column", minHeight: 0 }, children: [
789
877
  /* @__PURE__ */ jsxRuntime.jsx(Toolbar, { ed }),
790
878
  /* @__PURE__ */ jsxRuntime.jsx(
791
879
  LayersPanel,
@@ -797,8 +885,8 @@ function Editor({ defaultValue, onChange }) {
797
885
  }
798
886
  )
799
887
  ] }),
800
- /* @__PURE__ */ jsxRuntime.jsx(Canvas, { doc: ed.state.doc, selection: ed.state.selection, onSelect: ed.select, apply: ed.apply }),
801
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { borderLeft: "1px solid #e2e8f0", minHeight: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(Inspector, { doc: ed.state.doc, selection: ed.state.selection, apply: ed.apply }) })
888
+ /* @__PURE__ */ jsxRuntime.jsx(Canvas, { doc: ed.state.doc, selection: ed.state.selection, onSelect: ed.select, apply: ed.apply, registry, data }),
889
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { borderLeft: "1px solid var(--fcms-border)", minHeight: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(Inspector, { doc: ed.state.doc, selection: ed.state.selection, apply: ed.apply }) })
802
890
  ] });
803
891
  }
804
892
  function Toolbar({ ed }) {
@@ -807,8 +895,9 @@ function Toolbar({ ed }) {
807
895
  fontSize: 12,
808
896
  padding: "4px 10px",
809
897
  borderRadius: 6,
810
- border: "1px solid #e2e8f0",
811
- background: "#fff",
898
+ border: "1px solid var(--fcms-border)",
899
+ background: "var(--fcms-bg)",
900
+ color: "var(--fcms-fg)",
812
901
  cursor: "pointer"
813
902
  };
814
903
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -818,17 +907,95 @@ function Toolbar({ ed }) {
818
907
  display: "flex",
819
908
  gap: 6,
820
909
  padding: 8,
821
- borderBottom: "1px solid #e2e8f0",
910
+ borderBottom: "1px solid var(--fcms-border)",
822
911
  fontFamily: "system-ui, sans-serif"
823
912
  },
824
913
  children: [
825
914
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: { ...btn, opacity: ed.canUndo ? 1 : 0.4 }, disabled: !ed.canUndo, onClick: ed.undo, children: "Undo" }),
826
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: { ...btn, opacity: ed.canRedo ? 1 : 0.4 }, disabled: !ed.canRedo, onClick: ed.redo, children: "Redo" })
915
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: { ...btn, opacity: ed.canRedo ? 1 : 0.4 }, disabled: !ed.canRedo, onClick: ed.redo, children: "Redo" }),
916
+ /* @__PURE__ */ jsxRuntime.jsx(AddElementMenu, { ed, btn })
827
917
  ]
828
918
  }
829
919
  );
830
920
  }
831
- var CONTAINER_TYPES = /* @__PURE__ */ new Set(["section", "frame", "stack", "grid", "shape", "card", "device"]);
921
+ function AddElementMenu({ ed, btn }) {
922
+ const [open, setOpen] = react.useState(false);
923
+ react.useEffect(() => {
924
+ if (!open) return;
925
+ const close = () => setOpen(false);
926
+ const onKey = (e) => e.key === "Escape" && setOpen(false);
927
+ window.addEventListener("click", close);
928
+ window.addEventListener("keydown", onKey);
929
+ return () => {
930
+ window.removeEventListener("click", close);
931
+ window.removeEventListener("keydown", onKey);
932
+ };
933
+ }, [open]);
934
+ const add = (kind) => {
935
+ const { op, id } = buildInsertOp(ed.state.doc, kind, ed.state.selection);
936
+ ed.apply(op);
937
+ ed.select(id);
938
+ setOpen(false);
939
+ };
940
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", marginLeft: "auto" }, onClick: (e) => e.stopPropagation(), children: [
941
+ /* @__PURE__ */ jsxRuntime.jsx(
942
+ "button",
943
+ {
944
+ type: "button",
945
+ style: { ...btn, borderColor: "var(--fcms-accent, #7c3aed)" },
946
+ "aria-haspopup": "menu",
947
+ "aria-expanded": open,
948
+ "data-cms-add-trigger": "",
949
+ onClick: () => setOpen((v) => !v),
950
+ children: "+ Add"
951
+ }
952
+ ),
953
+ open && /* @__PURE__ */ jsxRuntime.jsx(
954
+ "div",
955
+ {
956
+ role: "menu",
957
+ "data-cms-add-menu": "",
958
+ style: {
959
+ position: "absolute",
960
+ top: "calc(100% + 4px)",
961
+ left: 0,
962
+ zIndex: 20,
963
+ minWidth: 150,
964
+ maxHeight: 280,
965
+ overflowY: "auto",
966
+ padding: 4,
967
+ borderRadius: 8,
968
+ border: "1px solid var(--fcms-border)",
969
+ background: "var(--fcms-bg)",
970
+ boxShadow: "0 12px 32px rgba(0,0,0,.28)"
971
+ },
972
+ children: ADD_MENU.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
973
+ "button",
974
+ {
975
+ type: "button",
976
+ role: "menuitem",
977
+ "data-cms-add": item.kind,
978
+ style: {
979
+ ...btn,
980
+ display: "block",
981
+ width: "100%",
982
+ textAlign: "left",
983
+ border: 0,
984
+ background: "transparent"
985
+ },
986
+ onClick: () => add(item.kind),
987
+ children: item.label
988
+ },
989
+ item.kind
990
+ ))
991
+ }
992
+ )
993
+ ] });
994
+ }
995
+ var DARK_VARS = "color-scheme:dark;--fcms-bg:#0b0f19;--fcms-fg:#e5e7eb;--fcms-muted:#94a3b8;--fcms-border:#27272a;--fcms-canvas:#0f141f;--fcms-input-bg:#111827;--fcms-row-fg:#cbd5e1;--fcms-sel-bg:color-mix(in oklab, #8b5cf6 24%, transparent);--fcms-sel-fg:#ddd6fe;";
996
+ var LIGHT_VARS = "color-scheme:light;--fcms-bg:#ffffff;--fcms-fg:#0f172a;--fcms-muted:#64748b;--fcms-border:#e2e8f0;--fcms-canvas:#f8fafc;--fcms-input-bg:#ffffff;--fcms-row-fg:#334155;--fcms-sel-bg:#ede9fe;--fcms-sel-fg:#5b21b6;";
997
+ var CHROME_CSS = `.fancy-cms-editor{--fcms-accent:#8b5cf6;${LIGHT_VARS}}@media (prefers-color-scheme:dark){.fancy-cms-editor{${DARK_VARS}}}:where(.light,[data-theme="light"]) .fancy-cms-editor{${LIGHT_VARS}}:where(.dark,[data-theme="dark"]) .fancy-cms-editor{${DARK_VARS}}`;
998
+ var CONTAINER_TYPES2 = /* @__PURE__ */ new Set(["section", "frame", "stack", "grid", "shape", "card", "device"]);
832
999
  function NodeInspector({
833
1000
  node,
834
1001
  transform,
@@ -882,7 +1049,7 @@ function NodeInspector({
882
1049
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: { ...miniBtn, alignSelf: "end" }, onClick: () => onTransform({}), title: "Clear transform", children: "Reset" })
883
1050
  ] })
884
1051
  ] }),
885
- !CONTAINER_TYPES.has(node.type) ? /* @__PURE__ */ jsxRuntime.jsxs(Group, { label: "Text", children: [
1052
+ !CONTAINER_TYPES2.has(node.type) ? /* @__PURE__ */ jsxRuntime.jsxs(Group, { label: "Text", children: [
886
1053
  /* @__PURE__ */ jsxRuntime.jsxs(Row, { children: [
887
1054
  /* @__PURE__ */ jsxRuntime.jsx(Color, { label: "Color", value: base.color ?? "#0f172a", onChange: (v) => onStyle({ color: v }) }),
888
1055
  /* @__PURE__ */ jsxRuntime.jsx(Num, { label: "Size", value: base.fontSize?.value, placeholder: "16", onChange: (v) => onStyle({ fontSize: v == null ? void 0 : len(v) }) })
@@ -919,7 +1086,7 @@ function NodeInspector({
919
1086
  ] }),
920
1087
  /* @__PURE__ */ jsxRuntime.jsx(Row, { children: /* @__PURE__ */ jsxRuntime.jsx(Txt, { label: "Border", value: base.border ?? "", placeholder: "1px solid #e2e8f0", onChange: (v) => onStyle({ border: v || void 0 }) }) })
921
1088
  ] }),
922
- CONTAINER_TYPES.has(node.type) ? /* @__PURE__ */ jsxRuntime.jsxs(Group, { label: "Layout", children: [
1089
+ CONTAINER_TYPES2.has(node.type) ? /* @__PURE__ */ jsxRuntime.jsxs(Group, { label: "Layout", children: [
923
1090
  /* @__PURE__ */ jsxRuntime.jsxs(Row, { children: [
924
1091
  /* @__PURE__ */ jsxRuntime.jsx(
925
1092
  Sel,
@@ -1302,7 +1469,7 @@ function EditablePage({
1302
1469
  const addNode = react.useCallback(
1303
1470
  (kind) => {
1304
1471
  const doc2 = ed.state.doc;
1305
- const parent = selNode ? CONTAINER_TYPES2.has(selNode.type) ? selNode.id : selNode.parent : doc2.sections[doc2.sections.length - 1] ?? null;
1472
+ const parent = selNode ? CONTAINER_TYPES.has(selNode.type) ? selNode.id : selNode.parent : doc2.sections[doc2.sections.length - 1] ?? null;
1306
1473
  const siblings = childrenOf(doc2, parent);
1307
1474
  const order = keyBetween(siblings.length ? siblings[siblings.length - 1].order : null, null);
1308
1475
  const id = `n${doc2.seq + 1}-${Math.floor(performance.now())}`;
@@ -1316,7 +1483,7 @@ function EditablePage({
1316
1483
  (kind, targetId) => {
1317
1484
  const doc2 = ed.state.doc;
1318
1485
  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;
1486
+ const parent = target ? CONTAINER_TYPES.has(target.type) ? target.id : target.parent : doc2.sections[doc2.sections.length - 1] ?? null;
1320
1487
  const siblings = childrenOf(doc2, parent);
1321
1488
  const order = keyBetween(siblings.length ? siblings[siblings.length - 1].order : null, null);
1322
1489
  const id = `n${doc2.seq + 1}-${Math.floor(performance.now())}`;
@@ -1349,7 +1516,7 @@ function EditablePage({
1349
1516
  const node = ed.state.doc.nodes[id];
1350
1517
  const r = el.getBoundingClientRect();
1351
1518
  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 };
1519
+ if (node && CONTAINER_TYPES.has(node.type)) return { id, edge: "inside", rect };
1353
1520
  return { id, edge: clientY < r.top + r.height / 2 ? "before" : "after", rect };
1354
1521
  };
1355
1522
  const onPageDragOver = (e) => {
@@ -1405,7 +1572,7 @@ function EditablePage({
1405
1572
  if (id) clip.current = snapshotSubtree(ed.state.doc, id);
1406
1573
  };
1407
1574
  const paste = (target) => {
1408
- if (clip.current) runOps(pasteOps(ed.state.doc, clip.current, target, CONTAINER_TYPES2));
1575
+ if (clip.current) runOps(pasteOps(ed.state.doc, clip.current, target, CONTAINER_TYPES));
1409
1576
  };
1410
1577
  const startEditText = (id) => {
1411
1578
  if (!id) return;
@@ -1477,7 +1644,7 @@ function EditablePage({
1477
1644
  {
1478
1645
  node: selNode ?? null,
1479
1646
  hasClipboard: Boolean(clip.current),
1480
- isContainer: selNode ? CONTAINER_TYPES2.has(selNode.type) : false,
1647
+ isContainer: selNode ? CONTAINER_TYPES.has(selNode.type) : false,
1481
1648
  onEditText: () => startEditText(selection),
1482
1649
  onAdd: addNode,
1483
1650
  onDuplicate: () => duplicate(selection),
@@ -1609,23 +1776,6 @@ function ElementPalette({ open, onDragChange }) {
1609
1776
  }
1610
1777
  );
1611
1778
  }
1612
- var CONTAINER_TYPES2 = /* @__PURE__ */ new Set(["section", "frame", "stack", "grid", "shape", "card", "device", "repeater"]);
1613
- var ADD_DEFAULTS = {
1614
- text: { type: "text", props: { content: "New text" }, style: { color: "inherit" } },
1615
- heading: { type: "heading", props: { content: "New heading" }, style: { fontSize: { value: 28, unit: "px" }, fontWeight: 700 } },
1616
- button: { type: "button", props: { label: "Button", href: "#", variant: "primary" }, style: {} },
1617
- link: { type: "link", props: { content: "link text", href: "#" }, style: { color: "#7c3aed" } },
1618
- image: { type: "image", props: { src: "", alt: "" }, style: {} },
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" }
1628
- };
1629
1779
  var GRIPS = [
1630
1780
  { key: "nw", north: true, west: true, cursor: "nwse-resize" },
1631
1781
  { key: "n", north: true, cursor: "ns-resize" },
@@ -1823,22 +1973,6 @@ function FloatingToolbar({
1823
1973
  ] })
1824
1974
  ] });
1825
1975
  }
1826
- var ADD_MENU = [
1827
- { kind: "heading", label: "Heading" },
1828
- { kind: "text", label: "Text" },
1829
- { kind: "button", label: "Button" },
1830
- { kind: "link", label: "Link" },
1831
- { kind: "image", label: "Image" },
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" }
1841
- ];
1842
1976
  function EditBar({
1843
1977
  editing,
1844
1978
  onToggle,