@particle-academy/fancy-cms-ui 0.4.0 → 0.5.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.
@@ -1,4 +1,4 @@
1
- import { emitDocCss, RenderNode, defaultRegistry } from './chunk-GOXVGEKU.js';
1
+ import { emitDocCss, RenderNode, defaultRegistry } from './chunk-FDCP3LVR.js';
2
2
  import { Fragment } from 'react';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
 
@@ -15,5 +15,5 @@ function CmsRegion({
15
15
  }
16
16
 
17
17
  export { CmsRegion };
18
- //# sourceMappingURL=chunk-QYNWSECG.js.map
19
- //# sourceMappingURL=chunk-QYNWSECG.js.map
18
+ //# sourceMappingURL=chunk-Z2X7B6YL.js.map
19
+ //# sourceMappingURL=chunk-Z2X7B6YL.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react/CmsRegion.tsx"],"names":[],"mappings":";;;;AAmBO,SAAS,SAAA,CAAU;AAAA,EACxB,GAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA,GAAW,eAAA;AAAA,EACX,aAAA,GAAgB;AAClB,CAAA,EAAiC;AAC/B,EAAA,4BACG,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,IAAA,aAAA,uBAAiB,OAAA,EAAA,EAAM,iBAAA,EAAgB,IAAI,QAAA,EAAA,UAAA,CAAW,GAAG,GAAE,CAAA,GAAW,IAAA;AAAA,oBACvE,GAAA,CAAC,UAAA,EAAA,EAAW,GAAA,EAAU,EAAA,EAAI,MAAM,QAAA,EAAoB;AAAA,GAAA,EACtD,CAAA;AAEJ","file":"chunk-QYNWSECG.js","sourcesContent":["import { Fragment, type ReactElement } from \"react\";\nimport type { PageDoc } from \"../document/types\";\nimport { emitDocCss } from \"../render/css\";\nimport { RenderNode } from \"./RenderNode\";\nimport { defaultRegistry, type ElementRegistry } from \"./registry\";\n\nexport interface CmsRegionProps {\n doc: PageDoc;\n /** Root node id of the region to render (a section, or any node). */\n root: string;\n registry?: ElementRegistry;\n includeStyles?: boolean;\n}\n\n/**\n * Render a single subtree — drop into a hand-coded page so the CMS owns just\n * that region (the \"guest, not host\" mounting mode). Phase 0/1 emits the whole\n * document's CSS; scoping it to the subtree is a later optimization.\n */\nexport function CmsRegion({\n doc,\n root,\n registry = defaultRegistry,\n includeStyles = true,\n}: CmsRegionProps): ReactElement {\n return (\n <Fragment>\n {includeStyles ? <style data-cms-styles=\"\">{emitDocCss(doc)}</style> : null}\n <RenderNode doc={doc} id={root} registry={registry} />\n </Fragment>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/react/CmsRegion.tsx"],"names":[],"mappings":";;;;AAmBO,SAAS,SAAA,CAAU;AAAA,EACxB,GAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA,GAAW,eAAA;AAAA,EACX,aAAA,GAAgB;AAClB,CAAA,EAAiC;AAC/B,EAAA,4BACG,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,IAAA,aAAA,uBAAiB,OAAA,EAAA,EAAM,iBAAA,EAAgB,IAAI,QAAA,EAAA,UAAA,CAAW,GAAG,GAAE,CAAA,GAAW,IAAA;AAAA,oBACvE,GAAA,CAAC,UAAA,EAAA,EAAW,GAAA,EAAU,EAAA,EAAI,MAAM,QAAA,EAAoB;AAAA,GAAA,EACtD,CAAA;AAEJ","file":"chunk-Z2X7B6YL.js","sourcesContent":["import { Fragment, type ReactElement } from \"react\";\nimport type { PageDoc } from \"../document/types\";\nimport { emitDocCss } from \"../render/css\";\nimport { RenderNode } from \"./RenderNode\";\nimport { defaultRegistry, type ElementRegistry } from \"./registry\";\n\nexport interface CmsRegionProps {\n doc: PageDoc;\n /** Root node id of the region to render (a section, or any node). */\n root: string;\n registry?: ElementRegistry;\n includeStyles?: boolean;\n}\n\n/**\n * Render a single subtree — drop into a hand-coded page so the CMS owns just\n * that region (the \"guest, not host\" mounting mode). Phase 0/1 emits the whole\n * document's CSS; scoping it to the subtree is a later optimization.\n */\nexport function CmsRegion({\n doc,\n root,\n registry = defaultRegistry,\n includeStyles = true,\n}: CmsRegionProps): ReactElement {\n return (\n <Fragment>\n {includeStyles ? <style data-cms-styles=\"\">{emitDocCss(doc)}</style> : null}\n <RenderNode doc={doc} id={root} registry={registry} />\n </Fragment>\n );\n}\n"]}
package/dist/editor.cjs CHANGED
@@ -1,38 +1,61 @@
1
1
  'use strict';
2
2
 
3
3
  var react = require('react');
4
+ var fancyDocCommons = require('@particle-academy/fancy-doc-commons');
4
5
  var jsxRuntime = require('react/jsx-runtime');
5
6
  var reactFancy = require('@particle-academy/react-fancy');
6
7
 
7
8
  // src/editor/Editor.tsx
8
-
9
- // src/document/reduce.ts
10
- function childrenOf(doc, parent) {
11
- if (parent === null) {
12
- return doc.sections.map((id) => doc.nodes[id]).filter((n) => Boolean(n));
9
+ function migrateDocVerbose(input3) {
10
+ const legacy = input3;
11
+ const sections = legacy.sections;
12
+ if (!Array.isArray(sections)) {
13
+ return { doc: input3, migrated: false, danglingIds: [], unlistedRootIds: [] };
13
14
  }
14
- const out = [];
15
- for (const id of Object.keys(doc.nodes)) {
16
- const n = doc.nodes[id];
17
- if (n.parent === parent) out.push(n);
15
+ const danglingIds = [];
16
+ const ordered = [];
17
+ const seen = /* @__PURE__ */ new Set();
18
+ for (const id of sections) {
19
+ if (!input3.nodes[id]) {
20
+ danglingIds.push(id);
21
+ continue;
22
+ }
23
+ if (seen.has(id)) continue;
24
+ seen.add(id);
25
+ ordered.push(id);
18
26
  }
19
- out.sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
20
- return out;
27
+ const unlistedRootIds = Object.values(input3.nodes).filter((n) => n.parent === null && !seen.has(n.id)).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0).map((n) => n.id);
28
+ const finalOrder = [...ordered, ...unlistedRootIds];
29
+ const nodes = { ...input3.nodes };
30
+ let prev = null;
31
+ for (const id of finalOrder) {
32
+ const key = fancyDocCommons.fractionalKey(prev, null);
33
+ nodes[id] = { ...nodes[id], order: key };
34
+ prev = key;
35
+ }
36
+ const { sections: _dropped, ...rest } = legacy;
37
+ return {
38
+ doc: { ...rest, nodes },
39
+ migrated: true,
40
+ danglingIds,
41
+ unlistedRootIds
42
+ };
43
+ }
44
+ function migrateDoc(input3) {
45
+ return migrateDocVerbose(input3).doc;
46
+ }
47
+ function childrenOf(doc, parent) {
48
+ return fancyDocCommons.childrenOf(doc, parent);
49
+ }
50
+ function rootIds(doc) {
51
+ return childrenOf(doc, null).map((n) => n.id);
52
+ }
53
+ function lastRootId(doc) {
54
+ const r = rootIds(doc);
55
+ return r[r.length - 1] ?? null;
21
56
  }
22
57
  function descendantIds(doc, id) {
23
- const out = [];
24
- const stack = [id];
25
- while (stack.length) {
26
- const current = stack.pop();
27
- for (const childId of Object.keys(doc.nodes)) {
28
- const n = doc.nodes[childId];
29
- if (n.parent === current) {
30
- out.push(childId);
31
- stack.push(childId);
32
- }
33
- }
34
- }
35
- return out;
58
+ return fancyDocCommons.descendantsOf(doc, id);
36
59
  }
37
60
  function patchNode(doc, id, patch) {
38
61
  const node = doc.nodes[id];
@@ -54,7 +77,6 @@ function reduce(doc, op, opts = {}) {
54
77
  return {
55
78
  ...doc,
56
79
  nodes: { ...doc.nodes, [op.node.id]: op.node },
57
- sections: op.node.parent === null ? [...doc.sections, op.node.id] : doc.sections,
58
80
  seq: doc.seq + 1
59
81
  };
60
82
  }
@@ -68,7 +90,6 @@ function reduce(doc, op, opts = {}) {
68
90
  return {
69
91
  ...doc,
70
92
  nodes,
71
- sections: doc.sections.filter((s) => !dead.has(s)),
72
93
  seq: doc.seq + 1
73
94
  };
74
95
  }
@@ -80,15 +101,9 @@ function reduce(doc, op, opts = {}) {
80
101
  if (op.parent !== null && descendantIds(doc, op.id).includes(op.parent)) {
81
102
  return invalid("move would create a cycle");
82
103
  }
83
- const wasTop = node.parent === null;
84
- const nowTop = op.parent === null;
85
- let sections = doc.sections;
86
- if (wasTop && !nowTop) sections = sections.filter((s) => s !== op.id);
87
- else if (!wasTop && nowTop) sections = [...sections, op.id];
88
104
  return {
89
105
  ...doc,
90
106
  nodes: { ...doc.nodes, [op.id]: { ...node, parent: op.parent, order: op.order } },
91
- sections,
92
107
  seq: doc.seq + 1
93
108
  };
94
109
  }
@@ -149,18 +164,25 @@ function reduce(doc, op, opts = {}) {
149
164
  return { ...doc, meta: { ...doc.meta, ...op.patch }, seq: doc.seq + 1 };
150
165
  case "set_theme":
151
166
  return { ...doc, theme: { ...doc.theme, ...op.patch }, seq: doc.seq + 1 };
152
- case "reorder_sections": {
153
- const current = new Set(doc.sections);
154
- const same = op.order.length === doc.sections.length && op.order.every((id) => current.has(id));
155
- if (!same) return invalid("reorder must be a permutation of current sections");
156
- return { ...doc, sections: [...op.order], seq: doc.seq + 1 };
167
+ case "reorder_roots": {
168
+ const currentRoots = childrenOf(doc, null);
169
+ const current = new Set(currentRoots.map((n) => n.id));
170
+ const same = op.order.length === currentRoots.length && op.order.every((id) => current.has(id));
171
+ if (!same) return invalid("reorder must be a permutation of the current roots");
172
+ const nodes = { ...doc.nodes };
173
+ let prev = null;
174
+ for (const id of op.order) {
175
+ prev = fancyDocCommons.fractionalKey(prev, null);
176
+ nodes[id] = { ...nodes[id], order: prev };
177
+ }
178
+ return { ...doc, nodes, seq: doc.seq + 1 };
157
179
  }
158
180
  default:
159
181
  return invalid(`unknown op "${op.t}"`);
160
182
  }
161
183
  }
162
184
  function initEditor(doc) {
163
- return { doc, past: [], future: [], selection: null };
185
+ return { doc: migrateDoc(doc), past: [], future: [], selection: null };
164
186
  }
165
187
  function editorReduce(state, action) {
166
188
  switch (action.type) {
@@ -249,7 +271,6 @@ function emptyDoc(id, slug = "/") {
249
271
  meta: { title: "Untitled", slug, scrollMode: "smooth" },
250
272
  theme: { name: "default" },
251
273
  breakpoints: ["base", "md", "lg"],
252
- sections: [],
253
274
  nodes: {}
254
275
  };
255
276
  }
@@ -457,14 +478,15 @@ function RenderNode({ doc, id, registry = defaultRegistry, data }) {
457
478
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cms": node.id, "data-cms-island": node.island ? node.type : void 0, className: node.className, children: inner });
458
479
  }
459
480
  function CmsPage({
460
- doc,
481
+ doc: input3,
461
482
  registry = defaultRegistry,
462
483
  data,
463
484
  includeStyles = true
464
485
  }) {
486
+ const doc = react.useMemo(() => migrateDoc(input3), [input3]);
465
487
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
466
488
  includeStyles ? /* @__PURE__ */ jsxRuntime.jsx("style", { "data-cms-styles": "", children: emitDocCss(doc) }) : null,
467
- doc.sections.map((id) => /* @__PURE__ */ jsxRuntime.jsx(RenderNode, { doc, id, registry, data }, id))
489
+ rootIds(doc).map((id) => /* @__PURE__ */ jsxRuntime.jsx(RenderNode, { doc, id, registry, data }, id))
468
490
  ] });
469
491
  }
470
492
  function Canvas({ doc, selection, onSelect, apply, registry, data }) {
@@ -553,50 +575,6 @@ function Canvas({ doc, selection, onSelect, apply, registry, data }) {
553
575
  function cssEscape(value) {
554
576
  return value.replace(/["\\]/g, "\\$&");
555
577
  }
556
-
557
- // src/document/fractional.ts
558
- var BASE = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
559
- var RADIX = BASE.length;
560
- var MID = Math.floor(RADIX / 2);
561
- function val(c) {
562
- const i = BASE.indexOf(c);
563
- return i < 0 ? 0 : i;
564
- }
565
- function keyBetween(a, b) {
566
- if (a === null) a = "";
567
- if (b === null) {
568
- return a + BASE[MID];
569
- }
570
- if (a >= b) {
571
- throw new Error(`keyBetween: lower bound "${a}" is not below upper bound "${b}"`);
572
- }
573
- let result = "";
574
- let i = 0;
575
- for (; ; ) {
576
- const ca = i < a.length ? val(a[i]) : 0;
577
- const cb = i < b.length ? val(b[i]) : RADIX;
578
- if (cb - ca > 1) {
579
- result += BASE[ca + Math.floor((cb - ca) / 2)];
580
- return result;
581
- }
582
- if (ca === cb) {
583
- result += BASE[ca];
584
- i++;
585
- continue;
586
- }
587
- result += BASE[ca];
588
- i++;
589
- for (; ; ) {
590
- const da = i < a.length ? val(a[i]) : 0;
591
- if (RADIX - da > 1) {
592
- result += BASE[da + Math.floor((RADIX - da) / 2)];
593
- return result;
594
- }
595
- result += BASE[da];
596
- i++;
597
- }
598
- }
599
- }
600
578
  var MIME = "application/x-cms-node";
601
579
  function isAncestorOrSelf(doc, id, maybeAncestor) {
602
580
  for (let cur = id; cur; cur = doc.nodes[cur]?.parent ?? null) {
@@ -606,7 +584,7 @@ function isAncestorOrSelf(doc, id, maybeAncestor) {
606
584
  }
607
585
  function LayersPanel({ doc, selection, onSelect, onMove }) {
608
586
  const [overId, setOverId] = react.useState(null);
609
- 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)) });
587
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflow: "auto", padding: 8, fontSize: 13, fontFamily: "system-ui, sans-serif" }, children: rootIds(doc).map((id) => /* @__PURE__ */ jsxRuntime.jsx(LayerRow, { doc, id, depth: 0, selection, onSelect, onMove, overId, setOverId }, id)) });
610
588
  }
611
589
  function LayerRow({ doc, id, depth, selection, onSelect, onMove, overId, setOverId }) {
612
590
  const node = doc.nodes[id];
@@ -623,7 +601,7 @@ function LayerRow({ doc, id, depth, selection, onSelect, onMove, overId, setOver
623
601
  const siblings = childrenOf(doc, node.parent);
624
602
  const idx = siblings.findIndex((n) => n.id === id);
625
603
  const next = siblings[idx + 1];
626
- onMove(dragId, node.parent, keyBetween(node.order, next ? next.order : null));
604
+ onMove(dragId, node.parent, fancyDocCommons.fractionalKey(node.order, next ? next.order : null));
627
605
  };
628
606
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
629
607
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -791,8 +769,6 @@ function Inspector({ doc, selection, apply }) {
791
769
  )
792
770
  ] });
