wendang-react 0.5.6 → 0.6.3

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.
Files changed (87) hide show
  1. package/NOTICE.md +47 -0
  2. package/README.md +39 -0
  3. package/dist/bindings/yjs.js +1 -1
  4. package/dist/chunks/{AnchoredPanel-D3nte06T.js → AnchoredPanel-Cv4RURwF.js} +1 -1
  5. package/dist/chunks/DocumentExportMenu-BrGipZ59.js +75 -0
  6. package/dist/chunks/{MindMapCanvas-D5XwjVH1.js → MindMapCanvas-tkFBBs4g.js} +22 -4
  7. package/dist/chunks/{MindMapViewer-CQTQAgNq.js → MindMapViewer-DJrryb2Y.js} +3 -3
  8. package/dist/chunks/{SpreadsheetViewer-DN_QQGud.js → SpreadsheetViewer-DxCxIUx_.js} +8 -2
  9. package/dist/chunks/{comment-hint-DN7LKJAn.js → comment-hint-B9qcrqvn.js} +2 -2
  10. package/dist/chunks/{extensions-B-CVVQhp.js → extensions-ByORRoRa.js} +3 -3
  11. package/dist/chunks/{index-Ii536CFG.js → index-DdfMnva8.js} +9 -3
  12. package/dist/chunks/{mind-topic-text-BBNTbFSe.js → mind-topic-text-DSyb95vL.js} +1 -1
  13. package/dist/document/viewer.js +6 -4
  14. package/dist/document.js +213 -22
  15. package/dist/export/json.js +5 -0
  16. package/dist/export/markdown.js +2 -0
  17. package/dist/export/mindmap.js +2 -0
  18. package/dist/export/pdf.js +6 -0
  19. package/dist/export/word.js +2 -0
  20. package/dist/export.js +2 -0
  21. package/dist/mindmap/viewer.js +1 -1
  22. package/dist/mindmap.js +1 -1
  23. package/dist/spreadsheet/viewer.js +1 -1
  24. package/dist/styles/callout.css +5 -5
  25. package/dist/styles/content-style.css +3 -3
  26. package/dist/styles/content-tokens.css +29 -0
  27. package/dist/styles/tokens.css +2 -14
  28. package/dist/styles.css +64 -24
  29. package/dist/types/document/DocumentExportMenu.d.ts +7 -0
  30. package/dist/types/document/viewer.d.ts +2 -0
  31. package/dist/types/document.d.ts +2 -0
  32. package/dist/types/engine/wui/core/overlay-scrollbar.d.ts +4 -0
  33. package/dist/types/export/json.d.ts +1 -0
  34. package/dist/types/export/markdown.d.ts +1 -0
  35. package/dist/types/export/mindmap.d.ts +1 -0
  36. package/dist/types/export/pdf.d.ts +2 -0
  37. package/dist/types/export/word.d.ts +1 -0
  38. package/dist/types/export.d.ts +1 -0
  39. package/dist/types/host-types.d.ts +2 -0
  40. package/dist/types/spreadsheet/SpreadsheetViewer.d.ts +1 -1
  41. package/package.json +28 -3
  42. package/third-party-notices/@mathjax__src@4.1.3-LICENSE.txt +202 -0
  43. package/third-party-notices/@noble__ciphers@1.3.0-LICENSE.txt +22 -0
  44. package/third-party-notices/@noble__hashes@1.8.0-LICENSE.txt +21 -0
  45. package/third-party-notices/@pdf-lib__standard-fonts@1.0.0-LICENSE.md.txt +21 -0
  46. package/third-party-notices/@pdf-lib__upng@1.0.1-LICENSE.txt +21 -0
  47. package/third-party-notices/@swc__helpers@0.5.23-LICENSE.txt +201 -0
  48. package/third-party-notices/@xmldom__xmldom@0.9.12-LICENSE.txt +8 -0
  49. package/third-party-notices/balanced-match@4.0.4-LICENSE.md.txt +23 -0
  50. package/third-party-notices/base64-js@0.0.8-LICENSE.MIT.txt +21 -0
  51. package/third-party-notices/brace-expansion@5.0.12-LICENSE.txt +23 -0
  52. package/third-party-notices/clone@2.1.2-LICENSE.txt +18 -0
  53. package/third-party-notices/commander@14.0.3-LICENSE.txt +22 -0
  54. package/third-party-notices/docx@9.15.0-LICENSE.txt +21 -0
  55. package/third-party-notices/fast-deep-equal@3.1.3-LICENSE.txt +21 -0
  56. package/third-party-notices/fflate@0.8.3-LICENSE.txt +21 -0
  57. package/third-party-notices/glob@13.0.6-LICENSE.md.txt +63 -0
  58. package/third-party-notices/linebreak@1.1.0-LICENSE.txt +21 -0
  59. package/third-party-notices/lru-cache@11.5.3-LICENSE.md.txt +55 -0
  60. package/third-party-notices/mhchemparser@4.2.1-LICENSE.txt.txt +201 -0
  61. package/third-party-notices/minimatch@10.2.6-LICENSE.md.txt +55 -0
  62. package/third-party-notices/minipass@7.1.3-LICENSE.md.txt +55 -0
  63. package/third-party-notices/mj-context-menu@1.0.0-LICENSE.txt +201 -0
  64. package/third-party-notices/nanoid@6.0.2-LICENSE.txt +20 -0
  65. package/third-party-notices/package-json-from-dist@1.0.1-LICENSE.md.txt +63 -0
  66. package/third-party-notices/pako@0.2.9-LICENSE.txt +21 -0
  67. package/third-party-notices/path-scurry@2.0.2-LICENSE.md.txt +55 -0
  68. package/third-party-notices/pdf-lib@1.17.1-LICENSE.md.txt +21 -0
  69. package/third-party-notices/pdfkit@0.20.2-LICENSE.txt +8 -0
  70. package/third-party-notices/pdfmake@0.3.13-LICENSE.txt +21 -0
  71. package/third-party-notices/png-js@2.0.0-LICENSE.txt +21 -0
  72. package/third-party-notices/restructure@3.0.2-LICENSE.txt +21 -0
  73. package/third-party-notices/rimraf@6.1.3-LICENSE.md.txt +55 -0
  74. package/third-party-notices/sax@1.6.1-LICENSE.md.txt +55 -0
  75. package/third-party-notices/speech-rule-engine@5.0.0-rc.4-LICENSE.txt +177 -0
  76. package/third-party-notices/tiny-inflate@1.0.3-LICENSE.txt +21 -0
  77. package/third-party-notices/tslib@1.14.1-LICENSE.txt.txt +12 -0
  78. package/third-party-notices/unicode-properties@1.4.1-LICENSE.txt +8 -0
  79. package/third-party-notices/unicode-trie@2.0.0-LICENSE.txt +8 -0
  80. package/third-party-notices/wendang-export@0.6.0-LICENSE.txt +21 -0
  81. package/third-party-notices/wendang-export@0.6.0-NOTICE.md.txt +51 -0
  82. package/third-party-notices/wendang-export@0.6.1-LICENSE.txt +21 -0
  83. package/third-party-notices/wendang-export@0.6.1-NOTICE.md.txt +70 -0
  84. package/third-party-notices/wendang-export@0.6.2-LICENSE.txt +21 -0
  85. package/third-party-notices/wendang-export@0.6.2-NOTICE.md.txt +70 -0
  86. package/third-party-notices/wicked-good-xpath@1.3.0-LICENSE.txt +23 -0
  87. package/third-party-notices/xmldoc@2.0.3-LICENSE.txt +23 -0
