wendang-react 0.6.2 → 0.6.4

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 (119) hide show
  1. package/NOTICE.md +1 -1
  2. package/README.md +105 -0
  3. package/dist/bindings/yjs.js +1 -5
  4. package/dist/chunks/AnchoredPanel-C7jMoPze.js +1 -0
  5. package/dist/chunks/DocumentExportMenu-CUMsgq3w.js +2 -0
  6. package/dist/chunks/Dropdown-D98tXfe0.js +3 -0
  7. package/dist/chunks/MindMapCanvas-CVXQXNOg.js +163 -0
  8. package/dist/chunks/MindMapViewer-BI8zbQM1.js +13 -0
  9. package/dist/chunks/SpreadsheetViewer-CoQ4VIgj.js +23 -0
  10. package/dist/chunks/code-highlight-BmaqTe1m.js +1 -30
  11. package/dist/chunks/code-highlight-engine-BFDzDPzy.js +1 -40
  12. package/dist/chunks/comment-hint-BhUxKjKK.js +14 -0
  13. package/dist/chunks/composition-state-Bl-U1R_2.js +1 -40
  14. package/dist/chunks/extensions-C1fCBnEs.js +14 -0
  15. package/dist/chunks/fuzzy-match-DYQR-4w2.js +1 -89
  16. package/dist/chunks/hooks-C53Dp0pr.js +1 -35
  17. package/dist/chunks/i18n-B0kCsIjc.js +2 -0
  18. package/dist/chunks/index-COeA2QcQ.js +15 -0
  19. package/dist/chunks/katex-WjrodtTU.js +1 -71
  20. package/dist/chunks/locale-DWpIJ_9X.js +1 -0
  21. package/dist/chunks/mind-map-controller-Ce76mETT.js +1 -0
  22. package/dist/chunks/mind-map-delete-CVsxdXfs.js +1 -31
  23. package/dist/chunks/mind-map-input-CEWRz_t6.js +1 -43
  24. package/dist/chunks/mind-topic-text-Bn1waxff.js +31 -0
  25. package/dist/chunks/popover-placement-D3xVYdkt.js +1 -47
  26. package/dist/chunks/worksheet-engine-c84sdD4N.js +1 -0
  27. package/dist/chunks/worksheet-preview-DsDVWxIM.js +1 -129
  28. package/dist/document/viewer.js +30 -289
  29. package/dist/document.js +120 -3622
  30. package/dist/export/json.js +1 -5
  31. package/dist/export/markdown.js +1 -2
  32. package/dist/export/mindmap.js +1 -2
  33. package/dist/export/pdf.js +1 -6
  34. package/dist/export/word.js +1 -2
  35. package/dist/export.js +1 -2
  36. package/dist/i18n.js +1 -0
  37. package/dist/index.js +1 -8
  38. package/dist/locales/en-US.js +1 -0
  39. package/dist/locales/es-ES.js +1 -0
  40. package/dist/locales/ja-JP.js +1 -0
  41. package/dist/locales/ko-KR.js +1 -0
  42. package/dist/locales/zh-CN.js +1 -0
  43. package/dist/locales/zh-TW.js +1 -0
  44. package/dist/mindmap/viewer.js +1 -6
  45. package/dist/mindmap.js +3 -123
  46. package/dist/shared.js +1 -52
  47. package/dist/spreadsheet/viewer.js +1 -5
  48. package/dist/spreadsheet/xlsx.js +1 -299
  49. package/dist/spreadsheet.js +2 -120
  50. package/dist/styles/callout.css +1 -34
  51. package/dist/styles/code-block.css +1 -58
  52. package/dist/styles/content-style.css +1 -619
  53. package/dist/styles/content-tokens.css +1 -29
  54. package/dist/styles/editor-interaction.css +1 -621
  55. package/dist/styles/file-video.css +1 -12
  56. package/dist/styles/image-preview.css +1 -103
  57. package/dist/styles/mind-map-block.css +1 -14
  58. package/dist/styles/mind-map-canvas.css +1 -80
  59. package/dist/styles/mind-map-comments.css +1 -93
  60. package/dist/styles/mind-map-details.css +1 -7
  61. package/dist/styles/mind-map-preview.css +1 -7
  62. package/dist/styles/mind-map-topic.css +1 -112
  63. package/dist/styles/page-picker.css +1 -47
  64. package/dist/styles/renderer.css +1 -45
  65. package/dist/styles/spreadsheet-editor.css +1 -3
  66. package/dist/styles/tokens.css +1 -142
  67. package/dist/styles/video-dialog.css +1 -41
  68. package/dist/styles/video-embed.css +1 -35
  69. package/dist/styles.css +1 -2631
  70. package/dist/types/editor/BlockAffordance.d.ts +5 -2
  71. package/dist/types/editor/CalloutView.d.ts +2 -1
  72. package/dist/types/editor/ImagePreview.d.ts +1 -1
  73. package/dist/types/editor/PagePicker.d.ts +1 -1
  74. package/dist/types/editor/extensions.d.ts +4 -1
  75. package/dist/types/engine/editor/block-commands.d.ts +1 -1
  76. package/dist/types/engine/editor/block-menu-hover.d.ts +16 -0
  77. package/dist/types/engine/editor/extensions/locale.d.ts +3 -0
  78. package/dist/types/engine/editor/nodes/image-nodeview.d.ts +1 -1
  79. package/dist/types/engine/host.d.ts +60 -2
  80. package/dist/types/engine/renderer/attachments.d.ts +3 -3
  81. package/dist/types/engine/shared/video-feedback.d.ts +1 -1
  82. package/dist/types/engine/worksheets/worksheet-engine.d.ts +1 -0
  83. package/dist/types/engine/worksheets/worksheet-xlsx.d.ts +6 -1
  84. package/dist/types/engine/wui/core/overlay-scrollbar.d.ts +4 -0
  85. package/dist/types/host-types.d.ts +2 -60
  86. package/dist/types/host.d.ts +8 -1
  87. package/dist/types/i18n.d.ts +3 -0
  88. package/dist/types/index.d.ts +2 -0
  89. package/dist/types/locales/en-US.d.ts +1 -0
  90. package/dist/types/locales/es-ES.d.ts +1 -0
  91. package/dist/types/locales/ja-JP.d.ts +1 -0
  92. package/dist/types/locales/ko-KR.d.ts +1 -0
  93. package/dist/types/locales/zh-CN.d.ts +1 -0
  94. package/dist/types/locales/zh-TW.d.ts +1 -0
  95. package/dist/types/spreadsheet/xlsx.d.ts +1 -1
  96. package/dist/types/wui/Dropdown.d.ts +2 -1
  97. package/dist/types/wui/index.d.ts +2 -1
  98. package/integrity.json +3135 -0
  99. package/package.json +15 -5
  100. package/verify-integrity.mjs +138 -0
  101. package/dist/chunks/AnchoredPanel-CSXrveAT.js +0 -68
  102. package/dist/chunks/DocumentExportMenu-DgDXDChd.js +0 -75
  103. package/dist/chunks/MindMapCanvas-I5M1SIyX.js +0 -2090
  104. package/dist/chunks/MindMapViewer-Nu3nEVHQ.js +0 -180
  105. package/dist/chunks/SpreadsheetViewer-CLDlnWyM.js +0 -163
  106. package/dist/chunks/comment-hint-Coq1laiR.js +0 -296
  107. package/dist/chunks/extensions-DMQedgOl.js +0 -4210
  108. package/dist/chunks/host-C-V688Rq.js +0 -197
  109. package/dist/chunks/index-CqaMYb3A.js +0 -720
  110. package/dist/chunks/mind-map-controller-B6SxK3GZ.js +0 -479
  111. package/dist/chunks/mind-topic-text-DYQR2Dzf.js +0 -446
  112. package/dist/chunks/nodes-iKqTGr_N.js +0 -291
  113. package/dist/chunks/worksheet-engine-TJ54m0KC.js +0 -125
  114. package/third-party-notices/wendang-export@0.6.0-NOTICE.md.txt +0 -51
  115. package/third-party-notices/wendang-export@0.6.1-LICENSE.txt +0 -21
  116. package/third-party-notices/wendang-export@0.6.2-LICENSE.txt +0 -21
  117. package/third-party-notices/wendang-export@0.6.2-NOTICE.md.txt +0 -70
  118. /package/third-party-notices/{wendang-export@0.6.0-LICENSE.txt → wendang-export@0.6.3-LICENSE.txt} +0 -0
  119. /package/third-party-notices/{wendang-export@0.6.1-NOTICE.md.txt → wendang-export@0.6.3-NOTICE.md.txt} +0 -0
