@particle-academy/fancy-cms-ui 0.2.0 → 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-XQ3KHMBJ.js → chunk-JN5MRSR2.js} +155 -6
- package/dist/chunk-JN5MRSR2.js.map +1 -0
- package/dist/editor.cjs +170 -43
- 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 +156 -2
- 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-CV5jFAgo.d.ts → useEditor-CyPSB3OQ.d.ts} +5 -2
- package/dist/{useEditor-CVT8sTum.d.cts → useEditor-FV_extlw.d.cts} +5 -2
- package/package.json +1 -1
- package/dist/chunk-XQ3KHMBJ.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -840,8 +840,82 @@ function Inspector({ doc, selection, apply }) {
|
|
|
840
840
|
)
|
|
841
841
|
] });
|
|
842
842
|
}
|
|
843
|
+
|
|
844
|
+
// src/editor/insert.ts
|
|
845
|
+
var CONTAINER_TYPES = /* @__PURE__ */ new Set([
|
|
846
|
+
"section",
|
|
847
|
+
"frame",
|
|
848
|
+
"stack",
|
|
849
|
+
"grid",
|
|
850
|
+
"shape",
|
|
851
|
+
"card",
|
|
852
|
+
"device",
|
|
853
|
+
"repeater"
|
|
854
|
+
]);
|
|
855
|
+
var ADD_DEFAULTS = {
|
|
856
|
+
text: { type: "text", props: { content: "New text" }, style: { color: "inherit" } },
|
|
857
|
+
heading: { type: "heading", props: { content: "New heading" }, style: { fontSize: { value: 28, unit: "px" }, fontWeight: 700 } },
|
|
858
|
+
button: { type: "button", props: { label: "Button", href: "#", variant: "primary" }, style: {} },
|
|
859
|
+
link: { type: "link", props: { content: "link text", href: "#" }, style: { color: "#7c3aed" } },
|
|
860
|
+
image: { type: "image", props: { src: "", alt: "" }, style: {} },
|
|
861
|
+
box: { type: "frame", props: {}, style: { padding: { value: 16, unit: "px" } } },
|
|
862
|
+
stack: { type: "stack", props: {}, style: { gap: { value: 12, unit: "px" } }, layout: "stack" },
|
|
863
|
+
grid: { type: "grid", props: {}, style: { gap: { value: 12, unit: "px" } }, layout: "grid" },
|
|
864
|
+
card: { type: "card", props: {}, style: { padding: { value: 16, unit: "px" }, radius: { value: 12, unit: "px" }, border: "1px solid #e2e8f0" } },
|
|
865
|
+
callout: { type: "callout", props: { content: "Heads up \u2014 this is a callout.", variant: "info" }, style: {} },
|
|
866
|
+
divider: { type: "divider", props: {}, style: {} },
|
|
867
|
+
code: { type: "code", props: { content: "npm install @particle-academy/react-fancy", lang: "bash" }, style: {} },
|
|
868
|
+
richtext: { type: "richtext", props: { html: "<p>Rich <strong>text</strong> with <em>inline</em> formatting.</p>" }, style: {} },
|
|
869
|
+
repeater: { type: "repeater", props: { items: "" }, style: { gap: { value: 12, unit: "px" } }, layout: "stack" }
|
|
870
|
+
};
|
|
871
|
+
var ADD_MENU = [
|
|
872
|
+
{ kind: "heading", label: "Heading" },
|
|
873
|
+
{ kind: "text", label: "Text" },
|
|
874
|
+
{ kind: "button", label: "Button" },
|
|
875
|
+
{ kind: "link", label: "Link" },
|
|
876
|
+
{ kind: "image", label: "Image" },
|
|
877
|
+
{ kind: "card", label: "Card" },
|
|
878
|
+
{ kind: "callout", label: "Callout" },
|
|
879
|
+
{ kind: "stack", label: "Stack" },
|
|
880
|
+
{ kind: "grid", label: "Grid" },
|
|
881
|
+
{ kind: "box", label: "Box" },
|
|
882
|
+
{ kind: "divider", label: "Divider" },
|
|
883
|
+
{ kind: "code", label: "Code" },
|
|
884
|
+
{ kind: "richtext", label: "Rich text" },
|
|
885
|
+
{ kind: "repeater", label: "Repeater" }
|
|
886
|
+
];
|
|
887
|
+
function resolveInsertParent(doc, selectedId) {
|
|
888
|
+
const selected = selectedId ? doc.nodes[selectedId] : null;
|
|
889
|
+
if (selected) {
|
|
890
|
+
return CONTAINER_TYPES.has(selected.type) ? selected.id : selected.parent;
|
|
891
|
+
}
|
|
892
|
+
return doc.sections[doc.sections.length - 1] ?? null;
|
|
893
|
+
}
|
|
894
|
+
function buildInsertOp(doc, kind, selectedId, targetId) {
|
|
895
|
+
const parent = targetId !== void 0 ? targetId && doc.nodes[targetId] ? CONTAINER_TYPES.has(doc.nodes[targetId].type) ? targetId : doc.nodes[targetId].parent : null : resolveInsertParent(doc, selectedId);
|
|
896
|
+
const siblings = childrenOf(doc, parent);
|
|
897
|
+
const order = keyBetween(siblings.length ? siblings[siblings.length - 1].order : null, null);
|
|
898
|
+
const id = `n${doc.seq + 1}-${Math.floor(performance.now())}`;
|
|
899
|
+
const def = ADD_DEFAULTS[kind];
|
|
900
|
+
return {
|
|
901
|
+
id,
|
|
902
|
+
op: {
|
|
903
|
+
t: "insert_node",
|
|
904
|
+
node: {
|
|
905
|
+
id,
|
|
906
|
+
type: def.type,
|
|
907
|
+
parent,
|
|
908
|
+
order,
|
|
909
|
+
layout: def.layout,
|
|
910
|
+
props: { ...def.props },
|
|
911
|
+
style: { base: { ...def.style } }
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
};
|
|
915
|
+
}
|
|
843
916
|
function Editor({ defaultValue, onChange, registry, data }) {
|
|
844
|
-
const
|
|
917
|
+
const initial = react.useMemo(() => defaultValue ?? emptyDoc("untitled"), [defaultValue]);
|
|
918
|
+
const ed = useEditor(initial);
|
|
845
919
|
const first = react.useRef(true);
|
|
846
920
|
const onChangeRef = useLatestRef(onChange);
|
|
847
921
|
react.useEffect(() => {
|
|
@@ -903,15 +977,93 @@ function Toolbar({ ed }) {
|
|
|
903
977
|
},
|
|
904
978
|
children: [
|
|
905
979
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: { ...btn, opacity: ed.canUndo ? 1 : 0.4 }, disabled: !ed.canUndo, onClick: ed.undo, children: "Undo" }),
|
|
906
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: { ...btn, opacity: ed.canRedo ? 1 : 0.4 }, disabled: !ed.canRedo, onClick: ed.redo, children: "Redo" })
|
|
980
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: { ...btn, opacity: ed.canRedo ? 1 : 0.4 }, disabled: !ed.canRedo, onClick: ed.redo, children: "Redo" }),
|
|
981
|
+
/* @__PURE__ */ jsxRuntime.jsx(AddElementMenu, { ed, btn })
|
|
907
982
|
]
|
|
908
983
|
}
|
|
909
984
|
);
|
|
910
985
|
}
|
|
986
|
+
function AddElementMenu({ ed, btn }) {
|
|
987
|
+
const [open, setOpen] = react.useState(false);
|
|
988
|
+
react.useEffect(() => {
|
|
989
|
+
if (!open) return;
|
|
990
|
+
const close = () => setOpen(false);
|
|
991
|
+
const onKey = (e) => e.key === "Escape" && setOpen(false);
|
|
992
|
+
window.addEventListener("click", close);
|
|
993
|
+
window.addEventListener("keydown", onKey);
|
|
994
|
+
return () => {
|
|
995
|
+
window.removeEventListener("click", close);
|
|
996
|
+
window.removeEventListener("keydown", onKey);
|
|
997
|
+
};
|
|
998
|
+
}, [open]);
|
|
999
|
+
const add = (kind) => {
|
|
1000
|
+
const { op, id } = buildInsertOp(ed.state.doc, kind, ed.state.selection);
|
|
1001
|
+
ed.apply(op);
|
|
1002
|
+
ed.select(id);
|
|
1003
|
+
setOpen(false);
|
|
1004
|
+
};
|
|
1005
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", marginLeft: "auto" }, onClick: (e) => e.stopPropagation(), children: [
|
|
1006
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1007
|
+
"button",
|
|
1008
|
+
{
|
|
1009
|
+
type: "button",
|
|
1010
|
+
style: { ...btn, borderColor: "var(--fcms-accent, #7c3aed)" },
|
|
1011
|
+
"aria-haspopup": "menu",
|
|
1012
|
+
"aria-expanded": open,
|
|
1013
|
+
"data-cms-add-trigger": "",
|
|
1014
|
+
onClick: () => setOpen((v) => !v),
|
|
1015
|
+
children: "+ Add"
|
|
1016
|
+
}
|
|
1017
|
+
),
|
|
1018
|
+
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1019
|
+
"div",
|
|
1020
|
+
{
|
|
1021
|
+
role: "menu",
|
|
1022
|
+
"data-cms-add-menu": "",
|
|
1023
|
+
style: {
|
|
1024
|
+
position: "absolute",
|
|
1025
|
+
top: "calc(100% + 4px)",
|
|
1026
|
+
left: 0,
|
|
1027
|
+
zIndex: 20,
|
|
1028
|
+
minWidth: 150,
|
|
1029
|
+
maxHeight: 280,
|
|
1030
|
+
overflowY: "auto",
|
|
1031
|
+
padding: 4,
|
|
1032
|
+
borderRadius: 8,
|
|
1033
|
+
border: "1px solid var(--fcms-border)",
|
|
1034
|
+
background: "var(--fcms-bg)",
|
|
1035
|
+
boxShadow: "0 12px 32px rgba(0,0,0,.28)"
|
|
1036
|
+
},
|
|
1037
|
+
children: ADD_MENU.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1038
|
+
"button",
|
|
1039
|
+
{
|
|
1040
|
+
type: "button",
|
|
1041
|
+
role: "menuitem",
|
|
1042
|
+
"data-cms-add": item.kind,
|
|
1043
|
+
style: {
|
|
1044
|
+
...btn,
|
|
1045
|
+
display: "block",
|
|
1046
|
+
width: "100%",
|
|
1047
|
+
textAlign: "left",
|
|
1048
|
+
border: 0,
|
|
1049
|
+
background: "transparent"
|
|
1050
|
+
},
|
|
1051
|
+
onClick: () => add(item.kind),
|
|
1052
|
+
children: item.label
|
|
1053
|
+
},
|
|
1054
|
+
item.kind
|
|
1055
|
+
))
|
|
1056
|
+
}
|
|
1057
|
+
)
|
|
1058
|
+
] });
|
|
1059
|
+
}
|
|
911
1060
|
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;";
|
|
912
1061
|
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;";
|
|
913
1062
|
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}}`;
|
|
914
1063
|
|
|
1064
|
+
exports.ADD_DEFAULTS = ADD_DEFAULTS;
|
|
1065
|
+
exports.ADD_MENU = ADD_MENU;
|
|
1066
|
+
exports.CONTAINER_TYPES = CONTAINER_TYPES;
|
|
915
1067
|
exports.Canvas = Canvas;
|
|
916
1068
|
exports.CmsPage = CmsPage;
|
|
917
1069
|
exports.CmsRegion = CmsRegion;
|
|
@@ -920,6 +1072,7 @@ exports.Editor = Editor;
|
|
|
920
1072
|
exports.Inspector = Inspector;
|
|
921
1073
|
exports.LayersPanel = LayersPanel;
|
|
922
1074
|
exports.RenderNode = RenderNode;
|
|
1075
|
+
exports.buildInsertOp = buildInsertOp;
|
|
923
1076
|
exports.childrenOf = childrenOf;
|
|
924
1077
|
exports.defaultRegistry = defaultRegistry;
|
|
925
1078
|
exports.descendantIds = descendantIds;
|
|
@@ -933,6 +1086,7 @@ exports.isBinding = isBinding;
|
|
|
933
1086
|
exports.keyBetween = keyBetween;
|
|
934
1087
|
exports.reduce = reduce;
|
|
935
1088
|
exports.reduceAll = reduceAll;
|
|
1089
|
+
exports.resolveInsertParent = resolveInsertParent;
|
|
936
1090
|
exports.resolveValue = resolveValue;
|
|
937
1091
|
exports.useEditor = useEditor;
|
|
938
1092
|
//# sourceMappingURL=index.cjs.map
|