dishui 0.0.81 → 0.0.83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/components/Accordion/index.js +6 -6
  2. package/dist/components/Accordion/index.js.map +1 -1
  3. package/dist/components/Button/index.d.ts +1 -0
  4. package/dist/components/Button/index.js.map +1 -1
  5. package/dist/components/ButtonMenu/index.d.ts +28 -0
  6. package/dist/components/ButtonMenu/index.js +197 -0
  7. package/dist/components/ButtonMenu/index.js.map +1 -0
  8. package/dist/components/Card/index.d.ts +7 -4
  9. package/dist/components/Card/index.js +98 -65
  10. package/dist/components/Card/index.js.map +1 -1
  11. package/dist/components/Demo/index.d.ts +5 -0
  12. package/dist/components/Demo/index.js +131 -56
  13. package/dist/components/Demo/index.js.map +1 -1
  14. package/dist/components/Demo/source.d.ts +9 -0
  15. package/dist/components/Demo/source.js +32 -0
  16. package/dist/components/Demo/source.js.map +1 -0
  17. package/dist/components/EmptyState/index.js +4 -4
  18. package/dist/components/EmptyState/index.js.map +1 -1
  19. package/dist/components/Field/index.d.ts +8 -0
  20. package/dist/components/Field/index.js +43 -0
  21. package/dist/components/Field/index.js.map +1 -0
  22. package/dist/components/LayoutSuite/DashboardSuite.d.ts +35 -0
  23. package/dist/components/LayoutSuite/DashboardSuite.js +61 -0
  24. package/dist/components/LayoutSuite/DashboardSuite.js.map +1 -0
  25. package/dist/components/LayoutSuite/index.d.ts +56 -0
  26. package/dist/components/LayoutSuite/index.js +101 -0
  27. package/dist/components/LayoutSuite/index.js.map +1 -0
  28. package/dist/components/List/index.js +5 -5
  29. package/dist/components/List/index.js.map +1 -1
  30. package/dist/components/Modal/focusScope.d.ts +1 -0
  31. package/dist/components/Modal/focusScope.js +81 -0
  32. package/dist/components/Modal/focusScope.js.map +1 -0
  33. package/dist/components/Modal/index.d.ts +4 -1
  34. package/dist/components/Modal/index.js +53 -48
  35. package/dist/components/Modal/index.js.map +1 -1
  36. package/dist/components/Page/Float.d.ts +14 -0
  37. package/dist/components/Page/Float2.js +154 -0
  38. package/dist/components/Page/Float2.js.map +1 -0
  39. package/dist/components/Page/index.d.ts +18 -5
  40. package/dist/components/Page/index.js +103 -34
  41. package/dist/components/Page/index.js.map +1 -1
  42. package/dist/components/Page/resize.d.ts +28 -0
  43. package/dist/components/Page/resize2.js +95 -0
  44. package/dist/components/Page/resize2.js.map +1 -0
  45. package/dist/components/PageHeader/index.d.ts +10 -3
  46. package/dist/components/PageHeader/index.js +46 -25
  47. package/dist/components/PageHeader/index.js.map +1 -1
  48. package/dist/components/PagePanel/index.d.ts +29 -0
  49. package/dist/components/PagePanel/index.js +99 -0
  50. package/dist/components/PagePanel/index.js.map +1 -0
  51. package/dist/components/Resizable/ResizeGrip.d.ts +5 -0
  52. package/dist/components/Resizable/ResizeGrip.js +14 -0
  53. package/dist/components/Resizable/ResizeGrip.js.map +1 -0
  54. package/dist/components/Resizable/index.js +57 -59
  55. package/dist/components/Resizable/index.js.map +1 -1
  56. package/dist/components/Resizable/useResize.d.ts +6 -0
  57. package/dist/components/Resizable/useResize.js +29 -28
  58. package/dist/components/Resizable/useResize.js.map +1 -1
  59. package/dist/components/SidebarToggleButton/index.d.ts +5 -3
  60. package/dist/components/SidebarToggleButton/index.js +24 -21
  61. package/dist/components/SidebarToggleButton/index.js.map +1 -1
  62. package/dist/components/Table/index.d.ts +10 -12
  63. package/dist/components/Table/index.js +25 -20
  64. package/dist/components/Table/index.js.map +1 -1
  65. package/dist/components/Text/index.d.ts +1 -1
  66. package/dist/components/Text/index.js +11 -10
  67. package/dist/components/Text/index.js.map +1 -1
  68. package/dist/components/Textarea/index.d.ts +14 -0
  69. package/dist/components/Textarea/index.js +44 -0
  70. package/dist/components/Textarea/index.js.map +1 -0
  71. package/dist/components/Tree/Tree.d.ts +2 -0
  72. package/dist/components/Tree/Tree.js +49 -40
  73. package/dist/components/Tree/Tree.js.map +1 -1
  74. package/dist/dishui.css +1 -1
  75. package/dist/index-nostyled.d.ts +9 -0
  76. package/dist/index.d.ts +11 -2
  77. package/dist/index.js +119 -113
  78. package/dist/layouts/Sidebar.d.ts +12 -1
  79. package/dist/layouts/Sidebar.js +121 -97
  80. package/dist/layouts/Sidebar.js.map +1 -1
  81. package/dist/lite.d.ts +10 -2
  82. package/dist/lite.js +17 -12
  83. package/dist/styles/themeStyles.js +6 -6
  84. package/dist/styles/themeStyles.js.map +1 -1
  85. package/dist/utils/menu.js +14 -16
  86. package/dist/utils/menu.js.map +1 -1
  87. package/package.json +3 -1
@@ -1,35 +1,41 @@
1
- import { useCopyToClipboard as e } from "../../hooks/useCopyToClipboard.js";
2
- import { useId as t, useState as n } from "react";
3
- import { jsx as r, jsxs as i } from "react/jsx-runtime";
4
- import { Prism as a } from "react-syntax-highlighter";
5
- import { coldarkDark as o } from "react-syntax-highlighter/dist/esm/styles/prism";
1
+ import e from "../Button/index.js";
2
+ import t from "../Text/index.js";
3
+ import { useCopyToClipboard as n } from "../../hooks/useCopyToClipboard.js";
4
+ import { formatDemoSource as r } from "./source.js";
5
+ import { useEffect as i, useId as a, useRef as o, useState as s } from "react";
6
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
7
+ import { Prism as u } from "react-syntax-highlighter";
8
+ import { coldarkDark as d } from "react-syntax-highlighter/dist/esm/styles/prism";
6
9
  //#region src/components/Demo/index.tsx