package/dist/document.js CHANGED
@@ -6,14 +6,14 @@ import { createPortal } from "react-dom";
6
6
  import { useRef, useState, useLayoutEffect, useEffect, useMemo, useId, forwardRef, useCallback, useImperativeHandle } from "react";
7
7
  import { ContentSchemaService, requiredSchemaVersion, SCHEMA_VERSION } from "wendang/schema";
8
8
  import { safeHref, TEXT_COLORS, HIGHLIGHT_COLORS, documentColorAttributes, parseVideoUrl } from "wendang/shared";
9
- import { b as buildColumnsJson, d as dismissSlash, u as unwrapCallout, h as highlightMenuBlock, T as TEXT_ALIGNS, c as currentTableCellPosition, r as readTableGeometry, t as tableHeaderActive, a as tablePositionAtCell, s as selectTableAxis, i as insertTableBoundary, e as CELL_ALIGNS, f as cellPositionAtDOM, g as selectTableCell, j as clippedTableSelection, k as tableSelectionMarkActive, l as setTableSelectionMark, m as setTableHeaderBackground, n as currentCellRect, o as setColumnWidth, p as autoFitColumn, q as distributeTableColumns, v as getSelectedBlocks, B as BlockRangeSelection, w as setBlockRangeSelection, x as setImageRangeSelection, y as pastedImageFiles, z as pastedRemoteImageUrls, A as coreExtensions, D as refreshInlineComments, E as addUploadPlaceholder, F as currentPlaceholderPos, G as insertUploadedBlock, H as removeUploadPlaceholder, I as replacePlaceholderWithNode } from "./chunks/extensions-B-CVVQhp.js";
10
- import { C } from "./chunks/extensions-B-CVVQhp.js";
9
+ import { b as buildColumnsJson, d as dismissSlash, u as unwrapCallout, h as highlightMenuBlock, T as TEXT_ALIGNS, c as currentTableCellPosition, r as readTableGeometry, t as tableHeaderActive, a as tablePositionAtCell, s as selectTableAxis, i as insertTableBoundary, e as CELL_ALIGNS, f as cellPositionAtDOM, g as selectTableCell, j as clippedTableSelection, k as tableSelectionMarkActive, l as setTableSelectionMark, m as setTableHeaderBackground, n as currentCellRect, o as setColumnWidth, p as autoFitColumn, q as distributeTableColumns, v as getSelectedBlocks, B as BlockRangeSelection, w as setBlockRangeSelection, x as setImageRangeSelection, y as pastedImageFiles, z as pastedRemoteImageUrls, A as coreExtensions, D as refreshInlineComments, E as addUploadPlaceholder, F as currentPlaceholderPos, G as insertUploadedBlock, H as removeUploadPlaceholder, I as replacePlaceholderWithNode } from "./chunks/extensions-ByORRoRa.js";
10
+ import { C } from "./chunks/extensions-ByORRoRa.js";
11
11
  import { a as useContentContext, p as primeAttachment, u as unavailableAttachment } from "./chunks/host-C-V688Rq.js";
12
12
  import { c as createMindMapController } from "./chunks/mind-map-controller-B6SxK3GZ.js";
