wendang-react 0.6.2 → 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.
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { C } from "../chunks/extensions-DMQedgOl.js";
2
+ import { C } from "../chunks/extensions-ByORRoRa.js";
3
3
  export {
4
4
  C as COLLAB_FIELD
5
5
  };
@@ -4,7 +4,7 @@ import { useRef, useState, useLayoutEffect } from "react";
4
4
  import { createPortal } from "react-dom";
5
5
  import { a as useContentContext } from "./host-C-V688Rq.js";
6
6
  import { p as placeAnchoredPopover } from "./popover-placement-D3xVYdkt.js";
7
- import { u as useLayer, L as LayerProvider, p as placePanel } from "./index-CqaMYb3A.js";
7
+ import { u as useLayer, L as LayerProvider, p as placePanel } from "./index-DdfMnva8.js";
8
8
  function AnchoredPanel({ anchor, onClose, align = "start", prefer = "below", gap = 8, label, role = "dialog", className = "", portal: portalOverride, children, onKeyDown }) {
9
9
  const context = useContentContext();
10
10
  const portal = typeof portalOverride === "function" ? portalOverride() : portalOverride !== void 0 ? portalOverride : context.portal;
@@ -2,7 +2,7 @@
2
2
  import { jsxs, jsx } from "react/jsx-runtime";
3
3
  import { useRef, useState, useEffect } from "react";
4
4
  import { b as useContentHost } from "./host-C-V688Rq.js";
5
- import { W as WSelect } from "./index-CqaMYb3A.js";
5
+ import { W as WSelect } from "./index-DdfMnva8.js";
6
6
  const options = [
7
7
  { value: "pdf", label: "PDF (.pdf)" },
8
8
  { value: "docx", label: "Word (.docx)" },
@@ -11,9 +11,9 @@ import { m as mindCanvasShortcut, s as selectMindTopic } from "./mind-map-input-
11
11
  import { b as useContentHost, a as useContentContext } from "./host-C-V688Rq.js";
12
12
  import { createPortal } from "react-dom";
13
13
  import { u as useLatest } from "./hooks-C53Dp0pr.js";
14
- import { a as WButton, c as WDialog, W as WSelect, d as WAlert } from "./index-CqaMYb3A.js";
15
- import { T as TopicLabel, A as AttachmentImage } from "./mind-topic-text-DYQR2Dzf.js";
16
- import { A as AnchoredPanel } from "./AnchoredPanel-CSXrveAT.js";
14
+ import { a as WButton, c as WDialog, W as WSelect, d as WAlert } from "./index-DdfMnva8.js";
15
+ import { T as TopicLabel, A as AttachmentImage } from "./mind-topic-text-DSyb95vL.js";
16
+ import { A as AnchoredPanel } from "./AnchoredPanel-Cv4RURwF.js";
17
17
  function mindMapDrop(model, drawing, id, point, allowSide = true) {
18
18
  const source = drawing.nodes.find((t) => t.id === id), root = drawing.nodes.find((t) => t.id === model.rootId);
19
19
  if (!source || !root || id === model.rootId) return null;
@@ -4,9 +4,9 @@ import { useState, useEffect, Suspense, useRef, lazy } from "react";
4
4
  import { readMindMap, mindMapOutline, MIND_MAP_PALETTE, layoutMindMap, mindRelationPaths } from "wendang/mindmap";
5
5
  import { MIND_TOPIC_FONT, mindTopicLineHeight, readableTextColor } from "wendang/shared";
6
6
  import { b as useContentHost } from "./host-C-V688Rq.js";
7
- import { a as WButton } from "./index-CqaMYb3A.js";
8
- import { T as TopicLabel, A as AttachmentImage } from "./mind-topic-text-DYQR2Dzf.js";
9
- const Canvas = lazy(() => import("./MindMapCanvas-I5M1SIyX.js").then((module) => ({ default: module.MindMapCanvas })));
7
+ import { a as WButton } from "./index-DdfMnva8.js";
8
+ import { T as TopicLabel, A as AttachmentImage } from "./mind-topic-text-DSyb95vL.js";
9
+ const Canvas = lazy(() => import("./MindMapCanvas-tkFBBs4g.js").then((module) => ({ default: module.MindMapCanvas })));
10
10
  function MindMapViewer({ value, modelValue, height, fetchAttachment }) {
11
11
  var _a;
12
12
  const model = value ?? modelValue;
@@ -3,7 +3,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useMemo } from "react";
4
4
  import { validateWorkbook } from "wendang/spreadsheet";
5
5
  import { p as previewAxes, a as previewMerges, c as columnName, b as cellStyleData, d as cellDisplay, s as safeColor } from "./worksheet-preview-DsDVWxIM.js";
6
- import { a as WButton } from "./index-CqaMYb3A.js";
6
+ import { a as WButton } from "./index-DdfMnva8.js";
7
7
  import { b as useContentHost } from "./host-C-V688Rq.js";
8
8
  function SpreadsheetViewer({ value, modelValue, allowExport = false, standalone = false, exportSnapshot, pageId }) {
9
9
  const host = useContentHost();
@@ -2,8 +2,8 @@
2
2
  import { jsxs, jsx } from "react/jsx-runtime";
3
3
  import { useState, useRef, useEffect } from "react";
4
4
  import { codeLanguageLabel, CODE_LANGUAGES, isKnownCodeLanguage } from "wendang/shared";
5
- import { a as WButton, W as WSelect, b as WIcon } from "./index-CqaMYb3A.js";
6
- import { A as AnchoredPanel } from "./AnchoredPanel-CSXrveAT.js";
5
+ import { a as WButton, W as WSelect, b as WIcon } from "./index-DdfMnva8.js";
6
+ import { A as AnchoredPanel } from "./AnchoredPanel-Cv4RURwF.js";
7
7
  import { b as useContentHost } from "./host-C-V688Rq.js";
8
8
  import { CODE_THEMES, codeLineCount } from "wendang/internal/code-block";
9
9
  function CodeToolbar({ text, language, editable, canCopy, display, onLanguage, onDisplay }) {
@@ -22,9 +22,9 @@ import { calloutDOMAttributes, effectiveCallout, CALLOUT_COLORS, CALLOUT_FILLS,
22
22
  import { closeHistory } from "@tiptap/pm/history";
23
23
  import { yUndoPluginKey, yCursorPlugin } from "@tiptap/y-tiptap";
24
24
  import { validCalloutAttrs } from "wendang/internal/callout";
25
- import { A as AnchoredPanel } from "./AnchoredPanel-CSXrveAT.js";
26
- import { a as WButton, b as WIcon } from "./index-CqaMYb3A.js";
27
- import { C as CodeToolbar, s as showCommentHint, h as hideCommentHint } from "./comment-hint-Coq1laiR.js";
25
+ import { A as AnchoredPanel } from "./AnchoredPanel-Cv4RURwF.js";
26
+ import { a as WButton, b as WIcon } from "./index-DdfMnva8.js";
27
+ import { C as CodeToolbar, s as showCommentHint, h as hideCommentHint } from "./comment-hint-B9qcrqvn.js";
28
28
  import CodeBlock from "@tiptap/extension-code-block";
29
29
  import { codeBlockDisplay, codeLineNumbers, codeBlockClass } from "wendang/internal/code-block";
30
30
  import { Node as Node$1, mergeAttributes, Extension } from "@tiptap/core";
@@ -283,6 +283,12 @@ const ICONS = {
283
283
  ["path", { d: "m9 11-6 6v3h9l3-3" }],
284
284
  ["path", { d: "m22 12-4.6 4.6a2 2 0 0 1-2.8 0l-5.2-5.2a2 2 0 0 1 0-2.8L14 4" }]
285
285
  ] },
286
+ "cell-fill": { els: [
287
+ ["path", { d: "M4 11 11 4l8 8-7 7a2 2 0 0 1-2.8 0l-5.2-5.2a2 2 0 0 1 0-2.8Z" }],
288
+ ["path", { d: "m8 3 4 4" }],
289
+ ["path", { d: "M5 11h13" }],
290
+ ["path", { d: "M21 14s2 2.2 2 3.5a2 2 0 0 1-4 0C19 16.2 21 14 21 14Z" }]
291
+ ] },
286
292
  // ---------------------------------------------------------------- 表格
287
293
  "table-row-plus": { els: [
288
294
  ["rect", { x: 3, y: 3, width: 18, height: 9, rx: 2 }],
@@ -6,7 +6,7 @@ import { a as useContentContext, b as useContentHost, f as formatBytes, c as att
6
6
  import { safeHref, documentColorAttributes } from "wendang/shared";
7
7
  import { normalizeVideoEmbed, videoSourceUrl, VIDEO_PROVIDER_LABELS, videoPlayerUrl } from "wendang/internal/video-embed";
8
8
  import { createPortal } from "react-dom";
9
- import { l as lockScroll, t as trapTab } from "./index-CqaMYb3A.js";
9
+ import { l as lockScroll, t as trapTab } from "./index-DdfMnva8.js";
10
10
  import { setMindTextMeasureFactory, MIND_TOPIC_FONT } from "wendang/internal/mind-topic-text";
11
11
  const ROW_SELECTOR = ".ywiki-image-gallery, .doc-image-gallery";
12
12
  function previewItemsFrom(image, fallbackLabel = "图片预览") {
@@ -5,13 +5,13 @@ import { resolveInlineComments, splitTextByMarks, safeHref, documentColorAttribu
5
5
  import { readMindMap } from "wendang/mindmap";
6
6
  import { isWorkbookDocument } from "wendang/spreadsheet";
7
7
  import { b as useContentHost } from "../chunks/host-C-V688Rq.js";
8
- import { M as MathView, V as VideoView, F as FileView, A as AttachmentImage } from "../chunks/mind-topic-text-DYQR2Dzf.js";
9
- import { M as MindMapBlock } from "../chunks/MindMapViewer-Nu3nEVHQ.js";
10
- import { S as SpreadsheetViewer } from "../chunks/SpreadsheetViewer-CLDlnWyM.js";
8
+ import { M as MathView, V as VideoView, F as FileView, A as AttachmentImage } from "../chunks/mind-topic-text-DSyb95vL.js";
9
+ import { M as MindMapBlock } from "../chunks/MindMapViewer-DJrryb2Y.js";
10
+ import { S as SpreadsheetViewer } from "../chunks/SpreadsheetViewer-DxCxIUx_.js";
11
11
  import { e as ensureCodeHighlight, c as codeTokens } from "../chunks/code-highlight-BmaqTe1m.js";
12
- import { h as hideCommentHint, s as showCommentHint, C as CodeToolbar } from "../chunks/comment-hint-Coq1laiR.js";
12
+ import { h as hideCommentHint, s as showCommentHint, C as CodeToolbar } from "../chunks/comment-hint-B9qcrqvn.js";
13
13
  import { codeBlockDisplay, codeLineNumbers, codeBlockClass } from "wendang/internal/code-block";
14
- import { D } from "../chunks/DocumentExportMenu-DgDXDChd.js";
14
+ import { D } from "../chunks/DocumentExportMenu-BrGipZ59.js";
15
15
  function CommentText({ marks, activeId, onMarkClick, children }) {
16
16
  return /* @__PURE__ */ jsx(
17
17
  "span",
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-DMQedgOl.js";
10
- import { C } from "./chunks/extensions-DMQedgOl.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-Nu3nEVHQ.js";
14
- import { p as previewItemsFrom, I as ImagePreview, V as VideoView } from "./chunks/mind-topic-text-DYQR2Dzf.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 { a as WButton, b as WIcon, l as lockScroll, t as trapTab, c as WDialog } from "./chunks/index-CqaMYb3A.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,7 +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-DgDXDChd.js";
31
+ import { D } from "./chunks/DocumentExportMenu-BrGipZ59.js";
32
32
  function linkHrefProblem(value) {
33
33
  const href = value.trim();
34
34
  if (!href) return "请输入链接地址。";
@@ -1496,6 +1496,110 @@ function placeTableMenu(anchor, menu, viewport) {
1496
1496
  maxHeight
1497
1497
  };
1498
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
+ }
1499
1603
  const CORNER_W = 44, CORNER_H = 26, GUTTER_GAP = 8;
1500
1604
  const anchorOf = (event) => {
1501
1605
  const rect = event.currentTarget.getBoundingClientRect();
@@ -1506,24 +1610,72 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1506
1610
  const { portal } = useContentContext(), axisCleanup = useRef(null);
1507
1611
  const [dismissed, setDismissed] = useState(false), [panel, setPanel] = useState("none");
1508
1612
  const [menuOpen, setMenuOpen] = useState(false), [menuScope, setMenuScope] = useState("table");
1613
+ const [menuFromToolbar, setMenuFromToolbar] = useState(false);
1509
1614
  const [showStyle, setShowStyle] = useState(false), [widthOpen, setWidthOpen] = useState(false), [width, setWidth] = useState(""), [busy, setBusy] = useState(false);
1510
1615
  const [toolbarSize, setToolbarSize] = useState({ width: 0, height: 0 });
1616
+ const [, setViewportRevision] = useState(0);
1511
1617
  const [menuAnchor, setMenuAnchor] = useState(null), [panelAnchor, setPanelAnchor] = useState(null);
1512
1618
  const menuRef = useRef(null), panelRef = useRef(null);
1619
+ const menuViewport = useRef(null), menuContent = useRef(null);
1620
+ const menuTrigger = useRef(null), panelTrigger = useRef(null);
1513
1621
  const [menuPlace, setMenuPlace] = useState({ left: 0, top: 0, maxHeight: 480 }), [panelPlace, setPanelPlace] = useState({ left: 0, top: 0 });
1514
- useEffect(() => {
1622
+ useLayoutEffect(() => {
1623
+ var _a2;
1515
1624
  if (!menuOpen || !menuAnchor) return;
1516
1625
  const element = menuRef.current;
1517
1626
  if (!element) return;
1518
- 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 }));
1519
1628
  }, [menuOpen, menuAnchor, widthOpen, showStyle, menuScope]);
1520
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(() => {
1521
1637
  if (panel === "none" || !panelAnchor) return;
1522
- const element = panelRef.current;
1523
- const card = { width: (element == null ? void 0 : element.offsetWidth) ?? 320, height: (element == null ? void 0 : element.offsetHeight) ?? 260 };
1524
- const placement = placeTableToolbar(panelAnchor, card, { width: innerWidth, height: innerHeight, topInset: 12 });
1525
- setPanelPlace({ left: placement.left, top: placement.top });
1526
- }, [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
+ }, []);
1527
1679
  const selectionRef = useRef(editor.state.selection), docRef = useRef(editor.state.doc);
1528
1680
  useEffect(() => {
1529
1681
  if (!selectionRef.current.eq(editor.state.selection) || docRef.current !== editor.state.doc) {
@@ -1559,6 +1711,8 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1559
1711
  selectTableCell(editor.view, pos);
1560
1712
  setPanel("none");
1561
1713
  setMenuScope("cell");
1714
+ setMenuFromToolbar(false);
1715
+ menuTrigger.current = null;
1562
1716
  setShowStyle(false);
1563
1717
  setMenuAnchor({ left: event.clientX, right: event.clientX, top: event.clientY, bottom: event.clientY });
1564
1718
  setMenuOpen(true);
@@ -1582,11 +1736,18 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1582
1736
  setMenuOpen(false);
1583
1737
  setPanel("none");
1584
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
+ };
1585
1744
  document.addEventListener("pointerdown", close, true);
1586
1745
  window.addEventListener("resize", resize);
1746
+ window.addEventListener("scroll", scroll, true);
1587
1747
  return () => {
1588
1748
  document.removeEventListener("pointerdown", close, true);
1589
1749
  window.removeEventListener("resize", resize);
1750
+ window.removeEventListener("scroll", scroll, true);
1590
1751
  };
1591
1752
  }, [menuOpen, panel]);
1592
1753
  function axisDown(axis, index, event) {
@@ -1644,13 +1805,16 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1644
1805
  }
1645
1806
  useEffect(() => {
1646
1807
  const escape = (event) => {
1808
+ var _a2, _b2;
1647
1809
  if (event.key !== "Escape" || event.isComposing) return;
1648
1810
  if (panel !== "none") {
1649
1811
  event.preventDefault();
1650
1812
  setPanel("none");
1813
+ (_a2 = panelTrigger.current) == null ? void 0 : _a2.focus({ preventScroll: true });
1651
1814
  } else if (menuOpen) {
1652
1815
  event.preventDefault();
1653
1816
  setMenuOpen(false);
1817
+ (_b2 = menuTrigger.current) == null ? void 0 : _b2.focus({ preventScroll: true });
1654
1818
  } else if (cellSelection) {
1655
1819
  event.preventDefault();
1656
1820
  setDismissed(true);
@@ -1698,12 +1862,22 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1698
1862
  } else setColor(panel === "color" ? "textStyle" : "highlight", value);
1699
1863
  }
1700
1864
  function showContext(event, scope = "table") {
1865
+ var _a2;
1701
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();
1702
1874
  if (scope === "table" && geometry) selectTableAxis(editor.view, geometry.cellPos, "table");
1875
+ const anchor = anchorOf(event);
1703
1876
  setPanel("none");
1704
1877
  setShowStyle(false);
1705
1878
  setMenuScope(scope);
1706
- 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 });
1707
1881
  setMenuOpen(true);
1708
1882
  }
1709
1883
  async function copyTable(cut) {
@@ -1738,6 +1912,8 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1738
1912
  setPanel("none");
1739
1913
  return;
1740
1914
  }
1915
+ panelTrigger.current = event.currentTarget;
1916
+ setMenuOpen(false);
1741
1917
  setPanelAnchor(anchorOf(event));
1742
1918
  setPanel(name);
1743
1919
  }
@@ -1798,7 +1974,7 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1798
1974
  if (!disabled) onClick();
1799
1975
  },
1800
1976
  children: [
1801
- /* @__PURE__ */ jsx(WIcon, { name: icon, size: 18 }),
1977
+ /* @__PURE__ */ jsx(WIcon, { name: icon, size: ["bold", "italic", "strike", "underline"].includes(icon) ? 20 : 18 }),
1802
1978
  extra
1803
1979
  ]
1804
1980
  }
@@ -1822,6 +1998,7 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1822
1998
  if (pos !== null) onBlockDrag == null ? void 0 : onBlockDrag(pos, event.nativeEvent, () => {
1823
1999
  selectTableAxis(editor.view, geometry.cellPos, "table");
1824
2000
  setMenuScope("table");
2001
+ setMenuFromToolbar(false);
1825
2002
  setShowStyle(false);
1826
2003
  setMenuAnchor(anchor);
1827
2004
  setMenuOpen(true);
@@ -1895,7 +2072,7 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1895
2072
  ] }),
1896
2073
  selection && /* @__PURE__ */ jsxs(Fragment, { children: [
1897
2074
  /* @__PURE__ */ jsx("div", { className: "tbl-selection", style: { left: selection.left, top: selection.top, width: selection.width, height: selection.height } }),
1898
- !menuOpen && /* @__PURE__ */ jsx(
2075
+ (!menuOpen || menuFromToolbar) && /* @__PURE__ */ jsx(
1899
2076
  "button",
1900
2077
  {
1901
2078
  type: "button",
@@ -1915,7 +2092,7 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1915
2092
  children: "···"
1916
2093
  }
1917
2094
  ),
1918
- cellSelection && !dismissed && !menuOpen && /* @__PURE__ */ jsx(
2095
+ cellSelection && !dismissed && (!menuOpen || menuFromToolbar) && /* @__PURE__ */ jsx(
1919
2096
  "div",
1920
2097
  {
1921
2098
  className: "tbl-cellbar",
@@ -1959,7 +2136,7 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
1959
2136
  item.key === "color" ? /* @__PURE__ */ jsxs(Fragment, { children: [
1960
2137
  "A",
1961
2138
  /* @__PURE__ */ jsx(WIcon, { name: "chevron-down", size: 12 })
1962
- ] }) : 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 }),
1963
2140
  /* @__PURE__ */ jsx("span", { className: "color-bar", style: { background: item.current ?? "transparent" }, "aria-hidden": "true" })
1964
2141
  ]
1965
2142
  },
@@ -2014,13 +2191,25 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
2014
2191
  "div",
2015
2192
  {
2016
2193
  ref: menuRef,
2017
- className: "tbl-ctx",
2018
- 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 },
2019
2196
  role: "menu",
2020
2197
  "aria-label": "表格操作菜单",
2021
- onMouseDown: (event) => event.preventDefault(),
2198
+ onMouseDown: (event) => {
2199
+ if (!(event.target instanceof HTMLInputElement)) event.preventDefault();
2200
+ },
2022
2201
  onContextMenu: (event) => event.preventDefault(),
2023
- 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: [
2024
2213
  menuItem("columns", "均分列宽", distribute),
2025
2214
  menuItem("palette", "表格样式", () => setShowStyle(!showStyle), { expanded: showStyle }),
2026
2215
  showStyle && /* @__PURE__ */ jsxs("div", { className: "ctx-styles", "aria-label": "表头样式", children: [
@@ -2158,7 +2347,7 @@ function TableControls({ editor, hover, revision, onNotice, onBlockDrag }) {
2158
2347
  chain().deleteTable().run();
2159
2348
  setMenuOpen(false);
2160
2349
  }, { danger: true })
2161
- ] })
2350
+ ] }) }) })
2162
2351
  }
2163
2352
  )
2164
2353
  ] }), portal)
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { M, a } from "../chunks/MindMapViewer-Nu3nEVHQ.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-I5M1SIyX.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-CLDlnWyM.js";
2
+ import { S } from "../chunks/SpreadsheetViewer-DxCxIUx_.js";
3
3
  export {
4
4
  S as SpreadsheetViewer
5
5
  };
