dishui 0.0.79 → 0.0.80
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/Avatar/index.d.ts +6 -4
- package/dist/components/Avatar/index.js +39 -28
- package/dist/components/Avatar/index.js.map +1 -1
- package/dist/components/Card/index.d.ts +16 -8
- package/dist/components/Card/index.js +81 -99
- package/dist/components/Card/index.js.map +1 -1
- package/dist/components/DateTimeInput/index.js +3 -2
- package/dist/components/DateTimeInput/index.js.map +1 -1
- package/dist/components/GroupedTable/index.d.ts +2 -1
- package/dist/components/GroupedTable/index.js +96 -37
- package/dist/components/GroupedTable/index.js.map +1 -1
- package/dist/components/Input/index.d.ts +2 -2
- package/dist/components/Input/index.js +129 -111
- package/dist/components/Input/index.js.map +1 -1
- package/dist/components/Label/index.js +1 -1
- package/dist/components/Label/index.js.map +1 -1
- package/dist/components/NavigationList/index.js +55 -24
- package/dist/components/NavigationList/index.js.map +1 -1
- package/dist/components/Resizable/index.d.ts +28 -0
- package/dist/components/Resizable/index.js +128 -0
- package/dist/components/Resizable/index.js.map +1 -0
- package/dist/components/Resizable/useResize.d.ts +21 -0
- package/dist/components/Resizable/useResize.js +60 -0
- package/dist/components/Resizable/useResize.js.map +1 -0
- package/dist/components/SidebarToggleButton/index.js +51 -43
- package/dist/components/SidebarToggleButton/index.js.map +1 -1
- package/dist/components/Slider/index.d.ts +17 -3
- package/dist/components/Slider/index.js +131 -28
- package/dist/components/Slider/index.js.map +1 -1
- package/dist/dishui.css +1 -1
- package/dist/index-nostyled.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +123 -121
- package/dist/layouts/Sidebar.js +34 -45
- package/dist/layouts/Sidebar.js.map +1 -1
- package/dist/lite.d.ts +2 -0
- package/dist/lite.js +20 -18
- package/dist/utils/i18n.js +145 -75
- package/dist/utils/i18n.js.map +1 -1
- package/dist/utils/menu.js +85 -8
- package/dist/utils/menu.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,34 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
/* empty css */
|
|
2
|
+
import { useId as e, useRef as t, useState as n } from "react";
|
|
3
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
3
4
|
//#region src/components/Input/index.tsx
|
|
4
|
-
var
|
|
5
|
-
let [
|
|
5
|
+
var a = ({ placeholder: a, value: o, onChange: s, type: c = "text", variant: l, size: u = "sm", disabled: d = !1, required: f = !1, label: p, labelPosition: m = "inline", leftSection: h, rightSection: g, pattern: _, className: v = "", validator: y = !1, validatorHint: b, validationRules: x = [], id: S, readOnly: C, ...w }) => {
|
|
6
|
+
let T = e(), E = S || T, [D, O] = n(!1), [k, A] = n(""), [j, M] = n(null), [N, P] = n(!1), [F, I] = n([]), L = t(null), R = c === "password" && D ? "text" : c, z = (e) => {
|
|
6
7
|
let t = e.target.value;
|
|
7
|
-
if (
|
|
8
|
-
let e = t.slice((
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
if (c === "password" && t.length > (o || "").length) {
|
|
9
|
+
let e = t.slice((o || "").length);
|
|
10
|
+
A(e), setTimeout(() => {
|
|
11
|
+
A("");
|
|
11
12
|
}, 1e3);
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
},
|
|
15
|
-
if (!
|
|
16
|
-
let t =
|
|
17
|
-
|
|
14
|
+
y && L.current && B(t), s && s(e);
|
|
15
|
+
}, B = (e) => {
|
|
16
|
+
if (!L.current) return;
|
|
17
|
+
let t = L.current.checkValidity(), n = [];
|
|
18
|
+
x.length > 0 && x.forEach((t) => {
|
|
18
19
|
t.pattern.test(e) || n.push(t.message);
|
|
19
|
-
}),
|
|
20
|
-
},
|
|
21
|
-
|
|
22
|
-
},
|
|
23
|
-
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
let
|
|
20
|
+
}), I(n), M(t && n.length === 0);
|
|
21
|
+
}, V = () => {
|
|
22
|
+
O(!D);
|
|
23
|
+
}, H = () => {
|
|
24
|
+
y && !j && P(!0);
|
|
25
|
+
}, U = () => {
|
|
26
|
+
P(!1);
|
|
27
|
+
}, W = "";
|
|
28
|
+
y && j !== null && (W = j ? "input-success" : "input-error");
|
|
29
|
+
let G = {
|
|
30
|
+
...w,
|
|
31
|
+
id: E,
|
|
32
|
+
readOnly: C,
|
|
33
|
+
"aria-invalid": w["aria-invalid"] ?? (y && j === !1 ? !0 : void 0)
|
|
34
|
+
}, K = "input dishui-input", q = l && !W ? `input-${l}` : "", J = u ? `input-${u}` : "", Y = y ? "validator" : "", X = c === "password" && /* @__PURE__ */ r("button", {
|
|
35
|
+
type: "button",
|
|
36
|
+
disabled: d,
|
|
37
|
+
"aria-label": D ? "Hide password" : "Show password",
|
|
38
|
+
"aria-pressed": D,
|
|
29
39
|
className: "cursor-pointer opacity-70 hover:opacity-100",
|
|
30
|
-
onClick:
|
|
31
|
-
children:
|
|
40
|
+
onClick: V,
|
|
41
|
+
children: D ? /* @__PURE__ */ i("svg", {
|
|
32
42
|
xmlns: "http://www.w3.org/2000/svg",
|
|
33
43
|
className: "h-5 w-5",
|
|
34
44
|
viewBox: "0 0 24 24",
|
|
@@ -36,62 +46,68 @@ var i = ({ placeholder: i, value: a, onChange: o, type: s = "text", variant: c,
|
|
|
36
46
|
stroke: "currentColor",
|
|
37
47
|
strokeWidth: "2",
|
|
38
48
|
children: [
|
|
39
|
-
/* @__PURE__ */
|
|
40
|
-
/* @__PURE__ */
|
|
41
|
-
/* @__PURE__ */
|
|
42
|
-
/* @__PURE__ */
|
|
49
|
+
/* @__PURE__ */ r("path", { d: "M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94" }),
|
|
50
|
+
/* @__PURE__ */ r("path", { d: "M14.12 14.12a3 3 0 1 1-4.24-4.24" }),
|
|
51
|
+
/* @__PURE__ */ r("path", { d: "M1 1l22 22" }),
|
|
52
|
+
/* @__PURE__ */ r("path", { d: "M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19" })
|
|
43
53
|
]
|
|
44
|
-
}) : /* @__PURE__ */
|
|
54
|
+
}) : /* @__PURE__ */ i("svg", {
|
|
45
55
|
xmlns: "http://www.w3.org/2000/svg",
|
|
46
56
|
className: "h-5 w-5",
|
|
47
57
|
viewBox: "0 0 24 24",
|
|
48
58
|
fill: "none",
|
|
49
59
|
stroke: "currentColor",
|
|
50
60
|
strokeWidth: "2",
|
|
51
|
-
children: [/* @__PURE__ */
|
|
61
|
+
children: [/* @__PURE__ */ r("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }), /* @__PURE__ */ r("circle", {
|
|
52
62
|
cx: "12",
|
|
53
63
|
cy: "12",
|
|
54
64
|
r: "3"
|
|
55
65
|
})]
|
|
56
66
|
})
|
|
57
|
-
}),
|
|
67
|
+
}), Z = /* @__PURE__ */ r("div", {
|
|
58
68
|
className: "validation-tooltip",
|
|
59
|
-
children:
|
|
69
|
+
children: F.length > 0 ? /* @__PURE__ */ r("ul", {
|
|
60
70
|
className: "text-xs list-disc pl-4 py-1",
|
|
61
|
-
children:
|
|
62
|
-
}) :
|
|
71
|
+
children: F.map((e, t) => /* @__PURE__ */ r("li", { children: e }, t))
|
|
72
|
+
}) : b ? /* @__PURE__ */ r("p", {
|
|
63
73
|
className: "text-xs py-1",
|
|
64
|
-
children:
|
|
74
|
+
children: b
|
|
65
75
|
}) : null
|
|
66
76
|
});
|
|
67
|
-
return
|
|
68
|
-
className: `relative w-full ${
|
|
69
|
-
onMouseEnter:
|
|
70
|
-
onMouseLeave:
|
|
77
|
+
return p || h || g || c === "password" ? p && m === "top" ? /* @__PURE__ */ i("div", {
|
|
78
|
+
className: `relative w-full ${v}`,
|
|
79
|
+
onMouseEnter: H,
|
|
80
|
+
onMouseLeave: U,
|
|
71
81
|
children: [
|
|
72
|
-
/* @__PURE__ */
|
|
82
|
+
/* @__PURE__ */ r("label", {
|
|
83
|
+
htmlFor: E,
|
|
73
84
|
className: "text-sm font-medium mb-1 block",
|
|
74
|
-
children:
|
|
85
|
+
children: p
|
|
75
86
|
}),
|
|
76
|
-
/* @__PURE__ */
|
|
77
|
-
className: `${
|
|
87
|
+
/* @__PURE__ */ i("label", {
|
|
88
|
+
className: `${K} ${q} ${J} ${Y} ${W} w-full flex items-center gap-2`,
|
|
78
89
|
children: [
|
|
79
|
-
|
|
80
|
-
/* @__PURE__ */
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
h && /* @__PURE__ */ r("span", { children: h }),
|
|
91
|
+
/* @__PURE__ */ r("input", {
|
|
92
|
+
...G,
|
|
93
|
+
ref: L,
|
|
94
|
+
type: R,
|
|
95
|
+
placeholder: a,
|
|
96
|
+
value: o,
|
|
97
|
+
onChange: z,
|
|
98
|
+
disabled: d,
|
|
99
|
+
required: f,
|
|
88
100
|
className: "grow",
|
|
89
|
-
pattern:
|
|
101
|
+
pattern: _
|
|
90
102
|
}),
|
|
91
|
-
|
|
103
|
+
c === "password" ? /* @__PURE__ */ r("button", {
|
|
104
|
+
type: "button",
|
|
105
|
+
disabled: d,
|
|
106
|
+
"aria-label": D ? "Hide password" : "Show password",
|
|
107
|
+
"aria-pressed": D,
|
|
92
108
|
className: "cursor-pointer opacity-70 hover:opacity-100",
|
|
93
|
-
onClick:
|
|
94
|
-
children:
|
|
109
|
+
onClick: V,
|
|
110
|
+
children: D ? /* @__PURE__ */ i("svg", {
|
|
95
111
|
xmlns: "http://www.w3.org/2000/svg",
|
|
96
112
|
className: "h-5 w-5",
|
|
97
113
|
viewBox: "0 0 24 24",
|
|
@@ -99,101 +115,103 @@ var i = ({ placeholder: i, value: a, onChange: o, type: s = "text", variant: c,
|
|
|
99
115
|
stroke: "currentColor",
|
|
100
116
|
strokeWidth: "2",
|
|
101
117
|
children: [
|
|
102
|
-
/* @__PURE__ */
|
|
103
|
-
/* @__PURE__ */
|
|
104
|
-
/* @__PURE__ */
|
|
105
|
-
/* @__PURE__ */
|
|
118
|
+
/* @__PURE__ */ r("path", { d: "M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94" }),
|
|
119
|
+
/* @__PURE__ */ r("path", { d: "M14.12 14.12a3 3 0 1 1-4.24-4.24" }),
|
|
120
|
+
/* @__PURE__ */ r("path", { d: "M1 1l22 22" }),
|
|
121
|
+
/* @__PURE__ */ r("path", { d: "M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19" })
|
|
106
122
|
]
|
|
107
|
-
}) : /* @__PURE__ */
|
|
123
|
+
}) : /* @__PURE__ */ i("svg", {
|
|
108
124
|
xmlns: "http://www.w3.org/2000/svg",
|
|
109
125
|
className: "h-5 w-5",
|
|
110
126
|
viewBox: "0 0 24 24",
|
|
111
127
|
fill: "none",
|
|
112
128
|
stroke: "currentColor",
|
|
113
129
|
strokeWidth: "2",
|
|
114
|
-
children: [/* @__PURE__ */
|
|
130
|
+
children: [/* @__PURE__ */ r("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }), /* @__PURE__ */ r("circle", {
|
|
115
131
|
cx: "12",
|
|
116
132
|
cy: "12",
|
|
117
133
|
r: "3"
|
|
118
134
|
})]
|
|
119
135
|
})
|
|
120
|
-
}) :
|
|
136
|
+
}) : g ? /* @__PURE__ */ r("span", { children: g }) : null
|
|
121
137
|
]
|
|
122
138
|
}),
|
|
123
|
-
|
|
139
|
+
y && b && !N && /* @__PURE__ */ r("p", {
|
|
124
140
|
className: "validator-hint text-xs mt-1 opacity-70",
|
|
125
|
-
children:
|
|
141
|
+
children: b
|
|
126
142
|
}),
|
|
127
|
-
|
|
143
|
+
N && y && !j && /* @__PURE__ */ r("div", {
|
|
128
144
|
className: "absolute z-10 mt-1 bg-base-200 border border-error rounded shadow-lg text-error px-3 py-1",
|
|
129
|
-
children:
|
|
145
|
+
children: Z
|
|
130
146
|
})
|
|
131
147
|
]
|
|
132
|
-
}) : /* @__PURE__ */
|
|
133
|
-
className: `relative w-full ${
|
|
134
|
-
onMouseEnter:
|
|
135
|
-
onMouseLeave:
|
|
148
|
+
}) : /* @__PURE__ */ i("div", {
|
|
149
|
+
className: `relative w-full ${v}`,
|
|
150
|
+
onMouseEnter: H,
|
|
151
|
+
onMouseLeave: U,
|
|
136
152
|
children: [
|
|
137
|
-
/* @__PURE__ */
|
|
138
|
-
className: `${
|
|
153
|
+
/* @__PURE__ */ i("label", {
|
|
154
|
+
className: `${K} ${q} ${J} ${Y} ${W} w-full flex items-center gap-2`,
|
|
139
155
|
children: [
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
/* @__PURE__ */
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
156
|
+
h && /* @__PURE__ */ r("span", { children: h }),
|
|
157
|
+
p && /* @__PURE__ */ r("span", { children: p }),
|
|
158
|
+
/* @__PURE__ */ r("input", {
|
|
159
|
+
...G,
|
|
160
|
+
ref: L,
|
|
161
|
+
type: R,
|
|
162
|
+
placeholder: a,
|
|
163
|
+
value: o,
|
|
164
|
+
onChange: z,
|
|
165
|
+
disabled: d,
|
|
166
|
+
required: f,
|
|
150
167
|
className: "grow",
|
|
151
|
-
pattern:
|
|
168
|
+
pattern: _
|
|
152
169
|
}),
|
|
153
|
-
|
|
170
|
+
c === "password" && k && /* @__PURE__ */ r("span", {
|
|
154
171
|
className: "password-recent absolute right-10 font-mono",
|
|
155
|
-
children:
|
|
172
|
+
children: k
|
|
156
173
|
}),
|
|
157
|
-
|
|
174
|
+
c === "password" ? /* @__PURE__ */ r("span", { children: X }) : g ? /* @__PURE__ */ r("span", { children: g }) : null
|
|
158
175
|
]
|
|
159
176
|
}),
|
|
160
|
-
|
|
177
|
+
y && b && !N && /* @__PURE__ */ r("p", {
|
|
161
178
|
className: "validator-hint text-xs mt-1 opacity-70",
|
|
162
|
-
children:
|
|
179
|
+
children: b
|
|
163
180
|
}),
|
|
164
|
-
|
|
181
|
+
N && y && !j && /* @__PURE__ */ r("div", {
|
|
165
182
|
className: "absolute z-10 mt-1 bg-base-200 border border-error rounded shadow-lg text-error px-3 py-1",
|
|
166
|
-
children:
|
|
183
|
+
children: Z
|
|
167
184
|
})
|
|
168
185
|
]
|
|
169
|
-
}) : /* @__PURE__ */
|
|
170
|
-
className: `relative w-full ${
|
|
171
|
-
onMouseEnter:
|
|
172
|
-
onMouseLeave:
|
|
186
|
+
}) : /* @__PURE__ */ i("div", {
|
|
187
|
+
className: `relative w-full ${v}`,
|
|
188
|
+
onMouseEnter: H,
|
|
189
|
+
onMouseLeave: U,
|
|
173
190
|
children: [
|
|
174
|
-
/* @__PURE__ */
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
191
|
+
/* @__PURE__ */ r("input", {
|
|
192
|
+
...G,
|
|
193
|
+
ref: L,
|
|
194
|
+
type: R,
|
|
195
|
+
placeholder: a,
|
|
196
|
+
value: o,
|
|
197
|
+
onChange: z,
|
|
198
|
+
disabled: d,
|
|
199
|
+
required: f,
|
|
200
|
+
className: `${K} ${q} ${J} ${Y} ${W} w-full`,
|
|
201
|
+
pattern: _
|
|
184
202
|
}),
|
|
185
|
-
|
|
203
|
+
y && b && !N && /* @__PURE__ */ r("p", {
|
|
186
204
|
className: "validator-hint text-xs mt-1 opacity-70",
|
|
187
|
-
children:
|
|
205
|
+
children: b
|
|
188
206
|
}),
|
|
189
|
-
|
|
207
|
+
N && y && !j && /* @__PURE__ */ r("div", {
|
|
190
208
|
className: "absolute z-10 mt-1 bg-base-200 border border-error rounded shadow-lg text-error px-3 py-1",
|
|
191
|
-
children:
|
|
209
|
+
children: Z
|
|
192
210
|
})
|
|
193
211
|
]
|
|
194
212
|
});
|
|
195
213
|
};
|
|
196
214
|
//#endregion
|
|
197
|
-
export {
|
|
215
|
+
export { a as default };
|
|
198
216
|
|
|
199
217
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Input/index.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from 'react';\n\nexport type InputProps = {\n placeholder?: string;\n value?: string;\n onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;\n type?: string;\n variant?: 'neutral' | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error' | 'ghost';\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n disabled?: boolean;\n required?: boolean;\n label?: string;\n labelPosition?: 'inline' | 'top';\n leftSection?: React.ReactNode;\n rightSection?: React.ReactNode;\n pattern?: string;\n className?: string;\n validator?: boolean;\n validatorHint?: string;\n validationRules?: {\n pattern: RegExp;\n message: string;\n }[];\n};\n\nconst Input = ({\n placeholder,\n value,\n onChange,\n type = 'text',\n variant,\n size = 'sm',\n disabled = false,\n required = false,\n label,\n labelPosition = 'inline',\n leftSection,\n rightSection,\n pattern,\n className = '',\n validator = false,\n validatorHint,\n validationRules = [],\n}: InputProps) => {\n // 密码显示/隐藏状态\n const [showPassword, setShowPassword] = useState(false);\n // 追踪最近输入的字符\n const [recentInput, setRecentInput] = useState('');\n // 表单验证状态\n const [isValid, setIsValid] = useState<boolean | null>(null);\n // 显示验证提示\n const [showValidationHint, setShowValidationHint] = useState(false);\n // 验证失败的规则消息\n const [failedRules, setFailedRules] = useState<string[]>([]);\n \n // 输入框引用,用于焦点和验证\n const inputRef = useRef<HTMLInputElement>(null);\n \n // 确定实际使用的输入类型\n const actualType = type === 'password' && showPassword ? 'text' : type;\n \n // 处理输入变化,包括密码字符延迟遮罩和验证\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n \n // 处理密码输入的特殊效果\n if (type === 'password' && newValue.length > (value || '').length) {\n // 获取新输入的字符\n const newChar = newValue.slice((value || '').length);\n setRecentInput(newChar);\n \n // 设置定时器延迟清除最近输入的字符\n setTimeout(() => {\n setRecentInput('');\n }, 1000); // 1秒后隐藏\n }\n \n // 验证输入\n if (validator && inputRef.current) {\n validateInput(newValue);\n }\n \n // 调用原始的onChange处理函数\n if (onChange) {\n onChange(e);\n }\n };\n \n // 验证输入值\n const validateInput = (inputValue: string) => {\n if (!inputRef.current) return;\n \n // 使用HTML5自带的验证\n const isNativeValid = inputRef.current.checkValidity();\n \n // 检查自定义验证规则\n const failedMessages: string[] = [];\n \n if (validationRules.length > 0) {\n validationRules.forEach(rule => {\n if (!rule.pattern.test(inputValue)) {\n failedMessages.push(rule.message);\n }\n });\n }\n \n setFailedRules(failedMessages);\n setIsValid(isNativeValid && failedMessages.length === 0);\n };\n \n // 切换密码显示/隐藏\n const togglePasswordVisibility = () => {\n setShowPassword(!showPassword);\n };\n \n // 鼠标悬停事件处理\n const handleMouseEnter = () => {\n if (validator && !isValid) {\n setShowValidationHint(true);\n }\n };\n \n const handleMouseLeave = () => {\n setShowValidationHint(false);\n };\n \n // 验证状态相关的类名\n let validationStateClass = '';\n if (validator && isValid !== null) {\n validationStateClass = isValid ? 'input-success' : 'input-error';\n }\n \n const baseClass = 'input';\n const variantClass = variant && !validationStateClass ? `input-${variant}` : '';\n const sizeClass = size ? `input-${size}` : '';\n const validatorClass = validator ? 'validator' : '';\n \n\n // 密码可见性切换按钮\n const passwordToggle = type === 'password' && (\n <span \n className=\"cursor-pointer opacity-70 hover:opacity-100\"\n onClick={togglePasswordVisibility}\n >\n {showPassword ? (\n // 眼睛关闭图标\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-5 w-5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94\" />\n <path d=\"M14.12 14.12a3 3 0 1 1-4.24-4.24\" />\n <path d=\"M1 1l22 22\" />\n <path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19\" />\n </svg>\n ) : (\n // 眼睛打开图标\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-5 w-5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n )}\n </span>\n );\n \n // 构建验证提示悬浮框\n const validationTooltip = (\n <div className=\"validation-tooltip\">\n {failedRules.length > 0 ? (\n <ul className=\"text-xs list-disc pl-4 py-1\">\n {failedRules.map((rule, index) => (\n <li key={index}>{rule}</li>\n ))}\n </ul>\n ) : validatorHint ? (\n <p className=\"text-xs py-1\">{validatorHint}</p>\n ) : null}\n </div>\n );\n\n // 如果有label,则使用label作为容器\n if (label || leftSection || rightSection || type === 'password') {\n // labelPosition === 'top': label above the input field\n if (label && labelPosition === 'top') {\n return (\n <div className={`relative w-full ${className}`} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>\n <span className=\"text-sm font-medium mb-1 block\">{label}</span>\n <label className={`${baseClass} ${variantClass} ${sizeClass} ${validatorClass} ${validationStateClass} w-full flex items-center gap-2`}>\n {leftSection && <span>{leftSection}</span>}\n <input\n ref={inputRef}\n type={actualType}\n placeholder={placeholder}\n value={value}\n onChange={handleInputChange}\n disabled={disabled}\n required={required}\n className=\"grow\"\n pattern={pattern}\n />\n {type === 'password' ? (\n <span className=\"cursor-pointer opacity-70 hover:opacity-100\" onClick={togglePasswordVisibility}>\n {showPassword ? (\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-5 w-5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94\" />\n <path d=\"M14.12 14.12a3 3 0 1 1-4.24-4.24\" />\n <path d=\"M1 1l22 22\" />\n <path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19\" />\n </svg>\n ) : (\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-5 w-5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n )}\n </span>\n ) : rightSection ? (\n <span>{rightSection}</span>\n ) : null}\n </label>\n {validator && validatorHint && !showValidationHint && (\n <p className=\"validator-hint text-xs mt-1 opacity-70\">{validatorHint}</p>\n )}\n {showValidationHint && validator && !isValid && (\n <div className=\"absolute z-10 mt-1 bg-base-200 border border-error rounded shadow-lg text-error px-3 py-1\">\n {validationTooltip}\n </div>\n )}\n </div>\n );\n }\n\n // Default: inline label\n return (\n <div className={`relative w-full ${className}`} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>\n <label className={`${baseClass} ${variantClass} ${sizeClass} ${validatorClass} ${validationStateClass} w-full flex items-center gap-2`}>\n {leftSection && <span>{leftSection}</span>}\n {label && <span>{label}</span>}\n <input\n ref={inputRef}\n type={actualType}\n placeholder={placeholder}\n value={value}\n onChange={handleInputChange}\n disabled={disabled}\n required={required}\n className=\"grow\"\n pattern={pattern}\n />\n {/* 显示最近输入的字符,仅针对密码字段 */}\n {type === 'password' && recentInput && (\n <span className=\"password-recent absolute right-10 font-mono\">\n {recentInput}\n </span>\n )}\n {/* 加入密码切换按钮或其他右侧元素 */}\n {type === 'password' ? (\n <span>{passwordToggle}</span>\n ) : rightSection ? (\n <span>{rightSection}</span>\n ) : null}\n </label>\n {validator && validatorHint && !showValidationHint && (\n <p className=\"validator-hint text-xs mt-1 opacity-70\">{validatorHint}</p>\n )}\n {showValidationHint && validator && !isValid && (\n <div className=\"absolute z-10 mt-1 bg-base-200 border border-error rounded shadow-lg text-error px-3 py-1\">\n {validationTooltip}\n </div>\n )}\n </div>\n );\n }\n\n // 如果没有label,则直接返回input\n return (\n <div className={`relative w-full ${className}`} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>\n <input\n ref={inputRef}\n type={actualType}\n placeholder={placeholder}\n value={value}\n onChange={handleInputChange}\n disabled={disabled}\n required={required}\n className={`${baseClass} ${variantClass} ${sizeClass} ${validatorClass} ${validationStateClass} w-full`}\n pattern={pattern}\n />\n {validator && validatorHint && !showValidationHint && (\n <p className=\"validator-hint text-xs mt-1 opacity-70\">{validatorHint}</p>\n )}\n {showValidationHint && validator && !isValid && (\n <div className=\"absolute z-10 mt-1 bg-base-200 border border-error rounded shadow-lg text-error px-3 py-1\">\n {validationTooltip}\n </div>\n )}\n </div>\n );\n};\n\nexport default Input; "],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Input/index.tsx"],"sourcesContent":["import React, { useState, useRef, useId } from 'react';\nimport './Input.css';\n\nexport type InputProps = Pick<React.InputHTMLAttributes<HTMLInputElement>, 'id' | 'name' | 'readOnly' | 'aria-label' | 'aria-labelledby' | 'aria-describedby' | 'aria-invalid'> & {\n placeholder?: string;\n value?: string;\n onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;\n type?: string;\n variant?: 'neutral' | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error' | 'ghost';\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n disabled?: boolean;\n required?: boolean;\n label?: string;\n labelPosition?: 'inline' | 'top';\n leftSection?: React.ReactNode;\n rightSection?: React.ReactNode;\n pattern?: string;\n className?: string;\n validator?: boolean;\n validatorHint?: string;\n validationRules?: {\n pattern: RegExp;\n message: string;\n }[];\n};\n\nconst Input = ({\n placeholder,\n value,\n onChange,\n type = 'text',\n variant,\n size = 'sm',\n disabled = false,\n required = false,\n label,\n labelPosition = 'inline',\n leftSection,\n rightSection,\n pattern,\n className = '',\n validator = false,\n validatorHint,\n validationRules = [],\n id,\n readOnly,\n ...inputAttributes\n}: InputProps) => {\n const generatedId = useId();\n const fieldId = id || generatedId;\n\n // 密码显示/隐藏状态\n const [showPassword, setShowPassword] = useState(false);\n // 追踪最近输入的字符\n const [recentInput, setRecentInput] = useState('');\n // 表单验证状态\n const [isValid, setIsValid] = useState<boolean | null>(null);\n // 显示验证提示\n const [showValidationHint, setShowValidationHint] = useState(false);\n // 验证失败的规则消息\n const [failedRules, setFailedRules] = useState<string[]>([]);\n \n // 输入框引用,用于焦点和验证\n const inputRef = useRef<HTMLInputElement>(null);\n \n // 确定实际使用的输入类型\n const actualType = type === 'password' && showPassword ? 'text' : type;\n \n // 处理输入变化,包括密码字符延迟遮罩和验证\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n \n // 处理密码输入的特殊效果\n if (type === 'password' && newValue.length > (value || '').length) {\n // 获取新输入的字符\n const newChar = newValue.slice((value || '').length);\n setRecentInput(newChar);\n \n // 设置定时器延迟清除最近输入的字符\n setTimeout(() => {\n setRecentInput('');\n }, 1000); // 1秒后隐藏\n }\n \n // 验证输入\n if (validator && inputRef.current) {\n validateInput(newValue);\n }\n \n // 调用原始的onChange处理函数\n if (onChange) {\n onChange(e);\n }\n };\n \n // 验证输入值\n const validateInput = (inputValue: string) => {\n if (!inputRef.current) return;\n \n // 使用HTML5自带的验证\n const isNativeValid = inputRef.current.checkValidity();\n \n // 检查自定义验证规则\n const failedMessages: string[] = [];\n \n if (validationRules.length > 0) {\n validationRules.forEach(rule => {\n if (!rule.pattern.test(inputValue)) {\n failedMessages.push(rule.message);\n }\n });\n }\n \n setFailedRules(failedMessages);\n setIsValid(isNativeValid && failedMessages.length === 0);\n };\n \n // 切换密码显示/隐藏\n const togglePasswordVisibility = () => {\n setShowPassword(!showPassword);\n };\n \n // 鼠标悬停事件处理\n const handleMouseEnter = () => {\n if (validator && !isValid) {\n setShowValidationHint(true);\n }\n };\n \n const handleMouseLeave = () => {\n setShowValidationHint(false);\n };\n \n // 验证状态相关的类名\n let validationStateClass = '';\n if (validator && isValid !== null) {\n validationStateClass = isValid ? 'input-success' : 'input-error';\n }\n \n const fieldAttributes = {\n ...inputAttributes,\n id: fieldId,\n readOnly,\n 'aria-invalid': inputAttributes['aria-invalid'] ?? (validator && isValid === false ? true : undefined),\n };\n const baseClass = 'input dishui-input';\n const variantClass = variant && !validationStateClass ? `input-${variant}` : '';\n const sizeClass = size ? `input-${size}` : '';\n const validatorClass = validator ? 'validator' : '';\n \n\n // 密码可见性切换按钮\n const passwordToggle = type === 'password' && (\n <button\n type=\"button\"\n disabled={disabled}\n aria-label={showPassword ? 'Hide password' : 'Show password'}\n aria-pressed={showPassword}\n className=\"cursor-pointer opacity-70 hover:opacity-100\"\n onClick={togglePasswordVisibility}\n >\n {showPassword ? (\n // 眼睛关闭图标\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-5 w-5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94\" />\n <path d=\"M14.12 14.12a3 3 0 1 1-4.24-4.24\" />\n <path d=\"M1 1l22 22\" />\n <path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19\" />\n </svg>\n ) : (\n // 眼睛打开图标\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-5 w-5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n )}\n </button>\n );\n \n // 构建验证提示悬浮框\n const validationTooltip = (\n <div className=\"validation-tooltip\">\n {failedRules.length > 0 ? (\n <ul className=\"text-xs list-disc pl-4 py-1\">\n {failedRules.map((rule, index) => (\n <li key={index}>{rule}</li>\n ))}\n </ul>\n ) : validatorHint ? (\n <p className=\"text-xs py-1\">{validatorHint}</p>\n ) : null}\n </div>\n );\n\n // 如果有label,则使用label作为容器\n if (label || leftSection || rightSection || type === 'password') {\n // labelPosition === 'top': label above the input field\n if (label && labelPosition === 'top') {\n return (\n <div className={`relative w-full ${className}`} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>\n <label htmlFor={fieldId} className=\"text-sm font-medium mb-1 block\">{label}</label>\n <label className={`${baseClass} ${variantClass} ${sizeClass} ${validatorClass} ${validationStateClass} w-full flex items-center gap-2`}>\n {leftSection && <span>{leftSection}</span>}\n <input\n {...fieldAttributes}\n ref={inputRef}\n type={actualType}\n placeholder={placeholder}\n value={value}\n onChange={handleInputChange}\n disabled={disabled}\n required={required}\n className=\"grow\"\n pattern={pattern}\n />\n {type === 'password' ? (\n <button type=\"button\" disabled={disabled} aria-label={showPassword ? 'Hide password' : 'Show password'} aria-pressed={showPassword} className=\"cursor-pointer opacity-70 hover:opacity-100\" onClick={togglePasswordVisibility}>\n {showPassword ? (\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-5 w-5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94\" />\n <path d=\"M14.12 14.12a3 3 0 1 1-4.24-4.24\" />\n <path d=\"M1 1l22 22\" />\n <path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19\" />\n </svg>\n ) : (\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-5 w-5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n )}\n </button>\n ) : rightSection ? (\n <span>{rightSection}</span>\n ) : null}\n </label>\n {validator && validatorHint && !showValidationHint && (\n <p className=\"validator-hint text-xs mt-1 opacity-70\">{validatorHint}</p>\n )}\n {showValidationHint && validator && !isValid && (\n <div className=\"absolute z-10 mt-1 bg-base-200 border border-error rounded shadow-lg text-error px-3 py-1\">\n {validationTooltip}\n </div>\n )}\n </div>\n );\n }\n\n // Default: inline label\n return (\n <div className={`relative w-full ${className}`} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>\n <label className={`${baseClass} ${variantClass} ${sizeClass} ${validatorClass} ${validationStateClass} w-full flex items-center gap-2`}>\n {leftSection && <span>{leftSection}</span>}\n {label && <span>{label}</span>}\n <input\n {...fieldAttributes}\n ref={inputRef}\n type={actualType}\n placeholder={placeholder}\n value={value}\n onChange={handleInputChange}\n disabled={disabled}\n required={required}\n className=\"grow\"\n pattern={pattern}\n />\n {/* 显示最近输入的字符,仅针对密码字段 */}\n {type === 'password' && recentInput && (\n <span className=\"password-recent absolute right-10 font-mono\">\n {recentInput}\n </span>\n )}\n {/* 加入密码切换按钮或其他右侧元素 */}\n {type === 'password' ? (\n <span>{passwordToggle}</span>\n ) : rightSection ? (\n <span>{rightSection}</span>\n ) : null}\n </label>\n {validator && validatorHint && !showValidationHint && (\n <p className=\"validator-hint text-xs mt-1 opacity-70\">{validatorHint}</p>\n )}\n {showValidationHint && validator && !isValid && (\n <div className=\"absolute z-10 mt-1 bg-base-200 border border-error rounded shadow-lg text-error px-3 py-1\">\n {validationTooltip}\n </div>\n )}\n </div>\n );\n }\n\n // 如果没有label,则直接返回input\n return (\n <div className={`relative w-full ${className}`} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>\n <input\n {...fieldAttributes}\n ref={inputRef}\n type={actualType}\n placeholder={placeholder}\n value={value}\n onChange={handleInputChange}\n disabled={disabled}\n required={required}\n className={`${baseClass} ${variantClass} ${sizeClass} ${validatorClass} ${validationStateClass} w-full`}\n pattern={pattern}\n />\n {validator && validatorHint && !showValidationHint && (\n <p className=\"validator-hint text-xs mt-1 opacity-70\">{validatorHint}</p>\n )}\n {showValidationHint && validator && !isValid && (\n <div className=\"absolute z-10 mt-1 bg-base-200 border border-error rounded shadow-lg text-error px-3 py-1\">\n {validationTooltip}\n </div>\n )}\n </div>\n );\n};\n\nexport default Input; "],"mappings":"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"}
|
|
@@ -23,7 +23,7 @@ var a = ({ children: a, variant: o = "neutral", size: s = "sm", outline: c = !1,
|
|
|
23
23
|
md: "text-base",
|
|
24
24
|
lg: "text-lg",
|
|
25
25
|
xl: "text-xl"
|
|
26
|
-
}, ee = F[s] || F.md, I = c || l || u, L = I ? "badge" : "label dark:text-white", R = !I && o ? `text-${o}` : "", z = c ? "badge-outline" : "", B = l ? "badge-dash" : "", V = u ? "badge-soft" : "", H = I && o && o !== "neutral" ? `badge-${o}` : "", U = e(L, R, ee, z, B, V, H, d ? "font-bold" : "", f ? "italic" : "", p ? "underline" : "", m ? "truncate" : "", D), W = (e) => {
|
|
26
|
+
}, ee = F[s] || F.md, I = c || l || u, L = I ? "badge" : e("label min-w-0 dark:text-white", !m && "whitespace-normal wrap-anywhere"), R = !I && o ? `text-${o}` : "", z = c ? "badge-outline" : "", B = l ? "badge-dash" : "", V = u ? "badge-soft" : "", H = I && o && o !== "neutral" ? `badge-${o}` : "", U = e(L, R, ee, z, B, V, H, d ? "font-bold" : "", f ? "italic" : "", p ? "underline" : "", m ? "truncate" : "", D), W = (e) => {
|
|
27
27
|
N("clicked"), b?.(e);
|
|
28
28
|
}, G = (e) => {
|
|
29
29
|
N("doubleClicked"), x?.(e);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Label/index.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, DragEvent } from 'react';\nimport { cn } from '../../utils/cn';\n\n// 扩展LabelState类型为字符串,允许用户定义任意状态\nexport type LabelState = string;\n\nexport type LabelStyleConfig = {\n [key: string]: {\n className?: string;\n style?: React.CSSProperties;\n }\n};\n\nexport type LabelProps = {\n children: React.ReactNode;\n variant?: 'neutral' | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error';\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n outline?: boolean;\n dash?: boolean;\n soft?: boolean;\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n ellipsis?: boolean;\n maxWidth?: string;\n stateTimeout?: number;\n styleConfig?: LabelStyleConfig;\n // 新增属性:用户自定义状态\n state?: LabelState;\n // 新增属性:状态变化回调\n onStateChange?: (newState: LabelState) => void;\n onClick?: (e: React.MouseEvent) => void;\n onDoubleClick?: (e: React.MouseEvent) => void;\n onMouseEnter?: (e: React.MouseEvent) => void;\n onMouseLeave?: (e: React.MouseEvent) => void;\n onDragStart?: (e: DragEvent<HTMLSpanElement>) => void;\n onDragEnd?: (e: DragEvent<HTMLSpanElement>) => void;\n draggable?: boolean;\n className?: string;\n style?: React.CSSProperties;\n};\n\nconst Label = ({\n children,\n variant = 'neutral',\n size = 'sm',\n outline = false,\n dash = false,\n soft = false,\n bold = false,\n italic = false,\n underline = false,\n ellipsis = false,\n maxWidth,\n stateTimeout,\n styleConfig = {},\n // 使用用户传入的状态,默认为'default'\n state: userState,\n onStateChange,\n onClick,\n onDoubleClick,\n onMouseEnter,\n onMouseLeave,\n onDragStart,\n onDragEnd,\n draggable = false,\n className = '',\n style = {},\n}: LabelProps) => {\n // 当用户传入state时使用用户的状态,否则内部管理状态\n const [internalState, setInternalState] = useState<LabelState>('default');\n const state = userState !== undefined ? userState : internalState;\n \n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n \n // 更新状态的函数,同时执行回调\n const updateState = (newState: LabelState) => {\n if (userState === undefined) {\n setInternalState(newState);\n }\n onStateChange?.(newState);\n resetStateTimeout(newState);\n };\n \n // 重置状态计时器\n const resetStateTimeout = (currentState: LabelState = state) => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n \n if (stateTimeout && currentState !== 'default' && userState === undefined) {\n timeoutRef.current = setTimeout(() => {\n setInternalState('default');\n onStateChange?.('default');\n }, stateTimeout);\n }\n };\n \n // 当状态变化或stateTimeout变化时重置计时器\n useEffect(() => {\n resetStateTimeout();\n \n // 清除计时器\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, [state, stateTimeout, userState]);\n \n // 尺寸类映射\n const sizeClassMap = {\n 'xs': 'text-xs',\n 'sm': 'text-sm',\n 'md': 'text-base',\n 'lg': 'text-lg',\n 'xl': 'text-xl',\n };\n const sizeClass = sizeClassMap[size] || sizeClassMap.md;\n \n // 样式类(依托 daisyUI badge 的 outline/dash/soft 外观,保证与主题联动)\n const decorated = outline || dash || soft;\n // 基础类:普通文本 label;带装饰时用 badge 充当“标签”容器\n //(装饰态不叠加 text-${variant}/dark:text-white,避免与 badge 自身前景色冲突)\n const baseClass = decorated ? 'badge' : 'label dark:text-white';\n const variantClass = !decorated && variant ? `text-${variant}` : '';\n const outlineClass = outline ? 'badge-outline' : '';\n const dashClass = dash ? 'badge-dash' : '';\n const softClass = soft ? 'badge-soft' : '';\n // 为带装饰的标签补上色调变体(badge-${variant}),让边框/底色跟随 variant\n const badgeVariantClass = decorated && variant && variant !== 'neutral' ? `badge-${variant}` : '';\n const boldClass = bold ? 'font-bold' : '';\n const italicClass = italic ? 'italic' : '';\n const underlineClass = underline ? 'underline' : '';\n const ellipsisClass = ellipsis ? 'truncate' : '';\n \n // 组合所有类名\n const labelClasses = cn(\n baseClass,\n variantClass,\n sizeClass,\n outlineClass,\n dashClass,\n softClass,\n badgeVariantClass,\n boldClass,\n italicClass,\n underlineClass,\n ellipsisClass,\n className\n );\n \n // 处理事件\n const handleClick = (e: React.MouseEvent) => {\n updateState('clicked');\n onClick?.(e);\n };\n \n const handleDoubleClick = (e: React.MouseEvent) => {\n updateState('doubleClicked');\n onDoubleClick?.(e);\n };\n \n const handleMouseEnter = (e: React.MouseEvent) => {\n updateState('hover');\n onMouseEnter?.(e);\n };\n \n const handleMouseLeave = (e: React.MouseEvent) => {\n updateState('default');\n onMouseLeave?.(e);\n };\n \n const handleDragStart = (e: DragEvent<HTMLSpanElement>) => {\n updateState('dragging');\n onDragStart?.(e);\n };\n \n const handleDragEnd = (e: DragEvent<HTMLSpanElement>) => {\n updateState('default');\n onDragEnd?.(e);\n };\n \n // 获取当前状态的自定义样式和类\n const stateStyle = styleConfig[state]?.style || {};\n const stateClassName = styleConfig[state]?.className || '';\n \n // 合并样式\n const combinedStyle = {\n ...style,\n ...stateStyle,\n ...(maxWidth ? { maxWidth } : {}),\n ...(ellipsis ? { display: 'inline-block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } : {})\n };\n \n // 最终类名\n const finalClassName = cn(labelClasses, stateClassName);\n \n return (\n <span\n className={finalClassName}\n style={combinedStyle}\n onClick={handleClick}\n onDoubleClick={handleDoubleClick}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n draggable={draggable}\n >\n {children}\n </span>\n );\n};\n\nexport default Label; "],"mappings":";;;;AA0CA,IAAM,KAAS,EACb,aACA,aAAU,WACV,UAAO,MACP,aAAU,IACV,UAAO,IACP,UAAO,IACP,UAAO,IACP,YAAS,IACT,eAAY,IACZ,cAAW,IACX,aACA,iBACA,iBAAc,CAAC,GAEf,OAAO,GACP,kBACA,YACA,kBACA,iBACA,iBACA,gBACA,cACA,eAAY,IACZ,eAAY,IACZ,WAAQ,CAAC,QACO;CAEhB,IAAM,CAAC,GAAe,KAAoB,EAAqB,SAAS,GAClE,IAAQ,MAAc,KAAA,IAAwB,IAAZ,GAElC,IAAa,EAA6C,IAAI,GAG9D,KAAe,MAAyB;EAK5C,AAJI,MAAc,KAAA,KAChB,EAAiB,CAAQ,GAE3B,IAAgB,CAAQ,GACxB,EAAkB,CAAQ;CAC5B,GAGM,KAAqB,IAA2B,MAAU;EAM9D,AALA,AAEE,EAAW,aADX,aAAa,EAAW,OAAO,GACV,OAGnB,KAAgB,MAAiB,aAAa,MAAc,KAAA,MAC9D,EAAW,UAAU,iBAAiB;GAEpC,AADA,EAAiB,SAAS,GAC1B,IAAgB,SAAS;EAC3B,GAAG,CAAY;CAEnB;CAGA,SACE,EAAkB,SAGL;EACX,AAAI,EAAW,WACb,aAAa,EAAW,OAAO;CAEnC,IACC;EAAC;EAAO;EAAc;CAAS,CAAC;CAGnC,IAAM,IAAe;EACnB,IAAM;EACN,IAAM;EACN,IAAM;EACN,IAAM;EACN,IAAM;CACR,GACM,KAAY,EAAa,MAAS,EAAa,IAG/C,IAAY,KAAW,KAAQ,GAG/B,IAAY,IAAY,UAAU,
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Label/index.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, DragEvent } from 'react';\nimport { cn } from '../../utils/cn';\n\n// 扩展LabelState类型为字符串,允许用户定义任意状态\nexport type LabelState = string;\n\nexport type LabelStyleConfig = {\n [key: string]: {\n className?: string;\n style?: React.CSSProperties;\n }\n};\n\nexport type LabelProps = {\n children: React.ReactNode;\n variant?: 'neutral' | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error';\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n outline?: boolean;\n dash?: boolean;\n soft?: boolean;\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n ellipsis?: boolean;\n maxWidth?: string;\n stateTimeout?: number;\n styleConfig?: LabelStyleConfig;\n // 新增属性:用户自定义状态\n state?: LabelState;\n // 新增属性:状态变化回调\n onStateChange?: (newState: LabelState) => void;\n onClick?: (e: React.MouseEvent) => void;\n onDoubleClick?: (e: React.MouseEvent) => void;\n onMouseEnter?: (e: React.MouseEvent) => void;\n onMouseLeave?: (e: React.MouseEvent) => void;\n onDragStart?: (e: DragEvent<HTMLSpanElement>) => void;\n onDragEnd?: (e: DragEvent<HTMLSpanElement>) => void;\n draggable?: boolean;\n className?: string;\n style?: React.CSSProperties;\n};\n\nconst Label = ({\n children,\n variant = 'neutral',\n size = 'sm',\n outline = false,\n dash = false,\n soft = false,\n bold = false,\n italic = false,\n underline = false,\n ellipsis = false,\n maxWidth,\n stateTimeout,\n styleConfig = {},\n // 使用用户传入的状态,默认为'default'\n state: userState,\n onStateChange,\n onClick,\n onDoubleClick,\n onMouseEnter,\n onMouseLeave,\n onDragStart,\n onDragEnd,\n draggable = false,\n className = '',\n style = {},\n}: LabelProps) => {\n // 当用户传入state时使用用户的状态,否则内部管理状态\n const [internalState, setInternalState] = useState<LabelState>('default');\n const state = userState !== undefined ? userState : internalState;\n \n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n \n // 更新状态的函数,同时执行回调\n const updateState = (newState: LabelState) => {\n if (userState === undefined) {\n setInternalState(newState);\n }\n onStateChange?.(newState);\n resetStateTimeout(newState);\n };\n \n // 重置状态计时器\n const resetStateTimeout = (currentState: LabelState = state) => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n \n if (stateTimeout && currentState !== 'default' && userState === undefined) {\n timeoutRef.current = setTimeout(() => {\n setInternalState('default');\n onStateChange?.('default');\n }, stateTimeout);\n }\n };\n \n // 当状态变化或stateTimeout变化时重置计时器\n useEffect(() => {\n resetStateTimeout();\n \n // 清除计时器\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, [state, stateTimeout, userState]);\n \n // 尺寸类映射\n const sizeClassMap = {\n 'xs': 'text-xs',\n 'sm': 'text-sm',\n 'md': 'text-base',\n 'lg': 'text-lg',\n 'xl': 'text-xl',\n };\n const sizeClass = sizeClassMap[size] || sizeClassMap.md;\n \n // 样式类(依托 daisyUI badge 的 outline/dash/soft 外观,保证与主题联动)\n const decorated = outline || dash || soft;\n // 基础类:普通文本 label;带装饰时用 badge 充当“标签”容器\n //(装饰态不叠加 text-${variant}/dark:text-white,避免与 badge 自身前景色冲突)\n const baseClass = decorated ? 'badge' : cn('label min-w-0 dark:text-white', !ellipsis && 'whitespace-normal wrap-anywhere');\n const variantClass = !decorated && variant ? `text-${variant}` : '';\n const outlineClass = outline ? 'badge-outline' : '';\n const dashClass = dash ? 'badge-dash' : '';\n const softClass = soft ? 'badge-soft' : '';\n // 为带装饰的标签补上色调变体(badge-${variant}),让边框/底色跟随 variant\n const badgeVariantClass = decorated && variant && variant !== 'neutral' ? `badge-${variant}` : '';\n const boldClass = bold ? 'font-bold' : '';\n const italicClass = italic ? 'italic' : '';\n const underlineClass = underline ? 'underline' : '';\n const ellipsisClass = ellipsis ? 'truncate' : '';\n \n // 组合所有类名\n const labelClasses = cn(\n baseClass,\n variantClass,\n sizeClass,\n outlineClass,\n dashClass,\n softClass,\n badgeVariantClass,\n boldClass,\n italicClass,\n underlineClass,\n ellipsisClass,\n className\n );\n \n // 处理事件\n const handleClick = (e: React.MouseEvent) => {\n updateState('clicked');\n onClick?.(e);\n };\n \n const handleDoubleClick = (e: React.MouseEvent) => {\n updateState('doubleClicked');\n onDoubleClick?.(e);\n };\n \n const handleMouseEnter = (e: React.MouseEvent) => {\n updateState('hover');\n onMouseEnter?.(e);\n };\n \n const handleMouseLeave = (e: React.MouseEvent) => {\n updateState('default');\n onMouseLeave?.(e);\n };\n \n const handleDragStart = (e: DragEvent<HTMLSpanElement>) => {\n updateState('dragging');\n onDragStart?.(e);\n };\n \n const handleDragEnd = (e: DragEvent<HTMLSpanElement>) => {\n updateState('default');\n onDragEnd?.(e);\n };\n \n // 获取当前状态的自定义样式和类\n const stateStyle = styleConfig[state]?.style || {};\n const stateClassName = styleConfig[state]?.className || '';\n \n // 合并样式\n const combinedStyle = {\n ...style,\n ...stateStyle,\n ...(maxWidth ? { maxWidth } : {}),\n ...(ellipsis ? { display: 'inline-block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } : {})\n };\n \n // 最终类名\n const finalClassName = cn(labelClasses, stateClassName);\n \n return (\n <span\n className={finalClassName}\n style={combinedStyle}\n onClick={handleClick}\n onDoubleClick={handleDoubleClick}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n draggable={draggable}\n >\n {children}\n </span>\n );\n};\n\nexport default Label; "],"mappings":";;;;AA0CA,IAAM,KAAS,EACb,aACA,aAAU,WACV,UAAO,MACP,aAAU,IACV,UAAO,IACP,UAAO,IACP,UAAO,IACP,YAAS,IACT,eAAY,IACZ,cAAW,IACX,aACA,iBACA,iBAAc,CAAC,GAEf,OAAO,GACP,kBACA,YACA,kBACA,iBACA,iBACA,gBACA,cACA,eAAY,IACZ,eAAY,IACZ,WAAQ,CAAC,QACO;CAEhB,IAAM,CAAC,GAAe,KAAoB,EAAqB,SAAS,GAClE,IAAQ,MAAc,KAAA,IAAwB,IAAZ,GAElC,IAAa,EAA6C,IAAI,GAG9D,KAAe,MAAyB;EAK5C,AAJI,MAAc,KAAA,KAChB,EAAiB,CAAQ,GAE3B,IAAgB,CAAQ,GACxB,EAAkB,CAAQ;CAC5B,GAGM,KAAqB,IAA2B,MAAU;EAM9D,AALA,AAEE,EAAW,aADX,aAAa,EAAW,OAAO,GACV,OAGnB,KAAgB,MAAiB,aAAa,MAAc,KAAA,MAC9D,EAAW,UAAU,iBAAiB;GAEpC,AADA,EAAiB,SAAS,GAC1B,IAAgB,SAAS;EAC3B,GAAG,CAAY;CAEnB;CAGA,SACE,EAAkB,SAGL;EACX,AAAI,EAAW,WACb,aAAa,EAAW,OAAO;CAEnC,IACC;EAAC;EAAO;EAAc;CAAS,CAAC;CAGnC,IAAM,IAAe;EACnB,IAAM;EACN,IAAM;EACN,IAAM;EACN,IAAM;EACN,IAAM;CACR,GACM,KAAY,EAAa,MAAS,EAAa,IAG/C,IAAY,KAAW,KAAQ,GAG/B,IAAY,IAAY,UAAU,EAAG,iCAAiC,CAAC,KAAY,iCAAiC,GACpH,IAAe,CAAC,KAAa,IAAU,QAAQ,MAAY,IAC3D,IAAe,IAAU,kBAAkB,IAC3C,IAAY,IAAO,eAAe,IAClC,IAAY,IAAO,eAAe,IAElC,IAAoB,KAAa,KAAW,MAAY,YAAY,SAAS,MAAY,IAOzF,IAAe,EACnB,GACA,GACA,IACA,GACA,GACA,GACA,GAbgB,IAAO,cAAc,IACnB,IAAS,WAAW,IACjB,IAAY,cAAc,IAC3B,IAAW,aAAa,IAe5C,CACF,GAGM,KAAe,MAAwB;EAE3C,AADA,EAAY,SAAS,GACrB,IAAU,CAAC;CACb,GAEM,KAAqB,MAAwB;EAEjD,AADA,EAAY,eAAe,GAC3B,IAAgB,CAAC;CACnB,GAEM,KAAoB,MAAwB;EAEhD,AADA,EAAY,OAAO,GACnB,IAAe,CAAC;CAClB,GAEM,KAAoB,MAAwB;EAEhD,AADA,EAAY,SAAS,GACrB,IAAe,CAAC;CAClB,GAEM,KAAmB,MAAkC;EAEzD,AADA,EAAY,UAAU,GACtB,IAAc,CAAC;CACjB,GAEM,KAAiB,MAAkC;EAEvD,AADA,EAAY,SAAS,GACrB,IAAY,CAAC;CACf,GAGM,IAAa,EAAY,EAAM,EAAE,SAAS,CAAC,GAC3C,IAAiB,EAAY,EAAM,EAAE,aAAa,IAGlD,IAAgB;EACpB,GAAG;EACH,GAAG;EACH,GAAI,IAAW,EAAE,YAAS,IAAI,CAAC;EAC/B,GAAI,IAAW;GAAE,SAAS;GAAgB,UAAU;GAAU,cAAc;GAAY,YAAY;EAAS,IAAI,CAAC;CACpH,GAGM,IAAiB,EAAG,GAAc,CAAc;CAEtD,OACE,kBAAC,QAAD;EACE,WAAW;EACX,OAAO;EACP,SAAS;EACT,eAAe;EACf,cAAc;EACd,cAAc;EACd,aAAa;EACb,WAAW;EACA;EAEV;CACG,CAAA;AAEV"}
|
|
@@ -1,48 +1,79 @@
|
|
|
1
1
|
import e from "../Button/index.js";
|
|
2
2
|
/* empty css */
|
|
3
|
-
import { useId as t,
|
|
4
|
-
import { jsx as
|
|
3
|
+
import { useId as t, useLayoutEffect as n, useRef as r, useState as i } from "react";
|
|
4
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/NavigationList/index.tsx
|
|
6
|
-
function
|
|
7
|
-
let [
|
|
6
|
+
function s({ items: s, value: c, onValueChange: l, root: u, defaultExpanded: d = !0, "aria-label": f }) {
|
|
7
|
+
let [p, m] = i(d), h = t(), g = r(null), _ = r(null), v = r(null), y = r(!1), b = !u || p;
|
|
8
|
+
n(() => {
|
|
9
|
+
let e = g.current, t = _.current;
|
|
10
|
+
if (!e || !t) return;
|
|
11
|
+
!b && e.contains(document.activeElement) && v.current?.querySelector("[aria-expanded]")?.focus();
|
|
12
|
+
let n = () => {
|
|
13
|
+
e.style.height = `${b ? t.getBoundingClientRect().height : 0}px`;
|
|
14
|
+
};
|
|
15
|
+
y.current ? n() : (e.style.transition = "none", n(), e.offsetHeight, e.style.removeProperty("transition"), y.current = !0);
|
|
16
|
+
let r = new ResizeObserver(n);
|
|
17
|
+
return r.observe(t), () => r.disconnect();
|
|
18
|
+
}, [b]);
|
|
19
|
+
let x = (t) => /* @__PURE__ */ o(e, {
|
|
8
20
|
type: "button",
|
|
9
21
|
variant: "ghost",
|
|
10
22
|
className: "blade-navigation-list__item",
|
|
11
|
-
"aria-pressed":
|
|
12
|
-
onClick: () =>
|
|
13
|
-
children: [/* @__PURE__ */
|
|
23
|
+
"aria-pressed": c === t.value,
|
|
24
|
+
onClick: () => l(t.value),
|
|
25
|
+
children: [/* @__PURE__ */ a("span", {
|
|
14
26
|
className: "blade-navigation-list__label",
|
|
15
27
|
children: t.label
|
|
16
|
-
}), t.count !== void 0 && /* @__PURE__ */
|
|
28
|
+
}), t.count !== void 0 && /* @__PURE__ */ a("span", {
|
|
17
29
|
className: "blade-navigation-list__count",
|
|
18
30
|
children: t.count
|
|
19
31
|
})]
|
|
20
32
|
});
|
|
21
|
-
return /* @__PURE__ */
|
|
33
|
+
return /* @__PURE__ */ o("div", {
|
|
22
34
|
className: "blade-navigation-list",
|
|
23
35
|
role: "group",
|
|
24
|
-
"aria-label":
|
|
25
|
-
children: [
|
|
36
|
+
"aria-label": f,
|
|
37
|
+
children: [u && /* @__PURE__ */ o("div", {
|
|
38
|
+
ref: v,
|
|
26
39
|
className: "blade-navigation-list__root",
|
|
27
|
-
children: [/* @__PURE__ */
|
|
40
|
+
children: [/* @__PURE__ */ a(e, {
|
|
28
41
|
type: "button",
|
|
29
42
|
variant: "ghost",
|
|
30
43
|
size: "xs",
|
|
31
|
-
|
|
32
|
-
"aria-
|
|
33
|
-
"aria-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
className: "blade-navigation-list__disclosure",
|
|
45
|
+
"aria-label": `${p ? "折叠" : "展开"}${f}`,
|
|
46
|
+
"aria-expanded": p,
|
|
47
|
+
"aria-controls": h,
|
|
48
|
+
onClick: () => m((e) => !e),
|
|
49
|
+
children: /* @__PURE__ */ a("svg", {
|
|
50
|
+
className: "blade-navigation-list__chevron",
|
|
51
|
+
"data-expanded": p,
|
|
52
|
+
width: "14",
|
|
53
|
+
height: "14",
|
|
54
|
+
viewBox: "0 0 16 16",
|
|
55
|
+
fill: "none",
|
|
56
|
+
stroke: "currentColor",
|
|
57
|
+
strokeWidth: "1.5",
|
|
58
|
+
"aria-hidden": "true",
|
|
59
|
+
children: /* @__PURE__ */ a("path", { d: "m6 3 5 5-5 5" })
|
|
60
|
+
})
|
|
61
|
+
}), x(u)]
|
|
62
|
+
}), /* @__PURE__ */ a("div", {
|
|
63
|
+
id: h,
|
|
64
|
+
ref: g,
|
|
65
|
+
className: "blade-navigation-list__panel",
|
|
66
|
+
inert: !b,
|
|
67
|
+
"aria-hidden": !b || void 0,
|
|
68
|
+
children: /* @__PURE__ */ a("ul", {
|
|
69
|
+
ref: _,
|
|
70
|
+
className: u ? "blade-navigation-list__children" : void 0,
|
|
71
|
+
children: s.map((e) => /* @__PURE__ */ a("li", { children: x(e) }, e.value))
|
|
72
|
+
})
|
|
42
73
|
})]
|
|
43
74
|
});
|
|
44
75
|
}
|
|
45
76
|
//#endregion
|
|
46
|
-
export {
|
|
77
|
+
export { s as default };
|
|
47
78
|
|
|
48
79
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/NavigationList/index.tsx"],"sourcesContent":["import React, { useId, useState } from 'react';\nimport Button from '../Button';\nimport './NavigationList.css';\n\nexport type NavigationListItem = {\n value: string;\n label: React.ReactNode;\n count?: React.ReactNode;\n};\n\nexport type NavigationListProps = {\n 'aria-label': string;\n items: readonly NavigationListItem[];\n value: string;\n onValueChange: (value: string) => void;\n /** Optional selectable parent with a separate disclosure control. */\n root?: NavigationListItem;\n defaultExpanded?: boolean;\n};\n\n/** A single-level navigation/filter list with native keyboard-operable controls. */\nexport default function NavigationList({ items, value, onValueChange, root, defaultExpanded = true, 'aria-label': label }: NavigationListProps) {\n const [expanded, setExpanded] = useState(defaultExpanded);\n const id = useId();\n const itemButton = (item: NavigationListItem) => <Button type=\"button\" variant=\"ghost\" className=\"blade-navigation-list__item\" aria-pressed={value === item.value} onClick={() => onValueChange(item.value)}>\n <span className=\"blade-navigation-list__label\">{item.label}</span>\n {item.count !== undefined && <span className=\"blade-navigation-list__count\">{item.count}</span>}\n </Button>;\n return <div className=\"blade-navigation-list\" role=\"group\" aria-label={label}>\n {root && <div className=\"blade-navigation-list__root\">\n <Button type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={`${expanded ? '折叠' : '展开'}${label}`} aria-expanded={expanded} aria-controls={id} onClick={() => setExpanded(current => !current)}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/NavigationList/index.tsx"],"sourcesContent":["import React, { useId, useLayoutEffect, useRef, useState } from 'react';\nimport Button from '../Button';\nimport './NavigationList.css';\n\nexport type NavigationListItem = {\n value: string;\n label: React.ReactNode;\n count?: React.ReactNode;\n};\n\nexport type NavigationListProps = {\n 'aria-label': string;\n items: readonly NavigationListItem[];\n value: string;\n onValueChange: (value: string) => void;\n /** Optional selectable parent with a separate disclosure control. */\n root?: NavigationListItem;\n defaultExpanded?: boolean;\n};\n\n/** A single-level navigation/filter list with native keyboard-operable controls. */\nexport default function NavigationList({ items, value, onValueChange, root, defaultExpanded = true, 'aria-label': label }: NavigationListProps) {\n const [expanded, setExpanded] = useState(defaultExpanded);\n const id = useId();\n const panelRef = useRef<HTMLDivElement>(null);\n const listRef = useRef<HTMLUListElement>(null);\n const rootRef = useRef<HTMLDivElement>(null);\n const initialized = useRef(false);\n const open = !root || expanded;\n\n useLayoutEffect(() => {\n const panel = panelRef.current;\n const list = listRef.current;\n if (!panel || !list) return;\n if (!open && panel.contains(document.activeElement)) {\n rootRef.current?.querySelector<HTMLButtonElement>('[aria-expanded]')?.focus();\n }\n const updateHeight = () => {\n panel.style.height = `${open ? list.getBoundingClientRect().height : 0}px`;\n };\n // Initialize without an entrance animation, including defaultExpanded=false.\n if (!initialized.current) {\n panel.style.transition = 'none';\n updateHeight();\n void panel.offsetHeight;\n panel.style.removeProperty('transition');\n initialized.current = true;\n } else {\n updateHeight();\n }\n // Observe the natural content, not the animated wrapper, to avoid feedback loops.\n const observer = new ResizeObserver(updateHeight);\n observer.observe(list);\n return () => observer.disconnect();\n }, [open]);\n const itemButton = (item: NavigationListItem) => <Button type=\"button\" variant=\"ghost\" className=\"blade-navigation-list__item\" aria-pressed={value === item.value} onClick={() => onValueChange(item.value)}>\n <span className=\"blade-navigation-list__label\">{item.label}</span>\n {item.count !== undefined && <span className=\"blade-navigation-list__count\">{item.count}</span>}\n </Button>;\n return <div className=\"blade-navigation-list\" role=\"group\" aria-label={label}>\n {root && <div ref={rootRef} className=\"blade-navigation-list__root\">\n <Button type=\"button\" variant=\"ghost\" size=\"xs\" className=\"blade-navigation-list__disclosure\" aria-label={`${expanded ? '折叠' : '展开'}${label}`} aria-expanded={expanded} aria-controls={id} onClick={() => setExpanded(current => !current)}><svg className=\"blade-navigation-list__chevron\" data-expanded={expanded} width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" aria-hidden=\"true\"><path d=\"m6 3 5 5-5 5\" /></svg></Button>\n {itemButton(root)}\n </div>}\n <div id={id} ref={panelRef} className=\"blade-navigation-list__panel\" inert={!open} aria-hidden={!open || undefined}>\n <ul ref={listRef} className={root ? 'blade-navigation-list__children' : undefined}>\n {items.map(item => <li key={item.value}>{itemButton(item)}</li>)}\n </ul>\n </div>\n </div>;\n}\n"],"mappings":";;;;;AAqBA,SAAwB,EAAe,EAAE,UAAO,UAAO,kBAAe,SAAM,qBAAkB,IAAM,cAAc,KAA8B;CAC5I,IAAM,CAAC,GAAU,KAAe,EAAS,CAAe,GAClD,IAAK,EAAM,GACX,IAAW,EAAuB,IAAI,GACtC,IAAU,EAAyB,IAAI,GACvC,IAAU,EAAuB,IAAI,GACrC,IAAc,EAAO,EAAK,GAC1B,IAAO,CAAC,KAAQ;CAEtB,QAAsB;EAClB,IAAM,IAAQ,EAAS,SACjB,IAAO,EAAQ;EACrB,IAAI,CAAC,KAAS,CAAC,GAAM;EACrB,AAAI,CAAC,KAAQ,EAAM,SAAS,SAAS,aAAa,KAC9C,EAAQ,SAAS,cAAiC,iBAAiB,CAAC,EAAE,MAAM;EAEhF,IAAM,UAAqB;GACvB,EAAM,MAAM,SAAS,GAAG,IAAO,EAAK,sBAAsB,CAAC,CAAC,SAAS,EAAE;EAC3E;EAEA,AAAK,EAAY,UAOb,EAAa,KANb,EAAM,MAAM,aAAa,QACzB,EAAa,GACb,EAAW,cACX,EAAM,MAAM,eAAe,YAAY,GACvC,EAAY,UAAU;EAK1B,IAAM,IAAW,IAAI,eAAe,CAAY;EAEhD,OADA,EAAS,QAAQ,CAAI,SACR,EAAS,WAAW;CACrC,GAAG,CAAC,CAAI,CAAC;CACT,IAAM,KAAc,MAA6B,kBAAC,GAAD;EAAQ,MAAK;EAAS,SAAQ;EAAQ,WAAU;EAA8B,gBAAc,MAAU,EAAK;EAAO,eAAe,EAAc,EAAK,KAAK;EAAzJ,UAAA,CAC7C,kBAAC,QAAD;GAAM,WAAU;GAAgC,UAAA,EAAK;EAAY,CAAA,GAChE,EAAK,UAAU,KAAA,KAAa,kBAAC,QAAD;GAAM,WAAU;GAAgC,UAAA,EAAK;EAAY,CAAA,CAC1F;;CACR,OAAO,kBAAC,OAAD;EAAK,WAAU;EAAwB,MAAK;EAAQ,cAAY;EAAhE,UAAA,CACF,KAAQ,kBAAC,OAAD;GAAK,KAAK;GAAS,WAAU;GAA7B,UAAA,CACL,kBAAC,GAAD;IAAQ,MAAK;IAAS,SAAQ;IAAQ,MAAK;IAAK,WAAU;IAAoC,cAAY,GAAG,IAAW,OAAO,OAAO;IAAS,iBAAe;IAAU,iBAAe;IAAI,eAAe,GAAY,MAAW,CAAC,CAAO;IAAG,UAAA,kBAAC,OAAD;KAAK,WAAU;KAAiC,iBAAe;KAAU,OAAM;KAAK,QAAO;KAAK,SAAQ;KAAY,MAAK;KAAO,QAAO;KAAe,aAAY;KAAM,eAAY;KAAO,UAAA,kBAAC,QAAD,EAAM,GAAE,eAAgB,CAAA;IAAM,CAAA;GAAS,CAAA,GAC7c,EAAW,CAAI,CACf;EACL,CAAA,GAAA,kBAAC,OAAD;GAAS;GAAI,KAAK;GAAU,WAAU;GAA+B,OAAO,CAAC;GAAM,eAAa,CAAC,KAAQ,KAAA;GACrG,UAAA,kBAAC,MAAD;IAAI,KAAK;IAAS,WAAW,IAAO,oCAAoC,KAAA;IACnE,UAAA,EAAM,KAAI,MAAQ,kBAAC,MAAD,EAAA,UAAsB,EAAW,CAAI,EAAM,GAAlC,EAAK,KAA6B,CAAC;GAC/D,CAAA;EACH,CAAA,CACJ;;AACT"}
|