@particle-academy/fancy-cms-ui 0.0.1-dev.8 → 0.1.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/index.cjs CHANGED
@@ -1,5 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+
3
6
  // src/document/types.ts
4
7
  function isBinding(v) {
5
8
  return typeof v === "object" && v !== null && typeof v.$bind === "string";
@@ -113,6 +116,10 @@ function reduce(doc, op, opts = {}) {
113
116
  props: { ...doc.nodes[op.id].props, ...op.patch }
114
117
  });
115
118
  }
119
+ case "set_layout": {
120
+ if (!doc.nodes[op.id]) return invalid("node not found");
121
+ return patchNode(doc, op.id, { layout: op.layout });
122
+ }
116
123
  case "set_style": {
117
124
  const node = doc.nodes[op.id];
118
125
  if (!node) return invalid("node not found");
@@ -199,6 +206,11 @@ function invert(doc, op) {
199
206
  for (const k of Object.keys(op.patch)) prev[k] = node.props[k];
200
207
  return [{ t: "set_props", id: op.id, patch: prev }];
201
208
  }
209
+ case "set_layout": {
210
+ const node = doc.nodes[op.id];
211
+ if (!node) return [];
212
+ return [{ t: "set_layout", id: op.id, layout: node.layout }];
213
+ }
202
214
  case "set_style": {
203
215
  const node = doc.nodes[op.id];
204
216
  if (!node) return [];
@@ -392,16 +404,521 @@ ${inner}
392
404
  }
393
405
  return blocks.join("\n\n") + (blocks.length ? "\n" : "");
394
406
  }
