dishui 0.0.84 → 0.0.89
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/components/Input/index.js +52 -62
- package/dist/components/Input/index.js.map +1 -1
- package/dist/components/LayoutSuite/index.d.ts +10 -0
- package/dist/components/LayoutSuite/index.js +27 -18
- package/dist/components/LayoutSuite/index.js.map +1 -1
- package/dist/components/Markdown/markdownComponents.js +1 -0
- package/dist/components/Markdown/markdownComponents.js.map +1 -1
- package/dist/components/Markdown/useMarkdownSource.js +46 -31
- package/dist/components/Markdown/useMarkdownSource.js.map +1 -1
- package/dist/components/Markdown/useMarkmapRenderer.js +44 -31
- package/dist/components/Markdown/useMarkmapRenderer.js.map +1 -1
- package/dist/components/Markdown/useMermaidRenderer.js +49 -31
- package/dist/components/Markdown/useMermaidRenderer.js.map +1 -1
- package/dist/components/ProtectedRoute/index.d.ts +2 -1
- package/dist/components/ProtectedRoute/index.js +16 -6
- package/dist/components/ProtectedRoute/index.js.map +1 -1
- package/dist/components/Select/index.d.ts +6 -0
- package/dist/components/Select/index.js +166 -136
- package/dist/components/Select/index.js.map +1 -1
- package/dist/components/Tabs/index.d.ts +12 -1
- package/dist/components/Tabs/index.js +42 -17
- package/dist/components/Tabs/index.js.map +1 -1
- package/dist/components/pro/ArticleContextMenu/index.js +7 -7
- package/dist/components/pro/CodeEditor/editors/CodeEditor.js +200 -189
- package/dist/components/pro/CodeEditor/editors/CodeEditor.js.map +1 -1
- package/dist/components/pro/CodeEditor/types.d.ts +3 -0
- package/dist/components/pro/DataTable/DataTable.d.ts +1 -1
- package/dist/components/pro/DataTable/DataTable.js +98 -240
- package/dist/components/pro/DataTable/DataTable.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableBody.js +14 -16
- package/dist/components/pro/DataTable/components/TableBody.js.map +1 -1
- package/dist/components/pro/DataTable/components/TablePagination.d.ts +3 -9
- package/dist/components/pro/DataTable/components/TablePagination.js +29 -25
- package/dist/components/pro/DataTable/components/TablePagination.js.map +1 -1
- package/dist/components/pro/DataTable/tanstack-table.d.ts +2 -2
- package/dist/components/pro/DataTable/tanstack-table.js +29 -21
- package/dist/components/pro/DataTable/tanstack-table.js.map +1 -1
- package/dist/components/pro/DataTable/treeDataUtils.d.ts +2 -0
- package/dist/components/pro/DataTable/treeDataUtils.js +18 -19
- package/dist/components/pro/DataTable/treeDataUtils.js.map +1 -1
- package/dist/components/pro/DataTable/types.d.ts +24 -0
- package/dist/components/pro/DataTable/useDataTableModel.d.ts +16 -0
- package/dist/components/pro/DataTable/useDataTableModel.js +148 -0
- package/dist/components/pro/DataTable/useDataTableModel.js.map +1 -0
- package/dist/components/pro/FileExplorer/Breadcrumb.js +12 -12
- package/dist/components/pro/Flow/nodes/DataNodeView.js +87 -82
- package/dist/components/pro/Flow/nodes/DataNodeView.js.map +1 -1
- package/dist/components/pro/Flow/nodes/MediaContent.js +1 -1
- package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
- package/dist/components/pro/Flow/nodes/MediaOverlay.js +1 -1
- package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
- package/dist/components/pro/Flow/nodes/Model3DView.js +69 -63
- package/dist/components/pro/Flow/nodes/Model3DView.js.map +1 -1
- package/dist/components/pro/Flow/nodes/chartGeometryBudget.d.ts +14 -0
- package/dist/components/pro/Flow/nodes/chartGeometryBudget.js +76 -0
- package/dist/components/pro/Flow/nodes/chartGeometryBudget.js.map +1 -0
- package/dist/components/pro/Flow/nodes/demandRender.d.ts +11 -0
- package/dist/components/pro/Flow/nodes/demandRender.js +26 -0
- package/dist/components/pro/Flow/nodes/demandRender.js.map +1 -0
- package/dist/components/pro/RichTextEditor/SlashMenu.js +68 -58
- package/dist/components/pro/RichTextEditor/SlashMenu.js.map +1 -1
- package/dist/contexts/AppContext.d.ts +1 -0
- package/dist/contexts/AppContext.js +144 -145
- package/dist/contexts/AppContext.js.map +1 -1
- package/dist/contexts/authentication.d.ts +7 -0
- package/dist/contexts/authentication.js +22 -0
- package/dist/contexts/authentication.js.map +1 -0
- package/dist/dishui.css +1 -1
- package/dist/hooks/useControllableState.d.ts +6 -14
- package/dist/hooks/useControllableState.js +21 -15
- package/dist/hooks/useControllableState.js.map +1 -1
- package/dist/hooks/useTableColumns.d.ts +3 -3
- package/dist/hooks/useTableColumns.js +2 -2
- package/dist/hooks/useTableColumns.js.map +1 -1
- package/dist/hooks/useTableData.d.ts +11 -4
- package/dist/hooks/useTableData.js +44 -26
- package/dist/hooks/useTableData.js.map +1 -1
- package/dist/index-nostyled.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +97 -97
- package/dist/utils/i18n.js +1 -1
- package/dist/utils/i18n.js.map +1 -1
- package/dist/utils/routerBuilder.d.ts +7 -5
- package/dist/utils/routerBuilder.js +11 -15
- package/dist/utils/routerBuilder.js.map +1 -1
- package/dist/utils/safeStorage.d.ts +8 -0
- package/dist/utils/safeStorage.js +45 -0
- package/dist/utils/safeStorage.js.map +1 -0
- package/package.json +22 -5
|
@@ -1,50 +1,65 @@
|
|
|
1
|
-
import { useEffect as e,
|
|
1
|
+
import { useEffect as e, useRef as t, useState as n } from "react";
|
|
2
2
|
//#region src/components/Markdown/useMarkdownSource.ts
|
|
3
|
-
async function
|
|
4
|
-
let
|
|
5
|
-
if (!
|
|
6
|
-
let [,
|
|
7
|
-
if (!
|
|
8
|
-
return
|
|
3
|
+
async function r(e, t, n) {
|
|
4
|
+
let r = /^s3:\/\/([^/]+)\/(.+)$/.exec(e);
|
|
5
|
+
if (!r) throw Error("Invalid S3 URL format. Expected: s3://bucket/key");
|
|
6
|
+
let [, i, a] = r, o = t?.region || "us-east-1", s = `${t?.endpoint || `https://${i}.s3.${o}.amazonaws.com`}/${a}`, c = await fetch(s, { signal: n });
|
|
7
|
+
if (!c.ok) throw Error(`S3 fetch failed: ${c.status} ${c.statusText}`);
|
|
8
|
+
return c.text();
|
|
9
9
|
}
|
|
10
|
-
function
|
|
11
|
-
let [
|
|
10
|
+
function i(i, a, o, s, c) {
|
|
11
|
+
let [l, u] = n(""), [d, f] = n(!1), [p, m] = n(null), h = t({
|
|
12
|
+
onLoad: s,
|
|
13
|
+
onError: c
|
|
14
|
+
});
|
|
15
|
+
e(() => {
|
|
16
|
+
h.current = {
|
|
17
|
+
onLoad: s,
|
|
18
|
+
onError: c
|
|
19
|
+
};
|
|
20
|
+
}, [s, c]);
|
|
21
|
+
let g = o?.region, _ = o?.endpoint;
|
|
12
22
|
return e(() => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
23
|
+
let e = new AbortController(), { signal: t } = e;
|
|
24
|
+
return (async () => {
|
|
25
|
+
if (m(null), i === "text") {
|
|
26
|
+
u(a), f(!1), h.current.onLoad?.(a);
|
|
16
27
|
return;
|
|
17
28
|
}
|
|
18
|
-
|
|
29
|
+
f(!0), u("");
|
|
19
30
|
try {
|
|
20
31
|
let e;
|
|
21
|
-
if (
|
|
22
|
-
let
|
|
23
|
-
if (!
|
|
24
|
-
e = await
|
|
25
|
-
} else if (
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
if (i === "url") {
|
|
33
|
+
let n = await fetch(a, { signal: t });
|
|
34
|
+
if (!n.ok) throw Error(`HTTP error! status: ${n.status}`);
|
|
35
|
+
e = await n.text();
|
|
36
|
+
} else if (i === "s3") e = await r(a, {
|
|
37
|
+
region: g,
|
|
38
|
+
endpoint: _
|
|
39
|
+
}, t);
|
|
40
|
+
else throw Error(`Unsupported source type: ${i}`);
|
|
41
|
+
if (t.aborted) return;
|
|
42
|
+
u(e), h.current.onLoad?.(e);
|
|
28
43
|
} catch (e) {
|
|
29
|
-
|
|
30
|
-
|
|
44
|
+
if (t.aborted) return;
|
|
45
|
+
let n = e instanceof Error ? e : Error(String(e));
|
|
46
|
+
m(n), h.current.onError?.(n);
|
|
31
47
|
} finally {
|
|
32
|
-
|
|
48
|
+
t.aborted || f(!1);
|
|
33
49
|
}
|
|
34
|
-
})();
|
|
50
|
+
})(), () => e.abort();
|
|
35
51
|
}, [
|
|
36
|
-
r,
|
|
37
52
|
i,
|
|
38
53
|
a,
|
|
39
|
-
|
|
40
|
-
|
|
54
|
+
g,
|
|
55
|
+
_
|
|
41
56
|
]), {
|
|
42
|
-
markdown:
|
|
43
|
-
loading:
|
|
44
|
-
error:
|
|
57
|
+
markdown: l,
|
|
58
|
+
loading: d,
|
|
59
|
+
error: p
|
|
45
60
|
};
|
|
46
61
|
}
|
|
47
62
|
//#endregion
|
|
48
|
-
export {
|
|
63
|
+
export { i as useMarkdownSource };
|
|
49
64
|
|
|
50
65
|
//# sourceMappingURL=useMarkdownSource.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMarkdownSource.js","names":[],"sources":["../../../src/components/Markdown/useMarkdownSource.ts"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport type { MarkdownSource, MarkdownProps } from './Markdown';\n\nasync function fetchFromS3(\n s3Url: string,\n config?: MarkdownProps['s3Config']
|
|
1
|
+
{"version":3,"file":"useMarkdownSource.js","names":[],"sources":["../../../src/components/Markdown/useMarkdownSource.ts"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport type { MarkdownSource, MarkdownProps } from './Markdown';\n\nasync function fetchFromS3(\n s3Url: string,\n config?: MarkdownProps['s3Config'],\n signal?: AbortSignal,\n): Promise<string> {\n const match = /^s3:\\/\\/([^/]+)\\/(.+)$/.exec(s3Url);\n if (!match) {\n throw new Error('Invalid S3 URL format. Expected: s3://bucket/key');\n }\n\n const [, bucket, key] = match;\n const region = config?.region || 'us-east-1';\n const endpoint = config?.endpoint || `https://${bucket}.s3.${region}.amazonaws.com`;\n const url = `${endpoint}/${key}`;\n\n const response = await fetch(url, { signal });\n if (!response.ok) {\n throw new Error(`S3 fetch failed: ${response.status} ${response.statusText}`);\n }\n\n return response.text();\n}\n\nexport function useMarkdownSource(\n source: MarkdownSource,\n content: string,\n s3Config?: MarkdownProps['s3Config'],\n onLoad?: (content: string) => void,\n onError?: (error: Error) => void,\n) {\n const [markdown, setMarkdown] = useState<string>('');\n const [loading, setLoading] = useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Callback identity is not a source change; notify the latest committed callbacks.\n const callbacks = useRef({ onLoad, onError });\n useEffect(() => {\n callbacks.current = { onLoad, onError };\n }, [onLoad, onError]);\n\n const region = s3Config?.region;\n const endpoint = s3Config?.endpoint;\n\n useEffect(() => {\n const controller = new AbortController();\n const { signal } = controller;\n\n const fetchContent = async () => {\n setError(null);\n if (source === 'text') {\n setMarkdown(content);\n setLoading(false);\n callbacks.current.onLoad?.(content);\n return;\n }\n\n setLoading(true);\n setMarkdown('');\n\n try {\n let text: string;\n\n if (source === 'url') {\n const response = await fetch(content, { signal });\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n text = await response.text();\n } else if (source === 's3') {\n text = await fetchFromS3(content, { region, endpoint }, signal);\n } else {\n throw new Error(`Unsupported source type: ${source}`);\n }\n\n if (signal.aborted) return;\n setMarkdown(text);\n callbacks.current.onLoad?.(text);\n } catch (err) {\n if (signal.aborted) return;\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n callbacks.current.onError?.(error);\n } finally {\n if (!signal.aborted) setLoading(false);\n }\n };\n\n fetchContent();\n return () => controller.abort();\n }, [source, content, region, endpoint]);\n\n return { markdown, loading, error };\n}\n"],"mappings":";;AAGA,eAAe,EACb,GACA,GACA,GACiB;CACjB,IAAM,IAAQ,yBAAyB,KAAK,CAAK;CACjD,IAAI,CAAC,GACH,MAAU,MAAM,kDAAkD;CAGpE,IAAM,GAAG,GAAQ,KAAO,GAClB,IAAS,GAAQ,UAAU,aAE3B,IAAM,GADK,GAAQ,YAAY,WAAW,EAAO,MAAM,EAAO,gBAC5C,GAAG,KAErB,IAAW,MAAM,MAAM,GAAK,EAAE,UAAO,CAAC;CAC5C,IAAI,CAAC,EAAS,IACZ,MAAU,MAAM,oBAAoB,EAAS,OAAO,GAAG,EAAS,YAAY;CAG9E,OAAO,EAAS,KAAK;AACvB;AAEA,SAAgB,EACd,GACA,GACA,GACA,GACA,GACA;CACA,IAAM,CAAC,GAAU,KAAe,EAAiB,EAAE,GAC7C,CAAC,GAAS,KAAc,EAAkB,EAAK,GAC/C,CAAC,GAAO,KAAY,EAAuB,IAAI,GAG/C,IAAY,EAAO;EAAE;EAAQ;CAAQ,CAAC;CAC5C,QAAgB;EACd,EAAU,UAAU;GAAE;GAAQ;EAAQ;CACxC,GAAG,CAAC,GAAQ,CAAO,CAAC;CAEpB,IAAM,IAAS,GAAU,QACnB,IAAW,GAAU;CAkD3B,OAhDA,QAAgB;EACd,IAAM,IAAa,IAAI,gBAAgB,GACjC,EAAE,cAAW;EA2CnB,QADA,YAxCiC;GAE/B,IADA,EAAS,IAAI,GACT,MAAW,QAAQ;IAGrB,AAFA,EAAY,CAAO,GACnB,EAAW,EAAK,GAChB,EAAU,QAAQ,SAAS,CAAO;IAClC;GACF;GAGA,AADA,EAAW,EAAI,GACf,EAAY,EAAE;GAEd,IAAI;IACF,IAAI;IAEJ,IAAI,MAAW,OAAO;KACpB,IAAM,IAAW,MAAM,MAAM,GAAS,EAAE,UAAO,CAAC;KAChD,IAAI,CAAC,EAAS,IACZ,MAAU,MAAM,uBAAuB,EAAS,QAAQ;KAE1D,IAAO,MAAM,EAAS,KAAK;IAC7B,OAAO,IAAI,MAAW,MACpB,IAAO,MAAM,EAAY,GAAS;KAAE;KAAQ;IAAS,GAAG,CAAM;SAE9D,MAAU,MAAM,4BAA4B,GAAQ;IAGtD,IAAI,EAAO,SAAS;IAEpB,AADA,EAAY,CAAI,GAChB,EAAU,QAAQ,SAAS,CAAI;GACjC,SAAS,GAAK;IACZ,IAAI,EAAO,SAAS;IACpB,IAAM,IAAQ,aAAe,QAAQ,IAAU,MAAM,OAAO,CAAG,CAAC;IAEhE,AADA,EAAS,CAAK,GACd,EAAU,QAAQ,UAAU,CAAK;GACnC,UAAU;IACR,AAAK,EAAO,WAAS,EAAW,EAAK;GACvC;EACF,EAEA,CAAa,SACA,EAAW,MAAM;CAChC,GAAG;EAAC;EAAQ;EAAS;EAAQ;CAAQ,CAAC,GAE/B;EAAE;EAAU;EAAS;CAAM;AACpC"}
|
|
@@ -1,38 +1,51 @@
|
|
|
1
|
-
import { useEffect as e } from "react";
|
|
2
|
-
import { Transformer as
|
|
3
|
-
import { Markmap as
|
|
1
|
+
import { useEffect as e, useRef as t } from "react";
|
|
2
|
+
import { Transformer as n } from "markmap-lib";
|
|
3
|
+
import { Markmap as r } from "markmap-view";
|
|
4
4
|
//#region src/components/Markdown/useMarkmapRenderer.ts
|
|
5
|
-
function
|
|
5
|
+
function i(e, t) {
|
|
6
|
+
clearTimeout(t.timer);
|
|
7
|
+
let n = t.instance;
|
|
8
|
+
t.instance = void 0, n && (n.svg.interrupt(), n.svg.selectAll("*").interrupt(), n.svg.on("wheel", null), n.destroy()), t.output && e.firstChild === t.output && e.replaceChildren();
|
|
9
|
+
}
|
|
10
|
+
function a(a, o, s) {
|
|
11
|
+
let c = t(/* @__PURE__ */ new Map()), l = t(null);
|
|
6
12
|
e(() => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
let e = c.current;
|
|
14
|
+
return () => {
|
|
15
|
+
e.forEach((e, t) => i(t, e)), e.clear();
|
|
16
|
+
};
|
|
17
|
+
}, []), e(() => {
|
|
18
|
+
let e = c.current, t = a.current, u = new Set(s && o && t ? t.querySelectorAll(".markmap-diagram") : []);
|
|
19
|
+
e.forEach((t, n) => {
|
|
20
|
+
(!u.has(n) || n.getAttribute("data-markmap-content") !== t.code || t.output && n.firstChild !== t.output) && (e.delete(n), i(n, t));
|
|
21
|
+
}), u.forEach((o) => {
|
|
22
|
+
if (e.has(o)) return;
|
|
23
|
+
let s = o.getAttribute("data-markmap-content") || "";
|
|
24
|
+
if (!s.trim()) return;
|
|
25
|
+
let c = {
|
|
26
|
+
code: s,
|
|
27
|
+
output: null
|
|
28
|
+
};
|
|
29
|
+
e.set(o, c);
|
|
30
|
+
let u = () => e.get(o) === c && a.current === t && t?.contains(o) && o.getAttribute("data-markmap-content") === s && (!c.output || o.firstChild === c.output);
|
|
31
|
+
c.timer = setTimeout(async () => {
|
|
32
|
+
if (u()) try {
|
|
33
|
+
l.current ??= new n();
|
|
34
|
+
let { root: e } = l.current.transform(s), t = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
35
|
+
t.style.width = "100%", t.style.height = "500px", o.replaceChildren(t), c.output = t;
|
|
36
|
+
let i = r.create(t, {});
|
|
37
|
+
c.instance = i, await i.setData(e), u() && await i.fit();
|
|
38
|
+
} catch (e) {
|
|
39
|
+
if (!u()) return;
|
|
40
|
+
i(o, c), console.error("Markmap render error:", e);
|
|
41
|
+
let t = document.createElement("pre");
|
|
42
|
+
t.className = "text-error", t.textContent = `Markmap 渲染失败: ${e}`, o.replaceChildren(t), c.output = t;
|
|
24
43
|
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}, 100);
|
|
29
|
-
}, [
|
|
30
|
-
i,
|
|
31
|
-
a,
|
|
32
|
-
r
|
|
33
|
-
]);
|
|
44
|
+
}, 100);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
34
47
|
}
|
|
35
48
|
//#endregion
|
|
36
|
-
export {
|
|
49
|
+
export { a as useMarkmapRenderer };
|
|
37
50
|
|
|
38
51
|
//# sourceMappingURL=useMarkmapRenderer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMarkmapRenderer.js","names":[],"sources":["../../../src/components/Markdown/useMarkmapRenderer.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport { Transformer } from 'markmap-lib';\nimport { Markmap } from 'markmap-view';\n\nexport function useMarkmapRenderer(\n containerRef: React.RefObject<HTMLDivElement | null>,\n markdown: string,\n enabled: boolean,\n) {\n useEffect(() => {\n
|
|
1
|
+
{"version":3,"file":"useMarkmapRenderer.js","names":[],"sources":["../../../src/components/Markdown/useMarkmapRenderer.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport { Transformer } from 'markmap-lib';\nimport { Markmap } from 'markmap-view';\n\ninterface Diagram {\n code: string;\n output: ChildNode | null;\n instance?: Markmap;\n timer?: ReturnType<typeof setTimeout>;\n}\n\nfunction dispose(element: HTMLElement, diagram: Diagram) {\n clearTimeout(diagram.timer);\n const instance = diagram.instance;\n diagram.instance = undefined;\n if (instance) {\n // destroy disconnects Markmap's observer/refresh subscription. Stop D3's\n // transitions and pan listener too, before removing the owned SVG.\n instance.svg.interrupt();\n instance.svg.selectAll('*').interrupt();\n instance.svg.on('wheel', null);\n instance.destroy();\n }\n if (diagram.output && element.firstChild === diagram.output) {\n element.replaceChildren();\n }\n}\n\nexport function useMarkmapRenderer(\n containerRef: React.RefObject<HTMLDivElement | null>,\n markdown: string,\n enabled: boolean,\n) {\n const diagrams = useRef(new Map<HTMLElement, Diagram>());\n const transformer = useRef<Transformer | null>(null);\n\n useEffect(() => {\n const entries = diagrams.current;\n return () => {\n entries.forEach((diagram, element) => dispose(element, diagram));\n entries.clear();\n };\n }, []);\n\n useEffect(() => {\n const entries = diagrams.current;\n const container = containerRef.current;\n const elements = new Set(enabled && markdown && container\n ? container.querySelectorAll<HTMLElement>('.markmap-diagram') : []);\n\n entries.forEach((diagram, element) => {\n if (!elements.has(element) || element.getAttribute('data-markmap-content') !== diagram.code ||\n (diagram.output && element.firstChild !== diagram.output)) {\n entries.delete(element);\n dispose(element, diagram);\n }\n });\n\n elements.forEach(element => {\n if (entries.has(element)) return;\n const code = element.getAttribute('data-markmap-content') || '';\n if (!code.trim()) return;\n const diagram: Diagram = { code, output: null };\n entries.set(element, diagram);\n const canCommit = () => entries.get(element) === diagram &&\n containerRef.current === container && container?.contains(element) &&\n element.getAttribute('data-markmap-content') === code &&\n (!diagram.output || element.firstChild === diagram.output);\n\n diagram.timer = setTimeout(async () => {\n if (!canCommit()) return;\n try {\n transformer.current ??= new Transformer();\n const { root } = transformer.current.transform(code);\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.style.width = '100%';\n svg.style.height = '500px';\n element.replaceChildren(svg);\n diagram.output = svg;\n // Keep the instance before starting asynchronous layout, so cleanup\n // can destroy it and a superseded layout never starts a late fit.\n const instance = Markmap.create(svg, {});\n diagram.instance = instance;\n await instance.setData(root);\n if (canCommit()) await instance.fit();\n } catch (err) {\n if (!canCommit()) return;\n dispose(element, diagram);\n console.error('Markmap render error:', err);\n const fallback = document.createElement('pre');\n fallback.className = 'text-error';\n fallback.textContent = `Markmap 渲染失败: ${err}`;\n element.replaceChildren(fallback);\n diagram.output = fallback;\n }\n }, 100);\n });\n });\n}\n"],"mappings":";;;;AAWA,SAAS,EAAQ,GAAsB,GAAkB;CACvD,aAAa,EAAQ,KAAK;CAC1B,IAAM,IAAW,EAAQ;CAUzB,AATA,EAAQ,WAAW,KAAA,GACf,MAGF,EAAS,IAAI,UAAU,GACvB,EAAS,IAAI,UAAU,GAAG,CAAC,CAAC,UAAU,GACtC,EAAS,IAAI,GAAG,SAAS,IAAI,GAC7B,EAAS,QAAQ,IAEf,EAAQ,UAAU,EAAQ,eAAe,EAAQ,UACnD,EAAQ,gBAAgB;AAE5B;AAEA,SAAgB,EACd,GACA,GACA,GACA;CACA,IAAM,IAAW,kBAAO,IAAI,IAA0B,CAAC,GACjD,IAAc,EAA2B,IAAI;CAUnD,AARA,QAAgB;EACd,IAAM,IAAU,EAAS;EACzB,aAAa;GAEX,AADA,EAAQ,SAAS,GAAS,MAAY,EAAQ,GAAS,CAAO,CAAC,GAC/D,EAAQ,MAAM;EAChB;CACF,GAAG,CAAC,CAAC,GAEL,QAAgB;EACd,IAAM,IAAU,EAAS,SACnB,IAAY,EAAa,SACzB,IAAW,IAAI,IAAI,KAAW,KAAY,IAC5C,EAAU,iBAA8B,kBAAkB,IAAI,CAAC,CAAC;EAUpE,AARA,EAAQ,SAAS,GAAS,MAAY;GACpC,CAAI,CAAC,EAAS,IAAI,CAAO,KAAK,EAAQ,aAAa,sBAAsB,MAAM,EAAQ,QAClF,EAAQ,UAAU,EAAQ,eAAe,EAAQ,YACpD,EAAQ,OAAO,CAAO,GACtB,EAAQ,GAAS,CAAO;EAE5B,CAAC,GAED,EAAS,SAAQ,MAAW;GAC1B,IAAI,EAAQ,IAAI,CAAO,GAAG;GAC1B,IAAM,IAAO,EAAQ,aAAa,sBAAsB,KAAK;GAC7D,IAAI,CAAC,EAAK,KAAK,GAAG;GAClB,IAAM,IAAmB;IAAE;IAAM,QAAQ;GAAK;GAC9C,EAAQ,IAAI,GAAS,CAAO;GAC5B,IAAM,UAAkB,EAAQ,IAAI,CAAO,MAAM,KAC/C,EAAa,YAAY,KAAa,GAAW,SAAS,CAAO,KACjE,EAAQ,aAAa,sBAAsB,MAAM,MAChD,CAAC,EAAQ,UAAU,EAAQ,eAAe,EAAQ;GAErD,EAAQ,QAAQ,WAAW,YAAY;IAChC,MAAU,GACf,IAAI;KACF,EAAY,YAAY,IAAI,EAAY;KACxC,IAAM,EAAE,YAAS,EAAY,QAAQ,UAAU,CAAI,GAC7C,IAAM,SAAS,gBAAgB,8BAA8B,KAAK;KAIxE,AAHA,EAAI,MAAM,QAAQ,QAClB,EAAI,MAAM,SAAS,SACnB,EAAQ,gBAAgB,CAAG,GAC3B,EAAQ,SAAS;KAGjB,IAAM,IAAW,EAAQ,OAAO,GAAK,CAAC,CAAC;KAGvC,AAFA,EAAQ,WAAW,GACnB,MAAM,EAAS,QAAQ,CAAI,GACvB,EAAU,KAAG,MAAM,EAAS,IAAI;IACtC,SAAS,GAAK;KACZ,IAAI,CAAC,EAAU,GAAG;KAElB,AADA,EAAQ,GAAS,CAAO,GACxB,QAAQ,MAAM,yBAAyB,CAAG;KAC1C,IAAM,IAAW,SAAS,cAAc,KAAK;KAI7C,AAHA,EAAS,YAAY,cACrB,EAAS,cAAc,iBAAiB,KACxC,EAAQ,gBAAgB,CAAQ,GAChC,EAAQ,SAAS;IACnB;GACF,GAAG,GAAG;EACR,CAAC;CACH,CAAC;AACH"}
|
|
@@ -1,44 +1,62 @@
|
|
|
1
|
-
import { useEffect as e, useRef as t
|
|
2
|
-
import
|
|
1
|
+
import { useEffect as e, useRef as t } from "react";
|
|
2
|
+
import n from "mermaid";
|
|
3
3
|
//#region src/components/Markdown/useMermaidRenderer.ts
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
var r = 0;
|
|
5
|
+
function i(e, t) {
|
|
6
|
+
let n = e.getAttribute("data-mermaid-content");
|
|
7
|
+
return n === null ? t?.output && e.firstChild === t.output ? t.code : e.querySelector("svg") ? "" : e.textContent || "" : n;
|
|
8
|
+
}
|
|
9
|
+
function a(e, t) {
|
|
10
|
+
clearTimeout(t.timer), t.output && e.firstChild === t.output && (e.textContent = i(e, t));
|
|
11
|
+
}
|
|
12
|
+
function o(o, s, c) {
|
|
13
|
+
let l = t(!1), u = t(/* @__PURE__ */ new Map());
|
|
6
14
|
e(() => {
|
|
7
|
-
|
|
15
|
+
let e = u.current;
|
|
16
|
+
return () => {
|
|
17
|
+
e.forEach((e, t) => a(t, e)), e.clear();
|
|
18
|
+
};
|
|
19
|
+
}, []), e(() => {
|
|
20
|
+
c && !l.current && (n.initialize({
|
|
8
21
|
startOnLoad: !1,
|
|
9
22
|
theme: "default",
|
|
10
|
-
securityLevel: "
|
|
23
|
+
securityLevel: "strict",
|
|
24
|
+
htmlLabels: !1,
|
|
11
25
|
fontFamily: "inherit",
|
|
12
26
|
flowchart: {
|
|
13
27
|
useMaxWidth: !0,
|
|
14
|
-
htmlLabels: !
|
|
28
|
+
htmlLabels: !1
|
|
15
29
|
}
|
|
16
|
-
}), l.current = !0
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
}), l.current = !0);
|
|
31
|
+
let e = u.current, t = o.current, d = new Set(c && s && t ? t.querySelectorAll(".mermaid-diagram") : []);
|
|
32
|
+
e.forEach((t, n) => {
|
|
33
|
+
(!d.has(n) || i(n, t) !== t.code || t.output && n.firstChild !== t.output) && (e.delete(n), a(n, t));
|
|
34
|
+
}), d.forEach((a) => {
|
|
35
|
+
if (e.has(a)) return;
|
|
36
|
+
let s = i(a);
|
|
37
|
+
if (!s.trim()) return;
|
|
38
|
+
let c = {
|
|
39
|
+
code: s,
|
|
40
|
+
output: null
|
|
41
|
+
};
|
|
42
|
+
e.set(a, c);
|
|
43
|
+
let l = () => e.get(a) === c && o.current === t && t?.contains(a) && i(a, c) === s;
|
|
44
|
+
c.timer = setTimeout(async () => {
|
|
45
|
+
if (l()) try {
|
|
46
|
+
let { svg: e } = await n.render(`dishui-mermaid-${++r}`, s);
|
|
47
|
+
if (!l()) return;
|
|
48
|
+
a.innerHTML = e, c.output = a.firstChild;
|
|
49
|
+
} catch (e) {
|
|
50
|
+
if (!l()) return;
|
|
51
|
+
console.error("Mermaid render error:", e);
|
|
52
|
+
let t = document.createElement("pre");
|
|
53
|
+
t.className = "text-error", t.textContent = s, a.replaceChildren(t), c.output = t;
|
|
29
54
|
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}, 100);
|
|
34
|
-
}, [
|
|
35
|
-
a,
|
|
36
|
-
o,
|
|
37
|
-
s,
|
|
38
|
-
i
|
|
39
|
-
]);
|
|
55
|
+
}, 100);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
40
58
|
}
|
|
41
59
|
//#endregion
|
|
42
|
-
export {
|
|
60
|
+
export { o as useMermaidRenderer };
|
|
43
61
|
|
|
44
62
|
//# sourceMappingURL=useMermaidRenderer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMermaidRenderer.js","names":[],"sources":["../../../src/components/Markdown/useMermaidRenderer.ts"],"sourcesContent":["import { useEffect, useRef
|
|
1
|
+
{"version":3,"file":"useMermaidRenderer.js","names":[],"sources":["../../../src/components/Markdown/useMermaidRenderer.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport mermaid from 'mermaid';\n\ninterface Diagram {\n code: string;\n output: ChildNode | null;\n timer?: ReturnType<typeof setTimeout>;\n}\n\n// Shared across hook instances, including renders started in the same millisecond.\nlet nextRenderId = 0;\n\nfunction readSource(element: HTMLElement, diagram?: Diagram): string {\n const source = element.getAttribute('data-mermaid-content');\n if (source !== null) return source;\n // Retain compatibility with text-only hook consumers without parsing our SVG.\n if (diagram?.output && element.firstChild === diagram.output) return diagram.code;\n return element.querySelector('svg') ? '' : element.textContent || '';\n}\n\nfunction dispose(element: HTMLElement, diagram: Diagram) {\n clearTimeout(diagram.timer);\n if (diagram.output && element.firstChild === diagram.output) {\n // An attribute-only consumer may already have supplied a new (or empty) source.\n element.textContent = readSource(element, diagram);\n }\n}\n\nexport function useMermaidRenderer(\n containerRef: React.RefObject<HTMLDivElement | null>,\n markdown: string,\n enabled: boolean,\n) {\n const initialized = useRef(false);\n const diagrams = useRef(new Map<HTMLElement, Diagram>());\n\n useEffect(() => {\n const entries = diagrams.current;\n return () => {\n entries.forEach((diagram, element) => dispose(element, diagram));\n entries.clear();\n };\n }, []);\n\n // Reconcile every commit: loading/visibility may replace the container even\n // when the markdown string is unchanged. Only changed blocks schedule work.\n useEffect(() => {\n if (enabled && !initialized.current) {\n mermaid.initialize({\n startOnLoad: false,\n theme: 'default',\n securityLevel: 'strict',\n htmlLabels: false,\n fontFamily: 'inherit',\n flowchart: { useMaxWidth: true, htmlLabels: false },\n });\n initialized.current = true;\n }\n\n const entries = diagrams.current;\n const container = containerRef.current;\n const elements = new Set(enabled && markdown && container\n ? container.querySelectorAll<HTMLElement>('.mermaid-diagram') : []);\n\n entries.forEach((diagram, element) => {\n if (!elements.has(element) || readSource(element, diagram) !== diagram.code ||\n (diagram.output && element.firstChild !== diagram.output)) {\n entries.delete(element);\n dispose(element, diagram);\n }\n });\n\n elements.forEach(element => {\n if (entries.has(element)) return;\n const code = readSource(element);\n if (!code.trim()) return;\n const diagram: Diagram = { code, output: null };\n entries.set(element, diagram);\n const canCommit = () => entries.get(element) === diagram &&\n containerRef.current === container && container?.contains(element) &&\n readSource(element, diagram) === code;\n\n diagram.timer = setTimeout(async () => {\n if (!canCommit()) return;\n try {\n const { svg } = await mermaid.render(`dishui-mermaid-${++nextRenderId}`, code);\n if (!canCommit()) return;\n element.innerHTML = svg;\n diagram.output = element.firstChild;\n } catch (err) {\n if (!canCommit()) return;\n console.error('Mermaid render error:', err);\n const fallback = document.createElement('pre');\n fallback.className = 'text-error';\n fallback.textContent = code;\n element.replaceChildren(fallback);\n diagram.output = fallback;\n }\n }, 100);\n });\n });\n}\n"],"mappings":";;;AAUA,IAAI,IAAe;AAEnB,SAAS,EAAW,GAAsB,GAA2B;CACnE,IAAM,IAAS,EAAQ,aAAa,sBAAsB;CAI1D,OAHI,MAAW,OAEX,GAAS,UAAU,EAAQ,eAAe,EAAQ,SAAe,EAAQ,OACtE,EAAQ,cAAc,KAAK,IAAI,KAAK,EAAQ,eAAe,KAHtC;AAI9B;AAEA,SAAS,EAAQ,GAAsB,GAAkB;CAEvD,AADA,aAAa,EAAQ,KAAK,GACtB,EAAQ,UAAU,EAAQ,eAAe,EAAQ,WAEnD,EAAQ,cAAc,EAAW,GAAS,CAAO;AAErD;AAEA,SAAgB,EACd,GACA,GACA,GACA;CACA,IAAM,IAAc,EAAO,EAAK,GAC1B,IAAW,kBAAO,IAAI,IAA0B,CAAC;CAYvD,AAVA,QAAgB;EACd,IAAM,IAAU,EAAS;EACzB,aAAa;GAEX,AADA,EAAQ,SAAS,GAAS,MAAY,EAAQ,GAAS,CAAO,CAAC,GAC/D,EAAQ,MAAM;EAChB;CACF,GAAG,CAAC,CAAC,GAIL,QAAgB;EACd,AAAI,KAAW,CAAC,EAAY,YAC1B,EAAQ,WAAW;GACjB,aAAa;GACb,OAAO;GACP,eAAe;GACf,YAAY;GACZ,YAAY;GACZ,WAAW;IAAE,aAAa;IAAM,YAAY;GAAM;EACpD,CAAC,GACD,EAAY,UAAU;EAGxB,IAAM,IAAU,EAAS,SACnB,IAAY,EAAa,SACzB,IAAW,IAAI,IAAI,KAAW,KAAY,IAC5C,EAAU,iBAA8B,kBAAkB,IAAI,CAAC,CAAC;EAUpE,AARA,EAAQ,SAAS,GAAS,MAAY;GACpC,CAAI,CAAC,EAAS,IAAI,CAAO,KAAK,EAAW,GAAS,CAAO,MAAM,EAAQ,QAClE,EAAQ,UAAU,EAAQ,eAAe,EAAQ,YACpD,EAAQ,OAAO,CAAO,GACtB,EAAQ,GAAS,CAAO;EAE5B,CAAC,GAED,EAAS,SAAQ,MAAW;GAC1B,IAAI,EAAQ,IAAI,CAAO,GAAG;GAC1B,IAAM,IAAO,EAAW,CAAO;GAC/B,IAAI,CAAC,EAAK,KAAK,GAAG;GAClB,IAAM,IAAmB;IAAE;IAAM,QAAQ;GAAK;GAC9C,EAAQ,IAAI,GAAS,CAAO;GAC5B,IAAM,UAAkB,EAAQ,IAAI,CAAO,MAAM,KAC/C,EAAa,YAAY,KAAa,GAAW,SAAS,CAAO,KACjE,EAAW,GAAS,CAAO,MAAM;GAEnC,EAAQ,QAAQ,WAAW,YAAY;IAChC,MAAU,GACf,IAAI;KACF,IAAM,EAAE,WAAQ,MAAM,EAAQ,OAAO,kBAAkB,EAAE,KAAgB,CAAI;KAC7E,IAAI,CAAC,EAAU,GAAG;KAElB,AADA,EAAQ,YAAY,GACpB,EAAQ,SAAS,EAAQ;IAC3B,SAAS,GAAK;KACZ,IAAI,CAAC,EAAU,GAAG;KAClB,QAAQ,MAAM,yBAAyB,CAAG;KAC1C,IAAM,IAAW,SAAS,cAAc,KAAK;KAI7C,AAHA,EAAS,YAAY,cACrB,EAAS,cAAc,GACvB,EAAQ,gBAAgB,CAAQ,GAChC,EAAQ,SAAS;IACnB;GACF,GAAG,GAAG;EACR,CAAC;CACH,CAAC;AACH"}
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { useAuth as e } from "../../contexts/AppContext.js";
|
|
2
|
-
import "react";
|
|
3
|
-
import { Fragment as
|
|
2
|
+
import { useEffect as t, useRef as n } from "react";
|
|
3
|
+
import { Fragment as r, jsx as i } from "react/jsx-runtime";
|
|
4
4
|
//#region src/components/ProtectedRoute/index.tsx
|
|
5
|
-
var
|
|
6
|
-
let { isAuthenticated:
|
|
7
|
-
return
|
|
5
|
+
var a = ({ children: a, requiredRoles: o = [], requireAny: s = !1, fallbackPath: c = "/login", fallback: l }) => {
|
|
6
|
+
let { isAuthenticated: u, hasRole: d, hasAnyRole: f } = e(), p = o.length === 0 || (s ? f(o) : o.every((e) => d(e))), m = !u || !p, h = u ? "/unauthorized" : c, g = l != null, _ = n(null);
|
|
7
|
+
return t(() => {
|
|
8
|
+
if (!m || g) {
|
|
9
|
+
_.current = null;
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
typeof window < "u" && _.current !== h && (_.current = h, window.location.href = h);
|
|
13
|
+
}, [
|
|
14
|
+
m,
|
|
15
|
+
g,
|
|
16
|
+
h
|
|
17
|
+
]), m ? g ? /* @__PURE__ */ i(r, { children: l }) : null : /* @__PURE__ */ i(r, { children: a });
|
|
8
18
|
};
|
|
9
19
|
//#endregion
|
|
10
|
-
export {
|
|
20
|
+
export { a as ProtectedRoute, a as default };
|
|
11
21
|
|
|
12
22
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/ProtectedRoute/index.tsx"],"sourcesContent":["import React from 'react';\nimport { useAuth } from '../../contexts/AppContext';\n\nexport type ProtectedRouteProps = {\n children: React.ReactNode;\n requiredRoles?: string[];\n requireAny?: boolean; // 如果为 true,只需要满足任一角色;如果为 false,需要满足所有角色\n fallbackPath?: string;\n fallback?: React.ReactNode;\n};\n\n/**\n * ProtectedRoute 组件\n * \n *
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/ProtectedRoute/index.tsx"],"sourcesContent":["import React, { useEffect, useRef } from 'react';\nimport { useAuth } from '../../contexts/AppContext';\n\nexport type ProtectedRouteProps = {\n children: React.ReactNode;\n requiredRoles?: string[];\n requireAny?: boolean; // 如果为 true,只需要满足任一角色;如果为 false,需要满足所有角色\n fallbackPath?: string;\n fallback?: React.ReactNode;\n};\n\n/**\n * ProtectedRoute 组件\n * \n * 用于保护需要认证或特定角色才能访问的页面内容。\n * 组件渲染晚于 loader;数据访问必须使用路由 beforeLoad 和服务端授权。\n * \n * @example\n * ```tsx\n * // 基本用法 - 只需要认证\n * <ProtectedRoute>\n * <AdminPanel />\n * </ProtectedRoute>\n * \n * // 需要特定角色\n * <ProtectedRoute requiredRoles={['admin']}>\n * <AdminPanel />\n * </ProtectedRoute>\n * \n * // 需要任一角色\n * <ProtectedRoute requiredRoles={['admin', 'moderator']} requireAny>\n * <ModeratorPanel />\n * </ProtectedRoute>\n * \n * // 自定义回退路径\n * <ProtectedRoute fallbackPath=\"/unauthorized\">\n * <SecretPage />\n * </ProtectedRoute>\n * \n * // 自定义回退组件\n * <ProtectedRoute fallback={<UnauthorizedMessage />}>\n * <SecretPage />\n * </ProtectedRoute>\n * ```\n */\nexport const ProtectedRoute: React.FC<ProtectedRouteProps> = ({\n children,\n requiredRoles = [],\n requireAny = false,\n fallbackPath = '/login',\n fallback,\n}) => {\n const { isAuthenticated, hasRole, hasAnyRole } = useAuth();\n\n const hasRequiredRoles = requiredRoles.length === 0 || (requireAny\n ? hasAnyRole(requiredRoles)\n : requiredRoles.every(role => hasRole(role)));\n const denied = !isAuthenticated || !hasRequiredRoles;\n const destination = !isAuthenticated ? fallbackPath : '/unauthorized';\n const hasFallback = fallback !== undefined && fallback !== null;\n const lastRedirect = useRef<string | null>(null);\n\n useEffect(() => {\n if (!denied || hasFallback) {\n lastRedirect.current = null;\n return;\n }\n // StrictMode replays effects; a second hard navigation can abort the first.\n if (typeof window !== 'undefined' && lastRedirect.current !== destination) {\n lastRedirect.current = destination;\n window.location.href = destination;\n }\n }, [denied, hasFallback, destination]);\n\n if (denied) return hasFallback ? <>{fallback}</> : null;\n return <>{children}</>;\n};\n\nexport default ProtectedRoute;\n\n"],"mappings":";;;;AA6CA,IAAa,KAAiD,EAC5D,aACA,mBAAgB,CAAC,GACjB,gBAAa,IACb,kBAAe,UACf,kBACI;CACJ,IAAM,EAAE,oBAAiB,YAAS,kBAAe,EAAQ,GAEnD,IAAmB,EAAc,WAAW,MAAM,IACpD,EAAW,CAAa,IACxB,EAAc,OAAM,MAAQ,EAAQ,CAAI,CAAC,IACvC,IAAS,CAAC,KAAmB,CAAC,GAC9B,IAAe,IAAiC,kBAAf,GACjC,IAAc,KAAuC,MACrD,IAAe,EAAsB,IAAI;CAe/C,OAbA,QAAgB;EACd,IAAI,CAAC,KAAU,GAAa;GAC1B,EAAa,UAAU;GACvB;EACF;EAEA,AAAI,OAAO,SAAW,OAAe,EAAa,YAAY,MAC5D,EAAa,UAAU,GACvB,OAAO,SAAS,OAAO;CAE3B,GAAG;EAAC;EAAQ;EAAa;CAAW,CAAC,GAEjC,IAAe,IAAc,kBAAA,GAAA,EAAA,UAAG,EAAW,CAAA,IAAI,OAC5C,kBAAA,GAAA,EAAG,YAAW,CAAA;AACvB"}
|
|
@@ -2,10 +2,16 @@ import React from 'react';
|
|
|
2
2
|
export interface Option {
|
|
3
3
|
value: string | number;
|
|
4
4
|
label: string;
|
|
5
|
+
disabled?: boolean;
|
|
5
6
|
}
|
|
6
7
|
export interface SelectProps {
|
|
7
8
|
/** Accessible name for the combobox. */
|
|
8
9
|
'aria-label'?: string;
|
|
10
|
+
'aria-labelledby'?: string;
|
|
11
|
+
'aria-describedby'?: string;
|
|
12
|
+
/** Optional ID for the combobox; generated per instance when omitted. */
|
|
13
|
+
id?: string;
|
|
14
|
+
disabled?: boolean;
|
|
9
15
|
options: Option[];
|
|
10
16
|
value?: string | number | (string | number)[];
|
|
11
17
|
onChange: (value: string | number | (string | number)[]) => void;
|