@sofereditor/react 0.1.0 → 0.2.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
@@ -1178,6 +1178,7 @@ function renderInline(delta, keyPrefix) {
1178
1178
  } else if ((0, import_core2.isImageEmbed)(op.insert)) {
1179
1179
  const key = `${keyPrefix}-${offset}`;
1180
1180
  const layout = op.insert.layout ?? "inline";
1181
+ const commentMarkId = op.attributes?.comment?.markId;
1181
1182
  if (layout === "wrap-left" || layout === "wrap-right") {
1182
1183
  wrapAnchors.push(
1183
1184
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ImageEmbedView, { embed: op.insert, offset, wrapAnchor: true }, `${key}-anchor`)
@@ -1195,7 +1196,14 @@ function renderInline(delta, keyPrefix) {
1195
1196
  )
1196
1197
  );
1197
1198
  } else {
1198
- body.push(/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ImageEmbedView, { embed: op.insert, offset }, key));
1199
+ const imgNode = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ImageEmbedView, { embed: op.insert, offset }, key);
1200
+ if (commentMarkId) {
1201
+ body.push(
1202
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "data-comment-id": commentMarkId, className: "ed-comment", children: imgNode }, `${key}-cmt`)
1203
+ );
1204
+ } else {
1205
+ body.push(imgNode);
1206
+ }
1199
1207
  }
1200
1208
  offset += 1;