7
- var s = ({ children: t, language: n = "jsx" }) => {
8
- let { copied: s, error: c, copy: l } = e();
9
- return /* @__PURE__ */ i("div", {
10
+ var f = ({ children: r, language: i = "jsx" }) => {
11
+ let { copied: a, error: o, copy: s } = n();
12
+ return /* @__PURE__ */ l("div", {
10
13
  className: "min-w-0 overflow-hidden rounded-lg border border-base-300",
11
- children: [/* @__PURE__ */ i("div", {
14
+ children: [/* @__PURE__ */ l("div", {
12
15
  className: "flex items-center justify-between gap-3 bg-base-200 px-4 py-2",
13
- children: [/* @__PURE__ */ r("span", {
14
- className: "font-mono text-xs opacity-70",
15
- children: n
16
- }), /* @__PURE__ */ i("div", {
16
+ children: [/* @__PURE__ */ c(t, {
17
+ size: "xs",
18
+ mono: !0,
19
+ color: "secondary",
20
+ children: i
21
+ }), /* @__PURE__ */ l("div", {
17
22
  className: "flex items-center gap-2",
18
- children: [/* @__PURE__ */ r("span", {
23
+ children: [/* @__PURE__ */ c(t, {
19
24
  role: "status",
20
- className: "text-xs",
21
- children: c ? "Copy failed / 复制失败,请手动复制" : s ? "Copied / 已复制" : ""
22
- }), /* @__PURE__ */ r("button", {
25
+ size: "xs",
26
+ children: o ? "Copy failed / 复制失败,请手动复制" : a ? "Copied / 已复制" : ""
27
+ }), /* @__PURE__ */ c(e, {
23
28
  type: "button",
24
- className: "btn btn-ghost btn-xs",
25
- onClick: () => void l(t),
29
+ variant: "ghost",
30
+ size: "xs",
31
+ onClick: () => void s(r),
26
32
  "aria-label": "Copy source code / 复制源代码",
27
33
  children: "Copy / 复制"
28
34
  })]
29
35
  })]
30
- }), /* @__PURE__ */ r(a, {
31
- language: n,
32
- style: o,
36
+ }), /* @__PURE__ */ c(u, {
37
+ language: i,
38
+ style: d,
33
39
  tabIndex: 0,
34
40
  "aria-label": "Source code / 源代码",
35
41
  customStyle: {
@@ -41,59 +47,128 @@ var s = ({ children: t, language: n = "jsx" }) => {
41
47
  maxHeight: "32rem",
42
48
  overflow: "auto"
43
49
  },
44
- children: t
50
+ children: r
45
51
  })]
46
52
  });
47
- }, c = ({ title: e, description: a, children: o, code: c, language: l = "jsx" }) => {
48
- let [u, d] = n(!1), f = t(), p = `${f}-title`, m = `${f}-code`;
49
- return /* @__PURE__ */ i("section", {
50
- "aria-labelledby": p,
51
- className: "mb-8 min-w-0 rounded-xl border border-base-300 bg-base-100 shadow-sm",
53
+ }, p = ({ title: n, description: u, children: d, code: p, language: m = "jsx", source: h, sourceContext: g }) => {
54
+ let [_, v] = s(!1), [y, b] = s(0), [x, S] = s(null), C = o(null);
55
+ i(() => {
56
+ if (!_ || typeof h != "function") return;
57
+ let e = !0;
58
+ return (C.current?.loader !== h || C.current.attempt !== y) && (C.current = {
59
+ loader: h,
60
+ attempt: y,
61
+ promise: Promise.resolve().then(() => h())
62
+ }), C.current.promise.then((t) => {
63
+ e && S({
64
+ loader: h,
65
+ attempt: y,
66
+ status: "success",
67
+ data: t
68
+ });
69
+ }, () => {
70
+ e && S({
71
+ loader: h,
72
+ attempt: y,
73
+ status: "error"
74
+ });
75
+ }), () => {
76
+ e = !1;
77
+ };
78
+ }, [
79
+ h,
80
+ _,
81
+ y
82
+ ]);
83
+ let w = typeof h == "function" && x?.loader === h && x.attempt === y ? x : null, T = typeof h == "function" ? w?.status === "success" ? w.data : void 0 : h, E = typeof h == "function" && !w, D = a(), O = `${D}-title`, k = `${D}-code`;
84
+ return /* @__PURE__ */ l("section", {
85
+ "aria-labelledby": O,
86
+ className: "dishui-demo mb-4 min-w-0 rounded-lg border border-hairline bg-page",
52
87
  children: [
53
- /* @__PURE__ */ i("div", {
54
- className: "border-b border-base-300 px-5 py-4",
55
- children: [/* @__PURE__ */ r("h3", {
56
- id: p,
57
- className: "text-lg font-semibold",
58
- children: e
59
- }), a && /* @__PURE__ */ r("p", {
60
- className: "mt-1 text-sm leading-relaxed opacity-70",
61
- children: a
88
+ /* @__PURE__ */ l("div", {
89
+ className: "border-b border-hairline bg-subtle px-4 py-3 rounded-t-lg",
90
+ children: [/* @__PURE__ */ c(t, {
91
+ as: "h3",
92
+ id: O,
93
+ size: "sm",
94
+ weight: "semibold",
95
+ children: n
96
+ }), u && /* @__PURE__ */ c(t, {
97
+ as: "p",
98
+ size: "sm",
99
+ color: "secondary",
100
+ className: "mt-1 leading-relaxed",
101
+ children: u
62
102
  })]
63
103
  }),
64
- /* @__PURE__ */ r("div", {
65
- className: "flex min-w-0 flex-wrap items-center gap-4 px-5 py-6",
66
- children: o
104
+ /* @__PURE__ */ c("div", {
105
+ className: "flex min-w-0 flex-wrap items-center gap-4 p-4",
106
+ children: d
67
107
  }),
68
- /* @__PURE__ */ i("div", {
108
+ /* @__PURE__ */ l("div", {
69
109
  className: "border-t border-base-300",
70
- children: [/* @__PURE__ */ i("button", {
110
+ children: [/* @__PURE__ */ l(e, {
71
111
  type: "button",
72
- className: "btn btn-ghost flex w-full items-center justify-between rounded-none rounded-b-xl px-5 text-sm font-medium",
73
- "aria-expanded": u,
74
- "aria-controls": m,
75
- onClick: () => d((e) => !e),
76
- children: [/* @__PURE__ */ r("span", { children: "Source Code / 源代码" }), /* @__PURE__ */ r("svg", {
112
+ variant: "ghost",
113
+ className: "flex w-full items-center justify-between rounded-none rounded-b-lg px-4 text-xs font-medium",
114
+ "aria-expanded": _,
115
+ "aria-controls": k,
116
+ onClick: () => v((e) => !e),
117
+ children: [/* @__PURE__ */ c(t, {
118
+ size: "xs",
119
+ weight: "medium",
120
+ color: "inherit",
121
+ children: "Source Code / 源代码"
122
+ }), /* @__PURE__ */ c("svg", {
77
123
  "aria-hidden": "true",
78
124
  xmlns: "http://www.w3.org/2000/svg",
79
- className: `h-4 w-4 transition-transform motion-reduce:transition-none ${u ? "rotate-180" : ""}`,
125
+ className: `h-4 w-4 transition-transform motion-reduce:transition-none ${_ ? "rotate-180" : ""}`,
80
126
  fill: "none",
81
127
  viewBox: "0 0 24 24",
82
128
  stroke: "currentColor",
83
- children: /* @__PURE__ */ r("path", {
129
+ children: /* @__PURE__ */ c("path", {
84
130
  strokeLinecap: "round",
85
131
  strokeLinejoin: "round",
86
132
  strokeWidth: "2",
87
133
  d: "M19 9l-7 7-7-7"
88
134
  })
89
135
  })]
90
- }), /* @__PURE__ */ r("div", {
91
- id: m,
92
- hidden: !u,
136
+ }), /* @__PURE__ */ c("div", {
137
+ id: k,
138
+ hidden: !_,
93
139
  className: "min-w-0 border-t border-base-300 p-4",
94
- children: u && /* @__PURE__ */ r(s, {
95
- language: l,
96
- children: c
140
+ children: _ && /* @__PURE__ */ c("div", {
141
+ className: "min-w-0 space-y-3",
142
+ children: /* @__PURE__ */ c("div", {
143
+ className: "min-w-0",
144
+ "aria-busy": E,
145
+ children: E ? /* @__PURE__ */ c(t, {
146
+ as: "p",
147
+ role: "status",
148
+ size: "sm",
149
+ children: "Loading source code… / 正在加载源码…"
150
+ }) : w?.status === "error" ? /* @__PURE__ */ l("div", {
151
+ className: "space-y-2",
152
+ children: [/* @__PURE__ */ c(t, {
153
+ as: "p",
154
+ role: "alert",
155
+ size: "sm",
156
+ children: "Could not load source code. Please retry. / 源码加载失败,请重试。"
157
+ }), /* @__PURE__ */ c(e, {
158
+ type: "button",
159
+ variant: "ghost",
160
+ size: "sm",
161
+ onClick: () => b((e) => e + 1),
162
+ children: "Retry loading source / 重新加载源码"
163
+ })]
164
+ }) : T ? /* @__PURE__ */ c(f, {
165
+ language: "tsx",
166
+ children: r(T, g)
167
+ }) : h ? null : /* @__PURE__ */ c(f, {
168
+ language: m,
169
+ children: p
170
+ })
171
+ })
97
172
  })
98
173
  })]
99
174
  })
@@ -101,6 +176,6 @@ var s = ({ children: t, language: n = "jsx" }) => {
101
176
  });
102
177
  };
103
178
  //#endregion
104
- export { c as default };
179
+ export { p as default };
105
180
 
106
181
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Demo/index.tsx"],"sourcesContent":["import React, { useId, useState } from 'react';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { coldarkDark } from 'react-syntax-highlighter/dist/esm/styles/prism';\nimport { useCopyToClipboard } from '../../hooks/useCopyToClipboard';\n\nexport interface CodeBlockProps {\n children: string;\n language?: string;\n}\n\nconst CodeBlock: React.FC<CodeBlockProps> = ({ children, language = 'jsx' }) => {\n const { copied, error, copy } = useCopyToClipboard();\n\n return (\n <div className=\"min-w-0 overflow-hidden rounded-lg border border-base-300\">\n <div className=\"flex items-center justify-between gap-3 bg-base-200 px-4 py-2\">\n <span className=\"font-mono text-xs opacity-70\">{language}</span>\n <div className=\"flex items-center gap-2\">\n <span role=\"status\" className=\"text-xs\">\n {error ? 'Copy failed / 复制失败,请手动复制' : copied ? 'Copied / 已复制' : ''}\n </span>\n <button\n type=\"button\"\n className=\"btn btn-ghost btn-xs\"\n onClick={() => void copy(children)}\n aria-label=\"Copy source code / 复制源代码\"\n >\n Copy / 复制\n </button>\n </div>\n </div>\n <SyntaxHighlighter\n language={language}\n style={coldarkDark}\n tabIndex={0}\n aria-label=\"Source code / 源代码\"\n customStyle={{\n margin: 0,\n borderRadius: 0,\n fontSize: '0.8125rem',\n lineHeight: 1.7,\n padding: '1rem',\n maxHeight: '32rem',\n overflow: 'auto',\n }}\n >\n {children}\n </SyntaxHighlighter>\n </div>\n );\n};\n\nexport interface DemoProps {\n title: string;\n description?: string;\n children: React.ReactNode;\n code: string;\n language?: string;\n}\n\nconst Demo: React.FC<DemoProps> = ({\n title,\n description,\n children,\n code,\n language = 'jsx',\n}) => {\n const [showCode, setShowCode] = useState(false);\n const id = useId();\n const titleId = `${id}-title`;\n const codeId = `${id}-code`;\n\n return (\n <section aria-labelledby={titleId} className=\"mb-8 min-w-0 rounded-xl border border-base-300 bg-base-100 shadow-sm\">\n <div className=\"border-b border-base-300 px-5 py-4\">\n <h3 id={titleId} className=\"text-lg font-semibold\">{title}</h3>\n {description && <p className=\"mt-1 text-sm leading-relaxed opacity-70\">{description}</p>}\n </div>\n\n <div className=\"flex min-w-0 flex-wrap items-center gap-4 px-5 py-6\">\n {children}\n </div>\n\n <div className=\"border-t border-base-300\">\n <button\n type=\"button\"\n className=\"btn btn-ghost flex w-full items-center justify-between rounded-none rounded-b-xl px-5 text-sm font-medium\"\n aria-expanded={showCode}\n aria-controls={codeId}\n onClick={() => setShowCode(value => !value)}\n >\n <span>Source Code / 源代码</span>\n <svg\n aria-hidden=\"true\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={`h-4 w-4 transition-transform motion-reduce:transition-none ${showCode ? 'rotate-180' : ''}`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </button>\n <div id={codeId} hidden={!showCode} className=\"min-w-0 border-t border-base-300 p-4\">\n {showCode && <CodeBlock language={language}>{code}</CodeBlock>}\n </div>\n </div>\n </section>\n );\n};\n\nexport default Demo;\n"],"mappings":";;;;;;AAUA,IAAM,KAAuC,EAAE,aAAU,cAAW,YAAY;CAC9E,IAAM,EAAE,WAAQ,UAAO,YAAS,EAAmB;CAEnD,OACE,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,QAAD;IAAM,WAAU;IAAgC,UAAA;GAAe,CAAA,GAC/D,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,QAAD;KAAM,MAAK;KAAS,WAAU;KAC3B,UAAA,IAAQ,6BAA6B,IAAS,iBAAiB;IAC5D,CAAA,GACN,kBAAC,UAAD;KACE,MAAK;KACL,WAAU;KACV,eAAe,KAAK,EAAK,CAAQ;KACjC,cAAW;KACZ,UAAA;IAEO,CAAA,CACL;GACF,CAAA,CAAA;EACL,CAAA,GAAA,kBAAC,GAAD;GACY;GACV,OAAO;GACP,UAAU;GACV,cAAW;GACX,aAAa;IACX,QAAQ;IACR,cAAc;IACd,UAAU;IACV,YAAY;IACZ,SAAS;IACT,WAAW;IACX,UAAU;GACZ;GAEC;EACgB,CAAA,CAChB;;AAET,GAUM,KAA6B,EACjC,UACA,gBACA,aACA,SACA,cAAW,YACP;CACJ,IAAM,CAAC,GAAU,KAAe,EAAS,EAAK,GACxC,IAAK,EAAM,GACX,IAAU,GAAG,EAAG,SAChB,IAAS,GAAG,EAAG;CAErB,OACE,kBAAC,WAAD;EAAS,mBAAiB;EAAS,WAAU;EAA7C,UAAA;GACE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,MAAD;KAAI,IAAI;KAAS,WAAU;KAAyB,UAAA;IAAU,CAAA,GAC7D,KAAe,kBAAC,KAAD;KAAG,WAAU;KAA2C,UAAA;IAAe,CAAA,CACpF;;GAEL,kBAAC,OAAD;IAAK,WAAU;IACZ;GACE,CAAA;GAEL,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,UAAD;KACE,MAAK;KACL,WAAU;KACV,iBAAe;KACf,iBAAe;KACf,eAAe,GAAY,MAAS,CAAC,CAAK;KAL5C,UAAA,CAOE,kBAAC,QAAD,EAAA,UAAM,oBAAuB,CAAA,GAC7B,kBAAC,OAAD;MACE,eAAY;MACZ,OAAM;MACN,WAAW,8DAA8D,IAAW,eAAe;MACnG,MAAK;MACL,SAAQ;MACR,QAAO;MAEP,UAAA,kBAAC,QAAD;OAAM,eAAc;OAAQ,gBAAe;OAAQ,aAAY;OAAI,GAAE;MAAkB,CAAA;KACpF,CAAA,CACC;IACR,CAAA,GAAA,kBAAC,OAAD;KAAK,IAAI;KAAQ,QAAQ,CAAC;KAAU,WAAU;KAC3C,UAAA,KAAY,kBAAC,GAAD;MAAqB;MAAW,UAAA;KAAgB,CAAA;IAC1D,CAAA,CACF;;EACE;;AAEb"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Demo/index.tsx"],"sourcesContent":["import React, { useEffect, useId, useRef, useState } from 'react';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { coldarkDark } from 'react-syntax-highlighter/dist/esm/styles/prism';\nimport { useCopyToClipboard } from '../../hooks/useCopyToClipboard';\nimport { formatDemoSource, type DemoSource } from './source';\nimport Button from '../Button';\nimport Text from '../Text';\n\nexport type { DemoSource } from './source';\n\nexport interface CodeBlockProps {\n children: string;\n language?: string;\n}\n\nconst CodeBlock: React.FC<CodeBlockProps> = ({ children, language = 'jsx' }) => {\n const { copied, error, copy } = useCopyToClipboard();\n\n return (\n <div className=\"min-w-0 overflow-hidden rounded-lg border border-base-300\">\n <div className=\"flex items-center justify-between gap-3 bg-base-200 px-4 py-2\">\n <Text size=\"xs\" mono color=\"secondary\">{language}</Text>\n <div className=\"flex items-center gap-2\">\n <Text role=\"status\" size=\"xs\">\n {error ? 'Copy failed / 复制失败,请手动复制' : copied ? 'Copied / 已复制' : ''}\n </Text>\n <Button\n type=\"button\"\n variant=\"ghost\" size=\"xs\"\n onClick={() => void copy(children)}\n aria-label=\"Copy source code / 复制源代码\"\n >\n Copy / 复制\n </Button>\n </div>\n </div>\n <SyntaxHighlighter\n language={language}\n style={coldarkDark}\n tabIndex={0}\n aria-label=\"Source code / 源代码\"\n customStyle={{\n margin: 0,\n borderRadius: 0,\n fontSize: '0.8125rem',\n lineHeight: 1.7,\n padding: '1rem',\n maxHeight: '32rem',\n overflow: 'auto',\n }}\n >\n {children}\n </SyntaxHighlighter>\n </div>\n );\n};\n\ntype DemoSourceLoader = () => Promise<DemoSource>;\n\ntype SourceLoadResult = {\n loader: DemoSourceLoader;\n attempt: number;\n} & ({ status: 'success'; data: DemoSource } | { status: 'error' });\n\nexport interface DemoProps {\n title: string;\n description?: string;\n children: React.ReactNode;\n code: string;\n language?: string;\n source?: DemoSource | DemoSourceLoader;\n sourceContext?: Record<string, unknown>;\n}\n\nconst Demo: React.FC<DemoProps> = ({\n title,\n description,\n children,\n code,\n language = 'jsx',\n source,\n sourceContext,\n}) => {\n const [showCode, setShowCode] = useState(false);\n const [attempt, setAttempt] = useState(0);\n const [loadResult, setLoadResult] = useState<SourceLoadResult | null>(null);\n const request = useRef<{\n loader: DemoSourceLoader;\n attempt: number;\n promise: Promise<DemoSource>;\n } | null>(null);\n\n useEffect(() => {\n if (!showCode || typeof source !== 'function') return;\n\n let active = true;\n // Reuse the request across collapse/reopen and StrictMode effect replays.\n if (request.current?.loader !== source || request.current.attempt !== attempt) {\n request.current = {\n loader: source,\n attempt,\n promise: Promise.resolve().then(() => source()),\n };\n }\n void request.current.promise.then(\n data => {\n if (active) setLoadResult({ loader: source, attempt, status: 'success', data });\n },\n () => {\n if (active) setLoadResult({ loader: source, attempt, status: 'error' });\n },\n );\n return () => { active = false; };\n }, [source, showCode, attempt]);\n\n // Match the loader before rendering so switching props cannot flash stale source.\n const currentResult = typeof source === 'function'\n && loadResult?.loader === source && loadResult.attempt === attempt\n ? loadResult : null;\n const resolvedSource = typeof source === 'function'\n ? currentResult?.status === 'success' ? currentResult.data : undefined\n : source;\n const loading = typeof source === 'function' && !currentResult;\n const id = useId();\n const titleId = `${id}-title`;\n const codeId = `${id}-code`;\n\n return (\n <section aria-labelledby={titleId} className=\"dishui-demo mb-4 min-w-0 rounded-lg border border-hairline bg-page\">\n <div className=\"border-b border-hairline bg-subtle px-4 py-3 rounded-t-lg\">\n <Text as=\"h3\" id={titleId} size=\"sm\" weight=\"semibold\">{title}</Text>\n {description && <Text as=\"p\" size=\"sm\" color=\"secondary\" className=\"mt-1 leading-relaxed\">{description}</Text>}\n </div>\n\n <div className=\"flex min-w-0 flex-wrap items-center gap-4 p-4\">\n {children}\n </div>\n\n <div className=\"border-t border-base-300\">\n <Button\n type=\"button\" variant=\"ghost\"\n className=\"flex w-full items-center justify-between rounded-none rounded-b-lg px-4 text-xs font-medium\"\n aria-expanded={showCode}\n aria-controls={codeId}\n onClick={() => setShowCode(value => !value)}\n >\n <Text size=\"xs\" weight=\"medium\" color=\"inherit\">Source Code / 源代码</Text>\n <svg\n aria-hidden=\"true\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={`h-4 w-4 transition-transform motion-reduce:transition-none ${showCode ? 'rotate-180' : ''}`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </Button>\n <div id={codeId} hidden={!showCode} className=\"min-w-0 border-t border-base-300 p-4\">\n {showCode && (\n <div className=\"min-w-0 space-y-3\">\n <div className=\"min-w-0\" aria-busy={loading}>\n {loading ? (\n <Text as=\"p\" role=\"status\" size=\"sm\">Loading source code… / 正在加载源码…</Text>\n ) : currentResult?.status === 'error' ? (\n <div className=\"space-y-2\">\n <Text as=\"p\" role=\"alert\" size=\"sm\">\n Could not load source code. Please retry. / 源码加载失败,请重试。\n </Text>\n <Button\n type=\"button\" variant=\"ghost\" size=\"sm\"\n onClick={() => setAttempt(value => value + 1)}\n >\n Retry loading source / 重新加载源码\n </Button>\n </div>\n ) : resolvedSource ? (\n <CodeBlock language=\"tsx\">\n {formatDemoSource(resolvedSource, sourceContext)}\n </CodeBlock>\n ) : !source ? (\n <CodeBlock language={language}>{code}</CodeBlock>\n ) : null}\n </div>\n </div>\n )}\n </div>\n </div>\n </section>\n );\n};\n\nexport default Demo;\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export interface DemoSource {
2
+ imports: string;
3
+ setup: string;
4
+ preview: string;
5
+ context: string[];
6
+ path?: string;
7
+ line?: number;
8
+ }
9
+ export declare function formatDemoSource(source: DemoSource, sourceContext?: Record<string, unknown>): string;
@@ -0,0 +1,32 @@
1
+ //#region src/components/Demo/source.ts
2
+ function e(e, t = !1) {
3
+ let n = e.replace(/\r\n/g, "\n").split("\n");
4
+ for (; n.length && !n[0].trim();) n.shift();
5
+ for (; n.length && !n[n.length - 1].trim();) n.pop();
6
+ if (e.includes("`")) return n.join("\n");
7
+ let r = t && n[0]?.match(/^\S/) ? n.slice(1) : n, i = Math.min(...r.filter((e) => e.trim()).map((e) => e.match(/^[\t ]*/)?.[0].length ?? 0));
8
+ return n.map((e, n) => t && n === 0 && /^\S/.test(e) ? e : e.slice(i)).join("\n");
9
+ }
10
+ function t(t, n = {}) {
11
+ let r = [];
12
+ for (let e of new Set(t.context)) {
13
+ if (!Object.prototype.hasOwnProperty.call(n, e)) continue;
14
+ let t = n[e];
15
+ try {
16
+ let n = t === void 0 ? "undefined" : JSON.stringify(t, null, 2);
17
+ n !== void 0 && r.push(`const ${e} = ${n};`);
18
+ } catch {
19
+ continue;
20
+ }
21
+ }
22
+ return [
23
+ e(t.imports),
24
+ r.join("\n"),
25
+ e(t.setup),
26
+ e(t.preview, !0)
27
+ ].filter(Boolean).join("\n\n");
28
+ }
29
+ //#endregion
30
+ export { t as formatDemoSource };
31
+
32
+ //# sourceMappingURL=source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.js","names":[],"sources":["../../../src/components/Demo/source.ts"],"sourcesContent":["export interface DemoSource {\n imports: string;\n setup: string;\n preview: string;\n context: string[];\n path?: string;\n line?: number;\n}\n\nfunction normalizeSection(code: string, trimmedFirstLine = false): string {\n const lines = code.replace(/\\r\\n/g, '\\n').split('\\n');\n while (lines.length && !lines[0].trim()) lines.shift();\n while (lines.length && !lines[lines.length - 1].trim()) lines.pop();\n // The extracted JSX starts at its first token; subsequent lines still carry the\n // page's indentation. Do not reindent template literals, whose spaces are data.\n if (code.includes('`')) return lines.join('\\n');\n const indentedLines = trimmedFirstLine && lines[0]?.match(/^\\S/) ? lines.slice(1) : lines;\n const indentation = Math.min(...indentedLines.filter(line => line.trim()).map(line => line.match(/^[\\t ]*/)?.[0].length ?? 0));\n return lines.map((line, index) => trimmedFirstLine && index === 0 && /^\\S/.test(line) ? line : line.slice(indentation)).join('\\n');\n}\n\nexport function formatDemoSource(\n source: DemoSource,\n sourceContext: Record<string, unknown> = {},\n): string {\n const declarations: string[] = [];\n for (const name of new Set(source.context)) {\n if (!Object.prototype.hasOwnProperty.call(sourceContext, name)) continue;\n const value = sourceContext[name];\n // Runtime functions and circular values cannot be represented as JSON source.\n try {\n const literal = value === undefined ? 'undefined' : JSON.stringify(value, null, 2);\n if (literal !== undefined) declarations.push(`const ${name} = ${literal};`);\n } catch {\n continue;\n }\n }\n\n return [\n normalizeSection(source.imports),\n declarations.join('\\n'),\n normalizeSection(source.setup),\n normalizeSection(source.preview, true),\n ].filter(Boolean).join('\\n\\n');\n}\n"],"mappings":";AASA,SAAS,EAAiB,GAAc,IAAmB,IAAe;CACxE,IAAM,IAAQ,EAAK,QAAQ,SAAS,IAAI,CAAC,CAAC,MAAM,IAAI;CACpD,OAAO,EAAM,UAAU,CAAC,EAAM,EAAE,CAAC,KAAK,IAAG,EAAM,MAAM;CACrD,OAAO,EAAM,UAAU,CAAC,EAAM,EAAM,SAAS,EAAE,CAAC,KAAK,IAAG,EAAM,IAAI;CAGlE,IAAI,EAAK,SAAS,GAAG,GAAG,OAAO,EAAM,KAAK,IAAI;CAC9C,IAAM,IAAgB,KAAoB,EAAM,EAAE,EAAE,MAAM,KAAK,IAAI,EAAM,MAAM,CAAC,IAAI,GAC9E,IAAc,KAAK,IAAI,GAAG,EAAc,QAAO,MAAQ,EAAK,KAAK,CAAC,CAAC,CAAC,KAAI,MAAQ,EAAK,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC;CAC7H,OAAO,EAAM,KAAK,GAAM,MAAU,KAAoB,MAAU,KAAK,MAAM,KAAK,CAAI,IAAI,IAAO,EAAK,MAAM,CAAW,CAAC,CAAC,CAAC,KAAK,IAAI;AACnI;AAEA,SAAgB,EACd,GACA,IAAyC,CAAC,GAClC;CACR,IAAM,IAAyB,CAAC;CAChC,KAAK,IAAM,KAAQ,IAAI,IAAI,EAAO,OAAO,GAAG;EAC1C,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAe,CAAI,GAAG;EAChE,IAAM,IAAQ,EAAc;EAE5B,IAAI;GACF,IAAM,IAAU,MAAU,KAAA,IAAY,cAAc,KAAK,UAAU,GAAO,MAAM,CAAC;GACjF,AAAI,MAAY,KAAA,KAAW,EAAa,KAAK,SAAS,EAAK,KAAK,EAAQ,EAAE;EAC5E,QAAQ;GACN;EACF;CACF;CAEA,OAAO;EACL,EAAiB,EAAO,OAAO;EAC/B,EAAa,KAAK,IAAI;EACtB,EAAiB,EAAO,KAAK;EAC7B,EAAiB,EAAO,SAAS,EAAI;CACvC,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,MAAM;AAC/B"}
@@ -2,18 +2,18 @@ import "react";
2
2
  import { jsx as e, jsxs as t } from "react/jsx-runtime";
3
3
  //#region src/components/EmptyState/index.tsx
4
4
  var n = ({ icon: n, title: r, description: i, action: a, fill: o = !0, className: s = "" }) => /* @__PURE__ */ t("div", {
5
- className: `flex flex-col items-center justify-center rounded-xl border border-dashed border-base-300 bg-base-200/50 py-16 text-center ${o ? "h-full w-full" : ""} ${s}`.trim(),
5
+ className: `dishui-empty-state flex min-w-0 flex-col items-center justify-center rounded-lg border border-dashed border-base-300 bg-base-100 px-6 py-12 text-center text-body leading-5 ${o ? "h-full w-full" : ""} ${s}`.trim(),
6
6
  children: [
7
7
  n && /* @__PURE__ */ e("span", {
8
- className: "mb-3 flex size-12 items-center justify-center rounded-full bg-base-content/5 text-base-content/40 [&>svg]:h-6 [&>svg]:w-6",
8
+ className: "mb-3 flex size-10 items-center justify-center rounded-lg bg-base-200 text-base-content/70 [&>svg]:h-5 [&>svg]:w-5",
9
9
  children: n
10
10
  }),
11
11
  /* @__PURE__ */ e("p", {
12
- className: "text-sm font-medium text-base-content/80",
12
+ className: "max-w-full break-words text-body font-medium text-base-content",
13
13
  children: r
14
14
  }),
15
15
  i && /* @__PURE__ */ e("p", {
16
- className: "mt-1 max-w-sm text-xs text-base-content/50",
16
+ className: "mt-1 max-w-sm break-words text-body-sm leading-5 text-base-content/70",
17
17
  children: i
18
18
  }),
19
19
  a && /* @__PURE__ */ e("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/EmptyState/index.tsx"],"sourcesContent":["import React from 'react';\n\nexport type EmptyStateProps = {\n /** 主图标(通常为 lucide 图标) */\n icon?: React.ReactNode;\n /** 主标题 */\n title: React.ReactNode;\n /** 补充说明 */\n description?: React.ReactNode;\n /** 底部操作(按钮等) */\n action?: React.ReactNode;\n /** 是否默认填满所在区域(宽高 100%,内容居中);默认 true */\n fill?: boolean;\n className?: string;\n};\n\n/**\n * 空状态:虚线边框卡片 + 图标 + 标题 + 说明,统一列表为空时的展示。\n * 默认填满所在区域(fill),在固定高度的容器内自动垂直居中。\n */\nconst EmptyState = ({\n icon,\n title,\n description,\n action,\n fill = true,\n className = '',\n}: EmptyStateProps) => {\n return (\n <div\n className={`flex flex-col items-center justify-center rounded-xl border border-dashed border-base-300 bg-base-200/50 py-16 text-center ${fill ? 'h-full w-full' : ''} ${className}`.trim()}\n >\n {icon && (\n <span className=\"mb-3 flex size-12 items-center justify-center rounded-full bg-base-content/5 text-base-content/40 [&>svg]:h-6 [&>svg]:w-6\">\n {icon}\n </span>\n )}\n <p className=\"text-sm font-medium text-base-content/80\">{title}</p>\n {description && (\n <p className=\"mt-1 max-w-sm text-xs text-base-content/50\">{description}</p>\n )}\n {action && <div className=\"mt-4\">{action}</div>}\n </div>\n );\n};\n\nexport default EmptyState;\n"],"mappings":";;;AAoBA,IAAM,KAAc,EAChB,SACA,UACA,gBACA,WACA,UAAO,IACP,eAAY,SAGR,kBAAC,OAAD;CACI,WAAW,8HAA8H,IAAO,kBAAkB,GAAG,GAAG,IAAY,KAAK;CAD7L,UAAA;EAGK,KACG,kBAAC,QAAD;GAAM,WAAU;GACX,UAAA;EACC,CAAA;EAEV,kBAAC,KAAD;GAAG,WAAU;GAA4C,UAAA;EAAS,CAAA;EACjE,KACG,kBAAC,KAAD;GAAG,WAAU;GAA8C,UAAA;EAAe,CAAA;EAE7E,KAAU,kBAAC,OAAD;GAAK,WAAU;GAAQ,UAAA;EAAY,CAAA;CAC7C"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/EmptyState/index.tsx"],"sourcesContent":["import React from 'react';\n\nexport type EmptyStateProps = {\n /** 主图标(通常为 lucide 图标) */\n icon?: React.ReactNode;\n /** 主标题 */\n title: React.ReactNode;\n /** 补充说明 */\n description?: React.ReactNode;\n /** 底部操作(按钮等) */\n action?: React.ReactNode;\n /** 是否默认填满所在区域(宽高 100%,内容居中);默认 true */\n fill?: boolean;\n className?: string;\n};\n\n/**\n * 空状态:虚线边框卡片 + 图标 + 标题 + 说明,统一列表为空时的展示。\n * 默认填满所在区域(fill),在固定高度的容器内自动垂直居中。\n */\nconst EmptyState = ({\n icon,\n title,\n description,\n action,\n fill = true,\n className = '',\n}: EmptyStateProps) => {\n return (\n <div\n className={`dishui-empty-state flex min-w-0 flex-col items-center justify-center rounded-lg border border-dashed border-base-300 bg-base-100 px-6 py-12 text-center text-body leading-5 ${fill ? 'h-full w-full' : ''} ${className}`.trim()}\n >\n {icon && (\n <span className=\"mb-3 flex size-10 items-center justify-center rounded-lg bg-base-200 text-base-content/70 [&>svg]:h-5 [&>svg]:w-5\">\n {icon}\n </span>\n )}\n <p className=\"max-w-full break-words text-body font-medium text-base-content\">{title}</p>\n {description && (\n <p className=\"mt-1 max-w-sm break-words text-body-sm leading-5 text-base-content/70\">{description}</p>\n )}\n {action && <div className=\"mt-4\">{action}</div>}\n </div>\n );\n};\n\nexport default EmptyState;\n"],"mappings":";;;AAoBA,IAAM,KAAc,EAChB,SACA,UACA,gBACA,WACA,UAAO,IACP,eAAY,SAGR,kBAAC,OAAD;CACI,WAAW,+KAA+K,IAAO,kBAAkB,GAAG,GAAG,IAAY,KAAK;CAD9O,UAAA;EAGK,KACG,kBAAC,QAAD;GAAM,WAAU;GACX,UAAA;EACC,CAAA;EAEV,kBAAC,KAAD;GAAG,WAAU;GAAkE,UAAA;EAAS,CAAA;EACvF,KACG,kBAAC,KAAD;GAAG,WAAU;GAAyE,UAAA;EAAe,CAAA;EAExG,KAAU,kBAAC,OAAD;GAAK,WAAU;GAAQ,UAAA;EAAY,CAAA;CAC7C"}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export interface FieldProps extends React.FieldsetHTMLAttributes<HTMLFieldSetElement> {
3
+ legend?: React.ReactNode;
4
+ description?: React.ReactNode;
5
+ error?: React.ReactNode;
6
+ }
7
+ declare const Field: React.ForwardRefExoticComponent<FieldProps & React.RefAttributes<HTMLFieldSetElement>>;
8
+ export default Field;
@@ -0,0 +1,43 @@
1
+ import { cn as e } from "../../utils/cn.js";
2
+ /* empty css */
3
+ import { forwardRef as t, useId as n } from "react";
4
+ import { jsx as r, jsxs as i } from "react/jsx-runtime";
5
+ //#region src/components/Field/index.tsx
6
+ var a = (e) => e != null && typeof e != "boolean" && e !== "", o = t(function({ legend: t, description: o, error: s, children: c, className: l, "aria-describedby": u, "aria-invalid": d, ...f }, p) {
7
+ let m = n(), h = `${m}-description`, g = `${m}-error`, _ = a(o), v = a(s), y = [
8
+ u,
9
+ _ ? h : void 0,
10
+ v ? g : void 0
11
+ ].filter(Boolean).join(" ") || void 0;
12
+ return /* @__PURE__ */ i("fieldset", {
13
+ ...f,
14
+ ref: p,
15
+ className: e("dishui-field", l),
16
+ "aria-describedby": y,
17
+ "aria-invalid": d ?? (v ? !0 : void 0),
18
+ children: [a(t) && /* @__PURE__ */ r("legend", {
19
+ className: "dishui-field-legend",
20
+ children: t
21
+ }), /* @__PURE__ */ i("div", {
22
+ className: "dishui-field-content",
23
+ children: [
24
+ _ && /* @__PURE__ */ r("div", {
25
+ id: h,
26
+ className: "dishui-field-description",
27
+ children: o
28
+ }),
29
+ c,
30
+ v && /* @__PURE__ */ r("div", {
31
+ id: g,
32
+ className: "dishui-field-error",
33
+ role: "alert",
34
+ children: s
35
+ })
36
+ ]
37
+ })]
38
+ });
39
+ });
40
+ //#endregion
41
+ export { o as default };
42
+
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Field/index.tsx"],"sourcesContent":["import React, { forwardRef, useId } from 'react';\nimport { cn } from '../../utils/cn';\nimport './style.css';\n\nexport interface FieldProps extends React.FieldsetHTMLAttributes<HTMLFieldSetElement> {\n legend?: React.ReactNode;\n description?: React.ReactNode;\n error?: React.ReactNode;\n}\n\nconst hasContent = (node: React.ReactNode) => node !== null && node !== undefined && typeof node !== 'boolean' && node !== '';\n\nconst Field = forwardRef<HTMLFieldSetElement, FieldProps>(function Field({\n legend,\n description,\n error,\n children,\n className,\n 'aria-describedby': describedBy,\n 'aria-invalid': invalid,\n ...props\n}, ref) {\n const id = useId();\n const descriptionId = `${id}-description`;\n const errorId = `${id}-error`;\n const showDescription = hasContent(description);\n const showError = hasContent(error);\n const ids = [describedBy, showDescription ? descriptionId : undefined, showError ? errorId : undefined]\n .filter(Boolean).join(' ') || undefined;\n\n return (\n <fieldset\n {...props}\n ref={ref}\n className={cn('dishui-field', className)}\n aria-describedby={ids}\n aria-invalid={invalid ?? (showError ? true : undefined)}\n >\n {hasContent(legend) && <legend className=\"dishui-field-legend\">{legend}</legend>}\n <div className=\"dishui-field-content\">\n {showDescription && <div id={descriptionId} className=\"dishui-field-description\">{description}</div>}\n {children}\n {showError && <div id={errorId} className=\"dishui-field-error\" role=\"alert\">{error}</div>}\n </div>\n </fieldset>\n );\n});\n\nexport default Field;\n"],"mappings":";;;;;AAUA,IAAM,KAAc,MAA0B,KAAS,QAA8B,OAAO,KAAS,aAAa,MAAS,IAErH,IAAQ,EAA4C,SAAe,EACvE,WACA,gBACA,UACA,aACA,cACA,oBAAoB,GACpB,gBAAgB,GAChB,GAAG,KACF,GAAK;CACN,IAAM,IAAK,EAAM,GACX,IAAgB,GAAG,EAAG,eACtB,IAAU,GAAG,EAAG,SAChB,IAAkB,EAAW,CAAW,GACxC,IAAY,EAAW,CAAK,GAC5B,IAAM;EAAC;EAAa,IAAkB,IAAgB,KAAA;EAAW,IAAY,IAAU,KAAA;CAAS,CAAC,CACpG,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA;CAEhC,OACE,kBAAC,YAAD;EACE,GAAI;EACC;EACL,WAAW,EAAG,gBAAgB,CAAS;EACvC,oBAAkB;EAClB,gBAAc,MAAY,IAAY,KAAO,KAAA;EAL/C,UAAA,CAOG,EAAW,CAAM,KAAK,kBAAC,UAAD;GAAQ,WAAU;GAAuB,UAAA;EAAe,CAAA,GAC/E,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACG,KAAmB,kBAAC,OAAD;KAAK,IAAI;KAAe,WAAU;KAA4B,UAAA;IAAiB,CAAA;IAClG;IACA,KAAa,kBAAC,OAAD;KAAK,IAAI;KAAS,WAAU;KAAqB,MAAK;KAAS,UAAA;IAAW,CAAA;GACrF;EACG,CAAA,CAAA;;AAEd,CAAC"}
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { type PageProps, type PageBodyProps, type PageMainProps, type PageAsideProps } from '../Page';
3
+ import { type CardMetricProps } from '../Card';
4
+ import { type NavigationListProps } from '../NavigationList';
5
+ import { type LayoutGridProps } from '../Layout';
6
+ export type DashboardSuiteProps = PageProps & {
7
+ header?: React.ReactNode;
8
+ overview?: React.ReactNode;
9
+ /** Persistent partial/stale/error feedback; data semantics remain with the caller. */
10
+ notice?: React.ReactNode;
11
+ metrics?: {
12
+ 'aria-label': string;
13
+ items: readonly (CardMetricProps & {
14
+ key: React.Key;
15
+ })[];
16
+ loading?: boolean;
17
+ grid?: Omit<LayoutGridProps, 'children'>;
18
+ };
19
+ /** Cross-dashboard filters, above navigation and main content. */
20
+ filters?: React.ReactNode;
21
+ navigation?: NavigationListProps;
22
+ /** Explicit children (including null) override the built-in NavigationList. */
23
+ left?: PageAsideProps;
24
+ body?: Omit<PageBodyProps, 'children'>;
25
+ main?: PageMainProps;
26
+ toolbar?: React.ReactNode;
27
+ contentHeader?: React.ReactNode;
28
+ footer?: React.ReactNode;
29
+ };
30
+ /** Controlled dashboard composition; no fetching, filtering or table dependency. */
31
+ export declare const DashboardSuite: ({ header, overview, notice, metrics, filters, navigation, left, body, main, toolbar, contentHeader, footer, children, fullHeight, className, ...page }: DashboardSuiteProps) => React.JSX.Element;
32
+ export declare const LayoutSuite: {
33
+ DashboardSuite: typeof DashboardSuite;
34
+ };
35
+ export default DashboardSuite;
@@ -0,0 +1,61 @@
1
+ import { cn as e } from "../../utils/cn.js";
2
+ import t from "../NavigationList/index.js";
3
+ import n from "../Card/index.js";
4
+ import r from "../Page/index.js";
5
+ import { Grid as i, Group as a } from "../Layout/index.js";
6
+ import "react";
7
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
8
+ //#region src/components/LayoutSuite/DashboardSuite.tsx
9
+ var c = ({ header: c, overview: l, notice: u, metrics: d, filters: f, navigation: p, left: m, body: h, main: g, toolbar: _, contentHeader: v, footer: y, children: b, fullHeight: x = !1, className: S, ...C }) => /* @__PURE__ */ s(r, {
10
+ ...C,
11
+ fullHeight: x,
12
+ className: e("gap-4", S),
13
+ children: [
14
+ c,
15
+ l,
16
+ u,
17
+ d && d.items.length > 0 && /* @__PURE__ */ o("section", {
18
+ "aria-label": d["aria-label"],
19
+ "aria-busy": d.loading,
20
+ children: /* @__PURE__ */ o(i, {
21
+ columns: "repeat(auto-fit, minmax(min(100%, 220px), 1fr))",
22
+ gap: 12,
23
+ ...d.grid,
24
+ children: d.items.map(({ key: e, ...t }) => /* @__PURE__ */ o(n.Metric, {
25
+ ...t,
26
+ loading: d.loading ?? t.loading
27
+ }, e))
28
+ })
29
+ }),
30
+ f,
31
+ /* @__PURE__ */ s(r.Body, {
32
+ scroll: x,
33
+ ...h,
34
+ children: [(m || p) && /* @__PURE__ */ o(r.Left, {
35
+ width: 240,
36
+ bordered: !1,
37
+ scroll: !1,
38
+ ...m,
39
+ children: m?.children === void 0 ? p && /* @__PURE__ */ o(t, { ...p }) : m.children
40
+ }), /* @__PURE__ */ o(r.Main, {
41
+ scroll: x,
42
+ ...g,
43
+ children: /* @__PURE__ */ s(a, {
44
+ direction: "column",
45
+ align: "stretch",
46
+ gap: 16,
47
+ children: [
48
+ _,
49
+ v,
50
+ b === void 0 ? g?.children : b
51
+ ]
52
+ })
53
+ })]
54
+ }),
55
+ y
56
+ ]
57
+ }), l = { DashboardSuite: c };
58
+ //#endregion
59
+ export { c as DashboardSuite, c as default, l as LayoutSuite };
60
+
61
+ //# sourceMappingURL=DashboardSuite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DashboardSuite.js","names":[],"sources":["../../../src/components/LayoutSuite/DashboardSuite.tsx"],"sourcesContent":["import React from 'react';\nimport Page, { type PageProps, type PageBodyProps, type PageMainProps, type PageAsideProps } from '../Page';\nimport Card, { type CardMetricProps } from '../Card';\nimport NavigationList, { type NavigationListProps } from '../NavigationList';\nimport { Grid, Group, type LayoutGridProps } from '../Layout';\nimport { cn } from '../../utils/cn';\n\nexport type DashboardSuiteProps = PageProps & {\n header?: React.ReactNode;\n overview?: React.ReactNode;\n /** Persistent partial/stale/error feedback; data semantics remain with the caller. */\n notice?: React.ReactNode;\n metrics?: {\n 'aria-label': string;\n items: readonly (CardMetricProps & { key: React.Key })[];\n loading?: boolean;\n grid?: Omit<LayoutGridProps, 'children'>;\n };\n /** Cross-dashboard filters, above navigation and main content. */\n filters?: React.ReactNode;\n navigation?: NavigationListProps;\n /** Explicit children (including null) override the built-in NavigationList. */\n left?: PageAsideProps;\n body?: Omit<PageBodyProps, 'children'>;\n main?: PageMainProps;\n toolbar?: React.ReactNode;\n contentHeader?: React.ReactNode;\n footer?: React.ReactNode;\n};\n\n/** Controlled dashboard composition; no fetching, filtering or table dependency. */\nexport const DashboardSuite = ({\n header, overview, notice, metrics, filters, navigation, left, body, main,\n toolbar, contentHeader, footer, children, fullHeight = false, className, ...page\n}: DashboardSuiteProps) => (\n <Page {...page} fullHeight={fullHeight} className={cn('gap-4', className)}>\n {header}\n {overview}\n {notice}\n {metrics && metrics.items.length > 0 && (\n <section aria-label={metrics['aria-label']} aria-busy={metrics.loading}>\n <Grid columns=\"repeat(auto-fit, minmax(min(100%, 220px), 1fr))\" gap={12} {...metrics.grid}>\n {metrics.items.map(({ key, ...metric }) => (\n <Card.Metric key={key} {...metric} loading={metrics.loading ?? metric.loading} />\n ))}\n </Grid>\n </section>\n )}\n {filters}\n <Page.Body scroll={fullHeight} {...body}>\n {(left || navigation) && (\n <Page.Left width={240} bordered={false} scroll={false} {...left}>\n {left?.children !== undefined ? left.children : navigation && <NavigationList {...navigation} />}\n </Page.Left>\n )}\n <Page.Main scroll={fullHeight} {...main}>\n <Group direction=\"column\" align=\"stretch\" gap={16}>\n {toolbar}\n {contentHeader}\n {children !== undefined ? children : main?.children}\n </Group>\n </Page.Main>\n </Page.Body>\n {footer}\n </Page>\n);\n\n// lite exposes only the lightweight suite, without loading the Sidebar/router graph.\nexport const LayoutSuite = { DashboardSuite };\nexport default DashboardSuite;\n"],"mappings":";;;;;;;;AA+BA,IAAa,KAAkB,EAC3B,WAAQ,aAAU,WAAQ,YAAS,YAAS,eAAY,SAAM,SAAM,SACpE,YAAS,kBAAe,WAAQ,aAAU,gBAAa,IAAO,cAAW,GAAG,QAE5E,kBAAC,GAAD;CAAM,GAAI;CAAkB;CAAY,WAAW,EAAG,SAAS,CAAS;CAAxE,UAAA;EACK;EACA;EACA;EACA,KAAW,EAAQ,MAAM,SAAS,KAC/B,kBAAC,WAAD;GAAS,cAAY,EAAQ;GAAe,aAAW,EAAQ;GAC3D,UAAA,kBAAC,GAAD;IAAM,SAAQ;IAAkD,KAAK;IAAI,GAAI,EAAQ;IAChF,UAAA,EAAQ,MAAM,KAAK,EAAE,QAAK,GAAG,QAC1B,kBAAC,EAAK,QAAN;KAAuB,GAAI;KAAQ,SAAS,EAAQ,WAAW,EAAO;IAAU,GAA9D,CAA8D,CACnF;GACC,CAAA;EACD,CAAA;EAEZ;EACD,kBAAC,EAAK,MAAN;GAAW,QAAQ;GAAY,GAAI;GAAnC,UAAA,EACM,KAAQ,MACN,kBAAC,EAAK,MAAN;IAAW,OAAO;IAAK,UAAU;IAAO,QAAQ;IAAO,GAAI;IACtD,UAAA,GAAM,aAAa,KAAA,IAA4B,KAAc,kBAAC,GAAD,EAAgB,GAAI,EAAa,CAAA,IAA/D,EAAK;GAC9B,CAAA,GAEf,kBAAC,EAAK,MAAN;IAAW,QAAQ;IAAY,GAAI;IAC/B,UAAA,kBAAC,GAAD;KAAO,WAAU;KAAS,OAAM;KAAU,KAAK;KAA/C,UAAA;MACK;MACA;MACA,MAAa,KAAA,IAAuB,GAAM,WAAjB;KACvB;;GACA,CAAA,CACJ;;EACV;CACC;IAIG,IAAc,EAAE,kBAAe"}
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import { type PageProps, type PageBodyProps, type PageMainProps, type PageAsideProps, type PagePanelProps, type PageFooterProps, type PageFloatProps } from '../Page';
3
+ import type { PageHeaderProps } from '../PageHeader';
4
+ import Sidebar from '../../layouts/Sidebar';
5
+ import { DashboardSuite } from './DashboardSuite';
6
+ export { DashboardSuite } from './DashboardSuite';
7
+ export type { DashboardSuiteProps } from './DashboardSuite';
8
+ /** Sidebar 保持原有 API;panel 仅配置外层 Page.Left / Page.Right。 */
9
+ export type LayoutSuiteSidebarProps = Omit<React.ComponentProps<typeof Sidebar>, 'language' | 'isCollapsed' | 'side'> & {
10
+ language?: 'zh' | 'en';
11
+ isCollapsed?: boolean;
12
+ /** 独立启用区域边缘调宽,不要求 onToggle 或 onWidthChange。 */
13
+ resizable?: boolean;
14
+ panel?: Omit<PageAsideProps, 'children'>;
15
+ };
16
+ export type LayoutSuiteHeaderProps = PageHeaderProps & PagePanelProps;
17
+ export type LayoutSuiteBaseProps = PageProps & {
18
+ /** 可选三段式页头;Admin / Blog 仍要求配置 header。 */
19
+ header?: LayoutSuiteHeaderProps;
20
+ footer?: PageFooterProps;
21
+ /** body 不接收 children;主内容支持顶层 children 或 main.children。 */
22
+ body?: Omit<PageBodyProps, 'children'>;
23
+ main?: PageMainProps;
24
+ };
25
+ export type AdminSuiteProps = LayoutSuiteBaseProps & {
26
+ header: LayoutSuiteHeaderProps;
27
+ left: LayoutSuiteSidebarProps;
28
+ };
29
+ export type WikiSuiteProps = LayoutSuiteBaseProps & {
30
+ left?: LayoutSuiteSidebarProps;
31
+ right?: LayoutSuiteSidebarProps;
32
+ float?: PageFloatProps;
33
+ };
34
+ export type BlogSuiteProps = LayoutSuiteBaseProps & {
35
+ header: LayoutSuiteHeaderProps;
36
+ footer?: PageFooterProps;
37
+ };
38
+ export type BlankSuiteProps = LayoutSuiteBaseProps & {
39
+ float?: PageFloatProps;
40
+ };
41
+ /** 后台:必填页头和内置导航侧栏。Sidebar 需置于 TanStack Router 上下文中。 */
42
+ export declare const AdminSuite: (props: AdminSuiteProps) => React.JSX.Element;
43
+ /** 文档:可选双侧导航与浮窗。 */
44
+ export declare const WikiSuite: (props: WikiSuiteProps) => React.JSX.Element;
45
+ /** 博客:必填页头,可选页脚。 */
46
+ export declare const BlogSuite: (props: BlogSuiteProps) => React.JSX.Element;
47
+ /** 空白页:主内容与可选浮窗。 */
48
+ export declare const BlankSuite: (props: BlankSuiteProps) => React.JSX.Element;
49
+ export declare const LayoutSuite: {
50
+ AdminSuite: typeof AdminSuite;
51
+ WikiSuite: typeof WikiSuite;
52
+ BlogSuite: typeof BlogSuite;
53
+ BlankSuite: typeof BlankSuite;
54
+ DashboardSuite: typeof DashboardSuite;
55
+ };
56
+ export default LayoutSuite;