package/dist/styles.css CHANGED
@@ -1872,6 +1872,31 @@
1872
1872
  .wd-dialog__body { padding: 4px 18px 20px; }
1873
1873
  .wd-dialog__footer { padding: 0 18px 16px; }
1874
1874
  }
1875
+ .w-overlay-scrollbar { overflow: hidden; }
1876
+ .w-overlay-scrollbar__viewport {
1877
+ overflow: auto; overscroll-behavior: contain; scrollbar-width: none; min-height: 0;
1878
+ box-sizing: border-box; padding: 6px; overflow-anchor: none;
1879
+ }
1880
+ .w-overlay-scrollbar__viewport::-webkit-scrollbar { display: none; width: 0; height: 0; }
1881
+ .w-overlay-scrollbar__track {
1882
+ position: absolute; top: 5px; right: 2px; bottom: 5px; z-index: 1; width: 10px;
1883
+ opacity: 0; transition: opacity .15s; touch-action: none; cursor: default;
1884
+ }
1885
+ .w-overlay-scrollbar__track[hidden] { display: none; }
1886
+ .w-overlay-scrollbar:hover > .w-overlay-scrollbar__track,
1887
+ .w-overlay-scrollbar:focus-within > .w-overlay-scrollbar__track,
1888
+ .w-overlay-scrollbar.is-scrolling > .w-overlay-scrollbar__track { opacity: 1; }
1889
+ .w-overlay-scrollbar__thumb {
1890
+ position: absolute; top: 0; right: 2px; width: 6px; border-radius: 999px; touch-action: none;
1891
+ background: color-mix(in srgb, var(--color-text-muted) 42%, transparent); cursor: grab;
1892
+ }
1893
+ .w-overlay-scrollbar__thumb:hover,
1894
+ .w-overlay-scrollbar.is-dragging-scrollbar .w-overlay-scrollbar__thumb {
1895
+ background: color-mix(in srgb, var(--color-text-muted) 66%, transparent);
1896
+ }
1897
+ .w-overlay-scrollbar.is-dragging-scrollbar .w-overlay-scrollbar__thumb { cursor: grabbing; }
1898
+ .w-overlay-scrollbar__thumb:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 1px; }
1899
+ @media (prefers-reduced-motion: reduce) { .w-overlay-scrollbar__track { transition: none; } }
1875
1900
  .mind-inline { height:100%; min-height:380px; }
