@particle-academy/fancy-cms-ui 0.0.1-dev.14 → 0.0.1-dev.16

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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { keyBetween } from './chunk-7YYLYBLI.js';
2
- import { CmsPage, defaultRegistry } from './chunk-IXPYY4S2.js';
2
+ import { CmsPage, defaultRegistry } from './chunk-KCJWSR7D.js';
3
3
  import { reduce, childrenOf, isBinding } from './chunk-3YZMELJJ.js';
4
4
  import { useReducer, useCallback, useMemo, useRef, useState, useLayoutEffect, Fragment, useEffect } from 'react';
5
5
  import { jsxs, jsx, Fragment as Fragment$1 } from 'react/jsx-runtime';
@@ -878,7 +878,7 @@ function EditablePage({
878
878
  },
879
879
  [ed, selNode]
880
880
  );
881
- const addNodeAt = useCallback(
881
+ useCallback(
882
882
  (kind, targetId) => {
883
883
  const doc2 = ed.state.doc;
884
884
  const target = targetId ? doc2.nodes[targetId] : null;
@@ -907,12 +907,48 @@ function EditablePage({
907
907
  window.addEventListener("mousemove", onMove);
908
908
  return () => window.removeEventListener("mousemove", onMove);
909
909
  }, [editing, draggingEl]);
910
+ const [dropHint, setDropHint] = useState(null);
911
+ const computeDropTarget = (clientX, clientY) => {
912
+ const el = document.elementFromPoint(clientX, clientY)?.closest("[data-cms]");
913
+ if (!el) return { id: null, edge: "inside", rect: null };
914
+ const id = el.getAttribute("data-cms");
915
+ const node = ed.state.doc.nodes[id];
916
+ const r = el.getBoundingClientRect();
917
+ const rect = { x: r.left, y: r.top, w: r.width, h: r.height };
918
+ if (node && CONTAINER_TYPES2.has(node.type)) return { id, edge: "inside", rect };
919
+ return { id, edge: clientY < r.top + r.height / 2 ? "before" : "after", rect };
920
+ };
921
+ const onPageDragOver = (e) => {
922
+ e.preventDefault();
923
+ e.dataTransfer.dropEffect = "copy";
924
+ setDropHint(computeDropTarget(e.clientX, e.clientY));
925
+ };
926
+ const insertRelative = (kind, hint) => {
927
+ const doc2 = ed.state.doc;
928
+ let parent;
929
+ let order;
930
+ if (!hint.id || hint.edge === "inside") {
931
+ parent = hint.id ?? (doc2.sections[doc2.sections.length - 1] ?? null);
932
+ const sib = childrenOf(doc2, parent);
933
+ order = keyBetween(sib.length ? sib[sib.length - 1].order : null, null);
934
+ } else {
935
+ const target = doc2.nodes[hint.id];
936
+ parent = target.parent;
937
+ const sib = childrenOf(doc2, parent);
938
+ const idx = sib.findIndex((n) => n.id === hint.id);
939
+ 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);
940
+ }
941
+ const id = `n${doc2.seq + 1}-${Math.floor(performance.now())}`;
942
+ const def = ADD_DEFAULTS[kind];
943
+ ed.apply({ t: "insert_node", node: { id, type: def.type, parent, order, layout: def.layout, props: { ...def.props }, style: { base: { ...def.style } } } });
944
+ ed.select(id);
945
+ };
910
946
  const onPageDrop = (e) => {
911
947
  const kind = e.dataTransfer.getData("application/x-cms-element");
912
948
  if (!kind) return;
913
949
  e.preventDefault();
914
- const el = document.elementFromPoint(e.clientX, e.clientY)?.closest("[data-cms]");
915
- addNodeAt(kind, el?.getAttribute("data-cms") ?? null);
950
+ insertRelative(kind, computeDropTarget(e.clientX, e.clientY));
951
+ setDropHint(null);
916
952
  setDraggingEl(false);
917
953
  };
918
954
  const setStyle = (patch) => selection && ed.apply({ t: "set_style", id: selection, breakpoint: "base", patch });
@@ -988,7 +1024,8 @@ function EditablePage({
988
1024
  ref: pageRef,
989
1025
  onClickCapture,
990
1026
  onContextMenu: onContextMenuSelect,
991
- onDragOver: editing ? (e) => e.preventDefault() : void 0,
1027
+ onDragOver: editing ? onPageDragOver : void 0,
1028
+ onDragLeave: editing ? () => setDropHint(null) : void 0,
992
1029
  onDrop: editing ? onPageDrop : void 0,
993
1030
  children: /* @__PURE__ */ jsx(CmsPage, { doc: ed.state.doc, registry, data })
994
1031
  }
@@ -1059,10 +1096,23 @@ function EditablePage({
1059
1096
  onAdd: addNode
1060
1097
  }
1061
1098
  ) : null,
1099
+ editing && dropHint?.rect ? /* @__PURE__ */ jsx(DropIndicator, { hint: dropHint }) : null,
1062
1100
  editing ? /* @__PURE__ */ jsx(ElementPalette, { open: paletteOpen, onDragChange: setDraggingEl }) : null,
1063
1101
  editing && timelineDock ? /* @__PURE__ */ jsx("div", { style: { position: "fixed", left: 0, right: 0, bottom: 0, zIndex: Z2 }, children: timelineDock }) : null
1064
1102
  ] });
1065
1103
  }
1104
+ function DropIndicator({
1105
+ hint
1106
+ }) {
1107
+ const r = hint.rect;
1108
+ if (!r) return null;
1109
+ const color = "#ec4899";
1110
+ if (hint.edge === "inside") {
1111
+ return /* @__PURE__ */ 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 } });
1112
+ }
1113
+ const y = hint.edge === "before" ? r.y : r.y + r.h;
1114
+ return /* @__PURE__ */ 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 } });
1115
+ }
1066
1116
  function ElementPalette({ open, onDragChange }) {
1067
1117
  return /* @__PURE__ */ jsxs(
1068
1118
  "div",
@@ -1139,6 +1189,7 @@ var ADD_DEFAULTS = {
1139
1189
  callout: { type: "callout", props: { content: "Heads up \u2014 this is a callout.", variant: "info" }, style: {} },
1140
1190
  divider: { type: "divider", props: {}, style: {} },
1141
1191
  code: { type: "code", props: { content: "npm install @particle-academy/react-fancy", lang: "bash" }, style: {} },
1192
+ richtext: { type: "richtext", props: { html: "<p>Rich <strong>text</strong> with <em>inline</em> formatting.</p>" }, style: {} },
1142
1193
  repeater: { type: "repeater", props: { items: "" }, style: { gap: { value: 12, unit: "px" } }, layout: "stack" }
1143
1194
  };
1144
1195
  var GRIPS = [
@@ -1351,6 +1402,7 @@ var ADD_MENU = [
1351
1402
  { kind: "box", label: "Box" },
1352
1403
  { kind: "divider", label: "Divider" },
1353
1404
  { kind: "code", label: "Code" },
1405
+ { kind: "richtext", label: "Rich text" },
1354
1406
  { kind: "repeater", label: "Repeater" }
1355
1407
  ];
1356
1408
  function EditBar({