@@ -1,180 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useState, useEffect, Suspense, useRef, lazy } from "react";
4
- import { readMindMap, mindMapOutline, MIND_MAP_PALETTE, layoutMindMap, mindRelationPaths } from "wendang/mindmap";
5
- import { MIND_TOPIC_FONT, mindTopicLineHeight, readableTextColor } from "wendang/shared";
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 })));
10
- function MindMapViewer({ value, modelValue, height, fetchAttachment }) {
11
- var _a;
12
- const model = value ?? modelValue;
13
- const root = useRef(null), [width, setWidth] = useState(900);
14
- useEffect(() => {
15
- const node = root.current;
16
- if (!node || typeof ResizeObserver === "undefined") return;
17
- setWidth(node.clientWidth || 900);
18
- const observer = new ResizeObserver((entries) => {
19
- var _a2;
20
- return setWidth(((_a2 = entries[0]) == null ? void 0 : _a2.contentRect.width) || 900);
21
- });
22
- observer.observe(node);
23
- return () => observer.disconnect();
24
- }, []);
25
- if (!model) return /* @__PURE__ */ jsx("p", { role: "alert", children: "思维导图格式无效" });
26
- const drawing = layoutMindMap(model), relations = mindRelationPaths(model, drawing);
27
- const color = MIND_MAP_PALETTE[model.theme];
28
- const previewHeight = height ?? model.height;
29
- const scale = Math.min(1, (previewHeight - 30) / drawing.bounds.height, Math.max(100, width - 24) / drawing.bounds.width);
30
- return /* @__PURE__ */ jsx(
31
- "div",
32
- {
33
- ref: root,
34
- className: "mind-preview-wrap",
35
- style: { height: previewHeight },
36
- role: "group",
37
- "aria-label": ((_a = model.topics.find((topic) => topic.id === model.rootId)) == null ? void 0 : _a.text) || "思维导图",
38
- children: /* @__PURE__ */ jsx("div", { className: "mind-preview-sized", style: { width: drawing.bounds.width * scale, height: drawing.bounds.height * scale }, children: /* @__PURE__ */ jsxs("div", { className: "mind-preview-scene", style: { width: drawing.bounds.width, height: drawing.bounds.height, transform: `scale(${scale})` }, children: [
39
- /* @__PURE__ */ jsxs(
40
- "svg",
41
- {
42
- className: "mind-preview-lines",
43
- width: drawing.bounds.width,
44
- height: drawing.bounds.height,
45
- viewBox: `${drawing.bounds.x} ${drawing.bounds.y} ${drawing.bounds.width} ${drawing.bounds.height}`,
46
- children: [
47
- drawing.edges.map((edge) => /* @__PURE__ */ jsx("path", { d: edge.path, fill: "none", stroke: color, strokeWidth: 2 }, edge.id)),
48
- relations.map((relation) => /* @__PURE__ */ jsxs("g", { children: [
49
- /* @__PURE__ */ jsx("path", { d: relation.path, fill: "none", stroke: "#9a68d4", strokeWidth: 2, strokeDasharray: "6 4" }),
50
- /* @__PURE__ */ jsx("text", { x: relation.x, y: relation.y, fontSize: 12, fill: "#9a68d4", children: relation.label || { related: "相关", depends: "依赖", reference: "参考" }[relation.kind] })
51
- ] }, relation.id))
52
- ]
53
- }
54
- ),
55
- drawing.nodes.map((topic) => /* @__PURE__ */ jsxs(
56
- "div",
57
- {
58
- className: `mind-preview-topic ${topic.id === model.rootId ? "root" : ""} ${topic.shape === "text" ? "text" : ""}`,
59
- style: {
60
- left: topic.x - drawing.bounds.x,
61
- top: topic.y - drawing.bounds.y,
62
- width: topic.width,
63
- minHeight: topic.height,
64
- fontFamily: MIND_TOPIC_FONT,
65
- borderRadius: topic.shape === "pill" ? 28 : void 0,
66
- background: topic.shape === "text" ? "transparent" : topic.background || void 0,
67
- color: topic.color || (topic.shape === "text" ? "var(--color-text)" : topic.background ? readableTextColor(topic.background) : void 0),
68
- fontSize: topic.fontSize || 14,
69
- textAlign: topic.align || "center",
70
- "--mind-color": color
71
- },
72
- children: [
73
- (topic.icon || topic.done) && /* @__PURE__ */ jsxs("span", { className: "mind-preview-icon", children: [
74
- topic.done ? "☑ " : "",
75
- topic.icon
76
- ] }),
77
- /* @__PURE__ */ jsx("span", { className: "mind-preview-title", style: { minHeight: topic.lines.length * mindTopicLineHeight(topic.fontSize || 14), lineHeight: `${mindTopicLineHeight(topic.fontSize || 14)}px` }, children: /* @__PURE__ */ jsx(TopicLabel, { topic }) }),
78
- topic.description && /* @__PURE__ */ jsx("span", { className: "mind-preview-description", children: topic.description }),
79
- topic.note && /* @__PURE__ */ jsx("span", { className: "mind-preview-note", title: topic.note, children: "▤ 备注" }),
80
- topic.attachmentId && /* @__PURE__ */ jsx("div", { className: "mind-preview-image", children: /* @__PURE__ */ jsx(AttachmentImage, { id: topic.attachmentId, alt: "主题图片", fetcher: fetchAttachment }) })
81
- ]
82
- },
83
- topic.id
84
- ))
85
- ] }) })
86
- }
87
- );
88
- }
89
- function MindMapBlock(props) {
90
- const host = useContentHost(), c = props.controller;
91
- const [open, setOpen] = useState(false), [outline, setOutline] = useState(false), [openComments, setOpenComments] = useState(false), [, update] = useState(0);
92
- const node = props.node ?? props.value ?? props.modelValue;
93
- const model = c ? c.snapshot() : node ? readMindMap(node) : null;
94
- const editable = (c == null ? void 0 : c.editable()) ?? false;
95
- const rows = model ? mindMapOutline(model) : [];
96
- function show() {
97
- if (model) {
98
- setOpen(true);
99
- if (c == null ? void 0 : c.context.viewState) c.context.viewState.openId = model.id;
100
- }
101
- }
102
- function close() {
103
- setOpen(false);
104
- setOpenComments(false);
105
- const state = c == null ? void 0 : c.context.viewState;
106
- if (state && state.openId === (model == null ? void 0 : model.id)) state.openId = null;
107
- }
108
- useEffect(() => {
109
- const stop = c == null ? void 0 : c.subscribe(() => {
110
- update((value) => value + 1);
111
- if (!c.snapshot()) setOpen(false);
112
- });
113
- return () => {
114
- stop == null ? void 0 : stop();
115
- };
116
- }, [c]);
117
- useEffect(() => {
118
- var _a;
119
- if (((_a = c == null ? void 0 : c.context.viewState) == null ? void 0 : _a.openId) === (model == null ? void 0 : model.id)) show();
120
- if (!host.location || !model) return;
121
- const linked = () => {
122
- const params = new URLSearchParams(host.location.current().replace(/^#/, ""));
123
- if (params.get("mind") === model.id && params.has("topic")) show();
124
- };
125
- linked();
126
- return host.location.subscribe(linked);
127
- }, [host.location, model == null ? void 0 : model.id, c]);
128
- if (!model) return /* @__PURE__ */ jsx("p", { role: "alert", children: "思维导图格式无效" });
129
- return /* @__PURE__ */ jsxs(
130
- "section",
131
- {
132
- className: "mind-map-block",
133
- "aria-label": "思维导图",
134
- style: { "--mind-color": MIND_MAP_PALETTE[model.theme] },
135
- onDoubleClick: (event) => {
136
- event.stopPropagation();
137
- show();
138
- },
139
- children: [
140
- /* @__PURE__ */ jsxs("header", { className: "mind-map-block-header", children: [
141
- /* @__PURE__ */ jsxs("span", { className: "mind-map-block-label", children: [
142
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "⌘" }),
143
- " 思维导图 ",
144
- /* @__PURE__ */ jsxs("span", { className: "mind-map-topic-count", children: [
145
- model.topics.length,
146
- " 个主题"
147
- ] })
148
- ] }),
149
- /* @__PURE__ */ jsxs("div", { className: "mind-map-block-actions", children: [
150
- host.comments && props.pageId && /* @__PURE__ */ jsx(WButton, { variant: "text", onClick: () => {
151
- setOpenComments(true);
152
- show();
153
- }, children: editable ? "讨论" : "查看讨论" }),
154
- /* @__PURE__ */ jsx(WButton, { variant: "text", onClick: () => setOutline(!outline), children: outline ? "查看导图" : "文字大纲" }),
155
- /* @__PURE__ */ jsx(WButton, { variant: "text", onClick: show, children: editable ? "编辑导图" : "放大查看" })
156
- ] })
157
- ] }),
158
- outline ? /* @__PURE__ */ jsx("div", { className: "mind-map-preview-outline", style: { maxHeight: model.height }, children: rows.map((row) => /* @__PURE__ */ jsx("div", { style: { paddingLeft: Math.min(row.depth, 20) * 18 }, children: row.text || "未命名主题" }, row.id)) }) : /* @__PURE__ */ jsx(MindMapViewer, { value: model, fetchAttachment: props.fetchAttachment ?? (c == null ? void 0 : c.context.fetchAttachment) }),
159
- open && /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("p", { role: "status", children: "正在加载导图…" }), children: /* @__PURE__ */ jsx(
160
- Canvas,
161
- {
162
- model,
163
- controller: c,
164
- pageId: props.pageId,
165
- canComment: props.canComment,
166
- allowExport: props.allowExport,
167
- fetchAttachment: props.fetchAttachment,
168
- openComments,
169
- onCommentsChanged: props.onCommentsChanged,
170
- onClose: close
171
- }
172
- ) })
173
- ]
174
- }
175
- );
176
- }
177
- export {
178
- MindMapBlock as M,
179
- MindMapViewer as a
180
- };
@@ -1,163 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useState, useEffect, useMemo } from "react";
4
- import { validateWorkbook } from "wendang/spreadsheet";
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";
7
- import { b as useContentHost } from "./host-C-V688Rq.js";
8
- function SpreadsheetViewer({ value, modelValue, allowExport = false, standalone = false, exportSnapshot, pageId }) {
9
- const host = useContentHost();
10
- const [sheetId, setSheetId] = useState(""), [row, setRow] = useState(0), [column, setColumn] = useState(0), [showAll, setShowAll] = useState(false), [error, setError] = useState("");
11
- const [exporting, setExporting] = useState(false);
12
- useEffect(() => {
13
- setRow(0);
14
- setColumn(0);
15
- }, [value, modelValue, showAll, sheetId]);
16
- const parsed = useMemo(() => {
17
- try {
18
- return { doc: validateWorkbook(value ?? modelValue), error: "" };
19
- } catch (error2) {
20
- return { doc: null, error: String(error2) };
21
- }
22
- }, [value, modelValue]);
23
- if (!parsed.doc) return /* @__PURE__ */ jsx("p", { role: "alert", children: parsed.error });
24
- const doc = parsed.doc, allIds = doc.workbook.sheetOrder, ids = allIds.filter((id) => {
25
- var _a;
26
- return showAll || !((_a = doc.workbook.sheets[id]) == null ? void 0 : _a.hidden);
27
- });
28
- const sheet = doc.workbook.sheets[ids.includes(sheetId) ? sheetId : ids[0]];
29
- if (!sheet) return /* @__PURE__ */ jsx("section", { className: "worksheet-preview", "aria-label": "工作表只读预览", children: /* @__PURE__ */ jsxs("nav", { className: "sheet-tabs", "aria-label": "工作表页", children: [
30
- /* @__PURE__ */ jsx("span", { className: "sheet-note", children: "没有可见工作表" }),
31
- /* @__PURE__ */ jsx(WButton, { "aria-pressed": showAll, onClick: () => setShowAll(true), children: "查看全部行列表页" })
32
- ] }) });
33
- const axes = previewAxes(doc, sheet, showAll);
34
- const pageRows = 100, pageColumns = 50;
35
- const rowStart = Math.min(row, Math.floor(Math.max(0, axes.rows.length - 1) / pageRows) * pageRows);
36
- const colStart = Math.min(column, Math.floor(Math.max(0, axes.columns.length - 1) / pageColumns) * pageColumns);
37
- const rows = axes.rows.slice(rowStart, rowStart + pageRows), columns = axes.columns.slice(colStart, colStart + pageColumns), merges = previewMerges(sheet, rows, columns);
38
- const dimension = (raw, fallback, upper = 600) => {
39
- const value2 = Number(raw);
40
- return Number.isFinite(value2) && value2 > 0 ? Math.min(Math.max(value2, 12), upper) : fallback;
41
- };
42
- const cellStyle = (r, c) => {
43
- var _a, _b;
44
- const merge = merges.get(`${r}:${c}`), rr = (merge == null ? void 0 : merge.sourceRow) ?? r, cc = (merge == null ? void 0 : merge.sourceColumn) ?? c;
45
- const style = cellStyleData(doc, sheet, rr, cc);
46
- const border = (side) => {
47
- var _a2;
48
- const raw = (_a2 = style.bd) == null ? void 0 : _a2[side];
49
- if (!(raw == null ? void 0 : raw.s)) return void 0;
50
- const line = raw.s === 7 ? "double" : [3, 4, 5, 6, 9, 10, 11, 12].includes(raw.s) ? "dashed" : "solid";
51
- return `${raw.s === 13 ? 3 : raw.s >= 7 ? 2 : 1}px ${line} ${safeColor(raw.cl) ?? "currentColor"}`;
52
- };
53
- return {
54
- color: safeColor(style.cl),
55
- backgroundColor: safeColor(style.bg),
56
- fontWeight: style.bl === 1 ? "bold" : void 0,
57
- fontStyle: style.it === 1 ? "italic" : void 0,
58
- fontSize: typeof style.fs === "number" ? `${dimension(style.fs, 11, 72)}pt` : void 0,
59
- textDecoration: [((_a = style.ul) == null ? void 0 : _a.s) === 1 ? "underline" : "", ((_b = style.st) == null ? void 0 : _b.s) === 1 ? "line-through" : ""].filter(Boolean).join(" ") || void 0,
60
- textAlign: style.ht === 2 ? "center" : style.ht === 3 ? "right" : void 0,
61
- verticalAlign: style.vt === 2 ? "middle" : style.vt === 3 ? "bottom" : "top",
62
- whiteSpace: style.tb === 3 ? "pre-wrap" : "pre",
63
- borderTop: border("t"),
64
- borderBottom: border("b"),
65
- borderLeft: border("l"),
66
- borderRight: border("r")
67
- };
68
- };
69
- async function exportFile() {
70
- if (!allowExport || exporting) return;
71
- setExporting(true);
72
- setError("");
73
- try {
74
- if (host.exports) {
75
- await host.exports.request({ kind: "spreadsheet", format: "xlsx", resourceId: pageId, blockId: doc.workbook.id });
76
- return;
77
- }
78
- const snapshot = exportSnapshot ? await exportSnapshot() : { title: doc.workbook.name, doc };
79
- const { exportXlsx } = await import("../spreadsheet/xlsx.js");
80
- const bytes = await exportXlsx(snapshot.doc);
81
- const url = URL.createObjectURL(new Blob([new Uint8Array(bytes)]));
82
- const a = document.createElement("a");
83
- a.href = url;
84
- a.download = `${snapshot.title || "工作表"}.xlsx`;
85
- a.click();
86
- setTimeout(() => URL.revokeObjectURL(url), 1e3);
87
- } catch (error2) {
88
- setError(String(error2));
89
- } finally {
90
- setExporting(false);
91
- }
92
- }
93
- return /* @__PURE__ */ jsxs("section", { className: `worksheet-preview${standalone ? " worksheet-preview-standalone" : ""}`, "aria-label": "工作表只读预览", children: [
94
- /* @__PURE__ */ jsxs("nav", { className: "sheet-tabs", "aria-label": "工作表页", children: [
95
- ids.map((id) => /* @__PURE__ */ jsxs(
96
- WButton,
97
- {
98
- role: "tab",
99
- variant: sheet.id === id ? "primary" : "text",
100
- "aria-selected": sheet.id === id,
101
- onClick: () => {
102
- setSheetId(id);
103
- setRow(0);
104
- setColumn(0);
105
- },
106
- children: [
107
- doc.workbook.sheets[id].name,
108
- doc.workbook.sheets[id].hidden ? "(隐藏)" : ""
109
- ]
110
- },
111
- id
112
- )),
113
- /* @__PURE__ */ jsx("span", { className: "sheet-note", children: "只读预览" }),
114
- /* @__PURE__ */ jsx(WButton, { "aria-pressed": showAll, onClick: () => setShowAll(!showAll), children: showAll ? "恢复保存视图" : "查看全部行列表页" }),
115
- allowExport && /* @__PURE__ */ jsx(WButton, { loading: exporting, onClick: () => void exportFile(), children: "导出 XLSX" })
116
- ] }),
117
- error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
118
- (axes.hasFilter || axes.hasHidden) && /* @__PURE__ */ jsx("p", { className: "sheet-view-note", role: "status", children: showAll ? "正在查看全部内容;仅改变本次预览。" : `按保存的隐藏与筛选状态显示${axes.filtered ? `,筛除 ${axes.filtered} 行` : ""}。` }),
119
- /* @__PURE__ */ jsx("div", { className: "sheet-table", tabIndex: 0, children: /* @__PURE__ */ jsxs("table", { children: [
120
- /* @__PURE__ */ jsxs("colgroup", { children: [
121
- /* @__PURE__ */ jsx("col", { style: { width: 40 } }),
122
- columns.map((c) => {
123
- var _a, _b;
124
- return /* @__PURE__ */ jsx("col", { style: { width: dimension((_b = (_a = sheet.columnData) == null ? void 0 : _a[c]) == null ? void 0 : _b.w, dimension(sheet.defaultColumnWidth, 100, 600), 600) } }, c);
125
- })
126
- ] }),
127
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
128
- /* @__PURE__ */ jsx("th", { "aria-label": "行号" }),
129
- columns.map((c) => /* @__PURE__ */ jsx("th", { children: columnName(c) }, c))
130
- ] }) }),
131
- /* @__PURE__ */ jsx("tbody", { children: rows.map((r) => {
132
- var _a, _b, _c, _d;
133
- return /* @__PURE__ */ jsxs("tr", { style: { height: dimension(((_b = (_a = sheet.rowData) == null ? void 0 : _a[r]) == null ? void 0 : _b.h) ?? ((_d = (_c = sheet.rowData) == null ? void 0 : _c[r]) == null ? void 0 : _d.ah), dimension(sheet.defaultRowHeight, 30, 600), 600) }, children: [
134
- /* @__PURE__ */ jsx("th", { children: r + 1 }),
135
- columns.map((c) => {
136
- var _a2, _b2;
137
- const merge = merges.get(`${r}:${c}`);
138
- if (merge == null ? void 0 : merge.hidden) return null;
139
- const rr = (merge == null ? void 0 : merge.sourceRow) ?? r, cc = (merge == null ? void 0 : merge.sourceColumn) ?? c, style = cellStyleData(doc, sheet, rr, cc);
140
- const display = cellDisplay((_b2 = (_a2 = sheet.cellData) == null ? void 0 : _a2[rr]) == null ? void 0 : _b2[cc], style);
141
- return /* @__PURE__ */ jsx("td", { rowSpan: merge == null ? void 0 : merge.rowspan, colSpan: merge == null ? void 0 : merge.colspan, title: display.note, style: cellStyle(r, c), children: display.text }, c);
142
- })
143
- ] }, r);
144
- }) })
145
- ] }) }),
146
- /* @__PURE__ */ jsxs("div", { className: "sheet-paging", children: [
147
- /* @__PURE__ */ jsxs("span", { children: [
148
- "第 ",
149
- rows.length ? `${rows[0] + 1}–${rows[rows.length - 1] + 1}` : "—",
150
- " 行 · ",
151
- columns.length ? `${columnName(columns[0])}–${columnName(columns[columns.length - 1])}` : "—",
152
- " 列 · 公式显示最近保存结果"
153
- ] }),
154
- /* @__PURE__ */ jsx(WButton, { disabled: rowStart === 0, onClick: () => setRow(Math.max(0, rowStart - pageRows)), children: "上一页行" }),
155
- /* @__PURE__ */ jsx(WButton, { disabled: rowStart + pageRows >= axes.rows.length, onClick: () => setRow(rowStart + pageRows), children: "下一页行" }),
156
- /* @__PURE__ */ jsx(WButton, { disabled: colStart === 0, onClick: () => setColumn(Math.max(0, colStart - pageColumns)), children: "上一页列" }),
157
- /* @__PURE__ */ jsx(WButton, { disabled: colStart + pageColumns >= axes.columns.length, onClick: () => setColumn(colStart + pageColumns), children: "下一页列" })
158
- ] })
159
- ] });
160
- }
161
- export {
162
- SpreadsheetViewer as S
163
- };
@@ -1,296 +0,0 @@
1
- "use client";
2
- import { jsxs, jsx } from "react/jsx-runtime";
3
- import { useState, useRef, useEffect } from "react";
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";
7
- import { b as useContentHost } from "./host-C-V688Rq.js";
8
- import { CODE_THEMES, codeLineCount } from "wendang/internal/code-block";
9
- function CodeToolbar({ text, language, editable, canCopy, display, onLanguage, onDisplay }) {
10
- const host = useContentHost();
11
- const [feedback, setFeedback] = useState(""), [copying, setCopying] = useState(false), [menu, setMenu] = useState(false);
12
- const [foldTip, setFoldTip] = useState(false), foldTrigger = useRef(null), hoverTimer = useRef(void 0);
13
- const trigger = useRef(null), menuRoot = useRef(null), timer = useRef(void 0);
14
- const alive = useRef(true), running = useRef(false), latest = useRef({ display, onDisplay, canCopy, text });
15
- latest.current = { display, onDisplay, canCopy, text };
16
- useEffect(() => {
17
- alive.current = true;
18
- return () => {
19
- alive.current = false;
20
- clearTimeout(timer.current);
21
- clearTimeout(hoverTimer.current);
22
- };
23
- }, []);
24
- useEffect(() => {
25
- var _a;
26
- try {
27
- const saved = (_a = host.preferences) == null ? void 0 : _a.get("code-theme");
28
- if (CODE_THEMES.some((item) => item.value === saved) && saved !== latest.current.display.theme)
29
- latest.current.onDisplay({ ...latest.current.display, theme: saved });
30
- } catch {
31
- }
32
- }, [host.preferences]);
33
- useEffect(() => {
34
- if (!foldTip) return;
35
- const close = () => setFoldTip(false);
36
- window.addEventListener("scroll", close, true);
37
- return () => window.removeEventListener("scroll", close, true);
38
- }, [foldTip]);
39
- function showFoldTip() {
40
- clearTimeout(hoverTimer.current);
41
- hoverTimer.current = setTimeout(() => setFoldTip(true), 200);
42
- }
43
- function hideFoldTip() {
44
- clearTimeout(hoverTimer.current);
45
- setFoldTip(false);
46
- }
47
- function update(patch) {
48
- onDisplay({ ...display, ...patch });
49
- }
50
- function settings(value) {
51
- var _a;
52
- if (value === "numbers") update({ lineNumbers: !display.lineNumbers });
53
- else if (value === "height") update({ limited: !display.limited });
54
- else if (CODE_THEMES.some((theme) => theme.value === value)) {
55
- try {
56
- (_a = host.preferences) == null ? void 0 : _a.set("code-theme", value);
57
- } catch {
58
- }
59
- update({ theme: value });
60
- }
61
- setMenu(false);
62
- }
63
- const label = language === "plaintext" ? "纯文本" : codeLanguageLabel(language) || "自动识别";
64
- const options = [
65
- { value: "", label: "自动识别" },
66
- { value: "plaintext", label: "纯文本" },
67
- ...CODE_LANGUAGES.filter((item) => item.value),
68
- ...!language || language === "plaintext" || isKnownCodeLanguage(language) ? [] : [{ value: language, label: language }]
69
- ];
70
- async function copy() {
71
- if (!latest.current.canCopy || running.current) return;
72
- running.current = true;
73
- setCopying(true);
74
- try {
75
- await navigator.clipboard.writeText(latest.current.text);
76
- if (alive.current) setFeedback("已复制");
77
- } catch {
78
- if (alive.current) setFeedback("复制失败,请重试");
79
- } finally {
80
- running.current = false;
81
- if (alive.current) setCopying(false);
82
- }
83
- if (!alive.current) return;
84
- clearTimeout(timer.current);
85
- timer.current = setTimeout(() => {
86
- if (alive.current) setFeedback("");
87
- }, 1800);
88
- }
89
- function menuKeydown(event) {
90
- var _a, _b;
91
- if (!menu || event.defaultPrevented || event.nativeEvent.isComposing || event.keyCode === 229) return;
92
- if (event.key === "Escape") {
93
- event.preventDefault();
94
- setMenu(false);
95
- (_a = trigger.current) == null ? void 0 : _a.focus();
96
- return;
97
- }
98
- if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
99
- const items = Array.from(((_b = menuRoot.current) == null ? void 0 : _b.querySelectorAll('[role="menuitem"],[role="menuitemradio"]')) ?? []);
100
- if (!items.length) return;
101
- event.preventDefault();
102
- const index = items.indexOf(document.activeElement);
103
- const next = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : (index + (event.key === "ArrowUp" ? -1 : 1) + items.length) % items.length;
104
- items[next].focus();
105
- }
106
- return /* @__PURE__ */ jsxs(
107
- "div",
108
- {
109
- className: "code-toolbar",
110
- contentEditable: false,
111
- "aria-label": "代码块工具栏",
112
- onKeyDown: (event) => {
113
- menuKeydown(event);
114
- if (event.key === "Escape") hideFoldTip();
115
- event.stopPropagation();
116
- },
117
- onPointerDown: (event) => event.stopPropagation(),
118
- children: [
119
- /* @__PURE__ */ jsx(
120
- WButton,
121
- {
122
- ref: foldTrigger,
123
- variant: "text",
124
- size: "mini",
125
- className: "code-fold-button",
126
- "aria-label": display.collapsed ? "展开代码块" : "折叠代码块",
127
- "aria-expanded": !display.collapsed,
128
- onMouseEnter: showFoldTip,
129
- onMouseLeave: hideFoldTip,
130
- onFocus: showFoldTip,
131
- onBlur: hideFoldTip,
132
- onClick: () => update({ collapsed: !display.collapsed }),
133
- children: /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", style: { transform: display.collapsed ? "rotate(-90deg)" : void 0 }, children: /* @__PURE__ */ jsx("path", { d: "m4 6 4 4 4-4", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) })
134
- }
135
- ),
136
- foldTip && /* @__PURE__ */ jsx(AnchoredPanel, { anchor: foldTrigger.current, onClose: hideFoldTip, role: "tooltip", align: "center", prefer: "above", gap: 8, className: "code-tooltip-popup", children: /* @__PURE__ */ jsx("div", { className: "w-tooltip", children: display.collapsed ? "展开代码" : "折叠代码" }) }),
137
- /* @__PURE__ */ jsxs("span", { className: "code-toolbar-summary", children: [
138
- display.collapsed ? "已折叠 · " : "",
139
- codeLineCount(text),
140
- " 行"
141
- ] }),
142
- /* @__PURE__ */ jsxs("div", { className: "code-toolbar-actions", children: [
143
- editable ? /* @__PURE__ */ jsx(WSelect, { className: "code-language-select", ariaLabel: "代码语言", value: language, options, size: "small", searchable: true, onChange: onLanguage }) : /* @__PURE__ */ jsx("span", { className: "code-language-label", children: label }),
144
- /* @__PURE__ */ jsx("span", { className: "code-toolbar-divider", "aria-hidden": "true" }),
145
- /* @__PURE__ */ jsxs(
146
- WButton,
147
- {
148
- variant: "text",
149
- size: "mini",
150
- className: "code-copy-button",
151
- "aria-label": "复制代码",
152
- disabled: !canCopy,
153
- loading: copying,
154
- title: canCopy ? "复制完整代码" : "当前空间未开放导出",
155
- onClick: () => void copy(),
156
- children: [
157
- /* @__PURE__ */ jsx(WIcon, { name: "copy", size: 14 }),
158
- /* @__PURE__ */ jsx("span", { children: feedback || "复制代码" })
159
- ]
160
- }
161
- ),
162
- feedback && /* @__PURE__ */ jsx("span", { className: "code-copy-announcement", role: "status", children: feedback }),
163
- /* @__PURE__ */ jsx(
164
- WButton,
165
- {
166
- ref: trigger,
167
- variant: "text",
168
- size: "mini",
169
- className: "code-settings-button",
170
- "aria-label": "代码块显示设置",
171
- "aria-expanded": menu,
172
- onClick: () => setMenu(!menu),
173
- children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "···" })
174
- }
175
- ),
176
- menu && /* @__PURE__ */ jsx(AnchoredPanel, { anchor: trigger.current, onClose: () => setMenu(false), role: "menu", label: "代码块显示设置", align: "end", gap: 6, className: "code-settings-popup", onKeyDown: menuKeydown, children: /* @__PURE__ */ jsxs("div", { ref: menuRoot, className: "w-dropdown", children: [
177
- /* @__PURE__ */ jsxs("div", { className: "w-dropdown-group", role: "group", "aria-label": "配色主题", children: [
178
- /* @__PURE__ */ jsx("div", { className: "w-dropdown-group__title", children: "配色主题" }),
179
- CODE_THEMES.map((theme) => /* @__PURE__ */ jsxs(
180
- "div",
181
- {
182
- className: "w-dropdown-option",
183
- role: "menuitemradio",
184
- tabIndex: -1,
185
- "aria-checked": display.theme === theme.value,
186
- onClick: () => settings(theme.value),
187
- onKeyDown: (event) => {
188
- if (event.key === "Enter" || event.key === " ") {
189
- event.preventDefault();
190
- settings(theme.value);
191
- }
192
- },
193
- children: [
194
- /* @__PURE__ */ jsx("span", { className: "code-theme-swatch", "data-code-swatch": theme.value, "aria-hidden": "true" }),
195
- theme.label,
196
- display.theme === theme.value && /* @__PURE__ */ jsx("span", { className: "code-option-check", "aria-hidden": "true", children: "✓" })
197
- ]
198
- },
199
- theme.value
200
- ))
201
- ] }),
202
- /* @__PURE__ */ jsx("div", { className: "w-dropdown-group", role: "group", children: [{ value: "numbers", label: display.lineNumbers ? "隐藏行号" : "显示行号" }, { value: "height", label: display.limited ? "取消高度限制" : "限制代码高度" }].map((option) => /* @__PURE__ */ jsx(
203
- "div",
204
- {
205
- className: "w-dropdown-option",
206
- role: "menuitem",
207
- tabIndex: -1,
208
- onClick: () => settings(option.value),
209
- onKeyDown: (event) => {
210
- if (event.key === "Enter" || event.key === " ") {
211
- event.preventDefault();
212
- settings(option.value);
213
- }
214
- },
215
- children: option.label
216
- },
217
- option.value
218
- )) })
219
- ] }) })
220
- ] })
221
- ]
222
- }
223
- );
224
- }
225
- const HINT_GAP = 8;
226
- const HINT_MIN_TOP_SPACE = 40;
227
- function commentHintPosition(rect, hint2, viewport) {
228
- const center = rect.left + rect.width / 2;
229
- const half = Math.max(0, hint2.width / 2);
230
- const minLeft = half + 8;
231
- const maxLeft = Math.max(minLeft, viewport.width - half - 8);
232
- const left = Math.min(Math.max(center, minLeft), maxLeft);
233
- const above = rect.top >= HINT_MIN_TOP_SPACE;
234
- return above ? { left, top: rect.top - HINT_GAP, placement: "top" } : { left, top: rect.top + rect.height + HINT_GAP, placement: "bottom" };
235
- }
236
- let hint = null;
237
- let hideOnScroll = null;
238
- function tokenOf(element, name, fallback) {
239
- const value = getComputedStyle(element).getPropertyValue(name).trim();
240
- return value || fallback;
241
- }
242
- function showCommentHint(anchor, text) {
243
- if (typeof document === "undefined") return;
244
- if (!(anchor instanceof HTMLElement)) return;
245
- hideCommentHint();
246
- const el = document.createElement("div");
247
- el.className = "doc-comment-hint";
248
- el.setAttribute("role", "tooltip");
249
- el.textContent = text;
250
- el.style.cssText = [
251
- "position:fixed",
252
- "z-index:1300",
253
- "pointer-events:none",
254
- "transform:translateX(-50%)",
255
- "padding:5px 9px",
256
- `border:1px solid ${tokenOf(anchor, "--color-border", "#dce2eb")}`,
257
- `background:${tokenOf(anchor, "--color-surface", "#ffffff")}`,
258
- `color:${tokenOf(anchor, "--color-text", "#1f2937")}`,
259
- "font-size:12px",
260
- "line-height:1.5",
261
- "white-space:nowrap",
262
- "box-shadow:0 6px 20px #1018282e",
263
- "border-radius:0"
264
- ].join(";");
265
- document.body.appendChild(el);
266
- const rect = anchor.getBoundingClientRect();
267
- const size = el.getBoundingClientRect();
268
- const pos = commentHintPosition(
269
- { left: rect.left, top: rect.top, width: rect.width, height: rect.height },
270
- { width: size.width, height: size.height },
271
- { width: window.innerWidth }
272
- );
273
- el.style.left = `${pos.left}px`;
274
- el.style.top = `${pos.top}px`;
275
- if (pos.placement === "bottom") el.style.transform = "translateX(-50%)";
276
- else el.style.transform = "translateX(-50%) translateY(-100%)";
277
- hint = el;
278
- hideOnScroll = () => hideCommentHint();
279
- window.addEventListener("scroll", hideOnScroll, true);
280
- window.addEventListener("resize", hideOnScroll);
281
- }
282
- function hideCommentHint() {
283
- if (!hint) return;
284
- hint.remove();
285
- hint = null;
286
- if (hideOnScroll) {
287
- window.removeEventListener("scroll", hideOnScroll, true);
288
- window.removeEventListener("resize", hideOnScroll);
289
- hideOnScroll = null;
290
- }
291
- }
292
- export {
293
- CodeToolbar as C,
294
- hideCommentHint as h,
295
- showCommentHint as s
296
- };