1876
1901
  .mind-inline .mind-map-workspace { height:100%; padding:0; }
1877
1902
  .mind-canvas-title { display: inline-flex; align-items: center; gap: 14px; max-width: calc(100vw - 110px); }
@@ -2518,7 +2543,6 @@
2518
2543
  .tool:hover { background:var(--color-surface-subtle); }
2519
2544
  .tool.on { background:var(--color-accent-soft); color:var(--color-accent); }
2520
2545
  .tool[aria-disabled='true'] { opacity:.3; cursor:not-allowed; }
2521
- .fill-icon { width:16px; height:16px; border:1px solid currentColor; border-radius:3px; background-color:transparent; }
2522
2546
  .color-tool { position:relative; padding-bottom:2px; }
2523
2547
  .color-bar { position:absolute; left:8px; right:8px; bottom:3px; height:2px; border-radius:1px; box-shadow:0 0 0 1px var(--color-surface); }
2524
2548
  .tool-sep { flex:0 0 1px; height:20px; background:var(--color-border); margin:0 4px; }
@@ -2537,7 +2561,7 @@
2537
2561
  .swatch .glyph { display:flex; align-items:center; justify-content:center; width:100%; height:100%; font-size:15px; font-weight:500; line-height:1; border-radius:0; }
2538
2562
  .swatch:hover { border-color:var(--color-accent); }
