@zero-library/common 2.2.7 → 2.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -1,13 +1,19 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
2
  import Icon, { MinusCircleOutlined, PlusCircleOutlined, RedoOutlined, FileUnknownOutlined, FileZipOutlined, FileMarkdownOutlined, FileGifOutlined, FileImageOutlined, FileJpgOutlined, NotificationOutlined, VideoCameraOutlined, FilePptOutlined, FileExcelOutlined, FileWordOutlined, FilePdfOutlined, FileTextOutlined, AudioMutedOutlined, AudioOutlined } from '@ant-design/icons';
3
- import { Spin, Flex, Button, Result, message, notification, Modal, Splitter, Empty, Image, Drawer, Tag, Avatar, Alert, Form, Input } from 'antd';
3
+ import { Spin, message, notification, Modal, Flex, Button, Result, Splitter, Empty, Image, Drawer, Tag, Avatar, Alert, Form, Input } from 'antd';
4
4
  import classNames from 'classnames';
5
5
  import { renderAsync } from 'docx-preview';
6
6
  import * as React16 from 'react';
7
7
  import { forwardRef, useState, useMemo, useEffect, useRef, lazy, Suspense, createContext, useCallback, useContext } from 'react';
8
+ import AES from 'crypto-js/aes';
9
+ import encUtf8 from 'crypto-js/enc-utf8';
10
+ import MarkdownIt from 'markdown-it';
11
+ import Decimal from 'decimal.js';
12
+ import dayjs from 'dayjs';
13
+ import relativeTime from 'dayjs/plugin/relativeTime';
14
+ import axios from 'axios';
8
15
  import parse from 'html-react-parser';
9
16
  import { jsonrepair } from 'jsonrepair';
10
- import markdownit from 'markdown-it';
11
17
  import { Worker, Viewer, PasswordStatus } from '@react-pdf-viewer/core';
12
18
  import { pageNavigationPlugin } from '@react-pdf-viewer/page-navigation';
13
19
  import { thumbnailPlugin } from '@react-pdf-viewer/thumbnail';
@@ -15,12 +21,6 @@ import { zoomPlugin } from '@react-pdf-viewer/zoom';
15
21
  import '@react-pdf-viewer/core/lib/styles/index.css';
16
22
  import zh_CN from '@react-pdf-viewer/locales/lib/zh_CN.json';
17
23
  import '@react-pdf-viewer/page-navigation/lib/styles/index.css';
18
- import AES from 'crypto-js/aes';
19
- import encUtf8 from 'crypto-js/enc-utf8';
20
- import Decimal from 'decimal.js';
21
- import dayjs from 'dayjs';
22
- import relativeTime from 'dayjs/plugin/relativeTime';
23
- import axios from 'axios';
24
24
  import '@react-pdf-viewer/thumbnail/lib/styles/index.css';
25
25
  import '@react-pdf-viewer/zoom/lib/styles/index.css';
26
26
  import { getMarkRange, Extension, isNodeSelection, useCurrentEditor, useEditor, EditorContext, BubbleMenu, EditorContent } from '@tiptap/react';
@@ -62,319 +62,32 @@ var AudioPlayer_default = ({ fileUrl }) => {
62
62
  "\u60A8\u7684\u6D4F\u89C8\u5668\u4E0D\u652F\u6301 audio \u6807\u7B7E\u3002"
63
63
  ] });
64
64
  };
