@hkyhy/marsun-components-core 0.1.61 → 0.1.63

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,31 +1,31 @@
1
- import { jsx as o } from "react/jsx-runtime";
2
- import { Empty as p, Spin as N } from "antd";
3
- import { useRef as v, useState as y, useEffect as P } from "react";
4
- import { getPreviewKind as b, needsBlobPreview as W } from "../previewKind.js";
1
+ import { jsx as a } from "react/jsx-runtime";
2
+ import { Empty as p, Spin as W } from "antd";
3
+ import { useRef as y, useState as v, useEffect as N } from "react";
4
+ import { getPreviewKind as b, needsBlobPreview as P } from "../previewKind.js";
5
5
  import c from "./style.module.scss.js";
6
- import H from "classnames";
7
- async function S(e) {
8
- const r = await fetch(e);
9
- if (!r.ok) throw new Error(`预览加载失败 (${r.status})`);
10
- return r.arrayBuffer();
6
+ import B from "classnames";
7
+ async function H(r) {
8
+ const e = await fetch(r);
9
+ if (!e.ok) throw new Error(`预览加载失败 (${e.status})`);
10
+ return e.arrayBuffer();
11
11
  }
12
- function h(e, r) {
13
- const t = e instanceof Error ? e.message : String(e ?? "");
14
- return r === "excel" && /anchors/i.test(t) ? "该 Excel 含图表/绘图等对象,当前预览引擎无法解析,请下载后用本地软件打开" : t && !/^Cannot read properties/i.test(t) && !/^undefined/i.test(t) ? t : r === "excel" ? "Excel 预览失败,请下载后查看" : "预览加载失败";
12
+ function h(r, e) {
13
+ const t = r instanceof Error ? r.message : String(r ?? "");
14
+ return e === "excel" && /anchors/i.test(t) ? "该 Excel 含图表/绘图等对象,当前预览引擎无法解析,请下载后用本地软件打开" : e === "word" && /ole|compound|docfile|not a valid/i.test(t) ? "旧版 Word(.doc)暂无法排版预览,请下载后用 Word 打开" : t && !/^Cannot read properties/i.test(t) && !/^undefined/i.test(t) ? t : e === "excel" ? "Excel 预览失败,请下载后查看" : e === "word" ? "Word 预览失败,请下载后查看" : "预览加载失败";
15
15
  }
16
- async function B(e) {
16
+ async function L(r) {
17
17
  try {
18
- const { default: r } = await import("../../../_virtual/jszip.min.js").then((i) => i.j), t = await r.loadAsync(e), a = Object.keys(t.files), n = a.filter(
18
+ const { default: e } = await import("../../../_virtual/jszip.min.js").then((i) => i.j), t = await e.loadAsync(r), n = Object.keys(t.files), o = n.filter(
19
19
  (i) => i.startsWith("xl/drawings/") || i.startsWith("xl/charts/") || i.startsWith("xl/diagrams/") || /drawing[0-9]*\.xml$/i.test(i)
20
20
  );
21
- if (n.length === 0) return null;
22
- for (const i of n)
21
+ if (o.length === 0) return null;
22
+ for (const i of o)
23
23
  t.remove(i);
24
24
  return await Promise.all(
25
- a.filter((i) => /^xl\/worksheets\/[^/]+\.xml$/i.test(i) && t.file(i)).map(async (i) => {
26
- const m = t.file(i);
27
- if (!m) return;
28
- const d = await m.async("string"), f = d.replace(/<drawing[^>]*\/>/gi, "").replace(/<drawing[^>]*>[\s\S]*?<\/drawing>/gi, "");
25
+ n.filter((i) => /^xl\/worksheets\/[^/]+\.xml$/i.test(i) && t.file(i)).map(async (i) => {
26
+ const w = t.file(i);
27
+ if (!w) return;
28
+ const d = await w.async("string"), f = d.replace(/<drawing[^>]*\/>/gi, "").replace(/<drawing[^>]*>[\s\S]*?<\/drawing>/gi, "");
29
29
  f !== d && t.file(i, f);
30
30
  })
31
31
  ), t.generateAsync({ type: "arraybuffer" });
@@ -33,107 +33,130 @@ async function B(e) {
33
33
  return null;
34
34
  }
35
35
  }
36
- async function x(e, r, t) {
37
- const a = e.init(r);
36
+ async function x(r, e, t) {
37
+ const n = r.init(e);
38
38
  try {
39
- return await a.preview(t), () => a.destroy();
40
- } catch (n) {
39
+ return await n.preview(t), () => n.destroy();
40
+ } catch (o) {
41
41
  try {
42
- a.destroy();
42
+ n.destroy();
43
43
  } catch {
44
44
  }
45
- throw n;
45
+ throw o;
46
46
  }
47
47
  }
48
- async function M(e, r) {
49
- var n;
48
+ async function T(r, e) {
49
+ var o;
50
50
  const [{ default: t }] = await Promise.all([
51
51
  import("@js-preview/excel"),
52
52
  Promise.resolve({ })
53
- ]), a = Math.max(
54
- ((n = e.parentElement) == null ? void 0 : n.clientHeight) ?? 0,
53
+ ]), n = Math.max(
54
+ ((o = r.parentElement) == null ? void 0 : o.clientHeight) ?? 0,
55
55
  Math.round(window.innerHeight * 0.65),
56
56
  480
57
57
  );
58
- e.style.height = `${a}px`;
58
+ r.style.height = `${n}px`;
59
59
  try {
60
- return await x(t, e, r);
60
+ return await x(t, r, e);
61
61
  } catch (i) {
62
- const m = i instanceof Error ? i.message : String(i ?? "");
63
- if (!/anchors/i.test(m))
62
+ const w = i instanceof Error ? i.message : String(i ?? "");
63
+ if (!/anchors/i.test(w))
64
64
  throw i instanceof Error ? i : new Error(h(i, "excel"));
65
- const d = await B(r);
65
+ const d = await L(e);
66
66
  if (!d)
67
67
  throw i instanceof Error ? i : new Error(h(i, "excel"));
68
- e.innerHTML = "";
68
+ r.innerHTML = "";
69
69
  try {
70
- return await x(t, e, d);
70
+ return await x(t, r, d);
71
71
  } catch (f) {
72
72
  throw f instanceof Error ? f : new Error(h(f, "excel"));
73
73
  }
74
74
  }
75
75
  }
76
- async function T(e, r) {
77
- const { renderAsync: t } = await import("docx-preview"), a = new Blob([r]);
78
- await t(a, e, e, {
79
- inWrapper: !0,
80
- ignoreWidth: !1,
81
- ignoreHeight: !1,
82
- breakPages: !0
83
- });
76
+ function S(r) {
77
+ const e = new Uint8Array(r);
78
+ return e.length >= 2 && e[0] === 80 && e[1] === 75;
84
79
  }
85
- async function j(e, r, t) {
86
- const { init: a } = await import("pptx-preview"), n = a(e, { width: t, height: Math.round(t * 0.5625), mode: "list" });
87
- return await n.preview(r), () => n.destroy();
80
+ function A(r) {
81
+ const e = new Uint8Array(r);
82
+ return e.length >= 4 && e[0] === 208 && e[1] === 207 && e[2] === 17 && e[3] === 224;
88
83
  }
89
- function k(e, r) {
90
- const t = new TextDecoder("utf-8"), a = document.createElement("pre");
91
- a.className = c["file-preview-text"], a.textContent = t.decode(r), e.appendChild(a);
84
+ function M(r) {
85
+ const e = new Uint8Array(r.byteLength > 64 ? r.slice(0, 64) : r);
86
+ let t = 0;
87
+ e.length >= 3 && e[0] === 239 && e[1] === 187 && e[2] === 191 && (t = 3);
88
+ const n = new TextDecoder("utf-8").decode(e.subarray(t)).trimStart().toLowerCase();
89
+ return n.startsWith("<!doctype") || n.startsWith("<html") || n.startsWith("<pre") || n.startsWith("<div") || n.startsWith("<article");
92
90
  }
93
- const J = ({
94
- file: e,
95
- previewUrl: r,
91
+ async function C(r, e) {
92
+ if (S(e)) {
93
+ const { renderAsync: t } = await import("docx-preview"), n = new Blob([e]);
94
+ await t(n, r, r, {
95
+ inWrapper: !0,
96
+ ignoreWidth: !1,
97
+ ignoreHeight: !1,
98
+ breakPages: !0
99
+ });
100
+ return;
101
+ }
102
+ if (M(e)) {
103
+ r.innerHTML = new TextDecoder("utf-8").decode(e);
104
+ return;
105
+ }
106
+ throw A(e) ? new Error("旧版 Word(.doc)暂无法排版预览,请下载后用 Word 打开") : new Error("无法识别的 Word 文件格式,请下载后查看");
107
+ }
108
+ async function j(r, e, t) {
109
+ const { init: n } = await import("pptx-preview"), o = n(r, { width: t, height: Math.round(t * 0.5625), mode: "list" });
110
+ return await o.preview(e), () => o.destroy();
111
+ }
112
+ function D(r, e) {
113
+ const t = new TextDecoder("utf-8"), n = document.createElement("pre");
114
+ n.className = c["file-preview-text"], n.textContent = t.decode(e), r.appendChild(n);
115
+ }
116
+ const K = ({
117
+ file: r,
118
+ previewUrl: e,
96
119
  unsupportedMessage: t = "暂不支持预览此文件类型"
97
120
  }) => {
98
- const a = v(null), n = v(void 0), [i, m] = y(!1), [d, f] = y(null), s = b(e);
99
- return P(() => {
121
+ const n = y(null), o = y(void 0), [i, w] = v(!1), [d, f] = v(null), s = b(r);
122
+ return N(() => {
100
123
  var g;
101
- const u = a.current;
102
- if (!u || !r) return;
103
- let w = !1;
104
- return (g = n.current) == null || g.call(n), n.current = void 0, u.innerHTML = "", f(null), (async () => {
124
+ const u = n.current;
125
+ if (!u || !e) return;
126
+ let m = !1;
127
+ return (g = o.current) == null || g.call(o), o.current = void 0, u.innerHTML = "", f(null), (async () => {
105
128
  if (s !== "image" && !(s === "pdf" || s === "iframe") && !(s === "video" || s === "audio") && s !== "unsupported") {
106
- m(!0);
129
+ w(!0);
107
130
  try {
108
- const l = await S(r);
109
- if (w) return;
131
+ const l = await H(e);
132
+ if (m) return;
110
133
  if (s === "excel")
111
- n.current = await M(u, l);
134
+ o.current = await T(u, l);
112
135
  else if (s === "word")
113
- await T(u, l);
136
+ await C(u, l);
114
137
  else if (s === "ppt") {
115
138
  const E = u.clientWidth || 852;
116
- n.current = await j(u, l, E);
117
- } else s === "text" && k(u, l);
139
+ o.current = await j(u, l, E);
140
+ } else s === "text" && D(u, l);
118
141
  } catch (l) {
119
- w || f(h(l, s));
142
+ m || f(h(l, s));
120
143
  } finally {
121
- w || m(!1);
144
+ m || w(!1);
122
145
  }
123
146
  }
124
147
  })(), () => {
125
148
  var l;
126
- w = !0, (l = n.current) == null || l.call(n), n.current = void 0, u.innerHTML = "";
149
+ m = !0, (l = o.current) == null || l.call(o), o.current = void 0, u.innerHTML = "";
127
150
  };
128
- }, [r, s, e.id, e.name]), r ? s === "image" ? /* @__PURE__ */ o("div", { className: c["file-preview-media-wrap"], children: /* @__PURE__ */ o("img", { src: r, alt: e.name, className: c["file-preview-image"] }) }) : s === "pdf" || s === "iframe" ? /* @__PURE__ */ o("iframe", { src: r, title: e.name, className: c["file-preview-iframe"] }) : s === "video" ? /* @__PURE__ */ o("div", { className: c["file-preview-media-wrap"], children: /* @__PURE__ */ o("video", { src: r, controls: !0, className: c["file-preview-video"] }) }) : s === "audio" ? /* @__PURE__ */ o("div", { className: c["file-preview-audio-wrap"], children: /* @__PURE__ */ o("audio", { src: r, controls: !0, className: c["file-preview-audio"] }) }) : s === "unsupported" ? /* @__PURE__ */ o(p, { description: t }) : W(s) ? /* @__PURE__ */ o(
151
+ }, [e, s, r.id, r.name]), e ? s === "image" ? /* @__PURE__ */ a("div", { className: c["file-preview-media-wrap"], children: /* @__PURE__ */ a("img", { src: e, alt: r.name, className: c["file-preview-image"] }) }) : s === "pdf" || s === "iframe" ? /* @__PURE__ */ a("iframe", { src: e, title: r.name, className: c["file-preview-iframe"] }) : s === "video" ? /* @__PURE__ */ a("div", { className: c["file-preview-media-wrap"], children: /* @__PURE__ */ a("video", { src: e, controls: !0, className: c["file-preview-video"] }) }) : s === "audio" ? /* @__PURE__ */ a("div", { className: c["file-preview-audio-wrap"], children: /* @__PURE__ */ a("audio", { src: e, controls: !0, className: c["file-preview-audio"] }) }) : s === "unsupported" ? /* @__PURE__ */ a(p, { description: t }) : P(s) ? /* @__PURE__ */ a(
129
152
  "div",
130
153
  {
131
- className: H(c["file-preview-office"], c["file-preview-office-wrap"]),
132
- children: /* @__PURE__ */ o(N, { spinning: i, classNames: { root: c["file-preview-office-spin"] }, children: d ? /* @__PURE__ */ o(p, { description: d }) : /* @__PURE__ */ o("div", { ref: a, className: c["file-preview-office-inner"] }) })
154
+ className: B(c["file-preview-office"], c["file-preview-office-wrap"]),
155
+ children: /* @__PURE__ */ a(W, { spinning: i, classNames: { root: c["file-preview-office-spin"] }, children: d ? /* @__PURE__ */ a(p, { description: d }) : /* @__PURE__ */ a("div", { ref: n, className: c["file-preview-office-inner"] }) })
133
156
  }
134
- ) : /* @__PURE__ */ o(p, { description: t }) : /* @__PURE__ */ o(p, { description: "无可预览地址" });
157
+ ) : /* @__PURE__ */ a(p, { description: t }) : /* @__PURE__ */ a(p, { description: "无可预览地址" });
135
158
  };
136
159
  export {
137
- J as default
160
+ K as default
138
161
  };
139
162
  //# sourceMappingURL=FilePreviewContent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FilePreviewContent.js","sources":["../../../../src/components/File/FilePreview/FilePreviewContent.tsx"],"sourcesContent":["import { Empty, Spin } from 'antd';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { getPreviewKind, needsBlobPreview } from '../previewKind';\nimport type { FileDisplayItem } from '../types';\nimport styles from './style.module.scss';\nimport classNames from 'classnames';\n\ninterface FilePreviewContentProps {\n file: FileDisplayItem;\n previewUrl?: string;\n unsupportedMessage?: string;\n}\n\nasync function fetchPreviewBlob(url: string): Promise<ArrayBuffer> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`预览加载失败 (${res.status})`);\n return res.arrayBuffer();\n}\n\nfunction mapPreviewError(err: unknown, kind: string): string {\n const raw = err instanceof Error ? err.message : String(err ?? '');\n if (kind === 'excel' && /anchors/i.test(raw)) {\n return '该 Excel 含图表/绘图等对象,当前预览引擎无法解析,请下载后用本地软件打开';\n }\n if (raw && !/^Cannot read properties/i.test(raw) && !/^undefined/i.test(raw)) {\n return raw;\n }\n return kind === 'excel' ? 'Excel 预览失败,请下载后查看' : '预览加载失败';\n}\n\n/** exceljs/@js-preview 对部分含 drawing/chart 的 xlsx 会在 reconcile 时读 anchors 崩溃;去掉绘图部件后重试。 */\nasync function stripExcelDrawings(data: ArrayBuffer): Promise<ArrayBuffer | null> {\n try {\n const { default: JSZip } = await import('jszip');\n const zip = await JSZip.loadAsync(data);\n const names = Object.keys(zip.files);\n const drop = names.filter(\n (n) =>\n n.startsWith('xl/drawings/') ||\n n.startsWith('xl/charts/') ||\n n.startsWith('xl/diagrams/') ||\n /drawing[0-9]*\\.xml$/i.test(n),\n );\n if (drop.length === 0) return null;\n for (const n of drop) {\n zip.remove(n);\n }\n // 清理 worksheet 中的 drawing 引用,避免指向已删部件\n await Promise.all(\n names\n .filter((n) => /^xl\\/worksheets\\/[^/]+\\.xml$/i.test(n) && zip.file(n))\n .map(async (n) => {\n const file = zip.file(n);\n if (!file) return;\n const xml = await file.async('string');\n const cleaned = xml\n .replace(/<drawing[^>]*\\/>/gi, '')\n .replace(/<drawing[^>]*>[\\s\\S]*?<\\/drawing>/gi, '');\n if (cleaned !== xml) zip.file(n, cleaned);\n }),\n );\n return zip.generateAsync({ type: 'arraybuffer' });\n } catch {\n return null;\n }\n}\n\nasync function previewExcelBuffer(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n jsPreviewExcel: { init: (el: HTMLElement) => any },\n container: HTMLElement,\n data: ArrayBuffer,\n) {\n const instance = jsPreviewExcel.init(container);\n try {\n await instance.preview(data);\n return () => instance.destroy();\n } catch (err) {\n try {\n instance.destroy();\n } catch {\n // ignore\n }\n throw err;\n }\n}\n\nasync function renderExcel(container: HTMLElement, data: ArrayBuffer) {\n const [{ default: jsPreviewExcel }] = await Promise.all([\n import('@js-preview/excel'),\n import('@js-preview/excel/lib/index.css'),\n ]);\n const height = Math.max(\n container.parentElement?.clientHeight ?? 0,\n Math.round(window.innerHeight * 0.65),\n 480,\n );\n container.style.height = `${height}px`;\n\n try {\n return await previewExcelBuffer(jsPreviewExcel, container, data);\n } catch (firstErr) {\n const msg = firstErr instanceof Error ? firstErr.message : String(firstErr ?? '');\n if (!/anchors/i.test(msg)) {\n throw firstErr instanceof Error ? firstErr : new Error(mapPreviewError(firstErr, 'excel'));\n }\n const stripped = await stripExcelDrawings(data);\n if (!stripped) {\n throw firstErr instanceof Error ? firstErr : new Error(mapPreviewError(firstErr, 'excel'));\n }\n container.innerHTML = '';\n try {\n return await previewExcelBuffer(jsPreviewExcel, container, stripped);\n } catch (retryErr) {\n throw retryErr instanceof Error ? retryErr : new Error(mapPreviewError(retryErr, 'excel'));\n }\n }\n}\n\nasync function renderWord(container: HTMLElement, data: ArrayBuffer) {\n const { renderAsync } = await import('docx-preview');\n const blob = new Blob([data]);\n await renderAsync(blob, container, container, {\n inWrapper: true,\n ignoreWidth: false,\n ignoreHeight: false,\n breakPages: true,\n });\n}\n\nasync function renderPpt(container: HTMLElement, data: ArrayBuffer, width: number) {\n const { init } = await import('pptx-preview');\n const previewer = init(container, { width, height: Math.round(width * 0.5625), mode: 'list' });\n await previewer.preview(data);\n return () => previewer.destroy();\n}\n\nfunction renderText(container: HTMLElement, data: ArrayBuffer) {\n const decoder = new TextDecoder('utf-8');\n const pre = document.createElement('pre');\n pre.className = styles['file-preview-text'] ?? '';\n pre.textContent = decoder.decode(data);\n container.appendChild(pre);\n}\n\nconst FilePreviewContent: React.FC<FilePreviewContentProps> = ({\n file,\n previewUrl,\n unsupportedMessage = '暂不支持预览此文件类型',\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const cleanupRef = useRef<(() => void) | void>(undefined);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const kind = getPreviewKind(file);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container || !previewUrl) return undefined;\n\n let cancelled = false;\n cleanupRef.current?.();\n cleanupRef.current = undefined;\n container.innerHTML = '';\n setError(null);\n\n const run = async () => {\n if (kind === 'image') return;\n if (kind === 'pdf' || kind === 'iframe') return;\n if (kind === 'video' || kind === 'audio') return;\n if (kind === 'unsupported') return;\n\n setLoading(true);\n try {\n const data = await fetchPreviewBlob(previewUrl);\n if (cancelled) return;\n\n if (kind === 'excel') {\n cleanupRef.current = await renderExcel(container, data);\n } else if (kind === 'word') {\n await renderWord(container, data);\n } else if (kind === 'ppt') {\n const width = container.clientWidth || 852;\n cleanupRef.current = await renderPpt(container, data, width);\n } else if (kind === 'text') {\n renderText(container, data);\n }\n } catch (err) {\n if (!cancelled) {\n setError(mapPreviewError(err, kind));\n }\n } finally {\n if (!cancelled) setLoading(false);\n }\n };\n\n void run();\n\n return () => {\n cancelled = true;\n cleanupRef.current?.();\n cleanupRef.current = undefined;\n container.innerHTML = '';\n };\n }, [previewUrl, kind, file.id, file.name]);\n\n if (!previewUrl) {\n return <Empty description=\"无可预览地址\" />;\n }\n\n if (kind === 'image') {\n return (\n <div className={styles['file-preview-media-wrap']}>\n <img src={previewUrl} alt={file.name} className={styles['file-preview-image']} />\n </div>\n );\n }\n\n if (kind === 'pdf' || kind === 'iframe') {\n return <iframe src={previewUrl} title={file.name} className={styles['file-preview-iframe']} />;\n }\n\n if (kind === 'video') {\n return (\n <div className={styles['file-preview-media-wrap']}>\n <video src={previewUrl} controls className={styles['file-preview-video']} />\n </div>\n );\n }\n\n if (kind === 'audio') {\n return (\n <div className={styles['file-preview-audio-wrap']}>\n <audio src={previewUrl} controls className={styles['file-preview-audio']} />\n </div>\n );\n }\n\n if (kind === 'unsupported') {\n return <Empty description={unsupportedMessage} />;\n }\n\n if (needsBlobPreview(kind)) {\n return (\n <div\n className={classNames(styles['file-preview-office'], styles['file-preview-office-wrap'])}\n >\n <Spin spinning={loading} classNames={{ root: styles['file-preview-office-spin'] }}>\n {error ? (\n <Empty description={error} />\n ) : (\n <div ref={containerRef} className={styles['file-preview-office-inner']} />\n )}\n </Spin>\n </div>\n );\n }\n\n return <Empty description={unsupportedMessage} />;\n};\n\nexport default FilePreviewContent;\n"],"names":["fetchPreviewBlob","url","res","mapPreviewError","err","kind","raw","stripExcelDrawings","data","JSZip","n","zip","names","drop","file","xml","cleaned","previewExcelBuffer","jsPreviewExcel","container","instance","renderExcel","height","_a","firstErr","msg","stripped","retryErr","renderWord","renderAsync","blob","renderPpt","width","init","previewer","renderText","decoder","pre","styles","FilePreviewContent","previewUrl","unsupportedMessage","containerRef","useRef","cleanupRef","loading","setLoading","useState","error","setError","getPreviewKind","useEffect","cancelled","jsx","Empty","needsBlobPreview","classNames","Spin"],"mappings":"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"}
1
+ {"version":3,"file":"FilePreviewContent.js","sources":["../../../../src/components/File/FilePreview/FilePreviewContent.tsx"],"sourcesContent":["import { Empty, Spin } from 'antd';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { getPreviewKind, needsBlobPreview } from '../previewKind';\nimport type { FileDisplayItem } from '../types';\nimport styles from './style.module.scss';\nimport classNames from 'classnames';\n\ninterface FilePreviewContentProps {\n file: FileDisplayItem;\n previewUrl?: string;\n unsupportedMessage?: string;\n}\n\nasync function fetchPreviewBlob(url: string): Promise<ArrayBuffer> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`预览加载失败 (${res.status})`);\n return res.arrayBuffer();\n}\n\nfunction mapPreviewError(err: unknown, kind: string): string {\n const raw = err instanceof Error ? err.message : String(err ?? '');\n if (kind === 'excel' && /anchors/i.test(raw)) {\n return '该 Excel 含图表/绘图等对象,当前预览引擎无法解析,请下载后用本地软件打开';\n }\n if (kind === 'word' && /ole|compound|docfile|not a valid/i.test(raw)) {\n return '旧版 Word(.doc)暂无法排版预览,请下载后用 Word 打开';\n }\n if (raw && !/^Cannot read properties/i.test(raw) && !/^undefined/i.test(raw)) {\n return raw;\n }\n return kind === 'excel'\n ? 'Excel 预览失败,请下载后查看'\n : kind === 'word'\n ? 'Word 预览失败,请下载后查看'\n : '预览加载失败';\n}\n\n/** exceljs/@js-preview 对部分含 drawing/chart 的 xlsx 会在 reconcile 时读 anchors 崩溃;去掉绘图部件后重试。 */\nasync function stripExcelDrawings(data: ArrayBuffer): Promise<ArrayBuffer | null> {\n try {\n const { default: JSZip } = await import('jszip');\n const zip = await JSZip.loadAsync(data);\n const names = Object.keys(zip.files);\n const drop = names.filter(\n (n) =>\n n.startsWith('xl/drawings/') ||\n n.startsWith('xl/charts/') ||\n n.startsWith('xl/diagrams/') ||\n /drawing[0-9]*\\.xml$/i.test(n),\n );\n if (drop.length === 0) return null;\n for (const n of drop) {\n zip.remove(n);\n }\n // 清理 worksheet 中的 drawing 引用,避免指向已删部件\n await Promise.all(\n names\n .filter((n) => /^xl\\/worksheets\\/[^/]+\\.xml$/i.test(n) && zip.file(n))\n .map(async (n) => {\n const file = zip.file(n);\n if (!file) return;\n const xml = await file.async('string');\n const cleaned = xml\n .replace(/<drawing[^>]*\\/>/gi, '')\n .replace(/<drawing[^>]*>[\\s\\S]*?<\\/drawing>/gi, '');\n if (cleaned !== xml) zip.file(n, cleaned);\n }),\n );\n return zip.generateAsync({ type: 'arraybuffer' });\n } catch {\n return null;\n }\n}\n\nasync function previewExcelBuffer(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n jsPreviewExcel: { init: (el: HTMLElement) => any },\n container: HTMLElement,\n data: ArrayBuffer,\n) {\n const instance = jsPreviewExcel.init(container);\n try {\n await instance.preview(data);\n return () => instance.destroy();\n } catch (err) {\n try {\n instance.destroy();\n } catch {\n // ignore\n }\n throw err;\n }\n}\n\nasync function renderExcel(container: HTMLElement, data: ArrayBuffer) {\n const [{ default: jsPreviewExcel }] = await Promise.all([\n import('@js-preview/excel'),\n import('@js-preview/excel/lib/index.css'),\n ]);\n const height = Math.max(\n container.parentElement?.clientHeight ?? 0,\n Math.round(window.innerHeight * 0.65),\n 480,\n );\n container.style.height = `${height}px`;\n\n try {\n return await previewExcelBuffer(jsPreviewExcel, container, data);\n } catch (firstErr) {\n const msg = firstErr instanceof Error ? firstErr.message : String(firstErr ?? '');\n if (!/anchors/i.test(msg)) {\n throw firstErr instanceof Error ? firstErr : new Error(mapPreviewError(firstErr, 'excel'));\n }\n const stripped = await stripExcelDrawings(data);\n if (!stripped) {\n throw firstErr instanceof Error ? firstErr : new Error(mapPreviewError(firstErr, 'excel'));\n }\n container.innerHTML = '';\n try {\n return await previewExcelBuffer(jsPreviewExcel, container, stripped);\n } catch (retryErr) {\n throw retryErr instanceof Error ? retryErr : new Error(mapPreviewError(retryErr, 'excel'));\n }\n }\n}\n\nfunction isZipBuffer(data: ArrayBuffer): boolean {\n const u = new Uint8Array(data);\n return u.length >= 2 && u[0] === 0x50 && u[1] === 0x4b; // PK\n}\n\nfunction isOleBuffer(data: ArrayBuffer): boolean {\n const u = new Uint8Array(data);\n return u.length >= 4 && u[0] === 0xd0 && u[1] === 0xcf && u[2] === 0x11 && u[3] === 0xe0;\n}\n\n/** 服务端把旧版 .doc 转成 HTML 后,预览响应不再是 OLE */\nfunction isLikelyHtmlBuffer(data: ArrayBuffer): boolean {\n const u = new Uint8Array(data.byteLength > 64 ? data.slice(0, 64) : data);\n let offset = 0;\n if (u.length >= 3 && u[0] === 0xef && u[1] === 0xbb && u[2] === 0xbf) offset = 3;\n const head = new TextDecoder('utf-8').decode(u.subarray(offset)).trimStart().toLowerCase();\n return (\n head.startsWith('<!doctype') ||\n head.startsWith('<html') ||\n head.startsWith('<pre') ||\n head.startsWith('<div') ||\n head.startsWith('<article')\n );\n}\n\nasync function renderWord(container: HTMLElement, data: ArrayBuffer) {\n // 误命名为 .doc 的真实 docx(ZIP)仍走 docx-preview\n if (isZipBuffer(data)) {\n const { renderAsync } = await import('docx-preview');\n const blob = new Blob([data]);\n await renderAsync(blob, container, container, {\n inWrapper: true,\n ignoreWidth: false,\n ignoreHeight: false,\n breakPages: true,\n });\n return;\n }\n\n // Assets 等对旧版 .doc 预览返回的 HTML\n if (isLikelyHtmlBuffer(data)) {\n container.innerHTML = new TextDecoder('utf-8').decode(data);\n return;\n }\n\n if (isOleBuffer(data)) {\n throw new Error('旧版 Word(.doc)暂无法排版预览,请下载后用 Word 打开');\n }\n\n throw new Error('无法识别的 Word 文件格式,请下载后查看');\n}\n\nasync function renderPpt(container: HTMLElement, data: ArrayBuffer, width: number) {\n const { init } = await import('pptx-preview');\n const previewer = init(container, { width, height: Math.round(width * 0.5625), mode: 'list' });\n await previewer.preview(data);\n return () => previewer.destroy();\n}\n\nfunction renderText(container: HTMLElement, data: ArrayBuffer) {\n const decoder = new TextDecoder('utf-8');\n const pre = document.createElement('pre');\n pre.className = styles['file-preview-text'] ?? '';\n pre.textContent = decoder.decode(data);\n container.appendChild(pre);\n}\n\nconst FilePreviewContent: React.FC<FilePreviewContentProps> = ({\n file,\n previewUrl,\n unsupportedMessage = '暂不支持预览此文件类型',\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const cleanupRef = useRef<(() => void) | void>(undefined);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const kind = getPreviewKind(file);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container || !previewUrl) return undefined;\n\n let cancelled = false;\n cleanupRef.current?.();\n cleanupRef.current = undefined;\n container.innerHTML = '';\n setError(null);\n\n const run = async () => {\n if (kind === 'image') return;\n if (kind === 'pdf' || kind === 'iframe') return;\n if (kind === 'video' || kind === 'audio') return;\n if (kind === 'unsupported') return;\n\n setLoading(true);\n try {\n const data = await fetchPreviewBlob(previewUrl);\n if (cancelled) return;\n\n if (kind === 'excel') {\n cleanupRef.current = await renderExcel(container, data);\n } else if (kind === 'word') {\n await renderWord(container, data);\n } else if (kind === 'ppt') {\n const width = container.clientWidth || 852;\n cleanupRef.current = await renderPpt(container, data, width);\n } else if (kind === 'text') {\n renderText(container, data);\n }\n } catch (err) {\n if (!cancelled) {\n setError(mapPreviewError(err, kind));\n }\n } finally {\n if (!cancelled) setLoading(false);\n }\n };\n\n void run();\n\n return () => {\n cancelled = true;\n cleanupRef.current?.();\n cleanupRef.current = undefined;\n container.innerHTML = '';\n };\n }, [previewUrl, kind, file.id, file.name]);\n\n if (!previewUrl) {\n return <Empty description=\"无可预览地址\" />;\n }\n\n if (kind === 'image') {\n return (\n <div className={styles['file-preview-media-wrap']}>\n <img src={previewUrl} alt={file.name} className={styles['file-preview-image']} />\n </div>\n );\n }\n\n if (kind === 'pdf' || kind === 'iframe') {\n return <iframe src={previewUrl} title={file.name} className={styles['file-preview-iframe']} />;\n }\n\n if (kind === 'video') {\n return (\n <div className={styles['file-preview-media-wrap']}>\n <video src={previewUrl} controls className={styles['file-preview-video']} />\n </div>\n );\n }\n\n if (kind === 'audio') {\n return (\n <div className={styles['file-preview-audio-wrap']}>\n <audio src={previewUrl} controls className={styles['file-preview-audio']} />\n </div>\n );\n }\n\n if (kind === 'unsupported') {\n return <Empty description={unsupportedMessage} />;\n }\n\n if (needsBlobPreview(kind)) {\n return (\n <div\n className={classNames(styles['file-preview-office'], styles['file-preview-office-wrap'])}\n >\n <Spin spinning={loading} classNames={{ root: styles['file-preview-office-spin'] }}>\n {error ? (\n <Empty description={error} />\n ) : (\n <div ref={containerRef} className={styles['file-preview-office-inner']} />\n )}\n </Spin>\n </div>\n );\n }\n\n return <Empty description={unsupportedMessage} />;\n};\n\nexport default FilePreviewContent;\n"],"names":["fetchPreviewBlob","url","res","mapPreviewError","err","kind","raw","stripExcelDrawings","data","JSZip","n","zip","names","drop","file","xml","cleaned","previewExcelBuffer","jsPreviewExcel","container","instance","renderExcel","height","_a","firstErr","msg","stripped","retryErr","isZipBuffer","u","isOleBuffer","isLikelyHtmlBuffer","offset","head","renderWord","renderAsync","blob","renderPpt","width","init","previewer","renderText","decoder","pre","styles","FilePreviewContent","previewUrl","unsupportedMessage","containerRef","useRef","cleanupRef","loading","setLoading","useState","error","setError","getPreviewKind","useEffect","cancelled","jsx","Empty","needsBlobPreview","classNames","Spin"],"mappings":"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"}
@@ -18,6 +18,12 @@ export interface TooltipInfoProps extends Pick<TooltipProps, 'placement' | 'mous
18
18
  children: React.ReactNode;
19
19
  /** CommonDescriptions 列数,默认 1(仅 descriptions 形态) */
20
20
  column?: number;
21
+ /**
22
+ * descriptions 是否带边框表格样式。
23
+ * 默认 false(气泡内用 dl,避免 table 在 Tooltip 里宽度塌陷);
24
+ * 需要 CommonDescriptions 默认「灰底标签格子」时传 true,并建议设 minWidth/maxWidth。
25
+ */
26
+ bordered?: boolean;
21
27
  /** 为 true 时不展示 Tooltip;descriptions 形态下 content 为空也不展示 */
22
28
  hidden?: boolean;
23
29
  /** 气泡最小宽度,默认 descriptions 220 / note 240 */
@@ -1,39 +1,40 @@
1
- import { jsx as o, Fragment as v, jsxs as W } from "react/jsx-runtime";
2
- import { Tooltip as y } from "antd";
3
- import N from "../Descriptions/CommonDescriptions.js";
4
- const C = ({
1
+ import { jsx as o, Fragment as W, jsxs as y } from "react/jsx-runtime";
2
+ import { Tooltip as N } from "antd";
3
+ import j from "../Descriptions/CommonDescriptions.js";
4
+ const S = ({
5
5
  type: a = "descriptions",
6
6
  content: i,
7
7
  note: r,
8
8
  children: e,
9
9
  column: l = 1,
10
- hidden: p = !1,
11
- minWidth: d,
12
- maxWidth: f,
13
- placement: m = "top",
14
- overlayClassName: c,
15
- overlayStyle: x,
16
- mouseEnterDelay: b = 0.3,
17
- ...g
10
+ bordered: p = !1,
11
+ hidden: d = !1,
12
+ minWidth: f,
13
+ maxWidth: m,
14
+ placement: c = "top",
15
+ overlayClassName: x,
16
+ overlayStyle: b,
17
+ mouseEnterDelay: g = 0.3,
18
+ ...h
18
19
  }) => {
19
- const t = a === "note", h = t ? !r : !i || i.length === 0;
20
- if (p || h)
21
- return /* @__PURE__ */ o(v, { children: e });
22
- const n = d ?? (t ? 240 : 220), s = f ?? (t ? 380 : 320), u = t ? /* @__PURE__ */ W("div", { className: "tooltip-info-note", children: [
20
+ const t = a === "note", u = t ? !r : !i || i.length === 0;
21
+ if (d || u)
22
+ return /* @__PURE__ */ o(W, { children: e });
23
+ const n = f ?? (t ? 240 : 220), s = m ?? (t ? 380 : 320), v = t ? /* @__PURE__ */ y("div", { className: "tooltip-info-note", children: [
23
24
  /* @__PURE__ */ o("div", { className: "tooltip-info-note-title", children: r.title }),
24
25
  /* @__PURE__ */ o("div", { className: "tooltip-info-note-desc", children: r.description })
25
26
  ] }) : (
26
- // bordered=false:antd Descriptions 改用 dl 布局而非 table,避免 table-layout:fixed
27
- // 在 max-content 气泡根下循环宽度塌陷,长文才能在 maxWidth 处正常换行
28
- /* @__PURE__ */ o(N, { content: i, column: l, size: "small", bordered: !1 })
27
+ // 默认 bordered=false:dl 布局,避免 table-layout:fixed 在气泡内宽度塌陷。
28
+ // 显式 bordered 时用表格灰底标签(对齐页面内 CommonDescriptions 默认观感)。
29
+ /* @__PURE__ */ o(j, { content: i, column: l, size: "small", bordered: p })
29
30
  );
30
31
  return /* @__PURE__ */ o(
31
- y,
32
+ N,
32
33
  {
33
- placement: m,
34
- mouseEnterDelay: b,
34
+ placement: c,
35
+ mouseEnterDelay: g,
35
36
  destroyOnHidden: !0,
36
- classNames: { root: ["tooltip-info-overlay", c].filter(Boolean).join(" ") },
37
+ classNames: { root: ["tooltip-info-overlay", x].filter(Boolean).join(" ") },
37
38
  styles: {
38
39
  root: {
39
40
  // 覆盖 antd 默认 width:max-content,给气泡确定的最小宽度,避免子元素循环塌陷
@@ -49,17 +50,17 @@ const C = ({
49
50
  background: "var(--tooltip-info-bg, var(--bg-color-white, #ffffff))",
50
51
  color: "var(--tooltip-info-color, var(--font-color, #222222))",
51
52
  boxShadow: "0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12)",
52
- ...x
53
+ ...b
53
54
  }
54
55
  },
55
56
  getPopupContainer: () => document.body,
56
- title: u,
57
- ...g,
57
+ title: v,
58
+ ...h,
58
59
  children: e
59
60
  }
60
61
  );
61
62
  };
62
63
  export {
63
- C as default
64
+ S as default
64
65
  };
65
66
  //# sourceMappingURL=TooltipInfo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TooltipInfo.js","sources":["../../../src/components/TooltipInfo/TooltipInfo.tsx"],"sourcesContent":["import type { TooltipProps } from 'antd';\nimport { Tooltip } from 'antd';\nimport React from 'react';\nimport type { DescriptionItem } from '../Descriptions/CommonDescriptions';\nimport CommonDescriptions from '../Descriptions/CommonDescriptions';\nimport './style.module.scss';\n\n/** Tooltip 展示形态:descriptions=结构化详情(默认);note=标题+描述分层 */\nexport type TooltipInfoType = 'descriptions' | 'note';\n\n/** note 形态内容:标题(粗体)+ 描述(次级色) */\nexport interface TooltipInfoNote {\n title: React.ReactNode;\n description: React.ReactNode;\n}\n\nexport interface TooltipInfoProps extends Pick<\n TooltipProps,\n 'placement' | 'mouseEnterDelay' | 'mouseLeaveDelay' | 'open' | 'onOpenChange'\n> {\n /** 展示形态,默认 descriptions */\n type?: TooltipInfoType;\n /** type='descriptions' 的详情项(默认形态) */\n content?: DescriptionItem[];\n /** type='note' 的标题与描述 */\n note?: TooltipInfoNote;\n children: React.ReactNode;\n /** CommonDescriptions 列数,默认 1(仅 descriptions 形态) */\n column?: number;\n /** 为 true 时不展示 Tooltip;descriptions 形态下 content 为空也不展示 */\n hidden?: boolean;\n /** 气泡最小宽度,默认 descriptions 220 / note 240 */\n minWidth?: number;\n /** 气泡最大宽度,默认 descriptions 320 / note 380 */\n maxWidth?: number;\n /** @deprecated 使用 classNames.root */\n overlayClassName?: string;\n /** @deprecated 使用 styles.root */\n overlayStyle?: React.CSSProperties;\n}\n\n/** Tooltip 详情展示:descriptions 形态用 CommonDescriptions;note 形态用标题+描述分层 */\nconst TooltipInfo: React.FC<TooltipInfoProps> = ({\n type = 'descriptions',\n content,\n note,\n children,\n column = 1,\n hidden = false,\n minWidth,\n maxWidth,\n placement = 'top',\n overlayClassName,\n overlayStyle,\n mouseEnterDelay = 0.3,\n ...rest\n}) => {\n const isNote = type === 'note';\n const empty = isNote ? !note : !content || content.length === 0;\n if (hidden || empty) {\n return <>{children}</>;\n }\n\n const minW = minWidth ?? (isNote ? 240 : 220);\n const maxW = maxWidth ?? (isNote ? 380 : 320);\n\n const title = isNote ? (\n <div className=\"tooltip-info-note\">\n <div className=\"tooltip-info-note-title\">{note!.title}</div>\n <div className=\"tooltip-info-note-desc\">{note!.description}</div>\n </div>\n ) : (\n // bordered=false:antd Descriptions 改用 dl 布局而非 table,避免 table-layout:fixed\n // 在 max-content 气泡根下循环宽度塌陷,长文才能在 maxWidth 处正常换行\n <CommonDescriptions content={content!} column={column} size=\"small\" bordered={false} />\n );\n\n return (\n <Tooltip\n placement={placement}\n mouseEnterDelay={mouseEnterDelay}\n destroyOnHidden\n classNames={{ root: ['tooltip-info-overlay', overlayClassName].filter(Boolean).join(' ') }}\n styles={{\n root: {\n // 覆盖 antd 默认 width:max-content,给气泡确定的最小宽度,避免子元素循环塌陷\n width: 'auto',\n minWidth: minW,\n maxWidth: maxW,\n },\n container: {\n boxSizing: 'border-box',\n minWidth: minW,\n maxWidth: maxW,\n padding: '8px 12px',\n background: 'var(--tooltip-info-bg, var(--bg-color-white, #ffffff))',\n color: 'var(--tooltip-info-color, var(--font-color, #222222))',\n boxShadow: '0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12)',\n ...overlayStyle,\n },\n }}\n getPopupContainer={() => document.body}\n title={title}\n {...rest}\n >\n {children}\n </Tooltip>\n );\n};\n\nexport default TooltipInfo;\n"],"names":["TooltipInfo","type","content","note","children","column","hidden","minWidth","maxWidth","placement","overlayClassName","overlayStyle","mouseEnterDelay","rest","isNote","empty","minW","maxW","title","jsxs","jsx","CommonDescriptions","Tooltip"],"mappings":";;;AA0CA,MAAMA,IAA0C,CAAC;AAAA,EAC/C,MAAAC,IAAO;AAAA,EACP,SAAAC;AAAA,EACA,MAAAC;AAAA,EACA,UAAAC;AAAA,EACA,QAAAC,IAAS;AAAA,EACT,QAAAC,IAAS;AAAA,EACT,UAAAC;AAAA,EACA,UAAAC;AAAA,EACA,WAAAC,IAAY;AAAA,EACZ,kBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,iBAAAC,IAAkB;AAAA,EAClB,GAAGC;AACL,MAAM;AACJ,QAAMC,IAASb,MAAS,QAClBc,IAAQD,IAAS,CAACX,IAAO,CAACD,KAAWA,EAAQ,WAAW;AAC9D,MAAII,KAAUS;AACZ,kCAAU,UAAAX,GAAS;AAGrB,QAAMY,IAAOT,MAAaO,IAAS,MAAM,MACnCG,IAAOT,MAAaM,IAAS,MAAM,MAEnCI,IAAQJ,IACZ,gBAAAK,EAAC,OAAA,EAAI,WAAU,qBACb,UAAA;AAAA,IAAA,gBAAAC,EAAC,OAAA,EAAI,WAAU,2BAA2B,UAAAjB,EAAM,OAAM;AAAA,IACtD,gBAAAiB,EAAC,OAAA,EAAI,WAAU,0BAA0B,YAAM,YAAA,CAAY;AAAA,EAAA,GAC7D;AAAA;AAAA;AAAA,sBAICC,GAAA,EAAmB,SAAAnB,GAAmB,QAAAG,GAAgB,MAAK,SAAQ,UAAU,GAAA,CAAO;AAAA;AAGvF,SACE,gBAAAe;AAAA,IAACE;AAAA,IAAA;AAAA,MACC,WAAAb;AAAA,MACA,iBAAAG;AAAA,MACA,iBAAe;AAAA,MACf,YAAY,EAAE,MAAM,CAAC,wBAAwBF,CAAgB,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAAA;AAAA,MACvF,QAAQ;AAAA,QACN,MAAM;AAAA;AAAA,UAEJ,OAAO;AAAA,UACP,UAAUM;AAAA,UACV,UAAUC;AAAA,QAAA;AAAA,QAEZ,WAAW;AAAA,UACT,WAAW;AAAA,UACX,UAAUD;AAAA,UACV,UAAUC;AAAA,UACV,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,WAAW;AAAA,UACX,GAAGN;AAAA,QAAA;AAAA,MACL;AAAA,MAEF,mBAAmB,MAAM,SAAS;AAAA,MAClC,OAAAO;AAAA,MACC,GAAGL;AAAA,MAEH,UAAAT;AAAA,IAAA;AAAA,EAAA;AAGP;"}
1
+ {"version":3,"file":"TooltipInfo.js","sources":["../../../src/components/TooltipInfo/TooltipInfo.tsx"],"sourcesContent":["import type { TooltipProps } from 'antd';\nimport { Tooltip } from 'antd';\nimport React from 'react';\nimport type { DescriptionItem } from '../Descriptions/CommonDescriptions';\nimport CommonDescriptions from '../Descriptions/CommonDescriptions';\nimport './style.module.scss';\n\n/** Tooltip 展示形态:descriptions=结构化详情(默认);note=标题+描述分层 */\nexport type TooltipInfoType = 'descriptions' | 'note';\n\n/** note 形态内容:标题(粗体)+ 描述(次级色) */\nexport interface TooltipInfoNote {\n title: React.ReactNode;\n description: React.ReactNode;\n}\n\nexport interface TooltipInfoProps extends Pick<\n TooltipProps,\n 'placement' | 'mouseEnterDelay' | 'mouseLeaveDelay' | 'open' | 'onOpenChange'\n> {\n /** 展示形态,默认 descriptions */\n type?: TooltipInfoType;\n /** type='descriptions' 的详情项(默认形态) */\n content?: DescriptionItem[];\n /** type='note' 的标题与描述 */\n note?: TooltipInfoNote;\n children: React.ReactNode;\n /** CommonDescriptions 列数,默认 1(仅 descriptions 形态) */\n column?: number;\n /**\n * descriptions 是否带边框表格样式。\n * 默认 false(气泡内用 dl,避免 table 在 Tooltip 里宽度塌陷);\n * 需要 CommonDescriptions 默认「灰底标签格子」时传 true,并建议设 minWidth/maxWidth。\n */\n bordered?: boolean;\n /** 为 true 时不展示 Tooltip;descriptions 形态下 content 为空也不展示 */\n hidden?: boolean;\n /** 气泡最小宽度,默认 descriptions 220 / note 240 */\n minWidth?: number;\n /** 气泡最大宽度,默认 descriptions 320 / note 380 */\n maxWidth?: number;\n /** @deprecated 使用 classNames.root */\n overlayClassName?: string;\n /** @deprecated 使用 styles.root */\n overlayStyle?: React.CSSProperties;\n}\n\n/** Tooltip 详情展示:descriptions 形态用 CommonDescriptions;note 形态用标题+描述分层 */\nconst TooltipInfo: React.FC<TooltipInfoProps> = ({\n type = 'descriptions',\n content,\n note,\n children,\n column = 1,\n bordered = false,\n hidden = false,\n minWidth,\n maxWidth,\n placement = 'top',\n overlayClassName,\n overlayStyle,\n mouseEnterDelay = 0.3,\n ...rest\n}) => {\n const isNote = type === 'note';\n const empty = isNote ? !note : !content || content.length === 0;\n if (hidden || empty) {\n return <>{children}</>;\n }\n\n const minW = minWidth ?? (isNote ? 240 : 220);\n const maxW = maxWidth ?? (isNote ? 380 : 320);\n\n const title = isNote ? (\n <div className=\"tooltip-info-note\">\n <div className=\"tooltip-info-note-title\">{note!.title}</div>\n <div className=\"tooltip-info-note-desc\">{note!.description}</div>\n </div>\n ) : (\n // 默认 bordered=false:dl 布局,避免 table-layout:fixed 在气泡内宽度塌陷。\n // 显式 bordered 时用表格灰底标签(对齐页面内 CommonDescriptions 默认观感)。\n <CommonDescriptions content={content!} column={column} size=\"small\" bordered={bordered} />\n );\n\n return (\n <Tooltip\n placement={placement}\n mouseEnterDelay={mouseEnterDelay}\n destroyOnHidden\n classNames={{ root: ['tooltip-info-overlay', overlayClassName].filter(Boolean).join(' ') }}\n styles={{\n root: {\n // 覆盖 antd 默认 width:max-content,给气泡确定的最小宽度,避免子元素循环塌陷\n width: 'auto',\n minWidth: minW,\n maxWidth: maxW,\n },\n container: {\n boxSizing: 'border-box',\n minWidth: minW,\n maxWidth: maxW,\n padding: '8px 12px',\n background: 'var(--tooltip-info-bg, var(--bg-color-white, #ffffff))',\n color: 'var(--tooltip-info-color, var(--font-color, #222222))',\n boxShadow: '0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12)',\n ...overlayStyle,\n },\n }}\n getPopupContainer={() => document.body}\n title={title}\n {...rest}\n >\n {children}\n </Tooltip>\n );\n};\n\nexport default TooltipInfo;\n"],"names":["TooltipInfo","type","content","note","children","column","bordered","hidden","minWidth","maxWidth","placement","overlayClassName","overlayStyle","mouseEnterDelay","rest","isNote","empty","minW","maxW","title","jsxs","jsx","CommonDescriptions","Tooltip"],"mappings":";;;AAgDA,MAAMA,IAA0C,CAAC;AAAA,EAC/C,MAAAC,IAAO;AAAA,EACP,SAAAC;AAAA,EACA,MAAAC;AAAA,EACA,UAAAC;AAAA,EACA,QAAAC,IAAS;AAAA,EACT,UAAAC,IAAW;AAAA,EACX,QAAAC,IAAS;AAAA,EACT,UAAAC;AAAA,EACA,UAAAC;AAAA,EACA,WAAAC,IAAY;AAAA,EACZ,kBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,iBAAAC,IAAkB;AAAA,EAClB,GAAGC;AACL,MAAM;AACJ,QAAMC,IAASd,MAAS,QAClBe,IAAQD,IAAS,CAACZ,IAAO,CAACD,KAAWA,EAAQ,WAAW;AAC9D,MAAIK,KAAUS;AACZ,kCAAU,UAAAZ,GAAS;AAGrB,QAAMa,IAAOT,MAAaO,IAAS,MAAM,MACnCG,IAAOT,MAAaM,IAAS,MAAM,MAEnCI,IAAQJ,IACZ,gBAAAK,EAAC,OAAA,EAAI,WAAU,qBACb,UAAA;AAAA,IAAA,gBAAAC,EAAC,OAAA,EAAI,WAAU,2BAA2B,UAAAlB,EAAM,OAAM;AAAA,IACtD,gBAAAkB,EAAC,OAAA,EAAI,WAAU,0BAA0B,YAAM,YAAA,CAAY;AAAA,EAAA,GAC7D;AAAA;AAAA;AAAA,sBAICC,GAAA,EAAmB,SAAApB,GAAmB,QAAAG,GAAgB,MAAK,SAAQ,UAAAC,EAAA,CAAoB;AAAA;AAG1F,SACE,gBAAAe;AAAA,IAACE;AAAA,IAAA;AAAA,MACC,WAAAb;AAAA,MACA,iBAAAG;AAAA,MACA,iBAAe;AAAA,MACf,YAAY,EAAE,MAAM,CAAC,wBAAwBF,CAAgB,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAAA;AAAA,MACvF,QAAQ;AAAA,QACN,MAAM;AAAA;AAAA,UAEJ,OAAO;AAAA,UACP,UAAUM;AAAA,UACV,UAAUC;AAAA,QAAA;AAAA,QAEZ,WAAW;AAAA,UACT,WAAW;AAAA,UACX,UAAUD;AAAA,UACV,UAAUC;AAAA,UACV,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,WAAW;AAAA,UACX,GAAGN;AAAA,QAAA;AAAA,MACL;AAAA,MAEF,mBAAmB,MAAM,SAAS;AAAA,MAClC,OAAAO;AAAA,MACC,GAAGL;AAAA,MAEH,UAAAV;AAAA,IAAA;AAAA,EAAA;AAGP;"}
package/dist/index.d.ts CHANGED
@@ -18,7 +18,7 @@ export { buildDepartmentPathMapFromTree, buildDepartmentPathMapFromFlat, getDepa
18
18
  export type { DepartmentPathMaps } from './utils/department/departmentPath';
19
19
  export { flattenDepartments, findDepartmentRootId, collectDepartmentIds, getNormalUserAccessibleDepartmentIds, extractDepartmentSubtree, getNormalUserDepartmentTree, intersectDepartmentIds, } from './utils/department/departmentScope';
20
20
  export type { DepartmentTreeNode, FlatDepartment } from './utils/department/types';
21
- export { EMPLOYEE_ID_SIX_DIGIT_PATTERN, EMPLOYEE_ID_FORMAT_MESSAGE, employeeIdFormatRule, isValidEmployeeIdFormat, } from './utils/user/employeeId';
21
+ export { EMPLOYEE_ID_MAX_LENGTH, EMPLOYEE_ID_PATTERN, EMPLOYEE_ID_SIX_DIGIT_PATTERN, EMPLOYEE_ID_FORMAT_MESSAGE, employeeIdFormatRule, isValidEmployeeIdFormat, } from './utils/user/employeeId';
22
22
  export { normalizeRawPersonList, normalizePersonDtos, resolvePersonDepartmentName, toPersonOptions, toReviewerPersonOptions, formatPersonValueLabel, toPersonSelectOptions, buildPersonOptionLookup, resolveSelectPersonOption, createPersonSelectFilter, matchPersonOptionSearch, } from './utils/personOption';
23
23
  export type { PersonOptionDto, ReviewerOptionDto, PersonSelectOption } from './utils/personOption';
24
24
  export * from './components/Auth';