@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 +282 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -3
- package/dist/index.d.ts +32 -3
- package/dist/index.js +282 -35
- package/dist/index.js.map +1 -1
- package/package.json +28 -16
package/dist/index.js
CHANGED
|
@@ -1153,6 +1153,7 @@ function renderInline(delta, keyPrefix) {
|
|
|
1153
1153
|
} else if (isImageEmbed(op.insert)) {
|
|
1154
1154
|
const key = `${keyPrefix}-${offset}`;
|
|
1155
1155
|
const layout = op.insert.layout ?? "inline";
|
|
1156
|
+
const commentMarkId = op.attributes?.comment?.markId;
|
|
1156
1157
|
if (layout === "wrap-left" || layout === "wrap-right") {
|
|
1157
1158
|
wrapAnchors.push(
|
|
1158
1159
|
/* @__PURE__ */ jsx6(ImageEmbedView, { embed: op.insert, offset, wrapAnchor: true }, `${key}-anchor`)
|
|
@@ -1170,7 +1171,14 @@ function renderInline(delta, keyPrefix) {
|
|
|
1170
1171
|
)
|
|
1171
1172
|
);
|
|
1172
1173
|
} else {
|
|
1173
|
-
|
|
1174
|
+
const imgNode = /* @__PURE__ */ jsx6(ImageEmbedView, { embed: op.insert, offset }, key);
|
|
1175
|
+
if (commentMarkId) {
|
|
1176
|
+
body.push(
|
|
1177
|
+
/* @__PURE__ */ jsx6("span", { "data-comment-id": commentMarkId, className: "ed-comment", children: imgNode }, `${key}-cmt`)
|
|
1178
|
+
);
|
|
1179
|
+
} else {
|
|
1180
|
+
body.push(imgNode);
|
|
1181
|
+
}
|
|
1174
1182
|
}
|
|
1175
1183
|
offset += 1;
|
|
1176
1184
|
} else if (op.insert != null) {
|
|
@@ -1261,6 +1269,8 @@ function ImageEmbedViewImpl({
|
|
|
1261
1269
|
height: embed.height,
|
|
1262
1270
|
contentEditable: false,
|
|
1263
1271
|
draggable: false,
|
|
1272
|
+
decoding: "sync",
|
|
1273
|
+
loading: "eager",
|
|
1264
1274
|
"data-embed": "image",
|
|
1265
1275
|
"data-embed-offset": offset,
|
|
1266
1276
|
"data-embed-align": align ?? "",
|
|
@@ -1665,8 +1675,9 @@ var A4_PAGE = {
|
|
|
1665
1675
|
marginLeft: 96,
|
|
1666
1676
|
marginRight: 96
|
|
1667
1677
|
};
|
|
1668
|
-
function contentHeight(g) {
|
|
1669
|
-
|
|
1678
|
+
function contentHeight(g, pageIndex = 0) {
|
|
1679
|
+
const extra = pageIndex === 0 ? g.firstPageExtraTop ?? 0 : 0;
|
|
1680
|
+
return g.height - g.marginTop - g.marginBottom - extra;
|
|
1670
1681
|
}
|
|
1671
1682
|
function contentWidth(g) {
|
|
1672
1683
|
return g.width - g.marginLeft - g.marginRight;
|
|
@@ -1683,14 +1694,19 @@ function defaultPageLayout(topLevelCount) {
|
|
|
1683
1694
|
function usePageLayout(rootRef, geometry, topLevelCount, deps) {
|
|
1684
1695
|
const [phase, setPhase] = useState6("measure");
|
|
1685
1696
|
const [layout, setLayout] = useState6(() => defaultPageLayout(topLevelCount));
|
|
1686
|
-
const lastDepsRef = useRef7(
|
|
1687
|
-
|
|
1688
|
-
|
|
1697
|
+
const lastDepsRef = useRef7(null);
|
|
1698
|
+
useLayoutEffect3(() => {
|
|
1699
|
+
const currentDeps = [...deps, topLevelCount, geometry];
|
|
1700
|
+
if (lastDepsRef.current !== null && shallowArrayEqual(lastDepsRef.current, currentDeps)) {
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1689
1703
|
lastDepsRef.current = currentDeps;
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1704
|
+
setLayout((prev) => {
|
|
1705
|
+
const next = defaultPageLayout(topLevelCount);
|
|
1706
|
+
return layoutsDeepEqual(prev, next) ? prev : next;
|
|
1707
|
+
});
|
|
1708
|
+
setPhase("measure");
|
|
1709
|
+
});
|
|
1694
1710
|
useLayoutEffect3(() => {
|
|
1695
1711
|
if (phase !== "measure") return;
|
|
1696
1712
|
const root = rootRef.current;
|
|
@@ -1700,19 +1716,20 @@ function usePageLayout(rootRef, geometry, topLevelCount, deps) {
|
|
|
1700
1716
|
if (!layoutsDeepEqual(layout, next)) setLayout(next);
|
|
1701
1717
|
setPhase("stable");
|
|
1702
1718
|
}, [phase, layout, geometry, topLevelCount, rootRef]);
|
|
1703
|
-
return layout;
|
|
1719
|
+
return { layout, phase };
|
|
1704
1720
|
}
|
|
1705
1721
|
function isUnfragmented(layout) {
|
|
1706
1722
|
return layout.pages.length === 1 && layout.pages[0].slots.every(
|
|
1707
|
-
(s) => s.fragment === void 0 && s.tableFragment === void 0
|
|
1723
|
+
(s) => s.fragment === void 0 && s.tableFragment === void 0 && s.listFragment === void 0
|
|
1708
1724
|
);
|
|
1709
1725
|
}
|
|
1710
1726
|
function computeLayout(root, geometry, topLevelCount) {
|
|
1711
1727
|
const tops = collectTopLevelElements(root);
|
|
1712
1728
|
if (tops.length === 0) return defaultPageLayout(topLevelCount);
|
|
1713
|
-
const
|
|
1729
|
+
const limitFor = (pageIndex) => contentHeight(geometry, pageIndex);
|
|
1714
1730
|
const pages = [{ slots: [] }];
|
|
1715
1731
|
let currentPage = pages[0];
|
|
1732
|
+
let limit = limitFor(0);
|
|
1716
1733
|
let used = 0;
|
|
1717
1734
|
const cap = Math.min(tops.length, topLevelCount);
|
|
1718
1735
|
for (let i = 0; i < cap; i++) {
|
|
@@ -1724,14 +1741,23 @@ function computeLayout(root, geometry, topLevelCount) {
|
|
|
1724
1741
|
continue;
|
|
1725
1742
|
}
|
|
1726
1743
|
if (isFragmentable(el)) {
|
|
1727
|
-
const result = placeFragmentedBlock(el, i, pages, used,
|
|
1744
|
+
const result = placeFragmentedBlock(el, i, pages, used, limitFor);
|
|
1728
1745
|
currentPage = pages[pages.length - 1];
|
|
1746
|
+
limit = limitFor(pages.length - 1);
|
|
1729
1747
|
used = result.lastUsed;
|
|
1730
1748
|
continue;
|
|
1731
1749
|
}
|
|
1732
1750
|
if (isTableTopLevel(el)) {
|
|
1733
|
-
const result = placeFragmentedTable(el, i, pages, used,
|
|
1751
|
+
const result = placeFragmentedTable(el, i, pages, used, limitFor);
|
|
1734
1752
|
currentPage = pages[pages.length - 1];
|
|
1753
|
+
limit = limitFor(pages.length - 1);
|
|
1754
|
+
used = result.lastUsed;
|
|
1755
|
+
continue;
|
|
1756
|
+
}
|
|
1757
|
+
if (isListTopLevel(el)) {
|
|
1758
|
+
const result = placeFragmentedList(el, i, pages, used, limitFor);
|
|
1759
|
+
currentPage = pages[pages.length - 1];
|
|
1760
|
+
limit = limitFor(pages.length - 1);
|
|
1735
1761
|
used = result.lastUsed;
|
|
1736
1762
|
continue;
|
|
1737
1763
|
}
|
|
@@ -1739,10 +1765,12 @@ function computeLayout(root, geometry, topLevelCount) {
|
|
|
1739
1765
|
currentPage.slots.push({ topLevelIndex: i });
|
|
1740
1766
|
pages.push({ slots: [] });
|
|
1741
1767
|
currentPage = pages[pages.length - 1];
|
|
1768
|
+
limit = limitFor(pages.length - 1);
|
|
1742
1769
|
used = 0;
|
|
1743
1770
|
} else {
|
|
1744
1771
|
pages.push({ slots: [] });
|
|
1745
1772
|
currentPage = pages[pages.length - 1];
|
|
1773
|
+
limit = limitFor(pages.length - 1);
|
|
1746
1774
|
currentPage.slots.push({ topLevelIndex: i });
|
|
1747
1775
|
used = h;
|
|
1748
1776
|
}
|
|
@@ -1750,7 +1778,8 @@ function computeLayout(root, geometry, topLevelCount) {
|
|
|
1750
1778
|
if (pages.length > 1 && pages[pages.length - 1].slots.length === 0) pages.pop();
|
|
1751
1779
|
return { pages };
|
|
1752
1780
|
}
|
|
1753
|
-
function placeFragmentedBlock(el, topLevelIndex, pages, startUsed,
|
|
1781
|
+
function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limitFor) {
|
|
1782
|
+
let limit = limitFor(pages.length - 1);
|
|
1754
1783
|
const totalChars = getBlockTextLength(el);
|
|
1755
1784
|
if (totalChars === 0) {
|
|
1756
1785
|
const h = elTotalHeight(el);
|
|
@@ -1758,6 +1787,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
|
|
|
1758
1787
|
if (startUsed + h > limit && currentPage2.slots.length > 0) {
|
|
1759
1788
|
pages.push({ slots: [] });
|
|
1760
1789
|
currentPage2 = pages[pages.length - 1];
|
|
1790
|
+
limit = limitFor(pages.length - 1);
|
|
1761
1791
|
startUsed = 0;
|
|
1762
1792
|
}
|
|
1763
1793
|
currentPage2.slots.push({ topLevelIndex });
|
|
@@ -1770,6 +1800,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
|
|
|
1770
1800
|
if (startUsed + h > limit && currentPage2.slots.length > 0) {
|
|
1771
1801
|
pages.push({ slots: [] });
|
|
1772
1802
|
currentPage2 = pages[pages.length - 1];
|
|
1803
|
+
limit = limitFor(pages.length - 1);
|
|
1773
1804
|
startUsed = 0;
|
|
1774
1805
|
}
|
|
1775
1806
|
currentPage2.slots.push({ topLevelIndex });
|
|
@@ -1784,6 +1815,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
|
|
|
1784
1815
|
if (available <= 0) {
|
|
1785
1816
|
pages.push({ slots: [] });
|
|
1786
1817
|
currentPage = pages[pages.length - 1];
|
|
1818
|
+
limit = limitFor(pages.length - 1);
|
|
1787
1819
|
used = 0;
|
|
1788
1820
|
continue;
|
|
1789
1821
|
}
|
|
@@ -1800,6 +1832,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
|
|
|
1800
1832
|
} else {
|
|
1801
1833
|
pages.push({ slots: [] });
|
|
1802
1834
|
currentPage = pages[pages.length - 1];
|
|
1835
|
+
limit = limitFor(pages.length - 1);
|
|
1803
1836
|
used = 0;
|
|
1804
1837
|
continue;
|
|
1805
1838
|
}
|
|
@@ -1817,6 +1850,7 @@ function placeFragmentedBlock(el, topLevelIndex, pages, startUsed, limit) {
|
|
|
1817
1850
|
if (lineIdx < lines.length) {
|
|
1818
1851
|
pages.push({ slots: [] });
|
|
1819
1852
|
currentPage = pages[pages.length - 1];
|
|
1853
|
+
limit = limitFor(pages.length - 1);
|
|
1820
1854
|
used = 0;
|
|
1821
1855
|
}
|
|
1822
1856
|
}
|
|
@@ -1905,7 +1939,8 @@ function isFragmentable(el) {
|
|
|
1905
1939
|
function isTableTopLevel(el) {
|
|
1906
1940
|
return el.querySelector(':scope > table[data-block-type="table"]') !== null;
|
|
1907
1941
|
}
|
|
1908
|
-
function placeFragmentedTable(el, topLevelIndex, pages, startUsed,
|
|
1942
|
+
function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limitFor) {
|
|
1943
|
+
let limit = limitFor(pages.length - 1);
|
|
1909
1944
|
const table = el.querySelector(':scope > table[data-block-type="table"]');
|
|
1910
1945
|
const tbody = table?.querySelector(":scope > tbody");
|
|
1911
1946
|
const trs = tbody ? Array.from(tbody.children) : [];
|
|
@@ -1915,6 +1950,7 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
|
|
|
1915
1950
|
if (startUsed + h > limit && currentPage2.slots.length > 0) {
|
|
1916
1951
|
pages.push({ slots: [] });
|
|
1917
1952
|
currentPage2 = pages[pages.length - 1];
|
|
1953
|
+
limit = limitFor(pages.length - 1);
|
|
1918
1954
|
startUsed = 0;
|
|
1919
1955
|
}
|
|
1920
1956
|
currentPage2.slots.push({ topLevelIndex });
|
|
@@ -1946,6 +1982,7 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
|
|
|
1946
1982
|
if (available <= 0) {
|
|
1947
1983
|
pages.push({ slots: [] });
|
|
1948
1984
|
currentPage = pages[pages.length - 1];
|
|
1985
|
+
limit = limitFor(pages.length - 1);
|
|
1949
1986
|
used = 0;
|
|
1950
1987
|
continue;
|
|
1951
1988
|
}
|
|
@@ -1964,6 +2001,7 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
|
|
|
1964
2001
|
} else {
|
|
1965
2002
|
pages.push({ slots: [] });
|
|
1966
2003
|
currentPage = pages[pages.length - 1];
|
|
2004
|
+
limit = limitFor(pages.length - 1);
|
|
1967
2005
|
used = 0;
|
|
1968
2006
|
continue;
|
|
1969
2007
|
}
|
|
@@ -1981,6 +2019,77 @@ function placeFragmentedTable(el, topLevelIndex, pages, startUsed, limit) {
|
|
|
1981
2019
|
if (rowIdx < trs.length) {
|
|
1982
2020
|
pages.push({ slots: [] });
|
|
1983
2021
|
currentPage = pages[pages.length - 1];
|
|
2022
|
+
limit = limitFor(pages.length - 1);
|
|
2023
|
+
used = 0;
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
return { lastUsed: used };
|
|
2027
|
+
}
|
|
2028
|
+
function isListTopLevel(el) {
|
|
2029
|
+
if (el.tagName !== "OL" && el.tagName !== "UL") return false;
|
|
2030
|
+
return el.classList.contains("ed-list");
|
|
2031
|
+
}
|
|
2032
|
+
function placeFragmentedList(el, topLevelIndex, pages, startUsed, limitFor) {
|
|
2033
|
+
let limit = limitFor(pages.length - 1);
|
|
2034
|
+
const items = [];
|
|
2035
|
+
for (const c of Array.from(el.children)) {
|
|
2036
|
+
if (c instanceof HTMLLIElement && c.classList.contains("ed-listitem")) {
|
|
2037
|
+
items.push(c);
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
if (items.length === 0) {
|
|
2041
|
+
const h = elTotalHeight(el);
|
|
2042
|
+
let currentPage2 = pages[pages.length - 1];
|
|
2043
|
+
if (startUsed + h > limit && currentPage2.slots.length > 0) {
|
|
2044
|
+
pages.push({ slots: [] });
|
|
2045
|
+
currentPage2 = pages[pages.length - 1];
|
|
2046
|
+
limit = limitFor(pages.length - 1);
|
|
2047
|
+
startUsed = 0;
|
|
2048
|
+
}
|
|
2049
|
+
currentPage2.slots.push({ topLevelIndex });
|
|
2050
|
+
return { lastUsed: startUsed + h };
|
|
2051
|
+
}
|
|
2052
|
+
const heights = items.map((li) => elTotalHeight(li));
|
|
2053
|
+
const sumHeights = heights.reduce((a, b) => a + b, 0);
|
|
2054
|
+
const wrapperOverhead = Math.max(0, elTotalHeight(el) - sumHeights);
|
|
2055
|
+
let i = 0;
|
|
2056
|
+
let currentPage = pages[pages.length - 1];
|
|
2057
|
+
let used = startUsed;
|
|
2058
|
+
let fragIndex = 0;
|
|
2059
|
+
while (i < items.length) {
|
|
2060
|
+
const available = Math.max(0, limit - used);
|
|
2061
|
+
const isFirstFragment = fragIndex === 0;
|
|
2062
|
+
let bestK = -1;
|
|
2063
|
+
let runningH = isFirstFragment ? wrapperOverhead : 0;
|
|
2064
|
+
for (let k = i; k < items.length; k++) {
|
|
2065
|
+
runningH += heights[k];
|
|
2066
|
+
if (runningH <= available) bestK = k;
|
|
2067
|
+
else break;
|
|
2068
|
+
}
|
|
2069
|
+
if (bestK < 0) {
|
|
2070
|
+
if (currentPage.slots.length === 0) {
|
|
2071
|
+
bestK = i;
|
|
2072
|
+
} else {
|
|
2073
|
+
pages.push({ slots: [] });
|
|
2074
|
+
currentPage = pages[pages.length - 1];
|
|
2075
|
+
limit = limitFor(pages.length - 1);
|
|
2076
|
+
used = 0;
|
|
2077
|
+
continue;
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
currentPage.slots.push({
|
|
2081
|
+
topLevelIndex,
|
|
2082
|
+
listFragment: { index: fragIndex, itemStart: i, itemEnd: bestK + 1 }
|
|
2083
|
+
});
|
|
2084
|
+
let consumed = isFirstFragment ? wrapperOverhead : 0;
|
|
2085
|
+
for (let k = i; k <= bestK; k++) consumed += heights[k];
|
|
2086
|
+
used += consumed;
|
|
2087
|
+
i = bestK + 1;
|
|
2088
|
+
fragIndex++;
|
|
2089
|
+
if (i < items.length) {
|
|
2090
|
+
pages.push({ slots: [] });
|
|
2091
|
+
currentPage = pages[pages.length - 1];
|
|
2092
|
+
limit = limitFor(pages.length - 1);
|
|
1984
2093
|
used = 0;
|
|
1985
2094
|
}
|
|
1986
2095
|
}
|
|
@@ -2056,6 +2165,14 @@ function layoutsDeepEqual(a, b) {
|
|
|
2056
2165
|
return false;
|
|
2057
2166
|
}
|
|
2058
2167
|
}
|
|
2168
|
+
const lA = sA[j].listFragment;
|
|
2169
|
+
const lB = sB[j].listFragment;
|
|
2170
|
+
if (lA || lB) {
|
|
2171
|
+
if (!lA || !lB) return false;
|
|
2172
|
+
if (lA.index !== lB.index || lA.itemStart !== lB.itemStart || lA.itemEnd !== lB.itemEnd) {
|
|
2173
|
+
return false;
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2059
2176
|
}
|
|
2060
2177
|
}
|
|
2061
2178
|
return true;
|
|
@@ -2082,7 +2199,7 @@ function usePageSettings(doc) {
|
|
|
2082
2199
|
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
2083
2200
|
}
|
|
2084
2201
|
function shallowEqual(a, b) {
|
|
2085
|
-
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;
|
|
2202
|
+
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;
|
|
2086
2203
|
}
|
|
2087
2204
|
|
|
2088
2205
|
// src/useEditor.ts
|
|
@@ -2806,8 +2923,33 @@ function Editor({
|
|
|
2806
2923
|
}
|
|
2807
2924
|
return;
|
|
2808
2925
|
}
|
|
2809
|
-
case "insertParagraph":
|
|
2810
2926
|
case "insertLineBreak": {
|
|
2927
|
+
e.preventDefault();
|
|
2928
|
+
if (ed.getBlockType() === "listItem") {
|
|
2929
|
+
insertText(ctx, "\n", ed.consumePendingMarks());
|
|
2930
|
+
return;
|
|
2931
|
+
}
|
|
2932
|
+
const selEmbed = ed.getSelectedEmbed();
|
|
2933
|
+
if (selEmbed) {
|
|
2934
|
+
const off = selEmbed.offset + 1;
|
|
2935
|
+
ctx.setSelection({
|
|
2936
|
+
anchor: {
|
|
2937
|
+
blockIndex: selEmbed.blockIndex,
|
|
2938
|
+
cellIndex: selEmbed.cellIndex,
|
|
2939
|
+
offset: off
|
|
2940
|
+
},
|
|
2941
|
+
focus: {
|
|
2942
|
+
blockIndex: selEmbed.blockIndex,
|
|
2943
|
+
cellIndex: selEmbed.cellIndex,
|
|
2944
|
+
offset: off
|
|
2945
|
+
}
|
|
2946
|
+
});
|
|
2947
|
+
}
|
|
2948
|
+
if (ed.splitListItem()) return;
|
|
2949
|
+
insertParagraph(ctx);
|
|
2950
|
+
return;
|
|
2951
|
+
}
|
|
2952
|
+
case "insertParagraph": {
|
|
2811
2953
|
e.preventDefault();
|
|
2812
2954
|
const selectedEmbed2 = ed.getSelectedEmbed();
|
|
2813
2955
|
if (selectedEmbed2) {
|
|
@@ -2906,6 +3048,20 @@ function Editor({
|
|
|
2906
3048
|
else ed.indentList();
|
|
2907
3049
|
return;
|
|
2908
3050
|
}
|
|
3051
|
+
if (!mod && (e.key === "Home" || e.key === "End")) {
|
|
3052
|
+
const root = rootRef.current;
|
|
3053
|
+
const sel = window.getSelection();
|
|
3054
|
+
const sm = sel?.modify;
|
|
3055
|
+
if (root && sel && sel.rangeCount > 0 && typeof sm === "function") {
|
|
3056
|
+
e.preventDefault();
|
|
3057
|
+
const alter = e.shiftKey ? "extend" : "move";
|
|
3058
|
+
const direction = e.key === "Home" ? "left" : "right";
|
|
3059
|
+
sm.call(sel, alter, direction, "lineboundary");
|
|
3060
|
+
const modelSel = readDomSelection(root);
|
|
3061
|
+
if (modelSel) ctxRef.current.setSelection(modelSel);
|
|
3062
|
+
}
|
|
3063
|
+
return;
|
|
3064
|
+
}
|
|
2909
3065
|
if (!mod) return;
|
|
2910
3066
|
const key = e.key.toLowerCase();
|
|
2911
3067
|
if (!e.shiftKey && !e.altKey && key === "z") {
|
|
@@ -2962,26 +3118,47 @@ function Editor({
|
|
|
2962
3118
|
}
|
|
2963
3119
|
}, []);
|
|
2964
3120
|
const topLevels = useMemo4(() => groupTopLevels(snapshot.blocks), [snapshot]);
|
|
3121
|
+
const topLevelsStructuralKey = useMemo4(
|
|
3122
|
+
() => topLevels.map(
|
|
3123
|
+
(t) => t.kind === "list" ? `L:${t.listKind}:${t.items.length}:${t.ordinalStart}` : `B:${t.block.type}:${t.block.attrs.level ?? ""}`
|
|
3124
|
+
).join("|"),
|
|
3125
|
+
[topLevels]
|
|
3126
|
+
);
|
|
2965
3127
|
const docSettings = usePageSettings(editor.doc);
|
|
2966
3128
|
const propIsSet = pageGeometry !== void 0;
|
|
2967
3129
|
const geom = propIsSet ? pageGeometry ?? A4_PAGE : docSettings;
|
|
2968
3130
|
const paginated = pageGeometry !== null;
|
|
2969
3131
|
const selectedEmbed = editor.getSelectedEmbed();
|
|
2970
|
-
const layout = usePageLayout(
|
|
3132
|
+
const { layout, phase: paginationPhase } = usePageLayout(
|
|
2971
3133
|
rootRef,
|
|
2972
3134
|
geom,
|
|
2973
3135
|
topLevels.length,
|
|
2974
|
-
|
|
3136
|
+
// Usar a chave estrutural (string) em vez do array `topLevels` direto:
|
|
3137
|
+
// o array reference muda a cada keystroke, mas a chave só muda quando
|
|
3138
|
+
// a SHAPE dos top-levels muda. `usePageLayout` compara deps via
|
|
3139
|
+
// `shallowArrayEqual` — string equality cobre isso.
|
|
3140
|
+
[topLevelsStructuralKey, pageGeometry]
|
|
2975
3141
|
);
|
|
2976
3142
|
const effectiveLayout = paginated ? layout : defaultPageLayout(topLevels.length);
|
|
2977
|
-
const pageStyle =
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
3143
|
+
const pageStyle = useMemo4(
|
|
3144
|
+
() => paginated ? {
|
|
3145
|
+
"--ed-page-width": `${geom.width}px`,
|
|
3146
|
+
"--ed-page-height": `${geom.height}px`,
|
|
3147
|
+
"--ed-page-margin-top": `${geom.marginTop}px`,
|
|
3148
|
+
"--ed-page-margin-bottom": `${geom.marginBottom}px`,
|
|
3149
|
+
"--ed-page-margin-left": `${geom.marginLeft}px`,
|
|
3150
|
+
"--ed-page-margin-right": `${geom.marginRight}px`
|
|
3151
|
+
} : void 0,
|
|
3152
|
+
[
|
|
3153
|
+
paginated,
|
|
3154
|
+
geom.width,
|
|
3155
|
+
geom.height,
|
|
3156
|
+
geom.marginTop,
|
|
3157
|
+
geom.marginBottom,
|
|
3158
|
+
geom.marginLeft,
|
|
3159
|
+
geom.marginRight
|
|
3160
|
+
]
|
|
3161
|
+
);
|
|
2985
3162
|
const body = /* @__PURE__ */ jsxs8(
|
|
2986
3163
|
"div",
|
|
2987
3164
|
{
|
|
@@ -2994,6 +3171,7 @@ function Editor({
|
|
|
2994
3171
|
role: "textbox",
|
|
2995
3172
|
"aria-multiline": "true",
|
|
2996
3173
|
className: (className ?? "ed-root") + (paginated ? " ed-root--paged" : " ed-root--flat"),
|
|
3174
|
+
"data-pagination-phase": paginated ? paginationPhase : void 0,
|
|
2997
3175
|
style: pageStyle,
|
|
2998
3176
|
onKeyDown,
|
|
2999
3177
|
onCompositionStart,
|
|
@@ -3004,12 +3182,16 @@ function Editor({
|
|
|
3004
3182
|
pageNumber: pi + 1,
|
|
3005
3183
|
pageCount: effectiveLayout.pages.length
|
|
3006
3184
|
};
|
|
3185
|
+
const pageInlineStyle = pi === 0 && geom.firstPageExtraTop ? {
|
|
3186
|
+
"--ed-page-margin-top": `${geom.marginTop + geom.firstPageExtraTop}px`
|
|
3187
|
+
} : void 0;
|
|
3007
3188
|
return /* @__PURE__ */ jsxs8(
|
|
3008
3189
|
"div",
|
|
3009
3190
|
{
|
|
3010
3191
|
className: "ed-page",
|
|
3011
3192
|
"data-page-number": ctx.pageNumber,
|
|
3012
3193
|
"data-page-total": ctx.pageCount,
|
|
3194
|
+
style: pageInlineStyle,
|
|
3013
3195
|
children: [
|
|
3014
3196
|
renderPageHeader && /* @__PURE__ */ jsx9("div", { className: "ed-page-header", contentEditable: false, children: renderPageHeader(ctx) }),
|
|
3015
3197
|
/* @__PURE__ */ jsx9("div", { className: "ed-page-content", children: page.slots.map((slot) => renderSlot(slot, topLevels)) }),
|
|
@@ -3055,11 +3237,29 @@ function groupTopLevels(snapshot) {
|
|
|
3055
3237
|
const groupStart = i;
|
|
3056
3238
|
const items = [];
|
|
3057
3239
|
const kind = block.attrs.listKind === "ordered" ? "ordered" : "bullet";
|
|
3058
|
-
|
|
3059
|
-
|
|
3240
|
+
const groupStyle = block.attrs.listStyle;
|
|
3241
|
+
while (i < snapshot.length) {
|
|
3242
|
+
const b = snapshot[i];
|
|
3243
|
+
if (b.type !== "listItem") break;
|
|
3244
|
+
if ((b.attrs.listKind ?? "bullet") !== kind) break;
|
|
3245
|
+
if (i > groupStart) {
|
|
3246
|
+
if (typeof b.attrs.listStart === "number") break;
|
|
3247
|
+
const itemStyle = b.attrs.listStyle;
|
|
3248
|
+
if (itemStyle !== void 0 && itemStyle !== groupStyle) break;
|
|
3249
|
+
}
|
|
3250
|
+
items.push({ block: b, index: i });
|
|
3060
3251
|
i++;
|
|
3061
3252
|
}
|
|
3062
|
-
|
|
3253
|
+
const firstAttrs = items[0].block.attrs;
|
|
3254
|
+
const ordinalStart = typeof firstAttrs.listStart === "number" && firstAttrs.listStart > 0 ? firstAttrs.listStart : 1;
|
|
3255
|
+
out.push({
|
|
3256
|
+
kind: "list",
|
|
3257
|
+
items,
|
|
3258
|
+
listKind: kind,
|
|
3259
|
+
ordinalStart,
|
|
3260
|
+
listStyle: groupStyle,
|
|
3261
|
+
key: groupStart
|
|
3262
|
+
});
|
|
3063
3263
|
continue;
|
|
3064
3264
|
}
|
|
3065
3265
|
out.push({ kind: "block", block, blockIndex: i, key: i });
|
|
@@ -3097,15 +3297,43 @@ function renderSlot(slot, topLevels) {
|
|
|
3097
3297
|
`${top.key}-tf${slot.tableFragment.index}`
|
|
3098
3298
|
);
|
|
3099
3299
|
}
|
|
3300
|
+
if (slot.listFragment && top.kind === "list") {
|
|
3301
|
+
return renderListFragment(top, slot.listFragment);
|
|
3302
|
+
}
|
|
3100
3303
|
return renderTopLevel(top);
|
|
3101
3304
|
}
|
|
3102
3305
|
function renderTopLevel(top) {
|
|
3103
3306
|
if (top.kind === "list") {
|
|
3104
3307
|
const tree = buildListTree(top.items);
|
|
3105
|
-
return renderListTree(tree, top.
|
|
3308
|
+
return renderListTree(tree, top, top.ordinalStart, `list-${top.key}`);
|
|
3106
3309
|
}
|
|
3107
3310
|
return /* @__PURE__ */ jsx9(NodeView, { block: top.block, index: top.blockIndex }, top.key);
|
|
3108
3311
|
}
|
|
3312
|
+
function renderListFragment(top, frag) {
|
|
3313
|
+
const ranges = topLevelItemRanges(top.items);
|
|
3314
|
+
const startRange = ranges[frag.itemStart];
|
|
3315
|
+
const endRange = ranges[frag.itemEnd - 1];
|
|
3316
|
+
if (!startRange || !endRange) return renderTopLevel(top);
|
|
3317
|
+
const sliced = top.items.slice(startRange[0], endRange[1]);
|
|
3318
|
+
const ordinalStart = top.ordinalStart + frag.itemStart;
|
|
3319
|
+
const key = `list-${top.key}-f${frag.index}`;
|
|
3320
|
+
const slicedTop = { ...top, items: sliced };
|
|
3321
|
+
const tree = buildListTree(sliced);
|
|
3322
|
+
return renderListTree(tree, slicedTop, ordinalStart, key);
|
|
3323
|
+
}
|
|
3324
|
+
function topLevelItemRanges(items) {
|
|
3325
|
+
const out = [];
|
|
3326
|
+
let currentStart = -1;
|
|
3327
|
+
items.forEach((it, idx) => {
|
|
3328
|
+
const level = clampListLevel2(it.block.attrs.listLevel);
|
|
3329
|
+
if (level === 0) {
|
|
3330
|
+
if (currentStart >= 0) out.push([currentStart, idx]);
|
|
3331
|
+
currentStart = idx;
|
|
3332
|
+
}
|
|
3333
|
+
});
|
|
3334
|
+
if (currentStart >= 0) out.push([currentStart, items.length]);
|
|
3335
|
+
return out;
|
|
3336
|
+
}
|
|
3109
3337
|
function buildListTree(items) {
|
|
3110
3338
|
const roots = [];
|
|
3111
3339
|
const stack = [{ children: roots, level: -1 }];
|
|
@@ -3118,9 +3346,28 @@ function buildListTree(items) {
|
|
|
3118
3346
|
}
|
|
3119
3347
|
return roots;
|
|
3120
3348
|
}
|
|
3121
|
-
function renderListTree(tree,
|
|
3349
|
+
function renderListTree(tree, top, start, key) {
|
|
3350
|
+
const className = `ed-list ed-list-${top.listKind}`;
|
|
3351
|
+
const style = top.listStyle ? { listStyleType: top.listStyle } : void 0;
|
|
3352
|
+
const items = tree.map((node) => /* @__PURE__ */ jsx9(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));
|
|
3353
|
+
if (top.listKind === "ordered") {
|
|
3354
|
+
return /* @__PURE__ */ jsx9(
|
|
3355
|
+
"ol",
|
|
3356
|
+
{
|
|
3357
|
+
className,
|
|
3358
|
+
"data-list-kind": "ordered",
|
|
3359
|
+
start: start > 1 ? start : void 0,
|
|
3360
|
+
style,
|
|
3361
|
+
children: items
|
|
3362
|
+
},
|
|
3363
|
+
key
|
|
3364
|
+
);
|
|
3365
|
+
}
|
|
3366
|
+
return /* @__PURE__ */ jsx9("ul", { className, "data-list-kind": "bullet", style, children: items }, key);
|
|
3367
|
+
}
|
|
3368
|
+
function renderNestedListTree(tree, kind, key) {
|
|
3122
3369
|
const Tag = kind === "ordered" ? "ol" : "ul";
|
|
3123
|
-
return /* @__PURE__ */ jsx9(Tag, { className: `ed-list ed-list-${kind}`, "data-list-kind": kind, children: tree.map((node) => /* @__PURE__ */ jsx9(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ?
|
|
3370
|
+
return /* @__PURE__ */ jsx9(Tag, { className: `ed-list ed-list-${kind}`, "data-list-kind": kind, children: tree.map((node) => /* @__PURE__ */ jsx9(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);
|
|
3124
3371
|
}
|
|
3125
3372
|
function clampListLevel2(l) {
|
|
3126
3373
|
if (typeof l !== "number" || !Number.isFinite(l)) return 0;
|