@ug666/ui-react 0.1.0 → 0.2.0
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/blocks/index.cjs +238 -0
- package/dist/blocks/index.cjs.map +1 -0
- package/dist/blocks/index.d.cts +86 -0
- package/dist/blocks/index.d.ts +86 -0
- package/dist/blocks/index.js +153 -0
- package/dist/blocks/index.js.map +1 -0
- package/dist/button-CaLZig8j.d.cts +22 -0
- package/dist/button-CaLZig8j.d.ts +22 -0
- package/dist/chunk-2IVRUJKO.js +377 -0
- package/dist/chunk-2IVRUJKO.js.map +1 -0
- package/dist/chunk-73WQAE3E.js +3003 -0
- package/dist/chunk-73WQAE3E.js.map +1 -0
- package/dist/chunk-RUDEZA5Q.js +62 -0
- package/dist/chunk-RUDEZA5Q.js.map +1 -0
- package/dist/chunk-S45GP6IB.js +254 -0
- package/dist/chunk-S45GP6IB.js.map +1 -0
- package/dist/components/index.cjs +3993 -0
- package/dist/components/index.cjs.map +1 -0
- package/dist/components/index.d.cts +1097 -0
- package/dist/components/index.d.ts +1097 -0
- package/dist/components/index.js +330 -0
- package/dist/components/index.js.map +1 -0
- package/dist/hooks/index.cjs +1 -0
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/index.cjs +1410 -710
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +274 -1340
- package/dist/index.d.ts +274 -1340
- package/dist/index.js +385 -3229
- package/dist/index.js.map +1 -1
- package/dist/labs/index.cjs +34 -0
- package/dist/labs/index.cjs.map +1 -0
- package/dist/labs/index.d.cts +12 -0
- package/dist/labs/index.d.ts +12 -0
- package/dist/labs/index.js +9 -0
- package/dist/labs/index.js.map +1 -0
- package/dist/patterns/index.cjs +758 -0
- package/dist/patterns/index.cjs.map +1 -0
- package/dist/patterns/index.d.cts +158 -0
- package/dist/patterns/index.d.ts +158 -0
- package/dist/patterns/index.js +320 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/primitives/index.cjs +384 -0
- package/dist/primitives/index.cjs.map +1 -0
- package/dist/primitives/index.d.cts +137 -0
- package/dist/primitives/index.d.ts +137 -0
- package/dist/primitives/index.js +56 -0
- package/dist/primitives/index.js.map +1 -0
- package/dist/sidebar-vl00Z2o-.d.cts +93 -0
- package/dist/sidebar-vl00Z2o-.d.ts +93 -0
- package/dist/styles.css +2499 -0
- package/dist/tokens.css +86 -9
- package/package.json +36 -6
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
3
|
+
import { VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
declare const buttonVariants: (props?: ({
|
|
6
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
|
|
7
|
+
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
8
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
10
|
+
/** 是否处于加载状态,加载时显示旋转图标并禁用点击 */
|
|
11
|
+
loading?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 通用按钮组件
|
|
15
|
+
* @example
|
|
16
|
+
* <Button variant="default" size="lg" onClick={handleClick}>确认</Button>
|
|
17
|
+
* <Button variant="destructive" loading>删除中...</Button>
|
|
18
|
+
* <Button variant="outline" size="sm">取消</Button>
|
|
19
|
+
*/
|
|
20
|
+
declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
|
|
21
|
+
|
|
22
|
+
export { type ButtonProps as B, Button as a, buttonVariants as b };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
3
|
+
import { VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
declare const buttonVariants: (props?: ({
|
|
6
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
|
|
7
|
+
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
8
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
10
|
+
/** 是否处于加载状态,加载时显示旋转图标并禁用点击 */
|
|
11
|
+
loading?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 通用按钮组件
|
|
15
|
+
* @example
|
|
16
|
+
* <Button variant="default" size="lg" onClick={handleClick}>确认</Button>
|
|
17
|
+
* <Button variant="destructive" loading>删除中...</Button>
|
|
18
|
+
* <Button variant="outline" size="sm">取消</Button>
|
|
19
|
+
*/
|
|
20
|
+
declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
|
|
21
|
+
|
|
22
|
+
export { type ButtonProps as B, Button as a, buttonVariants as b };
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cn
|
|
3
|
+
} from "./chunk-RUDEZA5Q.js";
|
|
4
|
+
|
|
5
|
+
// src/components/modal.tsx
|
|
6
|
+
import { forwardRef } from "react";
|
|
7
|
+
import { createPortal } from "react-dom";
|
|
8
|
+
import { X } from "lucide-react";
|
|
9
|
+
|
|
10
|
+
// src/hooks/use-escape-key.ts
|
|
11
|
+
import { useCallback, useEffect } from "react";
|
|
12
|
+
function useEscapeKey(open, onEscape) {
|
|
13
|
+
const handleEscape = useCallback(
|
|
14
|
+
(e) => {
|
|
15
|
+
if (e.key === "Escape") onEscape();
|
|
16
|
+
},
|
|
17
|
+
[onEscape]
|
|
18
|
+
);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (!open || typeof document === "undefined") return;
|
|
21
|
+
document.addEventListener("keydown", handleEscape);
|
|
22
|
+
document.body.style.overflow = "hidden";
|
|
23
|
+
return () => {
|
|
24
|
+
document.removeEventListener("keydown", handleEscape);
|
|
25
|
+
document.body.style.overflow = "";
|
|
26
|
+
};
|
|
27
|
+
}, [open, handleEscape]);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/internal/use-portal-container.ts
|
|
31
|
+
import { useEffect as useEffect2, useState } from "react";
|
|
32
|
+
function usePortalContainer() {
|
|
33
|
+
const [container, setContainer] = useState(null);
|
|
34
|
+
useEffect2(() => {
|
|
35
|
+
if (typeof document === "undefined") return;
|
|
36
|
+
setContainer(document.body);
|
|
37
|
+
}, []);
|
|
38
|
+
return container;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/components/modal.tsx
|
|
42
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
43
|
+
var Modal = forwardRef(({ open, onClose, children, className }, ref) => {
|
|
44
|
+
useEscapeKey(open, onClose);
|
|
45
|
+
const portalContainer = usePortalContainer();
|
|
46
|
+
if (!open || !portalContainer) return null;
|
|
47
|
+
return createPortal(
|
|
48
|
+
/* @__PURE__ */ jsxs(
|
|
49
|
+
"div",
|
|
50
|
+
{
|
|
51
|
+
ref,
|
|
52
|
+
className: cn(
|
|
53
|
+
"fixed inset-0 z-[80] flex items-center justify-center p-4",
|
|
54
|
+
className
|
|
55
|
+
),
|
|
56
|
+
role: "dialog",
|
|
57
|
+
"aria-modal": "true",
|
|
58
|
+
children: [
|
|
59
|
+
/* @__PURE__ */ jsx(
|
|
60
|
+
"div",
|
|
61
|
+
{
|
|
62
|
+
className: "absolute inset-0 bg-overlay",
|
|
63
|
+
onClick: onClose,
|
|
64
|
+
"aria-hidden": "true"
|
|
65
|
+
}
|
|
66
|
+
),
|
|
67
|
+
/* @__PURE__ */ jsx("div", { className: "relative z-10", children })
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
),
|
|
71
|
+
portalContainer
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
var ModalContent = forwardRef(({ className, maxWidth = "max-w-lg", children, ...props }, ref) => {
|
|
75
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn("flex max-h-[85vh] w-full flex-col rounded-lg border border-border-base bg-surface-1 shadow-xl", maxWidth, className), ...props, children });
|
|
76
|
+
});
|
|
77
|
+
var ModalHeader = forwardRef(({ className, ...props }, ref) => {
|
|
78
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn("flex shrink-0 items-center justify-between border-b border-border-base px-6 py-4", className), ...props });
|
|
79
|
+
});
|
|
80
|
+
var ModalTitle = forwardRef(({ className, ...props }, ref) => {
|
|
81
|
+
return /* @__PURE__ */ jsx("h2", { ref, className: cn("text-lg font-semibold text-text-primary", className), ...props });
|
|
82
|
+
});
|
|
83
|
+
var ModalFooter = forwardRef(({ className, ...props }, ref) => {
|
|
84
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn("flex shrink-0 items-center justify-end gap-2 border-t border-border-base px-6 py-4", className), ...props });
|
|
85
|
+
});
|
|
86
|
+
var ModalCloseButton = forwardRef(({ onClick, className, type = "button", ...props }, ref) => {
|
|
87
|
+
return /* @__PURE__ */ jsx(
|
|
88
|
+
"button",
|
|
89
|
+
{
|
|
90
|
+
ref,
|
|
91
|
+
type,
|
|
92
|
+
onClick,
|
|
93
|
+
className: cn(
|
|
94
|
+
"rounded-md p-1 text-text-tertiary transition-colors hover:bg-surface-3 hover:text-text-secondary",
|
|
95
|
+
className
|
|
96
|
+
),
|
|
97
|
+
"aria-label": "\u5173\u95ED",
|
|
98
|
+
...props,
|
|
99
|
+
children: /* @__PURE__ */ jsx(X, { size: 18 })
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
Modal.displayName = "Modal";
|
|
104
|
+
ModalContent.displayName = "ModalContent";
|
|
105
|
+
ModalHeader.displayName = "ModalHeader";
|
|
106
|
+
ModalTitle.displayName = "ModalTitle";
|
|
107
|
+
ModalFooter.displayName = "ModalFooter";
|
|
108
|
+
ModalCloseButton.displayName = "ModalCloseButton";
|
|
109
|
+
|
|
110
|
+
// src/components/sidebar.tsx
|
|
111
|
+
import { forwardRef as forwardRef2, useMemo, useState as useState2 } from "react";
|
|
112
|
+
import {
|
|
113
|
+
ChevronDown,
|
|
114
|
+
PanelLeftClose,
|
|
115
|
+
PanelLeftOpen,
|
|
116
|
+
Search,
|
|
117
|
+
X as X2
|
|
118
|
+
} from "lucide-react";
|
|
119
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
120
|
+
var variantStyles = {
|
|
121
|
+
primary: {
|
|
122
|
+
container: "border-r border-border-base bg-surface-1 text-text-primary shadow-sm",
|
|
123
|
+
active: "bg-primary/10 text-primary shadow-sm ring-1 ring-primary/20 before:absolute before:left-0 before:top-1/2 before:h-6 before:w-[3px] before:-translate-y-1/2 before:rounded-r-full before:bg-primary",
|
|
124
|
+
inactive: "text-text-secondary hover:bg-surface-2 hover:text-text-primary",
|
|
125
|
+
divider: "border-border-base",
|
|
126
|
+
icon: "bg-transparent text-text-tertiary group-hover:bg-surface-3 group-hover:text-primary",
|
|
127
|
+
activeIcon: "bg-primary/15 text-primary"
|
|
128
|
+
},
|
|
129
|
+
dark: {
|
|
130
|
+
container: "border-r border-border-base bg-surface-1 text-text-primary shadow-sm",
|
|
131
|
+
active: "bg-primary/10 text-primary shadow-sm ring-1 ring-primary/20 before:absolute before:left-0 before:top-1/2 before:h-6 before:w-[3px] before:-translate-y-1/2 before:rounded-r-full before:bg-primary",
|
|
132
|
+
inactive: "text-text-secondary hover:bg-surface-2 hover:text-text-primary",
|
|
133
|
+
divider: "border-border-base",
|
|
134
|
+
icon: "bg-transparent text-text-tertiary group-hover:bg-surface-3 group-hover:text-primary",
|
|
135
|
+
activeIcon: "bg-primary/15 text-primary"
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
function getItemKey(item, index, parentKey) {
|
|
139
|
+
return item.id ?? item.href ?? `${parentKey}-${index}-${item.label}`;
|
|
140
|
+
}
|
|
141
|
+
function itemHasActiveChild(item) {
|
|
142
|
+
return Boolean(item.children?.some((child) => child.active || itemHasActiveChild(child)));
|
|
143
|
+
}
|
|
144
|
+
function normalizeSearch(value) {
|
|
145
|
+
return value.toLowerCase().replace(/\s+/g, "");
|
|
146
|
+
}
|
|
147
|
+
function filterSidebarItems(items, query) {
|
|
148
|
+
if (!query) return items;
|
|
149
|
+
return items.reduce((result, item) => {
|
|
150
|
+
const children = item.children ? filterSidebarItems(item.children, query) : [];
|
|
151
|
+
const matched = normalizeSearch(item.label).includes(query);
|
|
152
|
+
if (matched || children.length > 0) {
|
|
153
|
+
result.push({ ...item, children });
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}, []);
|
|
157
|
+
}
|
|
158
|
+
var Sidebar = forwardRef2(
|
|
159
|
+
({
|
|
160
|
+
items,
|
|
161
|
+
variant = "primary",
|
|
162
|
+
collapsed,
|
|
163
|
+
defaultCollapsed = false,
|
|
164
|
+
onCollapsedChange,
|
|
165
|
+
collapsible = false,
|
|
166
|
+
searchable = false,
|
|
167
|
+
searchPlaceholder = "\u641C\u7D22\u83DC\u5355...",
|
|
168
|
+
responsive = false,
|
|
169
|
+
mobileOpen = false,
|
|
170
|
+
onMobileOpenChange,
|
|
171
|
+
header,
|
|
172
|
+
footer,
|
|
173
|
+
className
|
|
174
|
+
}, ref) => {
|
|
175
|
+
const styles = variantStyles[variant];
|
|
176
|
+
const [internalCollapsed, setInternalCollapsed] = useState2(defaultCollapsed);
|
|
177
|
+
const [expandedKeys, setExpandedKeys] = useState2(() => /* @__PURE__ */ new Set());
|
|
178
|
+
const [query, setQuery] = useState2("");
|
|
179
|
+
const effectiveCollapsed = collapsed ?? internalCollapsed;
|
|
180
|
+
const normalizedQuery = normalizeSearch(query);
|
|
181
|
+
const visibleItems = useMemo(() => filterSidebarItems(items, normalizedQuery), [items, normalizedQuery]);
|
|
182
|
+
function setCollapsedState(nextCollapsed) {
|
|
183
|
+
setInternalCollapsed(nextCollapsed);
|
|
184
|
+
onCollapsedChange?.(nextCollapsed);
|
|
185
|
+
}
|
|
186
|
+
function toggleExpanded(key) {
|
|
187
|
+
setExpandedKeys((current) => {
|
|
188
|
+
const next = new Set(current);
|
|
189
|
+
if (next.has(key)) {
|
|
190
|
+
next.delete(key);
|
|
191
|
+
} else {
|
|
192
|
+
next.add(key);
|
|
193
|
+
}
|
|
194
|
+
return next;
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function closeMobile() {
|
|
198
|
+
onMobileOpenChange?.(false);
|
|
199
|
+
}
|
|
200
|
+
function renderItems(list, depth = 0, parentKey = "root") {
|
|
201
|
+
return /* @__PURE__ */ jsx2("ul", { className: cn("flex flex-col gap-1", depth === 0 ? "px-2.5" : "ml-6 mt-1 border-l border-border-base pl-2"), children: list.map((item, index) => {
|
|
202
|
+
const key = getItemKey(item, index, parentKey);
|
|
203
|
+
const hasChildren = Boolean(item.children?.length);
|
|
204
|
+
const active = Boolean(item.active || itemHasActiveChild(item));
|
|
205
|
+
const expanded = !effectiveCollapsed && hasChildren && (normalizedQuery.length > 0 || active || expandedKeys.has(key));
|
|
206
|
+
const itemContent = /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
207
|
+
/* @__PURE__ */ jsx2(
|
|
208
|
+
"span",
|
|
209
|
+
{
|
|
210
|
+
className: cn(
|
|
211
|
+
"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg transition-colors",
|
|
212
|
+
active ? styles.activeIcon : styles.icon
|
|
213
|
+
),
|
|
214
|
+
children: /* @__PURE__ */ jsx2(item.icon, { size: 16 })
|
|
215
|
+
}
|
|
216
|
+
),
|
|
217
|
+
!effectiveCollapsed && /* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1 truncate text-left", children: item.label }),
|
|
218
|
+
!effectiveCollapsed && hasChildren && /* @__PURE__ */ jsx2(
|
|
219
|
+
ChevronDown,
|
|
220
|
+
{
|
|
221
|
+
size: 15,
|
|
222
|
+
className: cn("shrink-0 text-text-tertiary transition-transform", expanded && "rotate-180"),
|
|
223
|
+
"aria-hidden": "true"
|
|
224
|
+
}
|
|
225
|
+
)
|
|
226
|
+
] });
|
|
227
|
+
const itemClassName = cn(
|
|
228
|
+
"group relative flex min-w-0 items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm font-medium outline-none transition-all duration-150 focus-visible:ring-2 focus-visible:ring-primary/35",
|
|
229
|
+
effectiveCollapsed && "justify-center px-2",
|
|
230
|
+
active ? styles.active : styles.inactive
|
|
231
|
+
);
|
|
232
|
+
return /* @__PURE__ */ jsxs2("li", { children: [
|
|
233
|
+
hasChildren ? /* @__PURE__ */ jsx2(
|
|
234
|
+
"button",
|
|
235
|
+
{
|
|
236
|
+
type: "button",
|
|
237
|
+
className: cn("w-full", itemClassName),
|
|
238
|
+
"aria-expanded": expanded,
|
|
239
|
+
title: effectiveCollapsed ? item.label : void 0,
|
|
240
|
+
onClick: () => toggleExpanded(key),
|
|
241
|
+
children: itemContent
|
|
242
|
+
}
|
|
243
|
+
) : /* @__PURE__ */ jsx2(
|
|
244
|
+
"a",
|
|
245
|
+
{
|
|
246
|
+
href: item.href ?? "#",
|
|
247
|
+
"aria-current": item.active ? "page" : void 0,
|
|
248
|
+
className: itemClassName,
|
|
249
|
+
title: effectiveCollapsed ? item.label : void 0,
|
|
250
|
+
onClick: closeMobile,
|
|
251
|
+
children: itemContent
|
|
252
|
+
}
|
|
253
|
+
),
|
|
254
|
+
expanded && item.children ? renderItems(item.children, depth + 1, key) : null
|
|
255
|
+
] }, key);
|
|
256
|
+
}) });
|
|
257
|
+
}
|
|
258
|
+
const sidebar = /* @__PURE__ */ jsxs2(
|
|
259
|
+
"aside",
|
|
260
|
+
{
|
|
261
|
+
ref,
|
|
262
|
+
className: cn(
|
|
263
|
+
"flex flex-col overflow-hidden transition-all duration-300",
|
|
264
|
+
styles.container,
|
|
265
|
+
effectiveCollapsed ? "w-[72px]" : "w-64",
|
|
266
|
+
responsive && [
|
|
267
|
+
"fixed inset-y-0 left-0 z-50 md:relative md:inset-auto md:z-auto",
|
|
268
|
+
mobileOpen ? "translate-x-0" : "-translate-x-full md:translate-x-0"
|
|
269
|
+
],
|
|
270
|
+
className
|
|
271
|
+
),
|
|
272
|
+
children: [
|
|
273
|
+
(header || collapsible || responsive && mobileOpen) && /* @__PURE__ */ jsxs2(
|
|
274
|
+
"div",
|
|
275
|
+
{
|
|
276
|
+
className: cn(
|
|
277
|
+
"flex border-b px-3 py-3",
|
|
278
|
+
styles.divider,
|
|
279
|
+
effectiveCollapsed ? "justify-center" : "items-center gap-2"
|
|
280
|
+
),
|
|
281
|
+
children: [
|
|
282
|
+
!effectiveCollapsed && header ? /* @__PURE__ */ jsx2("div", { className: "min-w-0 flex-1", children: header }) : null,
|
|
283
|
+
collapsible && /* @__PURE__ */ jsx2(
|
|
284
|
+
"button",
|
|
285
|
+
{
|
|
286
|
+
type: "button",
|
|
287
|
+
className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-border-base bg-surface-2 text-text-secondary transition-colors hover:border-primary/40 hover:text-text-primary",
|
|
288
|
+
"aria-label": effectiveCollapsed ? "\u5C55\u5F00\u4FA7\u8FB9\u680F" : "\u6298\u53E0\u4FA7\u8FB9\u680F",
|
|
289
|
+
onClick: () => setCollapsedState(!effectiveCollapsed),
|
|
290
|
+
children: effectiveCollapsed ? /* @__PURE__ */ jsx2(PanelLeftOpen, { size: 17 }) : /* @__PURE__ */ jsx2(PanelLeftClose, { size: 17 })
|
|
291
|
+
}
|
|
292
|
+
),
|
|
293
|
+
responsive && /* @__PURE__ */ jsx2(
|
|
294
|
+
"button",
|
|
295
|
+
{
|
|
296
|
+
type: "button",
|
|
297
|
+
className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-border-base bg-surface-2 text-text-secondary transition-colors hover:border-primary/40 hover:text-text-primary md:hidden",
|
|
298
|
+
"aria-label": "\u5173\u95ED\u4FA7\u8FB9\u680F",
|
|
299
|
+
onClick: closeMobile,
|
|
300
|
+
children: /* @__PURE__ */ jsx2(X2, { size: 17 })
|
|
301
|
+
}
|
|
302
|
+
)
|
|
303
|
+
]
|
|
304
|
+
}
|
|
305
|
+
),
|
|
306
|
+
searchable && !effectiveCollapsed && /* @__PURE__ */ jsxs2("div", { className: cn("border-b px-3 py-3", styles.divider), children: [
|
|
307
|
+
/* @__PURE__ */ jsx2("label", { className: "sr-only", htmlFor: "ug-sidebar-search", children: "\u641C\u7D22\u83DC\u5355" }),
|
|
308
|
+
/* @__PURE__ */ jsxs2("div", { className: "relative", children: [
|
|
309
|
+
/* @__PURE__ */ jsx2(Search, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary", "aria-hidden": "true" }),
|
|
310
|
+
/* @__PURE__ */ jsx2(
|
|
311
|
+
"input",
|
|
312
|
+
{
|
|
313
|
+
id: "ug-sidebar-search",
|
|
314
|
+
value: query,
|
|
315
|
+
onChange: (event) => setQuery(event.target.value),
|
|
316
|
+
placeholder: searchPlaceholder,
|
|
317
|
+
autoComplete: "off",
|
|
318
|
+
className: "h-10 w-full rounded-lg border border-border-base bg-surface-0 px-3 pl-9 pr-9 text-sm text-text-primary outline-none transition-colors placeholder:text-text-tertiary focus:border-primary focus:ring-2 focus:ring-primary/20",
|
|
319
|
+
type: "text",
|
|
320
|
+
role: "searchbox"
|
|
321
|
+
}
|
|
322
|
+
),
|
|
323
|
+
query ? /* @__PURE__ */ jsx2(
|
|
324
|
+
"button",
|
|
325
|
+
{
|
|
326
|
+
type: "button",
|
|
327
|
+
className: "absolute right-1 top-1/2 flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-md text-text-tertiary transition-colors hover:bg-surface-2 hover:text-text-primary",
|
|
328
|
+
"aria-label": "\u6E05\u7A7A\u641C\u7D22",
|
|
329
|
+
onClick: () => setQuery(""),
|
|
330
|
+
children: /* @__PURE__ */ jsx2(X2, { size: 14 })
|
|
331
|
+
}
|
|
332
|
+
) : null
|
|
333
|
+
] })
|
|
334
|
+
] }),
|
|
335
|
+
/* @__PURE__ */ jsx2("nav", { className: "flex-1 overflow-y-auto py-3.5", children: visibleItems.length > 0 ? renderItems(visibleItems) : /* @__PURE__ */ jsx2("p", { className: "mx-3 rounded-lg border border-dashed border-border-base bg-surface-0 px-3 py-3 text-sm text-text-tertiary", children: "\u6CA1\u6709\u5339\u914D\u7684\u83DC\u5355" }) }),
|
|
336
|
+
footer && /* @__PURE__ */ jsx2(
|
|
337
|
+
"div",
|
|
338
|
+
{
|
|
339
|
+
className: cn(
|
|
340
|
+
"border-t px-2.5 py-3",
|
|
341
|
+
styles.divider,
|
|
342
|
+
effectiveCollapsed && "flex justify-center"
|
|
343
|
+
),
|
|
344
|
+
children: footer
|
|
345
|
+
}
|
|
346
|
+
)
|
|
347
|
+
]
|
|
348
|
+
}
|
|
349
|
+
);
|
|
350
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
351
|
+
responsive && mobileOpen ? /* @__PURE__ */ jsx2(
|
|
352
|
+
"button",
|
|
353
|
+
{
|
|
354
|
+
type: "button",
|
|
355
|
+
className: "fixed inset-0 z-40 bg-overlay md:hidden",
|
|
356
|
+
"aria-label": "\u5173\u95ED\u4FA7\u8FB9\u680F\u906E\u7F69",
|
|
357
|
+
onClick: closeMobile
|
|
358
|
+
}
|
|
359
|
+
) : null,
|
|
360
|
+
sidebar
|
|
361
|
+
] });
|
|
362
|
+
}
|
|
363
|
+
);
|
|
364
|
+
Sidebar.displayName = "Sidebar";
|
|
365
|
+
|
|
366
|
+
export {
|
|
367
|
+
useEscapeKey,
|
|
368
|
+
usePortalContainer,
|
|
369
|
+
Modal,
|
|
370
|
+
ModalContent,
|
|
371
|
+
ModalHeader,
|
|
372
|
+
ModalTitle,
|
|
373
|
+
ModalFooter,
|
|
374
|
+
ModalCloseButton,
|
|
375
|
+
Sidebar
|
|
376
|
+
};
|
|
377
|
+
//# sourceMappingURL=chunk-2IVRUJKO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/modal.tsx","../src/hooks/use-escape-key.ts","../src/internal/use-portal-container.ts","../src/components/sidebar.tsx"],"sourcesContent":["/**\n * @description: Modal 对话框组件 — 纯原生实现,支持遮罩点击关闭和 ESC 关闭,无 Radix 依赖\n * @author: UG - 一个斗码大陆苦逼的三段码之气的少年,并没有神秘戒指中码老的帮助,但总有一天,我会成为斗码大陆中码帝一样的存在。三十年河东,三十年河西,莫欺少年穷。\n * @date: 2026-04-15\n */\nimport { forwardRef } from 'react'\nimport { createPortal } from 'react-dom'\nimport { X } from 'lucide-react'\nimport { cn } from '../internal/cn'\nimport { useEscapeKey } from '../hooks/use-escape-key'\nimport { usePortalContainer } from '../internal/use-portal-container'\n\nexport interface ModalProps {\n /** 是否显示 */\n open: boolean\n /** 关闭回调 */\n onClose: () => void\n /** 子内容 */\n children: React.ReactNode\n /** 额外类名 */\n className?: string\n}\n\nexport interface ModalContentProps extends React.HTMLAttributes<HTMLDivElement> {\n /** 最大宽度,默认 max-w-lg */\n maxWidth?: string\n}\n\nexport type ModalHeaderProps = React.HTMLAttributes<HTMLDivElement>\nexport type ModalTitleProps = React.HTMLAttributes<HTMLHeadingElement>\nexport type ModalFooterProps = React.HTMLAttributes<HTMLDivElement>\nexport interface ModalCloseButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}\n\n/**\n * 对话框组件\n * @example\n * <Modal open={isOpen} onClose={() => setIsOpen(false)}>\n * <ModalContent>\n * <ModalHeader>\n * <ModalTitle>确认删除</ModalTitle>\n * </ModalHeader>\n * <p className=\"px-6 pb-4 text-sm text-text-secondary\">此操作不可撤销。</p>\n * <ModalFooter>\n * <Button variant=\"outline\" onClick={() => setIsOpen(false)}>取消</Button>\n * <Button variant=\"destructive\">删除</Button>\n * </ModalFooter>\n * </ModalContent>\n * </Modal>\n */\nconst Modal = forwardRef<HTMLDivElement, ModalProps>(({ open, onClose, children, className }, ref) => {\n useEscapeKey(open, onClose)\n const portalContainer = usePortalContainer()\n\n if (!open || !portalContainer) return null\n\n return createPortal(\n <div\n ref={ref}\n className={cn(\n 'fixed inset-0 z-[80] flex items-center justify-center p-4',\n className\n )}\n role=\"dialog\"\n aria-modal=\"true\"\n >\n {/* 遮罩层,点击关闭 */}\n <div\n className=\"absolute inset-0 bg-overlay\"\n onClick={onClose}\n aria-hidden=\"true\"\n />\n {/* 内容区域,阻止事件冒泡 */}\n <div className=\"relative z-10\">{children}</div>\n </div>,\n portalContainer\n )\n})\n\nconst ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(({ className, maxWidth = 'max-w-lg', children, ...props }, ref) => {\n return (\n <div ref={ref} className={cn('flex max-h-[85vh] w-full flex-col rounded-lg border border-border-base bg-surface-1 shadow-xl', maxWidth, className)} {...props}>\n {children}\n </div>\n )\n})\n\nconst ModalHeader = forwardRef<HTMLDivElement, ModalHeaderProps>(({ className, ...props }, ref) => {\n return <div ref={ref} className={cn('flex shrink-0 items-center justify-between border-b border-border-base px-6 py-4', className)} {...props} />\n})\n\nconst ModalTitle = forwardRef<HTMLHeadingElement, ModalTitleProps>(({ className, ...props }, ref) => {\n return <h2 ref={ref} className={cn('text-lg font-semibold text-text-primary', className)} {...props} />\n})\n\nconst ModalFooter = forwardRef<HTMLDivElement, ModalFooterProps>(({ className, ...props }, ref) => {\n return <div ref={ref} className={cn('flex shrink-0 items-center justify-end gap-2 border-t border-border-base px-6 py-4', className)} {...props} />\n})\n\n/** 独立关闭按钮,可放在 ModalHeader 右侧 */\nconst ModalCloseButton = forwardRef<HTMLButtonElement, ModalCloseButtonProps>(({ onClick, className, type = 'button', ...props }, ref) => {\n return (\n <button\n ref={ref}\n type={type}\n onClick={onClick}\n className={cn(\n 'rounded-md p-1 text-text-tertiary transition-colors hover:bg-surface-3 hover:text-text-secondary',\n className\n )}\n aria-label=\"关闭\"\n {...props}\n >\n <X size={18} />\n </button>\n )\n})\n\nModal.displayName = 'Modal'\nModalContent.displayName = 'ModalContent'\nModalHeader.displayName = 'ModalHeader'\nModalTitle.displayName = 'ModalTitle'\nModalFooter.displayName = 'ModalFooter'\nModalCloseButton.displayName = 'ModalCloseButton'\n\nexport { Modal, ModalContent, ModalHeader, ModalTitle, ModalFooter, ModalCloseButton }\n","/**\n * @description: 内部 hook — 当组件处于 open 状态时,监听 Escape 键并锁定 body 滚动\n * @author: UG - 一个斗码大陆苦逼的三段码之气的少年,并没有神秘戒指中码老的帮助,但总有一天,我会成为斗码大陆中码帝一样的存在。三十年河东,三十年河西,莫欺少年穷。\n * @date: 2026-04-17\n */\nimport { useCallback, useEffect } from 'react'\n\n/**\n * 叠加层组件(Modal / Sheet / Drawer / Dialog)公共行为:\n * - open 为 true 时:注册 keydown 监听,锁定 body 滚动\n * - open 为 false 或卸载时:移除监听,解锁 body 滚动\n *\n * @param open - 组件是否处于展开状态\n * @param onEscape - 按下 Escape 时的回调\n */\nexport function useEscapeKey(open: boolean, onEscape: () => void): void {\n const handleEscape = useCallback(\n (e: KeyboardEvent) => {\n if (e.key === 'Escape') onEscape()\n },\n [onEscape],\n )\n\n useEffect(() => {\n if (!open || typeof document === 'undefined') return\n document.addEventListener('keydown', handleEscape)\n document.body.style.overflow = 'hidden'\n return () => {\n document.removeEventListener('keydown', handleEscape)\n document.body.style.overflow = ''\n }\n }, [open, handleEscape])\n}\n","/**\n * @description: 内部 hook — 在客户端挂载后提供 portal 容器,避免 SSR render 阶段访问 document\n * @author: UG - 一个斗码大陆苦逼的三段码之气的少年,并没有神秘戒指中码老的帮助,但总有一天,我会成为斗码大陆中码帝一样的存在。三十年河东,三十年河西,莫欺少年穷。\n * @date: 2026-05-31\n */\nimport { useEffect, useState } from 'react'\n\nexport function usePortalContainer(): HTMLElement | null {\n const [container, setContainer] = useState<HTMLElement | null>(null)\n\n useEffect(() => {\n if (typeof document === 'undefined') return\n setContainer(document.body)\n }, [])\n\n return container\n}\n","/**\n * @description: Sidebar 侧边栏布局组件 — 支持 primary/dark 两种风格,collapsed 折叠态,底部 slot\n * @author: UG - 一个斗码大陆苦逼的三段码之气的少年,并没有神秘戒指中码老的帮助,但总有一天,我会成为斗码大陆中码帝一样的存在。三十年河东,三十年河西,莫欺少年穷。\n * @date: 2026-04-18\n */\nimport { forwardRef, useMemo, useState } from 'react'\nimport {\n ChevronDown,\n PanelLeftClose,\n PanelLeftOpen,\n Search,\n X,\n type LucideIcon,\n} from 'lucide-react'\nimport { cn } from '../internal/cn'\n\nexport interface SidebarItem {\n id?: string\n label: string\n href?: string\n icon: LucideIcon\n active?: boolean\n children?: SidebarItem[]\n}\n\nexport type SidebarVariant = 'primary' | 'dark'\n\nexport interface SidebarProps {\n /** 导航菜单项 */\n items: SidebarItem[]\n /** 视觉变体:primary 品牌色(默认),dark 深灰色(推荐后台管理) */\n variant?: SidebarVariant\n /** 是否折叠,折叠时只显示图标 */\n collapsed?: boolean\n /** 非受控折叠默认值 */\n defaultCollapsed?: boolean\n /** 折叠状态变化回调 */\n onCollapsedChange?: (collapsed: boolean) => void\n /** 是否显示内置折叠按钮 */\n collapsible?: boolean\n /** 是否显示内置搜索 */\n searchable?: boolean\n /** 搜索输入占位文案 */\n searchPlaceholder?: string\n /** 是否启用移动端抽屉模式 */\n responsive?: boolean\n /** 移动端抽屉是否打开 */\n mobileOpen?: boolean\n /** 移动端抽屉开关回调 */\n onMobileOpenChange?: (open: boolean) => void\n /** 顶部插槽,用于品牌或用户信息 */\n header?: React.ReactNode\n /** 底部插槽,用于退出登录等操作 */\n footer?: React.ReactNode\n /** 额外类名 */\n className?: string\n}\n\nconst variantStyles: Record<SidebarVariant, {\n container: string\n active: string\n inactive: string\n divider: string\n icon: string\n activeIcon: string\n}> = {\n primary: {\n container: 'border-r border-border-base bg-surface-1 text-text-primary shadow-sm',\n active: 'bg-primary/10 text-primary shadow-sm ring-1 ring-primary/20 before:absolute before:left-0 before:top-1/2 before:h-6 before:w-[3px] before:-translate-y-1/2 before:rounded-r-full before:bg-primary',\n inactive: 'text-text-secondary hover:bg-surface-2 hover:text-text-primary',\n divider: 'border-border-base',\n icon: 'bg-transparent text-text-tertiary group-hover:bg-surface-3 group-hover:text-primary',\n activeIcon: 'bg-primary/15 text-primary',\n },\n dark: {\n container: 'border-r border-border-base bg-surface-1 text-text-primary shadow-sm',\n active: 'bg-primary/10 text-primary shadow-sm ring-1 ring-primary/20 before:absolute before:left-0 before:top-1/2 before:h-6 before:w-[3px] before:-translate-y-1/2 before:rounded-r-full before:bg-primary',\n inactive: 'text-text-secondary hover:bg-surface-2 hover:text-text-primary',\n divider: 'border-border-base',\n icon: 'bg-transparent text-text-tertiary group-hover:bg-surface-3 group-hover:text-primary',\n activeIcon: 'bg-primary/15 text-primary',\n },\n}\n\nfunction getItemKey(item: SidebarItem, index: number, parentKey: string): string {\n return item.id ?? item.href ?? `${parentKey}-${index}-${item.label}`\n}\n\nfunction itemHasActiveChild(item: SidebarItem): boolean {\n return Boolean(item.children?.some((child) => child.active || itemHasActiveChild(child)))\n}\n\nfunction normalizeSearch(value: string): string {\n return value.toLowerCase().replace(/\\s+/g, '')\n}\n\nfunction filterSidebarItems(items: SidebarItem[], query: string): SidebarItem[] {\n if (!query) return items\n\n return items.reduce<SidebarItem[]>((result, item) => {\n const children = item.children ? filterSidebarItems(item.children, query) : []\n const matched = normalizeSearch(item.label).includes(query)\n\n if (matched || children.length > 0) {\n result.push({ ...item, children })\n }\n\n return result\n }, [])\n}\n\n/**\n * 侧边栏布局组件\n * @example\n * <Sidebar variant=\"dark\" items={navItems} footer={<LogoutButton />} />\n */\nconst Sidebar = forwardRef<HTMLElement, SidebarProps>(\n (\n {\n items,\n variant = 'primary',\n collapsed,\n defaultCollapsed = false,\n onCollapsedChange,\n collapsible = false,\n searchable = false,\n searchPlaceholder = '搜索菜单...',\n responsive = false,\n mobileOpen = false,\n onMobileOpenChange,\n header,\n footer,\n className,\n },\n ref,\n ) => {\n const styles = variantStyles[variant]\n const [internalCollapsed, setInternalCollapsed] = useState(defaultCollapsed)\n const [expandedKeys, setExpandedKeys] = useState<Set<string>>(() => new Set())\n const [query, setQuery] = useState('')\n const effectiveCollapsed = collapsed ?? internalCollapsed\n const normalizedQuery = normalizeSearch(query)\n const visibleItems = useMemo(() => filterSidebarItems(items, normalizedQuery), [items, normalizedQuery])\n\n function setCollapsedState(nextCollapsed: boolean) {\n setInternalCollapsed(nextCollapsed)\n onCollapsedChange?.(nextCollapsed)\n }\n\n function toggleExpanded(key: string) {\n setExpandedKeys((current) => {\n const next = new Set(current)\n if (next.has(key)) {\n next.delete(key)\n } else {\n next.add(key)\n }\n return next\n })\n }\n\n function closeMobile() {\n onMobileOpenChange?.(false)\n }\n\n function renderItems(list: SidebarItem[], depth = 0, parentKey = 'root') {\n return (\n <ul className={cn('flex flex-col gap-1', depth === 0 ? 'px-2.5' : 'ml-6 mt-1 border-l border-border-base pl-2')}>\n {list.map((item, index) => {\n const key = getItemKey(item, index, parentKey)\n const hasChildren = Boolean(item.children?.length)\n const active = Boolean(item.active || itemHasActiveChild(item))\n const expanded = !effectiveCollapsed && hasChildren && (normalizedQuery.length > 0 || active || expandedKeys.has(key))\n const itemContent = (\n <>\n <span\n className={cn(\n 'flex h-8 w-8 shrink-0 items-center justify-center rounded-lg transition-colors',\n active ? styles.activeIcon : styles.icon,\n )}\n >\n <item.icon size={16} />\n </span>\n {!effectiveCollapsed && <span className=\"min-w-0 flex-1 truncate text-left\">{item.label}</span>}\n {!effectiveCollapsed && hasChildren && (\n <ChevronDown\n size={15}\n className={cn('shrink-0 text-text-tertiary transition-transform', expanded && 'rotate-180')}\n aria-hidden=\"true\"\n />\n )}\n </>\n )\n const itemClassName = cn(\n 'group relative flex min-w-0 items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm font-medium outline-none transition-all duration-150 focus-visible:ring-2 focus-visible:ring-primary/35',\n effectiveCollapsed && 'justify-center px-2',\n active ? styles.active : styles.inactive,\n )\n\n return (\n <li key={key}>\n {hasChildren ? (\n <button\n type=\"button\"\n className={cn('w-full', itemClassName)}\n aria-expanded={expanded}\n title={effectiveCollapsed ? item.label : undefined}\n onClick={() => toggleExpanded(key)}\n >\n {itemContent}\n </button>\n ) : (\n <a\n href={item.href ?? '#'}\n aria-current={item.active ? 'page' : undefined}\n className={itemClassName}\n title={effectiveCollapsed ? item.label : undefined}\n onClick={closeMobile}\n >\n {itemContent}\n </a>\n )}\n {expanded && item.children ? renderItems(item.children, depth + 1, key) : null}\n </li>\n )\n })}\n </ul>\n )\n }\n\n const sidebar = (\n <aside\n ref={ref}\n className={cn(\n 'flex flex-col overflow-hidden transition-all duration-300',\n styles.container,\n effectiveCollapsed ? 'w-[72px]' : 'w-64',\n responsive && [\n 'fixed inset-y-0 left-0 z-50 md:relative md:inset-auto md:z-auto',\n mobileOpen ? 'translate-x-0' : '-translate-x-full md:translate-x-0',\n ],\n className,\n )}\n >\n {(header || collapsible || (responsive && mobileOpen)) && (\n <div\n className={cn(\n 'flex border-b px-3 py-3',\n styles.divider,\n effectiveCollapsed ? 'justify-center' : 'items-center gap-2',\n )}\n >\n {!effectiveCollapsed && header ? <div className=\"min-w-0 flex-1\">{header}</div> : null}\n {collapsible && (\n <button\n type=\"button\"\n className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-border-base bg-surface-2 text-text-secondary transition-colors hover:border-primary/40 hover:text-text-primary\"\n aria-label={effectiveCollapsed ? '展开侧边栏' : '折叠侧边栏'}\n onClick={() => setCollapsedState(!effectiveCollapsed)}\n >\n {effectiveCollapsed ? <PanelLeftOpen size={17} /> : <PanelLeftClose size={17} />}\n </button>\n )}\n {responsive && (\n <button\n type=\"button\"\n className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-border-base bg-surface-2 text-text-secondary transition-colors hover:border-primary/40 hover:text-text-primary md:hidden\"\n aria-label=\"关闭侧边栏\"\n onClick={closeMobile}\n >\n <X size={17} />\n </button>\n )}\n </div>\n )}\n\n {searchable && !effectiveCollapsed && (\n <div className={cn('border-b px-3 py-3', styles.divider)}>\n <label className=\"sr-only\" htmlFor=\"ug-sidebar-search\">搜索菜单</label>\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\" aria-hidden=\"true\" />\n <input\n id=\"ug-sidebar-search\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder={searchPlaceholder}\n autoComplete=\"off\"\n className=\"h-10 w-full rounded-lg border border-border-base bg-surface-0 px-3 pl-9 pr-9 text-sm text-text-primary outline-none transition-colors placeholder:text-text-tertiary focus:border-primary focus:ring-2 focus:ring-primary/20\"\n type=\"text\"\n role=\"searchbox\"\n />\n {query ? (\n <button\n type=\"button\"\n className=\"absolute right-1 top-1/2 flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-md text-text-tertiary transition-colors hover:bg-surface-2 hover:text-text-primary\"\n aria-label=\"清空搜索\"\n onClick={() => setQuery('')}\n >\n <X size={14} />\n </button>\n ) : null}\n </div>\n </div>\n )}\n\n <nav className=\"flex-1 overflow-y-auto py-3.5\">\n {visibleItems.length > 0 ? (\n renderItems(visibleItems)\n ) : (\n <p className=\"mx-3 rounded-lg border border-dashed border-border-base bg-surface-0 px-3 py-3 text-sm text-text-tertiary\">\n 没有匹配的菜单\n </p>\n )}\n </nav>\n\n {footer && (\n <div\n className={cn(\n 'border-t px-2.5 py-3',\n styles.divider,\n effectiveCollapsed && 'flex justify-center',\n )}\n >\n {footer}\n </div>\n )}\n </aside>\n )\n\n return (\n <>\n {responsive && mobileOpen ? (\n <button\n type=\"button\"\n className=\"fixed inset-0 z-40 bg-overlay md:hidden\"\n aria-label=\"关闭侧边栏遮罩\"\n onClick={closeMobile}\n />\n ) : null}\n {sidebar}\n </>\n )\n },\n)\n\nSidebar.displayName = 'Sidebar'\n\nexport { Sidebar }\n"],"mappings":"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","names":["useEffect","forwardRef","useState","X","jsx","jsxs","forwardRef","useState","X"]}
|