13
- import { M as MindMapBlock } from "./chunks/MindMapViewer-CQTQAgNq.js";
14
- import { p as previewItemsFrom, I as ImagePreview, V as VideoView } from "./chunks/mind-topic-text-BBNTbFSe.js";
13
+ import { M as MindMapBlock } from "./chunks/MindMapViewer-DJrryb2Y.js";
14
+ import { p as previewItemsFrom, I as ImagePreview, V as VideoView } from "./chunks/mind-topic-text-DSyb95vL.js";
15
15
  import { u as useLatest, a as useReady, b as asError } from "./chunks/hooks-C53Dp0pr.js";
16
- import { W as WButton, b as WIcon, l as lockScroll, t as trapTab, c as WDialog } from "./chunks/index-Ii536CFG.js";
16
+ import { a as WButton, b as WIcon, p as placePanel, l as lockScroll, t as trapTab, c as WDialog } from "./chunks/index-DdfMnva8.js";
17
17
  import { p as placeAnchoredPopover } from "./chunks/popover-placement-D3xVYdkt.js";
18
18
  import { A, a, b } from "./chunks/popover-placement-D3xVYdkt.js";
19
19
  import { isSafeHref } from "wendang/internal/safe-href";
@@ -28,6 +28,7 @@ import { CellSelection, TableMap } from "@tiptap/pm/tables";
28
28
  import { CELL_BACKGROUNDS } from "wendang/internal/table-cell-format";
29
29
  import { r as rankPages } from "./chunks/fuzzy-match-DYQR-4w2.js";
30
30
  import { inspectVideoUrl, VIDEO_PROVIDER_LABELS, videoSourceUrl } from "wendang/internal/video-embed";
31
+ import { D } from "./chunks/DocumentExportMenu-BrGipZ59.js";
31
32
  function linkHrefProblem(value) {
32
33
  const href = value.trim();
33
34
  if (!href) return "请输入链接地址。";
@@ -1495,6 +1496,110 @@ function placeTableMenu(anchor, menu, viewport) {
1495
1496
  maxHeight
1496
1497
  };
1497
1498
  }
1499
+ function attachOverlayScrollbar(host, viewport, content) {
1500
+ const track = document.createElement("div"), thumb = document.createElement("div");
1501
+ track.className = "w-overlay-scrollbar__track";
1502
+ thumb.className = "w-overlay-scrollbar__thumb";
1503
+ const originalId = viewport.id;
1504
+ if (!viewport.id) viewport.id = `wd-scroll-${crypto.randomUUID()}`;
1505
+ thumb.tabIndex = 0;
1506
+ thumb.setAttribute("role", "scrollbar");
1507
+ thumb.setAttribute("aria-label", "菜单滚动条");
1508
+ thumb.setAttribute("aria-orientation", "vertical");
1509
+ thumb.setAttribute("aria-controls", viewport.id);
1510
+ thumb.setAttribute("aria-valuemin", "0");
1511
+ track.append(thumb);
1512
+ host.append(track);
1513
+ let timer;
1514
+ let drag;
1515
+ let thumbHeight = 0;
1516
+ const events = new AbortController();
1517
+ function active() {
1518
+ host.classList.add("is-scrolling");
1519
+ clearTimeout(timer);
1520
+ timer = setTimeout(() => {
1521
+ if (!drag) host.classList.remove("is-scrolling");
1522
+ }, 700);
1523
+ }
1524
+ function update() {
1525
+ const maximum = Math.max(0, viewport.scrollHeight - viewport.clientHeight);
1526
+ track.hidden = maximum <= 1;
1527
+ const height = track.clientHeight;
1528
+ thumbHeight = Math.min(height, Math.max(28, height * viewport.clientHeight / Math.max(1, viewport.scrollHeight)));
1529
+ thumb.style.height = `${thumbHeight}px`;
1530
+ thumb.style.transform = `translateY(${maximum ? (height - thumbHeight) * viewport.scrollTop / maximum : 0}px)`;
1531
+ thumb.setAttribute("aria-valuemax", String(Math.round(maximum)));
1532
+ thumb.setAttribute("aria-valuenow", String(Math.round(viewport.scrollTop)));
1533
+ }
1534
+ viewport.addEventListener("scroll", () => {
1535
+ update();
1536
+ active();
1537
+ }, { passive: true, signal: events.signal });
1538
+ thumb.addEventListener("pointerdown", (event) => {
1539
+ if (event.button !== 0) return;
1540
+ event.preventDefault();
1541
+ event.stopPropagation();
1542
+ thumb.focus({ preventScroll: true });
1543
+ drag = {
1544
+ y: event.clientY,
1545
+ top: viewport.scrollTop,
1546
+ maximum: viewport.scrollHeight - viewport.clientHeight,
1547
+ travel: Math.max(1, track.clientHeight - thumbHeight)
1548
+ };
1549
+ host.classList.add("is-dragging-scrollbar");
1550
+ active();
1551
+ }, { signal: events.signal });
1552
+ window.addEventListener("pointermove", (event) => {
1553
+ if (!drag) return;
1554
+ event.preventDefault();
1555
+ viewport.scrollTop = Math.max(0, Math.min(drag.maximum, drag.top + (event.clientY - drag.y) * drag.maximum / drag.travel));
1556
+ update();
1557
+ }, { signal: events.signal });
1558
+ function finish() {
1559
+ if (!drag) return;
1560
+ drag = void 0;
1561
+ host.classList.remove("is-dragging-scrollbar");
1562
+ active();
1563
+ }
1564
+ window.addEventListener("pointerup", finish, { signal: events.signal });
1565
+ window.addEventListener("pointercancel", finish, { signal: events.signal });
1566
+ window.addEventListener("blur", finish, { signal: events.signal });
1567
+ track.addEventListener("pointerdown", (event) => {
1568
+ if (event.target !== track || event.button !== 0) return;
1569
+ event.preventDefault();
1570
+ event.stopPropagation();
1571
+ const top = track.getBoundingClientRect().top;
1572
+ viewport.scrollTop = (event.clientY - top - thumbHeight / 2) / Math.max(1, track.clientHeight - thumbHeight) * (viewport.scrollHeight - viewport.clientHeight);
1573
+ update();
1574
+ active();
1575
+ }, { signal: events.signal });
1576
+ thumb.addEventListener("keydown", (event) => {
1577
+ const deltas = { ArrowDown: 32, ArrowUp: -32, PageDown: viewport.clientHeight * 0.8, PageUp: -viewport.clientHeight * 0.8 };
1578
+ const delta = deltas[event.key];
1579
+ if (delta === void 0 && event.key !== "Home" && event.key !== "End") return;
1580
+ event.preventDefault();
1581
+ event.stopPropagation();
1582
+ viewport.scrollTop = event.key === "Home" ? 0 : event.key === "End" ? viewport.scrollHeight : viewport.scrollTop + delta;
1583
+ update();
1584
+ active();
1585
+ }, { signal: events.signal });
1586
+ const resize = new ResizeObserver(update);
1587
+ resize.observe(viewport);
1588
+ resize.observe(content);
1589
+ resize.observe(host);
1590
+ update();
1591
+ return {
1592
+ update,
1593
+ destroy() {
1594
+ events.abort();
1595
+ resize.disconnect();
1596
+ clearTimeout(timer);
1597
+ track.remove();
1598
+ host.classList.remove("is-scrolling", "is-dragging-scrollbar");
1599
+ if (!originalId) viewport.removeAttribute("id");
1600
+ }
1601
+ };
1602
+ }
1498
1603
  const CORNER_W = 44, CORNER_H = 26, GUTTER_GAP = 8;
