@classic-homes/theme-react 0.1.52 → 0.1.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +12 -10
- package/dist/index.d.mts +750 -53
- package/dist/index.d.ts +750 -53
- package/dist/index.js +1451 -217
- package/dist/index.mjs +1447 -233
- package/package.json +13 -3
package/dist/index.mjs
CHANGED
|
@@ -39,9 +39,9 @@ var buttonVariants = cva(
|
|
|
39
39
|
}
|
|
40
40
|
);
|
|
41
41
|
var Button = React.forwardRef(
|
|
42
|
-
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
42
|
+
({ className, variant, size, asChild = false, children, ...props }, ref) => {
|
|
43
43
|
const Comp = asChild ? Slot : "button";
|
|
44
|
-
return /* @__PURE__ */ jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref, ...props });
|
|
44
|
+
return /* @__PURE__ */ jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref, ...props, children });
|
|
45
45
|
}
|
|
46
46
|
);
|
|
47
47
|
Button.displayName = "Button";
|
|
@@ -50,8 +50,8 @@ Button.displayName = "Button";
|
|
|
50
50
|
import * as React2 from "react";
|
|
51
51
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
52
52
|
var Card = React2.forwardRef(
|
|
53
|
-
({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
|
|
54
|
-
|
|
53
|
+
({ className, as: Component = "div", ...props }, ref) => /* @__PURE__ */ jsx2(
|
|
54
|
+
Component,
|
|
55
55
|
{
|
|
56
56
|
ref,
|
|
57
57
|
className: cn(
|
|
@@ -68,8 +68,8 @@ var CardHeader = React2.forwardRef(
|
|
|
68
68
|
);
|
|
69
69
|
CardHeader.displayName = "CardHeader";
|
|
70
70
|
var CardTitle = React2.forwardRef(
|
|
71
|
-
({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
|
|
72
|
-
|
|
71
|
+
({ className, as: Component = "h3", ...props }, ref) => /* @__PURE__ */ jsx2(
|
|
72
|
+
Component,
|
|
73
73
|
{
|
|
74
74
|
ref,
|
|
75
75
|
className: cn("text-2xl font-semibold leading-none tracking-tight", className),
|
|
@@ -93,13 +93,32 @@ CardFooter.displayName = "CardFooter";
|
|
|
93
93
|
import * as React3 from "react";
|
|
94
94
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
95
95
|
var Input = React3.forwardRef(
|
|
96
|
-
({
|
|
96
|
+
({
|
|
97
|
+
className,
|
|
98
|
+
type,
|
|
99
|
+
"aria-invalid": ariaInvalid,
|
|
100
|
+
required,
|
|
101
|
+
"aria-describedby": ariaDescribedBy,
|
|
102
|
+
...props
|
|
103
|
+
}, ref) => {
|
|
104
|
+
if (process.env.NODE_ENV !== "production") {
|
|
105
|
+
if (!props["aria-label"] && !props["aria-labelledby"] && !props.id) {
|
|
106
|
+
console.warn(
|
|
107
|
+
"Input: Missing accessible label. Provide aria-label, aria-labelledby, or associate with a Label using id/htmlFor for WCAG compliance."
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
97
111
|
return /* @__PURE__ */ jsx3(
|
|
98
112
|
"input",
|
|
99
113
|
{
|
|
100
114
|
type,
|
|
115
|
+
"aria-invalid": ariaInvalid,
|
|
116
|
+
"aria-required": required,
|
|
117
|
+
"aria-describedby": ariaDescribedBy,
|
|
118
|
+
required,
|
|
101
119
|
className: cn(
|
|
102
120
|
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
121
|
+
ariaInvalid === true || ariaInvalid === "true" ? "border-destructive focus-visible:ring-destructive" : "",
|
|
103
122
|
className
|
|
104
123
|
),
|
|
105
124
|
ref,
|
|
@@ -111,7 +130,57 @@ var Input = React3.forwardRef(
|
|
|
111
130
|
Input.displayName = "Input";
|
|
112
131
|
|
|
113
132
|
// src/components/PasswordInput.tsx
|
|
133
|
+
import * as React5 from "react";
|
|
134
|
+
|
|
135
|
+
// src/hooks/useAnnounce.ts
|
|
114
136
|
import * as React4 from "react";
|
|
137
|
+
function useAnnounce(defaultOptions) {
|
|
138
|
+
const [message, setMessage] = React4.useState("");
|
|
139
|
+
const [politeness, setPoliteness] = React4.useState(
|
|
140
|
+
defaultOptions?.politeness ?? "polite"
|
|
141
|
+
);
|
|
142
|
+
const clearTimeoutRef = React4.useRef(null);
|
|
143
|
+
const clear = React4.useCallback(() => {
|
|
144
|
+
setMessage("");
|
|
145
|
+
if (clearTimeoutRef.current) {
|
|
146
|
+
clearTimeout(clearTimeoutRef.current);
|
|
147
|
+
clearTimeoutRef.current = null;
|
|
148
|
+
}
|
|
149
|
+
}, []);
|
|
150
|
+
const announce = React4.useCallback(
|
|
151
|
+
(newMessage, options) => {
|
|
152
|
+
if (clearTimeoutRef.current) {
|
|
153
|
+
clearTimeout(clearTimeoutRef.current);
|
|
154
|
+
}
|
|
155
|
+
if (options?.politeness) {
|
|
156
|
+
setPoliteness(options.politeness);
|
|
157
|
+
}
|
|
158
|
+
setMessage(newMessage);
|
|
159
|
+
const delay = options?.clearDelay ?? defaultOptions?.clearDelay ?? 1e3;
|
|
160
|
+
if (delay > 0) {
|
|
161
|
+
clearTimeoutRef.current = setTimeout(() => {
|
|
162
|
+
setMessage("");
|
|
163
|
+
}, delay);
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
[defaultOptions?.clearDelay]
|
|
167
|
+
);
|
|
168
|
+
React4.useEffect(() => {
|
|
169
|
+
return () => {
|
|
170
|
+
if (clearTimeoutRef.current) {
|
|
171
|
+
clearTimeout(clearTimeoutRef.current);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}, []);
|
|
175
|
+
return {
|
|
176
|
+
announce,
|
|
177
|
+
message,
|
|
178
|
+
politeness,
|
|
179
|
+
clear
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// src/components/PasswordInput.tsx
|
|
115
184
|
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
116
185
|
var EyeIcon = () => /* @__PURE__ */ jsxs(
|
|
117
186
|
"svg",
|
|
@@ -124,6 +193,8 @@ var EyeIcon = () => /* @__PURE__ */ jsxs(
|
|
|
124
193
|
strokeWidth: 2,
|
|
125
194
|
strokeLinecap: "round",
|
|
126
195
|
strokeLinejoin: "round",
|
|
196
|
+
"aria-hidden": "true",
|
|
197
|
+
focusable: "false",
|
|
127
198
|
children: [
|
|
128
199
|
/* @__PURE__ */ jsx4("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }),
|
|
129
200
|
/* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "3" })
|
|
@@ -141,20 +212,48 @@ var EyeOffIcon = () => /* @__PURE__ */ jsx4(
|
|
|
141
212
|
strokeWidth: 2,
|
|
142
213
|
strokeLinecap: "round",
|
|
143
214
|
strokeLinejoin: "round",
|
|
215
|
+
"aria-hidden": "true",
|
|
216
|
+
focusable: "false",
|
|
144
217
|
children: /* @__PURE__ */ jsx4("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.94M9.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.19m-6.72-1.07a3 3 0 1 1-4.24-4.24M1 1l22 22" })
|
|
145
218
|
}
|
|
146
219
|
);
|
|
147
|
-
var PasswordInput =
|
|
148
|
-
({
|
|
149
|
-
|
|
220
|
+
var PasswordInput = React5.forwardRef(
|
|
221
|
+
({
|
|
222
|
+
className,
|
|
223
|
+
disabled,
|
|
224
|
+
showLabel = "Show password",
|
|
225
|
+
hideLabel = "Hide password",
|
|
226
|
+
visibleAnnouncement = "Password is now visible",
|
|
227
|
+
hiddenAnnouncement = "Password is now hidden",
|
|
228
|
+
id,
|
|
229
|
+
"aria-label": ariaLabel,
|
|
230
|
+
"aria-labelledby": ariaLabelledBy,
|
|
231
|
+
...props
|
|
232
|
+
}, ref) => {
|
|
233
|
+
const [showPassword, setShowPassword] = React5.useState(false);
|
|
234
|
+
const { announce, message, politeness } = useAnnounce();
|
|
235
|
+
if (process.env.NODE_ENV !== "production") {
|
|
236
|
+
if (!ariaLabel && !ariaLabelledBy && !id) {
|
|
237
|
+
console.warn(
|
|
238
|
+
"PasswordInput: Missing accessible label. Provide aria-label, aria-labelledby, or an id to associate with a Label element for WCAG compliance."
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
150
242
|
const toggleVisibility = () => {
|
|
151
|
-
setShowPassword((prev) =>
|
|
243
|
+
setShowPassword((prev) => {
|
|
244
|
+
const newState = !prev;
|
|
245
|
+
announce(newState ? visibleAnnouncement : hiddenAnnouncement);
|
|
246
|
+
return newState;
|
|
247
|
+
});
|
|
152
248
|
};
|
|
153
249
|
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
154
250
|
/* @__PURE__ */ jsx4(
|
|
155
251
|
"input",
|
|
156
252
|
{
|
|
157
253
|
type: showPassword ? "text" : "password",
|
|
254
|
+
id,
|
|
255
|
+
"aria-label": ariaLabel,
|
|
256
|
+
"aria-labelledby": ariaLabelledBy,
|
|
158
257
|
className: cn(
|
|
159
258
|
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 pr-10 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
160
259
|
className
|
|
@@ -168,35 +267,37 @@ var PasswordInput = React4.forwardRef(
|
|
|
168
267
|
"button",
|
|
169
268
|
{
|
|
170
269
|
type: "button",
|
|
171
|
-
className: "absolute right-0 top-0 h-
|
|
270
|
+
className: "absolute right-0 top-0 h-11 w-11 -mr-0.5 -mt-0.5 flex items-center justify-center text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded-r-md disabled:pointer-events-none disabled:opacity-50",
|
|
172
271
|
onClick: toggleVisibility,
|
|
173
272
|
disabled,
|
|
174
273
|
"aria-label": showPassword ? hideLabel : showLabel,
|
|
274
|
+
"aria-pressed": showPassword,
|
|
175
275
|
children: showPassword ? /* @__PURE__ */ jsx4(EyeOffIcon, {}) : /* @__PURE__ */ jsx4(EyeIcon, {})
|
|
176
276
|
}
|
|
177
|
-
)
|
|
277
|
+
),
|
|
278
|
+
/* @__PURE__ */ jsx4("div", { role: "status", "aria-live": politeness, "aria-atomic": "true", className: "sr-only", children: message })
|
|
178
279
|
] });
|
|
179
280
|
}
|
|
180
281
|
);
|
|
181
282
|
PasswordInput.displayName = "PasswordInput";
|
|
182
283
|
|
|
183
284
|
// src/components/Label.tsx
|
|
184
|
-
import * as
|
|
285
|
+
import * as React6 from "react";
|
|
185
286
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
186
287
|
import { cva as cva2 } from "class-variance-authority";
|
|
187
288
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
188
289
|
var labelVariants = cva2(
|
|
189
290
|
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
190
291
|
);
|
|
191
|
-
var Label =
|
|
292
|
+
var Label = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(LabelPrimitive.Root, { ref, className: cn(labelVariants(), className), ...props }));
|
|
192
293
|
Label.displayName = LabelPrimitive.Root.displayName;
|
|
193
294
|
|
|
194
295
|
// src/components/Badge.tsx
|
|
195
|
-
import * as
|
|
296
|
+
import * as React7 from "react";
|
|
196
297
|
import { cva as cva3 } from "class-variance-authority";
|
|
197
|
-
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
298
|
+
import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
198
299
|
var badgeVariants = cva3(
|
|
199
|
-
"inline-flex items-center rounded-full border border-border px-2.5 py-0.5 text-xs font-semibold transition-colors
|
|
300
|
+
"inline-flex items-center rounded-full border border-border px-2.5 py-0.5 text-xs font-semibold transition-colors",
|
|
200
301
|
{
|
|
201
302
|
variants: {
|
|
202
303
|
variant: {
|
|
@@ -211,15 +312,28 @@ var badgeVariants = cva3(
|
|
|
211
312
|
}
|
|
212
313
|
}
|
|
213
314
|
);
|
|
214
|
-
var Badge =
|
|
215
|
-
({ className, variant, ...props }, ref) => {
|
|
216
|
-
|
|
315
|
+
var Badge = React7.forwardRef(
|
|
316
|
+
({ className, variant, live, label, children, ...props }, ref) => {
|
|
317
|
+
if (process.env.NODE_ENV !== "production") {
|
|
318
|
+
if (live && !label) {
|
|
319
|
+
console.warn(
|
|
320
|
+
'Badge: When using live={true} for dynamic content, consider providing a label prop for better screen reader context (e.g., label="unread notifications" for a count badge).'
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return /* @__PURE__ */ jsxs2(
|
|
217
325
|
"div",
|
|
218
326
|
{
|
|
219
327
|
ref,
|
|
220
|
-
role: "status",
|
|
328
|
+
role: live ? "status" : void 0,
|
|
329
|
+
"aria-live": live ? "polite" : void 0,
|
|
330
|
+
"aria-atomic": live ? "true" : void 0,
|
|
221
331
|
className: cn(badgeVariants({ variant }), className),
|
|
222
|
-
...props
|
|
332
|
+
...props,
|
|
333
|
+
children: [
|
|
334
|
+
children,
|
|
335
|
+
label && /* @__PURE__ */ jsx6("span", { className: "sr-only", children: label })
|
|
336
|
+
]
|
|
223
337
|
}
|
|
224
338
|
);
|
|
225
339
|
}
|
|
@@ -227,81 +341,123 @@ var Badge = React6.forwardRef(
|
|
|
227
341
|
Badge.displayName = "Badge";
|
|
228
342
|
|
|
229
343
|
// src/components/Separator.tsx
|
|
230
|
-
import * as
|
|
344
|
+
import * as React8 from "react";
|
|
231
345
|
import * as SeparatorPrimitive from "@radix-ui/react-separator";
|
|
232
346
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
233
|
-
var Separator =
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
"shrink-0 bg-border",
|
|
241
|
-
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
|
242
|
-
className
|
|
243
|
-
),
|
|
244
|
-
...props
|
|
347
|
+
var Separator = React8.forwardRef(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => {
|
|
348
|
+
if (process.env.NODE_ENV !== "production") {
|
|
349
|
+
if (!decorative && !props["aria-label"]) {
|
|
350
|
+
console.warn(
|
|
351
|
+
"Separator: Non-decorative separators (decorative={false}) should have an aria-label to describe the content they separate."
|
|
352
|
+
);
|
|
353
|
+
}
|
|
245
354
|
}
|
|
246
|
-
|
|
355
|
+
return /* @__PURE__ */ jsx7(
|
|
356
|
+
SeparatorPrimitive.Root,
|
|
357
|
+
{
|
|
358
|
+
ref,
|
|
359
|
+
decorative,
|
|
360
|
+
orientation,
|
|
361
|
+
className: cn(
|
|
362
|
+
"shrink-0 bg-border",
|
|
363
|
+
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
|
364
|
+
className
|
|
365
|
+
),
|
|
366
|
+
...props
|
|
367
|
+
}
|
|
368
|
+
);
|
|
369
|
+
});
|
|
247
370
|
Separator.displayName = SeparatorPrimitive.Root.displayName;
|
|
248
371
|
|
|
249
372
|
// src/components/Switch.tsx
|
|
250
|
-
import * as
|
|
373
|
+
import * as React9 from "react";
|
|
251
374
|
import * as SwitchPrimitives from "@radix-ui/react-switch";
|
|
252
375
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
253
376
|
var SwitchRoot = SwitchPrimitives.Root;
|
|
254
377
|
var SwitchThumb = SwitchPrimitives.Thumb;
|
|
255
|
-
var Switch =
|
|
256
|
-
({
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
className: cn(
|
|
271
|
-
"pointer-events-none block rounded-full bg-background shadow-lg ring-0 transition-transform",
|
|
272
|
-
size === "default" && "h-5 w-5 data-[state=checked]:translate-x-[22px] data-[state=unchecked]:translate-x-0.5",
|
|
273
|
-
size === "sm" && "h-4 w-4 data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
|
274
|
-
)
|
|
275
|
-
}
|
|
276
|
-
)
|
|
378
|
+
var Switch = React9.forwardRef(
|
|
379
|
+
({
|
|
380
|
+
className,
|
|
381
|
+
size = "default",
|
|
382
|
+
"aria-label": ariaLabel,
|
|
383
|
+
"aria-labelledby": ariaLabelledBy,
|
|
384
|
+
"aria-describedby": ariaDescribedBy,
|
|
385
|
+
...props
|
|
386
|
+
}, ref) => {
|
|
387
|
+
if (process.env.NODE_ENV !== "production") {
|
|
388
|
+
if (!ariaLabel && !ariaLabelledBy && !props.id) {
|
|
389
|
+
console.warn(
|
|
390
|
+
"Switch: Missing accessible label. Provide aria-label, aria-labelledby, or associate with a Label using id/htmlFor for WCAG compliance."
|
|
391
|
+
);
|
|
392
|
+
}
|
|
277
393
|
}
|
|
278
|
-
|
|
394
|
+
return /* @__PURE__ */ jsx8(
|
|
395
|
+
SwitchRoot,
|
|
396
|
+
{
|
|
397
|
+
className: cn(
|
|
398
|
+
"peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
|
399
|
+
size === "default" && "h-7 w-12",
|
|
400
|
+
size === "sm" && "h-5 w-9",
|
|
401
|
+
className
|
|
402
|
+
),
|
|
403
|
+
ref,
|
|
404
|
+
"aria-label": ariaLabel,
|
|
405
|
+
"aria-labelledby": ariaLabelledBy,
|
|
406
|
+
"aria-describedby": ariaDescribedBy,
|
|
407
|
+
...props,
|
|
408
|
+
children: /* @__PURE__ */ jsx8(
|
|
409
|
+
SwitchThumb,
|
|
410
|
+
{
|
|
411
|
+
className: cn(
|
|
412
|
+
"pointer-events-none block rounded-full bg-background shadow-lg ring-0 transition-transform",
|
|
413
|
+
size === "default" && "h-5 w-5 data-[state=checked]:translate-x-[22px] data-[state=unchecked]:translate-x-0.5",
|
|
414
|
+
size === "sm" && "h-4 w-4 data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
|
415
|
+
)
|
|
416
|
+
}
|
|
417
|
+
)
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
}
|
|
279
421
|
);
|
|
280
422
|
Switch.displayName = SwitchPrimitives.Root.displayName;
|
|
281
423
|
|
|
282
424
|
// src/components/Avatar.tsx
|
|
283
|
-
import * as
|
|
425
|
+
import * as React10 from "react";
|
|
284
426
|
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
|
285
427
|
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
286
|
-
var Avatar =
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
428
|
+
var Avatar = React10.forwardRef(
|
|
429
|
+
({ className, name, "aria-label": ariaLabel, ...props }, ref) => {
|
|
430
|
+
if (process.env.NODE_ENV !== "production") {
|
|
431
|
+
if (!ariaLabel && !name) {
|
|
432
|
+
console.warn(
|
|
433
|
+
'Avatar: Missing accessible text. Provide either a "name" prop or "aria-label" for screen reader users.'
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
const computedAriaLabel = ariaLabel ?? (name ? `Avatar for ${name}` : void 0);
|
|
438
|
+
return /* @__PURE__ */ jsx9(
|
|
439
|
+
AvatarPrimitive.Root,
|
|
440
|
+
{
|
|
441
|
+
ref,
|
|
442
|
+
"aria-label": computedAriaLabel,
|
|
443
|
+
className: cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className),
|
|
444
|
+
...props
|
|
445
|
+
}
|
|
446
|
+
);
|
|
292
447
|
}
|
|
293
|
-
)
|
|
448
|
+
);
|
|
294
449
|
Avatar.displayName = AvatarPrimitive.Root.displayName;
|
|
295
|
-
var AvatarImage =
|
|
450
|
+
var AvatarImage = React10.forwardRef(({ className, alt, ...props }, ref) => /* @__PURE__ */ jsx9(
|
|
296
451
|
AvatarPrimitive.Image,
|
|
297
452
|
{
|
|
298
453
|
ref,
|
|
454
|
+
alt,
|
|
299
455
|
className: cn("aspect-square h-full w-full object-cover", className),
|
|
300
456
|
...props
|
|
301
457
|
}
|
|
302
458
|
));
|
|
303
459
|
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
|
|
304
|
-
var AvatarFallback =
|
|
460
|
+
var AvatarFallback = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
|
|
305
461
|
AvatarPrimitive.Fallback,
|
|
306
462
|
{
|
|
307
463
|
ref,
|
|
@@ -315,9 +471,9 @@ var AvatarFallback = React9.forwardRef(({ className, ...props }, ref) => /* @__P
|
|
|
315
471
|
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
|
|
316
472
|
|
|
317
473
|
// src/components/Dialog.tsx
|
|
318
|
-
import * as
|
|
474
|
+
import * as React11 from "react";
|
|
319
475
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
320
|
-
import { jsx as jsx10, jsxs as
|
|
476
|
+
import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
321
477
|
var PrimitiveOverlay = DialogPrimitive.Overlay;
|
|
322
478
|
var PrimitiveContent = DialogPrimitive.Content;
|
|
323
479
|
var PrimitiveTitle = DialogPrimitive.Title;
|
|
@@ -326,7 +482,7 @@ var Dialog = DialogPrimitive.Root;
|
|
|
326
482
|
var DialogTrigger = DialogPrimitive.Trigger;
|
|
327
483
|
var DialogPortal = DialogPrimitive.Portal;
|
|
328
484
|
var DialogClose = DialogPrimitive.Close;
|
|
329
|
-
var DialogOverlay =
|
|
485
|
+
var DialogOverlay = React11.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx10(
|
|
330
486
|
PrimitiveOverlay,
|
|
331
487
|
{
|
|
332
488
|
ref,
|
|
@@ -338,7 +494,7 @@ var DialogOverlay = React10.forwardRef(({ className, ...props }, ref) => /* @__P
|
|
|
338
494
|
}
|
|
339
495
|
));
|
|
340
496
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
341
|
-
var DialogContent =
|
|
497
|
+
var DialogContent = React11.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs3(DialogPortal, { children: [
|
|
342
498
|
/* @__PURE__ */ jsx10(DialogOverlay, {}),
|
|
343
499
|
/* @__PURE__ */ jsx10(
|
|
344
500
|
PrimitiveContent,
|
|
@@ -364,7 +520,7 @@ var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx10(
|
|
|
364
520
|
}
|
|
365
521
|
);
|
|
366
522
|
DialogFooter.displayName = "DialogFooter";
|
|
367
|
-
var DialogTitle =
|
|
523
|
+
var DialogTitle = React11.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx10(
|
|
368
524
|
PrimitiveTitle,
|
|
369
525
|
{
|
|
370
526
|
ref,
|
|
@@ -373,7 +529,7 @@ var DialogTitle = React10.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
373
529
|
}
|
|
374
530
|
));
|
|
375
531
|
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
376
|
-
var DialogDescription =
|
|
532
|
+
var DialogDescription = React11.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx10(
|
|
377
533
|
PrimitiveDescription,
|
|
378
534
|
{
|
|
379
535
|
ref,
|
|
@@ -384,9 +540,9 @@ var DialogDescription = React10.forwardRef(({ className, ...props }, ref) => /*
|
|
|
384
540
|
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
385
541
|
|
|
386
542
|
// src/components/PageHeader.tsx
|
|
387
|
-
import * as
|
|
543
|
+
import * as React12 from "react";
|
|
388
544
|
import { cva as cva4 } from "class-variance-authority";
|
|
389
|
-
import { jsx as jsx11, jsxs as
|
|
545
|
+
import { jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
390
546
|
var pageHeaderContainerVariants = cva4("", {
|
|
391
547
|
variants: {
|
|
392
548
|
variant: {
|
|
@@ -435,25 +591,34 @@ var pageHeaderActionsVariants = cva4("flex gap-4", {
|
|
|
435
591
|
variant: "default"
|
|
436
592
|
}
|
|
437
593
|
});
|
|
438
|
-
var PageHeader =
|
|
439
|
-
({ className, variant, title, subtitle, actions, ...props }, ref) =>
|
|
440
|
-
"
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
/* @__PURE__ */ jsx11("h1", { className: pageHeaderTitleVariants({ variant }), children: title }),
|
|
447
|
-
subtitle && /* @__PURE__ */ jsx11("p", { className: pageHeaderSubtitleVariants({ variant }), children: subtitle }),
|
|
448
|
-
actions && /* @__PURE__ */ jsx11("div", { className: pageHeaderActionsVariants({ variant }), children: actions })
|
|
449
|
-
]
|
|
594
|
+
var PageHeader = React12.forwardRef(
|
|
595
|
+
({ className, variant, title, subtitle, actions, as: Heading = "h1", ...props }, ref) => {
|
|
596
|
+
if (process.env.NODE_ENV !== "production") {
|
|
597
|
+
if (Heading === "h1") {
|
|
598
|
+
console.warn(
|
|
599
|
+
'PageHeader: Using as="h1" (the default). Ensure there is only one h1 per page for proper document structure. Consider as="h2" for secondary headers.'
|
|
600
|
+
);
|
|
601
|
+
}
|
|
450
602
|
}
|
|
451
|
-
|
|
603
|
+
return /* @__PURE__ */ jsxs4(
|
|
604
|
+
"header",
|
|
605
|
+
{
|
|
606
|
+
ref,
|
|
607
|
+
className: cn(pageHeaderContainerVariants({ variant }), className),
|
|
608
|
+
...props,
|
|
609
|
+
children: [
|
|
610
|
+
/* @__PURE__ */ jsx11(Heading, { className: pageHeaderTitleVariants({ variant }), children: title }),
|
|
611
|
+
subtitle && /* @__PURE__ */ jsx11("p", { className: pageHeaderSubtitleVariants({ variant }), children: subtitle }),
|
|
612
|
+
actions && /* @__PURE__ */ jsx11("div", { className: pageHeaderActionsVariants({ variant }), children: actions })
|
|
613
|
+
]
|
|
614
|
+
}
|
|
615
|
+
);
|
|
616
|
+
}
|
|
452
617
|
);
|
|
453
618
|
PageHeader.displayName = "PageHeader";
|
|
454
619
|
|
|
455
620
|
// src/components/DataPanel.tsx
|
|
456
|
-
import * as
|
|
621
|
+
import * as React13 from "react";
|
|
457
622
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
458
623
|
import {
|
|
459
624
|
DEFAULT_PANEL_STATE,
|
|
@@ -479,7 +644,7 @@ import {
|
|
|
479
644
|
calculateDetachedPositionFromPinned,
|
|
480
645
|
getPinnedPullTransform
|
|
481
646
|
} from "@classic-homes/data-panel-core";
|
|
482
|
-
import { Fragment, jsx as jsx12, jsxs as
|
|
647
|
+
import { Fragment, jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
483
648
|
var DropdownTrigger = DropdownMenuPrimitive.Trigger;
|
|
484
649
|
var DropdownContent = DropdownMenuPrimitive.Content;
|
|
485
650
|
var DropdownLabel = DropdownMenuPrimitive.Label;
|
|
@@ -494,28 +659,28 @@ function useDataPanel(options = {}) {
|
|
|
494
659
|
constraints = {}
|
|
495
660
|
} = options;
|
|
496
661
|
const resolvedConstraints = { ...DEFAULT_CONSTRAINTS, ...constraints };
|
|
497
|
-
const [persistedState] =
|
|
662
|
+
const [persistedState] = React13.useState(() => {
|
|
498
663
|
if (persistKey && typeof window !== "undefined") {
|
|
499
664
|
return loadPanelState(persistKey);
|
|
500
665
|
}
|
|
501
666
|
return null;
|
|
502
667
|
});
|
|
503
|
-
const [mode, setMode] =
|
|
504
|
-
const [edge, setEdge] =
|
|
505
|
-
const [isExpanded, setIsExpanded] =
|
|
668
|
+
const [mode, setMode] = React13.useState(persistedState?.mode ?? initialMode);
|
|
669
|
+
const [edge, setEdge] = React13.useState(persistedState?.edge ?? initialEdge);
|
|
670
|
+
const [isExpanded, setIsExpanded] = React13.useState(
|
|
506
671
|
persistedState?.isExpanded ?? initialExpanded
|
|
507
672
|
);
|
|
508
|
-
const [detachedPosition, setDetachedPosition] =
|
|
673
|
+
const [detachedPosition, setDetachedPosition] = React13.useState(
|
|
509
674
|
persistedState?.detachedPosition ?? DEFAULT_PANEL_STATE.detachedPosition
|
|
510
675
|
);
|
|
511
|
-
const [detachedSize, setDetachedSize] =
|
|
676
|
+
const [detachedSize, setDetachedSize] = React13.useState(
|
|
512
677
|
persistedState?.detachedSize ?? DEFAULT_PANEL_STATE.detachedSize
|
|
513
678
|
);
|
|
514
|
-
const [pinnedSize, setPinnedSize] =
|
|
679
|
+
const [pinnedSize, setPinnedSize] = React13.useState(
|
|
515
680
|
persistedState?.pinnedSize ?? DEFAULT_PANEL_STATE.pinnedSize
|
|
516
681
|
);
|
|
517
|
-
const saveTimeoutRef =
|
|
518
|
-
const debouncedSave =
|
|
682
|
+
const saveTimeoutRef = React13.useRef(null);
|
|
683
|
+
const debouncedSave = React13.useCallback(() => {
|
|
519
684
|
if (!persistKey) return;
|
|
520
685
|
if (saveTimeoutRef.current) {
|
|
521
686
|
clearTimeout(saveTimeoutRef.current);
|
|
@@ -533,7 +698,7 @@ function useDataPanel(options = {}) {
|
|
|
533
698
|
});
|
|
534
699
|
}, 300);
|
|
535
700
|
}, [persistKey, mode, edge, isExpanded, detachedPosition, detachedSize, pinnedSize]);
|
|
536
|
-
const handleSetMode =
|
|
701
|
+
const handleSetMode = React13.useCallback(
|
|
537
702
|
(newMode) => {
|
|
538
703
|
setMode(newMode);
|
|
539
704
|
if (newMode === "detached" && typeof window !== "undefined" && detachedPosition.x === DEFAULT_PANEL_STATE.detachedPosition.x && detachedPosition.y === DEFAULT_PANEL_STATE.detachedPosition.y) {
|
|
@@ -544,7 +709,7 @@ function useDataPanel(options = {}) {
|
|
|
544
709
|
},
|
|
545
710
|
[detachedPosition, detachedSize]
|
|
546
711
|
);
|
|
547
|
-
const handleSetDetachedPosition =
|
|
712
|
+
const handleSetDetachedPosition = React13.useCallback(
|
|
548
713
|
(position) => {
|
|
549
714
|
if (typeof window === "undefined") {
|
|
550
715
|
setDetachedPosition(position);
|
|
@@ -556,13 +721,13 @@ function useDataPanel(options = {}) {
|
|
|
556
721
|
},
|
|
557
722
|
[detachedSize]
|
|
558
723
|
);
|
|
559
|
-
const handleSetDetachedSize =
|
|
724
|
+
const handleSetDetachedSize = React13.useCallback(
|
|
560
725
|
(size) => {
|
|
561
726
|
setDetachedSize(constrainSize(size, resolvedConstraints));
|
|
562
727
|
},
|
|
563
728
|
[resolvedConstraints]
|
|
564
729
|
);
|
|
565
|
-
const handleSetPinnedSize =
|
|
730
|
+
const handleSetPinnedSize = React13.useCallback(
|
|
566
731
|
(size) => {
|
|
567
732
|
if (typeof window === "undefined") {
|
|
568
733
|
setPinnedSize(size);
|
|
@@ -576,7 +741,7 @@ function useDataPanel(options = {}) {
|
|
|
576
741
|
},
|
|
577
742
|
[edge, resolvedConstraints]
|
|
578
743
|
);
|
|
579
|
-
|
|
744
|
+
React13.useEffect(() => {
|
|
580
745
|
debouncedSave();
|
|
581
746
|
}, [debouncedSave]);
|
|
582
747
|
return {
|
|
@@ -609,7 +774,7 @@ var ChevronUpIcon = () => /* @__PURE__ */ jsx12(
|
|
|
609
774
|
children: /* @__PURE__ */ jsx12("path", { d: "m18 15-6-6-6 6" })
|
|
610
775
|
}
|
|
611
776
|
);
|
|
612
|
-
var MoreVerticalIcon = () => /* @__PURE__ */
|
|
777
|
+
var MoreVerticalIcon = () => /* @__PURE__ */ jsxs5(
|
|
613
778
|
"svg",
|
|
614
779
|
{
|
|
615
780
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -628,7 +793,7 @@ var MoreVerticalIcon = () => /* @__PURE__ */ jsxs4(
|
|
|
628
793
|
]
|
|
629
794
|
}
|
|
630
795
|
);
|
|
631
|
-
var CloseIcon = () => /* @__PURE__ */
|
|
796
|
+
var CloseIcon = () => /* @__PURE__ */ jsxs5(
|
|
632
797
|
"svg",
|
|
633
798
|
{
|
|
634
799
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -652,10 +817,11 @@ var edgeLabels = {
|
|
|
652
817
|
top: "Pin to top",
|
|
653
818
|
bottom: "Pin to bottom"
|
|
654
819
|
};
|
|
655
|
-
var DataPanelHeader =
|
|
820
|
+
var DataPanelHeader = React13.forwardRef(
|
|
656
821
|
({
|
|
657
822
|
title,
|
|
658
823
|
subtitle,
|
|
824
|
+
titleId,
|
|
659
825
|
mode,
|
|
660
826
|
edge,
|
|
661
827
|
isExpanded,
|
|
@@ -670,7 +836,7 @@ var DataPanelHeader = React12.forwardRef(
|
|
|
670
836
|
className,
|
|
671
837
|
draggable = false
|
|
672
838
|
}, ref) => {
|
|
673
|
-
return /* @__PURE__ */
|
|
839
|
+
return /* @__PURE__ */ jsxs5(
|
|
674
840
|
"div",
|
|
675
841
|
{
|
|
676
842
|
ref,
|
|
@@ -681,11 +847,11 @@ var DataPanelHeader = React12.forwardRef(
|
|
|
681
847
|
),
|
|
682
848
|
"data-panel-header": true,
|
|
683
849
|
children: [
|
|
684
|
-
/* @__PURE__ */ jsx12("div", { className: "flex flex-col min-w-0 flex-1", children: headerContent ? headerContent : /* @__PURE__ */
|
|
685
|
-
title && /* @__PURE__ */ jsx12("h3", { className: "text-sm font-semibold leading-none truncate", children: title }),
|
|
850
|
+
/* @__PURE__ */ jsx12("div", { className: "flex flex-col min-w-0 flex-1", children: headerContent ? headerContent : /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
851
|
+
title && /* @__PURE__ */ jsx12("h3", { id: titleId, className: "text-sm font-semibold leading-none truncate", children: title }),
|
|
686
852
|
subtitle && /* @__PURE__ */ jsx12("p", { className: "text-xs text-muted-foreground mt-1 truncate", children: subtitle })
|
|
687
853
|
] }) }),
|
|
688
|
-
/* @__PURE__ */
|
|
854
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1 shrink-0", children: [
|
|
689
855
|
headerActions,
|
|
690
856
|
/* @__PURE__ */ jsx12(
|
|
691
857
|
"button",
|
|
@@ -698,7 +864,7 @@ var DataPanelHeader = React12.forwardRef(
|
|
|
698
864
|
children: /* @__PURE__ */ jsx12("span", { className: cn("transition-transform", !isExpanded && "rotate-180"), children: /* @__PURE__ */ jsx12(ChevronUpIcon, {}) })
|
|
699
865
|
}
|
|
700
866
|
),
|
|
701
|
-
!disableModeSwitch && /* @__PURE__ */
|
|
867
|
+
!disableModeSwitch && /* @__PURE__ */ jsxs5(DropdownMenuPrimitive.Root, { children: [
|
|
702
868
|
/* @__PURE__ */ jsx12(DropdownTrigger, { asChild: true, children: /* @__PURE__ */ jsx12(
|
|
703
869
|
"button",
|
|
704
870
|
{
|
|
@@ -708,7 +874,7 @@ var DataPanelHeader = React12.forwardRef(
|
|
|
708
874
|
children: /* @__PURE__ */ jsx12(MoreVerticalIcon, {})
|
|
709
875
|
}
|
|
710
876
|
) }),
|
|
711
|
-
/* @__PURE__ */ jsx12(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */
|
|
877
|
+
/* @__PURE__ */ jsx12(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsxs5(
|
|
712
878
|
DropdownContent,
|
|
713
879
|
{
|
|
714
880
|
className: "z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95",
|
|
@@ -716,7 +882,7 @@ var DataPanelHeader = React12.forwardRef(
|
|
|
716
882
|
align: "end",
|
|
717
883
|
children: [
|
|
718
884
|
/* @__PURE__ */ jsx12(DropdownLabel, { className: "px-2 py-1.5 text-sm font-semibold", children: "Panel Position" }),
|
|
719
|
-
["left", "right", "top", "bottom"].map((e) => /* @__PURE__ */
|
|
885
|
+
["left", "right", "top", "bottom"].map((e) => /* @__PURE__ */ jsxs5(
|
|
720
886
|
DropdownItem,
|
|
721
887
|
{
|
|
722
888
|
className: "relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
@@ -732,7 +898,7 @@ var DataPanelHeader = React12.forwardRef(
|
|
|
732
898
|
e
|
|
733
899
|
)),
|
|
734
900
|
/* @__PURE__ */ jsx12(DropdownSeparator, { className: "-mx-1 my-1 h-px bg-muted" }),
|
|
735
|
-
/* @__PURE__ */
|
|
901
|
+
/* @__PURE__ */ jsxs5(
|
|
736
902
|
DropdownItem,
|
|
737
903
|
{
|
|
738
904
|
className: "relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground",
|
|
@@ -764,13 +930,22 @@ var DataPanelHeader = React12.forwardRef(
|
|
|
764
930
|
}
|
|
765
931
|
);
|
|
766
932
|
DataPanelHeader.displayName = "DataPanelHeader";
|
|
767
|
-
var DataPanelContent =
|
|
768
|
-
({ children, className }, ref) => {
|
|
769
|
-
return /* @__PURE__ */ jsx12(
|
|
933
|
+
var DataPanelContent = React13.forwardRef(
|
|
934
|
+
({ children, className, "aria-label": ariaLabel = "Panel content" }, ref) => {
|
|
935
|
+
return /* @__PURE__ */ jsx12(
|
|
936
|
+
"div",
|
|
937
|
+
{
|
|
938
|
+
ref,
|
|
939
|
+
role: "region",
|
|
940
|
+
"aria-label": ariaLabel,
|
|
941
|
+
className: cn("flex-1 overflow-auto p-4", className),
|
|
942
|
+
children
|
|
943
|
+
}
|
|
944
|
+
);
|
|
770
945
|
}
|
|
771
946
|
);
|
|
772
947
|
DataPanelContent.displayName = "DataPanelContent";
|
|
773
|
-
var DataPanelFooter =
|
|
948
|
+
var DataPanelFooter = React13.forwardRef(
|
|
774
949
|
({ actions = [], footerContent, footerActions, className }, ref) => {
|
|
775
950
|
if (!footerContent && actions.length === 0 && !footerActions) {
|
|
776
951
|
return null;
|
|
@@ -787,7 +962,7 @@ var DataPanelFooter = React12.forwardRef(
|
|
|
787
962
|
"flex items-center justify-end gap-2 border-t border-border bg-muted/30 px-4 py-3",
|
|
788
963
|
className
|
|
789
964
|
),
|
|
790
|
-
children: footerContent ? footerContent : /* @__PURE__ */
|
|
965
|
+
children: footerContent ? footerContent : /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
791
966
|
footerActions,
|
|
792
967
|
actions.map((action, index) => /* @__PURE__ */ jsx12(
|
|
793
968
|
Button,
|
|
@@ -806,7 +981,7 @@ var DataPanelFooter = React12.forwardRef(
|
|
|
806
981
|
}
|
|
807
982
|
);
|
|
808
983
|
DataPanelFooter.displayName = "DataPanelFooter";
|
|
809
|
-
var DataPanelTab =
|
|
984
|
+
var DataPanelTab = React13.forwardRef(
|
|
810
985
|
({ title = "Panel", edge, onClick, className }, ref) => {
|
|
811
986
|
const positionClasses = {
|
|
812
987
|
left: "left-0 top-1/2 -translate-y-1/2 rounded-r-md border-l-0",
|
|
@@ -821,7 +996,7 @@ var DataPanelTab = React12.forwardRef(
|
|
|
821
996
|
top: "rotate-180",
|
|
822
997
|
bottom: ""
|
|
823
998
|
}[edge];
|
|
824
|
-
return /* @__PURE__ */
|
|
999
|
+
return /* @__PURE__ */ jsxs5(
|
|
825
1000
|
"button",
|
|
826
1001
|
{
|
|
827
1002
|
ref,
|
|
@@ -843,7 +1018,186 @@ var DataPanelTab = React12.forwardRef(
|
|
|
843
1018
|
}
|
|
844
1019
|
);
|
|
845
1020
|
DataPanelTab.displayName = "DataPanelTab";
|
|
846
|
-
var
|
|
1021
|
+
var KEYBOARD_RESIZE_STEP = 10;
|
|
1022
|
+
var KEYBOARD_RESIZE_STEP_LARGE = 50;
|
|
1023
|
+
function ResizeHandles({
|
|
1024
|
+
mode,
|
|
1025
|
+
edge,
|
|
1026
|
+
detachedSize,
|
|
1027
|
+
pinnedSize,
|
|
1028
|
+
onResizeStart,
|
|
1029
|
+
onSizeChange,
|
|
1030
|
+
onPinnedSizeChange,
|
|
1031
|
+
constraints
|
|
1032
|
+
}) {
|
|
1033
|
+
const handleDetachedKeyDown = React13.useCallback(
|
|
1034
|
+
(e, handle) => {
|
|
1035
|
+
const step = e.shiftKey ? KEYBOARD_RESIZE_STEP_LARGE : KEYBOARD_RESIZE_STEP;
|
|
1036
|
+
let newSize = { ...detachedSize };
|
|
1037
|
+
let handled = false;
|
|
1038
|
+
switch (e.key) {
|
|
1039
|
+
case "ArrowUp":
|
|
1040
|
+
if (handle.includes("top")) {
|
|
1041
|
+
newSize.height = Math.max(constraints.minHeight || 200, detachedSize.height + step);
|
|
1042
|
+
handled = true;
|
|
1043
|
+
} else if (handle.includes("bottom")) {
|
|
1044
|
+
newSize.height = Math.max(constraints.minHeight || 200, detachedSize.height - step);
|
|
1045
|
+
handled = true;
|
|
1046
|
+
}
|
|
1047
|
+
break;
|
|
1048
|
+
case "ArrowDown":
|
|
1049
|
+
if (handle.includes("top")) {
|
|
1050
|
+
newSize.height = Math.max(constraints.minHeight || 200, detachedSize.height - step);
|
|
1051
|
+
handled = true;
|
|
1052
|
+
} else if (handle.includes("bottom")) {
|
|
1053
|
+
newSize.height = Math.min(constraints.maxHeight || 800, detachedSize.height + step);
|
|
1054
|
+
handled = true;
|
|
1055
|
+
}
|
|
1056
|
+
break;
|
|
1057
|
+
case "ArrowLeft":
|
|
1058
|
+
if (handle.includes("left")) {
|
|
1059
|
+
newSize.width = Math.max(constraints.minWidth || 280, detachedSize.width + step);
|
|
1060
|
+
handled = true;
|
|
1061
|
+
} else if (handle.includes("right")) {
|
|
1062
|
+
newSize.width = Math.max(constraints.minWidth || 280, detachedSize.width - step);
|
|
1063
|
+
handled = true;
|
|
1064
|
+
}
|
|
1065
|
+
break;
|
|
1066
|
+
case "ArrowRight":
|
|
1067
|
+
if (handle.includes("left")) {
|
|
1068
|
+
newSize.width = Math.max(constraints.minWidth || 280, detachedSize.width - step);
|
|
1069
|
+
handled = true;
|
|
1070
|
+
} else if (handle.includes("right")) {
|
|
1071
|
+
newSize.width = Math.min(constraints.maxWidth || 600, detachedSize.width + step);
|
|
1072
|
+
handled = true;
|
|
1073
|
+
}
|
|
1074
|
+
break;
|
|
1075
|
+
}
|
|
1076
|
+
if (handled) {
|
|
1077
|
+
e.preventDefault();
|
|
1078
|
+
onSizeChange(newSize);
|
|
1079
|
+
}
|
|
1080
|
+
},
|
|
1081
|
+
[detachedSize, constraints, onSizeChange]
|
|
1082
|
+
);
|
|
1083
|
+
const handlePinnedKeyDown = React13.useCallback(
|
|
1084
|
+
(e) => {
|
|
1085
|
+
const step = e.shiftKey ? KEYBOARD_RESIZE_STEP_LARGE : KEYBOARD_RESIZE_STEP;
|
|
1086
|
+
let newSize = pinnedSize;
|
|
1087
|
+
let handled = false;
|
|
1088
|
+
const isHorizontal2 = edge === "left" || edge === "right";
|
|
1089
|
+
if (isHorizontal2) {
|
|
1090
|
+
if (e.key === "ArrowLeft" && edge === "right" || e.key === "ArrowRight" && edge === "left") {
|
|
1091
|
+
newSize = Math.min(constraints.maxWidth || 600, pinnedSize + step);
|
|
1092
|
+
handled = true;
|
|
1093
|
+
} else if (e.key === "ArrowRight" && edge === "right" || e.key === "ArrowLeft" && edge === "left") {
|
|
1094
|
+
newSize = Math.max(constraints.minWidth || 280, pinnedSize - step);
|
|
1095
|
+
handled = true;
|
|
1096
|
+
}
|
|
1097
|
+
} else {
|
|
1098
|
+
if (e.key === "ArrowUp" && edge === "bottom" || e.key === "ArrowDown" && edge === "top") {
|
|
1099
|
+
newSize = Math.min(constraints.maxHeight || 800, pinnedSize + step);
|
|
1100
|
+
handled = true;
|
|
1101
|
+
} else if (e.key === "ArrowDown" && edge === "bottom" || e.key === "ArrowUp" && edge === "top") {
|
|
1102
|
+
newSize = Math.max(constraints.minHeight || 200, pinnedSize - step);
|
|
1103
|
+
handled = true;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
if (handled) {
|
|
1107
|
+
e.preventDefault();
|
|
1108
|
+
onPinnedSizeChange(newSize);
|
|
1109
|
+
}
|
|
1110
|
+
},
|
|
1111
|
+
[edge, pinnedSize, constraints, onPinnedSizeChange]
|
|
1112
|
+
);
|
|
1113
|
+
const getAriaValueNow = (handle) => {
|
|
1114
|
+
if (handle.includes("left") || handle.includes("right")) {
|
|
1115
|
+
return mode === "detached" ? detachedSize.width : pinnedSize;
|
|
1116
|
+
}
|
|
1117
|
+
return mode === "detached" ? detachedSize.height : pinnedSize;
|
|
1118
|
+
};
|
|
1119
|
+
const getAriaValueMinMax = (handle) => {
|
|
1120
|
+
const isWidth = handle.includes("left") || handle.includes("right");
|
|
1121
|
+
if (isWidth) {
|
|
1122
|
+
return {
|
|
1123
|
+
min: constraints.minWidth || 280,
|
|
1124
|
+
max: constraints.maxWidth || 600
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
return {
|
|
1128
|
+
min: constraints.minHeight || 200,
|
|
1129
|
+
max: constraints.maxHeight || 800
|
|
1130
|
+
};
|
|
1131
|
+
};
|
|
1132
|
+
if (mode === "detached") {
|
|
1133
|
+
const handles = [
|
|
1134
|
+
"top",
|
|
1135
|
+
"bottom",
|
|
1136
|
+
"left",
|
|
1137
|
+
"right",
|
|
1138
|
+
"top-left",
|
|
1139
|
+
"top-right",
|
|
1140
|
+
"bottom-left",
|
|
1141
|
+
"bottom-right"
|
|
1142
|
+
];
|
|
1143
|
+
return /* @__PURE__ */ jsx12(Fragment, { children: handles.map((handle) => {
|
|
1144
|
+
const isCorner = handle.includes("-");
|
|
1145
|
+
const isHorizontal2 = handle === "top" || handle === "bottom";
|
|
1146
|
+
const isVertical = handle === "left" || handle === "right";
|
|
1147
|
+
const { min: min2, max: max2 } = getAriaValueMinMax(handle);
|
|
1148
|
+
return /* @__PURE__ */ jsx12(
|
|
1149
|
+
"div",
|
|
1150
|
+
{
|
|
1151
|
+
className: cn(
|
|
1152
|
+
"resize-handle",
|
|
1153
|
+
isHorizontal2 && "resize-handle--horizontal",
|
|
1154
|
+
isVertical && "resize-handle--vertical",
|
|
1155
|
+
isCorner && "resize-handle--corner",
|
|
1156
|
+
`resize-handle--${handle}`
|
|
1157
|
+
),
|
|
1158
|
+
role: "slider",
|
|
1159
|
+
tabIndex: 0,
|
|
1160
|
+
"aria-orientation": isVertical ? "vertical" : "horizontal",
|
|
1161
|
+
"aria-label": `Resize panel from ${handle.replace("-", " ")} ${isCorner ? "corner" : "edge"}`,
|
|
1162
|
+
"aria-valuenow": getAriaValueNow(handle),
|
|
1163
|
+
"aria-valuemin": min2,
|
|
1164
|
+
"aria-valuemax": max2,
|
|
1165
|
+
"aria-valuetext": `${getAriaValueNow(handle)} pixels`,
|
|
1166
|
+
style: isCorner ? { "--handle-radius": "6px" } : void 0,
|
|
1167
|
+
onPointerDown: (e) => onResizeStart(e, handle),
|
|
1168
|
+
onKeyDown: (e) => handleDetachedKeyDown(e, handle)
|
|
1169
|
+
},
|
|
1170
|
+
handle
|
|
1171
|
+
);
|
|
1172
|
+
}) });
|
|
1173
|
+
}
|
|
1174
|
+
const pinnedHandle = getPinnedResizeHandle(edge);
|
|
1175
|
+
const isHorizontal = edge === "left" || edge === "right";
|
|
1176
|
+
const { min, max } = getAriaValueMinMax(pinnedHandle);
|
|
1177
|
+
return /* @__PURE__ */ jsx12(
|
|
1178
|
+
"div",
|
|
1179
|
+
{
|
|
1180
|
+
className: cn(
|
|
1181
|
+
"resize-handle",
|
|
1182
|
+
edge === "left" && "resize-handle--vertical resize-handle--right",
|
|
1183
|
+
edge === "right" && "resize-handle--vertical resize-handle--left",
|
|
1184
|
+
edge === "top" && "resize-handle--horizontal resize-handle--bottom",
|
|
1185
|
+
edge === "bottom" && "resize-handle--horizontal resize-handle--top"
|
|
1186
|
+
),
|
|
1187
|
+
role: "slider",
|
|
1188
|
+
tabIndex: 0,
|
|
1189
|
+
"aria-orientation": isHorizontal ? "horizontal" : "vertical",
|
|
1190
|
+
"aria-label": `Resize panel from ${edge} edge`,
|
|
1191
|
+
"aria-valuenow": pinnedSize,
|
|
1192
|
+
"aria-valuemin": min,
|
|
1193
|
+
"aria-valuemax": max,
|
|
1194
|
+
"aria-valuetext": `${pinnedSize} pixels`,
|
|
1195
|
+
onPointerDown: (e) => onResizeStart(e, pinnedHandle),
|
|
1196
|
+
onKeyDown: handlePinnedKeyDown
|
|
1197
|
+
}
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
1200
|
+
var DataPanel = React13.forwardRef(
|
|
847
1201
|
({
|
|
848
1202
|
open: controlledOpen,
|
|
849
1203
|
onOpenChange,
|
|
@@ -872,31 +1226,33 @@ var DataPanel = React12.forwardRef(
|
|
|
872
1226
|
className
|
|
873
1227
|
}, ref) => {
|
|
874
1228
|
const resolvedConstraints = { ...DEFAULT_CONSTRAINTS, ...constraints };
|
|
875
|
-
const
|
|
876
|
-
const
|
|
877
|
-
const [
|
|
878
|
-
const [
|
|
1229
|
+
const panelId = React13.useId();
|
|
1230
|
+
const titleId = `${panelId}-title`;
|
|
1231
|
+
const [internalOpen, setInternalOpen] = React13.useState(true);
|
|
1232
|
+
const [internalMode, setInternalMode] = React13.useState(DEFAULT_PANEL_STATE.mode);
|
|
1233
|
+
const [internalEdge, setInternalEdge] = React13.useState(DEFAULT_PANEL_STATE.edge);
|
|
1234
|
+
const [internalExpanded, setInternalExpanded] = React13.useState(
|
|
879
1235
|
DEFAULT_PANEL_STATE.isExpanded
|
|
880
1236
|
);
|
|
881
|
-
const [detachedPosition, setDetachedPosition] =
|
|
1237
|
+
const [detachedPosition, setDetachedPosition] = React13.useState(
|
|
882
1238
|
DEFAULT_PANEL_STATE.detachedPosition
|
|
883
1239
|
);
|
|
884
|
-
const [detachedSize, setDetachedSize] =
|
|
885
|
-
const [pinnedSize, setPinnedSize] =
|
|
886
|
-
const [isDragging, setIsDragging] =
|
|
887
|
-
const [isResizing, setIsResizing] =
|
|
888
|
-
const [snapPreview, setSnapPreview] =
|
|
889
|
-
const [isPinnedDragging, setIsPinnedDragging] =
|
|
890
|
-
const [pullOffset, setPullOffset] =
|
|
891
|
-
const dragStateRef =
|
|
1240
|
+
const [detachedSize, setDetachedSize] = React13.useState(DEFAULT_PANEL_STATE.detachedSize);
|
|
1241
|
+
const [pinnedSize, setPinnedSize] = React13.useState(DEFAULT_PANEL_STATE.pinnedSize);
|
|
1242
|
+
const [isDragging, setIsDragging] = React13.useState(false);
|
|
1243
|
+
const [isResizing, setIsResizing] = React13.useState(false);
|
|
1244
|
+
const [snapPreview, setSnapPreview] = React13.useState(null);
|
|
1245
|
+
const [isPinnedDragging, setIsPinnedDragging] = React13.useState(false);
|
|
1246
|
+
const [pullOffset, setPullOffset] = React13.useState(0);
|
|
1247
|
+
const dragStateRef = React13.useRef({
|
|
892
1248
|
startPosition: { x: 0, y: 0 },
|
|
893
1249
|
startPanelPosition: { x: 0, y: 0 }
|
|
894
1250
|
});
|
|
895
|
-
const pinnedDragStateRef =
|
|
1251
|
+
const pinnedDragStateRef = React13.useRef({
|
|
896
1252
|
startPosition: { x: 0, y: 0 },
|
|
897
1253
|
hasDetached: false
|
|
898
1254
|
});
|
|
899
|
-
const resizeStateRef =
|
|
1255
|
+
const resizeStateRef = React13.useRef({
|
|
900
1256
|
handle: null,
|
|
901
1257
|
startPosition: { x: 0, y: 0 },
|
|
902
1258
|
startSize: { width: 0, height: 0 },
|
|
@@ -906,8 +1262,8 @@ var DataPanel = React12.forwardRef(
|
|
|
906
1262
|
const mode = controlledMode ?? internalMode;
|
|
907
1263
|
const edge = controlledEdge ?? internalEdge;
|
|
908
1264
|
const isExpanded = controlledExpanded ?? internalExpanded;
|
|
909
|
-
const saveTimeoutRef =
|
|
910
|
-
const debouncedSave =
|
|
1265
|
+
const saveTimeoutRef = React13.useRef(null);
|
|
1266
|
+
const debouncedSave = React13.useCallback(() => {
|
|
911
1267
|
if (!persistKey) return;
|
|
912
1268
|
if (saveTimeoutRef.current) {
|
|
913
1269
|
clearTimeout(saveTimeoutRef.current);
|
|
@@ -933,7 +1289,7 @@ var DataPanel = React12.forwardRef(
|
|
|
933
1289
|
detachedSize,
|
|
934
1290
|
pinnedSize
|
|
935
1291
|
]);
|
|
936
|
-
|
|
1292
|
+
React13.useEffect(() => {
|
|
937
1293
|
if (!persistKey) return;
|
|
938
1294
|
const persisted = loadPanelState(persistKey);
|
|
939
1295
|
if (persisted) {
|
|
@@ -946,7 +1302,7 @@ var DataPanel = React12.forwardRef(
|
|
|
946
1302
|
if (persisted.pinnedSize) setPinnedSize(persisted.pinnedSize);
|
|
947
1303
|
}
|
|
948
1304
|
}, [persistKey, controlledMode, controlledEdge, controlledExpanded]);
|
|
949
|
-
|
|
1305
|
+
React13.useEffect(() => {
|
|
950
1306
|
if (mode === "detached" && detachedPosition.x === DEFAULT_PANEL_STATE.detachedPosition.x && detachedPosition.y === DEFAULT_PANEL_STATE.detachedPosition.y) {
|
|
951
1307
|
setDetachedPosition(
|
|
952
1308
|
getInitialDetachedPosition(detachedSize, window.innerWidth, window.innerHeight)
|
|
@@ -1004,7 +1360,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1004
1360
|
document.body.style.userSelect = "none";
|
|
1005
1361
|
}
|
|
1006
1362
|
};
|
|
1007
|
-
const handleDragMove =
|
|
1363
|
+
const handleDragMove = React13.useCallback(
|
|
1008
1364
|
(e) => {
|
|
1009
1365
|
if (!isDragging) return;
|
|
1010
1366
|
const currentPos = getPointerPosition(e);
|
|
@@ -1031,7 +1387,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1031
1387
|
},
|
|
1032
1388
|
[isDragging, detachedSize, snapThreshold]
|
|
1033
1389
|
);
|
|
1034
|
-
const handleDragEnd =
|
|
1390
|
+
const handleDragEnd = React13.useCallback(() => {
|
|
1035
1391
|
if (!isDragging) return;
|
|
1036
1392
|
setIsDragging(false);
|
|
1037
1393
|
document.body.style.cursor = "";
|
|
@@ -1044,7 +1400,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1044
1400
|
debouncedSave();
|
|
1045
1401
|
}
|
|
1046
1402
|
}, [isDragging, snapPreview, handleModeChange, handleEdgeChange, debouncedSave]);
|
|
1047
|
-
const handlePinnedDragMove =
|
|
1403
|
+
const handlePinnedDragMove = React13.useCallback(
|
|
1048
1404
|
(e) => {
|
|
1049
1405
|
if (!isPinnedDragging) return;
|
|
1050
1406
|
const currentPos = getPointerPosition(e);
|
|
@@ -1080,7 +1436,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1080
1436
|
},
|
|
1081
1437
|
[isPinnedDragging, edge, detachThreshold, pinnedSize, detachedSize, handleModeChange]
|
|
1082
1438
|
);
|
|
1083
|
-
const handlePinnedDragEnd =
|
|
1439
|
+
const handlePinnedDragEnd = React13.useCallback(() => {
|
|
1084
1440
|
if (!isPinnedDragging) return;
|
|
1085
1441
|
setIsPinnedDragging(false);
|
|
1086
1442
|
setPullOffset(0);
|
|
@@ -1102,7 +1458,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1102
1458
|
document.body.style.cursor = getResizeCursor(handle);
|
|
1103
1459
|
document.body.style.userSelect = "none";
|
|
1104
1460
|
};
|
|
1105
|
-
const handleResizeMove =
|
|
1461
|
+
const handleResizeMove = React13.useCallback(
|
|
1106
1462
|
(e) => {
|
|
1107
1463
|
if (!isResizing || !resizeStateRef.current.handle) return;
|
|
1108
1464
|
const currentPos = getPointerPosition(e);
|
|
@@ -1140,7 +1496,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1140
1496
|
},
|
|
1141
1497
|
[isResizing, mode, edge, resolvedConstraints]
|
|
1142
1498
|
);
|
|
1143
|
-
const handleResizeEnd =
|
|
1499
|
+
const handleResizeEnd = React13.useCallback(() => {
|
|
1144
1500
|
if (!isResizing) return;
|
|
1145
1501
|
setIsResizing(false);
|
|
1146
1502
|
resizeStateRef.current.handle = null;
|
|
@@ -1148,7 +1504,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1148
1504
|
document.body.style.userSelect = "";
|
|
1149
1505
|
debouncedSave();
|
|
1150
1506
|
}, [isResizing, debouncedSave]);
|
|
1151
|
-
|
|
1507
|
+
React13.useEffect(() => {
|
|
1152
1508
|
if (isDragging) {
|
|
1153
1509
|
window.addEventListener("pointermove", handleDragMove);
|
|
1154
1510
|
window.addEventListener("pointerup", handleDragEnd);
|
|
@@ -1158,7 +1514,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1158
1514
|
};
|
|
1159
1515
|
}
|
|
1160
1516
|
}, [isDragging, handleDragMove, handleDragEnd]);
|
|
1161
|
-
|
|
1517
|
+
React13.useEffect(() => {
|
|
1162
1518
|
if (isPinnedDragging) {
|
|
1163
1519
|
window.addEventListener("pointermove", handlePinnedDragMove);
|
|
1164
1520
|
window.addEventListener("pointerup", handlePinnedDragEnd);
|
|
@@ -1168,7 +1524,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1168
1524
|
};
|
|
1169
1525
|
}
|
|
1170
1526
|
}, [isPinnedDragging, handlePinnedDragMove, handlePinnedDragEnd]);
|
|
1171
|
-
|
|
1527
|
+
React13.useEffect(() => {
|
|
1172
1528
|
if (isResizing) {
|
|
1173
1529
|
window.addEventListener("pointermove", handleResizeMove);
|
|
1174
1530
|
window.addEventListener("pointerup", handleResizeEnd);
|
|
@@ -1178,7 +1534,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1178
1534
|
};
|
|
1179
1535
|
}
|
|
1180
1536
|
}, [isResizing, handleResizeMove, handleResizeEnd]);
|
|
1181
|
-
const panelStyles =
|
|
1537
|
+
const panelStyles = React13.useMemo(() => {
|
|
1182
1538
|
if (mode === "pinned") {
|
|
1183
1539
|
const baseStyles = getPinnedPositionStyles(edge, pinnedSize);
|
|
1184
1540
|
if (pullOffset > 0) {
|
|
@@ -1205,7 +1561,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1205
1561
|
if (!isExpanded && mode === "pinned") {
|
|
1206
1562
|
return /* @__PURE__ */ jsx12(DataPanelTab, { title, edge, onClick: () => handleExpandedChange(true) });
|
|
1207
1563
|
}
|
|
1208
|
-
return /* @__PURE__ */
|
|
1564
|
+
return /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1209
1565
|
snapPreview && /* @__PURE__ */ jsx12(
|
|
1210
1566
|
"div",
|
|
1211
1567
|
{
|
|
@@ -1218,7 +1574,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1218
1574
|
)
|
|
1219
1575
|
}
|
|
1220
1576
|
),
|
|
1221
|
-
/* @__PURE__ */
|
|
1577
|
+
/* @__PURE__ */ jsxs5(
|
|
1222
1578
|
"div",
|
|
1223
1579
|
{
|
|
1224
1580
|
ref,
|
|
@@ -1231,9 +1587,10 @@ var DataPanel = React12.forwardRef(
|
|
|
1231
1587
|
className
|
|
1232
1588
|
),
|
|
1233
1589
|
style: panelStyles,
|
|
1234
|
-
role: mode === "detached" ? "dialog" :
|
|
1590
|
+
role: mode === "detached" ? "dialog" : "complementary",
|
|
1235
1591
|
"aria-modal": mode === "detached" ? "true" : void 0,
|
|
1236
|
-
"aria-labelledby": title ?
|
|
1592
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
1593
|
+
"aria-label": !title ? "Side panel" : void 0,
|
|
1237
1594
|
onPointerDown: handleDragStart,
|
|
1238
1595
|
children: [
|
|
1239
1596
|
/* @__PURE__ */ jsx12(
|
|
@@ -1241,6 +1598,7 @@ var DataPanel = React12.forwardRef(
|
|
|
1241
1598
|
{
|
|
1242
1599
|
title,
|
|
1243
1600
|
subtitle,
|
|
1601
|
+
titleId,
|
|
1244
1602
|
mode,
|
|
1245
1603
|
edge,
|
|
1246
1604
|
isExpanded,
|
|
@@ -1264,80 +1622,31 @@ var DataPanel = React12.forwardRef(
|
|
|
1264
1622
|
footerActions
|
|
1265
1623
|
}
|
|
1266
1624
|
),
|
|
1267
|
-
!disableResize && /* @__PURE__ */ jsx12(
|
|
1268
|
-
|
|
1269
|
-
"div",
|
|
1270
|
-
{
|
|
1271
|
-
className: "resize-handle resize-handle--horizontal resize-handle--top",
|
|
1272
|
-
onPointerDown: (e) => handleResizeStart(e, "top")
|
|
1273
|
-
}
|
|
1274
|
-
),
|
|
1275
|
-
/* @__PURE__ */ jsx12(
|
|
1276
|
-
"div",
|
|
1277
|
-
{
|
|
1278
|
-
className: "resize-handle resize-handle--horizontal resize-handle--bottom",
|
|
1279
|
-
onPointerDown: (e) => handleResizeStart(e, "bottom")
|
|
1280
|
-
}
|
|
1281
|
-
),
|
|
1282
|
-
/* @__PURE__ */ jsx12(
|
|
1283
|
-
"div",
|
|
1284
|
-
{
|
|
1285
|
-
className: "resize-handle resize-handle--vertical resize-handle--left",
|
|
1286
|
-
onPointerDown: (e) => handleResizeStart(e, "left")
|
|
1287
|
-
}
|
|
1288
|
-
),
|
|
1289
|
-
/* @__PURE__ */ jsx12(
|
|
1290
|
-
"div",
|
|
1291
|
-
{
|
|
1292
|
-
className: "resize-handle resize-handle--vertical resize-handle--right",
|
|
1293
|
-
onPointerDown: (e) => handleResizeStart(e, "right")
|
|
1294
|
-
}
|
|
1295
|
-
),
|
|
1296
|
-
/* @__PURE__ */ jsx12(
|
|
1297
|
-
"div",
|
|
1298
|
-
{
|
|
1299
|
-
className: "resize-handle resize-handle--corner resize-handle--top-left",
|
|
1300
|
-
style: { "--handle-radius": "6px" },
|
|
1301
|
-
onPointerDown: (e) => handleResizeStart(e, "top-left")
|
|
1302
|
-
}
|
|
1303
|
-
),
|
|
1304
|
-
/* @__PURE__ */ jsx12(
|
|
1305
|
-
"div",
|
|
1306
|
-
{
|
|
1307
|
-
className: "resize-handle resize-handle--corner resize-handle--top-right",
|
|
1308
|
-
style: { "--handle-radius": "6px" },
|
|
1309
|
-
onPointerDown: (e) => handleResizeStart(e, "top-right")
|
|
1310
|
-
}
|
|
1311
|
-
),
|
|
1312
|
-
/* @__PURE__ */ jsx12(
|
|
1313
|
-
"div",
|
|
1314
|
-
{
|
|
1315
|
-
className: "resize-handle resize-handle--corner resize-handle--bottom-left",
|
|
1316
|
-
style: { "--handle-radius": "6px" },
|
|
1317
|
-
onPointerDown: (e) => handleResizeStart(e, "bottom-left")
|
|
1318
|
-
}
|
|
1319
|
-
),
|
|
1320
|
-
/* @__PURE__ */ jsx12(
|
|
1321
|
-
"div",
|
|
1322
|
-
{
|
|
1323
|
-
className: "resize-handle resize-handle--corner resize-handle--bottom-right",
|
|
1324
|
-
style: { "--handle-radius": "6px" },
|
|
1325
|
-
onPointerDown: (e) => handleResizeStart(e, "bottom-right")
|
|
1326
|
-
}
|
|
1327
|
-
)
|
|
1328
|
-
] }) : /* @__PURE__ */ jsx12(
|
|
1329
|
-
"div",
|
|
1625
|
+
!disableResize && /* @__PURE__ */ jsx12(
|
|
1626
|
+
ResizeHandles,
|
|
1330
1627
|
{
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
)
|
|
1338
|
-
|
|
1628
|
+
mode,
|
|
1629
|
+
edge,
|
|
1630
|
+
detachedSize,
|
|
1631
|
+
pinnedSize,
|
|
1632
|
+
onResizeStart: handleResizeStart,
|
|
1633
|
+
onSizeChange: (size) => setDetachedSize(constrainSize(size, resolvedConstraints)),
|
|
1634
|
+
onPinnedSizeChange: (size) => {
|
|
1635
|
+
if (typeof window === "undefined") {
|
|
1636
|
+
setPinnedSize(size);
|
|
1637
|
+
return;
|
|
1638
|
+
}
|
|
1639
|
+
if (isHorizontalEdge(edge)) {
|
|
1640
|
+
setPinnedSize(constrainPinnedWidth(size, resolvedConstraints, window.innerWidth));
|
|
1641
|
+
} else {
|
|
1642
|
+
setPinnedSize(
|
|
1643
|
+
constrainPinnedHeight(size, resolvedConstraints, window.innerHeight)
|
|
1644
|
+
);
|
|
1645
|
+
}
|
|
1646
|
+
},
|
|
1647
|
+
constraints: resolvedConstraints
|
|
1339
1648
|
}
|
|
1340
|
-
)
|
|
1649
|
+
)
|
|
1341
1650
|
]
|
|
1342
1651
|
}
|
|
1343
1652
|
)
|
|
@@ -1345,6 +1654,891 @@ var DataPanel = React12.forwardRef(
|
|
|
1345
1654
|
}
|
|
1346
1655
|
);
|
|
1347
1656
|
DataPanel.displayName = "DataPanel";
|
|
1657
|
+
|
|
1658
|
+
// src/components/Skeleton.tsx
|
|
1659
|
+
import * as React14 from "react";
|
|
1660
|
+
import { cva as cva5 } from "class-variance-authority";
|
|
1661
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
1662
|
+
var skeletonVariants = cva5("rounded-md bg-muted", {
|
|
1663
|
+
variants: {
|
|
1664
|
+
variant: {
|
|
1665
|
+
default: "",
|
|
1666
|
+
text: "h-4 w-full",
|
|
1667
|
+
avatar: "h-12 w-12 rounded-full",
|
|
1668
|
+
card: "h-32 w-full",
|
|
1669
|
+
button: "h-10 w-24",
|
|
1670
|
+
title: "h-6 w-3/4"
|
|
1671
|
+
}
|
|
1672
|
+
},
|
|
1673
|
+
defaultVariants: {
|
|
1674
|
+
variant: "default"
|
|
1675
|
+
}
|
|
1676
|
+
});
|
|
1677
|
+
var Skeleton = React14.forwardRef(
|
|
1678
|
+
({ className, variant, animation = "pulse", ...props }, ref) => {
|
|
1679
|
+
const animationClass = animation === "pulse" ? "animate-pulse" : animation === "shimmer" ? "animate-shimmer" : "";
|
|
1680
|
+
return /* @__PURE__ */ jsx13(
|
|
1681
|
+
"div",
|
|
1682
|
+
{
|
|
1683
|
+
ref,
|
|
1684
|
+
className: cn(skeletonVariants({ variant }), animationClass, className),
|
|
1685
|
+
...props
|
|
1686
|
+
}
|
|
1687
|
+
);
|
|
1688
|
+
}
|
|
1689
|
+
);
|
|
1690
|
+
Skeleton.displayName = "Skeleton";
|
|
1691
|
+
|
|
1692
|
+
// src/components/Spinner.tsx
|
|
1693
|
+
import * as React15 from "react";
|
|
1694
|
+
import { cva as cva6 } from "class-variance-authority";
|
|
1695
|
+
import { jsx as jsx14, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1696
|
+
var spinnerVariants = cva6("animate-spin text-current", {
|
|
1697
|
+
variants: {
|
|
1698
|
+
size: {
|
|
1699
|
+
sm: "h-4 w-4",
|
|
1700
|
+
md: "h-6 w-6",
|
|
1701
|
+
lg: "h-8 w-8",
|
|
1702
|
+
xl: "h-12 w-12"
|
|
1703
|
+
}
|
|
1704
|
+
},
|
|
1705
|
+
defaultVariants: {
|
|
1706
|
+
size: "md"
|
|
1707
|
+
}
|
|
1708
|
+
});
|
|
1709
|
+
var Spinner = React15.forwardRef(
|
|
1710
|
+
({ className, size, label = "Loading...", ...props }, ref) => {
|
|
1711
|
+
return /* @__PURE__ */ jsxs6(
|
|
1712
|
+
"svg",
|
|
1713
|
+
{
|
|
1714
|
+
ref,
|
|
1715
|
+
className: cn(spinnerVariants({ size }), className),
|
|
1716
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1717
|
+
fill: "none",
|
|
1718
|
+
viewBox: "0 0 24 24",
|
|
1719
|
+
"aria-label": label,
|
|
1720
|
+
role: "status",
|
|
1721
|
+
...props,
|
|
1722
|
+
children: [
|
|
1723
|
+
/* @__PURE__ */ jsx14(
|
|
1724
|
+
"circle",
|
|
1725
|
+
{
|
|
1726
|
+
className: "opacity-25",
|
|
1727
|
+
cx: "12",
|
|
1728
|
+
cy: "12",
|
|
1729
|
+
r: "10",
|
|
1730
|
+
stroke: "currentColor",
|
|
1731
|
+
strokeWidth: "4"
|
|
1732
|
+
}
|
|
1733
|
+
),
|
|
1734
|
+
/* @__PURE__ */ jsx14(
|
|
1735
|
+
"path",
|
|
1736
|
+
{
|
|
1737
|
+
className: "opacity-75",
|
|
1738
|
+
fill: "currentColor",
|
|
1739
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
1740
|
+
}
|
|
1741
|
+
),
|
|
1742
|
+
/* @__PURE__ */ jsx14("title", { children: label })
|
|
1743
|
+
]
|
|
1744
|
+
}
|
|
1745
|
+
);
|
|
1746
|
+
}
|
|
1747
|
+
);
|
|
1748
|
+
Spinner.displayName = "Spinner";
|
|
1749
|
+
|
|
1750
|
+
// src/components/LoadingLogo.tsx
|
|
1751
|
+
import * as React16 from "react";
|
|
1752
|
+
import { jsx as jsx15, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1753
|
+
var logoPaths = [
|
|
1754
|
+
"M9.902 16.6c.3.7 1.7.8 1-.6-.6-1.4-2.3-5.1-6.1-6.3-1.7-.5-3.7.4-4.3 1.6-.4.7-1.1 2.9.5 4.3.8.7 1.9 1.2 3.6 1 .4-.1.9-.5.6-.8-.5-.4-1.9-1.7-1.1-2.7.7-.8 1.4-.6 2-.3.4.2 2.1 1 3.7 3.6l.1.2z",
|
|
1755
|
+
"M14.602 16.6c-.3.7-1.7.8-1-.6.6-1.4 2.3-5.1 6.1-6.3 1.7-.5 3.7.4 4.3 1.6.4.7 1.1 2.9-.5 4.3-.8.7-1.9 1.2-3.6 1-.4-.1-.9-.5-.6-.8.5-.4 1.9-1.7 1.1-2.7-.7-.8-1.4-.6-2-.3-.4.2-2.1 1-3.7 3.6l-.1.2z",
|
|
1756
|
+
"M12.202 0c.7 1.3 2.1 3.2 2.3 5.3.1 1.5-.8 8.3-2.3 11.7-1.5-3.5-2.4-10.3-2.3-11.7.2-2.1 1.6-4 2.3-5.3z",
|
|
1757
|
+
"M9.002 18.1c-.8 0-.7.8-.1.8h6.7c.7 0 .7-.8-.1-.8h-6.5z",
|
|
1758
|
+
"M13.802 24.8c-1.1-1.1-.9-4.6-.9-4.6h-1.3s.2 3.6-.9 4.6h3.1z",
|
|
1759
|
+
"M14.202 22.5c-.1-.3-.5-1.4-.6-2.3 0-.2.6-.5.7.1.1.6.4 1.6.6 1.9.3.5-.4.9-.7.3z",
|
|
1760
|
+
"M10.302 22.5c.1-.3.5-1.4.6-2.2 0-.3-.5-.6-.7 0-.1.6-.4 1.6-.6 1.9-.3.5.4.9.7.3z"
|
|
1761
|
+
];
|
|
1762
|
+
var colors = {
|
|
1763
|
+
dark: {
|
|
1764
|
+
fill: "#C50F22",
|
|
1765
|
+
fillLoading: "#ffffff",
|
|
1766
|
+
stroke: "#C50F22"
|
|
1767
|
+
},
|
|
1768
|
+
light: {
|
|
1769
|
+
fill: "#ffffff",
|
|
1770
|
+
fillLoading: "#C50F22",
|
|
1771
|
+
stroke: "#ffffff"
|
|
1772
|
+
}
|
|
1773
|
+
};
|
|
1774
|
+
var LoadingLogo = React16.forwardRef(
|
|
1775
|
+
({ width = 40, height = 40, loading = false, variant = "dark", className, ...props }, ref) => {
|
|
1776
|
+
const currentColors = colors[variant];
|
|
1777
|
+
const fillColor = loading ? currentColors.fillLoading : currentColors.fill;
|
|
1778
|
+
const strokeColor = currentColors.stroke;
|
|
1779
|
+
return /* @__PURE__ */ jsxs7(
|
|
1780
|
+
"div",
|
|
1781
|
+
{
|
|
1782
|
+
ref,
|
|
1783
|
+
className: cn("inline-flex items-center justify-center", className),
|
|
1784
|
+
style: { width: `${width}px`, height: `${height}px` },
|
|
1785
|
+
role: loading ? "status" : "img",
|
|
1786
|
+
"aria-label": loading ? "Loading" : "Classic Homes",
|
|
1787
|
+
...props,
|
|
1788
|
+
children: [
|
|
1789
|
+
/* @__PURE__ */ jsxs7(
|
|
1790
|
+
"svg",
|
|
1791
|
+
{
|
|
1792
|
+
width: "100%",
|
|
1793
|
+
height: "100%",
|
|
1794
|
+
viewBox: "-1 0 26 25",
|
|
1795
|
+
fill: "none",
|
|
1796
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1797
|
+
"aria-hidden": "true",
|
|
1798
|
+
children: [
|
|
1799
|
+
/* @__PURE__ */ jsx15("g", { fill: fillColor, className: "transition-all duration-300", children: logoPaths.map((path, i) => /* @__PURE__ */ jsx15("path", { d: path }, i)) }),
|
|
1800
|
+
loading && /* @__PURE__ */ jsx15(
|
|
1801
|
+
"g",
|
|
1802
|
+
{
|
|
1803
|
+
fill: "none",
|
|
1804
|
+
stroke: strokeColor,
|
|
1805
|
+
strokeWidth: "0.5",
|
|
1806
|
+
strokeDasharray: "10 4",
|
|
1807
|
+
className: "animate-trace",
|
|
1808
|
+
children: logoPaths.map((path, i) => /* @__PURE__ */ jsx15("path", { d: path }, i))
|
|
1809
|
+
}
|
|
1810
|
+
)
|
|
1811
|
+
]
|
|
1812
|
+
}
|
|
1813
|
+
),
|
|
1814
|
+
loading && /* @__PURE__ */ jsx15("span", { className: "sr-only", children: "Loading" })
|
|
1815
|
+
]
|
|
1816
|
+
}
|
|
1817
|
+
);
|
|
1818
|
+
}
|
|
1819
|
+
);
|
|
1820
|
+
LoadingLogo.displayName = "LoadingLogo";
|
|
1821
|
+
|
|
1822
|
+
// src/components/ProgressBar.tsx
|
|
1823
|
+
import * as React17 from "react";
|
|
1824
|
+
import { cva as cva7 } from "class-variance-authority";
|
|
1825
|
+
import { jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1826
|
+
var progressBarVariants = cva7("w-full overflow-hidden rounded-full bg-muted", {
|
|
1827
|
+
variants: {
|
|
1828
|
+
size: {
|
|
1829
|
+
sm: "h-1",
|
|
1830
|
+
md: "h-2",
|
|
1831
|
+
lg: "h-3"
|
|
1832
|
+
}
|
|
1833
|
+
},
|
|
1834
|
+
defaultVariants: {
|
|
1835
|
+
size: "md"
|
|
1836
|
+
}
|
|
1837
|
+
});
|
|
1838
|
+
var progressFillVariants = cva7("h-full rounded-full transition-all duration-300", {
|
|
1839
|
+
variants: {
|
|
1840
|
+
variant: {
|
|
1841
|
+
default: "bg-primary",
|
|
1842
|
+
success: "bg-success",
|
|
1843
|
+
warning: "bg-warning",
|
|
1844
|
+
destructive: "bg-destructive"
|
|
1845
|
+
}
|
|
1846
|
+
},
|
|
1847
|
+
defaultVariants: {
|
|
1848
|
+
variant: "default"
|
|
1849
|
+
}
|
|
1850
|
+
});
|
|
1851
|
+
var ProgressBar = React17.forwardRef(
|
|
1852
|
+
({ className, size, variant, value, max = 100, label = "Progress", showValue = false, ...props }, ref) => {
|
|
1853
|
+
const isIndeterminate = value === void 0;
|
|
1854
|
+
const clampedValue = isIndeterminate ? 0 : Math.min(Math.max(0, value), max);
|
|
1855
|
+
const percentage = isIndeterminate ? 0 : Math.round(clampedValue / max * 100);
|
|
1856
|
+
return /* @__PURE__ */ jsxs8(
|
|
1857
|
+
"div",
|
|
1858
|
+
{
|
|
1859
|
+
ref,
|
|
1860
|
+
role: "progressbar",
|
|
1861
|
+
"aria-label": label,
|
|
1862
|
+
"aria-valuenow": isIndeterminate ? void 0 : clampedValue,
|
|
1863
|
+
"aria-valuemin": 0,
|
|
1864
|
+
"aria-valuemax": max,
|
|
1865
|
+
className: cn("flex items-center gap-2", className),
|
|
1866
|
+
...props,
|
|
1867
|
+
children: [
|
|
1868
|
+
/* @__PURE__ */ jsx16("div", { className: cn(progressBarVariants({ size })), children: /* @__PURE__ */ jsx16(
|
|
1869
|
+
"div",
|
|
1870
|
+
{
|
|
1871
|
+
className: cn(
|
|
1872
|
+
progressFillVariants({ variant }),
|
|
1873
|
+
isIndeterminate && "w-1/4 animate-progress-indeterminate"
|
|
1874
|
+
),
|
|
1875
|
+
style: isIndeterminate ? void 0 : { width: `${percentage}%` }
|
|
1876
|
+
}
|
|
1877
|
+
) }),
|
|
1878
|
+
showValue && !isIndeterminate && /* @__PURE__ */ jsxs8("span", { className: "text-sm tabular-nums text-muted-foreground", children: [
|
|
1879
|
+
percentage,
|
|
1880
|
+
"%"
|
|
1881
|
+
] })
|
|
1882
|
+
]
|
|
1883
|
+
}
|
|
1884
|
+
);
|
|
1885
|
+
}
|
|
1886
|
+
);
|
|
1887
|
+
ProgressBar.displayName = "ProgressBar";
|
|
1888
|
+
|
|
1889
|
+
// src/components/LoadingOverlay.tsx
|
|
1890
|
+
import * as React18 from "react";
|
|
1891
|
+
import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1892
|
+
var spinnerSizeMap = { sm: "sm", md: "md", lg: "lg", xl: "xl" };
|
|
1893
|
+
var logoSizeMap = { sm: 32, md: 40, lg: 56, xl: 80 };
|
|
1894
|
+
var LoadingOverlay = React18.forwardRef(
|
|
1895
|
+
({
|
|
1896
|
+
loading = true,
|
|
1897
|
+
variant = "spinner",
|
|
1898
|
+
mode = "overlay",
|
|
1899
|
+
size = "md",
|
|
1900
|
+
message,
|
|
1901
|
+
progress,
|
|
1902
|
+
blur = true,
|
|
1903
|
+
opaque = false,
|
|
1904
|
+
delay = 0,
|
|
1905
|
+
className,
|
|
1906
|
+
children,
|
|
1907
|
+
...props
|
|
1908
|
+
}, ref) => {
|
|
1909
|
+
const [visible, setVisible] = React18.useState(delay === 0 && loading);
|
|
1910
|
+
React18.useEffect(() => {
|
|
1911
|
+
if (!loading) {
|
|
1912
|
+
setVisible(false);
|
|
1913
|
+
return;
|
|
1914
|
+
}
|
|
1915
|
+
if (delay === 0) {
|
|
1916
|
+
setVisible(true);
|
|
1917
|
+
return;
|
|
1918
|
+
}
|
|
1919
|
+
const timer = setTimeout(() => setVisible(true), delay);
|
|
1920
|
+
return () => clearTimeout(timer);
|
|
1921
|
+
}, [loading, delay]);
|
|
1922
|
+
if (!visible) {
|
|
1923
|
+
return mode === "inline" ? null : /* @__PURE__ */ jsx17(Fragment2, { children });
|
|
1924
|
+
}
|
|
1925
|
+
const indicator = /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
1926
|
+
variant === "spinner" && /* @__PURE__ */ jsx17(Spinner, { size: spinnerSizeMap[size] }),
|
|
1927
|
+
variant === "logo" && /* @__PURE__ */ jsx17(LoadingLogo, { loading: true, width: logoSizeMap[size], height: logoSizeMap[size] }),
|
|
1928
|
+
variant === "progress" && /* @__PURE__ */ jsx17(ProgressBar, { value: progress, className: "w-48 max-w-full" }),
|
|
1929
|
+
variant === "skeleton" && /* @__PURE__ */ jsxs9("div", { className: "w-full space-y-3", children: [
|
|
1930
|
+
/* @__PURE__ */ jsx17(Skeleton, { variant: "title" }),
|
|
1931
|
+
/* @__PURE__ */ jsx17(Skeleton, { variant: "text" }),
|
|
1932
|
+
/* @__PURE__ */ jsx17(Skeleton, { variant: "text" }),
|
|
1933
|
+
/* @__PURE__ */ jsx17(Skeleton, { variant: "text", className: "w-2/3" })
|
|
1934
|
+
] }),
|
|
1935
|
+
message && /* @__PURE__ */ jsx17("p", { className: "mt-2 text-sm text-muted-foreground animate-pulse-subtle", children: message }),
|
|
1936
|
+
!message && /* @__PURE__ */ jsx17("span", { className: "sr-only", children: "Loading" })
|
|
1937
|
+
] });
|
|
1938
|
+
if (mode === "inline") {
|
|
1939
|
+
return /* @__PURE__ */ jsx17(
|
|
1940
|
+
"div",
|
|
1941
|
+
{
|
|
1942
|
+
ref,
|
|
1943
|
+
role: "status",
|
|
1944
|
+
"aria-live": "polite",
|
|
1945
|
+
className: cn("inline-flex items-center gap-2", className),
|
|
1946
|
+
...props,
|
|
1947
|
+
children: indicator
|
|
1948
|
+
}
|
|
1949
|
+
);
|
|
1950
|
+
}
|
|
1951
|
+
const bgClass = opaque ? "bg-background" : mode === "fullscreen" ? "bg-background/80" : "bg-background/60";
|
|
1952
|
+
const positionClass = mode === "fullscreen" ? "fixed inset-0 z-50" : "absolute inset-0 z-10";
|
|
1953
|
+
return /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
1954
|
+
children,
|
|
1955
|
+
/* @__PURE__ */ jsx17(
|
|
1956
|
+
"div",
|
|
1957
|
+
{
|
|
1958
|
+
ref,
|
|
1959
|
+
role: "status",
|
|
1960
|
+
"aria-live": "polite",
|
|
1961
|
+
className: cn(
|
|
1962
|
+
positionClass,
|
|
1963
|
+
bgClass,
|
|
1964
|
+
blur && "backdrop-blur-sm",
|
|
1965
|
+
"flex flex-col items-center justify-center",
|
|
1966
|
+
className
|
|
1967
|
+
),
|
|
1968
|
+
...props,
|
|
1969
|
+
children: indicator
|
|
1970
|
+
}
|
|
1971
|
+
)
|
|
1972
|
+
] });
|
|
1973
|
+
}
|
|
1974
|
+
);
|
|
1975
|
+
LoadingOverlay.displayName = "LoadingOverlay";
|
|
1976
|
+
|
|
1977
|
+
// src/components/LoadingPage.tsx
|
|
1978
|
+
import * as React19 from "react";
|
|
1979
|
+
import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1980
|
+
var LoadingPage = React19.forwardRef(
|
|
1981
|
+
({
|
|
1982
|
+
loading = true,
|
|
1983
|
+
message,
|
|
1984
|
+
progress,
|
|
1985
|
+
showLogo = true,
|
|
1986
|
+
logoVariant = "dark",
|
|
1987
|
+
delay = 200,
|
|
1988
|
+
className,
|
|
1989
|
+
...props
|
|
1990
|
+
}, ref) => {
|
|
1991
|
+
const [visible, setVisible] = React19.useState(delay === 0 && loading);
|
|
1992
|
+
React19.useEffect(() => {
|
|
1993
|
+
if (!loading) {
|
|
1994
|
+
setVisible(false);
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1997
|
+
if (delay === 0) {
|
|
1998
|
+
setVisible(true);
|
|
1999
|
+
return;
|
|
2000
|
+
}
|
|
2001
|
+
const timer = setTimeout(() => setVisible(true), delay);
|
|
2002
|
+
return () => clearTimeout(timer);
|
|
2003
|
+
}, [loading, delay]);
|
|
2004
|
+
if (!visible) return null;
|
|
2005
|
+
return /* @__PURE__ */ jsxs10(
|
|
2006
|
+
"div",
|
|
2007
|
+
{
|
|
2008
|
+
ref,
|
|
2009
|
+
role: "status",
|
|
2010
|
+
"aria-live": "polite",
|
|
2011
|
+
className: cn(
|
|
2012
|
+
"fixed inset-0 z-50 flex flex-col items-center justify-center bg-background",
|
|
2013
|
+
className
|
|
2014
|
+
),
|
|
2015
|
+
...props,
|
|
2016
|
+
children: [
|
|
2017
|
+
showLogo ? /* @__PURE__ */ jsx18(LoadingLogo, { loading: true, width: 64, height: 64, variant: logoVariant }) : /* @__PURE__ */ jsx18(Spinner, { size: "xl" }),
|
|
2018
|
+
progress !== void 0 && /* @__PURE__ */ jsx18(ProgressBar, { value: progress, className: "mt-6 w-48 max-w-full" }),
|
|
2019
|
+
message && /* @__PURE__ */ jsx18("p", { className: "mt-4 text-sm text-muted-foreground animate-pulse-subtle", children: message }),
|
|
2020
|
+
/* @__PURE__ */ jsxs10("span", { className: "sr-only", children: [
|
|
2021
|
+
message || "Loading",
|
|
2022
|
+
progress !== void 0 && `, ${Math.round(progress)}% complete`
|
|
2023
|
+
] })
|
|
2024
|
+
]
|
|
2025
|
+
}
|
|
2026
|
+
);
|
|
2027
|
+
}
|
|
2028
|
+
);
|
|
2029
|
+
LoadingPage.displayName = "LoadingPage";
|
|
2030
|
+
|
|
2031
|
+
// src/components/LoadingSection.tsx
|
|
2032
|
+
import * as React20 from "react";
|
|
2033
|
+
import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2034
|
+
var LoadingSection = React20.forwardRef(
|
|
2035
|
+
({
|
|
2036
|
+
loading = false,
|
|
2037
|
+
variant = "spinner",
|
|
2038
|
+
message,
|
|
2039
|
+
progress,
|
|
2040
|
+
minHeight = "12rem",
|
|
2041
|
+
blur = true,
|
|
2042
|
+
delay = 0,
|
|
2043
|
+
className,
|
|
2044
|
+
children,
|
|
2045
|
+
...props
|
|
2046
|
+
}, ref) => {
|
|
2047
|
+
return /* @__PURE__ */ jsxs11(
|
|
2048
|
+
"div",
|
|
2049
|
+
{
|
|
2050
|
+
ref,
|
|
2051
|
+
className: cn("relative", className),
|
|
2052
|
+
style: { minHeight },
|
|
2053
|
+
"aria-busy": loading,
|
|
2054
|
+
...props,
|
|
2055
|
+
children: [
|
|
2056
|
+
children,
|
|
2057
|
+
loading && /* @__PURE__ */ jsx19(
|
|
2058
|
+
LoadingOverlay,
|
|
2059
|
+
{
|
|
2060
|
+
mode: "overlay",
|
|
2061
|
+
variant,
|
|
2062
|
+
message,
|
|
2063
|
+
progress,
|
|
2064
|
+
blur,
|
|
2065
|
+
delay
|
|
2066
|
+
}
|
|
2067
|
+
)
|
|
2068
|
+
]
|
|
2069
|
+
}
|
|
2070
|
+
);
|
|
2071
|
+
}
|
|
2072
|
+
);
|
|
2073
|
+
LoadingSection.displayName = "LoadingSection";
|
|
2074
|
+
|
|
2075
|
+
// src/components/LiveRegion.tsx
|
|
2076
|
+
import * as React21 from "react";
|
|
2077
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
2078
|
+
var LiveRegion = React21.forwardRef(
|
|
2079
|
+
({ message, politeness = "polite", atomic = true, visuallyHidden = true, className, children }, ref) => {
|
|
2080
|
+
return /* @__PURE__ */ jsx20(
|
|
2081
|
+
"div",
|
|
2082
|
+
{
|
|
2083
|
+
ref,
|
|
2084
|
+
role: "status",
|
|
2085
|
+
"aria-live": politeness,
|
|
2086
|
+
"aria-atomic": atomic,
|
|
2087
|
+
className: cn(
|
|
2088
|
+
visuallyHidden && "sr-only absolute h-px w-px overflow-hidden whitespace-nowrap border-0 p-0",
|
|
2089
|
+
className
|
|
2090
|
+
),
|
|
2091
|
+
children: message || children
|
|
2092
|
+
}
|
|
2093
|
+
);
|
|
2094
|
+
}
|
|
2095
|
+
);
|
|
2096
|
+
LiveRegion.displayName = "LiveRegion";
|
|
2097
|
+
|
|
2098
|
+
// src/components/SkipLink.tsx
|
|
2099
|
+
import * as React22 from "react";
|
|
2100
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
2101
|
+
var SkipLink = React22.forwardRef(
|
|
2102
|
+
({ targetId, className, children = "Skip to main content", ...props }, ref) => {
|
|
2103
|
+
const handleClick = (e) => {
|
|
2104
|
+
e.preventDefault();
|
|
2105
|
+
const target = document.getElementById(targetId);
|
|
2106
|
+
if (target) {
|
|
2107
|
+
if (target.tabIndex === -1) {
|
|
2108
|
+
target.setAttribute("tabindex", "-1");
|
|
2109
|
+
}
|
|
2110
|
+
target.focus();
|
|
2111
|
+
target.scrollIntoView();
|
|
2112
|
+
} else if (process.env.NODE_ENV !== "production") {
|
|
2113
|
+
console.warn(
|
|
2114
|
+
`SkipLink: Target element with id="${targetId}" not found. Ensure the target element exists and has the correct id attribute.`
|
|
2115
|
+
);
|
|
2116
|
+
}
|
|
2117
|
+
props.onClick?.(e);
|
|
2118
|
+
};
|
|
2119
|
+
return /* @__PURE__ */ jsx21(
|
|
2120
|
+
"a",
|
|
2121
|
+
{
|
|
2122
|
+
ref,
|
|
2123
|
+
href: `#${targetId}`,
|
|
2124
|
+
className: cn("skip-link", className),
|
|
2125
|
+
onClick: handleClick,
|
|
2126
|
+
...props,
|
|
2127
|
+
children
|
|
2128
|
+
}
|
|
2129
|
+
);
|
|
2130
|
+
}
|
|
2131
|
+
);
|
|
2132
|
+
SkipLink.displayName = "SkipLink";
|
|
2133
|
+
|
|
2134
|
+
// src/hooks/useFocusTrap.ts
|
|
2135
|
+
import { useEffect as useEffect5, useRef as useRef3, useCallback as useCallback3 } from "react";
|
|
2136
|
+
var FOCUSABLE_SELECTOR = [
|
|
2137
|
+
"a[href]",
|
|
2138
|
+
"area[href]",
|
|
2139
|
+
'input:not([disabled]):not([type="hidden"])',
|
|
2140
|
+
"select:not([disabled])",
|
|
2141
|
+
"textarea:not([disabled])",
|
|
2142
|
+
"button:not([disabled])",
|
|
2143
|
+
"iframe",
|
|
2144
|
+
"object",
|
|
2145
|
+
"embed",
|
|
2146
|
+
"[contenteditable]",
|
|
2147
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
2148
|
+
].join(",");
|
|
2149
|
+
function getFocusableElements(container) {
|
|
2150
|
+
const elements = container.querySelectorAll(FOCUSABLE_SELECTOR);
|
|
2151
|
+
return Array.from(elements).filter(
|
|
2152
|
+
(el) => el.offsetParent !== null && getComputedStyle(el).visibility !== "hidden"
|
|
2153
|
+
);
|
|
2154
|
+
}
|
|
2155
|
+
function useFocusTrap(options = {}) {
|
|
2156
|
+
const { active = true, returnFocusTo, initialFocus, preventScroll = false } = options;
|
|
2157
|
+
const containerRef = useRef3(null);
|
|
2158
|
+
const previousActiveElementRef = useRef3(null);
|
|
2159
|
+
const handleKeyDown = useCallback3(
|
|
2160
|
+
(event) => {
|
|
2161
|
+
if (!active || event.key !== "Tab") return;
|
|
2162
|
+
const container = containerRef.current;
|
|
2163
|
+
if (!container) return;
|
|
2164
|
+
const focusableElements = getFocusableElements(container);
|
|
2165
|
+
if (focusableElements.length === 0) return;
|
|
2166
|
+
const firstElement = focusableElements[0];
|
|
2167
|
+
const lastElement = focusableElements[focusableElements.length - 1];
|
|
2168
|
+
if (event.shiftKey) {
|
|
2169
|
+
if (document.activeElement === firstElement) {
|
|
2170
|
+
event.preventDefault();
|
|
2171
|
+
lastElement.focus({ preventScroll });
|
|
2172
|
+
}
|
|
2173
|
+
} else {
|
|
2174
|
+
if (document.activeElement === lastElement) {
|
|
2175
|
+
event.preventDefault();
|
|
2176
|
+
firstElement.focus({ preventScroll });
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
},
|
|
2180
|
+
[active, preventScroll]
|
|
2181
|
+
);
|
|
2182
|
+
useEffect5(() => {
|
|
2183
|
+
if (!active) return;
|
|
2184
|
+
const container = containerRef.current;
|
|
2185
|
+
if (!container) return;
|
|
2186
|
+
previousActiveElementRef.current = document.activeElement;
|
|
2187
|
+
const focusableElements = getFocusableElements(container);
|
|
2188
|
+
if (focusableElements.length > 0) {
|
|
2189
|
+
let elementToFocus = null;
|
|
2190
|
+
if (initialFocus) {
|
|
2191
|
+
elementToFocus = container.querySelector(initialFocus);
|
|
2192
|
+
}
|
|
2193
|
+
if (!elementToFocus) {
|
|
2194
|
+
elementToFocus = focusableElements[0];
|
|
2195
|
+
}
|
|
2196
|
+
requestAnimationFrame(() => {
|
|
2197
|
+
elementToFocus?.focus({ preventScroll });
|
|
2198
|
+
});
|
|
2199
|
+
}
|
|
2200
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
2201
|
+
return () => {
|
|
2202
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
2203
|
+
const elementToReturn = returnFocusTo ?? previousActiveElementRef.current;
|
|
2204
|
+
if (elementToReturn && typeof elementToReturn.focus === "function") {
|
|
2205
|
+
elementToReturn.focus({ preventScroll });
|
|
2206
|
+
}
|
|
2207
|
+
};
|
|
2208
|
+
}, [active, initialFocus, returnFocusTo, handleKeyDown, preventScroll]);
|
|
2209
|
+
return containerRef;
|
|
2210
|
+
}
|
|
2211
|
+
|
|
2212
|
+
// src/hooks/useFocusRef.ts
|
|
2213
|
+
import { useRef as useRef4, useEffect as useEffect6 } from "react";
|
|
2214
|
+
function useFocusRef(options = {}) {
|
|
2215
|
+
const { focusOnMount = false, preventScroll = false, delay = 0 } = options;
|
|
2216
|
+
const ref = useRef4(null);
|
|
2217
|
+
useEffect6(() => {
|
|
2218
|
+
if (!focusOnMount) return;
|
|
2219
|
+
const focus = () => {
|
|
2220
|
+
if (ref.current && typeof ref.current.focus === "function") {
|
|
2221
|
+
ref.current.focus({ preventScroll });
|
|
2222
|
+
}
|
|
2223
|
+
};
|
|
2224
|
+
if (delay > 0) {
|
|
2225
|
+
const timer = setTimeout(focus, delay);
|
|
2226
|
+
return () => clearTimeout(timer);
|
|
2227
|
+
} else {
|
|
2228
|
+
const frame = requestAnimationFrame(focus);
|
|
2229
|
+
return () => cancelAnimationFrame(frame);
|
|
2230
|
+
}
|
|
2231
|
+
}, [focusOnMount, preventScroll, delay]);
|
|
2232
|
+
return ref;
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
// src/hooks/useReducedMotion.ts
|
|
2236
|
+
import { useState as useState6, useEffect as useEffect7 } from "react";
|
|
2237
|
+
function useReducedMotion() {
|
|
2238
|
+
const [reducedMotion, setReducedMotion] = useState6(false);
|
|
2239
|
+
useEffect7(() => {
|
|
2240
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
2241
|
+
setReducedMotion(mediaQuery.matches);
|
|
2242
|
+
const handleChange = (event) => {
|
|
2243
|
+
setReducedMotion(event.matches);
|
|
2244
|
+
};
|
|
2245
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
2246
|
+
return () => {
|
|
2247
|
+
mediaQuery.removeEventListener("change", handleChange);
|
|
2248
|
+
};
|
|
2249
|
+
}, []);
|
|
2250
|
+
return reducedMotion;
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2253
|
+
// src/hooks/useArrowNavigation.ts
|
|
2254
|
+
import { useCallback as useCallback4, useRef as useRef5 } from "react";
|
|
2255
|
+
var DEFAULT_SELECTOR = '[role="menuitem"], [role="option"], [role="tab"], button, a, [tabindex]:not([tabindex="-1"])';
|
|
2256
|
+
function useArrowNavigation(options = {}) {
|
|
2257
|
+
const {
|
|
2258
|
+
orientation = "vertical",
|
|
2259
|
+
loop = true,
|
|
2260
|
+
itemSelector = DEFAULT_SELECTOR,
|
|
2261
|
+
onFocusChange
|
|
2262
|
+
} = options;
|
|
2263
|
+
const containerRef = useRef5(null);
|
|
2264
|
+
const focusedIndexRef = useRef5(-1);
|
|
2265
|
+
const getFocusableItems = useCallback4(() => {
|
|
2266
|
+
if (!containerRef.current) return [];
|
|
2267
|
+
return Array.from(containerRef.current.querySelectorAll(itemSelector));
|
|
2268
|
+
}, [itemSelector]);
|
|
2269
|
+
const focusItem = useCallback4(
|
|
2270
|
+
(index) => {
|
|
2271
|
+
const items = getFocusableItems();
|
|
2272
|
+
if (items.length === 0) return;
|
|
2273
|
+
let targetIndex = index;
|
|
2274
|
+
if (loop) {
|
|
2275
|
+
if (targetIndex < 0) targetIndex = items.length - 1;
|
|
2276
|
+
if (targetIndex >= items.length) targetIndex = 0;
|
|
2277
|
+
} else {
|
|
2278
|
+
targetIndex = Math.max(0, Math.min(targetIndex, items.length - 1));
|
|
2279
|
+
}
|
|
2280
|
+
const element = items[targetIndex];
|
|
2281
|
+
if (element) {
|
|
2282
|
+
element.focus();
|
|
2283
|
+
focusedIndexRef.current = targetIndex;
|
|
2284
|
+
onFocusChange?.(targetIndex, element);
|
|
2285
|
+
}
|
|
2286
|
+
},
|
|
2287
|
+
[getFocusableItems, loop, onFocusChange]
|
|
2288
|
+
);
|
|
2289
|
+
const handleKeyDown = useCallback4(
|
|
2290
|
+
(event) => {
|
|
2291
|
+
const items = getFocusableItems();
|
|
2292
|
+
if (items.length === 0) return;
|
|
2293
|
+
const currentIndex = focusedIndexRef.current;
|
|
2294
|
+
let handled = false;
|
|
2295
|
+
switch (event.key) {
|
|
2296
|
+
case "ArrowUp":
|
|
2297
|
+
if (orientation === "vertical" || orientation === "both") {
|
|
2298
|
+
focusItem(currentIndex - 1);
|
|
2299
|
+
handled = true;
|
|
2300
|
+
}
|
|
2301
|
+
break;
|
|
2302
|
+
case "ArrowDown":
|
|
2303
|
+
if (orientation === "vertical" || orientation === "both") {
|
|
2304
|
+
focusItem(currentIndex + 1);
|
|
2305
|
+
handled = true;
|
|
2306
|
+
}
|
|
2307
|
+
break;
|
|
2308
|
+
case "ArrowLeft":
|
|
2309
|
+
if (orientation === "horizontal" || orientation === "both") {
|
|
2310
|
+
focusItem(currentIndex - 1);
|
|
2311
|
+
handled = true;
|
|
2312
|
+
}
|
|
2313
|
+
break;
|
|
2314
|
+
case "ArrowRight":
|
|
2315
|
+
if (orientation === "horizontal" || orientation === "both") {
|
|
2316
|
+
focusItem(currentIndex + 1);
|
|
2317
|
+
handled = true;
|
|
2318
|
+
}
|
|
2319
|
+
break;
|
|
2320
|
+
case "Home":
|
|
2321
|
+
focusItem(0);
|
|
2322
|
+
handled = true;
|
|
2323
|
+
break;
|
|
2324
|
+
case "End":
|
|
2325
|
+
focusItem(items.length - 1);
|
|
2326
|
+
handled = true;
|
|
2327
|
+
break;
|
|
2328
|
+
}
|
|
2329
|
+
if (handled) {
|
|
2330
|
+
event.preventDefault();
|
|
2331
|
+
event.stopPropagation();
|
|
2332
|
+
}
|
|
2333
|
+
},
|
|
2334
|
+
[orientation, focusItem, getFocusableItems]
|
|
2335
|
+
);
|
|
2336
|
+
const handleFocus = useCallback4(
|
|
2337
|
+
(event) => {
|
|
2338
|
+
const items = getFocusableItems();
|
|
2339
|
+
const index = items.indexOf(event.target);
|
|
2340
|
+
if (index !== -1) {
|
|
2341
|
+
focusedIndexRef.current = index;
|
|
2342
|
+
}
|
|
2343
|
+
},
|
|
2344
|
+
[getFocusableItems]
|
|
2345
|
+
);
|
|
2346
|
+
const containerProps = {
|
|
2347
|
+
ref: (node) => {
|
|
2348
|
+
containerRef.current = node;
|
|
2349
|
+
},
|
|
2350
|
+
onKeyDown: handleKeyDown,
|
|
2351
|
+
onFocus: handleFocus
|
|
2352
|
+
};
|
|
2353
|
+
const getItemProps = useCallback4(
|
|
2354
|
+
(index) => ({
|
|
2355
|
+
tabIndex: index === 0 ? 0 : -1,
|
|
2356
|
+
onFocus: () => {
|
|
2357
|
+
focusedIndexRef.current = index;
|
|
2358
|
+
}
|
|
2359
|
+
}),
|
|
2360
|
+
[]
|
|
2361
|
+
);
|
|
2362
|
+
return {
|
|
2363
|
+
containerProps,
|
|
2364
|
+
getItemProps,
|
|
2365
|
+
focusItem,
|
|
2366
|
+
getFocusedIndex: () => focusedIndexRef.current
|
|
2367
|
+
};
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
// src/hooks/useRovingTabindex.ts
|
|
2371
|
+
import { useState as useState7, useCallback as useCallback5, useRef as useRef6 } from "react";
|
|
2372
|
+
var DEFAULT_SELECTOR2 = "[data-roving-tabindex-item]";
|
|
2373
|
+
function useRovingTabindex(options = {}) {
|
|
2374
|
+
const { loop = true, itemSelector = DEFAULT_SELECTOR2, initialIndex = 0, onIndexChange } = options;
|
|
2375
|
+
const [activeIndex, setActiveIndex] = useState7(initialIndex);
|
|
2376
|
+
const containerRef = useRef6(null);
|
|
2377
|
+
const itemsRef = useRef6(/* @__PURE__ */ new Map());
|
|
2378
|
+
const getItems = useCallback5(() => {
|
|
2379
|
+
if (!containerRef.current) {
|
|
2380
|
+
return Array.from(itemsRef.current.values());
|
|
2381
|
+
}
|
|
2382
|
+
return Array.from(containerRef.current.querySelectorAll(itemSelector));
|
|
2383
|
+
}, [itemSelector]);
|
|
2384
|
+
const focusIndex = useCallback5(
|
|
2385
|
+
(index) => {
|
|
2386
|
+
const items = getItems();
|
|
2387
|
+
if (items.length === 0) return;
|
|
2388
|
+
let targetIndex = index;
|
|
2389
|
+
if (loop) {
|
|
2390
|
+
if (targetIndex < 0) targetIndex = items.length - 1;
|
|
2391
|
+
if (targetIndex >= items.length) targetIndex = 0;
|
|
2392
|
+
} else {
|
|
2393
|
+
targetIndex = Math.max(0, Math.min(targetIndex, items.length - 1));
|
|
2394
|
+
}
|
|
2395
|
+
setActiveIndex(targetIndex);
|
|
2396
|
+
onIndexChange?.(targetIndex);
|
|
2397
|
+
const element = items[targetIndex];
|
|
2398
|
+
if (element) {
|
|
2399
|
+
element.focus();
|
|
2400
|
+
}
|
|
2401
|
+
},
|
|
2402
|
+
[getItems, loop, onIndexChange]
|
|
2403
|
+
);
|
|
2404
|
+
const handleKeyDown = useCallback5(
|
|
2405
|
+
(event) => {
|
|
2406
|
+
const items = getItems();
|
|
2407
|
+
if (items.length === 0) return;
|
|
2408
|
+
let handled = false;
|
|
2409
|
+
switch (event.key) {
|
|
2410
|
+
case "ArrowUp":
|
|
2411
|
+
case "ArrowLeft":
|
|
2412
|
+
focusIndex(activeIndex - 1);
|
|
2413
|
+
handled = true;
|
|
2414
|
+
break;
|
|
2415
|
+
case "ArrowDown":
|
|
2416
|
+
case "ArrowRight":
|
|
2417
|
+
focusIndex(activeIndex + 1);
|
|
2418
|
+
handled = true;
|
|
2419
|
+
break;
|
|
2420
|
+
case "Home":
|
|
2421
|
+
focusIndex(0);
|
|
2422
|
+
handled = true;
|
|
2423
|
+
break;
|
|
2424
|
+
case "End":
|
|
2425
|
+
focusIndex(items.length - 1);
|
|
2426
|
+
handled = true;
|
|
2427
|
+
break;
|
|
2428
|
+
}
|
|
2429
|
+
if (handled) {
|
|
2430
|
+
event.preventDefault();
|
|
2431
|
+
event.stopPropagation();
|
|
2432
|
+
}
|
|
2433
|
+
},
|
|
2434
|
+
[activeIndex, focusIndex, getItems]
|
|
2435
|
+
);
|
|
2436
|
+
const containerProps = {
|
|
2437
|
+
ref: (node) => {
|
|
2438
|
+
containerRef.current = node;
|
|
2439
|
+
},
|
|
2440
|
+
onKeyDown: handleKeyDown
|
|
2441
|
+
};
|
|
2442
|
+
const getItemProps = useCallback5(
|
|
2443
|
+
(index) => ({
|
|
2444
|
+
"data-roving-tabindex-item": true,
|
|
2445
|
+
tabIndex: index === activeIndex ? 0 : -1,
|
|
2446
|
+
ref: (node) => {
|
|
2447
|
+
if (node) {
|
|
2448
|
+
itemsRef.current.set(index, node);
|
|
2449
|
+
} else {
|
|
2450
|
+
itemsRef.current.delete(index);
|
|
2451
|
+
}
|
|
2452
|
+
},
|
|
2453
|
+
onClick: () => {
|
|
2454
|
+
setActiveIndex(index);
|
|
2455
|
+
onIndexChange?.(index);
|
|
2456
|
+
},
|
|
2457
|
+
onFocus: () => {
|
|
2458
|
+
if (activeIndex !== index) {
|
|
2459
|
+
setActiveIndex(index);
|
|
2460
|
+
onIndexChange?.(index);
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
}),
|
|
2464
|
+
[activeIndex, onIndexChange]
|
|
2465
|
+
);
|
|
2466
|
+
return {
|
|
2467
|
+
containerProps,
|
|
2468
|
+
getItemProps,
|
|
2469
|
+
activeIndex,
|
|
2470
|
+
setActiveIndex: focusIndex,
|
|
2471
|
+
focusNext: () => focusIndex(activeIndex + 1),
|
|
2472
|
+
focusPrevious: () => focusIndex(activeIndex - 1),
|
|
2473
|
+
focusFirst: () => focusIndex(0),
|
|
2474
|
+
focusLast: () => focusIndex(getItems().length - 1)
|
|
2475
|
+
};
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
// src/hooks/useEscapeKey.ts
|
|
2479
|
+
import * as React23 from "react";
|
|
2480
|
+
function useEscapeKey(callback, options) {
|
|
2481
|
+
const { enabled = true, preventDefault = true, stopPropagation = false } = options ?? {};
|
|
2482
|
+
const callbackRef = React23.useRef(callback);
|
|
2483
|
+
React23.useEffect(() => {
|
|
2484
|
+
callbackRef.current = callback;
|
|
2485
|
+
}, [callback]);
|
|
2486
|
+
React23.useEffect(() => {
|
|
2487
|
+
if (!enabled) return;
|
|
2488
|
+
const handleKeyDown = (event) => {
|
|
2489
|
+
if (event.key === "Escape") {
|
|
2490
|
+
if (preventDefault) {
|
|
2491
|
+
event.preventDefault();
|
|
2492
|
+
}
|
|
2493
|
+
if (stopPropagation) {
|
|
2494
|
+
event.stopPropagation();
|
|
2495
|
+
}
|
|
2496
|
+
callbackRef.current(event);
|
|
2497
|
+
}
|
|
2498
|
+
};
|
|
2499
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
2500
|
+
return () => {
|
|
2501
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
2502
|
+
};
|
|
2503
|
+
}, [enabled, preventDefault, stopPropagation]);
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
// src/hooks/useClickOutside.ts
|
|
2507
|
+
import * as React24 from "react";
|
|
2508
|
+
function useClickOutside(ref, callback, options) {
|
|
2509
|
+
const {
|
|
2510
|
+
enabled = true,
|
|
2511
|
+
events = ["mousedown", "touchstart"],
|
|
2512
|
+
ignoreElements = []
|
|
2513
|
+
} = options ?? {};
|
|
2514
|
+
const callbackRef = React24.useRef(callback);
|
|
2515
|
+
React24.useEffect(() => {
|
|
2516
|
+
callbackRef.current = callback;
|
|
2517
|
+
}, [callback]);
|
|
2518
|
+
React24.useEffect(() => {
|
|
2519
|
+
if (!enabled) return;
|
|
2520
|
+
const handleEvent = (event) => {
|
|
2521
|
+
const target = event.target;
|
|
2522
|
+
if (ref.current?.contains(target)) {
|
|
2523
|
+
return;
|
|
2524
|
+
}
|
|
2525
|
+
for (const ignoreRef of ignoreElements) {
|
|
2526
|
+
if (ignoreRef.current?.contains(target)) {
|
|
2527
|
+
return;
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
callbackRef.current(event);
|
|
2531
|
+
};
|
|
2532
|
+
events.forEach((eventType) => {
|
|
2533
|
+
document.addEventListener(eventType, handleEvent);
|
|
2534
|
+
});
|
|
2535
|
+
return () => {
|
|
2536
|
+
events.forEach((eventType) => {
|
|
2537
|
+
document.removeEventListener(eventType, handleEvent);
|
|
2538
|
+
});
|
|
2539
|
+
};
|
|
2540
|
+
}, [enabled, events, ignoreElements, ref]);
|
|
2541
|
+
}
|
|
1348
2542
|
export {
|
|
1349
2543
|
Avatar,
|
|
1350
2544
|
AvatarFallback,
|
|
@@ -1374,9 +2568,18 @@ export {
|
|
|
1374
2568
|
DialogTrigger,
|
|
1375
2569
|
Input,
|
|
1376
2570
|
Label,
|
|
2571
|
+
LiveRegion,
|
|
2572
|
+
LoadingLogo,
|
|
2573
|
+
LoadingOverlay,
|
|
2574
|
+
LoadingPage,
|
|
2575
|
+
LoadingSection,
|
|
1377
2576
|
PageHeader,
|
|
1378
2577
|
PasswordInput,
|
|
2578
|
+
ProgressBar,
|
|
1379
2579
|
Separator,
|
|
2580
|
+
Skeleton,
|
|
2581
|
+
SkipLink,
|
|
2582
|
+
Spinner,
|
|
1380
2583
|
Switch,
|
|
1381
2584
|
badgeVariants,
|
|
1382
2585
|
buttonVariants,
|
|
@@ -1385,5 +2588,16 @@ export {
|
|
|
1385
2588
|
pageHeaderContainerVariants,
|
|
1386
2589
|
pageHeaderSubtitleVariants,
|
|
1387
2590
|
pageHeaderTitleVariants,
|
|
1388
|
-
|
|
2591
|
+
progressBarVariants,
|
|
2592
|
+
skeletonVariants,
|
|
2593
|
+
spinnerVariants,
|
|
2594
|
+
useAnnounce,
|
|
2595
|
+
useArrowNavigation,
|
|
2596
|
+
useClickOutside,
|
|
2597
|
+
useDataPanel,
|
|
2598
|
+
useEscapeKey,
|
|
2599
|
+
useFocusRef,
|
|
2600
|
+
useFocusTrap,
|
|
2601
|
+
useReducedMotion,
|
|
2602
|
+
useRovingTabindex
|
|
1389
2603
|
};
|