407
+ function getPath(data, path) {
408
+ return path.split(".").reduce((o, k) => o == null ? void 0 : o[k], data);
409
+ }
410
+ function resolveValue(v, data) {
411
+ if (v === void 0 || v === null) return v;
412
+ if (isBinding(v)) return getPath(data, v.$bind);
413
+ return v;
414
+ }
415
+ var defaultRegistry = {
416
+ section: ({ children }) => children,
417
+ stack: ({ children }) => children,
418
+ grid: ({ children }) => children,
419
+ frame: ({ children }) => children,
420
+ shape: ({ children }) => children,
421
+ card: ({ children }) => children,
422
+ text: ({ node, text }) => text(node.props.content),
423
+ heading: ({ node, text }) => text(node.props.content) || "Heading",
424
+ // Rich text — inline-formatted HTML (gradient spans, links, <code>, …) that
425
+ // plain `text` can't express. The author owns the markup (it's their content).
426
+ richtext: ({ node, text }) => /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: text(node.props.html) } }),
427
+ link: ({ node, text }) => /* @__PURE__ */ jsxRuntime.jsx("a", { href: text(node.props.href) || "#", style: { color: "inherit", textDecoration: "underline" }, children: text(node.props.content) || "link" }),
428
+ divider: () => /* @__PURE__ */ jsxRuntime.jsx("hr", { style: { border: "none", borderTop: "1px solid #e2e8f0", margin: 0 } }),
429
+ callout: ({ node, text }) => {
430
+ const tone = { info: "#3b82f6", success: "#10b981", warning: "#f59e0b", danger: "#ef4444" }[text(node.props.variant)] ?? "#3b82f6";
431
+ 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" }) });
432
+ },
433
+ 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) }) }),
434
+ button: ({ node, text }) => {
435
+ const label2 = text(node.props.label) || text(node.props.content) || "Button";
436
+ const variant = text(node.props.variant) || "primary";
437
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cms-button": variant, style: buttonStyle(variant), children: label2 });
438
+ },
439
+ image: ({ node, text }) => /* @__PURE__ */ jsxRuntime.jsx(
440
+ "img",
441
+ {
442
+ src: text(node.props.src),
443
+ alt: text(node.props.alt),
444
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
445
+ }
446
+ )
447
+ };
448
+ function buttonStyle(variant) {
449
+ const base = {
450
+ display: "inline-flex",
451
+ alignItems: "center",
452
+ gap: 6,
453
+ padding: "9px 16px",
454
+ borderRadius: 8,
455
+ fontWeight: 600,
456
+ fontSize: 14,
457
+ lineHeight: 1,
458
+ cursor: "pointer",
459
+ userSelect: "none"
460
+ };
461
+ if (variant === "ghost") return { ...base, background: "transparent", color: "inherit", border: "1px solid currentColor" };
462
+ if (variant === "outline") return { ...base, background: "transparent", color: "#7c3aed", border: "1px solid #7c3aed" };
463
+ return { ...base, background: "#7c3aed", color: "#fff", border: "1px solid #7c3aed" };
464
+ }
465
+ function RenderNode({ doc, id, registry = defaultRegistry, data }) {
466
+ const node = doc.nodes[id];
467
+ if (!node) return null;
468
+ if (node.type === "repeater") {
469
+ const arr = resolveValue(node.props.items, data);
470
+ const items = Array.isArray(arr) ? arr : [];
471
+ const template = childrenOf(doc, id)[0];
472
+ 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 });
473
+ }
474
+ const kids = childrenOf(doc, id).map((child) => /* @__PURE__ */ jsxRuntime.jsx(RenderNode, { doc, id: child.id, registry, data }, child.id));
475
+ const resolve = (v) => resolveValue(v, data);
476
+ const text = (v) => {
477
+ const r = resolve(v);
478
+ return r === void 0 || r === null ? "" : String(r);
479
+ };
480
+ const renderer = registry[node.type];
481
+ const inner = renderer ? renderer({ node, doc, children: kids, data, resolve, text }) : node.island ? null : kids;
482
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cms": node.id, "data-cms-island": node.island ? node.type : void 0, className: node.className, children: inner });
483
+ }
484
+ function CmsPage({
485
+ doc,
486
+ registry = defaultRegistry,
487
+ data,
488
+ includeStyles = true
489
+ }) {
490
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
491
+ includeStyles ? /* @__PURE__ */ jsxRuntime.jsx("style", { "data-cms-styles": "", children: emitDocCss(doc) }) : null,
492
+ doc.sections.map((id) => /* @__PURE__ */ jsxRuntime.jsx(RenderNode, { doc, id, registry, data }, id))
493
+ ] });
494
+ }
495
+ function CmsRegion({
496
+ doc,
497
+ root,
498
+ registry = defaultRegistry,
499
+ includeStyles = true
500
+ }) {
501
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
502
+ includeStyles ? /* @__PURE__ */ jsxRuntime.jsx("style", { "data-cms-styles": "", children: emitDocCss(doc) }) : null,
503
+ /* @__PURE__ */ jsxRuntime.jsx(RenderNode, { doc, id: root, registry })
504
+ ] });
505
+ }
506
+ function initEditor(doc) {
507
+ return { doc, past: [], future: [], selection: null };
508
+ }
509
+ function editorReduce(state, action) {
510
+ switch (action.type) {
511
+ case "apply": {
512
+ const next = reduce(state.doc, action.op);
513
+ if (next === state.doc) return state;
514
+ return {
515
+ ...state,
516
+ doc: next,
517
+ past: [...state.past, state.doc].slice(-100),
518
+ future: []
519
+ };
520
+ }
521
+ case "undo": {
522
+ if (state.past.length === 0) return state;
523
+ const prev = state.past[state.past.length - 1];
524
+ return {
525
+ ...state,
526
+ doc: prev,
527
+ past: state.past.slice(0, -1),
528
+ future: [state.doc, ...state.future]
529
+ };
530
+ }
531
+ case "redo": {
532
+ if (state.future.length === 0) return state;
533
+ const next = state.future[0];
534
+ return {
535
+ ...state,
536
+ doc: next,
537
+ past: [...state.past, state.doc],
538
+ future: state.future.slice(1)
539
+ };
540
+ }
541
+ case "select":
542
+ return state.selection === action.id ? state : { ...state, selection: action.id };
543
+ case "replace":
544
+ return state.doc === action.doc ? state : { ...state, doc: action.doc, future: [] };
545
+ default:
546
+ return state;
547
+ }
548
+ }
549
+
550
+ // src/editor/useEditor.ts
551
+ function useEditor(initialDoc) {
552
+ const [state, dispatch] = react.useReducer(editorReduce, initialDoc, initEditor);
553
+ const apply = react.useCallback((op) => dispatch({ type: "apply", op }), []);
554
+ const undo = react.useCallback(() => dispatch({ type: "undo" }), []);
555
+ const redo = react.useCallback(() => dispatch({ type: "redo" }), []);
556
+ const select = react.useCallback((id) => dispatch({ type: "select", id }), []);
557
+ const replace = react.useCallback((doc) => dispatch({ type: "replace", doc }), []);
558
+ return react.useMemo(
559
+ () => ({
560
+ state,
561
+ apply,
562
+ undo,
563
+ redo,
564
+ select,
565
+ replace,
566
+ canUndo: state.past.length > 0,
567
+ canRedo: state.future.length > 0
568
+ }),
569
+ [state, apply, undo, redo, select, replace]
570
+ );
571
+ }
572
+ function Canvas({ doc, selection, onSelect, apply }) {
573
+ const ref = react.useRef(null);
574
+ const [box, setBox] = react.useState(null);
575
+ const drag = react.useRef(null);
576
+ react.useLayoutEffect(() => {
577
+ const root = ref.current;
578
+ if (!root || !selection) {
579
+ setBox(null);
580
+ return;
581
+ }
582
+ const el = root.querySelector(`[data-cms="${cssEscape(selection)}"]`);
583
+ if (!el) {
584
+ setBox(null);
585
+ return;
586
+ }
587
+ const r = el.getBoundingClientRect();
588
+ const rootRect = root.getBoundingClientRect();
589
+ setBox({
590
+ x: r.left - rootRect.left + root.scrollLeft,
591
+ y: r.top - rootRect.top + root.scrollTop,
592
+ w: r.width,
593
+ h: r.height
594
+ });
595
+ }, [selection, doc]);
596
+ const handleClick = (e) => {
597
+ const target = e.target.closest("[data-cms]");
598
+ onSelect(target ? target.getAttribute("data-cms") : null);
599
+ };
600
+ const handlePointerDown = (e) => {
601
+ if (!selection) return;
602
+ const c = doc.nodes[selection]?.constraints?.base;
603
+ const left = c && c.left && typeof c.left === "object" ? c.left.value : 0;
604
+ const top = c && c.top && typeof c.top === "object" ? c.top.value : 0;
605
+ drag.current = { x: e.clientX, y: e.clientY, left, top };
606
+ e.currentTarget.setPointerCapture(e.pointerId);
607
+ e.stopPropagation();
608
+ };
609
+ const handlePointerMove = (e) => {
610
+ const d = drag.current;
611
+ if (!d || !selection) return;
612
+ apply({
613
+ t: "set_constraints",
614
+ id: selection,
615
+ breakpoint: "base",
616
+ patch: {
617
+ left: { value: Math.round(d.left + (e.clientX - d.x)), unit: "px" },
618
+ top: { value: Math.round(d.top + (e.clientY - d.y)), unit: "px" }
619
+ }
620
+ });
621
+ };
622
+ const handlePointerUp = () => {
623
+ drag.current = null;
624
+ };
625
+ const surface = {
626
+ position: "relative",
627
+ overflow: "auto",
628
+ height: "100%",
629
+ background: "#f8fafc"
630
+ };
631
+ const overlay = box ? {
632
+ position: "absolute",
633
+ left: box.x,
634
+ top: box.y,
635
+ width: box.w,
636
+ height: box.h,
637
+ outline: "2px solid #8b5cf6",
638
+ outlineOffset: -1,
639
+ cursor: "move",
640
+ touchAction: "none"
641
+ } : { display: "none" };
642
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, onClick: handleClick, style: surface, children: [
643
+ /* @__PURE__ */ jsxRuntime.jsx(CmsPage, { doc }),
644
+ /* @__PURE__ */ jsxRuntime.jsx(
645
+ "div",
646
+ {
647
+ onPointerDown: handlePointerDown,
648
+ onPointerMove: handlePointerMove,
649
+ onPointerUp: handlePointerUp,
650
+ style: overlay
651
+ }
652
+ )
653
+ ] });
654
+ }
655
+ function cssEscape(value) {
656
+ return value.replace(/["\\]/g, "\\$&");
657
+ }
658
+ var MIME = "application/x-cms-node";
659
+ function isAncestorOrSelf(doc, id, maybeAncestor) {
660
+ for (let cur = id; cur; cur = doc.nodes[cur]?.parent ?? null) {
661
+ if (cur === maybeAncestor) return true;
662
+ }
663
+ return false;
664
+ }
665
+ function LayersPanel({ doc, selection, onSelect, onMove }) {
666
+ const [overId, setOverId] = react.useState(null);
667
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflow: "auto", padding: 8, fontSize: 13, fontFamily: "system-ui, sans-serif" }, children: doc.sections.map((id) => /* @__PURE__ */ jsxRuntime.jsx(LayerRow, { doc, id, depth: 0, selection, onSelect, onMove, overId, setOverId }, id)) });
668
+ }
669
+ function LayerRow({ doc, id, depth, selection, onSelect, onMove, overId, setOverId }) {
670
+ const node = doc.nodes[id];
671
+ if (!node) return null;
672
+ const selected = selection === id;
673
+ const draggable = Boolean(onMove);
674
+ const drop = (e) => {
675
+ e.preventDefault();
676
+ e.stopPropagation();
677
+ setOverId(null);
678
+ if (!onMove) return;
679
+ const dragId = e.dataTransfer.getData(MIME);
680
+ if (!dragId || dragId === id || isAncestorOrSelf(doc, id, dragId)) return;
681
+ const siblings = childrenOf(doc, node.parent);
682
+ const idx = siblings.findIndex((n) => n.id === id);
683
+ const next = siblings[idx + 1];
684
+ onMove(dragId, node.parent, keyBetween(node.order, next ? next.order : null));
685
+ };
686
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
687
+ /* @__PURE__ */ jsxRuntime.jsxs(
688
+ "button",
689
+ {
690
+ type: "button",
691
+ draggable,
692
+ onClick: () => onSelect(id),
693
+ onDragStart: (e) => {
694
+ e.dataTransfer.setData(MIME, id);
695
+ e.dataTransfer.effectAllowed = "move";
696
+ },
697
+ onDragOver: (e) => {
698
+ if (!onMove) return;
699
+ e.preventDefault();
700
+ e.dataTransfer.dropEffect = "move";
701
+ if (overId !== id) setOverId(id);
702
+ },
703
+ onDragLeave: () => overId === id && setOverId(null),
704
+ onDrop: drop,
705
+ style: {
706
+ display: "block",
707
+ width: "100%",
708
+ textAlign: "left",
709
+ border: "none",
710
+ borderRadius: 6,
711
+ cursor: draggable ? "grab" : "pointer",
712
+ padding: "4px 8px",
713
+ paddingLeft: 8 + depth * 14,
714
+ background: selected ? "#ede9fe" : "transparent",
715
+ color: selected ? "#5b21b6" : "#334155",
716
+ font: "inherit",
717
+ boxShadow: overId === id ? "inset 0 -2px 0 0 #8b5cf6" : "none"
718
+ },
719
+ children: [
720
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { opacity: 0.6 }, children: node.type }),
721
+ " \xB7 ",
722
+ id
723
+ ]
724
+ }
725
+ ),
726
+ childrenOf(doc, id).map((child) => /* @__PURE__ */ jsxRuntime.jsx(LayerRow, { doc, id: child.id, depth: depth + 1, selection, onSelect, onMove, overId, setOverId }, child.id))
727
+ ] });
728
+ }
729
+ var label = {
730
+ display: "block",
731
+ fontSize: 11,
732
+ textTransform: "uppercase",
733
+ letterSpacing: "0.04em",
734
+ color: "#94a3b8",
735
+ margin: "10px 0 4px"
736
+ };
737
+ var input = {
738
+ width: "100%",
739
+ boxSizing: "border-box",
740
+ padding: "6px 8px",
741
+ borderRadius: 6,
742
+ border: "1px solid #e2e8f0",
743
+ font: "inherit",
744
+ fontSize: 13
745
+ };
746
+ function Inspector({ doc, selection, apply }) {
747
+ const node = selection ? doc.nodes[selection] : null;
748
+ if (!node) {
749
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 16, color: "#94a3b8", fontFamily: "system-ui, sans-serif", fontSize: 13 }, children: "Select an element to edit." });
750
+ }
751
+ const s = node.style.base;
752
+ const setStyle = (patch) => apply({ t: "set_style", id: node.id, breakpoint: "base", patch });
753
+ const setProp = (key, value) => apply({ t: "set_props", id: node.id, patch: { [key]: value } });
754
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { overflow: "auto", padding: 16, fontFamily: "system-ui, sans-serif", height: "100%", boxSizing: "border-box" }, children: [
755
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, fontWeight: 600, color: "#0f172a" }, children: node.type }),
756
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "#94a3b8", marginBottom: 8 }, children: node.id }),
757
+ node.type === "text" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
758
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: label, children: "Content" }),
759
+ /* @__PURE__ */ jsxRuntime.jsx(
760
+ "textarea",
761
+ {
762
+ style: { ...input, minHeight: 64, resize: "vertical" },
763
+ value: typeof node.props.content === "string" ? node.props.content : "",
764
+ onChange: (e) => setProp("content", e.target.value)
765
+ }
766
+ )
767
+ ] }) : null,
768
+ node.type === "image" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
769
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: label, children: "Source" }),
770
+ /* @__PURE__ */ jsxRuntime.jsx(
771
+ "input",
772
+ {
773
+ style: input,
774
+ value: typeof node.props.src === "string" ? node.props.src : "",
775
+ onChange: (e) => setProp("src", e.target.value)
776
+ }
777
+ )
778
+ ] }) : null,
779
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: label, children: "Background" }),
780
+ /* @__PURE__ */ jsxRuntime.jsx(
781
+ "input",
782
+ {
783
+ style: input,
784
+ placeholder: "#ffffff | gradient | url(\u2026)",
785
+ value: s.background ?? "",
786
+ onChange: (e) => setStyle({ background: e.target.value })
787
+ }
788
+ ),
789
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: label, children: "Text color" }),
790
+ /* @__PURE__ */ jsxRuntime.jsx(
791
+ "input",
792
+ {
793
+ style: input,
794
+ placeholder: "#0f172a",
795
+ value: s.color ?? "",
796
+ onChange: (e) => setStyle({ color: e.target.value })
797
+ }
798
+ ),
799
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: label, children: "Font size (px)" }),
800
+ /* @__PURE__ */ jsxRuntime.jsx(
801
+ "input",
802
+ {
803
+ type: "number",
804
+ style: input,
805
+ value: s.fontSize?.value ?? "",
806
+ onChange: (e) => setStyle({ fontSize: { value: Number(e.target.value) || 0, unit: "px" } })
807
+ }
808
+ ),
809
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: label, children: "Padding (px)" }),
810
+ /* @__PURE__ */ jsxRuntime.jsx(
811
+ "input",
812
+ {
813
+ type: "number",
814
+ style: input,
815
+ value: s.padding?.value ?? "",
816
+ onChange: (e) => setStyle({ padding: { value: Number(e.target.value) || 0, unit: "px" } })
817
+ }
818
+ ),
819
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: label, children: "Opacity" }),
820
+ /* @__PURE__ */ jsxRuntime.jsx(
821
+ "input",
822
+ {
823
+ type: "number",
824
+ step: "0.1",
825
+ min: "0",
826
+ max: "1",
827
+ style: input,
828
+ value: s.opacity ?? "",
829
+ onChange: (e) => setStyle({ opacity: Number(e.target.value) })
830
+ }
831
+ )
832
+ ] });
833
+ }
834
+ function Editor({ defaultValue, onChange }) {
835
+ const ed = useEditor(defaultValue);
836
+ const first = react.useRef(true);
837
+ react.useEffect(() => {
838
+ if (first.current) {
839
+ first.current = false;
840
+ return;
841
+ }
842
+ onChange?.(ed.state.doc);
843
+ }, [ed.state.doc, onChange]);
844
+ const shell = {
845
+ display: "grid",
846
+ gridTemplateColumns: "220px 1fr 300px",
847
+ height: "100%",
848
+ minHeight: 0,
849
+ background: "#fff",
850
+ color: "#0f172a",
851
+ border: "1px solid #e2e8f0",
852
+ borderRadius: 12,
853
+ overflow: "hidden"
854
+ };
855
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: shell, children: [
856
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { borderRight: "1px solid #e2e8f0", display: "flex", flexDirection: "column", minHeight: 0 }, children: [
857
+ /* @__PURE__ */ jsxRuntime.jsx(Toolbar, { ed }),
858
+ /* @__PURE__ */ jsxRuntime.jsx(
859
+ LayersPanel,
860
+ {
861
+ doc: ed.state.doc,
862
+ selection: ed.state.selection,
863
+ onSelect: ed.select,
864
+ onMove: (id, parent, order) => ed.apply({ t: "move_node", id, parent, order })
865
+ }
866
+ )
867
+ ] }),
868
+ /* @__PURE__ */ jsxRuntime.jsx(Canvas, { doc: ed.state.doc, selection: ed.state.selection, onSelect: ed.select, apply: ed.apply }),
869
+ /* @__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 }) })
870
+ ] });
871
+ }
872
+ function Toolbar({ ed }) {
873
+ const btn = {
874
+ font: "inherit",
875
+ fontSize: 12,
876
+ padding: "4px 10px",
877
+ borderRadius: 6,
878
+ border: "1px solid #e2e8f0",
879
+ background: "#fff",
880
+ cursor: "pointer"
881
+ };
882
+ return /* @__PURE__ */ jsxRuntime.jsxs(
883
+ "div",
884
+ {
885
+ style: {
886
+ display: "flex",
887
+ gap: 6,
888
+ padding: 8,
889
+ borderBottom: "1px solid #e2e8f0",
890
+ fontFamily: "system-ui, sans-serif"
891
+ },
892
+ children: [
893
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: { ...btn, opacity: ed.canUndo ? 1 : 0.4 }, disabled: !ed.canUndo, onClick: ed.undo, children: "Undo" }),
894
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: { ...btn, opacity: ed.canRedo ? 1 : 0.4 }, disabled: !ed.canRedo, onClick: ed.redo, children: "Redo" })
895
+ ]
896
+ }
897
+ );
898
+ }
395
899
 