2539
2563
  .swatch.selected { border-color:var(--color-accent); box-shadow:0 0 0 1px var(--color-accent); }
2540
- .tbl-ctx { z-index:80; padding:4px; background:var(--color-surface); border:1px solid var(--color-border); border-radius:8px; box-shadow:var(--shadow-pop); }
2564
+ .tbl-ctx { z-index:80; padding:0; box-sizing:border-box; background:var(--color-surface); border:1px solid var(--color-border); border-radius:8px; box-shadow:var(--shadow-pop); }
2541
2565
  /* 菜单项:与 Vue 的 TableContextMenu.vue 同尺寸与间距。 */
2542
2566
  .ctx-item { display:flex; align-items:center; gap:8px; width:100%; border:none; background:transparent; min-height:32px; padding:7px 10px; border-radius:6px; color:var(--color-text); cursor:pointer; text-align:left; font:inherit; font-size:13px; }
2543
2567
  .ctx-item:hover { background:var(--color-surface-subtle); }
@@ -0,0 +1,4 @@
1
+ export declare function attachOverlayScrollbar(host: HTMLElement, viewport: HTMLElement, content: HTMLElement): {
2
+ update: () => void;
3
+ destroy(): void;
4
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wendang-react",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "Wendang 原生 React 文档、工作表和思维导图编辑与展示组件。",
5
5
  "type": "module",
6
6
  "license": "MIT",