@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/README.md +9 -0
- package/dist/{chunk-524NYOHK.js → chunk-JN5MRSR2.js} +185 -29
- package/dist/chunk-JN5MRSR2.js.map +1 -0
- package/dist/editor.cjs +200 -66
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.d.cts +1 -1
- package/dist/editor.d.ts +1 -1
- package/dist/editor.js +10 -43
- package/dist/editor.js.map +1 -1
- package/dist/index.cjs +186 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -5
- package/dist/index.d.ts +50 -5
- package/dist/index.js +1 -1
- package/dist/{useEditor-DLH7hU6G.d.cts → useEditor-CyPSB3OQ.d.ts} +20 -5
- package/dist/{useEditor-qmF9n2e6.d.ts → useEditor-FV_extlw.d.cts} +20 -5
- package/package.json +1 -1
- package/dist/chunk-524NYOHK.js.map +0 -1
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: "
|
|
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 ? "
|
|
646
|
-
color: selected ? "
|
|
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: "
|
|
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
|
|
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: "
|
|
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: "
|
|
687
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "
|
|
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
|
-
|
|
766
|
-
|
|
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: "
|
|
782
|
-
color: "
|
|
783
|
-
border: "1px solid
|
|
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.
|
|
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
|
|
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
|
|
811
|
-
background: "
|
|
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
|
|
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
|
-
|
|
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
|
-
!
|
|
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
|
-
|
|
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 ?
|
|
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 ?
|
|
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 &&
|
|
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,
|
|
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 ?
|
|
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,
|