1201
1209
  } else if (op.insert != null) {
@@ -1286,6 +1294,8 @@ function ImageEmbedViewImpl({
1286
1294
  height: embed.height,
1287
1295
  contentEditable: false,
1288
1296
  draggable: false,
1297
+ decoding: "sync",
1298
+ loading: "eager",
1289
1299
  "data-embed": "image",
1290
1300
  "data-embed-offset": offset,
1291
1301
  "data-embed-align": align ?? "",
@@ -1684,8 +1694,9 @@ var A4_PAGE = {
1684
1694
  marginLeft: 96,
1685
1695
  marginRight: 96
1686
1696
  };
1687
- function contentHeight(g) {
1688
- return g.height - g.marginTop - g.marginBottom;
1697
+ function contentHeight(g, pageIndex = 0) {
1698
+ const extra = pageIndex === 0 ? g.firstPageExtraTop ?? 0 : 0;
1699
+ return g.height - g.marginTop - g.marginBottom - extra;
1689
1700
  }
1690
1701
  function contentWidth(g) {
1691
1702
  return g.width - g.marginLeft - g.marginRight;
@@ -1702,14 +1713,19 @@ function defaultPageLayout(topLevelCount) {
1702
1713
  function usePageLayout(rootRef, geometry, topLevelCount, deps) {
1703
1714
  const [phase, setPhase] = (0, import_react9.useState)("measure");
1704
1715
  const [layout, setLayout] = (0, import_react9.useState)(() => defaultPageLayout(topLevelCount));
1705
- const lastDepsRef = (0, import_react9.useRef)([]);
1706
- const currentDeps = [...deps, topLevelCount, geometry];
1707
- if (!shallowArrayEqual(lastDepsRef.current, currentDeps)) {
1716
+ const lastDepsRef = (0, import_react9.useRef)(null);
1717
+ (0, import_react9.useLayoutEffect)(() => {
1718
+ const currentDeps = [...deps, topLevelCount, geometry];
1719
+ if (lastDepsRef.current !== null && shallowArrayEqual(lastDepsRef.current, currentDeps)) {
1720
+ return;
1721
+ }
1708
1722
  lastDepsRef.current = currentDeps;
1709
- if (phase !== "measure") setPhase("measure");
1710
- const next = defaultPageLayout(topLevelCount);
1711
- if (!layoutsDeepEqual(layout, next)) setLayout(next);
1712
- }
1723
+ setLayout((prev) => {
1724
+ const next = defaultPageLayout(topLevelCount);
1725
+ return layoutsDeepEqual(prev, next) ? prev : next;
1726
+ });
1727
+ setPhase("measure");
1728
+ });
1713
1729
  (0, import_react9.useLayoutEffect)(() => {
1714
1730
  if (phase !== "measure") return;
1715
1731
  const root = rootRef.current;
@@ -1719,19 +1735,20 @@ function usePageLayout(rootRef, geometry, topLevelCount, deps) {
1719
1735
  if (!layoutsDeepEqual(layout, next)) setLayout(next);
1720
1736
  setPhase("stable");
1721
1737
  }, [phase, layout, geometry, topLevelCount, rootRef]);
1722
- return layout;
1738
+ return { layout, phase };
1723
1739
  }
1724
1740
  function isUnfragmented(layout) {
1725
1741
  return layout.pages.length === 1 && layout.pages[0].slots.every(
1726
- (s) => s.fragment === void 0 && s.tableFragment === void 0
1742
+ (s) => s.fragment === void 0 && s.tableFragment === void 0 && s.listFragment === void 0
1727
1743
  );
1728
1744
  }
1729
1745
  function computeLayout(root, geometry, topLevelCount) {
1730
1746
  const tops = collectTopLevelElements(root);
1731
1747
  if (tops.length === 0) return defaultPageLayout(topLevelCount);
1732
- const limit = contentHeight(geometry);
1748
+ const limitFor = (pageIndex) => contentHeight(geometry, pageIndex);
1733
1749
  const pages = [{ slots: [] }];
1734
1750
  let currentPage = pages[0];
1751
+ let limit = limitFor(0);
1735
1752
  let used = 0;
1736
1753
  const cap = Math.min(tops.length, topLevelCount);
1737
1754
  for (let i = 0; i < cap; i++) {
@@ -1743,14 +1760,23 @@ function computeLayout(root, geometry, topLevelCount) {
1743
1760
  continue;
1744
1761
  }
1745
1762
  if (isFragmentable(el)) {
1746
- const result = placeFragmentedBlock(el, i, pages, used, limit);
1763
+ const result = placeFragmentedBlock(el, i, pages, used, limitFor);
1747
1764
  currentPage = pages[pages.length - 1];
1765
+ limit = limitFor(pages.length - 1);
1748
1766
  used = result.lastUsed;
1749
1767
  continue;
1750
1768
  }
1751
1769
  if (isTableTopLevel(el)) {
1752
- const result = placeFragmentedTable(el, i, pages, used, limit);
1770
+ const result = placeFragmentedTable(el, i, pages, used, limitFor);
1753
1771
  currentPage = pages[pages.length - 1];
1772
+ limit = limitFor(pages.length - 1);
1773
+ used = result.lastUsed;
1774
+ continue;
1775
+ }
1776
+ if (isListTopLevel(el)) {
1777
+ const result = placeFragmentedList(el, i, pages, used, limitFor);
1778
+ currentPage = pages[pages.length - 1];
1779
+ limit = limitFor(pages.length - 1);
1754
1780
  used = result.lastUsed;
1755
1781
  continue;
1756
1782
  }
@@ -1758,10 +1784,12 @@ function computeLayout(root, geometry, topLevelCount) {
1758
1784
  currentPage.slots.push({ topLevelIndex: i });
1759
1785
  pages.push({ slots: [] });
1760
1786
  currentPage = pages[pages.length - 1];
1787
+ limit = limitFor(pages.length - 1);
1761
1788
  used = 0;
1762
1789
  } else {
1763
1790
  pages.push({ slots: [] });
1764
1791
  currentPage = pages[pages.length - 1];
1792
+ limit = limitFor(pages.length - 1);
1765
1793
  currentPage.slots.push({ topLevelIndex: i });
1766
1794
  used = h;
1767
1795
  }
@@ -1769,7 +1797,8 @@ function computeLayout(root, geometry, topLevelCount) {
1769
1797
  if (pages.length > 1 && pages[pages.length - 1].slots.length === 0) pages.pop();
1770
1798
  return { pages };
1771
1799
  }
1772
- function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1800
+ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limitFor) {
1801
+ let limit = limitFor(pages.length - 1);
1773
1802
  const totalChars = getBlockTextLength(el);
1774
1803
  if (totalChars === 0) {
1775
1804
  const h = elTotalHeight(el);
@@ -1777,6 +1806,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1777
1806
  if (startUsed + h > limit && currentPage2.slots.length > 0) {
1778
1807
  pages.push({ slots: [] });
1779
1808
  currentPage2 = pages[pages.length - 1];
1809
+ limit = limitFor(pages.length - 1);
1780
1810
  startUsed = 0;
1781
1811
  }
1782
1812
  currentPage2.slots.push({ topLevelIndex });
@@ -1789,6 +1819,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1789
1819
  if (startUsed + h > limit && currentPage2.slots.length > 0) {
1790
1820
  pages.push({ slots: [] });
1791
1821
  currentPage2 = pages[pages.length - 1];
1822
+ limit = limitFor(pages.length - 1);
1792
1823
  startUsed = 0;
1793
1824
  }
1794
1825
  currentPage2.slots.push({ topLevelIndex });
@@ -1803,6 +1834,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1803
1834
  if (available <= 0) {
1804
1835
  pages.push({ slots: [] });
1805
1836
  currentPage = pages[pages.length - 1];
1837
+ limit = limitFor(pages.length - 1);
1806
1838
  used = 0;
1807
1839
  continue;
1808
1840
  }
@@ -1819,6 +1851,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1819
1851
  } else {
1820
1852
  pages.push({ slots: [] });
1821
1853
  currentPage = pages[pages.length - 1];
1854
+ limit = limitFor(pages.length - 1);
1822
1855
  used = 0;
1823
1856
  continue;
1824
1857
  }
@@ -1836,6 +1869,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
1836
1869
  if (lineIdx < lines.length) {
1837
1870
  pages.push({ slots: [] });
1838
1871
  currentPage = pages[pages.length - 1];
1872
+ limit = limitFor(pages.length - 1);
1839
1873
  used = 0;
1840
1874
  }
1841
1875
  }
@@ -1924,7 +1958,8 @@ function isFragmentable(el) {
1924
1958
  function isTableTopLevel(el) {
1925
1959
  return el.querySelector(':scope > table[data-block-type="table"]') !== null;
1926
1960
  }
1927
- function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
1961
+ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limitFor) {
1962
+ let limit = limitFor(pages.length - 1);
1928
1963
  const table = el.querySelector(':scope > table[data-block-type="table"]');
1929
1964
  const tbody = table?.querySelector(":scope > tbody");
1930
1965
  const trs = tbody ? Array.from(tbody.children) : [];
@@ -1934,6 +1969,7 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
1934
1969
  if (startUsed + h > limit && currentPage2.slots.length > 0) {
1935
1970
  pages.push({ slots: [] });
1936
1971
  currentPage2 = pages[pages.length - 1];
1972
+ limit = limitFor(pages.length - 1);
1937
1973
  startUsed = 0;
1938
1974
  }
1939
1975
  currentPage2.slots.push({ topLevelIndex });
@@ -1965,6 +2001,7 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
1965
2001
  if (available <= 0) {
1966
2002
  pages.push({ slots: [] });
1967
2003
  currentPage = pages[pages.length - 1];
2004
+ limit = limitFor(pages.length - 1);
1968
2005
  used = 0;
1969
2006
  continue;
1970
2007
  }
@@ -1983,6 +2020,7 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
1983
2020
  } else {
1984
2021
  pages.push({ slots: [] });
1985
2022
  currentPage = pages[pages.length - 1];
2023
+ limit = limitFor(pages.length - 1);
1986
2024
  used = 0;
1987
2025
  continue;
1988
2026
  }
@@ -2000,6 +2038,77 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
2000
2038
  if (rowIdx < trs.length) {
2001
2039
  pages.push({ slots: [] });
2002
2040
  currentPage = pages[pages.length - 1];
2041
+ limit = limitFor(pages.length - 1);
2042
+ used = 0;
2043
+ }
2044
+ }
2045
+ return { lastUsed: used };
2046
+ }
2047
+ function isListTopLevel(el) {
2048
+ if (el.tagName !== "OL" && el.tagName !== "UL") return false;
2049
+ return el.classList.contains("ed-list");
2050
+ }
2051
+ function placeFragmentedList(el, topLevelIndex, pages, startUsed, limitFor) {
2052
+ let limit = limitFor(pages.length - 1);
2053
+ const items = [];
2054
+ for (const c of Array.from(el.children)) {
2055
+ if (c instanceof HTMLLIElement && c.classList.contains("ed-listitem")) {
2056
+ items.push(c);
2057
+ }
2058
+ }
2059
+ if (items.length === 0) {
2060
+ const h = elTotalHeight(el);
2061
+ let currentPage2 = pages[pages.length - 1];
2062
+ if (startUsed + h > limit && currentPage2.slots.length > 0) {
2063
+ pages.push({ slots: [] });
2064
+ currentPage2 = pages[pages.length - 1];
2065
+ limit = limitFor(pages.length - 1);
2066
+ startUsed = 0;
2067
+ }
2068
+ currentPage2.slots.push({ topLevelIndex });
2069
+ return { lastUsed: startUsed + h };
2070
+ }
2071
+ const heights = items.map((li) => elTotalHeight(li));
2072
+ const sumHeights = heights.reduce((a, b) => a + b, 0);
2073
+ const wrapperOverhead = Math.max(0, elTotalHeight(el) - sumHeights);
2074
+ let i = 0;
2075
+ let currentPage = pages[pages.length - 1];
2076
+ let used = startUsed;
2077
+ let fragIndex = 0;
2078
+ while (i < items.length) {
2079
+ const available = Math.max(0, limit - used);
2080
+ const isFirstFragment = fragIndex === 0;
2081
+ let bestK = -1;
2082
+ let runningH = isFirstFragment ? wrapperOverhead : 0;
2083
+ for (let k = i; k < items.length; k++) {
2084
+ runningH += heights[k];
2085
+ if (runningH <= available) bestK = k;
2086
+ else break;
2087
+ }
2088
+ if (bestK < 0) {
2089
+ if (currentPage.slots.length === 0) {
2090
+ bestK = i;
2091
+ } else {
2092
+ pages.push({ slots: [] });
2093
+ currentPage = pages[pages.length - 1];
2094
+ limit = limitFor(pages.length - 1);
2095
+ used = 0;
2096
+ continue;
2097
+ }
2098
+ }
2099
+ currentPage.slots.push({
2100
+ topLevelIndex,
2101
+ listFragment: { index: fragIndex, itemStart: i, itemEnd: bestK + 1 }
2102
+ });
2103
+ let consumed = isFirstFragment ? wrapperOverhead : 0;
2104
+ for (let k = i; k <= bestK; k++) consumed += heights[k];
2105
+ used += consumed;
2106
+ i = bestK + 1;
2107
+ fragIndex++;
2108
+ if (i < items.length) {
2109
+ pages.push({ slots: [] });
2110
+ currentPage = pages[pages.length - 1];
2111
+ limit = limitFor(pages.length - 1);
2003
2112
  used = 0;
2004
2113
  }
2005
2114
  }
@@ -2075,6 +2184,14 @@ function layoutsDeepEqual(a, b) {
2075
2184
  return false;
2076
2185
  }
2077
2186
  }
2187
+ const lA = sA[j].listFragment;
2188
+ const lB = sB[j].listFragment;
2189
+ if (lA || lB) {
2190
+ if (!lA || !lB) return false;
2191
+ if (lA.index !== lB.index || lA.itemStart !== lB.itemStart || lA.itemEnd !== lB.itemEnd) {
2192
+ return false;
2193
+ }
2194
+ }
2078
2195
  }
2079
2196
  }
2080
2197
  return true;
@@ -2101,7 +2218,7 @@ function usePageSettings(doc) {
2101
2218
  return (0, import_react10.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
2102
2219
  }
2103
2220
  function shallowEqual(a, b) {
2104
- return a.width === b.width && a.height === b.height && a.marginTop === b.marginTop && a.marginBottom === b.marginBottom && a.marginLeft === b.marginLeft && a.marginRight === b.marginRight && a.preset === b.preset;
2221
+ return a.width === b.width && a.height === b.height && a.marginTop === b.marginTop && a.marginBottom === b.marginBottom && a.marginLeft === b.marginLeft && a.marginRight === b.marginRight && a.preset === b.preset && a.systemHeaderTitle === b.systemHeaderTitle && a.systemHeaderAuthor === b.systemHeaderAuthor;
2105
2222
  }
2106
2223
 
2107
2224
  // src/useEditor.ts
@@ -2791,8 +2908,33 @@ function Editor({
2791
2908
  }
2792
2909
  return;
2793
2910
  }
2794
- case "insertParagraph":
2795
2911
  case "insertLineBreak": {
2912
+ e.preventDefault();
2913
+ if (ed.getBlockType() === "listItem") {
2914
+ (0, import_core5.insertText)(ctx, "\n", ed.consumePendingMarks());
2915
+ return;
2916
+ }
2917
+ const selEmbed = ed.getSelectedEmbed();
2918
+ if (selEmbed) {
2919
+ const off = selEmbed.offset + 1;
2920
+ ctx.setSelection({
2921
+ anchor: {
2922
+ blockIndex: selEmbed.blockIndex,
2923
+ cellIndex: selEmbed.cellIndex,
2924
+ offset: off
2925
+ },
2926
+ focus: {
2927
+ blockIndex: selEmbed.blockIndex,
2928
+ cellIndex: selEmbed.cellIndex,
2929
+ offset: off
2930
+ }
2931
+ });
2932
+ }
2933
+ if (ed.splitListItem()) return;
2934
+ (0, import_core5.insertParagraph)(ctx);
2935
+ return;
2936
+ }
2937
+ case "insertParagraph": {
2796
2938
  e.preventDefault();
2797
2939
  const selectedEmbed2 = ed.getSelectedEmbed();
2798
2940
  if (selectedEmbed2) {
@@ -2891,6 +3033,20 @@ function Editor({
2891
3033
  else ed.indentList();
2892
3034
  return;
2893
3035
  }
3036
+ if (!mod && (e.key === "Home" || e.key === "End")) {
3037
+ const root = rootRef.current;
3038
+ const sel = window.getSelection();
3039
+ const sm = sel?.modify;
3040
+ if (root && sel && sel.rangeCount > 0 && typeof sm === "function") {
3041
+ e.preventDefault();
3042
+ const alter = e.shiftKey ? "extend" : "move";
3043
+ const direction = e.key === "Home" ? "left" : "right";
3044
+ sm.call(sel, alter, direction, "lineboundary");
3045
+ const modelSel = readDomSelection(root);
3046
+ if (modelSel) ctxRef.current.setSelection(modelSel);
3047
+ }
3048
+ return;
3049
+ }
2894
3050
  if (!mod) return;
2895
3051
  const key = e.key.toLowerCase();
2896
3052
  if (!e.shiftKey && !e.altKey && key === "z") {
@@ -2947,26 +3103,47 @@ function Editor({
2947
3103
  }
2948
3104
  }, []);
2949
3105
  const topLevels = (0, import_react12.useMemo)(() => groupTopLevels(snapshot.blocks), [snapshot]);
3106
+ const topLevelsStructuralKey = (0, import_react12.useMemo)(
3107
+ () => topLevels.map(
3108
+ (t) => t.kind === "list" ? `L:${t.listKind}:${t.items.length}:${t.ordinalStart}` : `B:${t.block.type}:${t.block.attrs.level ?? ""}`
3109
+ ).join("|"),
3110
+ [topLevels]
3111
+ );
2950
3112
  const docSettings = usePageSettings(editor.doc);
2951
3113
  const propIsSet = pageGeometry !== void 0;
2952
3114
  const geom = propIsSet ? pageGeometry ?? A4_PAGE : docSettings;
2953
3115
  const paginated = pageGeometry !== null;
2954
3116
  const selectedEmbed = editor.getSelectedEmbed();
2955
- const layout = usePageLayout(
3117
+ const { layout, phase: paginationPhase } = usePageLayout(
2956
3118
  rootRef,
2957
3119
  geom,
2958
3120
  topLevels.length,
2959
- [topLevels, pageGeometry]
3121
+ // Usar a chave estrutural (string) em vez do array `topLevels` direto:
3122
+ // o array reference muda a cada keystroke, mas a chave só muda quando
3123
+ // a SHAPE dos top-levels muda. `usePageLayout` compara deps via
3124
+ // `shallowArrayEqual` — string equality cobre isso.
3125
+ [topLevelsStructuralKey, pageGeometry]
2960
3126
  );
2961
3127
  const effectiveLayout = paginated ? layout : defaultPageLayout(topLevels.length);
2962
- const pageStyle = paginated ? {
2963
- "--ed-page-width": `${geom.width}px`,
2964
- "--ed-page-height": `${geom.height}px`,
2965
- "--ed-page-margin-top": `${geom.marginTop}px`,
2966
- "--ed-page-margin-bottom": `${geom.marginBottom}px`,
2967
- "--ed-page-margin-left": `${geom.marginLeft}px`,
2968
- "--ed-page-margin-right": `${geom.marginRight}px`
2969
- } : void 0;
3128
+ const pageStyle = (0, import_react12.useMemo)(
3129
+ () => paginated ? {
3130
+ "--ed-page-width": `${geom.width}px`,
3131
+ "--ed-page-height": `${geom.height}px`,
3132
+ "--ed-page-margin-top": `${geom.marginTop}px`,
3133
+ "--ed-page-margin-bottom": `${geom.marginBottom}px`,
3134
+ "--ed-page-margin-left": `${geom.marginLeft}px`,
3135
+ "--ed-page-margin-right": `${geom.marginRight}px`
3136
+ } : void 0,
3137
+ [
3138
+ paginated,
3139
+ geom.width,
3140
+ geom.height,
3141
+ geom.marginTop,
3142
+ geom.marginBottom,
3143
+ geom.marginLeft,
3144
+ geom.marginRight
3145
+ ]
3146
+ );
2970
3147
  const body = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2971
3148
  "div",
2972
3149
  {
@@ -2979,6 +3156,7 @@ function Editor({
2979
3156
  role: "textbox",
2980
3157
  "aria-multiline": "true",
2981
3158
  className: (className ?? "ed-root") + (paginated ? " ed-root--paged" : " ed-root--flat"),
3159
+ "data-pagination-phase": paginated ? paginationPhase : void 0,
2982
3160
  style: pageStyle,
2983
3161
  onKeyDown,
2984
3162
  onCompositionStart,
@@ -2989,12 +3167,16 @@ function Editor({
2989
3167
  pageNumber: pi + 1,
2990
3168
  pageCount: effectiveLayout.pages.length
2991
3169
  };
3170
+ const pageInlineStyle = pi === 0 && geom.firstPageExtraTop ? {
3171
+ "--ed-page-margin-top": `${geom.marginTop + geom.firstPageExtraTop}px`
3172
+ } : void 0;
2992
3173
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2993
3174
  "div",
2994
3175
  {
2995
3176
  className: "ed-page",
2996
3177
  "data-page-number": ctx.pageNumber,
2997
3178
  "data-page-total": ctx.pageCount,
3179
+ style: pageInlineStyle,
2998
3180
  children: [
2999
3181
  renderPageHeader && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ed-page-header", contentEditable: false, children: renderPageHeader(ctx) }),
3000
3182
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ed-page-content", children: page.slots.map((slot) => renderSlot(slot, topLevels)) }),
@@ -3040,11 +3222,29 @@ function groupTopLevels(snapshot) {
3040
3222
  const groupStart = i;
3041
3223
  const items = [];
3042
3224
  const kind = block.attrs.listKind === "ordered" ? "ordered" : "bullet";
3043
- while (i < snapshot.length && snapshot[i].type === "listItem" && (snapshot[i].attrs.listKind ?? "bullet") === kind) {
3044
- items.push({ block: snapshot[i], index: i });
3225
+ const groupStyle = block.attrs.listStyle;
3226
+ while (i < snapshot.length) {
3227
+ const b = snapshot[i];
3228
+ if (b.type !== "listItem") break;
3229
+ if ((b.attrs.listKind ?? "bullet") !== kind) break;
3230
+ if (i > groupStart) {
3231
+ if (typeof b.attrs.listStart === "number") break;
3232
+ const itemStyle = b.attrs.listStyle;
3233
+ if (itemStyle !== void 0 && itemStyle !== groupStyle) break;
3234
+ }
3235
+ items.push({ block: b, index: i });
3045
3236
  i++;
3046
3237
  }
3047
- out.push({ kind: "list", items, listKind: kind, key: groupStart });
3238
+ const firstAttrs = items[0].block.attrs;
3239
+ const ordinalStart = typeof firstAttrs.listStart === "number" && firstAttrs.listStart > 0 ? firstAttrs.listStart : 1;
3240
+ out.push({
3241
+ kind: "list",
3242
+ items,
3243
+ listKind: kind,
3244
+ ordinalStart,
3245
+ listStyle: groupStyle,
3246
+ key: groupStart
3247
+ });
3048
3248
  continue;
3049
3249
  }
3050
3250
  out.push({ kind: "block", block, blockIndex: i, key: i });
@@ -3082,15 +3282,43 @@ function renderSlot(slot, topLevels) {
3082
3282
  `${top.key}-tf${slot.tableFragment.index}`
3083
3283
  );
3084
3284
  }
3285
+ if (slot.listFragment && top.kind === "list") {
3286
+ return renderListFragment(top, slot.listFragment);
3287
+ }
3085
3288
  return renderTopLevel(top);
3086
3289
  }
3087
3290
  function renderTopLevel(top) {
3088
3291
  if (top.kind === "list") {
3089
3292
  const tree = buildListTree(top.items);
3090
- return renderListTree(tree, top.listKind, `list-${top.key}`);
3293
+ return renderListTree(tree, top, top.ordinalStart, `list-${top.key}`);
3091
3294
  }
3092
3295
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NodeView, { block: top.block, index: top.blockIndex }, top.key);
3093
3296
  }
3297
+ function renderListFragment(top, frag) {
3298
+ const ranges = topLevelItemRanges(top.items);
3299
+ const startRange = ranges[frag.itemStart];
3300
+ const endRange = ranges[frag.itemEnd - 1];
3301
+ if (!startRange || !endRange) return renderTopLevel(top);
3302
+ const sliced = top.items.slice(startRange[0], endRange[1]);
3303
+ const ordinalStart = top.ordinalStart + frag.itemStart;
3304
+ const key = `list-${top.key}-f${frag.index}`;
3305
+ const slicedTop = { ...top, items: sliced };
3306
+ const tree = buildListTree(sliced);
3307
+ return renderListTree(tree, slicedTop, ordinalStart, key);
3308
+ }
3309
+ function topLevelItemRanges(items) {
3310
+ const out = [];
3311
+ let currentStart = -1;
3312
+ items.forEach((it, idx) => {
3313
+ const level = clampListLevel2(it.block.attrs.listLevel);
3314
+ if (level === 0) {
3315
+ if (currentStart >= 0) out.push([currentStart, idx]);
3316
+ currentStart = idx;
3317
+ }
3318
+ });
3319
+ if (currentStart >= 0) out.push([currentStart, items.length]);
3320
+ return out;
3321
+ }
3094
3322
  function buildListTree(items) {
3095
3323
  const roots = [];
3096
3324
  const stack = [{ children: roots, level: -1 }];
@@ -3103,9 +3331,28 @@ function buildListTree(items) {
3103
3331
  }
3104
3332
  return roots;
3105
3333
  }
3106
- function renderListTree(tree, kind, key) {
3334
+ function renderListTree(tree, top, start, key) {
3335
+ const className = `ed-list ed-list-${top.listKind}`;
3336
+ const style = top.listStyle ? { listStyleType: top.listStyle } : void 0;
3337
+ const items = tree.map((node) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children, top.listKind, `nested-${node.entry.index}`) : null }, node.entry.index));
3338
+ if (top.listKind === "ordered") {
3339
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3340
+ "ol",
3341
+ {
3342
+ className,
3343
+ "data-list-kind": "ordered",
3344
+ start: start > 1 ? start : void 0,
3345
+ style,
3346
+ children: items
3347
+ },
3348
+ key
3349
+ );
3350
+ }
3351
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { className, "data-list-kind": "bullet", style, children: items }, key);
3352
+ }
3353
+ function renderNestedListTree(tree, kind, key) {
3107
3354
  const Tag = kind === "ordered" ? "ol" : "ul";
3108
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Tag, { className: `ed-list ed-list-${kind}`, "data-list-kind": kind, children: tree.map((node) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderListTree(node.children, kind, `nested-${node.entry.index}`) : null }, node.entry.index)) }, key);
3355
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Tag, { className: `ed-list ed-list-${kind}`, "data-list-kind": kind, children: tree.map((node) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children, kind, `nested-${node.entry.index}`) : null }, node.entry.index)) }, key);
3109
3356
  }
3110
3357
  function clampListLevel2(l) {
3111
3358
  if (typeof l !== "number" || !Number.isFinite(l)) return 0;