900
+ exports.Canvas = Canvas;
901
+ exports.CmsPage = CmsPage;
902
+ exports.CmsRegion = CmsRegion;
396
903
  exports.DEFAULT_BREAKPOINTS = DEFAULT_BREAKPOINTS;
904
+ exports.Editor = Editor;
905
+ exports.Inspector = Inspector;
906
+ exports.LayersPanel = LayersPanel;
907
+ exports.RenderNode = RenderNode;
397
908
  exports.childrenOf = childrenOf;
909
+ exports.defaultRegistry = defaultRegistry;
398
910
  exports.descendantIds = descendantIds;
911
+ exports.editorReduce = editorReduce;
399
912
  exports.emitDocCss = emitDocCss;
400
913
  exports.emptyDoc = emptyDoc;
914
+ exports.getPath = getPath;
915
+ exports.initEditor = initEditor;
401
916
  exports.invert = invert;
402
917
  exports.isBinding = isBinding;
403
918
  exports.keyBetween = keyBetween;
404
919
  exports.reduce = reduce;
405
920
  exports.reduceAll = reduceAll;
921
+ exports.resolveValue = resolveValue;
922
+ exports.useEditor = useEditor;
406
923
  //# sourceMappingURL=index.cjs.map
407
924
  //# sourceMappingURL=index.cjs.map