65
- var DocxPreview_default = ({ fileUrl, scale = 1 }) => {
66
- const containerRef = useRef(null);
67
- const [zoomRatio, setZoomRatio] = useState(scale);
68
- useEffect(() => {
69
- if (!fileUrl || !containerRef.current) return;
70
- containerRef.current.innerHTML = "";
71
- fetch(fileUrl).then((res) => res.arrayBuffer()).then(
72
- (arrayBuffer) => renderAsync(arrayBuffer, containerRef.current, null, {
73
- breakPages: true,
74
- renderHeaders: true,
75
- renderFooters: true,
76
- ignoreWidth: false,
77
- ignoreHeight: false
78
- })
79
- ).catch((err) => {
80
- console.error("docx-preview \u6E32\u67D3\u5931\u8D25:", err);
81
- if (containerRef.current) containerRef.current.innerHTML = '<p class="text-center">\u6587\u6863\u52A0\u8F7D\u5931\u8D25</p>';
82
- });
83
- }, [fileUrl]);
84
- const zoomIn = () => setZoomRatio((z) => Math.min(z + 0.1, 3));
85
- const zoomOut = () => setZoomRatio((z) => Math.max(z - 0.1, 0.3));
86
- const resetZoom = () => {
87
- setZoomRatio(1);
88
- };
89
- return /* @__PURE__ */ jsxs("div", { className: classNames(styles_module_default.nsPreviewDocx, "height-full"), children: [
90
- /* @__PURE__ */ jsxs(Flex, { gap: 6, align: "center", className: styles_module_default.docxToolbar, children: [
91
- /* @__PURE__ */ jsx(Button, { onClick: zoomOut, icon: /* @__PURE__ */ jsx(MinusCircleOutlined, {}), title: "\u7F29\u5C0F" }),
92
- /* @__PURE__ */ jsx(Button, { onClick: zoomIn, icon: /* @__PURE__ */ jsx(PlusCircleOutlined, {}), title: "\u653E\u5927" }),
93
- /* @__PURE__ */ jsx(Button, { onClick: resetZoom, icon: /* @__PURE__ */ jsx(RedoOutlined, {}), title: "\u8FD8\u539F" })
94
- ] }),
95
- /* @__PURE__ */ jsx("div", { className: classNames(styles_module_default.docxContent, "height-full", "scroll-fade-in"), children: /* @__PURE__ */ jsx(
96
- "div",
97
- {
98
- ref: containerRef,
99
- style: {
100
- transform: `scale(${zoomRatio})`,
101
- transformOrigin: "top center"
102
- }
103
- }
104
- ) })
105
- ] });
106
- };
107
- var FileIcon_default = ({ suffix, fontSize = 22 }) => {
108
- const styles = { fontSize, color: "var(--ant-color-primary)" };
109
- const Icon2 = useMemo(() => {
110
- switch (suffix?.toUpperCase()) {
111
- case "TXT":
112
- return /* @__PURE__ */ jsx(FileTextOutlined, {});
113
- case "PDF":
114
- return /* @__PURE__ */ jsx(FilePdfOutlined, {});
115
- case "DOC":
116
- case "DOCX":
117
- return /* @__PURE__ */ jsx(FileWordOutlined, {});
118
- case "XLS":
119
- case "XLSX":
120
- return /* @__PURE__ */ jsx(FileExcelOutlined, {});
121
- case "PPT":
122
- return /* @__PURE__ */ jsx(FilePptOutlined, {});
123
- case "MP4":
124
- case "MOV":
125
- case "MKV":
126
- case "AVI":
127
- case "FLV":
128
- return /* @__PURE__ */ jsx(VideoCameraOutlined, {});
129
- case "MP3":
130
- case "WAV":
131
- case "M4A":
132
- case "ACC":
133
- case "WMA":
134
- return /* @__PURE__ */ jsx(NotificationOutlined, {});
135
- case "JPG":
136
- case "JPEG":
137
- return /* @__PURE__ */ jsx(FileJpgOutlined, {});
138
- case "PNG":
139
- return /* @__PURE__ */ jsx(FileImageOutlined, {});
140
- case "GIF":
141
- return /* @__PURE__ */ jsx(FileGifOutlined, {});
142
- case "MD":
143
- case "MARKDOWN":
144
- return /* @__PURE__ */ jsx(FileMarkdownOutlined, {});
145
- case "ZIP":
146
- case "RAR":
147
- case "7Z":
148
- return /* @__PURE__ */ jsx(FileZipOutlined, {});
149
- case "CATALOG":
150
- return /* @__PURE__ */ jsx("i", { style: styles, className: "iconfont icon-wenjianjia" });
151
- // 文件夹图标
152
- default:
153
- return /* @__PURE__ */ jsx(FileUnknownOutlined, {});
154
- }
155
- }, [suffix]);
156
- return /* @__PURE__ */ jsx("span", { style: styles, children: Icon2 });
157
- };
158
- var VideoPlayer_default = ({ fileUrl }) => {
159
- return /* @__PURE__ */ jsxs("video", { controls: true, className: styles_module_default.nsPreviewVideo, children: [
160
- /* @__PURE__ */ jsx("source", { src: fileUrl, type: "video/mp4" }),
161
- "\u60A8\u7684\u6D4F\u89C8\u5668\u4E0D\u652F\u6301 video \u6807\u7B7E\u3002"
162
- ] });
163
- };
164
- var baseComponentMap = {
165
- // renderMarkdown: () => import('@/components/RenderMarkdown')
166
- };
167
- var LazyComponent_default = ({ type, customComponents, ...rest }) => {
168
- const componentMap = useMemo(() => {
169
- return { ...baseComponentMap, ...customComponents };
170
- }, [customComponents]);
171
- const LazyComponent = useMemo(() => {
172
- const loader = componentMap[type];
173
- return loader ? lazy(loader) : null;
174
- }, [type, componentMap]);
175
- if (!LazyComponent) return /* @__PURE__ */ jsxs("div", { children: [
176
- "\u672A\u77E5\u7C7B\u578B\uFF1A",
177
- type
178
- ] });
179
- return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("div", { children: "\u52A0\u8F7D\u4E2D..." }), children: /* @__PURE__ */ jsx(LazyComponent, { ...rest }) });
180
- };
181
- var md = markdownit({ html: true, breaks: true });
182
- md.renderer.rules.link_open = function(tokens, idx, options, env, self) {
183
- const token = tokens[idx];
184
- token.attrPush(["target", "_blank"]);
185
- return self.renderToken(tokens, idx, options);
186
- };
187
- function parseData(raw) {
188
- let obj = {};
189
- try {
190
- obj = JSON.parse(raw);
191
- } catch {
192
- try {
193
- obj = JSON.parse(jsonrepair(raw));
194
- } catch {
195
- obj = { _raw: raw };
196
- }
197
- }
198
- return obj;
65
+
66
+ // src/utils/is.ts
67
+ var toString = Object.prototype.toString;
68
+ function is(val, type) {
69
+ return toString.call(val) === `[object ${type}]`;
199
70
  }
200
- function highlightKeywords(html, keywords) {
201
- const escaped = keywords.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
202
- const regex = new RegExp(`(${escaped.join("|")})`, "gi");
203
- return html.replace(regex, '<span class="cube-hl">$1</span>');
71
+ function isUnDef(val) {
72
+ return is(val, "Undefined");
204
73
  }
205
- function makePlaceholder(id) {
206
- return `__ALERT_DATA_${id}__`;
74
+ function isDef(val) {
75
+ return !isUnDef(val);
207
76
  }
208
- function alertMarkClean(src) {
209
- let pos = 0;
210
- let id = 0;
211
- let out = "";
212
- const placeholders = /* @__PURE__ */ new Map();
213
- while (pos < src.length) {
214
- const start = src.indexOf(":::alert", pos);
215
- if (start === -1) {
216
- out += src.slice(pos);
217
- break;
218
- }
219
- out += src.slice(pos, start);
220
- const afterStart = src.slice(start);
221
- const relAfter = afterStart.slice(":::alert".length);
222
- const matchLineEnd = relAfter.search(/\s*:::\s*/);
223
- let endIdx = -1;
224
- let isNoEnd = 1;
225
- if (matchLineEnd !== -1) {
226
- endIdx = start + ":::alert".length + matchLineEnd;
227
- isNoEnd = 0;
228
- } else {
229
- endIdx = src.length;
230
- isNoEnd = 1;
231
- }
232
- const inner = src.slice(start + ":::alert".length, endIdx).trim();
233
- const typeMatch = inner.match(/type\s*=\s*(?:(['"])(.*?)\1|(\S+))/);
234
- const type = typeMatch ? typeMatch[2] ?? typeMatch[3] : void 0;
235
- const dataIdx = inner.search(/\bdata\s*=/);
236
- let rawData = "";
237
- if (dataIdx !== -1) {
238
- rawData = inner.slice(dataIdx + inner.slice(dataIdx).match(/\bdata\s*=/)[0].length).trim();
239
- }
240
- const ph = makePlaceholder(id++);
241
- placeholders.set(ph, rawData);
242
- const typeText = type ? `type=${JSON.stringify(type)}` : "";
243
- out += `:::alert ${typeText} data="${ph}" loading="${isNoEnd}" :::`;
244
- const realClose = src.indexOf(":::", endIdx);
245
- pos = realClose === -1 ? endIdx : realClose + 3;
77
+ function isObject(val) {
78
+ return is(val, "Object");
79
+ }
80
+ function isEmptyObj(val) {
81
+ if (isObject(val)) {
82
+ return Object.keys(val).length === 0;
246
83
  }
247
- return { text: out, placeholders };
84
+ return false;
248
85
  }
249
- function alertInlinePlugin(md2) {
250
- md2.inline.ruler.before("emphasis", "alert_inline", function(state, silent) {
251
- const pos = state.pos;
252
- const src = state.src;
253
- if (src.slice(pos, pos + 3) !== ":::") return false;
254
- const m = src.slice(pos).match(/^:::alert\b([^\n\r]*?):::/);
255
- if (!m) return false;
256
- if (silent) return false;
257
- const raw = m[1].trim();
258
- const html = `<lazy-component ${raw}></lazy-component>`;
259
- const token = state.push("html_inline", "", 0);
260
- token.content = html;
261
- state.pos += m[0].length;
262
- return true;
263
- });
86
+ function isDate(val) {
87
+ return is(val, "Date");
264
88
  }
265
- try {
266
- md.use(alertInlinePlugin);
267
- } catch {
268
- }
269
- var filterMarkdown = (content = "") => {
270
- if (!content) return content;
271
- return content.replace(/<!--[\s\S]*?(?:-->|$)/g, "");
272
- };
273
- var RenderMarkdown_default = ({ content = "", searchValue, customComponents, ...rest }) => {
274
- const reactContent = useMemo(() => {
275
- if (!content) return null;
276
- const { text: preprocessed, placeholders } = alertMarkClean(filterMarkdown(content));
277
- let rawHtml = md.render(preprocessed);
278
- rawHtml = searchValue ? highlightKeywords(rawHtml, [searchValue]) : rawHtml;
279
- let lazyIndex = -1;
280
- return parse(rawHtml, {
281
- replace: (domNode) => {
282
- if (domNode.name === "lazy-component") {
283
- lazyIndex++;
284
- const el = domNode;
285
- const type = el.attribs.type;
286
- const loading = !!Number(el.attribs.loading);
287
- const dataAttr = el.attribs.data || "";
288
- let data = {};
289
- if (/^__ALERT_DATA_\d+__$/.test(dataAttr)) {
290
- const raw = placeholders.get(dataAttr) ?? "";
291
- data = parseData(raw);
292
- }
293
- return /* @__PURE__ */ jsx(LazyComponent_default, { customComponents, type, data, loading, ...rest }, `${type}${lazyIndex}`);
294
- }
295
- }
296
- });
297
- }, [content, searchValue]);
298
- return /* @__PURE__ */ jsx("div", { className: "ns-markdown", children: reactContent });
299
- };
300
- var MarkdownPreview_default = ({ fileUrl, searchValue }) => {
301
- const [content, setContent] = useState("");
302
- const [error, setError] = useState("");
303
- const fetchMarkdown = async () => {
304
- const res = await fetch(fileUrl);
305
- if (res.status !== 200) {
306
- throw new Error(`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${res.status}`);
307
- }
308
- const markdownText = await res.text();
309
- if (!markdownText) {
310
- throw new Error("\u8FD4\u56DE\u5185\u5BB9\u4E3A\u7A7A");
311
- }
312
- setContent(markdownText);
313
- };
314
- const init = async () => {
315
- setContent("");
316
- setError("");
317
- if (fileUrl) {
318
- try {
319
- await fetchMarkdown();
320
- } catch (error2) {
321
- setError("\u52A0\u8F7D\u6216\u89E3\u6790 Markdown \u5931\u8D25");
322
- }
323
- }
324
- };
325
- useEffect(() => {
326
- init();
327
- }, [fileUrl]);
328
- return error ? /* @__PURE__ */ jsx(Result, { status: "error", title: error }) : /* @__PURE__ */ jsx("div", { className: "height-full", children: /* @__PURE__ */ jsx(RenderMarkdown_default, { content, searchValue }) });
329
- };
330
-
331
- // src/hooks/iframe/iframeRelay.ts
332
- function emit(type, data, to = "top") {
333
- const payload = { type, data, to };
334
- try {
335
- window.parent.postMessage(payload, "*");
336
- } catch (err) {
337
- console.warn("emit parent failed", err);
338
- }
339
- }
340
- function emitToChild(iframeWindow, type, data, origin = "*") {
341
- if (!iframeWindow) {
342
- console.warn("emitToChild failed: iframeWindow is null");
343
- return;
344
- }
345
- const payload = { type, data, to: "child" };
346
- try {
347
- iframeWindow.postMessage(payload, origin);
348
- } catch (err) {
349
- console.warn("emit to child failed", err);
350
- }
351
- }
352
-
353
- // src/utils/is.ts
354
- var toString = Object.prototype.toString;
355
- function is(val, type) {
356
- return toString.call(val) === `[object ${type}]`;
357
- }
358
- function isUnDef(val) {
359
- return is(val, "Undefined");
360
- }
361
- function isDef(val) {
362
- return !isUnDef(val);
363
- }
364
- function isObject(val) {
365
- return is(val, "Object");
366
- }
367
- function isEmptyObj(val) {
368
- if (isObject(val)) {
369
- return Object.keys(val).length === 0;
370
- }
371
- return false;
372
- }
373
- function isDate(val) {
374
- return is(val, "Date");
375
- }
376
- function isNull(val) {
377
- return is(val, "Null");
89
+ function isNull(val) {
90
+ return is(val, "Null");
378
91
  }
379
92
  function isNullOrUnDef(val) {
380
93
  return isUnDef(val) || isNull(val);
@@ -496,143 +209,6 @@ var isJson = (text = "") => {
496
209
  return false;
497
210
  }
498
211
  };
499
-
500
- // src/hooks/iframe/useIframeRelayBridge.ts
501
- var useIframeRelayBridge_default = (allowedOrigins = ["*"]) => {
502
- const handlers = useRef({});
503
- useEffect(() => {
504
- const onMessage = (evt) => {
505
- const { data, source, origin } = evt;
506
- if (!data || !isObject(data) || !data.type) return;
507
- if (allowedOrigins[0] !== "*" && !allowedOrigins.includes(origin)) return;
508
- const { type, data: params, to = "parent" } = data;
509
- const isTop = window.parent === window;
510
- if (to === "top" && !isTop) {
511
- window.parent.postMessage(data, allowedOrigins[0] === "*" ? "*" : origin);
512
- return;
513
- }
514
- const fns = handlers.current[type] || [];
515
- fns.forEach((fn) => fn(params, source, origin));
516
- };
517
- window.addEventListener("message", onMessage);
518
- return () => window.removeEventListener("message", onMessage);
519
- }, [allowedOrigins]);
520
- function on(type, handler) {
521
- handlers.current[type] = handlers.current[type] || [];
522
- handlers.current[type].push(handler);
523
- }
524
- function off(type, handler) {
525
- handlers.current[type] = (handlers.current[type] || []).filter((fn) => fn !== handler);
526
- }
527
- return { on, off };
528
- };
529
- var useAutoRefresh_default = (listenValue, shouldRefresh, callback, delay = 1e4) => {
530
- const timerRef = useRef(null);
531
- const shouldRefreshRef = useRef(shouldRefresh);
532
- const callbackRef = useRef(callback);
533
- const [num, setNum] = useState(0);
534
- useEffect(() => {
535
- shouldRefreshRef.current = shouldRefresh;
536
- callbackRef.current = callback;
537
- }, [shouldRefresh, callback]);
538
- useEffect(() => {
539
- if (timerRef.current) {
540
- clearTimeout(timerRef.current);
541
- timerRef.current = null;
542
- }
543
- if (shouldRefreshRef.current(listenValue)) {
544
- timerRef.current = setTimeout(async () => {
545
- await callbackRef.current();
546
- setNum(num + 1);
547
- }, delay);
548
- }
549
- return () => {
550
- if (timerRef.current) {
551
- clearTimeout(timerRef.current);
552
- }
553
- };
554
- }, [listenValue, delay, num]);
555
- };
556
- var useCountDown_default = (callback) => {
557
- const [count, setCount] = useState(0);
558
- const [startCount, setStartCount] = useState(0);
559
- const timer = useRef(null);
560
- const pause = () => {
561
- clearInterval(timer.current);
562
- timer.current = null;
563
- };
564
- const start = (initialValue = 60) => {
565
- pause();
566
- setCount(initialValue);
567
- setStartCount((startCount2) => startCount2 + 1);
568
- timer.current = setInterval(() => {
569
- setCount((count2) => count2 - 1);
570
- }, 1e3);
571
- };
572
- useEffect(() => {
573
- return () => {
574
- pause();
575
- };
576
- }, []);
577
- useEffect(() => {
578
- if (count === 0 && startCount !== 0) {
579
- pause();
580
- callback?.();
581
- }
582
- }, [count]);
583
- return { count, start, pause, startCount };
584
- };
585
- var useCreateValtioContext_default = () => {
586
- const Context = createContext(null);
587
- const ValtioProvider = ({ store, children }) => /* @__PURE__ */ jsx(Context.Provider, { value: store, children });
588
- const useValtioStore = () => {
589
- const store = useContext(Context);
590
- if (!store) throw new Error("useStore must be used within Provider");
591
- return store;
592
- };
593
- return {
594
- ValtioProvider,
595
- useValtioStore,
596
- // 导出 Context 以便外部使用
597
- Context
598
- };
599
- };
600
- var useDebounce_default = (func, wait = 400) => {
601
- const { current } = useRef({ func, timeOut: null });
602
- useEffect(() => {
603
- current.func = func;
604
- }, [func]);
605
- let args;
606
- function debounce(..._args) {
607
- args = _args;
608
- if (current.timeOut) {
609
- clearTimeout(current.timeOut);
610
- current.timeOut = null;
611
- }
612
- return new Promise((resolve, reject) => {
613
- current.timeOut = setTimeout(async () => {
614
- try {
615
- const result = await current.func.apply(null, args);
616
- resolve(result);
617
- } catch (e) {
618
- reject(e);
619
- }
620
- }, wait);
621
- });
622
- }
623
- function cancel() {
624
- if (!current.timeOut) return;
625
- clearTimeout(current.timeOut);
626
- current.timeOut = null;
627
- }
628
- function flush() {
629
- cancel();
630
- return current.func.apply(null, args);
631
- }
632
- debounce.flush = flush;
633
- debounce.cancel = cancel;
634
- return useCallback(debounce, []);
635
- };
636
212
  var OperatorToMethodName = {
637
213
  "+": "plus",
638
214
  "-": "minus",
@@ -1193,7 +769,7 @@ function formatSize(value, options = {}) {
1193
769
  return `${toFixed(size, precision2, !trimZero)}${UNIT_LIST[index]}`;
1194
770
  }
1195
771
  var markdownToText = (() => {
1196
- const md2 = new markdownit({
772
+ const md2 = new MarkdownIt({
1197
773
  html: true,
1198
774
  linkify: true,
1199
775
  typographer: false
@@ -1205,174 +781,17 @@ var markdownToText = (() => {
1205
781
  return text;
1206
782
  };
1207
783
  })();
1208
-
1209
- // src/hooks/useDeepEffect.ts
1210
- var useDeepEffect_default = (effect, deps) => {
1211
- const prevDepsRef = useRef();
1212
- const depsChanged = !prevDepsRef.current || deps.length !== prevDepsRef.current.length || deps.some((dep, i) => !deepEqual(dep, prevDepsRef.current[i]));
1213
- useEffect(() => {
1214
- if (depsChanged) {
1215
- prevDepsRef.current = deps;
1216
- return effect();
1217
- }
1218
- }, [depsChanged]);
784
+ dayjs.extend(relativeTime);
785
+ var DEFAULT_DATE_TIME_FORMAT = "YYYY-MM-DD HH:mm:ss";
786
+ var DEFAULT_DATE_FORMAT = "YYYY-MM-DD";
787
+ var DEFAULT_YEAR_MONTH_FORMAT = "YYYY\u5E74MM\u6708";
788
+ var DEFAULT_YEAR_MONTH_DAY_FORMAT = "YYYY\u5E74MM\u6708DD\u65E5";
789
+ var DEFAULT_UNIT = "date";
790
+ var getStartOfTimestamp = (date, unit = DEFAULT_UNIT) => {
791
+ return dayjs(date).startOf(unit).valueOf();
1219
792
  };
1220
- var useRefState_default = (init) => {
1221
- const [state, setState] = useState(init);
1222
- const stateRef = useRef(init);
1223
- const setProxy = (newVal) => {
1224
- stateRef.current = newVal;
1225
- setState(newVal);
1226
- };
1227
- const getState = () => stateRef.current;
1228
- return [state, setProxy, getState];
1229
- };
1230
- var useSpeech_default = ({ onResult, lang = "zh-CN" }) => {
1231
- const [permission, setPermission] = useState("prompt");
1232
- const [isRecording, setIsRecording] = useState(false);
1233
- const recognitionRef = useRef(null);
1234
- useEffect(() => {
1235
- const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
1236
- if (!SpeechRecognition) {
1237
- setPermission("unsupported");
1238
- return;
1239
- }
1240
- const recognition = new SpeechRecognition();
1241
- recognition.continuous = true;
1242
- recognition.interimResults = false;
1243
- recognition.lang = lang;
1244
- recognition.onresult = (event) => {
1245
- let transcript = "";
1246
- for (let i = event.resultIndex; i < event.results.length; i++) {
1247
- transcript += event.results[i][0].transcript;
1248
- }
1249
- onResult?.(transcript.trim());
1250
- };
1251
- recognition.onend = () => {
1252
- setIsRecording(false);
1253
- };
1254
- recognition.onerror = (error) => {
1255
- setIsRecording(false);
1256
- console.error("Speech recognition error:", error);
1257
- };
1258
- recognitionRef.current = recognition;
1259
- return () => {
1260
- recognition.stop?.();
1261
- recognition.onresult = null;
1262
- recognition.onend = null;
1263
- recognition.onerror = null;
1264
- };
1265
- }, [lang, onResult]);
1266
- useEffect(() => {
1267
- if (!navigator.permissions) return;
1268
- navigator.permissions.query({ name: "microphone" }).then((status) => {
1269
- setPermission(status.state);
1270
- status.onchange = () => setPermission(status.state);
1271
- });
1272
- }, []);
1273
- const requestPermission = useCallback(async () => {
1274
- try {
1275
- await navigator.mediaDevices.getUserMedia({ audio: true });
1276
- setPermission("granted");
1277
- } catch {
1278
- setPermission("denied");
1279
- }
1280
- }, []);
1281
- const start = useCallback(() => {
1282
- if (permission === "prompt") {
1283
- requestPermission();
1284
- return;
1285
- }
1286
- if (permission !== "granted") return;
1287
- if (!isRecording) {
1288
- recognitionRef.current?.start();
1289
- setIsRecording(true);
1290
- }
1291
- }, [permission, isRecording, requestPermission]);
1292
- const stop = useCallback(() => {
1293
- try {
1294
- recognitionRef.current?.stop();
1295
- } finally {
1296
- setIsRecording(false);
1297
- }
1298
- }, []);
1299
- return {
1300
- /**
1301
- * 权限状态
1302
- */
1303
- permission,
1304
- /**
1305
- * 录音状态
1306
- */
1307
- isRecording,
1308
- /** 开始语音识别 */
1309
- start,
1310
- /** 停止语音识别 */
1311
- stop
1312
- };
1313
- };
1314
- var useSyncInput_default = (storeValue, setStoreValue) => {
1315
- const [inputValue, setInputValue] = useState(storeValue);
1316
- useEffect(() => {
1317
- if (storeValue !== inputValue) {
1318
- setInputValue(storeValue);
1319
- }
1320
- }, [storeValue]);
1321
- const handleValueChange = (value) => {
1322
- setStoreValue(value);
1323
- setInputValue(value);
1324
- };
1325
- return {
1326
- inputValue,
1327
- setInputValue: handleValueChange
1328
- };
1329
- };
1330
- var useThrottle_default = (func, wait) => {
1331
- const { current } = useRef({ func, timeOut: null });
1332
- useEffect(() => {
1333
- current.func = func;
1334
- }, [func]);
1335
- let args;
1336
- function throttle(..._args) {
1337
- args = _args;
1338
- return new Promise((resolve, reject) => {
1339
- if (!current.timeOut) {
1340
- try {
1341
- const result = current.func.apply(null, args);
1342
- resolve(result);
1343
- } catch (e) {
1344
- reject(e);
1345
- }
1346
- current.timeOut = setTimeout(() => {
1347
- current.timeOut = null;
1348
- }, wait);
1349
- }
1350
- });
1351
- }
1352
- function cancel() {
1353
- if (!current.timeOut) return;
1354
- clearTimeout(current.timeOut);
1355
- current.timeOut = null;
1356
- }
1357
- function flush() {
1358
- cancel();
1359
- return current.func.apply(null, args);
1360
- }
1361
- throttle.flush = flush;
1362
- throttle.cancel = cancel;
1363
- return useCallback(throttle, []);
1364
- };
1365
- dayjs.extend(relativeTime);
1366
- var DEFAULT_DATE_TIME_FORMAT = "YYYY-MM-DD HH:mm:ss";
1367
- var DEFAULT_DATE_FORMAT = "YYYY-MM-DD";
1368
- var DEFAULT_YEAR_MONTH_FORMAT = "YYYY\u5E74MM\u6708";
1369
- var DEFAULT_YEAR_MONTH_DAY_FORMAT = "YYYY\u5E74MM\u6708DD\u65E5";
1370
- var DEFAULT_UNIT = "date";
1371
- var getStartOfTimestamp = (date, unit = DEFAULT_UNIT) => {
1372
- return dayjs(date).startOf(unit).valueOf();
1373
- };
1374
- var getEndOfTimestamp = (date, unit = DEFAULT_UNIT) => {
1375
- return dayjs(date).endOf(unit).valueOf();
793
+ var getEndOfTimestamp = (date, unit = DEFAULT_UNIT) => {
794
+ return dayjs(date).endOf(unit).valueOf();
1376
795
  };
1377
796
  var formatDate = (date, fmt = DEFAULT_DATE_TIME_FORMAT) => {
1378
797
  if (date) {
@@ -1690,7 +1109,6 @@ function createSecureManager({ key, storage = localStorage, aesKey }) {
1690
1109
  try {
1691
1110
  return JSON.parse(cipher);
1692
1111
  } catch (e) {
1693
- console.log("Failed to parse stored data:", e);
1694
1112
  return cipher;
1695
1113
  }
1696
1114
  };
@@ -1721,8 +1139,590 @@ function createTokenManager({ key, storage = localStorage }) {
1721
1139
  clear: tokenManager.clear
1722
1140
  };
1723
1141
  }
1724
-
1725
- // src/hooks/webSocket/useWebSocket.ts
1142
+ var DocxPreview_default = ({ fileUrl, scale = 1 }) => {
1143
+ const containerRef = useRef(null);
1144
+ const [zoomRatio, setZoomRatio] = useState(scale);
1145
+ useEffect(() => {
1146
+ if (!fileUrl || !containerRef.current) return;
1147
+ containerRef.current.innerHTML = "";
1148
+ fetch(fileUrl).then((res) => res.arrayBuffer()).then(async (arrayBuffer) => {
1149
+ await renderAsync(arrayBuffer, containerRef.current, null, {
1150
+ breakPages: true,
1151
+ renderHeaders: true,
1152
+ renderFooters: true,
1153
+ ignoreWidth: false,
1154
+ ignoreHeight: false
1155
+ });
1156
+ containerRef.current.querySelectorAll("a[href]").forEach((linkEle) => {
1157
+ const href = linkEle.getAttribute("href");
1158
+ if (href && isExternal(href)) {
1159
+ linkEle.setAttribute("target", "_blank");
1160
+ linkEle.setAttribute("rel", "noopener noreferrer");
1161
+ }
1162
+ });
1163
+ }).catch((err) => {
1164
+ console.error("docx-preview \u6E32\u67D3\u5931\u8D25:", err);
1165
+ if (containerRef.current) containerRef.current.innerHTML = '<p class="text-center">\u6587\u6863\u52A0\u8F7D\u5931\u8D25</p>';
1166
+ });
1167
+ }, [fileUrl]);
1168
+ const zoomIn = () => setZoomRatio((z) => Math.min(z + 0.1, 3));
1169
+ const zoomOut = () => setZoomRatio((z) => Math.max(z - 0.1, 0.3));
1170
+ const resetZoom = () => {
1171
+ setZoomRatio(1);
1172
+ };
1173
+ return /* @__PURE__ */ jsxs("div", { className: classNames(styles_module_default.nsPreviewDocx, "height-full"), children: [
1174
+ /* @__PURE__ */ jsxs(Flex, { gap: 6, align: "center", className: styles_module_default.docxToolbar, children: [
1175
+ /* @__PURE__ */ jsx(Button, { onClick: zoomOut, icon: /* @__PURE__ */ jsx(MinusCircleOutlined, {}), title: "\u7F29\u5C0F" }),
1176
+ /* @__PURE__ */ jsx(Button, { onClick: zoomIn, icon: /* @__PURE__ */ jsx(PlusCircleOutlined, {}), title: "\u653E\u5927" }),
1177
+ /* @__PURE__ */ jsx(Button, { onClick: resetZoom, icon: /* @__PURE__ */ jsx(RedoOutlined, {}), title: "\u8FD8\u539F" })
1178
+ ] }),
1179
+ /* @__PURE__ */ jsx("div", { className: classNames(styles_module_default.docxContent, "height-full", "scroll-fade-in"), children: /* @__PURE__ */ jsx(
1180
+ "div",
1181
+ {
1182
+ ref: containerRef,
1183
+ style: {
1184
+ transform: `scale(${zoomRatio})`,
1185
+ transformOrigin: "top center"
1186
+ }
1187
+ }
1188
+ ) })
1189
+ ] });
1190
+ };
1191
+ var FileIcon_default = ({ suffix, fontSize = 22 }) => {
1192
+ const styles = { fontSize, color: "var(--ant-color-primary)" };
1193
+ const Icon2 = useMemo(() => {
1194
+ switch (suffix?.toUpperCase()) {
1195
+ case "TXT":
1196
+ return /* @__PURE__ */ jsx(FileTextOutlined, {});
1197
+ case "PDF":
1198
+ return /* @__PURE__ */ jsx(FilePdfOutlined, {});
1199
+ case "DOC":
1200
+ case "DOCX":
1201
+ return /* @__PURE__ */ jsx(FileWordOutlined, {});
1202
+ case "XLS":
1203
+ case "XLSX":
1204
+ return /* @__PURE__ */ jsx(FileExcelOutlined, {});
1205
+ case "PPT":
1206
+ return /* @__PURE__ */ jsx(FilePptOutlined, {});
1207
+ case "MP4":
1208
+ case "MOV":
1209
+ case "MKV":
1210
+ case "AVI":
1211
+ case "FLV":
1212
+ return /* @__PURE__ */ jsx(VideoCameraOutlined, {});
1213
+ case "MP3":
1214
+ case "WAV":
1215
+ case "M4A":
1216
+ case "ACC":
1217
+ case "WMA":
1218
+ return /* @__PURE__ */ jsx(NotificationOutlined, {});
1219
+ case "JPG":
1220
+ case "JPEG":
1221
+ return /* @__PURE__ */ jsx(FileJpgOutlined, {});
1222
+ case "PNG":
1223
+ return /* @__PURE__ */ jsx(FileImageOutlined, {});
1224
+ case "GIF":
1225
+ return /* @__PURE__ */ jsx(FileGifOutlined, {});
1226
+ case "MD":
1227
+ case "MARKDOWN":
1228
+ return /* @__PURE__ */ jsx(FileMarkdownOutlined, {});
1229
+ case "ZIP":
1230
+ case "RAR":
1231
+ case "7Z":
1232
+ return /* @__PURE__ */ jsx(FileZipOutlined, {});
1233
+ case "CATALOG":
1234
+ return /* @__PURE__ */ jsx("i", { style: styles, className: "iconfont icon-wenjianjia" });
1235
+ // 文件夹图标
1236
+ default:
1237
+ return /* @__PURE__ */ jsx(FileUnknownOutlined, {});
1238
+ }
1239
+ }, [suffix]);
1240
+ return /* @__PURE__ */ jsx("span", { style: styles, children: Icon2 });
1241
+ };
1242
+ var VideoPlayer_default = ({ fileUrl }) => {
1243
+ return /* @__PURE__ */ jsxs("video", { controls: true, className: styles_module_default.nsPreviewVideo, children: [
1244
+ /* @__PURE__ */ jsx("source", { src: fileUrl, type: "video/mp4" }),
1245
+ "\u60A8\u7684\u6D4F\u89C8\u5668\u4E0D\u652F\u6301 video \u6807\u7B7E\u3002"
1246
+ ] });
1247
+ };
1248
+ var baseComponentMap = {
1249
+ // renderMarkdown: () => import('@/components/RenderMarkdown')
1250
+ };
1251
+ var LazyComponent_default = ({ type, customComponents, ...rest }) => {
1252
+ const componentMap = useMemo(() => {
1253
+ return { ...baseComponentMap, ...customComponents };
1254
+ }, [customComponents]);
1255
+ const LazyComponent = useMemo(() => {
1256
+ const loader = componentMap[type];
1257
+ return loader ? lazy(loader) : null;
1258
+ }, [type, componentMap]);
1259
+ if (!LazyComponent) return /* @__PURE__ */ jsxs("div", { children: [
1260
+ "\u672A\u77E5\u7C7B\u578B\uFF1A",
1261
+ type
1262
+ ] });
1263
+ return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("div", { children: "\u52A0\u8F7D\u4E2D..." }), children: /* @__PURE__ */ jsx(LazyComponent, { ...rest }) });
1264
+ };
1265
+ var md = MarkdownIt({ html: true, breaks: true });
1266
+ md.renderer.rules.link_open = function(tokens, idx, options, env, self) {
1267
+ const token = tokens[idx];
1268
+ token.attrPush(["target", "_blank"]);
1269
+ return self.renderToken(tokens, idx, options);
1270
+ };
1271
+ function parseData(raw) {
1272
+ let obj = {};
1273
+ try {
1274
+ obj = JSON.parse(raw);
1275
+ } catch {
1276
+ try {
1277
+ obj = JSON.parse(jsonrepair(raw));
1278
+ } catch {
1279
+ obj = { _raw: raw };
1280
+ }
1281
+ }
1282
+ return obj;
1283
+ }
1284
+ function highlightKeywords(html, keywords) {
1285
+ const escaped = keywords.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
1286
+ const regex = new RegExp(`(${escaped.join("|")})`, "gi");
1287
+ return html.replace(regex, '<span class="cube-hl">$1</span>');
1288
+ }
1289
+ function makePlaceholder(id) {
1290
+ return `__ALERT_DATA_${id}__`;
1291
+ }
1292
+ function alertMarkClean(src) {
1293
+ let pos = 0;
1294
+ let id = 0;
1295
+ let out = "";
1296
+ const placeholders = /* @__PURE__ */ new Map();
1297
+ while (pos < src.length) {
1298
+ const start = src.indexOf(":::alert", pos);
1299
+ if (start === -1) {
1300
+ out += src.slice(pos);
1301
+ break;
1302
+ }
1303
+ out += src.slice(pos, start);
1304
+ const afterStart = src.slice(start);
1305
+ const relAfter = afterStart.slice(":::alert".length);
1306
+ const matchLineEnd = relAfter.search(/\s*:::\s*/);
1307
+ let endIdx = -1;
1308
+ let isNoEnd = 1;
1309
+ if (matchLineEnd !== -1) {
1310
+ endIdx = start + ":::alert".length + matchLineEnd;
1311
+ isNoEnd = 0;
1312
+ } else {
1313
+ endIdx = src.length;
1314
+ isNoEnd = 1;
1315
+ }
1316
+ const inner = src.slice(start + ":::alert".length, endIdx).trim();
1317
+ const typeMatch = inner.match(/type\s*=\s*(?:(['"])(.*?)\1|(\S+))/);
1318
+ const type = typeMatch ? typeMatch[2] ?? typeMatch[3] : void 0;
1319
+ const dataIdx = inner.search(/\bdata\s*=/);
1320
+ let rawData = "";
1321
+ if (dataIdx !== -1) {
1322
+ rawData = inner.slice(dataIdx + inner.slice(dataIdx).match(/\bdata\s*=/)[0].length).trim();
1323
+ }
1324
+ const ph = makePlaceholder(id++);
1325
+ placeholders.set(ph, rawData);
1326
+ const typeText = type ? `type=${JSON.stringify(type)}` : "";
1327
+ out += `:::alert ${typeText} data="${ph}" loading="${isNoEnd}" :::`;
1328
+ const realClose = src.indexOf(":::", endIdx);
1329
+ pos = realClose === -1 ? endIdx : realClose + 3;
1330
+ }
1331
+ return { text: out, placeholders };
1332
+ }
1333
+ function alertInlinePlugin(md2) {
1334
+ md2.inline.ruler.before("emphasis", "alert_inline", function(state, silent) {
1335
+ const pos = state.pos;
1336
+ const src = state.src;
1337
+ if (src.slice(pos, pos + 3) !== ":::") return false;
1338
+ const m = src.slice(pos).match(/^:::alert\b([^\n\r]*?):::/);
1339
+ if (!m) return false;
1340
+ if (silent) return false;
1341
+ const raw = m[1].trim();
1342
+ const html = `<lazy-component ${raw}></lazy-component>`;
1343
+ const token = state.push("html_inline", "", 0);
1344
+ token.content = html;
1345
+ state.pos += m[0].length;
1346
+ return true;
1347
+ });
1348
+ }
1349
+ try {
1350
+ md.use(alertInlinePlugin);
1351
+ } catch {
1352
+ }
1353
+ var filterMarkdown = (content = "") => {
1354
+ if (!content) return content;
1355
+ return content.replace(/<!--[\s\S]*?(?:-->|$)/g, "");
1356
+ };
1357
+ var RenderMarkdown_default = ({ content = "", searchValue, customComponents, ...rest }) => {
1358
+ const reactContent = useMemo(() => {
1359
+ if (!content) return null;
1360
+ const { text: preprocessed, placeholders } = alertMarkClean(filterMarkdown(content));
1361
+ let rawHtml = md.render(preprocessed);
1362
+ rawHtml = searchValue ? highlightKeywords(rawHtml, [searchValue]) : rawHtml;
1363
+ let lazyIndex = -1;
1364
+ return parse(rawHtml, {
1365
+ replace: (domNode) => {
1366
+ if (domNode.name === "lazy-component") {
1367
+ lazyIndex++;
1368
+ const el = domNode;
1369
+ const type = el.attribs.type;
1370
+ const loading = !!Number(el.attribs.loading);
1371
+ const dataAttr = el.attribs.data || "";
1372
+ let data = {};
1373
+ if (/^__ALERT_DATA_\d+__$/.test(dataAttr)) {
1374
+ const raw = placeholders.get(dataAttr) ?? "";
1375
+ data = parseData(raw);
1376
+ }
1377
+ return /* @__PURE__ */ jsx(LazyComponent_default, { customComponents, type, data, loading, ...rest }, `${type}${lazyIndex}`);
1378
+ }
1379
+ }
1380
+ });
1381
+ }, [content, searchValue]);
1382
+ return /* @__PURE__ */ jsx("div", { className: "ns-markdown", children: reactContent });
1383
+ };
1384
+ var MarkdownPreview_default = ({ fileUrl, searchValue }) => {
1385
+ const [content, setContent] = useState("");
1386
+ const [error, setError] = useState("");
1387
+ const fetchMarkdown = async () => {
1388
+ const res = await fetch(fileUrl);
1389
+ if (res.status !== 200) {
1390
+ throw new Error(`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${res.status}`);
1391
+ }
1392
+ const markdownText = await res.text();
1393
+ if (!markdownText) {
1394
+ throw new Error("\u8FD4\u56DE\u5185\u5BB9\u4E3A\u7A7A");
1395
+ }
1396
+ setContent(markdownText);
1397
+ };
1398
+ const init = async () => {
1399
+ setContent("");
1400
+ setError("");
1401
+ if (fileUrl) {
1402
+ try {
1403
+ await fetchMarkdown();
1404
+ } catch (error2) {
1405
+ setError("\u52A0\u8F7D\u6216\u89E3\u6790 Markdown \u5931\u8D25");
1406
+ }
1407
+ }
1408
+ };
1409
+ useEffect(() => {
1410
+ init();
1411
+ }, [fileUrl]);
1412
+ return error ? /* @__PURE__ */ jsx(Result, { status: "error", title: error }) : /* @__PURE__ */ jsx("div", { className: "height-full", children: /* @__PURE__ */ jsx(RenderMarkdown_default, { content, searchValue }) });
1413
+ };
1414
+
1415
+ // src/hooks/iframe/iframeRelay.ts
1416
+ function emit(type, data, to = "top") {
1417
+ const payload = { type, data, to };
1418
+ try {
1419
+ window.parent.postMessage(payload, "*");
1420
+ } catch (err) {
1421
+ console.warn("emit parent failed", err);
1422
+ }
1423
+ }
1424
+ function emitToChild(iframeWindow, type, data, origin = "*") {
1425
+ if (!iframeWindow) {
1426
+ console.warn("emitToChild failed: iframeWindow is null");
1427
+ return;
1428
+ }
1429
+ const payload = { type, data, to: "child" };
1430
+ try {
1431
+ iframeWindow.postMessage(payload, origin);
1432
+ } catch (err) {
1433
+ console.warn("emit to child failed", err);
1434
+ }
1435
+ }
1436
+ var useIframeRelayBridge_default = (allowedOrigins = ["*"]) => {
1437
+ const handlers = useRef({});
1438
+ useEffect(() => {
1439
+ const onMessage = (evt) => {
1440
+ const { data, source, origin } = evt;
1441
+ if (!data || !isObject(data) || !data.type) return;
1442
+ if (allowedOrigins[0] !== "*" && !allowedOrigins.includes(origin)) return;
1443
+ const { type, data: params, to = "parent" } = data;
1444
+ const isTop = window.parent === window;
1445
+ if (to === "top" && !isTop) {
1446
+ window.parent.postMessage(data, allowedOrigins[0] === "*" ? "*" : origin);
1447
+ return;
1448
+ }
1449
+ const fns = handlers.current[type] || [];
1450
+ fns.forEach((fn) => fn(params, source, origin));
1451
+ };
1452
+ window.addEventListener("message", onMessage);
1453
+ return () => window.removeEventListener("message", onMessage);
1454
+ }, [allowedOrigins]);
1455
+ function on(type, handler) {
1456
+ handlers.current[type] = handlers.current[type] || [];
1457
+ handlers.current[type].push(handler);
1458
+ }
1459
+ function off(type, handler) {
1460
+ handlers.current[type] = (handlers.current[type] || []).filter((fn) => fn !== handler);
1461
+ }
1462
+ return { on, off };
1463
+ };
1464
+ var useAutoRefresh_default = (listenValue, shouldRefresh, callback, delay = 1e4) => {
1465
+ const timerRef = useRef(null);
1466
+ const shouldRefreshRef = useRef(shouldRefresh);
1467
+ const callbackRef = useRef(callback);
1468
+ const [num, setNum] = useState(0);
1469
+ useEffect(() => {
1470
+ shouldRefreshRef.current = shouldRefresh;
1471
+ callbackRef.current = callback;
1472
+ }, [shouldRefresh, callback]);
1473
+ useEffect(() => {
1474
+ if (timerRef.current) {
1475
+ clearTimeout(timerRef.current);
1476
+ timerRef.current = null;
1477
+ }
1478
+ if (shouldRefreshRef.current(listenValue)) {
1479
+ timerRef.current = setTimeout(async () => {
1480
+ await callbackRef.current();
1481
+ setNum(num + 1);
1482
+ }, delay);
1483
+ }
1484
+ return () => {
1485
+ if (timerRef.current) {
1486
+ clearTimeout(timerRef.current);
1487
+ }
1488
+ };
1489
+ }, [listenValue, delay, num]);
1490
+ };
1491
+ var useCountDown_default = (callback) => {
1492
+ const [count, setCount] = useState(0);
1493
+ const [startCount, setStartCount] = useState(0);
1494
+ const timer = useRef(null);
1495
+ const pause = () => {
1496
+ clearInterval(timer.current);
1497
+ timer.current = null;
1498
+ };
1499
+ const start = (initialValue = 60) => {
1500
+ pause();
1501
+ setCount(initialValue);
1502
+ setStartCount((startCount2) => startCount2 + 1);
1503
+ timer.current = setInterval(() => {
1504
+ setCount((count2) => count2 - 1);
1505
+ }, 1e3);
1506
+ };
1507
+ useEffect(() => {
1508
+ return () => {
1509
+ pause();
1510
+ };
1511
+ }, []);
1512
+ useEffect(() => {
1513
+ if (count === 0 && startCount !== 0) {
1514
+ pause();
1515
+ callback?.();
1516
+ }
1517
+ }, [count]);
1518
+ return { count, start, pause, startCount };
1519
+ };
1520
+ var useCreateValtioContext_default = () => {
1521
+ const Context = createContext(null);
1522
+ const ValtioProvider = ({ store, children }) => /* @__PURE__ */ jsx(Context.Provider, { value: store, children });
1523
+ const useValtioStore = () => {
1524
+ const store = useContext(Context);
1525
+ if (!store) throw new Error("useStore must be used within Provider");
1526
+ return store;
1527
+ };
1528
+ return {
1529
+ ValtioProvider,
1530
+ useValtioStore,
1531
+ // 导出 Context 以便外部使用
1532
+ Context
1533
+ };
1534
+ };
1535
+ var useDebounce_default = (func, wait = 400) => {
1536
+ const { current } = useRef({ func, timeOut: null });
1537
+ useEffect(() => {
1538
+ current.func = func;
1539
+ }, [func]);
1540
+ let args;
1541
+ function debounce(..._args) {
1542
+ args = _args;
1543
+ if (current.timeOut) {
1544
+ clearTimeout(current.timeOut);
1545
+ current.timeOut = null;
1546
+ }
1547
+ return new Promise((resolve, reject) => {
1548
+ current.timeOut = setTimeout(async () => {
1549
+ try {
1550
+ const result = await current.func.apply(null, args);
1551
+ resolve(result);
1552
+ } catch (e) {
1553
+ reject(e);
1554
+ }
1555
+ }, wait);
1556
+ });
1557
+ }
1558
+ function cancel() {
1559
+ if (!current.timeOut) return;
1560
+ clearTimeout(current.timeOut);
1561
+ current.timeOut = null;
1562
+ }
1563
+ function flush() {
1564
+ cancel();
1565
+ return current.func.apply(null, args);
1566
+ }
1567
+ debounce.flush = flush;
1568
+ debounce.cancel = cancel;
1569
+ return useCallback(debounce, []);
1570
+ };
1571
+ var useDeepEffect_default = (effect, deps) => {
1572
+ const prevDepsRef = useRef();
1573
+ const depsChanged = !prevDepsRef.current || deps.length !== prevDepsRef.current.length || deps.some((dep, i) => !deepEqual(dep, prevDepsRef.current[i]));
1574
+ useEffect(() => {
1575
+ if (depsChanged) {
1576
+ prevDepsRef.current = deps;
1577
+ return effect();
1578
+ }
1579
+ }, [depsChanged]);
1580
+ };
1581
+ var useRefState_default = (init) => {
1582
+ const [state, setState] = useState(init);
1583
+ const stateRef = useRef(init);
1584
+ const setProxy = (newVal) => {
1585
+ stateRef.current = newVal;
1586
+ setState(newVal);
1587
+ };
1588
+ const getState = () => stateRef.current;
1589
+ return [state, setProxy, getState];
1590
+ };
1591
+ var useSpeech_default = ({ onResult, lang = "zh-CN" }) => {
1592
+ const [permission, setPermission] = useState("prompt");
1593
+ const [isRecording, setIsRecording] = useState(false);
1594
+ const recognitionRef = useRef(null);
1595
+ useEffect(() => {
1596
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
1597
+ if (!SpeechRecognition) {
1598
+ setPermission("unsupported");
1599
+ return;
1600
+ }
1601
+ const recognition = new SpeechRecognition();
1602
+ recognition.continuous = true;
1603
+ recognition.interimResults = false;
1604
+ recognition.lang = lang;
1605
+ recognition.onresult = (event) => {
1606
+ let transcript = "";
1607
+ for (let i = event.resultIndex; i < event.results.length; i++) {
1608
+ transcript += event.results[i][0].transcript;
1609
+ }
1610
+ onResult?.(transcript.trim());
1611
+ };
1612
+ recognition.onend = () => {
1613
+ setIsRecording(false);
1614
+ };
1615
+ recognition.onerror = (error) => {
1616
+ setIsRecording(false);
1617
+ console.error("Speech recognition error:", error);
1618
+ };
1619
+ recognitionRef.current = recognition;
1620
+ return () => {
1621
+ recognition.stop?.();
1622
+ recognition.onresult = null;
1623
+ recognition.onend = null;
1624
+ recognition.onerror = null;
1625
+ };
1626
+ }, [lang, onResult]);
1627
+ useEffect(() => {
1628
+ if (!navigator.permissions) return;
1629
+ navigator.permissions.query({ name: "microphone" }).then((status) => {
1630
+ setPermission(status.state);
1631
+ status.onchange = () => setPermission(status.state);
1632
+ });
1633
+ }, []);
1634
+ const requestPermission = useCallback(async () => {
1635
+ try {
1636
+ await navigator.mediaDevices.getUserMedia({ audio: true });
1637
+ setPermission("granted");
1638
+ } catch {
1639
+ setPermission("denied");
1640
+ }
1641
+ }, []);
1642
+ const start = useCallback(() => {
1643
+ if (permission === "prompt") {
1644
+ requestPermission();
1645
+ return;
1646
+ }
1647
+ if (permission !== "granted") return;
1648
+ if (!isRecording) {
1649
+ recognitionRef.current?.start();
1650
+ setIsRecording(true);
1651
+ }
1652
+ }, [permission, isRecording, requestPermission]);
1653
+ const stop = useCallback(() => {
1654
+ try {
1655
+ recognitionRef.current?.stop();
1656
+ } finally {
1657
+ setIsRecording(false);
1658
+ }
1659
+ }, []);
1660
+ return {
1661
+ /**
1662
+ * 权限状态
1663
+ */
1664
+ permission,
1665
+ /**
1666
+ * 录音状态
1667
+ */
1668
+ isRecording,
1669
+ /** 开始语音识别 */
1670
+ start,
1671
+ /** 停止语音识别 */
1672
+ stop
1673
+ };
1674
+ };
1675
+ var useSyncInput_default = (storeValue, setStoreValue) => {
1676
+ const [inputValue, setInputValue] = useState(storeValue);
1677
+ useEffect(() => {
1678
+ if (storeValue !== inputValue) {
1679
+ setInputValue(storeValue);
1680
+ }
1681
+ }, [storeValue]);
1682
+ const handleValueChange = (value) => {
1683
+ setStoreValue(value);
1684
+ setInputValue(value);
1685
+ };
1686
+ return {
1687
+ inputValue,
1688
+ setInputValue: handleValueChange
1689
+ };
1690
+ };
1691
+ var useThrottle_default = (func, wait) => {
1692
+ const { current } = useRef({ func, timeOut: null });
1693
+ useEffect(() => {
1694
+ current.func = func;
1695
+ }, [func]);
1696
+ let args;
1697
+ function throttle(..._args) {
1698
+ args = _args;
1699
+ return new Promise((resolve, reject) => {
1700
+ if (!current.timeOut) {
1701
+ try {
1702
+ const result = current.func.apply(null, args);
1703
+ resolve(result);
1704
+ } catch (e) {
1705
+ reject(e);
1706
+ }
1707
+ current.timeOut = setTimeout(() => {
1708
+ current.timeOut = null;
1709
+ }, wait);
1710
+ }
1711
+ });
1712
+ }
1713
+ function cancel() {
1714
+ if (!current.timeOut) return;
1715
+ clearTimeout(current.timeOut);
1716
+ current.timeOut = null;
1717
+ }
1718
+ function flush() {
1719
+ cancel();
1720
+ return current.func.apply(null, args);
1721
+ }
1722
+ throttle.flush = flush;
1723
+ throttle.cancel = cancel;
1724
+ return useCallback(throttle, []);
1725
+ };
1726
1726
  var useWebSocket_default = ({
1727
1727
  url,
1728
1728
  onMessage,
@@ -1884,7 +1884,7 @@ var ProtectedView = ({
1884
1884
  };
1885
1885
  var openLinksNewTabPlugin = () => {
1886
1886
  const onAnnotationLayerRender = (e) => {
1887
- e.container.querySelectorAll(".rpv-core__annotation--link a").forEach((linkEle) => {
1887
+ e.container.querySelectorAll(".rpv-core__annotation--link a[href]").forEach((linkEle) => {
1888
1888
  const href = linkEle.getAttribute("href");
1889
1889
  if (href && isExternal(href)) {
1890
1890
  linkEle.setAttribute("target", "_blank");