1499
1604
  const anchorOf = (event) => {
1500
1605
  const rect = event.currentTarget.getBoundingClientRect();
@@ -1505,24 +1610,72 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1505
1610
  const { portal } = useContentContext(), axisCleanup = useRef(null);
1506
1611
  const [dismissed, setDismissed] = useState(false), [panel, setPanel] = useState("none");
1507
1612
  const [menuOpen, setMenuOpen] = useState(false), [menuScope, setMenuScope] = useState("table");
1613
+ const [menuFromToolbar, setMenuFromToolbar] = useState(false);
1508
1614
  const [showStyle, setShowStyle] = useState(false), [widthOpen, setWidthOpen] = useState(false), [width, setWidth] = useState(""), [busy, setBusy] = useState(false);
1509
1615
  const [toolbarSize, setToolbarSize] = useState({ width: 0, height: 0 });
1616
+ const [, setViewportRevision] = useState(0);
1510
1617
  const [menuAnchor, setMenuAnchor] = useState(null), [panelAnchor, setPanelAnchor] = useState(null);
1511
1618
  const menuRef = useRef(null), panelRef = useRef(null);
1619
+ const menuViewport = useRef(null), menuContent = useRef(null);
1620
+ const menuTrigger = useRef(null), panelTrigger = useRef(null);
1512
1621
  const [menuPlace, setMenuPlace] = useState({ left: 0, top: 0, maxHeight: 480 }), [panelPlace, setPanelPlace] = useState({ left: 0, top: 0 });
1513
- useEffect(() => {
1622
+ useLayoutEffect(() => {
1623
+ var _a2;
1514
1624
  if (!menuOpen || !menuAnchor) return;
1515
1625
  const element = menuRef.current;
1516
1626
  if (!element) return;
1517
- setMenuPlace(placeTableMenu(menuAnchor, { width: element.offsetWidth, height: element.offsetHeight }, { width: innerWidth, height: innerHeight, topInset: 12 }));
1627
+ setMenuPlace(placeTableMenu(menuAnchor, { width: element.offsetWidth, height: (((_a2 = menuViewport.current) == null ? void 0 : _a2.scrollHeight) ?? element.scrollHeight) + 2 }, { width: innerWidth, height: innerHeight, topInset: 12 }));
1518
1628
  }, [menuOpen, menuAnchor, widthOpen, showStyle, menuScope]);
1519
1629
  useEffect(() => {
1630
+ var _a2;
1631
+ if (!menuOpen || !menuRef.current || !menuViewport.current || !menuContent.current) return;
1632
+ const scrollbar = attachOverlayScrollbar(menuRef.current, menuViewport.current, menuContent.current);
1633
+ (_a2 = menuRef.current.querySelector('[role="menuitem"]')) == null ? void 0 : _a2.focus({ preventScroll: true });
1634
+ return () => scrollbar.destroy();
1635
+ }, [menuOpen, portal]);
1636
+ useLayoutEffect(() => {
1520
1637
  if (panel === "none" || !panelAnchor) return;
1521
- const element = panelRef.current;
1522
- const card = { width: (element == null ? void 0 : element.offsetWidth) ?? 320, height: (element == null ? void 0 : element.offsetHeight) ?? 260 };
1523
- const placement = placeTableToolbar(panelAnchor, card, { width: innerWidth, height: innerHeight, topInset: 12 });
1524
- setPanelPlace({ left: placement.left, top: placement.top });
1525
- }, [panel, panelAnchor]);
1638
+ const measure = () => {
1639
+ var _a2;
1640
+ const element = panelRef.current, trigger = (_a2 = panelTrigger.current) == null ? void 0 : _a2.getBoundingClientRect();
1641
+ if (!element || !trigger) return;
1642
+ const placement = placePanel({
1643
+ trigger,
1644
+ panel: { width: element.offsetWidth, height: element.offsetHeight },
1645
+ position: "bl",
1646
+ gap: 6,
1647
+ viewport: { width: innerWidth, height: innerHeight }
1648
+ });
1649
+ setPanelPlace((previous) => previous.left === placement.left && previous.top === placement.top ? previous : { left: placement.left, top: placement.top });
1650
+ };
1651
+ measure();
1652
+ const observer = new ResizeObserver(measure);
1653
+ if (panelRef.current) observer.observe(panelRef.current);
1654
+ let frame = 0;
1655
+ const scroll = () => {
1656
+ cancelAnimationFrame(frame);
1657
+ frame = requestAnimationFrame(measure);
1658
+ };
1659
+ window.addEventListener("scroll", scroll, true);
1660
+ return () => {
1661
+ observer.disconnect();
1662
+ cancelAnimationFrame(frame);
1663
+ window.removeEventListener("scroll", scroll, true);
1664
+ };
1665
+ });
1666
+ useEffect(() => {
1667
+ const update = (event) => {
1668
+ var _a2, _b2;
1669
+ if (event.target instanceof Node && (((_a2 = menuRef.current) == null ? void 0 : _a2.contains(event.target)) || ((_b2 = panelRef.current) == null ? void 0 : _b2.contains(event.target)))) return;
1670
+ setViewportRevision((value) => value + 1);
1671
+ };
1672
+ window.addEventListener("scroll", update, true);
1673
+ window.addEventListener("resize", update);
1674
+ return () => {
1675
+ window.removeEventListener("scroll", update, true);
1676
+ window.removeEventListener("resize", update);
1677
+ };
1678
+ }, []);
1526
1679
  const selectionRef = useRef(editor.state.selection), docRef = useRef(editor.state.doc);
1527
1680
  useEffect(() => {
1528
1681
  if (!selectionRef.current.eq(editor.state.selection) || docRef.current !== editor.state.doc) {
@@ -1558,6 +1711,8 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1558
1711
  selectTableCell(editor.view, pos);
1559
1712
  setPanel("none");
1560
1713
  setMenuScope("cell");
1714
+ setMenuFromToolbar(false);
1715
+ menuTrigger.current = null;
1561
1716
  setShowStyle(false);
1562
1717
  setMenuAnchor({ left: event.clientX, right: event.clientX, top: event.clientY, bottom: event.clientY });
1563
1718
  setMenuOpen(true);
@@ -1581,11 +1736,18 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1581
1736
  setMenuOpen(false);
1582
1737
  setPanel("none");
1583
1738
  };
1739
+ const scroll = (event) => {
1740
+ var _a2, _b2;
1741
+ if (event.target instanceof Node && (((_a2 = menuRef.current) == null ? void 0 : _a2.contains(event.target)) || ((_b2 = panelRef.current) == null ? void 0 : _b2.contains(event.target)))) return;
1742
+ setMenuOpen(false);
1743
+ };
1584
1744
  document.addEventListener("pointerdown", close, true);
1585
1745
  window.addEventListener("resize", resize);
1746
+ window.addEventListener("scroll", scroll, true);
1586
1747
  return () => {
1587
1748
  document.removeEventListener("pointerdown", close, true);
1588
1749
  window.removeEventListener("resize", resize);
1750
+ window.removeEventListener("scroll", scroll, true);
1589
1751
  };
1590
1752
  }, [menuOpen, panel]);
1591
1753
  function axisDown(axis, index, event) {
@@ -1643,13 +1805,16 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1643
1805
  }
1644
1806
  useEffect(() => {
1645
1807
  const escape = (event) => {
1808
+ var _a2, _b2;
1646
1809
  if (event.key !== "Escape" || event.isComposing) return;
1647
1810
  if (panel !== "none") {
1648
1811
  event.preventDefault();
1649
1812
  setPanel("none");
1813
+ (_a2 = panelTrigger.current) == null ? void 0 : _a2.focus({ preventScroll: true });
1650
1814
  } else if (menuOpen) {
1651
1815
  event.preventDefault();
1652
1816
  setMenuOpen(false);
1817
+ (_b2 = menuTrigger.current) == null ? void 0 : _b2.focus({ preventScroll: true });
1653
1818
  } else if (cellSelection) {
1654
1819
  event.preventDefault();
1655
1820
  setDismissed(true);
@@ -1697,12 +1862,22 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1697
1862
  } else setColor(panel === "color" ? "textStyle" : "highlight", value);
1698
1863
  }
1699
1864
  function showContext(event, scope = "table") {
1865
+ var _a2;
1700
1866
  if (!event) return;
1867
+ const trigger = event.currentTarget;
1868
+ if (menuOpen && menuTrigger.current === trigger) {
1869
+ setMenuOpen(false);
1870
+ return;
1871
+ }
1872
+ menuTrigger.current = trigger;
1873
+ const bar = (_a2 = trigger.closest(".tbl-cellbar")) == null ? void 0 : _a2.getBoundingClientRect();
1701
1874
  if (scope === "table" && geometry) selectTableAxis(editor.view, geometry.cellPos, "table");
1875
+ const anchor = anchorOf(event);
1702
1876
  setPanel("none");
1703
1877
  setShowStyle(false);
1704
1878
  setMenuScope(scope);
1705
- setMenuAnchor(anchorOf(event));
1879
+ setMenuFromToolbar(!!bar);
1880
+ setMenuAnchor({ ...anchor, top: (bar == null ? void 0 : bar.top) ?? anchor.top, bottom: (bar == null ? void 0 : bar.bottom) ?? anchor.bottom });
1706
1881
  setMenuOpen(true);
1707
1882
  }
1708
1883
  async function copyTable(cut) {
@@ -1737,6 +1912,8 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1737
1912
  setPanel("none");
1738
1913
  return;
1739
1914
  }
1915
+ panelTrigger.current = event.currentTarget;
1916
+ setMenuOpen(false);
1740
1917
  setPanelAnchor(anchorOf(event));
1741
1918
  setPanel(name);
1742
1919
  }
@@ -1797,7 +1974,7 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1797
1974
  if (!disabled) onClick();
1798
1975
  },
1799
1976
  children: [
1800
- /* @__PURE__ */ jsx(WIcon, { name: icon, size: 18 }),
1977
+ /* @__PURE__ */ jsx(WIcon, { name: icon, size: ["bold", "italic", "strike", "underline"].includes(icon) ? 20 : 18 }),
1801
1978
  extra
1802
1979
  ]
1803
1980
  }