793
771
  }
794
-
795
- // src/editor/insert.ts
796
772
  var CONTAINER_TYPES = /* @__PURE__ */ new Set([
797
773
  "section",
798
774
  "frame",
@@ -840,12 +816,12 @@ function resolveInsertParent(doc, selectedId) {
840
816
  if (selected) {
841
817
  return CONTAINER_TYPES.has(selected.type) ? selected.id : selected.parent;
842
818
  }
843
- return doc.sections[doc.sections.length - 1] ?? null;
819
+ return lastRootId(doc);
844
820
  }
845
821
  function buildInsertOp(doc, kind, selectedId, targetId) {
846
822
  const parent = resolveInsertParent(doc, selectedId);
847
823
  const siblings = childrenOf(doc, parent);
848
- const order = keyBetween(siblings.length ? siblings[siblings.length - 1].order : null, null);
824
+ const order = fancyDocCommons.fractionalKey(siblings.length ? siblings[siblings.length - 1].order : null, null);
849
825
  const id = `n${doc.seq + 1}-${Math.floor(performance.now())}`;
850
826
  const def = ADD_DEFAULTS[kind];
851
827
  return {
@@ -1271,8 +1247,6 @@ var input2 = {
1271
1247
  };
1272
1248
  var iconBtn = { background: "transparent", border: "none", color: "#e2e8f0", cursor: "pointer", fontSize: 13, padding: 4, borderRadius: 6 };
1273
1249
  var miniBtn = { font: "inherit", fontSize: 11, color: "#e2e8f0", background: "#334155", border: "1px solid #475569", borderRadius: 6, padding: "5px 10px", cursor: "pointer" };
1274
-
1275
- // src/editor/editorOps.ts
1276
1250
  function childrenOfMap(nodes, parent) {
1277
1251
  return Object.values(nodes).filter((n) => n.parent === parent).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
1278
1252
  }
@@ -1306,20 +1280,20 @@ function duplicateOps(doc, id) {
1306
1280
  if (!node) return { ops: [], newRootId: null };
1307
1281
  const sibs = childrenOf(doc, node.parent);
1308
1282
  const idx = sibs.findIndex((s) => s.id === id);
1309
- const newOrder = keyBetween(node.order, sibs[idx + 1]?.order ?? null);
1283
+ const newOrder = fancyDocCommons.fractionalKey(node.order, sibs[idx + 1]?.order ?? null);
1310
1284
  const { ops, newRootId } = cloneFrom(doc.nodes, id, node.parent, newOrder, doc.seq);
1311
1285
  if (node.parent === null && newRootId) {
1312
- const base = doc.sections;
1286
+ const base = childrenOf(doc, null).map((n) => n.id);
1313
1287
  const at = base.indexOf(id);
1314
- ops.push({ t: "reorder_sections", order: [...base.slice(0, at + 1), newRootId, ...base.slice(at + 1)] });
1288
+ ops.push({ t: "reorder_roots", order: [...base.slice(0, at + 1), newRootId, ...base.slice(at + 1)] });
1315
1289
  }
1316
1290
  return { ops, newRootId };
1317
1291
  }
1318
1292
  function pasteOps(doc, clip, target, containerTypes) {
1319
1293
  const sel = target ? doc.nodes[target] : null;
1320
- const parent = sel ? containerTypes.has(sel.type) ? sel.id : sel.parent : doc.sections[doc.sections.length - 1] ?? null;
1294
+ const parent = sel ? containerTypes.has(sel.type) ? sel.id : sel.parent : lastRootId(doc);
1321
1295
  const sibs = childrenOf(doc, parent);
1322
- const newOrder = keyBetween(sibs.length ? sibs[sibs.length - 1].order : null, null);
1296
+ const newOrder = fancyDocCommons.fractionalKey(sibs.length ? sibs[sibs.length - 1].order : null, null);
1323
1297
  const { ops, newRootId } = cloneFrom(clip.nodes, clip.rootId, parent, newOrder, doc.seq);
1324
1298
  return { ops, newRootId };
1325
1299
  }
@@ -1327,14 +1301,14 @@ function reorderOps(doc, id, dir) {
1327
1301
  const node = doc.nodes[id];
1328
1302
  if (!node) return [];
1329
1303
  if (node.parent === null) {
1330
- const s = [...doc.sections];
1304
+ const s = childrenOf(doc, null).map((n) => n.id);
1331
1305
  const i = s.indexOf(id);
1332
1306
  if (i < 0) return [];
1333
1307
  s.splice(i, 1);
1334
1308
  if (dir === "front") s.unshift(id);
1335
1309
  else if (dir === "back") s.push(id);
1336
1310
  else s.splice(Math.max(0, Math.min(s.length, dir === "up" ? i - 1 : i + 1)), 0, id);
1337
- return [{ t: "reorder_sections", order: s }];
1311
+ return [{ t: "reorder_roots", order: s }];
1338
1312
  }
1339
1313
  const sibs = childrenOf(doc, node.parent);
1340
1314
  const idx = sibs.findIndex((sb) => sb.id === id);
@@ -1343,16 +1317,16 @@ function reorderOps(doc, id, dir) {
1343
1317
  let newOrder;
1344
1318
  if (dir === "up") {
1345
1319
  if (idx <= 0) return [];
1346
- newOrder = keyBetween(sibs[idx - 2]?.order ?? null, sibs[idx - 1].order);
1320
+ newOrder = fancyDocCommons.fractionalKey(sibs[idx - 2]?.order ?? null, sibs[idx - 1].order);
1347
1321
  } else if (dir === "down") {
1348
1322
  if (idx >= last) return [];
1349
- newOrder = keyBetween(sibs[idx + 1].order, sibs[idx + 2]?.order ?? null);
1323
+ newOrder = fancyDocCommons.fractionalKey(sibs[idx + 1].order, sibs[idx + 2]?.order ?? null);
1350
1324
  } else if (dir === "front") {
1351
1325
  if (idx >= last) return [];
1352
- newOrder = keyBetween(sibs[last].order, null);
1326
+ newOrder = fancyDocCommons.fractionalKey(sibs[last].order, null);
1353
1327
  } else {
1354
1328
  if (idx <= 0) return [];
1355
- newOrder = keyBetween(null, sibs[0].order);
1329
+ newOrder = fancyDocCommons.fractionalKey(null, sibs[0].order);
1356
1330
  }
1357
1331
  return [{ t: "move_node", id, parent: node.parent, order: newOrder }];
1358
1332
  }
@@ -1485,9 +1459,9 @@ function EditablePage({
1485
1459
  const addNode = react.useCallback(
1486
1460
  (kind) => {
1487
1461
  const doc2 = ed.state.doc;
1488
- const parent = selNode ? CONTAINER_TYPES.has(selNode.type) ? selNode.id : selNode.parent : doc2.sections[doc2.sections.length - 1] ?? null;
1462
+ const parent = selNode ? CONTAINER_TYPES.has(selNode.type) ? selNode.id : selNode.parent : lastRootId(doc2);
1489
1463
  const siblings = childrenOf(doc2, parent);
1490
- const order = keyBetween(siblings.length ? siblings[siblings.length - 1].order : null, null);
1464
+ const order = fancyDocCommons.fractionalKey(siblings.length ? siblings[siblings.length - 1].order : null, null);
1491
1465
  const id = `n${doc2.seq + 1}-${Math.floor(performance.now())}`;
1492
1466
  const def = ADD_DEFAULTS[kind];
1493
1467
  ed.apply({ t: "insert_node", node: { id, type: def.type, parent, order, layout: def.layout, props: { ...def.props }, style: { base: { ...def.style } } } });
@@ -1499,9 +1473,9 @@ function EditablePage({
1499
1473
  (kind, targetId) => {
1500
1474
  const doc2 = ed.state.doc;
1501
1475
  const target = targetId ? doc2.nodes[targetId] : null;
1502
- const parent = target ? CONTAINER_TYPES.has(target.type) ? target.id : target.parent : doc2.sections[doc2.sections.length - 1] ?? null;
1476
+ const parent = target ? CONTAINER_TYPES.has(target.type) ? target.id : target.parent : lastRootId(doc2);
1503
1477
  const siblings = childrenOf(doc2, parent);
1504
- const order = keyBetween(siblings.length ? siblings[siblings.length - 1].order : null, null);
1478
+ const order = fancyDocCommons.fractionalKey(siblings.length ? siblings[siblings.length - 1].order : null, null);
1505
1479
  const id = `n${doc2.seq + 1}-${Math.floor(performance.now())}`;
1506
1480
  const def = ADD_DEFAULTS[kind];
1507
1481
  ed.apply({ t: "insert_node", node: { id, type: def.type, parent, order, layout: def.layout, props: { ...def.props }, style: { base: { ...def.style } } } });
@@ -1545,15 +1519,15 @@ function EditablePage({
1545
1519
  let parent;
1546
1520
  let order;
1547
1521
  if (!hint.id || hint.edge === "inside") {
1548
- parent = hint.id ?? (doc2.sections[doc2.sections.length - 1] ?? null);
1522
+ parent = hint.id ?? lastRootId(doc2);
1549
1523
  const sib = childrenOf(doc2, parent);
1550
- order = keyBetween(sib.length ? sib[sib.length - 1].order : null, null);
1524
+ order = fancyDocCommons.fractionalKey(sib.length ? sib[sib.length - 1].order : null, null);
1551
1525
  } else {
1552
1526
  const target = doc2.nodes[hint.id];
1553
1527
  parent = target.parent;
1554
1528
  const sib = childrenOf(doc2, parent);
1555
1529
  const idx = sib.findIndex((n) => n.id === hint.id);
1556
- 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);
1530
+ order = hint.edge === "before" ? fancyDocCommons.fractionalKey(idx > 0 ? sib[idx - 1].order : null, target.order) : fancyDocCommons.fractionalKey(target.order, idx < sib.length - 1 ? sib[idx + 1].order : null);
1557
1531
  }
1558
1532
  const id = `n${doc2.seq + 1}-${Math.floor(performance.now())}`;
1559
1533
  const def = ADD_DEFAULTS[kind];