@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.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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1707
|
-
|
|
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
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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 =
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
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
|
-
|
|
3044
|
-
|
|
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
|
-
|
|
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.
|
|
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,
|
|
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 ?
|
|
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;
|