@@ -1821,6 +1998,7 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1821
1998
  if (pos !== null) onBlockDrag == null ? void 0 : onBlockDrag(pos, event.nativeEvent, () => {
1822
1999
  selectTableAxis(editor.view, geometry.cellPos, "table");
1823
2000
  setMenuScope("table");
2001
+ setMenuFromToolbar(false);
1824
2002
  setShowStyle(false);
1825
2003
  setMenuAnchor(anchor);
1826
2004
  setMenuOpen(true);
@@ -1894,7 +2072,7 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1894
2072
  ] }),
1895
2073
  selection && /* @__PURE__ */ jsxs(Fragment, { children: [
1896
2074
  /* @__PURE__ */ jsx("div", { className: "tbl-selection", style: { left: selection.left, top: selection.top, width: selection.width, height: selection.height } }),
1897
- !menuOpen && /* @__PURE__ */ jsx(
2075
+ (!menuOpen || menuFromToolbar) && /* @__PURE__ */ jsx(
1898
2076
  "button",
1899
2077
  {
1900
2078
  type: "button",
@@ -1914,7 +2092,7 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1914
2092
  children: "···"
1915
2093
  }
1916
2094
  ),
1917
- cellSelection && !dismissed && !menuOpen && /* @__PURE__ */ jsx(
2095
+ cellSelection && !dismissed && (!menuOpen || menuFromToolbar) && /* @__PURE__ */ jsx(
1918
2096
  "div",
1919
2097
  {
1920
2098
  className: "tbl-cellbar",
@@ -1958,7 +2136,7 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1958
2136
  item.key === "color" ? /* @__PURE__ */ jsxs(Fragment, { children: [
1959
2137
  "A",
1960
2138
  /* @__PURE__ */ jsx(WIcon, { name: "chevron-down", size: 12 })
1961
- ] }) : item.key === "highlight" ? /* @__PURE__ */ jsx(WIcon, { name: "marker", size: 17 }) : /* @__PURE__ */ jsx("span", { className: "fill-icon" }),
2139
+ ] }) : /* @__PURE__ */ jsx(WIcon, { name: item.key === "highlight" ? "marker" : "cell-fill", size: 20 }),
1962
2140
  /* @__PURE__ */ jsx("span", { className: "color-bar", style: { background: item.current ?? "transparent" }, "aria-hidden": "true" })
1963
2141
  ]
1964
2142
  },
@@ -2013,13 +2191,25 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
2013
2191
  "div",
2014
2192
  {
2015
2193
  ref: menuRef,
2016
- className: "tbl-ctx",
2017
- style: { position: "fixed", left: menuPlace.left, top: menuPlace.top, maxHeight: menuPlace.maxHeight, overflow: "auto", width: 216 },
2194
+ className: "tbl-ctx w-overlay-scrollbar",
2195
+ style: { position: "fixed", left: menuPlace.left, top: menuPlace.top, maxHeight: menuPlace.maxHeight, width: 216 },
2018
2196
  role: "menu",
2019
2197
  "aria-label": "表格操作菜单",
2020
- onMouseDown: (event) => event.preventDefault(),
2198
+ onMouseDown: (event) => {
2199
+ if (!(event.target instanceof HTMLInputElement)) event.preventDefault();
2200
+ },
2021
2201
  onContextMenu: (event) => event.preventDefault(),
2022
- children: menuScope === "table" ? /* @__PURE__ */ jsxs(Fragment, { children: [
2202
+ onKeyDown: (event) => {
2203
+ var _a2;
2204
+ if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key) || event.target instanceof HTMLInputElement) return;
2205
+ const buttons = [...((_a2 = menuRef.current) == null ? void 0 : _a2.querySelectorAll('[role^="menuitem"]:not(:disabled)')) ?? []];
2206
+ if (!buttons.length) return;
2207
+ event.preventDefault();
2208
+ const current = buttons.indexOf(document.activeElement);
2209
+ const next = event.key === "Home" ? 0 : event.key === "End" ? buttons.length - 1 : (current + (event.key === "ArrowDown" ? 1 : -1) + buttons.length) % buttons.length;
2210
+ buttons[next].focus();
2211
+ },
2212
+ children: /* @__PURE__ */ jsx("div", { ref: menuViewport, className: "w-overlay-scrollbar__viewport", style: { maxHeight: Math.max(0, menuPlace.maxHeight - 2) }, children: /* @__PURE__ */ jsx("div", { ref: menuContent, children: menuScope === "table" ? /* @__PURE__ */ jsxs(Fragment, { children: [
2023
2213
  menuItem("columns", "均分列宽", distribute),
2024
2214
  menuItem("palette", "表格样式", () => setShowStyle(!showStyle), { expanded: showStyle }),
2025
2215
  showStyle && /* @__PURE__ */ jsxs("div", { className: "ctx-styles", "aria-label": "表头样式", children: [
@@ -2157,7 +2347,7 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
2157
2347
  chain().deleteTable().run();
2158
2348
  setMenuOpen(false);
2159
2349
  }, { danger: true })
2160
- ] })
2350
+ ] }) }) })
2161
2351
  }
2162
2352
  )
2163
2353
  ] }), portal)
@@ -3614,6 +3804,7 @@ export {
3614
3804
  b as ANCHORED_POPOVER_VIEW_MARGIN,
3615
3805
  C as COLLAB_FIELD,
3616
3806
  DocumentEditor,
3807
+ D as DocumentExportMenu,
3617
3808
  coreExtensions,
3618
3809
  placeAnchoredPopover,
3619
3810
  sameDocument
@@ -0,0 +1,5 @@
1
+ "use client";
2
+ import { jsonFile } from "wendang-export/json";
3
+ export {
4
+ jsonFile
5
+ };
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ export * from "wendang-export/markdown";
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ export * from "wendang-export/mindmap";
@@ -0,0 +1,6 @@
1
+ "use client";
2
+ export * from "wendang-export/pdf";
3
+ import { defaultPdfFontUrl } from "wendang-export/font";
4
+ export {
5
+ defaultPdfFontUrl
6
+ };
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ export * from "wendang-export/word";
package/dist/export.js ADDED
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ export * from "wendang-export";
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { M, a } from "../chunks/MindMapViewer-CQTQAgNq.js";
2
+ import { M, a } from "../chunks/MindMapViewer-DJrryb2Y.js";
3
3
  export {
4
4
  M as MindMapBlock,
5
5
  a as MindMapViewer
package/dist/mindmap.js CHANGED
@@ -8,7 +8,7 @@ import { T as TextStyle, H as Highlight, M as MindMap, a as MindMapTopic, b as M
8
8
  import { c as createMindMapController } from "./chunks/mind-map-controller-B6SxK3GZ.js";
9
9
  import { b as useContentHost, u as unavailableAttachment } from "./chunks/host-C-V688Rq.js";
10
10
  import { u as useLatest, a as useReady } from "./chunks/hooks-C53Dp0pr.js";
11
- import { MindMapCanvas } from "./chunks/MindMapCanvas-D5XwjVH1.js";
11
+ import { MindMapCanvas } from "./chunks/MindMapCanvas-tkFBBs4g.js";
12
12
  const MindMapEditor = forwardRef(function MindMapEditor2(props, ref) {
13
13
  var _a, _b, _c;
14
14
  const latest = useLatest(props), host = useContentHost(), hostRef = useLatest(host), mount = useRef(null);
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { S } from "../chunks/SpreadsheetViewer-DN_QQGud.js";
2
+ import { S } from "../chunks/SpreadsheetViewer-DxCxIUx_.js";
3
3
  export {
4
4
  S as SpreadsheetViewer
5
5
  };
@@ -9,10 +9,10 @@
9
9
  }
10
10
  .ywiki-content .doc-callout {
11
11
  --callout-first-line-height:calc(var(--content-font-size) * var(--content-line-height));
12
- position:relative;display:grid;grid-template-columns:30px minmax(0,1fr);column-gap:12px;align-items:start;
13
- border:1px solid var(--callout-border,var(--callout-border-blue));border-radius:9px;
12
+ position:relative;display:grid;grid-template-columns:var(--content-callout-icon-width) minmax(0,1fr);column-gap:var(--content-callout-gap);align-items:start;
13
+ border:1px solid var(--callout-border,var(--callout-border-blue));border-radius:var(--content-callout-radius);
14
14
  background:var(--callout-fill,var(--doc-highlight-blue));color:var(--callout-text,var(--content-text-color));
15
- padding:16px 18px;
15
+ padding:var(--content-callout-padding-y) var(--content-callout-padding-x);
16
16
  }
17
17
  .ywiki-content .doc-callout[data-icon-hidden='true'] {grid-template-columns:minmax(0,1fr);}
18
18
  .callout-controls-host {display:contents;}
@@ -20,8 +20,8 @@
20
20
  .ywiki-content .doc-callout[data-icon-hidden='true']>.doc-callout-content {grid-column:1;}
21
21
  .ywiki-content .doc-callout .callout-icon {
22
22
  grid-column:1;grid-row:1;align-self:start;display:inline-flex;align-items:center;justify-content:center;
23
- width:30px;min-width:30px;height:var(--callout-first-line-height);min-height:0;padding:0;
24
- font-size:22px;line-height:1;user-select:none;color:inherit;
23
+ width:var(--content-callout-icon-width);min-width:var(--content-callout-icon-width);height:var(--callout-first-line-height);min-height:0;padding:0;
24
+ font-size:var(--content-callout-icon-size);line-height:1;user-select:none;color:inherit;
25
25
  }
26
26
  /* A heading on the first line has its own size and leading; later paragraphs do not move the icon. */
27
27
  .ywiki-content .doc-callout:has(>.doc-callout-content>h1:first-child){--callout-first-line-height:calc(var(--content-font-size) * 1.625 * 1.3);}
@@ -169,7 +169,7 @@
169
169
  font-size: var(--content-table-font-size);
170
170
  background: var(--color-surface);
171
171
  border: 1px solid var(--table-grid-color);
172
- border-radius: 6px;
172
+ border-radius: var(--content-table-radius);
173
173
  overflow: hidden;
174
174
  }
175
175
  .ywiki-content :where(.doc-table-wrap, .tableWrapper) {
@@ -182,7 +182,7 @@
182
182
  border: none;
183
183
  border-right: 1px solid var(--table-grid-color);
184
184
  border-bottom: 1px solid var(--table-grid-color);
185
- padding: 6px 8px;
185
+ padding: var(--content-table-padding-y) var(--content-table-padding-x);
186
186
  line-height: var(--content-table-line-height);
187
187
  min-width: 60px;
188
188
  text-align: left;
@@ -237,7 +237,7 @@
237
237
  * 因此同行几乎等高、右侧没有空白。
238
238
  */
239
239
  .ywiki-content .doc-image-gallery {
240
- gap: 12px;
240
+ gap: var(--content-gallery-gap);
241
241
  align-items: flex-start;
242
242
  }
243
243
  .ywiki-content .doc-image-gallery > .doc-image {
@@ -0,0 +1,29 @@
1
+ /* Generated from wendang/shared CONTENT_PRESENTATION. */
2
+ .wendang {
3
+ --content-font-size: 16px;
4
+ --content-line-height: 1.75;
5
+ --content-text-color: var(--color-text);
6
+ --content-heading-color: #101828;
7
+ --content-table-header-bg: #edf3fc;
8
+ --content-table-grid-color: #d5dfed;
9
+ --content-table-font-size: calc(var(--content-font-size) * 13 / 14);
10
+ --content-table-line-height: 1.5;
11
+ --content-table-radius: 6px;
12
+ --content-table-padding-x: 8px;
13
+ --content-table-padding-y: 6px;
14
+ --content-media-radius: 8px;
15
+ --content-gallery-gap: 12px;
16
+ --content-callout-radius: 9px;
17
+ --content-callout-padding-x: 18px;
18
+ --content-callout-padding-y: 16px;
19
+ --content-callout-icon-width: 30px;
20
+ --content-callout-icon-size: 22px;
21
+ --content-callout-gap: 12px;
22
+ --space-block: calc(var(--content-font-size) * 5 / 7);
23
+ --space-module: calc(var(--content-font-size) * 9 / 7);
24
+ --space-heading-top: calc(var(--content-font-size) * 2);
25
+ --space-heading-bottom: calc(var(--content-font-size) * 5 / 7);
26
+ --space-list-item: calc(var(--content-font-size) * 0.25);
27
+ --space-list-block: calc(var(--content-font-size) * 0.5);
28
+ --space-divider: calc(var(--content-font-size) * 2);
29
+ }
@@ -1,3 +1,5 @@
1
+ @import './content-tokens.css';
2
+
1
3
  .wendang {
2
4
  --color-bg: #f6f8fc; --color-surface: #fff; --color-surface-subtle: #f5f7fa;
3
5
  --color-text: #1f2937; --color-text-muted: #667085; --color-text-faint: #7c8798;
@@ -19,7 +21,6 @@
19
21
  --comment-mark-bg: #ffe58f; --comment-mark-line: #d48806;
20
22
  --comment-mark-bg-reply: #ffd66688; --comment-mark-line-reply: #ff9900;
21
23
  --comment-mark-bg-active: #ffc53d; --comment-mark-line-active: #ad6800;
22
- --content-font-size: 16px; --content-line-height: 1.75; --content-text-color: var(--color-text);
23
24
  --content-width: 100%; --shadow-pop: 0 10px 32px #14284a20;
24
25
  /*
25
26
  * 内容排版 token(表格、标题、间距、媒体)。
@@ -29,12 +30,6 @@
29
30
  * 无效值会让整条声明在计算值阶段失效,于是表格边框变成 none、表头背景
30
31
  * 变透明、段落与标题的间距塌成 0。颜色用绝对值,间距跟随 --content-font-size。
31
32
  */
32
- --content-heading-color: #101828;
33
- --content-table-header-bg: #edf3fc;
34
- --content-table-grid-color: #d5dfed;
35
- --content-table-font-size: calc(var(--content-font-size) * 13 / 14);
36
- --content-table-line-height: 1.5;
37
- --content-media-radius: 8px;
38
33
  --content-scroll-offset: 80px;
39
34
  /**
40
35
  * 块间距(段落之间)。
@@ -45,13 +40,6 @@
45
40
  * 可见的白缝——间距太小时这段预算不够,两个块的底色会糊成一整块
46
41
  * (用户实测:"带了选中背景后上下间距没了")。
47
42
  */
48
- --space-block: calc(var(--content-font-size) * 5 / 7);
49
- --space-module: calc(var(--content-font-size) * 9 / 7);
50
- --space-heading-top: calc(var(--content-font-size) * 2);
51
- --space-heading-bottom: calc(var(--content-font-size) * 5 / 7);
52
- --space-list-item: calc(var(--content-font-size) * 0.25);
53
- --space-list-block: calc(var(--content-font-size) * 0.5);
54
- --space-divider: calc(var(--content-font-size) * 2);
55
43
  --color-code-bg: #f1f5fa;
56
44
  color: var(--color-text); background: var(--color-surface);
57
45
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", sans-serif;