@kjaniec-dev/ui 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3824 -180
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +666 -3
- package/dist/index.d.ts +666 -3
- package/dist/index.js +3764 -180
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var clsx = require('clsx');
|
|
4
4
|
var tailwindMerge = require('tailwind-merge');
|
|
5
|
-
var
|
|
5
|
+
var React52 = require('react');
|
|
6
6
|
var classVarianceAuthority = require('class-variance-authority');
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
|
|
@@ -24,7 +24,7 @@ function _interopNamespace(e) {
|
|
|
24
24
|
return Object.freeze(n);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
var
|
|
27
|
+
var React52__namespace = /*#__PURE__*/_interopNamespace(React52);
|
|
28
28
|
|
|
29
29
|
// src/lib/cn.ts
|
|
30
30
|
function cn(...inputs) {
|
|
@@ -60,7 +60,7 @@ var buttonVariants = classVarianceAuthority.cva(
|
|
|
60
60
|
defaultVariants: { variant: "primary", size: "md" }
|
|
61
61
|
}
|
|
62
62
|
);
|
|
63
|
-
var Button =
|
|
63
|
+
var Button = React52__namespace.forwardRef(
|
|
64
64
|
({ className, variant, size, loading, leadingIcon, trailingIcon, children, disabled, ...props }, ref) => {
|
|
65
65
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
66
66
|
"button",
|
|
@@ -107,7 +107,7 @@ var badgeVariants = classVarianceAuthority.cva(
|
|
|
107
107
|
defaultVariants: { variant: "neutral" }
|
|
108
108
|
}
|
|
109
109
|
);
|
|
110
|
-
var Badge =
|
|
110
|
+
var Badge = React52__namespace.forwardRef(
|
|
111
111
|
({ className, variant, dot, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs("span", { ref, className: cn(badgeVariants({ variant }), className), ...props, children: [
|
|
112
112
|
dot && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-current", "aria-hidden": true }),
|
|
113
113
|
children
|
|
@@ -134,7 +134,7 @@ var iconColor = {
|
|
|
134
134
|
warning: "text-warning",
|
|
135
135
|
danger: "text-danger"
|
|
136
136
|
};
|
|
137
|
-
var Alert =
|
|
137
|
+
var Alert = React52__namespace.forwardRef(
|
|
138
138
|
({ className, variant = "info", icon, title, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, role: "alert", className: cn(alertVariants({ variant }), className), ...props, children: [
|
|
139
139
|
icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("shrink-0 mt-0.5 [&_svg]:h-[1.15rem] [&_svg]:w-[1.15rem]", iconColor[variant ?? "info"]), children: icon }),
|
|
140
140
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-foreground", children: [
|
|
@@ -144,7 +144,7 @@ var Alert = React18__namespace.forwardRef(
|
|
|
144
144
|
] })
|
|
145
145
|
);
|
|
146
146
|
Alert.displayName = "Alert";
|
|
147
|
-
var Spinner =
|
|
147
|
+
var Spinner = React52__namespace.forwardRef(
|
|
148
148
|
({ className, size = 24, style, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
149
149
|
"span",
|
|
150
150
|
{
|
|
@@ -161,7 +161,7 @@ var Spinner = React18__namespace.forwardRef(
|
|
|
161
161
|
)
|
|
162
162
|
);
|
|
163
163
|
Spinner.displayName = "Spinner";
|
|
164
|
-
var Progress =
|
|
164
|
+
var Progress = React52__namespace.forwardRef(
|
|
165
165
|
({ className, value = 0, tone = "primary", barClassName, ...props }, ref) => {
|
|
166
166
|
const pct = Math.max(0, Math.min(100, value));
|
|
167
167
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -191,14 +191,14 @@ var Progress = React18__namespace.forwardRef(
|
|
|
191
191
|
}
|
|
192
192
|
);
|
|
193
193
|
Progress.displayName = "Progress";
|
|
194
|
-
var Label =
|
|
194
|
+
var Label = React52__namespace.forwardRef(
|
|
195
195
|
({ className, required, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs("label", { ref, className: cn("text-[0.8rem] font-semibold text-foreground", className), ...props, children: [
|
|
196
196
|
children,
|
|
197
197
|
required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-danger", children: " *" })
|
|
198
198
|
] })
|
|
199
199
|
);
|
|
200
200
|
Label.displayName = "Label";
|
|
201
|
-
var Hint =
|
|
201
|
+
var Hint = React52__namespace.forwardRef(
|
|
202
202
|
({ className, error, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
203
203
|
"span",
|
|
204
204
|
{
|
|
@@ -209,17 +209,17 @@ var Hint = React18__namespace.forwardRef(
|
|
|
209
209
|
)
|
|
210
210
|
);
|
|
211
211
|
Hint.displayName = "Hint";
|
|
212
|
-
var Field =
|
|
212
|
+
var Field = React52__namespace.forwardRef(
|
|
213
213
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex flex-col gap-1.5", className), ...props })
|
|
214
214
|
);
|
|
215
215
|
Field.displayName = "Field";
|
|
216
|
-
var FormField =
|
|
216
|
+
var FormField = React52__namespace.forwardRef(
|
|
217
217
|
({ className, label, hint, error, required, children, ...props }, ref) => {
|
|
218
|
-
const id =
|
|
218
|
+
const id = React52__namespace.useId();
|
|
219
219
|
const hintId = `${id}-hint`;
|
|
220
220
|
const errorId = `${id}-error`;
|
|
221
|
-
const child =
|
|
222
|
-
const clonedChild =
|
|
221
|
+
const child = React52__namespace.Children.only(children);
|
|
222
|
+
const clonedChild = React52__namespace.cloneElement(child, {
|
|
223
223
|
id: child.props.id ?? id,
|
|
224
224
|
"aria-describedby": cn(
|
|
225
225
|
hint && hintId,
|
|
@@ -238,9 +238,136 @@ var FormField = React18__namespace.forwardRef(
|
|
|
238
238
|
}
|
|
239
239
|
);
|
|
240
240
|
FormField.displayName = "FormField";
|
|
241
|
+
var sizeDimensions = {
|
|
242
|
+
sm: 36,
|
|
243
|
+
md: 64,
|
|
244
|
+
lg: 96,
|
|
245
|
+
xl: 128
|
|
246
|
+
};
|
|
247
|
+
var defaultStrokeWidths = {
|
|
248
|
+
sm: 3.5,
|
|
249
|
+
md: 6,
|
|
250
|
+
lg: 8,
|
|
251
|
+
xl: 10
|
|
252
|
+
};
|
|
253
|
+
var textSizeClasses = {
|
|
254
|
+
sm: "text-[0.65rem] font-semibold leading-none",
|
|
255
|
+
md: "text-xs font-semibold leading-none",
|
|
256
|
+
lg: "text-base font-bold leading-none",
|
|
257
|
+
xl: "text-xl font-bold leading-none"
|
|
258
|
+
};
|
|
259
|
+
var toneClasses = {
|
|
260
|
+
primary: "text-primary stroke-current",
|
|
261
|
+
secondary: "text-secondary stroke-current",
|
|
262
|
+
success: "text-success stroke-current",
|
|
263
|
+
warning: "text-warning stroke-current",
|
|
264
|
+
danger: "text-danger stroke-current",
|
|
265
|
+
info: "text-info stroke-current"
|
|
266
|
+
};
|
|
267
|
+
var ProgressRing = React52__namespace.forwardRef(
|
|
268
|
+
({
|
|
269
|
+
className,
|
|
270
|
+
style,
|
|
271
|
+
value = 0,
|
|
272
|
+
min = 0,
|
|
273
|
+
max = 100,
|
|
274
|
+
size = "md",
|
|
275
|
+
strokeWidth,
|
|
276
|
+
tone = "primary",
|
|
277
|
+
showValue = false,
|
|
278
|
+
formatValue,
|
|
279
|
+
trackClassName,
|
|
280
|
+
indicatorClassName,
|
|
281
|
+
children,
|
|
282
|
+
"aria-label": ariaLabel,
|
|
283
|
+
...props
|
|
284
|
+
}, ref) => {
|
|
285
|
+
const range2 = max > min ? max - min : 100;
|
|
286
|
+
const clampedValue = Math.max(min, Math.min(max, value));
|
|
287
|
+
const percentage = Math.max(0, Math.min(100, (clampedValue - min) / range2 * 100));
|
|
288
|
+
const dimension = sizeDimensions[size];
|
|
289
|
+
const strokeWidthVal = strokeWidth ?? defaultStrokeWidths[size];
|
|
290
|
+
const radius = Math.max(0, (dimension - strokeWidthVal) / 2);
|
|
291
|
+
const circumference = 2 * Math.PI * radius;
|
|
292
|
+
const strokeDashoffset = circumference - percentage / 100 * circumference;
|
|
293
|
+
const computedAriaLabel = ariaLabel ?? (props["aria-labelledby"] ? void 0 : "Progress");
|
|
294
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
295
|
+
"div",
|
|
296
|
+
{
|
|
297
|
+
ref,
|
|
298
|
+
role: "progressbar",
|
|
299
|
+
"aria-label": computedAriaLabel,
|
|
300
|
+
"aria-valuenow": clampedValue,
|
|
301
|
+
"aria-valuemin": min,
|
|
302
|
+
"aria-valuemax": max,
|
|
303
|
+
className: cn("relative inline-flex items-center justify-center shrink-0", className),
|
|
304
|
+
style: { width: dimension, height: dimension, ...style },
|
|
305
|
+
...props,
|
|
306
|
+
children: [
|
|
307
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
308
|
+
"svg",
|
|
309
|
+
{
|
|
310
|
+
width: dimension,
|
|
311
|
+
height: dimension,
|
|
312
|
+
viewBox: `0 0 ${dimension} ${dimension}`,
|
|
313
|
+
className: "-rotate-90 transform",
|
|
314
|
+
children: [
|
|
315
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
316
|
+
"circle",
|
|
317
|
+
{
|
|
318
|
+
cx: dimension / 2,
|
|
319
|
+
cy: dimension / 2,
|
|
320
|
+
r: radius,
|
|
321
|
+
strokeWidth: strokeWidthVal,
|
|
322
|
+
className: cn("stroke-muted/30 fill-none", trackClassName)
|
|
323
|
+
}
|
|
324
|
+
),
|
|
325
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
326
|
+
"circle",
|
|
327
|
+
{
|
|
328
|
+
cx: dimension / 2,
|
|
329
|
+
cy: dimension / 2,
|
|
330
|
+
r: radius,
|
|
331
|
+
strokeWidth: strokeWidthVal,
|
|
332
|
+
strokeDasharray: circumference,
|
|
333
|
+
strokeDashoffset,
|
|
334
|
+
strokeLinecap: percentage === 0 ? "butt" : "round",
|
|
335
|
+
className: cn(
|
|
336
|
+
"fill-none transition-[stroke-dashoffset,opacity] duration-500 ease-in-out",
|
|
337
|
+
percentage === 0 && "opacity-0",
|
|
338
|
+
toneClasses[tone],
|
|
339
|
+
indicatorClassName
|
|
340
|
+
)
|
|
341
|
+
}
|
|
342
|
+
)
|
|
343
|
+
]
|
|
344
|
+
}
|
|
345
|
+
),
|
|
346
|
+
(children || showValue) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
347
|
+
"div",
|
|
348
|
+
{
|
|
349
|
+
className: cn(
|
|
350
|
+
"absolute inset-0 flex flex-col items-center justify-center text-center text-foreground p-1",
|
|
351
|
+
textSizeClasses[size]
|
|
352
|
+
),
|
|
353
|
+
children: children ?? (formatValue ? formatValue(clampedValue, Math.round(percentage)) : `${Math.round(percentage)}%`)
|
|
354
|
+
}
|
|
355
|
+
)
|
|
356
|
+
]
|
|
357
|
+
}
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
);
|
|
361
|
+
ProgressRing.displayName = "ProgressRing";
|
|
362
|
+
var ProgressRingField = React52__namespace.forwardRef(
|
|
363
|
+
({ label, hint, error, required, fieldClassName, ...ringProps }, ref) => {
|
|
364
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className: fieldClassName, children: /* @__PURE__ */ jsxRuntime.jsx(ProgressRing, { ref, "aria-label": ringProps["aria-label"] ?? label, ...ringProps }) });
|
|
365
|
+
}
|
|
366
|
+
);
|
|
367
|
+
ProgressRingField.displayName = "ProgressRingField";
|
|
241
368
|
var baseField = "w-full font-sans text-sm text-foreground bg-surface border rounded-kj-md px-[0.85rem] transition-[border-color,box-shadow] duration-150 placeholder:text-muted-foreground focus:outline-none focus:border-ring focus:ring-[3px] focus:ring-ring/30 disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed";
|
|
242
|
-
var Input =
|
|
243
|
-
({ className, error, leadingIcon,
|
|
369
|
+
var Input = React52__namespace.forwardRef(
|
|
370
|
+
({ className, error, leadingIcon, ...props }, ref) => {
|
|
244
371
|
const field = /* @__PURE__ */ jsxRuntime.jsx(
|
|
245
372
|
"input",
|
|
246
373
|
{
|
|
@@ -264,7 +391,7 @@ var Input = React18__namespace.forwardRef(
|
|
|
264
391
|
}
|
|
265
392
|
);
|
|
266
393
|
Input.displayName = "Input";
|
|
267
|
-
var Textarea =
|
|
394
|
+
var Textarea = React52__namespace.forwardRef(
|
|
268
395
|
({ className, error, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
269
396
|
"textarea",
|
|
270
397
|
{
|
|
@@ -281,14 +408,14 @@ var Textarea = React18__namespace.forwardRef(
|
|
|
281
408
|
)
|
|
282
409
|
);
|
|
283
410
|
Textarea.displayName = "Textarea";
|
|
284
|
-
var TextField =
|
|
411
|
+
var TextField = React52__namespace.forwardRef(
|
|
285
412
|
({ label, hint, error, required, className, ...props }, ref) => {
|
|
286
413
|
return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsxRuntime.jsx(Input, { ref, error: !!error, ...props }) });
|
|
287
414
|
}
|
|
288
415
|
);
|
|
289
416
|
TextField.displayName = "TextField";
|
|
290
417
|
var chevron = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E";
|
|
291
|
-
var Select =
|
|
418
|
+
var Select = React52__namespace.forwardRef(
|
|
292
419
|
({ className, error, style, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
293
420
|
"select",
|
|
294
421
|
{
|
|
@@ -316,15 +443,15 @@ var Select = React18__namespace.forwardRef(
|
|
|
316
443
|
)
|
|
317
444
|
);
|
|
318
445
|
Select.displayName = "Select";
|
|
319
|
-
var SelectField =
|
|
446
|
+
var SelectField = React52__namespace.forwardRef(
|
|
320
447
|
({ label, hint, error, required, className, children, ...props }, ref) => {
|
|
321
448
|
return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsxRuntime.jsx(Select, { ref, error: !!error, ...props, children }) });
|
|
322
449
|
}
|
|
323
450
|
);
|
|
324
451
|
SelectField.displayName = "SelectField";
|
|
325
|
-
var Checkbox =
|
|
452
|
+
var Checkbox = React52__namespace.forwardRef(
|
|
326
453
|
({ className, label, id, ...props }, ref) => {
|
|
327
|
-
const autoId =
|
|
454
|
+
const autoId = React52__namespace.useId();
|
|
328
455
|
const inputId = id ?? autoId;
|
|
329
456
|
return /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: inputId, className: cn("inline-flex items-center gap-2.5 cursor-pointer text-sm select-none", className), children: [
|
|
330
457
|
/* @__PURE__ */ jsxRuntime.jsx("input", { ref, id: inputId, type: "checkbox", className: "peer sr-only", ...props }),
|
|
@@ -334,9 +461,9 @@ var Checkbox = React18__namespace.forwardRef(
|
|
|
334
461
|
}
|
|
335
462
|
);
|
|
336
463
|
Checkbox.displayName = "Checkbox";
|
|
337
|
-
var Radio =
|
|
464
|
+
var Radio = React52__namespace.forwardRef(
|
|
338
465
|
({ className, label, id, ...props }, ref) => {
|
|
339
|
-
const autoId =
|
|
466
|
+
const autoId = React52__namespace.useId();
|
|
340
467
|
const inputId = id ?? autoId;
|
|
341
468
|
return /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: inputId, className: cn("inline-flex items-center gap-2.5 cursor-pointer text-sm select-none", className), children: [
|
|
342
469
|
/* @__PURE__ */ jsxRuntime.jsx("input", { ref, id: inputId, type: "radio", className: "peer sr-only", ...props }),
|
|
@@ -346,9 +473,9 @@ var Radio = React18__namespace.forwardRef(
|
|
|
346
473
|
}
|
|
347
474
|
);
|
|
348
475
|
Radio.displayName = "Radio";
|
|
349
|
-
var CheckboxField =
|
|
476
|
+
var CheckboxField = React52__namespace.forwardRef(
|
|
350
477
|
({ label, hint, error, className, ...props }, ref) => {
|
|
351
|
-
const id =
|
|
478
|
+
const id = React52__namespace.useId();
|
|
352
479
|
const hintId = `${id}-hint`;
|
|
353
480
|
const errorId = `${id}-error`;
|
|
354
481
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1 w-full", className), children: [
|
|
@@ -369,9 +496,9 @@ var CheckboxField = React18__namespace.forwardRef(
|
|
|
369
496
|
}
|
|
370
497
|
);
|
|
371
498
|
CheckboxField.displayName = "CheckboxField";
|
|
372
|
-
var Switch =
|
|
499
|
+
var Switch = React52__namespace.forwardRef(
|
|
373
500
|
({ className, label, id, ...props }, ref) => {
|
|
374
|
-
const autoId =
|
|
501
|
+
const autoId = React52__namespace.useId();
|
|
375
502
|
const inputId = id ?? autoId;
|
|
376
503
|
return /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: inputId, className: cn("inline-flex items-center gap-2.5 cursor-pointer text-sm select-none", className), children: [
|
|
377
504
|
/* @__PURE__ */ jsxRuntime.jsx("input", { ref, id: inputId, type: "checkbox", role: "switch", className: "peer sr-only", ...props }),
|
|
@@ -381,19 +508,47 @@ var Switch = React18__namespace.forwardRef(
|
|
|
381
508
|
}
|
|
382
509
|
);
|
|
383
510
|
Switch.displayName = "Switch";
|
|
384
|
-
var Slider =
|
|
385
|
-
({ className, ...props }, ref) =>
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
511
|
+
var Slider = React52__namespace.forwardRef(
|
|
512
|
+
({ className, style, value, defaultValue, min = 0, max = 100, onChange, ...props }, ref) => {
|
|
513
|
+
const [localValue, setLocalValue] = React52__namespace.useState(
|
|
514
|
+
Number(defaultValue ?? value ?? 50)
|
|
515
|
+
);
|
|
516
|
+
const isControlled = value !== void 0;
|
|
517
|
+
const currentVal = isControlled ? Number(value) : localValue;
|
|
518
|
+
const numMin = Number(min);
|
|
519
|
+
const numMax = Number(max);
|
|
520
|
+
const percentage = Math.min(
|
|
521
|
+
100,
|
|
522
|
+
Math.max(0, (currentVal - numMin) / (numMax - numMin) * 100)
|
|
523
|
+
);
|
|
524
|
+
const handleChange = (e) => {
|
|
525
|
+
if (!isControlled) {
|
|
526
|
+
setLocalValue(Number(e.target.value));
|
|
527
|
+
}
|
|
528
|
+
onChange?.(e);
|
|
529
|
+
};
|
|
530
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
531
|
+
"input",
|
|
532
|
+
{
|
|
533
|
+
ref,
|
|
534
|
+
type: "range",
|
|
535
|
+
value,
|
|
536
|
+
defaultValue,
|
|
537
|
+
min,
|
|
538
|
+
max,
|
|
539
|
+
onChange: handleChange,
|
|
540
|
+
style: {
|
|
541
|
+
background: `linear-gradient(to right, var(--kj-primary) ${percentage}%, var(--kj-border, rgba(120, 120, 128, 0.2)) ${percentage}%)`,
|
|
542
|
+
...style
|
|
543
|
+
},
|
|
544
|
+
className: cn(
|
|
545
|
+
"kj-slider w-full h-1.5 rounded-full appearance-none cursor-pointer accent-primary",
|
|
546
|
+
className
|
|
547
|
+
),
|
|
548
|
+
...props
|
|
549
|
+
}
|
|
550
|
+
);
|
|
551
|
+
}
|
|
397
552
|
);
|
|
398
553
|
Slider.displayName = "Slider";
|
|
399
554
|
var sliderThumbCSS = `
|
|
@@ -434,7 +589,47 @@ function Segmented({
|
|
|
434
589
|
}
|
|
435
590
|
);
|
|
436
591
|
}
|
|
437
|
-
|
|
592
|
+
function ToggleGroup({
|
|
593
|
+
options,
|
|
594
|
+
value,
|
|
595
|
+
onChange,
|
|
596
|
+
disabled,
|
|
597
|
+
className,
|
|
598
|
+
...props
|
|
599
|
+
}) {
|
|
600
|
+
const toggle = (optionValue) => {
|
|
601
|
+
if (disabled) return;
|
|
602
|
+
const next = value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue];
|
|
603
|
+
onChange(next);
|
|
604
|
+
};
|
|
605
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
606
|
+
"div",
|
|
607
|
+
{
|
|
608
|
+
role: "group",
|
|
609
|
+
className: cn("inline-flex gap-0.5 p-[3px] rounded-kj-md bg-muted", className),
|
|
610
|
+
...props,
|
|
611
|
+
children: options.map((opt) => {
|
|
612
|
+
const active = value.includes(opt.value);
|
|
613
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
614
|
+
"button",
|
|
615
|
+
{
|
|
616
|
+
type: "button",
|
|
617
|
+
"aria-pressed": active,
|
|
618
|
+
disabled,
|
|
619
|
+
onClick: () => toggle(opt.value),
|
|
620
|
+
className: cn(
|
|
621
|
+
"px-3.5 py-1.5 text-[0.82rem] font-semibold rounded-[calc(var(--kj-radius-md)-3px)] cursor-pointer transition-all duration-150 disabled:cursor-not-allowed disabled:opacity-50",
|
|
622
|
+
active ? "bg-surface text-foreground shadow-kj-xs" : "bg-transparent text-muted-foreground hover:text-foreground"
|
|
623
|
+
),
|
|
624
|
+
children: opt.label
|
|
625
|
+
},
|
|
626
|
+
opt.value
|
|
627
|
+
);
|
|
628
|
+
})
|
|
629
|
+
}
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
var Card = React52__namespace.forwardRef(
|
|
438
633
|
({ as: Tag = "div", className, elevated, interactive, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
439
634
|
Tag,
|
|
440
635
|
{
|
|
@@ -450,23 +645,23 @@ var Card = React18__namespace.forwardRef(
|
|
|
450
645
|
)
|
|
451
646
|
);
|
|
452
647
|
Card.displayName = "Card";
|
|
453
|
-
var CardHeader =
|
|
648
|
+
var CardHeader = React52__namespace.forwardRef(
|
|
454
649
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("p-[1.35rem] flex flex-col gap-1", className), ...props })
|
|
455
650
|
);
|
|
456
651
|
CardHeader.displayName = "CardHeader";
|
|
457
|
-
var CardTitle =
|
|
458
|
-
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, className: cn("m-0 text-base font-bold tracking-[-0.01em]", className), ...props })
|
|
652
|
+
var CardTitle = React52__namespace.forwardRef(
|
|
653
|
+
({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, className: cn("m-0 text-base font-bold tracking-[-0.01em]", className), ...props, children })
|
|
459
654
|
);
|
|
460
655
|
CardTitle.displayName = "CardTitle";
|
|
461
|
-
var CardDescription =
|
|
656
|
+
var CardDescription = React52__namespace.forwardRef(
|
|
462
657
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn("m-0 text-[0.85rem] text-muted-foreground", className), ...props })
|
|
463
658
|
);
|
|
464
659
|
CardDescription.displayName = "CardDescription";
|
|
465
|
-
var CardContent =
|
|
660
|
+
var CardContent = React52__namespace.forwardRef(
|
|
466
661
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("px-[1.35rem] pb-[1.35rem]", className), ...props })
|
|
467
662
|
);
|
|
468
663
|
CardContent.displayName = "CardContent";
|
|
469
|
-
var CardFooter =
|
|
664
|
+
var CardFooter = React52__namespace.forwardRef(
|
|
470
665
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
471
666
|
"div",
|
|
472
667
|
{
|
|
@@ -477,7 +672,7 @@ var CardFooter = React18__namespace.forwardRef(
|
|
|
477
672
|
)
|
|
478
673
|
);
|
|
479
674
|
CardFooter.displayName = "CardFooter";
|
|
480
|
-
var Stat =
|
|
675
|
+
var Stat = React52__namespace.forwardRef(
|
|
481
676
|
({ className, label, value, delta, trend, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(Card, { ref, className: cn("p-[1.35rem] flex flex-col gap-2", className), ...props, children: [
|
|
482
677
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.78rem] font-semibold uppercase tracking-[0.05em] text-muted-foreground", children: label }),
|
|
483
678
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[2rem] font-bold tracking-[-0.03em] tabular-nums leading-none", children: value }),
|
|
@@ -517,7 +712,7 @@ var avatarVariants = classVarianceAuthority.cva(
|
|
|
517
712
|
defaultVariants: { size: "md", tone: "secondary" }
|
|
518
713
|
}
|
|
519
714
|
);
|
|
520
|
-
var Avatar =
|
|
715
|
+
var Avatar = React52__namespace.forwardRef(
|
|
521
716
|
({ className, size, tone, src, alt, status, children, ...props }, ref) => {
|
|
522
717
|
const node = /* @__PURE__ */ jsxRuntime.jsx("span", { ref, className: cn(avatarVariants({ size, tone }), "overflow-hidden", className), ...props, children: src ? /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt, className: "h-full w-full object-cover" }) : children });
|
|
523
718
|
if (!status) return node;
|
|
@@ -528,21 +723,21 @@ var Avatar = React18__namespace.forwardRef(
|
|
|
528
723
|
}
|
|
529
724
|
);
|
|
530
725
|
Avatar.displayName = "Avatar";
|
|
531
|
-
var AvatarGroup =
|
|
726
|
+
var AvatarGroup = React52__namespace.forwardRef(
|
|
532
727
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex [&>*:not(:first-child)]:-ml-2.5", className), ...props })
|
|
533
728
|
);
|
|
534
729
|
AvatarGroup.displayName = "AvatarGroup";
|
|
535
|
-
var TabsContext =
|
|
730
|
+
var TabsContext = React52__namespace.createContext(null);
|
|
536
731
|
function useTabs() {
|
|
537
|
-
const ctx =
|
|
732
|
+
const ctx = React52__namespace.useContext(TabsContext);
|
|
538
733
|
if (!ctx) throw new Error("Tabs.* must be used within <Tabs>");
|
|
539
734
|
return ctx;
|
|
540
735
|
}
|
|
541
736
|
function Tabs({ value, defaultValue, onValueChange, className, children, ...props }) {
|
|
542
|
-
const [internal, setInternal] =
|
|
543
|
-
const uid =
|
|
737
|
+
const [internal, setInternal] = React52__namespace.useState(defaultValue ?? "");
|
|
738
|
+
const uid = React52__namespace.useId();
|
|
544
739
|
const current = value ?? internal;
|
|
545
|
-
const setValue =
|
|
740
|
+
const setValue = React52__namespace.useCallback(
|
|
546
741
|
(v) => {
|
|
547
742
|
if (value === void 0) setInternal(v);
|
|
548
743
|
onValueChange?.(v);
|
|
@@ -551,7 +746,7 @@ function Tabs({ value, defaultValue, onValueChange, className, children, ...prop
|
|
|
551
746
|
);
|
|
552
747
|
return /* @__PURE__ */ jsxRuntime.jsx(TabsContext.Provider, { value: { value: current, setValue, uid }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className, ...props, children }) });
|
|
553
748
|
}
|
|
554
|
-
var TabsList =
|
|
749
|
+
var TabsList = React52__namespace.forwardRef(
|
|
555
750
|
({ className, onKeyDown, ...props }, ref) => {
|
|
556
751
|
const handleKeyDown = (e) => {
|
|
557
752
|
const container = e.currentTarget;
|
|
@@ -598,7 +793,7 @@ var TabsList = React18__namespace.forwardRef(
|
|
|
598
793
|
}
|
|
599
794
|
);
|
|
600
795
|
TabsList.displayName = "TabsList";
|
|
601
|
-
var TabsTrigger =
|
|
796
|
+
var TabsTrigger = React52__namespace.forwardRef(
|
|
602
797
|
({ className, value, children, ...props }, ref) => {
|
|
603
798
|
const { value: current, setValue, uid } = useTabs();
|
|
604
799
|
const active = current === value;
|
|
@@ -627,7 +822,7 @@ var TabsTrigger = React18__namespace.forwardRef(
|
|
|
627
822
|
}
|
|
628
823
|
);
|
|
629
824
|
TabsTrigger.displayName = "TabsTrigger";
|
|
630
|
-
var TabsContent =
|
|
825
|
+
var TabsContent = React52__namespace.forwardRef(
|
|
631
826
|
({ className, value, ...props }, ref) => {
|
|
632
827
|
const { value: current, uid } = useTabs();
|
|
633
828
|
const active = current === value;
|
|
@@ -647,10 +842,10 @@ var TabsContent = React18__namespace.forwardRef(
|
|
|
647
842
|
}
|
|
648
843
|
);
|
|
649
844
|
TabsContent.displayName = "TabsContent";
|
|
650
|
-
var AccordionContext =
|
|
845
|
+
var AccordionContext = React52__namespace.createContext(null);
|
|
651
846
|
function Accordion({ type = "single", defaultValue = [], className, children, ...props }) {
|
|
652
|
-
const [open, setOpen] =
|
|
653
|
-
const toggle =
|
|
847
|
+
const [open, setOpen] = React52__namespace.useState(defaultValue);
|
|
848
|
+
const toggle = React52__namespace.useCallback(
|
|
654
849
|
(v) => {
|
|
655
850
|
setOpen((prev) => {
|
|
656
851
|
const isOpen = prev.includes(v);
|
|
@@ -662,15 +857,15 @@ function Accordion({ type = "single", defaultValue = [], className, children, ..
|
|
|
662
857
|
);
|
|
663
858
|
return /* @__PURE__ */ jsxRuntime.jsx(AccordionContext.Provider, { value: { open, toggle }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("border border-border rounded-kj-lg overflow-hidden", className), ...props, children }) });
|
|
664
859
|
}
|
|
665
|
-
var ItemContext =
|
|
666
|
-
var AccordionItem =
|
|
860
|
+
var ItemContext = React52__namespace.createContext("");
|
|
861
|
+
var AccordionItem = React52__namespace.forwardRef(
|
|
667
862
|
({ className, value, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(ItemContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("border-t border-border first:border-t-0", className), ...props }) })
|
|
668
863
|
);
|
|
669
864
|
AccordionItem.displayName = "AccordionItem";
|
|
670
|
-
var AccordionTrigger =
|
|
865
|
+
var AccordionTrigger = React52__namespace.forwardRef(
|
|
671
866
|
({ className, children, ...props }, ref) => {
|
|
672
|
-
const ctx =
|
|
673
|
-
const value =
|
|
867
|
+
const ctx = React52__namespace.useContext(AccordionContext);
|
|
868
|
+
const value = React52__namespace.useContext(ItemContext);
|
|
674
869
|
const isOpen = ctx.open.includes(value);
|
|
675
870
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
676
871
|
"button",
|
|
@@ -707,10 +902,10 @@ var AccordionTrigger = React18__namespace.forwardRef(
|
|
|
707
902
|
}
|
|
708
903
|
);
|
|
709
904
|
AccordionTrigger.displayName = "AccordionTrigger";
|
|
710
|
-
var AccordionContent =
|
|
905
|
+
var AccordionContent = React52__namespace.forwardRef(
|
|
711
906
|
({ className, children, ...props }, ref) => {
|
|
712
|
-
const ctx =
|
|
713
|
-
const value =
|
|
907
|
+
const ctx = React52__namespace.useContext(AccordionContext);
|
|
908
|
+
const value = React52__namespace.useContext(ItemContext);
|
|
714
909
|
const isOpen = ctx.open.includes(value);
|
|
715
910
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
716
911
|
"div",
|
|
@@ -724,11 +919,11 @@ var AccordionContent = React18__namespace.forwardRef(
|
|
|
724
919
|
}
|
|
725
920
|
);
|
|
726
921
|
AccordionContent.displayName = "AccordionContent";
|
|
727
|
-
var MenuContext =
|
|
922
|
+
var MenuContext = React52__namespace.createContext(null);
|
|
728
923
|
function DropdownMenu({ children, className }) {
|
|
729
|
-
const [open, setOpen] =
|
|
730
|
-
const ref =
|
|
731
|
-
|
|
924
|
+
const [open, setOpen] = React52__namespace.useState(false);
|
|
925
|
+
const ref = React52__namespace.useRef(null);
|
|
926
|
+
React52__namespace.useEffect(() => {
|
|
732
927
|
if (!open) return;
|
|
733
928
|
const onDoc = (e) => {
|
|
734
929
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -743,11 +938,11 @@ function DropdownMenu({ children, className }) {
|
|
|
743
938
|
}, [open]);
|
|
744
939
|
return /* @__PURE__ */ jsxRuntime.jsx(MenuContext.Provider, { value: { open, setOpen }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("relative inline-block", className), children }) });
|
|
745
940
|
}
|
|
746
|
-
var DropdownMenuTrigger =
|
|
747
|
-
const ctx =
|
|
941
|
+
var DropdownMenuTrigger = React52__namespace.forwardRef(({ onClick, asChild, ...props }, ref) => {
|
|
942
|
+
const ctx = React52__namespace.useContext(MenuContext);
|
|
748
943
|
if (asChild) {
|
|
749
|
-
const child =
|
|
750
|
-
return
|
|
944
|
+
const child = React52__namespace.Children.only(props.children);
|
|
945
|
+
return React52__namespace.cloneElement(child, {
|
|
751
946
|
ref,
|
|
752
947
|
...props,
|
|
753
948
|
...child.props,
|
|
@@ -777,9 +972,9 @@ var DropdownMenuTrigger = React18__namespace.forwardRef(({ onClick, asChild, ...
|
|
|
777
972
|
});
|
|
778
973
|
DropdownMenuTrigger.displayName = "DropdownMenuTrigger";
|
|
779
974
|
function DropdownMenuContent({ className, align = "start", children, ...props }) {
|
|
780
|
-
const ctx =
|
|
781
|
-
const ref =
|
|
782
|
-
|
|
975
|
+
const ctx = React52__namespace.useContext(MenuContext);
|
|
976
|
+
const ref = React52__namespace.useRef(null);
|
|
977
|
+
React52__namespace.useEffect(() => {
|
|
783
978
|
if (!ctx.open) return;
|
|
784
979
|
const container = ref.current;
|
|
785
980
|
if (container) {
|
|
@@ -826,9 +1021,9 @@ function DropdownMenuContent({ className, align = "start", children, ...props })
|
|
|
826
1021
|
}
|
|
827
1022
|
);
|
|
828
1023
|
}
|
|
829
|
-
var DropdownMenuItem =
|
|
1024
|
+
var DropdownMenuItem = React52__namespace.forwardRef(
|
|
830
1025
|
({ className, danger, icon, children, onClick, ...props }, ref) => {
|
|
831
|
-
const ctx =
|
|
1026
|
+
const ctx = React52__namespace.useContext(MenuContext);
|
|
832
1027
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
833
1028
|
"button",
|
|
834
1029
|
{
|
|
@@ -858,11 +1053,11 @@ DropdownMenuItem.displayName = "DropdownMenuItem";
|
|
|
858
1053
|
function DropdownMenuSeparator({ className }) {
|
|
859
1054
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("h-px bg-border my-1.5", className), role: "separator" });
|
|
860
1055
|
}
|
|
861
|
-
var Breadcrumb =
|
|
1056
|
+
var Breadcrumb = React52__namespace.forwardRef(
|
|
862
1057
|
({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("nav", { ref, "aria-label": "Breadcrumb", className: cn("flex items-center gap-1.5 text-[0.85rem] text-muted-foreground", className), ...props, children })
|
|
863
1058
|
);
|
|
864
1059
|
Breadcrumb.displayName = "Breadcrumb";
|
|
865
|
-
var BreadcrumbItem =
|
|
1060
|
+
var BreadcrumbItem = React52__namespace.forwardRef(
|
|
866
1061
|
({ className, current, children, ...props }, ref) => {
|
|
867
1062
|
if (current) {
|
|
868
1063
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-current": "page", className: cn("text-foreground font-semibold", className), children });
|
|
@@ -909,7 +1104,7 @@ function Pagination({ page, pageCount, onPageChange, className }) {
|
|
|
909
1104
|
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Next", disabled: page >= pageCount, onClick: () => onPageChange(page + 1), children: /* @__PURE__ */ jsxRuntime.jsx(Chevron, { dir: "right" }) })
|
|
910
1105
|
] });
|
|
911
1106
|
}
|
|
912
|
-
var BottomNavigation =
|
|
1107
|
+
var BottomNavigation = React52__namespace.forwardRef(
|
|
913
1108
|
({ className, items, showLabels = "always", fixed = true, ...props }, ref) => {
|
|
914
1109
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
915
1110
|
"nav",
|
|
@@ -981,27 +1176,27 @@ var BottomNavigation = React18__namespace.forwardRef(
|
|
|
981
1176
|
}
|
|
982
1177
|
);
|
|
983
1178
|
BottomNavigation.displayName = "BottomNavigation";
|
|
984
|
-
var TableWrap =
|
|
1179
|
+
var TableWrap = React52__namespace.forwardRef(
|
|
985
1180
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("border border-border rounded-kj-lg overflow-x-auto w-full", className), ...props })
|
|
986
1181
|
);
|
|
987
1182
|
TableWrap.displayName = "TableWrap";
|
|
988
|
-
var Table =
|
|
1183
|
+
var Table = React52__namespace.forwardRef(
|
|
989
1184
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("table", { ref, className: cn("w-full border-collapse text-[0.85rem]", className), ...props })
|
|
990
1185
|
);
|
|
991
1186
|
Table.displayName = "Table";
|
|
992
|
-
var TableHeader =
|
|
1187
|
+
var TableHeader = React52__namespace.forwardRef(
|
|
993
1188
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("thead", { ref, className, ...props })
|
|
994
1189
|
);
|
|
995
1190
|
TableHeader.displayName = "TableHeader";
|
|
996
|
-
var TableBody =
|
|
1191
|
+
var TableBody = React52__namespace.forwardRef(
|
|
997
1192
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { ref, className, ...props })
|
|
998
1193
|
);
|
|
999
1194
|
TableBody.displayName = "TableBody";
|
|
1000
|
-
var TableRow =
|
|
1195
|
+
var TableRow = React52__namespace.forwardRef(
|
|
1001
1196
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tr", { ref, className: cn("transition-colors hover:bg-muted/50", className), ...props })
|
|
1002
1197
|
);
|
|
1003
1198
|
TableRow.displayName = "TableRow";
|
|
1004
|
-
var TableHead =
|
|
1199
|
+
var TableHead = React52__namespace.forwardRef(
|
|
1005
1200
|
({ className, numeric, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1006
1201
|
"th",
|
|
1007
1202
|
{
|
|
@@ -1016,7 +1211,7 @@ var TableHead = React18__namespace.forwardRef(
|
|
|
1016
1211
|
)
|
|
1017
1212
|
);
|
|
1018
1213
|
TableHead.displayName = "TableHead";
|
|
1019
|
-
var TableCell =
|
|
1214
|
+
var TableCell = React52__namespace.forwardRef(
|
|
1020
1215
|
({ className, numeric, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1021
1216
|
"td",
|
|
1022
1217
|
{
|
|
@@ -1032,30 +1227,33 @@ var TableCell = React18__namespace.forwardRef(
|
|
|
1032
1227
|
);
|
|
1033
1228
|
TableCell.displayName = "TableCell";
|
|
1034
1229
|
function Tooltip({ content, children, className }) {
|
|
1035
|
-
return
|
|
1036
|
-
|
|
1037
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1230
|
+
return (
|
|
1231
|
+
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
|
|
1232
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("relative inline-flex group", className), tabIndex: 0, children: [
|
|
1233
|
+
children,
|
|
1234
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1235
|
+
"span",
|
|
1236
|
+
{
|
|
1237
|
+
role: "tooltip",
|
|
1238
|
+
className: cn(
|
|
1239
|
+
"pointer-events-none absolute bottom-[calc(100%+8px)] left-1/2 -translate-x-1/2 translate-y-1 whitespace-nowrap",
|
|
1240
|
+
"rounded-kj-sm bg-foreground text-background text-xs font-medium px-2.5 py-1.5 shadow-kj-md",
|
|
1241
|
+
"opacity-0 transition-all duration-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0",
|
|
1242
|
+
"after:content-[''] after:absolute after:top-full after:left-1/2 after:-translate-x-1/2 after:border-[5px] after:border-transparent after:border-t-foreground"
|
|
1243
|
+
),
|
|
1244
|
+
children: content
|
|
1245
|
+
}
|
|
1246
|
+
)
|
|
1247
|
+
] })
|
|
1248
|
+
);
|
|
1051
1249
|
}
|
|
1052
|
-
var ModalContext =
|
|
1250
|
+
var ModalContext = React52__namespace.createContext(null);
|
|
1053
1251
|
function Modal({ open, onClose, children, width = 440, className, showClose = true }) {
|
|
1054
|
-
const titleId =
|
|
1055
|
-
const descId =
|
|
1056
|
-
const containerRef =
|
|
1057
|
-
const lastActiveElement =
|
|
1058
|
-
|
|
1252
|
+
const titleId = React52__namespace.useId();
|
|
1253
|
+
const descId = React52__namespace.useId();
|
|
1254
|
+
const containerRef = React52__namespace.useRef(null);
|
|
1255
|
+
const lastActiveElement = React52__namespace.useRef(null);
|
|
1256
|
+
React52__namespace.useEffect(() => {
|
|
1059
1257
|
if (!open) {
|
|
1060
1258
|
if (lastActiveElement.current) {
|
|
1061
1259
|
lastActiveElement.current.focus();
|
|
@@ -1156,20 +1354,20 @@ function Modal({ open, onClose, children, width = 440, className, showClose = tr
|
|
|
1156
1354
|
}
|
|
1157
1355
|
);
|
|
1158
1356
|
}
|
|
1159
|
-
function ModalTitle({ className, id, ...props }) {
|
|
1160
|
-
const ctx =
|
|
1161
|
-
return /* @__PURE__ */ jsxRuntime.jsx("h3", { id: id ?? ctx?.titleId, className: cn("m-0 mb-2 text-[1.15rem] font-bold tracking-[-0.01em]", className), ...props });
|
|
1357
|
+
function ModalTitle({ className, id, children, ...props }) {
|
|
1358
|
+
const ctx = React52__namespace.useContext(ModalContext);
|
|
1359
|
+
return /* @__PURE__ */ jsxRuntime.jsx("h3", { id: id ?? ctx?.titleId, className: cn("m-0 mb-2 text-[1.15rem] font-bold tracking-[-0.01em]", className), ...props, children });
|
|
1162
1360
|
}
|
|
1163
1361
|
function ModalDescription({ className, id, ...props }) {
|
|
1164
|
-
const ctx =
|
|
1362
|
+
const ctx = React52__namespace.useContext(ModalContext);
|
|
1165
1363
|
return /* @__PURE__ */ jsxRuntime.jsx("p", { id: id ?? ctx?.descId, className: cn("m-0 text-[0.9rem] text-muted-foreground", className), ...props });
|
|
1166
1364
|
}
|
|
1167
1365
|
function ModalActions({ className, ...props }) {
|
|
1168
1366
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex gap-2.5 justify-end mt-6", className), ...props });
|
|
1169
1367
|
}
|
|
1170
|
-
var ToastContext =
|
|
1368
|
+
var ToastContext = React52__namespace.createContext(null);
|
|
1171
1369
|
function useToast() {
|
|
1172
|
-
const ctx =
|
|
1370
|
+
const ctx = React52__namespace.useContext(ToastContext);
|
|
1173
1371
|
if (!ctx) throw new Error("useToast must be used within <ToastProvider>");
|
|
1174
1372
|
return ctx;
|
|
1175
1373
|
}
|
|
@@ -1190,13 +1388,13 @@ var toneBorder = {
|
|
|
1190
1388
|
danger: "border-l-danger"
|
|
1191
1389
|
};
|
|
1192
1390
|
function ToastProvider({ children }) {
|
|
1193
|
-
const [items, setItems] =
|
|
1194
|
-
const idRef =
|
|
1195
|
-
const remove =
|
|
1391
|
+
const [items, setItems] = React52__namespace.useState([]);
|
|
1392
|
+
const idRef = React52__namespace.useRef(0);
|
|
1393
|
+
const remove = React52__namespace.useCallback((id) => {
|
|
1196
1394
|
setItems((prev) => prev.map((t) => t.id === id ? { ...t, leaving: true } : t));
|
|
1197
1395
|
setTimeout(() => setItems((prev) => prev.filter((t) => t.id !== id)), 250);
|
|
1198
1396
|
}, []);
|
|
1199
|
-
const toast =
|
|
1397
|
+
const toast = React52__namespace.useCallback(
|
|
1200
1398
|
({ message, tone = "default", duration = 3200 }) => {
|
|
1201
1399
|
const id = ++idRef.current;
|
|
1202
1400
|
setItems((prev) => [...prev, { id, message, tone, duration }]);
|
|
@@ -1226,7 +1424,7 @@ function ToastProvider({ children }) {
|
|
|
1226
1424
|
)) })
|
|
1227
1425
|
] });
|
|
1228
1426
|
}
|
|
1229
|
-
var PageHeader =
|
|
1427
|
+
var PageHeader = React52__namespace.forwardRef(
|
|
1230
1428
|
({ eyebrow, title, description, actions }, ref) => /* @__PURE__ */ jsxRuntime.jsx("header", { ref, className: "py-12 md:py-16", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6 md:flex-row md:items-end md:justify-between", children: [
|
|
1231
1429
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 max-w-2xl", children: [
|
|
1232
1430
|
eyebrow && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-xs font-bold uppercase tracking-[0.2em] text-primary", children: eyebrow }),
|
|
@@ -1237,7 +1435,111 @@ var PageHeader = React18__namespace.forwardRef(
|
|
|
1237
1435
|
] }) })
|
|
1238
1436
|
);
|
|
1239
1437
|
PageHeader.displayName = "PageHeader";
|
|
1240
|
-
var
|
|
1438
|
+
var SectionHeaderKicker = React52__namespace.forwardRef(
|
|
1439
|
+
({ className, children, ...props }, ref) => {
|
|
1440
|
+
if (!children) return null;
|
|
1441
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1442
|
+
"p",
|
|
1443
|
+
{
|
|
1444
|
+
ref,
|
|
1445
|
+
className: cn(
|
|
1446
|
+
"font-mono text-xs font-bold uppercase tracking-[0.2em] text-primary",
|
|
1447
|
+
className
|
|
1448
|
+
),
|
|
1449
|
+
...props,
|
|
1450
|
+
children
|
|
1451
|
+
}
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
);
|
|
1455
|
+
SectionHeaderKicker.displayName = "SectionHeaderKicker";
|
|
1456
|
+
var SectionHeaderTitle = React52__namespace.forwardRef(
|
|
1457
|
+
({ className, as: Component = "h2", children, ...props }, ref) => {
|
|
1458
|
+
if (!children) return null;
|
|
1459
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1460
|
+
Component,
|
|
1461
|
+
{
|
|
1462
|
+
ref,
|
|
1463
|
+
className: cn("text-2xl font-bold tracking-tight text-foreground sm:text-3xl", className),
|
|
1464
|
+
...props,
|
|
1465
|
+
children
|
|
1466
|
+
}
|
|
1467
|
+
);
|
|
1468
|
+
}
|
|
1469
|
+
);
|
|
1470
|
+
SectionHeaderTitle.displayName = "SectionHeaderTitle";
|
|
1471
|
+
var SectionHeaderDescription = React52__namespace.forwardRef(({ className, children, ...props }, ref) => {
|
|
1472
|
+
if (!children) return null;
|
|
1473
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1474
|
+
"p",
|
|
1475
|
+
{
|
|
1476
|
+
ref,
|
|
1477
|
+
className: cn("text-base leading-relaxed text-muted-foreground max-w-2xl", className),
|
|
1478
|
+
...props,
|
|
1479
|
+
children
|
|
1480
|
+
}
|
|
1481
|
+
);
|
|
1482
|
+
});
|
|
1483
|
+
SectionHeaderDescription.displayName = "SectionHeaderDescription";
|
|
1484
|
+
var SectionHeaderActions = React52__namespace.forwardRef(
|
|
1485
|
+
({ className, children, ...props }, ref) => {
|
|
1486
|
+
if (!children) return null;
|
|
1487
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex flex-wrap items-center gap-3", className), ...props, children });
|
|
1488
|
+
}
|
|
1489
|
+
);
|
|
1490
|
+
SectionHeaderActions.displayName = "SectionHeaderActions";
|
|
1491
|
+
var SectionHeader = React52__namespace.forwardRef(
|
|
1492
|
+
({
|
|
1493
|
+
kicker,
|
|
1494
|
+
title,
|
|
1495
|
+
description,
|
|
1496
|
+
actions,
|
|
1497
|
+
align = "left",
|
|
1498
|
+
headingLevel = "h2",
|
|
1499
|
+
divider = false,
|
|
1500
|
+
className,
|
|
1501
|
+
children,
|
|
1502
|
+
...props
|
|
1503
|
+
}, ref) => {
|
|
1504
|
+
const isCentered = align === "center";
|
|
1505
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1506
|
+
"div",
|
|
1507
|
+
{
|
|
1508
|
+
ref,
|
|
1509
|
+
className: cn(
|
|
1510
|
+
"space-y-4",
|
|
1511
|
+
isCentered ? "text-center items-center mx-auto max-w-3xl" : "md:flex md:items-end md:justify-between md:space-y-0",
|
|
1512
|
+
divider && "border-b border-border pb-6",
|
|
1513
|
+
className
|
|
1514
|
+
),
|
|
1515
|
+
...props,
|
|
1516
|
+
children: children ? children : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1517
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1518
|
+
"div",
|
|
1519
|
+
{
|
|
1520
|
+
className: cn(
|
|
1521
|
+
"space-y-2",
|
|
1522
|
+
isCentered && "flex flex-col items-center"
|
|
1523
|
+
),
|
|
1524
|
+
children: [
|
|
1525
|
+
kicker && /* @__PURE__ */ jsxRuntime.jsx(SectionHeaderKicker, { children: kicker }),
|
|
1526
|
+
title && /* @__PURE__ */ jsxRuntime.jsx(SectionHeaderTitle, { as: headingLevel, children: title }),
|
|
1527
|
+
description && /* @__PURE__ */ jsxRuntime.jsx(SectionHeaderDescription, { children: description })
|
|
1528
|
+
]
|
|
1529
|
+
}
|
|
1530
|
+
),
|
|
1531
|
+
actions && /* @__PURE__ */ jsxRuntime.jsx(SectionHeaderActions, { className: cn(isCentered && "justify-center mt-4"), children: actions })
|
|
1532
|
+
] })
|
|
1533
|
+
}
|
|
1534
|
+
);
|
|
1535
|
+
}
|
|
1536
|
+
);
|
|
1537
|
+
SectionHeader.displayName = "SectionHeader";
|
|
1538
|
+
SectionHeader.Kicker = SectionHeaderKicker;
|
|
1539
|
+
SectionHeader.Title = SectionHeaderTitle;
|
|
1540
|
+
SectionHeader.Description = SectionHeaderDescription;
|
|
1541
|
+
SectionHeader.Actions = SectionHeaderActions;
|
|
1542
|
+
var EmptyState = React52__namespace.forwardRef(
|
|
1241
1543
|
({ className, icon, title, description, action, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1242
1544
|
"div",
|
|
1243
1545
|
{
|
|
@@ -1257,7 +1559,7 @@ var EmptyState = React18__namespace.forwardRef(
|
|
|
1257
1559
|
)
|
|
1258
1560
|
);
|
|
1259
1561
|
EmptyState.displayName = "EmptyState";
|
|
1260
|
-
var MetricCard =
|
|
1562
|
+
var MetricCard = React52__namespace.forwardRef(
|
|
1261
1563
|
({ className, title, value, trend, trendDirection = "neutral", description, icon, ...props }, ref) => {
|
|
1262
1564
|
const trendColor = {
|
|
1263
1565
|
up: "text-success bg-success-surface border-success/20",
|
|
@@ -1298,22 +1600,22 @@ function DataTable({
|
|
|
1298
1600
|
onSort,
|
|
1299
1601
|
...props
|
|
1300
1602
|
}) {
|
|
1301
|
-
const getRowId =
|
|
1603
|
+
const getRowId = React52__namespace.useCallback(
|
|
1302
1604
|
(row, index) => getRowKey ? getRowKey(row, index) : index,
|
|
1303
1605
|
[getRowKey]
|
|
1304
1606
|
);
|
|
1305
1607
|
const isSelectionActive = selectedRows !== void 0 && onSelectionChange !== void 0;
|
|
1306
|
-
const allSelected =
|
|
1608
|
+
const allSelected = React52__namespace.useMemo(() => {
|
|
1307
1609
|
if (!isSelectionActive || data.length === 0) return false;
|
|
1308
1610
|
return data.every((row, idx) => selectedRows.has(getRowId(row, idx)));
|
|
1309
1611
|
}, [isSelectionActive, data, selectedRows, getRowId]);
|
|
1310
|
-
const someSelected =
|
|
1612
|
+
const someSelected = React52__namespace.useMemo(() => {
|
|
1311
1613
|
if (!isSelectionActive || data.length === 0) return false;
|
|
1312
1614
|
const selectedCount = data.filter((row, idx) => selectedRows.has(getRowId(row, idx))).length;
|
|
1313
1615
|
return selectedCount > 0 && selectedCount < data.length;
|
|
1314
1616
|
}, [isSelectionActive, data, selectedRows, getRowId]);
|
|
1315
|
-
const headerCheckboxRef =
|
|
1316
|
-
|
|
1617
|
+
const headerCheckboxRef = React52__namespace.useRef(null);
|
|
1618
|
+
React52__namespace.useEffect(() => {
|
|
1317
1619
|
if (headerCheckboxRef.current) {
|
|
1318
1620
|
headerCheckboxRef.current.indeterminate = someSelected;
|
|
1319
1621
|
}
|
|
@@ -1467,7 +1769,7 @@ function DataTable({
|
|
|
1467
1769
|
] });
|
|
1468
1770
|
}
|
|
1469
1771
|
DataTable.displayName = "DataTable";
|
|
1470
|
-
var ErrorState =
|
|
1772
|
+
var ErrorState = React52__namespace.forwardRef(
|
|
1471
1773
|
({ className, title = "Wyst\u0105pi\u0142 b\u0142\u0105d", message, onRetry, retryLabel = "Spr\xF3buj ponownie", ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1472
1774
|
"div",
|
|
1473
1775
|
{
|
|
@@ -1487,7 +1789,7 @@ var ErrorState = React18__namespace.forwardRef(
|
|
|
1487
1789
|
)
|
|
1488
1790
|
);
|
|
1489
1791
|
ErrorState.displayName = "ErrorState";
|
|
1490
|
-
var Skeleton =
|
|
1792
|
+
var Skeleton = React52__namespace.forwardRef(
|
|
1491
1793
|
({ className, variant = "rectangular", width, height, style, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1492
1794
|
"div",
|
|
1493
1795
|
{
|
|
@@ -1509,7 +1811,7 @@ var Skeleton = React18__namespace.forwardRef(
|
|
|
1509
1811
|
)
|
|
1510
1812
|
);
|
|
1511
1813
|
Skeleton.displayName = "Skeleton";
|
|
1512
|
-
var DashboardShell =
|
|
1814
|
+
var DashboardShell = React52__namespace.forwardRef(
|
|
1513
1815
|
({
|
|
1514
1816
|
className,
|
|
1515
1817
|
sidebar,
|
|
@@ -1521,7 +1823,7 @@ var DashboardShell = React18__namespace.forwardRef(
|
|
|
1521
1823
|
mobileSidebar,
|
|
1522
1824
|
...props
|
|
1523
1825
|
}, ref) => {
|
|
1524
|
-
const [mobileOpen, setMobileOpen] =
|
|
1826
|
+
const [mobileOpen, setMobileOpen] = React52__namespace.useState(false);
|
|
1525
1827
|
const contentWidthClass = {
|
|
1526
1828
|
default: "max-w-7xl w-full mx-auto",
|
|
1527
1829
|
wide: "max-w-screen-2xl w-full mx-auto",
|
|
@@ -1612,7 +1914,7 @@ var DashboardShell = React18__namespace.forwardRef(
|
|
|
1612
1914
|
}
|
|
1613
1915
|
);
|
|
1614
1916
|
DashboardShell.displayName = "DashboardShell";
|
|
1615
|
-
var SettingsLayout =
|
|
1917
|
+
var SettingsLayout = React52__namespace.forwardRef(
|
|
1616
1918
|
({ className, sidebar, children, title, description, ...props }, ref) => {
|
|
1617
1919
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("space-y-6 w-full", className), ...props, children: [
|
|
1618
1920
|
(title || description) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-border pb-4", children: [
|
|
@@ -1627,7 +1929,7 @@ var SettingsLayout = React18__namespace.forwardRef(
|
|
|
1627
1929
|
}
|
|
1628
1930
|
);
|
|
1629
1931
|
SettingsLayout.displayName = "SettingsLayout";
|
|
1630
|
-
var DetailPageLayout =
|
|
1932
|
+
var DetailPageLayout = React52__namespace.forwardRef(
|
|
1631
1933
|
({ className, title, description, backHref, backLabel = "Back", onBackClick, actions, aside, children, ...props }, ref) => {
|
|
1632
1934
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("space-y-6 w-full", className), ...props, children: [
|
|
1633
1935
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
@@ -1673,7 +1975,7 @@ var DetailPageLayout = React18__namespace.forwardRef(
|
|
|
1673
1975
|
}
|
|
1674
1976
|
);
|
|
1675
1977
|
DetailPageLayout.displayName = "DetailPageLayout";
|
|
1676
|
-
var TableToolbar =
|
|
1978
|
+
var TableToolbar = React52__namespace.forwardRef(
|
|
1677
1979
|
({ className, searchQuery, onSearchChange, searchPlaceholder = "Search...", actions, filters, ...props }, ref) => {
|
|
1678
1980
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1679
1981
|
"div",
|
|
@@ -1742,9 +2044,9 @@ function Drawer({
|
|
|
1742
2044
|
width = "max-w-md",
|
|
1743
2045
|
side = "right"
|
|
1744
2046
|
}) {
|
|
1745
|
-
const containerRef =
|
|
1746
|
-
const lastActiveElement =
|
|
1747
|
-
|
|
2047
|
+
const containerRef = React52__namespace.useRef(null);
|
|
2048
|
+
const lastActiveElement = React52__namespace.useRef(null);
|
|
2049
|
+
React52__namespace.useEffect(() => {
|
|
1748
2050
|
if (!open) {
|
|
1749
2051
|
if (lastActiveElement.current) {
|
|
1750
2052
|
lastActiveElement.current.focus();
|
|
@@ -1863,11 +2165,11 @@ function Drawer({
|
|
|
1863
2165
|
}
|
|
1864
2166
|
Drawer.displayName = "Drawer";
|
|
1865
2167
|
function CommandPalette({ open, onClose, items, placeholder = "Type a command or search..." }) {
|
|
1866
|
-
const [search, setSearch] =
|
|
1867
|
-
const [activeIndex, setActiveIndex] =
|
|
1868
|
-
const containerRef =
|
|
1869
|
-
const listRef =
|
|
1870
|
-
|
|
2168
|
+
const [search, setSearch] = React52__namespace.useState("");
|
|
2169
|
+
const [activeIndex, setActiveIndex] = React52__namespace.useState(0);
|
|
2170
|
+
const containerRef = React52__namespace.useRef(null);
|
|
2171
|
+
const listRef = React52__namespace.useRef(null);
|
|
2172
|
+
React52__namespace.useEffect(() => {
|
|
1871
2173
|
if (open) {
|
|
1872
2174
|
setSearch("");
|
|
1873
2175
|
setActiveIndex(0);
|
|
@@ -1876,17 +2178,17 @@ function CommandPalette({ open, onClose, items, placeholder = "Type a command or
|
|
|
1876
2178
|
document.body.style.overflow = "";
|
|
1877
2179
|
}
|
|
1878
2180
|
}, [open]);
|
|
1879
|
-
const filteredItems =
|
|
2181
|
+
const filteredItems = React52__namespace.useMemo(() => {
|
|
1880
2182
|
if (!search) return items;
|
|
1881
2183
|
const cleanSearch = search.toLowerCase();
|
|
1882
2184
|
return items.filter(
|
|
1883
2185
|
(item) => item.title.toLowerCase().includes(cleanSearch) || item.subtitle?.toLowerCase().includes(cleanSearch) || item.category?.toLowerCase().includes(cleanSearch)
|
|
1884
2186
|
);
|
|
1885
2187
|
}, [search, items]);
|
|
1886
|
-
|
|
2188
|
+
React52__namespace.useEffect(() => {
|
|
1887
2189
|
setActiveIndex(0);
|
|
1888
2190
|
}, [filteredItems]);
|
|
1889
|
-
|
|
2191
|
+
React52__namespace.useEffect(() => {
|
|
1890
2192
|
if (!open) return;
|
|
1891
2193
|
const handleKeyDown = (e) => {
|
|
1892
2194
|
if (e.key === "Escape") {
|
|
@@ -1910,7 +2212,7 @@ function CommandPalette({ open, onClose, items, placeholder = "Type a command or
|
|
|
1910
2212
|
document.addEventListener("keydown", handleKeyDown);
|
|
1911
2213
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
1912
2214
|
}, [open, filteredItems, activeIndex, onClose]);
|
|
1913
|
-
|
|
2215
|
+
React52__namespace.useEffect(() => {
|
|
1914
2216
|
if (listRef.current) {
|
|
1915
2217
|
const activeEl = listRef.current.querySelector('[aria-selected="true"]');
|
|
1916
2218
|
if (activeEl) {
|
|
@@ -2113,7 +2415,7 @@ var fabVariants = classVarianceAuthority.cva(
|
|
|
2113
2415
|
defaultVariants: { variant: "primary", size: "md", position: "bottom-right" }
|
|
2114
2416
|
}
|
|
2115
2417
|
);
|
|
2116
|
-
var Fab =
|
|
2418
|
+
var Fab = React52__namespace.forwardRef(
|
|
2117
2419
|
({ className, variant, size, position, mobileOnly, icon, label, loading, disabled, ...props }, ref) => {
|
|
2118
2420
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2119
2421
|
"button",
|
|
@@ -2140,7 +2442,7 @@ var Fab = React18__namespace.forwardRef(
|
|
|
2140
2442
|
}
|
|
2141
2443
|
);
|
|
2142
2444
|
Fab.displayName = "Fab";
|
|
2143
|
-
var BottomSheetContext =
|
|
2445
|
+
var BottomSheetContext = React52__namespace.createContext(null);
|
|
2144
2446
|
function BottomSheet({
|
|
2145
2447
|
open,
|
|
2146
2448
|
onClose,
|
|
@@ -2149,12 +2451,12 @@ function BottomSheet({
|
|
|
2149
2451
|
className,
|
|
2150
2452
|
showClose = true
|
|
2151
2453
|
}) {
|
|
2152
|
-
const titleId =
|
|
2153
|
-
const descId =
|
|
2154
|
-
const containerRef =
|
|
2155
|
-
const lastActiveElement =
|
|
2156
|
-
const [mounted, setMounted] =
|
|
2157
|
-
|
|
2454
|
+
const titleId = React52__namespace.useId();
|
|
2455
|
+
const descId = React52__namespace.useId();
|
|
2456
|
+
const containerRef = React52__namespace.useRef(null);
|
|
2457
|
+
const lastActiveElement = React52__namespace.useRef(null);
|
|
2458
|
+
const [mounted, setMounted] = React52__namespace.useState(open);
|
|
2459
|
+
React52__namespace.useEffect(() => {
|
|
2158
2460
|
if (open) {
|
|
2159
2461
|
setMounted(true);
|
|
2160
2462
|
} else {
|
|
@@ -2162,7 +2464,7 @@ function BottomSheet({
|
|
|
2162
2464
|
return () => clearTimeout(timer);
|
|
2163
2465
|
}
|
|
2164
2466
|
}, [open]);
|
|
2165
|
-
|
|
2467
|
+
React52__namespace.useEffect(() => {
|
|
2166
2468
|
if (!open) return;
|
|
2167
2469
|
lastActiveElement.current = document.activeElement;
|
|
2168
2470
|
const container = containerRef.current;
|
|
@@ -2284,12 +2586,12 @@ function BottomSheet({
|
|
|
2284
2586
|
function BottomSheetHeader({ className, ...props }) {
|
|
2285
2587
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("p-6 flex flex-col gap-1.5 border-b border-border", className), ...props });
|
|
2286
2588
|
}
|
|
2287
|
-
function BottomSheetTitle({ className, id, ...props }) {
|
|
2288
|
-
const ctx =
|
|
2289
|
-
return /* @__PURE__ */ jsxRuntime.jsx("h2", { id: id ?? ctx?.titleId, className: cn("m-0 text-[1.15rem] font-bold tracking-[-0.01em]", className), ...props });
|
|
2589
|
+
function BottomSheetTitle({ className, id, children, ...props }) {
|
|
2590
|
+
const ctx = React52__namespace.useContext(BottomSheetContext);
|
|
2591
|
+
return /* @__PURE__ */ jsxRuntime.jsx("h2", { id: id ?? ctx?.titleId, className: cn("m-0 text-[1.15rem] font-bold tracking-[-0.01em]", className), ...props, children });
|
|
2290
2592
|
}
|
|
2291
2593
|
function BottomSheetDescription({ className, id, ...props }) {
|
|
2292
|
-
const ctx =
|
|
2594
|
+
const ctx = React52__namespace.useContext(BottomSheetContext);
|
|
2293
2595
|
return /* @__PURE__ */ jsxRuntime.jsx("p", { id: id ?? ctx?.descId, className: cn("m-0 text-[0.9rem] text-muted-foreground", className), ...props });
|
|
2294
2596
|
}
|
|
2295
2597
|
function BottomSheetContent({ className, ...props }) {
|
|
@@ -2310,7 +2612,7 @@ var kbdVariants = classVarianceAuthority.cva(
|
|
|
2310
2612
|
defaultVariants: { size: "sm" }
|
|
2311
2613
|
}
|
|
2312
2614
|
);
|
|
2313
|
-
var Kbd =
|
|
2615
|
+
var Kbd = React52__namespace.forwardRef(
|
|
2314
2616
|
({ className, size, keys, children, ...props }, ref) => {
|
|
2315
2617
|
if (keys && keys.length > 0) {
|
|
2316
2618
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2327,9 +2629,9 @@ var Kbd = React18__namespace.forwardRef(
|
|
|
2327
2629
|
}
|
|
2328
2630
|
);
|
|
2329
2631
|
Kbd.displayName = "Kbd";
|
|
2330
|
-
var CodeBlock =
|
|
2632
|
+
var CodeBlock = React52__namespace.forwardRef(
|
|
2331
2633
|
({ className, code, language, filename, copyable = true, maxHeight, ...props }, ref) => {
|
|
2332
|
-
const [copied, setCopied] =
|
|
2634
|
+
const [copied, setCopied] = React52__namespace.useState(false);
|
|
2333
2635
|
const canCopy = copyable && typeof navigator !== "undefined" && !!navigator.clipboard;
|
|
2334
2636
|
const onCopy = () => {
|
|
2335
2637
|
navigator.clipboard.writeText(code).then(
|
|
@@ -2375,26 +2677,40 @@ var CodeBlock = React18__namespace.forwardRef(
|
|
|
2375
2677
|
}
|
|
2376
2678
|
);
|
|
2377
2679
|
CodeBlock.displayName = "CodeBlock";
|
|
2378
|
-
|
|
2680
|
+
function Separator({ orientation = "horizontal", decorative = true, className }) {
|
|
2681
|
+
const semanticProps = decorative ? { role: "none", "aria-hidden": true } : { role: "separator", "aria-orientation": orientation };
|
|
2682
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2683
|
+
"div",
|
|
2684
|
+
{
|
|
2685
|
+
className: cn(
|
|
2686
|
+
"shrink-0 bg-border",
|
|
2687
|
+
orientation === "horizontal" ? "h-px w-full" : "w-px h-full",
|
|
2688
|
+
className
|
|
2689
|
+
),
|
|
2690
|
+
...semanticProps
|
|
2691
|
+
}
|
|
2692
|
+
);
|
|
2693
|
+
}
|
|
2694
|
+
var PopoverContext = React52__namespace.createContext(null);
|
|
2379
2695
|
function usePopoverContext(part) {
|
|
2380
|
-
const ctx =
|
|
2696
|
+
const ctx = React52__namespace.useContext(PopoverContext);
|
|
2381
2697
|
if (!ctx) throw new Error(`${part} must be used inside <Popover>`);
|
|
2382
2698
|
return ctx;
|
|
2383
2699
|
}
|
|
2384
2700
|
function Popover({ children, className, open: openProp, onOpenChange }) {
|
|
2385
|
-
const [openState, setOpenState] =
|
|
2701
|
+
const [openState, setOpenState] = React52__namespace.useState(false);
|
|
2386
2702
|
const controlled = openProp !== void 0;
|
|
2387
2703
|
const open = controlled ? openProp : openState;
|
|
2388
|
-
const triggerRef =
|
|
2389
|
-
const ref =
|
|
2390
|
-
const setOpen =
|
|
2704
|
+
const triggerRef = React52__namespace.useRef(null);
|
|
2705
|
+
const ref = React52__namespace.useRef(null);
|
|
2706
|
+
const setOpen = React52__namespace.useCallback(
|
|
2391
2707
|
(v) => {
|
|
2392
2708
|
if (!controlled) setOpenState(v);
|
|
2393
2709
|
onOpenChange?.(v);
|
|
2394
2710
|
},
|
|
2395
2711
|
[controlled, onOpenChange]
|
|
2396
2712
|
);
|
|
2397
|
-
|
|
2713
|
+
React52__namespace.useEffect(() => {
|
|
2398
2714
|
if (!open) return;
|
|
2399
2715
|
const onDoc = (e) => {
|
|
2400
2716
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -2414,7 +2730,7 @@ function Popover({ children, className, open: openProp, onOpenChange }) {
|
|
|
2414
2730
|
}, [open, setOpen]);
|
|
2415
2731
|
return /* @__PURE__ */ jsxRuntime.jsx(PopoverContext.Provider, { value: { open, setOpen, triggerRef }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("relative inline-block", className), children }) });
|
|
2416
2732
|
}
|
|
2417
|
-
var PopoverTrigger =
|
|
2733
|
+
var PopoverTrigger = React52__namespace.forwardRef(({ onClick, asChild, ...props }, ref) => {
|
|
2418
2734
|
const ctx = usePopoverContext("PopoverTrigger");
|
|
2419
2735
|
const setRefs = (node) => {
|
|
2420
2736
|
ctx.triggerRef.current = node;
|
|
@@ -2422,8 +2738,8 @@ var PopoverTrigger = React18__namespace.forwardRef(({ onClick, asChild, ...props
|
|
|
2422
2738
|
else if (ref) ref.current = node;
|
|
2423
2739
|
};
|
|
2424
2740
|
if (asChild) {
|
|
2425
|
-
const child =
|
|
2426
|
-
return
|
|
2741
|
+
const child = React52__namespace.Children.only(props.children);
|
|
2742
|
+
return React52__namespace.cloneElement(child, {
|
|
2427
2743
|
ref: setRefs,
|
|
2428
2744
|
...props,
|
|
2429
2745
|
...child.props,
|
|
@@ -2474,8 +2790,8 @@ function PopoverContent({
|
|
|
2474
2790
|
...props
|
|
2475
2791
|
}) {
|
|
2476
2792
|
const ctx = usePopoverContext("PopoverContent");
|
|
2477
|
-
const ref =
|
|
2478
|
-
|
|
2793
|
+
const ref = React52__namespace.useRef(null);
|
|
2794
|
+
React52__namespace.useEffect(() => {
|
|
2479
2795
|
if (ctx.open) ref.current?.focus();
|
|
2480
2796
|
}, [ctx.open]);
|
|
2481
2797
|
if (!ctx.open) return null;
|
|
@@ -2496,15 +2812,3289 @@ function PopoverContent({
|
|
|
2496
2812
|
}
|
|
2497
2813
|
);
|
|
2498
2814
|
}
|
|
2815
|
+
function toArray(v) {
|
|
2816
|
+
if (v == null) return [];
|
|
2817
|
+
return Array.isArray(v) ? v : [v];
|
|
2818
|
+
}
|
|
2819
|
+
var Combobox = React52__namespace.forwardRef(
|
|
2820
|
+
function Combobox2(props, ref) {
|
|
2821
|
+
const {
|
|
2822
|
+
options,
|
|
2823
|
+
placeholder = "Select\u2026",
|
|
2824
|
+
searchPlaceholder = "Search\u2026",
|
|
2825
|
+
emptyMessage = "No results",
|
|
2826
|
+
disabled = false,
|
|
2827
|
+
error = false,
|
|
2828
|
+
required = false,
|
|
2829
|
+
className,
|
|
2830
|
+
id,
|
|
2831
|
+
name,
|
|
2832
|
+
"aria-describedby": describedBy
|
|
2833
|
+
} = props;
|
|
2834
|
+
const multiple = props.multiple ?? false;
|
|
2835
|
+
const reactId = React52__namespace.useId();
|
|
2836
|
+
const baseId = id ?? reactId;
|
|
2837
|
+
const listId = `${baseId}-listbox`;
|
|
2838
|
+
const optionId = (i) => `${baseId}-opt-${i}`;
|
|
2839
|
+
const controlled = props.value !== void 0;
|
|
2840
|
+
const [internal, setInternal] = React52__namespace.useState(() => toArray(props.defaultValue));
|
|
2841
|
+
const selected = controlled ? toArray(props.value) : internal;
|
|
2842
|
+
const [open, setOpen] = React52__namespace.useState(false);
|
|
2843
|
+
const [search, setSearch] = React52__namespace.useState("");
|
|
2844
|
+
const [activeIndex, setActiveIndex] = React52__namespace.useState(0);
|
|
2845
|
+
const containerRef = React52__namespace.useRef(null);
|
|
2846
|
+
const triggerRef = React52__namespace.useRef(null);
|
|
2847
|
+
const inputRef = React52__namespace.useRef(null);
|
|
2848
|
+
const listRef = React52__namespace.useRef(null);
|
|
2849
|
+
const setTriggerRef = (node) => {
|
|
2850
|
+
triggerRef.current = node;
|
|
2851
|
+
if (typeof ref === "function") ref(node);
|
|
2852
|
+
else if (ref) ref.current = node;
|
|
2853
|
+
};
|
|
2854
|
+
const filtered = React52__namespace.useMemo(() => {
|
|
2855
|
+
const q = search.trim().toLowerCase();
|
|
2856
|
+
return q ? options.filter((o) => o.label.toLowerCase().includes(q)) : options;
|
|
2857
|
+
}, [search, options]);
|
|
2858
|
+
const firstEnabled = React52__namespace.useCallback(() => {
|
|
2859
|
+
const i = filtered.findIndex((o) => !o.disabled);
|
|
2860
|
+
return i === -1 ? 0 : i;
|
|
2861
|
+
}, [filtered]);
|
|
2862
|
+
const labelFor = (v) => options.find((o) => o.value === v)?.label ?? v;
|
|
2863
|
+
const emit = (next) => {
|
|
2864
|
+
if (!controlled) setInternal(next);
|
|
2865
|
+
if (props.multiple) {
|
|
2866
|
+
props.onChange?.(next);
|
|
2867
|
+
} else {
|
|
2868
|
+
props.onChange?.(next[0] ?? "");
|
|
2869
|
+
}
|
|
2870
|
+
};
|
|
2871
|
+
const closePopup = React52__namespace.useCallback(() => {
|
|
2872
|
+
setOpen(false);
|
|
2873
|
+
setSearch("");
|
|
2874
|
+
}, []);
|
|
2875
|
+
const openPopup = () => {
|
|
2876
|
+
if (!disabled) setOpen(true);
|
|
2877
|
+
};
|
|
2878
|
+
const handleSelect = (opt) => {
|
|
2879
|
+
if (opt.disabled) return;
|
|
2880
|
+
if (multiple) {
|
|
2881
|
+
const next = selected.includes(opt.value) ? selected.filter((v) => v !== opt.value) : [...selected, opt.value];
|
|
2882
|
+
emit(next);
|
|
2883
|
+
inputRef.current?.focus();
|
|
2884
|
+
} else {
|
|
2885
|
+
emit([opt.value]);
|
|
2886
|
+
closePopup();
|
|
2887
|
+
triggerRef.current?.focus();
|
|
2888
|
+
}
|
|
2889
|
+
};
|
|
2890
|
+
const removeValue = (value) => {
|
|
2891
|
+
emit(selected.filter((v) => v !== value));
|
|
2892
|
+
};
|
|
2893
|
+
React52__namespace.useEffect(() => {
|
|
2894
|
+
if (open) setActiveIndex(firstEnabled());
|
|
2895
|
+
}, [open, firstEnabled]);
|
|
2896
|
+
React52__namespace.useEffect(() => {
|
|
2897
|
+
if (open) inputRef.current?.focus();
|
|
2898
|
+
}, [open]);
|
|
2899
|
+
React52__namespace.useEffect(() => {
|
|
2900
|
+
if (!open) return;
|
|
2901
|
+
const onDown = (e) => {
|
|
2902
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) closePopup();
|
|
2903
|
+
};
|
|
2904
|
+
document.addEventListener("mousedown", onDown);
|
|
2905
|
+
return () => document.removeEventListener("mousedown", onDown);
|
|
2906
|
+
}, [open, closePopup]);
|
|
2907
|
+
React52__namespace.useEffect(() => {
|
|
2908
|
+
const el = listRef.current?.querySelector('[data-active="true"]');
|
|
2909
|
+
el?.scrollIntoView({ block: "nearest" });
|
|
2910
|
+
}, [activeIndex]);
|
|
2911
|
+
const moveActive = (dir) => {
|
|
2912
|
+
if (filtered.length === 0) return;
|
|
2913
|
+
setActiveIndex((prev) => {
|
|
2914
|
+
let i = prev;
|
|
2915
|
+
for (let step = 0; step < filtered.length; step++) {
|
|
2916
|
+
i = (i + dir + filtered.length) % filtered.length;
|
|
2917
|
+
if (!filtered[i]?.disabled) return i;
|
|
2918
|
+
}
|
|
2919
|
+
return prev;
|
|
2920
|
+
});
|
|
2921
|
+
};
|
|
2922
|
+
const onInputKeyDown = (e) => {
|
|
2923
|
+
switch (e.key) {
|
|
2924
|
+
case "ArrowDown":
|
|
2925
|
+
e.preventDefault();
|
|
2926
|
+
moveActive(1);
|
|
2927
|
+
break;
|
|
2928
|
+
case "ArrowUp":
|
|
2929
|
+
e.preventDefault();
|
|
2930
|
+
moveActive(-1);
|
|
2931
|
+
break;
|
|
2932
|
+
case "Home":
|
|
2933
|
+
e.preventDefault();
|
|
2934
|
+
setActiveIndex(firstEnabled());
|
|
2935
|
+
break;
|
|
2936
|
+
case "End":
|
|
2937
|
+
e.preventDefault();
|
|
2938
|
+
for (let i = filtered.length - 1; i >= 0; i--) {
|
|
2939
|
+
if (!filtered[i].disabled) {
|
|
2940
|
+
setActiveIndex(i);
|
|
2941
|
+
break;
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
break;
|
|
2945
|
+
case "Enter":
|
|
2946
|
+
e.preventDefault();
|
|
2947
|
+
if (filtered[activeIndex]) handleSelect(filtered[activeIndex]);
|
|
2948
|
+
break;
|
|
2949
|
+
case "Escape":
|
|
2950
|
+
e.preventDefault();
|
|
2951
|
+
closePopup();
|
|
2952
|
+
triggerRef.current?.focus();
|
|
2953
|
+
break;
|
|
2954
|
+
case "Backspace":
|
|
2955
|
+
if (multiple && search === "" && selected.length > 0) {
|
|
2956
|
+
removeValue(selected[selected.length - 1]);
|
|
2957
|
+
}
|
|
2958
|
+
break;
|
|
2959
|
+
}
|
|
2960
|
+
};
|
|
2961
|
+
const onTriggerKeyDown = (e) => {
|
|
2962
|
+
if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
|
|
2963
|
+
e.preventDefault();
|
|
2964
|
+
openPopup();
|
|
2965
|
+
}
|
|
2966
|
+
};
|
|
2967
|
+
const showPlaceholder = multiple ? selected.length === 0 : !selected[0];
|
|
2968
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: cn("relative w-full", className), children: [
|
|
2969
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2970
|
+
"div",
|
|
2971
|
+
{
|
|
2972
|
+
className: cn(
|
|
2973
|
+
"relative flex w-full items-center gap-1.5 flex-wrap border rounded-kj-md bg-surface",
|
|
2974
|
+
"pl-[0.85rem] pr-9 py-[calc(0.45rem*var(--kj-density,1))] min-h-[calc(2.5rem*var(--kj-density,1))]",
|
|
2975
|
+
"transition-[border-color,box-shadow] duration-150",
|
|
2976
|
+
"focus-within:outline-none focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/30",
|
|
2977
|
+
disabled && "bg-muted cursor-not-allowed",
|
|
2978
|
+
error ? "border-danger" : "border-input"
|
|
2979
|
+
),
|
|
2980
|
+
children: [
|
|
2981
|
+
multiple && selected.map((value) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2982
|
+
"span",
|
|
2983
|
+
{
|
|
2984
|
+
className: "inline-flex items-center gap-1 rounded-kj-sm bg-primary/10 text-primary text-xs font-medium pl-2 pr-1 py-0.5",
|
|
2985
|
+
children: [
|
|
2986
|
+
labelFor(value),
|
|
2987
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2988
|
+
"button",
|
|
2989
|
+
{
|
|
2990
|
+
type: "button",
|
|
2991
|
+
"aria-label": `Remove ${labelFor(value)}`,
|
|
2992
|
+
disabled,
|
|
2993
|
+
onClick: (e) => {
|
|
2994
|
+
e.stopPropagation();
|
|
2995
|
+
removeValue(value);
|
|
2996
|
+
},
|
|
2997
|
+
className: "rounded-full p-0.5 leading-none hover:bg-primary/20",
|
|
2998
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-3 w-3", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 6l12 12M18 6L6 18" }) })
|
|
2999
|
+
}
|
|
3000
|
+
)
|
|
3001
|
+
]
|
|
3002
|
+
},
|
|
3003
|
+
value
|
|
3004
|
+
)),
|
|
3005
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3006
|
+
"button",
|
|
3007
|
+
{
|
|
3008
|
+
ref: setTriggerRef,
|
|
3009
|
+
type: "button",
|
|
3010
|
+
id,
|
|
3011
|
+
disabled,
|
|
3012
|
+
"aria-haspopup": "listbox",
|
|
3013
|
+
"aria-expanded": open,
|
|
3014
|
+
"aria-controls": open && filtered.length > 0 ? listId : void 0,
|
|
3015
|
+
"aria-invalid": error || void 0,
|
|
3016
|
+
"aria-required": required || void 0,
|
|
3017
|
+
"aria-describedby": describedBy,
|
|
3018
|
+
onClick: () => open ? closePopup() : openPopup(),
|
|
3019
|
+
onKeyDown: onTriggerKeyDown,
|
|
3020
|
+
className: cn(
|
|
3021
|
+
"flex-1 min-w-[60px] text-left bg-transparent border-none outline-none cursor-pointer text-sm disabled:cursor-not-allowed",
|
|
3022
|
+
showPlaceholder && "text-muted-foreground"
|
|
3023
|
+
),
|
|
3024
|
+
children: multiple ? selected.length === 0 ? placeholder : "" : (selected[0] ? labelFor(selected[0]) : "") || placeholder
|
|
3025
|
+
}
|
|
3026
|
+
),
|
|
3027
|
+
name && multiple && selected.map((v) => /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: v }, v)),
|
|
3028
|
+
name && !multiple && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: selected[0] ?? "" }),
|
|
3029
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) }) })
|
|
3030
|
+
]
|
|
3031
|
+
}
|
|
3032
|
+
),
|
|
3033
|
+
open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute z-40 top-[calc(100%+6px)] left-0 w-full min-w-[12rem] bg-surface border border-border rounded-kj-md shadow-kj-lg overflow-hidden animate-[kjpop_.12s_ease]", children: [
|
|
3034
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3035
|
+
"input",
|
|
3036
|
+
{
|
|
3037
|
+
ref: inputRef,
|
|
3038
|
+
type: "text",
|
|
3039
|
+
role: "combobox",
|
|
3040
|
+
"aria-autocomplete": "list",
|
|
3041
|
+
"aria-expanded": open,
|
|
3042
|
+
"aria-controls": filtered.length > 0 ? listId : void 0,
|
|
3043
|
+
"aria-activedescendant": filtered[activeIndex] ? optionId(activeIndex) : void 0,
|
|
3044
|
+
"aria-label": searchPlaceholder,
|
|
3045
|
+
placeholder: searchPlaceholder,
|
|
3046
|
+
value: search,
|
|
3047
|
+
onChange: (e) => setSearch(e.target.value),
|
|
3048
|
+
onKeyDown: onInputKeyDown,
|
|
3049
|
+
className: "w-full bg-transparent text-sm text-foreground placeholder:text-muted-foreground outline-none px-2 py-1"
|
|
3050
|
+
}
|
|
3051
|
+
) }),
|
|
3052
|
+
filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3053
|
+
"div",
|
|
3054
|
+
{
|
|
3055
|
+
ref: listRef,
|
|
3056
|
+
id: listId,
|
|
3057
|
+
role: "listbox",
|
|
3058
|
+
"aria-multiselectable": multiple || void 0,
|
|
3059
|
+
"aria-label": placeholder,
|
|
3060
|
+
className: "max-h-60 overflow-y-auto p-1",
|
|
3061
|
+
children: filtered.map((opt, i) => {
|
|
3062
|
+
const isSelected = selected.includes(opt.value);
|
|
3063
|
+
const isActive = i === activeIndex;
|
|
3064
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3065
|
+
"div",
|
|
3066
|
+
{
|
|
3067
|
+
id: optionId(i),
|
|
3068
|
+
role: "option",
|
|
3069
|
+
"aria-selected": isSelected,
|
|
3070
|
+
"aria-disabled": opt.disabled || void 0,
|
|
3071
|
+
"data-active": isActive || void 0,
|
|
3072
|
+
onMouseEnter: () => !opt.disabled && setActiveIndex(i),
|
|
3073
|
+
onClick: () => handleSelect(opt),
|
|
3074
|
+
className: cn(
|
|
3075
|
+
"flex items-center justify-between gap-2 px-3 py-2 rounded-kj-sm text-sm cursor-pointer select-none",
|
|
3076
|
+
opt.disabled && "text-muted-foreground opacity-50 cursor-not-allowed",
|
|
3077
|
+
!opt.disabled && isActive && "bg-primary/10 text-primary",
|
|
3078
|
+
!opt.disabled && !isActive && "text-foreground hover:bg-muted"
|
|
3079
|
+
),
|
|
3080
|
+
children: [
|
|
3081
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: opt.label }),
|
|
3082
|
+
isSelected && /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4 text-primary shrink-0", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m5 12 5 5L20 7" }) })
|
|
3083
|
+
]
|
|
3084
|
+
},
|
|
3085
|
+
opt.value
|
|
3086
|
+
);
|
|
3087
|
+
})
|
|
3088
|
+
}
|
|
3089
|
+
)
|
|
3090
|
+
] })
|
|
3091
|
+
] });
|
|
3092
|
+
}
|
|
3093
|
+
);
|
|
3094
|
+
Combobox.displayName = "Combobox";
|
|
3095
|
+
var ComboboxField = React52__namespace.forwardRef(
|
|
3096
|
+
function ComboboxField2({ label, hint, error, required, className, ...props }, ref) {
|
|
3097
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsxRuntime.jsx(Combobox, { ref, error: !!error, ...props }) });
|
|
3098
|
+
}
|
|
3099
|
+
);
|
|
3100
|
+
ComboboxField.displayName = "ComboboxField";
|
|
3101
|
+
|
|
3102
|
+
// src/components/calendar-internals.ts
|
|
3103
|
+
function startOfDay(d) {
|
|
3104
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
3105
|
+
}
|
|
3106
|
+
function isSameDay(a, b) {
|
|
3107
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
3108
|
+
}
|
|
3109
|
+
function addDays(d, n) {
|
|
3110
|
+
const r = new Date(d);
|
|
3111
|
+
r.setDate(r.getDate() + n);
|
|
3112
|
+
return r;
|
|
3113
|
+
}
|
|
3114
|
+
function addMonths(d, n) {
|
|
3115
|
+
const r = new Date(d);
|
|
3116
|
+
r.setMonth(r.getMonth() + n);
|
|
3117
|
+
return r;
|
|
3118
|
+
}
|
|
3119
|
+
function clampToMonth(year, month, day) {
|
|
3120
|
+
const daysInTarget = new Date(year, month + 1, 0).getDate();
|
|
3121
|
+
return new Date(year, month, Math.min(day, daysInTarget));
|
|
3122
|
+
}
|
|
3123
|
+
function addMonthsClamped(d, n) {
|
|
3124
|
+
return clampToMonth(d.getFullYear(), d.getMonth() + n, d.getDate());
|
|
3125
|
+
}
|
|
3126
|
+
function addYearsClamped(d, n) {
|
|
3127
|
+
return clampToMonth(d.getFullYear() + n, d.getMonth(), d.getDate());
|
|
3128
|
+
}
|
|
3129
|
+
function startOfMonth(d) {
|
|
3130
|
+
return new Date(d.getFullYear(), d.getMonth(), 1);
|
|
3131
|
+
}
|
|
3132
|
+
function startOfWeek(d) {
|
|
3133
|
+
const r = startOfDay(d);
|
|
3134
|
+
r.setDate(r.getDate() - r.getDay());
|
|
3135
|
+
return r;
|
|
3136
|
+
}
|
|
3137
|
+
function buildGridDays(viewMonth) {
|
|
3138
|
+
const gridStart = startOfWeek(startOfMonth(viewMonth));
|
|
3139
|
+
return Array.from({ length: 42 }, (_, i) => addDays(gridStart, i));
|
|
3140
|
+
}
|
|
3141
|
+
function dateKey(d) {
|
|
3142
|
+
return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
|
|
3143
|
+
}
|
|
3144
|
+
function toISODateString(d) {
|
|
3145
|
+
const y = d.getFullYear();
|
|
3146
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
3147
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
3148
|
+
return `${y}-${m}-${day}`;
|
|
3149
|
+
}
|
|
3150
|
+
var monthLabelFormat = new Intl.DateTimeFormat(void 0, { month: "long", year: "numeric" });
|
|
3151
|
+
var fullDateFormat = new Intl.DateTimeFormat(void 0, { dateStyle: "full" });
|
|
3152
|
+
var weekdayShortFormat = new Intl.DateTimeFormat(void 0, { weekday: "short" });
|
|
3153
|
+
var weekdayLongFormat = new Intl.DateTimeFormat(void 0, { weekday: "long" });
|
|
3154
|
+
var weekdayLabels = Array.from({ length: 7 }, (_, i) => {
|
|
3155
|
+
const d = addDays(startOfWeek(/* @__PURE__ */ new Date()), i);
|
|
3156
|
+
return { key: i, short: weekdayShortFormat.format(d), long: weekdayLongFormat.format(d) };
|
|
3157
|
+
});
|
|
3158
|
+
var CalendarGrid = React52__namespace.forwardRef(function CalendarGrid2({ viewMonth, isDayDisabled, cellState, onSelectDay, onFocusDay, initialFocusDate, className }, ref) {
|
|
3159
|
+
const gridDays = React52__namespace.useMemo(() => buildGridDays(viewMonth), [viewMonth]);
|
|
3160
|
+
const inViewMonth = (d) => d.getMonth() === viewMonth.getMonth() && d.getFullYear() === viewMonth.getFullYear();
|
|
3161
|
+
const [focusedDate, setFocusedDate] = React52__namespace.useState(() => startOfDay(initialFocusDate));
|
|
3162
|
+
const pendingFocusRef = React52__namespace.useRef(false);
|
|
3163
|
+
const gridRef = React52__namespace.useRef(null);
|
|
3164
|
+
const rovingTarget = inViewMonth(focusedDate) && !isDayDisabled(focusedDate) ? focusedDate : gridDays.find((d) => inViewMonth(d) && !isDayDisabled(d)) ?? gridDays.find((d) => inViewMonth(d)) ?? gridDays[0];
|
|
3165
|
+
const moveFocusTo = (next, viaKeyboard) => {
|
|
3166
|
+
pendingFocusRef.current = viaKeyboard;
|
|
3167
|
+
setFocusedDate(next);
|
|
3168
|
+
onFocusDay?.(next);
|
|
3169
|
+
};
|
|
3170
|
+
React52__namespace.useEffect(() => {
|
|
3171
|
+
if (!pendingFocusRef.current) return;
|
|
3172
|
+
pendingFocusRef.current = false;
|
|
3173
|
+
const el = gridRef.current?.querySelector(`[data-date="${dateKey(rovingTarget)}"]`);
|
|
3174
|
+
el?.focus();
|
|
3175
|
+
}, [rovingTarget]);
|
|
3176
|
+
const step = (from, delta) => {
|
|
3177
|
+
let next = addDays(from, delta);
|
|
3178
|
+
let guard = 0;
|
|
3179
|
+
while (isDayDisabled(next) && guard < 1e3) {
|
|
3180
|
+
next = addDays(next, delta);
|
|
3181
|
+
guard++;
|
|
3182
|
+
}
|
|
3183
|
+
return isDayDisabled(next) ? from : next;
|
|
3184
|
+
};
|
|
3185
|
+
const selectDay = (d) => {
|
|
3186
|
+
if (isDayDisabled(d)) return;
|
|
3187
|
+
moveFocusTo(d, false);
|
|
3188
|
+
onSelectDay(d);
|
|
3189
|
+
};
|
|
3190
|
+
const onGridKeyDown = (e) => {
|
|
3191
|
+
switch (e.key) {
|
|
3192
|
+
case "ArrowRight":
|
|
3193
|
+
e.preventDefault();
|
|
3194
|
+
moveFocusTo(step(rovingTarget, 1), true);
|
|
3195
|
+
break;
|
|
3196
|
+
case "ArrowLeft":
|
|
3197
|
+
e.preventDefault();
|
|
3198
|
+
moveFocusTo(step(rovingTarget, -1), true);
|
|
3199
|
+
break;
|
|
3200
|
+
case "ArrowDown":
|
|
3201
|
+
e.preventDefault();
|
|
3202
|
+
moveFocusTo(step(rovingTarget, 7), true);
|
|
3203
|
+
break;
|
|
3204
|
+
case "ArrowUp":
|
|
3205
|
+
e.preventDefault();
|
|
3206
|
+
moveFocusTo(step(rovingTarget, -7), true);
|
|
3207
|
+
break;
|
|
3208
|
+
case "Home": {
|
|
3209
|
+
e.preventDefault();
|
|
3210
|
+
const target = startOfWeek(rovingTarget);
|
|
3211
|
+
moveFocusTo(isDayDisabled(target) ? step(target, 1) : target, true);
|
|
3212
|
+
break;
|
|
3213
|
+
}
|
|
3214
|
+
case "End": {
|
|
3215
|
+
e.preventDefault();
|
|
3216
|
+
const target = addDays(startOfWeek(rovingTarget), 6);
|
|
3217
|
+
moveFocusTo(isDayDisabled(target) ? step(target, -1) : target, true);
|
|
3218
|
+
break;
|
|
3219
|
+
}
|
|
3220
|
+
case "PageUp": {
|
|
3221
|
+
e.preventDefault();
|
|
3222
|
+
const target = e.shiftKey ? addYearsClamped(rovingTarget, -1) : addMonthsClamped(rovingTarget, -1);
|
|
3223
|
+
moveFocusTo(isDayDisabled(target) ? step(target, -1) : target, true);
|
|
3224
|
+
break;
|
|
3225
|
+
}
|
|
3226
|
+
case "PageDown": {
|
|
3227
|
+
e.preventDefault();
|
|
3228
|
+
const target = e.shiftKey ? addYearsClamped(rovingTarget, 1) : addMonthsClamped(rovingTarget, 1);
|
|
3229
|
+
moveFocusTo(isDayDisabled(target) ? step(target, 1) : target, true);
|
|
3230
|
+
break;
|
|
3231
|
+
}
|
|
3232
|
+
case "Enter":
|
|
3233
|
+
case " ":
|
|
3234
|
+
e.preventDefault();
|
|
3235
|
+
selectDay(rovingTarget);
|
|
3236
|
+
break;
|
|
3237
|
+
}
|
|
3238
|
+
};
|
|
3239
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn(className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: gridRef, role: "grid", "aria-label": monthLabelFormat.format(viewMonth), onKeyDown: onGridKeyDown, children: [
|
|
3240
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { role: "row", className: "grid grid-cols-7", children: weekdayLabels.map((w) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3241
|
+
"div",
|
|
3242
|
+
{
|
|
3243
|
+
role: "columnheader",
|
|
3244
|
+
"aria-label": w.long,
|
|
3245
|
+
className: "h-8 flex items-center justify-center text-xs font-medium text-muted-foreground",
|
|
3246
|
+
children: w.short
|
|
3247
|
+
},
|
|
3248
|
+
w.key
|
|
3249
|
+
)) }),
|
|
3250
|
+
Array.from({ length: 6 }, (_, week) => /* @__PURE__ */ jsxRuntime.jsx("div", { role: "row", className: "grid grid-cols-7", children: gridDays.slice(week * 7, week * 7 + 7).map((day) => {
|
|
3251
|
+
if (!inViewMonth(day)) {
|
|
3252
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "gridcell", "aria-hidden": "true", className: "h-9" }, dateKey(day));
|
|
3253
|
+
}
|
|
3254
|
+
const disabled = isDayDisabled(day);
|
|
3255
|
+
const state = cellState(day);
|
|
3256
|
+
const isRoving = isSameDay(day, rovingTarget);
|
|
3257
|
+
const isEndpoint = !!(state.selected || state.rangeStart || state.rangeEnd);
|
|
3258
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3259
|
+
"button",
|
|
3260
|
+
{
|
|
3261
|
+
type: "button",
|
|
3262
|
+
role: "gridcell",
|
|
3263
|
+
"data-date": dateKey(day),
|
|
3264
|
+
tabIndex: isRoving ? 0 : -1,
|
|
3265
|
+
"aria-selected": isEndpoint,
|
|
3266
|
+
"aria-disabled": disabled || void 0,
|
|
3267
|
+
"aria-label": fullDateFormat.format(day),
|
|
3268
|
+
onMouseEnter: () => onFocusDay?.(day),
|
|
3269
|
+
onClick: () => selectDay(day),
|
|
3270
|
+
className: cn(
|
|
3271
|
+
"h-9 w-9 mx-auto flex items-center justify-center text-sm",
|
|
3272
|
+
state.inRange && !isEndpoint ? "rounded-none" : "rounded-full",
|
|
3273
|
+
"focus:outline-none focus:ring-[3px] focus:ring-ring/30",
|
|
3274
|
+
disabled && "text-muted-foreground opacity-40 cursor-not-allowed",
|
|
3275
|
+
!disabled && isEndpoint && "bg-primary text-primary-foreground",
|
|
3276
|
+
!disabled && state.inRange && !isEndpoint && "bg-primary/15 text-foreground",
|
|
3277
|
+
!disabled && !isEndpoint && !state.inRange && state.today && "ring-1 ring-primary text-primary font-medium",
|
|
3278
|
+
!disabled && !isEndpoint && !state.inRange && !state.today && "text-foreground hover:bg-muted"
|
|
3279
|
+
),
|
|
3280
|
+
children: day.getDate()
|
|
3281
|
+
},
|
|
3282
|
+
dateKey(day)
|
|
3283
|
+
);
|
|
3284
|
+
}) }, week))
|
|
3285
|
+
] }) });
|
|
3286
|
+
});
|
|
3287
|
+
CalendarGrid.displayName = "CalendarGrid";
|
|
3288
|
+
var Calendar = React52__namespace.forwardRef(
|
|
3289
|
+
function Calendar2({ value, defaultValue, onChange, month, defaultMonth, onMonthChange, min, max, disabledDates, className }, ref) {
|
|
3290
|
+
const controlled = value !== void 0;
|
|
3291
|
+
const [internalValue, setInternalValue] = React52__namespace.useState(defaultValue);
|
|
3292
|
+
const selected = controlled ? value : internalValue;
|
|
3293
|
+
const monthControlled = month !== void 0;
|
|
3294
|
+
const [internalMonth, setInternalMonth] = React52__namespace.useState(
|
|
3295
|
+
() => startOfMonth(month ?? defaultMonth ?? selected ?? /* @__PURE__ */ new Date())
|
|
3296
|
+
);
|
|
3297
|
+
const viewMonth = monthControlled ? startOfMonth(month) : internalMonth;
|
|
3298
|
+
const setViewMonth = (next) => {
|
|
3299
|
+
const normalized = startOfMonth(next);
|
|
3300
|
+
if (!monthControlled) setInternalMonth(normalized);
|
|
3301
|
+
onMonthChange?.(normalized);
|
|
3302
|
+
};
|
|
3303
|
+
const isDayDisabled = React52__namespace.useCallback(
|
|
3304
|
+
(d) => {
|
|
3305
|
+
if (min && d < startOfDay(min)) return true;
|
|
3306
|
+
if (max && d > startOfDay(max)) return true;
|
|
3307
|
+
return disabledDates?.(d) ?? false;
|
|
3308
|
+
},
|
|
3309
|
+
[min, max, disabledDates]
|
|
3310
|
+
);
|
|
3311
|
+
const commitValue = (d) => {
|
|
3312
|
+
if (!controlled) setInternalValue(d);
|
|
3313
|
+
onChange?.(d);
|
|
3314
|
+
};
|
|
3315
|
+
const today = /* @__PURE__ */ new Date();
|
|
3316
|
+
const cellState = (d) => ({
|
|
3317
|
+
selected: selected ? isSameDay(d, selected) : false,
|
|
3318
|
+
today: isSameDay(d, today)
|
|
3319
|
+
});
|
|
3320
|
+
const inViewMonth = (d) => d.getMonth() === viewMonth.getMonth() && d.getFullYear() === viewMonth.getFullYear();
|
|
3321
|
+
const handleFocusDay = (d) => {
|
|
3322
|
+
if (!inViewMonth(d)) setViewMonth(d);
|
|
3323
|
+
};
|
|
3324
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("w-[280px] select-none", className), children: [
|
|
3325
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
3326
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3327
|
+
"button",
|
|
3328
|
+
{
|
|
3329
|
+
type: "button",
|
|
3330
|
+
"aria-label": "Previous month",
|
|
3331
|
+
onClick: () => setViewMonth(addMonths(viewMonth, -1)),
|
|
3332
|
+
className: "p-1.5 rounded-kj-sm text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
3333
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) })
|
|
3334
|
+
}
|
|
3335
|
+
),
|
|
3336
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground", children: monthLabelFormat.format(viewMonth) }),
|
|
3337
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3338
|
+
"button",
|
|
3339
|
+
{
|
|
3340
|
+
type: "button",
|
|
3341
|
+
"aria-label": "Next month",
|
|
3342
|
+
onClick: () => setViewMonth(addMonths(viewMonth, 1)),
|
|
3343
|
+
className: "p-1.5 rounded-kj-sm text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
3344
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) })
|
|
3345
|
+
}
|
|
3346
|
+
)
|
|
3347
|
+
] }),
|
|
3348
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3349
|
+
CalendarGrid,
|
|
3350
|
+
{
|
|
3351
|
+
viewMonth,
|
|
3352
|
+
isDayDisabled,
|
|
3353
|
+
cellState,
|
|
3354
|
+
onSelectDay: commitValue,
|
|
3355
|
+
onFocusDay: handleFocusDay,
|
|
3356
|
+
initialFocusDate: selected ?? /* @__PURE__ */ new Date()
|
|
3357
|
+
}
|
|
3358
|
+
)
|
|
3359
|
+
] });
|
|
3360
|
+
}
|
|
3361
|
+
);
|
|
3362
|
+
Calendar.displayName = "Calendar";
|
|
3363
|
+
var displayFormat = new Intl.DateTimeFormat(void 0, { dateStyle: "medium" });
|
|
3364
|
+
var DatePicker = React52__namespace.forwardRef(
|
|
3365
|
+
function DatePicker2({
|
|
3366
|
+
value,
|
|
3367
|
+
defaultValue,
|
|
3368
|
+
onChange,
|
|
3369
|
+
min,
|
|
3370
|
+
max,
|
|
3371
|
+
disabledDates,
|
|
3372
|
+
placeholder = "Pick a date\u2026",
|
|
3373
|
+
disabled = false,
|
|
3374
|
+
error = false,
|
|
3375
|
+
required = false,
|
|
3376
|
+
className,
|
|
3377
|
+
id,
|
|
3378
|
+
name,
|
|
3379
|
+
"aria-describedby": describedBy
|
|
3380
|
+
}, ref) {
|
|
3381
|
+
const controlled = value !== void 0;
|
|
3382
|
+
const [internalValue, setInternalValue] = React52__namespace.useState(defaultValue);
|
|
3383
|
+
const selected = controlled ? value : internalValue;
|
|
3384
|
+
const [open, setOpen] = React52__namespace.useState(false);
|
|
3385
|
+
const containerRef = React52__namespace.useRef(null);
|
|
3386
|
+
const triggerRef = React52__namespace.useRef(null);
|
|
3387
|
+
const setTriggerRef = (node) => {
|
|
3388
|
+
triggerRef.current = node;
|
|
3389
|
+
if (typeof ref === "function") ref(node);
|
|
3390
|
+
else if (ref) ref.current = node;
|
|
3391
|
+
};
|
|
3392
|
+
const commitValue = (d) => {
|
|
3393
|
+
if (!controlled) setInternalValue(d);
|
|
3394
|
+
onChange?.(d);
|
|
3395
|
+
};
|
|
3396
|
+
const closePopup = React52__namespace.useCallback(() => setOpen(false), []);
|
|
3397
|
+
const openPopup = () => {
|
|
3398
|
+
if (!disabled) setOpen(true);
|
|
3399
|
+
};
|
|
3400
|
+
const handleCalendarChange = (d) => {
|
|
3401
|
+
commitValue(d);
|
|
3402
|
+
closePopup();
|
|
3403
|
+
triggerRef.current?.focus();
|
|
3404
|
+
};
|
|
3405
|
+
React52__namespace.useEffect(() => {
|
|
3406
|
+
if (!open) return;
|
|
3407
|
+
const onDown = (e) => {
|
|
3408
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) closePopup();
|
|
3409
|
+
};
|
|
3410
|
+
document.addEventListener("mousedown", onDown);
|
|
3411
|
+
return () => document.removeEventListener("mousedown", onDown);
|
|
3412
|
+
}, [open, closePopup]);
|
|
3413
|
+
const onTriggerKeyDown = (e) => {
|
|
3414
|
+
if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
|
|
3415
|
+
e.preventDefault();
|
|
3416
|
+
openPopup();
|
|
3417
|
+
} else if (e.key === "Escape" && open) {
|
|
3418
|
+
e.preventDefault();
|
|
3419
|
+
closePopup();
|
|
3420
|
+
}
|
|
3421
|
+
};
|
|
3422
|
+
const onPanelKeyDown = (e) => {
|
|
3423
|
+
if (e.key === "Escape") {
|
|
3424
|
+
e.preventDefault();
|
|
3425
|
+
closePopup();
|
|
3426
|
+
triggerRef.current?.focus();
|
|
3427
|
+
}
|
|
3428
|
+
};
|
|
3429
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: cn("relative inline-block w-full", className), children: [
|
|
3430
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3431
|
+
"button",
|
|
3432
|
+
{
|
|
3433
|
+
ref: setTriggerRef,
|
|
3434
|
+
type: "button",
|
|
3435
|
+
id,
|
|
3436
|
+
disabled,
|
|
3437
|
+
"aria-haspopup": "grid",
|
|
3438
|
+
"aria-expanded": open,
|
|
3439
|
+
"aria-invalid": error || void 0,
|
|
3440
|
+
"aria-required": required || void 0,
|
|
3441
|
+
"aria-describedby": describedBy,
|
|
3442
|
+
onClick: () => open ? closePopup() : openPopup(),
|
|
3443
|
+
onKeyDown: onTriggerKeyDown,
|
|
3444
|
+
className: cn(
|
|
3445
|
+
"w-full flex items-center justify-between gap-2 border rounded-kj-md bg-surface text-left text-sm",
|
|
3446
|
+
"pl-[0.85rem] pr-3 py-[calc(0.6rem*var(--kj-density,1))]",
|
|
3447
|
+
"transition-[border-color,box-shadow] duration-150",
|
|
3448
|
+
"focus:outline-none focus:border-ring focus:ring-[3px] focus:ring-ring/30",
|
|
3449
|
+
disabled && "bg-muted text-muted-foreground cursor-not-allowed",
|
|
3450
|
+
error ? "border-danger" : "border-input",
|
|
3451
|
+
!selected && "text-muted-foreground"
|
|
3452
|
+
),
|
|
3453
|
+
children: [
|
|
3454
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: selected ? displayFormat.format(selected) : placeholder }),
|
|
3455
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3456
|
+
"svg",
|
|
3457
|
+
{
|
|
3458
|
+
viewBox: "0 0 24 24",
|
|
3459
|
+
className: "h-4 w-4 text-muted-foreground shrink-0",
|
|
3460
|
+
fill: "none",
|
|
3461
|
+
stroke: "currentColor",
|
|
3462
|
+
strokeWidth: "2",
|
|
3463
|
+
strokeLinecap: "round",
|
|
3464
|
+
strokeLinejoin: "round",
|
|
3465
|
+
children: [
|
|
3466
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
|
|
3467
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 10h18M8 2v4M16 2v4" })
|
|
3468
|
+
]
|
|
3469
|
+
}
|
|
3470
|
+
)
|
|
3471
|
+
]
|
|
3472
|
+
}
|
|
3473
|
+
),
|
|
3474
|
+
name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: selected ? toISODateString(selected) : "" }),
|
|
3475
|
+
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3476
|
+
"div",
|
|
3477
|
+
{
|
|
3478
|
+
onKeyDown: onPanelKeyDown,
|
|
3479
|
+
className: "absolute z-40 top-[calc(100%+6px)] left-0 bg-surface border border-border rounded-kj-md shadow-kj-lg p-3 animate-[kjpop_.12s_ease]",
|
|
3480
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Calendar, { value: selected, onChange: handleCalendarChange, min, max, disabledDates })
|
|
3481
|
+
}
|
|
3482
|
+
)
|
|
3483
|
+
] });
|
|
3484
|
+
}
|
|
3485
|
+
);
|
|
3486
|
+
DatePicker.displayName = "DatePicker";
|
|
3487
|
+
var DatePickerField = React52__namespace.forwardRef(
|
|
3488
|
+
function DatePickerField2({ label, hint, error, required, className, ...props }, ref) {
|
|
3489
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsxRuntime.jsx(DatePicker, { ref, error: !!error, ...props }) });
|
|
3490
|
+
}
|
|
3491
|
+
);
|
|
3492
|
+
DatePickerField.displayName = "DatePickerField";
|
|
3493
|
+
function isBetweenExclusive(d, lo, hi) {
|
|
3494
|
+
const t = startOfDay(d).getTime();
|
|
3495
|
+
return t > startOfDay(lo).getTime() && t < startOfDay(hi).getTime();
|
|
3496
|
+
}
|
|
3497
|
+
var RangeCalendar = React52__namespace.forwardRef(
|
|
3498
|
+
function RangeCalendar2({ value, defaultValue, onChange, month, defaultMonth, onMonthChange, min, max, disabledDates, className }, ref) {
|
|
3499
|
+
const controlled = value !== void 0;
|
|
3500
|
+
const [internalValue, setInternalValue] = React52__namespace.useState(defaultValue ?? {});
|
|
3501
|
+
const range2 = controlled ? value : internalValue;
|
|
3502
|
+
const monthControlled = month !== void 0;
|
|
3503
|
+
const [internalMonth, setInternalMonth] = React52__namespace.useState(
|
|
3504
|
+
() => startOfMonth(month ?? defaultMonth ?? range2.start ?? /* @__PURE__ */ new Date())
|
|
3505
|
+
);
|
|
3506
|
+
const leftMonth = monthControlled ? startOfMonth(month) : internalMonth;
|
|
3507
|
+
const rightMonth = addMonths(leftMonth, 1);
|
|
3508
|
+
const setViewMonth = (next) => {
|
|
3509
|
+
const normalized = startOfMonth(next);
|
|
3510
|
+
if (!monthControlled) setInternalMonth(normalized);
|
|
3511
|
+
onMonthChange?.(normalized);
|
|
3512
|
+
};
|
|
3513
|
+
const isDayDisabled = React52__namespace.useCallback(
|
|
3514
|
+
(d) => {
|
|
3515
|
+
if (min && d < startOfDay(min)) return true;
|
|
3516
|
+
if (max && d > startOfDay(max)) return true;
|
|
3517
|
+
return disabledDates?.(d) ?? false;
|
|
3518
|
+
},
|
|
3519
|
+
[min, max, disabledDates]
|
|
3520
|
+
);
|
|
3521
|
+
const [pendingStart, setPendingStart] = React52__namespace.useState(void 0);
|
|
3522
|
+
const [hoverDate, setHoverDate] = React52__namespace.useState(void 0);
|
|
3523
|
+
const commitRange = (next) => {
|
|
3524
|
+
if (!controlled) setInternalValue(next);
|
|
3525
|
+
onChange?.(next);
|
|
3526
|
+
};
|
|
3527
|
+
const handleSelectDay = (d) => {
|
|
3528
|
+
const day = startOfDay(d);
|
|
3529
|
+
if (pendingStart === void 0) {
|
|
3530
|
+
setPendingStart(day);
|
|
3531
|
+
setHoverDate(void 0);
|
|
3532
|
+
return;
|
|
3533
|
+
}
|
|
3534
|
+
if (day < startOfDay(pendingStart)) {
|
|
3535
|
+
setPendingStart(day);
|
|
3536
|
+
setHoverDate(void 0);
|
|
3537
|
+
return;
|
|
3538
|
+
}
|
|
3539
|
+
commitRange({ start: pendingStart, end: day });
|
|
3540
|
+
setPendingStart(void 0);
|
|
3541
|
+
setHoverDate(void 0);
|
|
3542
|
+
};
|
|
3543
|
+
const today = /* @__PURE__ */ new Date();
|
|
3544
|
+
const previewEnd = pendingStart !== void 0 ? hoverDate : void 0;
|
|
3545
|
+
const cellState = (d) => {
|
|
3546
|
+
const isToday = isSameDay(d, today);
|
|
3547
|
+
if (pendingStart !== void 0) {
|
|
3548
|
+
if (previewEnd === void 0) {
|
|
3549
|
+
return { rangeStart: isSameDay(d, pendingStart), today: isToday };
|
|
3550
|
+
}
|
|
3551
|
+
if (startOfDay(previewEnd) < startOfDay(pendingStart)) {
|
|
3552
|
+
return { rangeStart: isSameDay(d, previewEnd), today: isToday };
|
|
3553
|
+
}
|
|
3554
|
+
return {
|
|
3555
|
+
rangeStart: isSameDay(d, pendingStart),
|
|
3556
|
+
rangeEnd: isSameDay(d, previewEnd),
|
|
3557
|
+
inRange: isBetweenExclusive(d, pendingStart, previewEnd),
|
|
3558
|
+
today: isToday
|
|
3559
|
+
};
|
|
3560
|
+
}
|
|
3561
|
+
if (range2.start && range2.end) {
|
|
3562
|
+
return {
|
|
3563
|
+
rangeStart: isSameDay(d, range2.start),
|
|
3564
|
+
rangeEnd: isSameDay(d, range2.end),
|
|
3565
|
+
inRange: isBetweenExclusive(d, range2.start, range2.end),
|
|
3566
|
+
today: isToday
|
|
3567
|
+
};
|
|
3568
|
+
}
|
|
3569
|
+
return { rangeStart: range2.start ? isSameDay(d, range2.start) : false, today: isToday };
|
|
3570
|
+
};
|
|
3571
|
+
const inLockedRange = (d) => d.getMonth() === leftMonth.getMonth() && d.getFullYear() === leftMonth.getFullYear() || d.getMonth() === rightMonth.getMonth() && d.getFullYear() === rightMonth.getFullYear();
|
|
3572
|
+
const handleFocusDay = (d) => {
|
|
3573
|
+
if (pendingStart !== void 0) setHoverDate(d);
|
|
3574
|
+
if (!inLockedRange(d)) setViewMonth(d);
|
|
3575
|
+
};
|
|
3576
|
+
const navButton = (direction) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3577
|
+
"button",
|
|
3578
|
+
{
|
|
3579
|
+
type: "button",
|
|
3580
|
+
"aria-label": direction === "prev" ? "Previous month" : "Next month",
|
|
3581
|
+
onClick: () => setViewMonth(addMonths(leftMonth, direction === "prev" ? -1 : 1)),
|
|
3582
|
+
className: "p-1.5 rounded-kj-sm text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
3583
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: direction === "prev" ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) : /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) })
|
|
3584
|
+
}
|
|
3585
|
+
);
|
|
3586
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("flex gap-6 select-none", className), children: [
|
|
3587
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-[280px]", children: [
|
|
3588
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
3589
|
+
navButton("prev"),
|
|
3590
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground", children: monthLabelFormat.format(leftMonth) }),
|
|
3591
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-[26px]", "aria-hidden": "true" })
|
|
3592
|
+
] }),
|
|
3593
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3594
|
+
CalendarGrid,
|
|
3595
|
+
{
|
|
3596
|
+
viewMonth: leftMonth,
|
|
3597
|
+
isDayDisabled,
|
|
3598
|
+
cellState,
|
|
3599
|
+
onSelectDay: handleSelectDay,
|
|
3600
|
+
onFocusDay: handleFocusDay,
|
|
3601
|
+
initialFocusDate: pendingStart ?? range2.start ?? /* @__PURE__ */ new Date()
|
|
3602
|
+
}
|
|
3603
|
+
)
|
|
3604
|
+
] }),
|
|
3605
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-[280px]", children: [
|
|
3606
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
3607
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-[26px]", "aria-hidden": "true" }),
|
|
3608
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground", children: monthLabelFormat.format(rightMonth) }),
|
|
3609
|
+
navButton("next")
|
|
3610
|
+
] }),
|
|
3611
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3612
|
+
CalendarGrid,
|
|
3613
|
+
{
|
|
3614
|
+
viewMonth: rightMonth,
|
|
3615
|
+
isDayDisabled,
|
|
3616
|
+
cellState,
|
|
3617
|
+
onSelectDay: handleSelectDay,
|
|
3618
|
+
onFocusDay: handleFocusDay,
|
|
3619
|
+
initialFocusDate: pendingStart ?? range2.start ?? /* @__PURE__ */ new Date()
|
|
3620
|
+
}
|
|
3621
|
+
)
|
|
3622
|
+
] })
|
|
3623
|
+
] });
|
|
3624
|
+
}
|
|
3625
|
+
);
|
|
3626
|
+
RangeCalendar.displayName = "RangeCalendar";
|
|
3627
|
+
var displayFormat2 = new Intl.DateTimeFormat(void 0, { dateStyle: "medium" });
|
|
3628
|
+
function formatRangeLabel(range2) {
|
|
3629
|
+
if (!range2.start || !range2.end) return void 0;
|
|
3630
|
+
return `${displayFormat2.format(range2.start)} \u2013 ${displayFormat2.format(range2.end)}`;
|
|
3631
|
+
}
|
|
3632
|
+
var DateRangePicker = React52__namespace.forwardRef(
|
|
3633
|
+
function DateRangePicker2({
|
|
3634
|
+
value,
|
|
3635
|
+
defaultValue,
|
|
3636
|
+
onChange,
|
|
3637
|
+
min,
|
|
3638
|
+
max,
|
|
3639
|
+
disabledDates,
|
|
3640
|
+
placeholder = "Pick a date range\u2026",
|
|
3641
|
+
disabled = false,
|
|
3642
|
+
error = false,
|
|
3643
|
+
required = false,
|
|
3644
|
+
className,
|
|
3645
|
+
id,
|
|
3646
|
+
name,
|
|
3647
|
+
"aria-describedby": describedBy
|
|
3648
|
+
}, ref) {
|
|
3649
|
+
const controlled = value !== void 0;
|
|
3650
|
+
const [internalValue, setInternalValue] = React52__namespace.useState(defaultValue ?? {});
|
|
3651
|
+
const selected = controlled ? value : internalValue;
|
|
3652
|
+
const [open, setOpen] = React52__namespace.useState(false);
|
|
3653
|
+
const containerRef = React52__namespace.useRef(null);
|
|
3654
|
+
const triggerRef = React52__namespace.useRef(null);
|
|
3655
|
+
const setTriggerRef = (node) => {
|
|
3656
|
+
triggerRef.current = node;
|
|
3657
|
+
if (typeof ref === "function") ref(node);
|
|
3658
|
+
else if (ref) ref.current = node;
|
|
3659
|
+
};
|
|
3660
|
+
const commitValue = (r) => {
|
|
3661
|
+
if (!controlled) setInternalValue(r);
|
|
3662
|
+
onChange?.(r);
|
|
3663
|
+
};
|
|
3664
|
+
const closePopup = React52__namespace.useCallback(() => setOpen(false), []);
|
|
3665
|
+
const openPopup = () => {
|
|
3666
|
+
if (!disabled) setOpen(true);
|
|
3667
|
+
};
|
|
3668
|
+
const handleRangeChange = (r) => {
|
|
3669
|
+
commitValue(r);
|
|
3670
|
+
closePopup();
|
|
3671
|
+
triggerRef.current?.focus();
|
|
3672
|
+
};
|
|
3673
|
+
React52__namespace.useEffect(() => {
|
|
3674
|
+
if (!open) return;
|
|
3675
|
+
const onDown = (e) => {
|
|
3676
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) closePopup();
|
|
3677
|
+
};
|
|
3678
|
+
document.addEventListener("mousedown", onDown);
|
|
3679
|
+
return () => document.removeEventListener("mousedown", onDown);
|
|
3680
|
+
}, [open, closePopup]);
|
|
3681
|
+
const onTriggerKeyDown = (e) => {
|
|
3682
|
+
if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
|
|
3683
|
+
e.preventDefault();
|
|
3684
|
+
openPopup();
|
|
3685
|
+
} else if (e.key === "Escape" && open) {
|
|
3686
|
+
e.preventDefault();
|
|
3687
|
+
closePopup();
|
|
3688
|
+
triggerRef.current?.focus();
|
|
3689
|
+
}
|
|
3690
|
+
};
|
|
3691
|
+
const onPanelKeyDown = (e) => {
|
|
3692
|
+
if (e.key === "Escape") {
|
|
3693
|
+
e.preventDefault();
|
|
3694
|
+
closePopup();
|
|
3695
|
+
triggerRef.current?.focus();
|
|
3696
|
+
}
|
|
3697
|
+
};
|
|
3698
|
+
const label = formatRangeLabel(selected);
|
|
3699
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: cn("relative inline-block w-full", className), children: [
|
|
3700
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3701
|
+
"button",
|
|
3702
|
+
{
|
|
3703
|
+
ref: setTriggerRef,
|
|
3704
|
+
type: "button",
|
|
3705
|
+
id,
|
|
3706
|
+
disabled,
|
|
3707
|
+
"aria-haspopup": "dialog",
|
|
3708
|
+
"aria-expanded": open,
|
|
3709
|
+
"aria-invalid": error || void 0,
|
|
3710
|
+
"aria-required": required || void 0,
|
|
3711
|
+
"aria-describedby": describedBy,
|
|
3712
|
+
onClick: () => open ? closePopup() : openPopup(),
|
|
3713
|
+
onKeyDown: onTriggerKeyDown,
|
|
3714
|
+
className: cn(
|
|
3715
|
+
"w-full flex items-center justify-between gap-2 border rounded-kj-md bg-surface text-left text-sm",
|
|
3716
|
+
"pl-[0.85rem] pr-3 py-[calc(0.6rem*var(--kj-density,1))]",
|
|
3717
|
+
"transition-[border-color,box-shadow] duration-150",
|
|
3718
|
+
"focus:outline-none focus:border-ring focus:ring-[3px] focus:ring-ring/30",
|
|
3719
|
+
disabled && "bg-muted text-muted-foreground cursor-not-allowed",
|
|
3720
|
+
error ? "border-danger" : "border-input",
|
|
3721
|
+
!label && "text-muted-foreground"
|
|
3722
|
+
),
|
|
3723
|
+
children: [
|
|
3724
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: label ?? placeholder }),
|
|
3725
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3726
|
+
"svg",
|
|
3727
|
+
{
|
|
3728
|
+
viewBox: "0 0 24 24",
|
|
3729
|
+
className: "h-4 w-4 text-muted-foreground shrink-0",
|
|
3730
|
+
fill: "none",
|
|
3731
|
+
stroke: "currentColor",
|
|
3732
|
+
strokeWidth: "2",
|
|
3733
|
+
strokeLinecap: "round",
|
|
3734
|
+
strokeLinejoin: "round",
|
|
3735
|
+
children: [
|
|
3736
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
|
|
3737
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 10h18M8 2v4M16 2v4" })
|
|
3738
|
+
]
|
|
3739
|
+
}
|
|
3740
|
+
)
|
|
3741
|
+
]
|
|
3742
|
+
}
|
|
3743
|
+
),
|
|
3744
|
+
name && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3745
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name: `${name}Start`, value: selected.start ? toISODateString(selected.start) : "" }),
|
|
3746
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name: `${name}End`, value: selected.end ? toISODateString(selected.end) : "" })
|
|
3747
|
+
] }),
|
|
3748
|
+
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3749
|
+
"div",
|
|
3750
|
+
{
|
|
3751
|
+
onKeyDown: onPanelKeyDown,
|
|
3752
|
+
className: "absolute z-40 top-[calc(100%+6px)] left-0 bg-surface border border-border rounded-kj-md shadow-kj-lg p-3 animate-[kjpop_.12s_ease]",
|
|
3753
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(RangeCalendar, { value: selected, onChange: handleRangeChange, min, max, disabledDates })
|
|
3754
|
+
}
|
|
3755
|
+
)
|
|
3756
|
+
] });
|
|
3757
|
+
}
|
|
3758
|
+
);
|
|
3759
|
+
DateRangePicker.displayName = "DateRangePicker";
|
|
3760
|
+
var DateRangePickerField = React52__namespace.forwardRef(
|
|
3761
|
+
function DateRangePickerField2({ label, hint, error, required, className, ...props }, ref) {
|
|
3762
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsxRuntime.jsx(DateRangePicker, { ref, error: !!error, ...props }) });
|
|
3763
|
+
}
|
|
3764
|
+
);
|
|
3765
|
+
DateRangePickerField.displayName = "DateRangePickerField";
|
|
3766
|
+
var Dropzone = React52__namespace.forwardRef(
|
|
3767
|
+
function Dropzone2({
|
|
3768
|
+
onFiles,
|
|
3769
|
+
accept,
|
|
3770
|
+
multiple = true,
|
|
3771
|
+
disabled = false,
|
|
3772
|
+
className,
|
|
3773
|
+
children,
|
|
3774
|
+
id,
|
|
3775
|
+
"aria-describedby": describedBy,
|
|
3776
|
+
"aria-invalid": ariaInvalid,
|
|
3777
|
+
"aria-required": ariaRequired
|
|
3778
|
+
}, ref) {
|
|
3779
|
+
const inputRef = React52__namespace.useRef(null);
|
|
3780
|
+
const [dragActive, setDragActive] = React52__namespace.useState(false);
|
|
3781
|
+
const dragCounter = React52__namespace.useRef(0);
|
|
3782
|
+
const invalid = ariaInvalid === true || ariaInvalid === "true";
|
|
3783
|
+
const openPicker = () => {
|
|
3784
|
+
if (!disabled) inputRef.current?.click();
|
|
3785
|
+
};
|
|
3786
|
+
const handleInputChange = (e) => {
|
|
3787
|
+
const files = e.target.files ? Array.from(e.target.files) : [];
|
|
3788
|
+
if (files.length > 0) onFiles(files);
|
|
3789
|
+
e.target.value = "";
|
|
3790
|
+
};
|
|
3791
|
+
const handleDragEnter = (e) => {
|
|
3792
|
+
e.preventDefault();
|
|
3793
|
+
if (disabled) return;
|
|
3794
|
+
dragCounter.current += 1;
|
|
3795
|
+
setDragActive(true);
|
|
3796
|
+
};
|
|
3797
|
+
const handleDragOver = (e) => {
|
|
3798
|
+
e.preventDefault();
|
|
3799
|
+
};
|
|
3800
|
+
const handleDragLeave = (e) => {
|
|
3801
|
+
e.preventDefault();
|
|
3802
|
+
if (disabled) return;
|
|
3803
|
+
dragCounter.current -= 1;
|
|
3804
|
+
if (dragCounter.current <= 0) {
|
|
3805
|
+
dragCounter.current = 0;
|
|
3806
|
+
setDragActive(false);
|
|
3807
|
+
}
|
|
3808
|
+
};
|
|
3809
|
+
const handleDrop = (e) => {
|
|
3810
|
+
e.preventDefault();
|
|
3811
|
+
dragCounter.current = 0;
|
|
3812
|
+
setDragActive(false);
|
|
3813
|
+
if (disabled) return;
|
|
3814
|
+
const files = e.dataTransfer?.files ? Array.from(e.dataTransfer.files) : [];
|
|
3815
|
+
if (files.length > 0) onFiles(files);
|
|
3816
|
+
};
|
|
3817
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full", className), children: [
|
|
3818
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3819
|
+
"button",
|
|
3820
|
+
{
|
|
3821
|
+
ref,
|
|
3822
|
+
type: "button",
|
|
3823
|
+
id,
|
|
3824
|
+
disabled,
|
|
3825
|
+
"aria-describedby": describedBy,
|
|
3826
|
+
"aria-invalid": ariaInvalid,
|
|
3827
|
+
"aria-required": ariaRequired,
|
|
3828
|
+
"data-drag-active": dragActive || void 0,
|
|
3829
|
+
onClick: openPicker,
|
|
3830
|
+
onDragEnter: handleDragEnter,
|
|
3831
|
+
onDragOver: handleDragOver,
|
|
3832
|
+
onDragLeave: handleDragLeave,
|
|
3833
|
+
onDrop: handleDrop,
|
|
3834
|
+
className: cn(
|
|
3835
|
+
"w-full flex flex-col items-center justify-center gap-2 rounded-kj-md border-2 border-dashed px-6 py-8 text-center text-sm transition-colors",
|
|
3836
|
+
"focus:outline-none focus:ring-[3px] focus:ring-ring/30",
|
|
3837
|
+
disabled ? "border-input bg-muted text-muted-foreground cursor-not-allowed" : dragActive ? "border-primary bg-primary/5 text-foreground cursor-pointer" : invalid ? "border-danger bg-surface text-muted-foreground hover:text-foreground cursor-pointer" : "border-input bg-surface text-muted-foreground hover:border-primary hover:text-foreground cursor-pointer"
|
|
3838
|
+
),
|
|
3839
|
+
children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3840
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", className: "h-7 w-7", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
3841
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 16V4M7 9l5-5 5 5" }),
|
|
3842
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 16v3a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-3" })
|
|
3843
|
+
] }),
|
|
3844
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
3845
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: "Drag and drop files here" }),
|
|
3846
|
+
", or click to browse"
|
|
3847
|
+
] })
|
|
3848
|
+
] })
|
|
3849
|
+
}
|
|
3850
|
+
),
|
|
3851
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3852
|
+
"input",
|
|
3853
|
+
{
|
|
3854
|
+
ref: inputRef,
|
|
3855
|
+
type: "file",
|
|
3856
|
+
accept,
|
|
3857
|
+
multiple,
|
|
3858
|
+
disabled,
|
|
3859
|
+
onChange: handleInputChange,
|
|
3860
|
+
className: "sr-only",
|
|
3861
|
+
tabIndex: -1,
|
|
3862
|
+
"aria-hidden": "true"
|
|
3863
|
+
}
|
|
3864
|
+
)
|
|
3865
|
+
] });
|
|
3866
|
+
}
|
|
3867
|
+
);
|
|
3868
|
+
Dropzone.displayName = "Dropzone";
|
|
3869
|
+
|
|
3870
|
+
// src/components/file-upload-internals.ts
|
|
3871
|
+
var KB = 1024;
|
|
3872
|
+
function formatBytes(bytes) {
|
|
3873
|
+
if (bytes < KB) return `${bytes} B`;
|
|
3874
|
+
const units = ["KB", "MB", "GB", "TB"];
|
|
3875
|
+
let value = bytes / KB;
|
|
3876
|
+
let unitIndex = 0;
|
|
3877
|
+
while (value >= KB && unitIndex < units.length - 1) {
|
|
3878
|
+
value /= KB;
|
|
3879
|
+
unitIndex++;
|
|
3880
|
+
}
|
|
3881
|
+
return `${value.toFixed(1)} ${units[unitIndex]}`;
|
|
3882
|
+
}
|
|
3883
|
+
function matchesAccept(file, accept) {
|
|
3884
|
+
if (!accept || accept.trim() === "") return true;
|
|
3885
|
+
const tokens = accept.split(",").map((t) => t.trim()).filter(Boolean);
|
|
3886
|
+
if (tokens.length === 0) return true;
|
|
3887
|
+
const fileType = file.type.toLowerCase();
|
|
3888
|
+
const fileName = file.name.toLowerCase();
|
|
3889
|
+
return tokens.some((token) => {
|
|
3890
|
+
const t = token.toLowerCase();
|
|
3891
|
+
if (t.startsWith(".")) return fileName.endsWith(t);
|
|
3892
|
+
if (t.endsWith("/*")) return fileType.startsWith(t.slice(0, -1));
|
|
3893
|
+
return fileType === t;
|
|
3894
|
+
});
|
|
3895
|
+
}
|
|
3896
|
+
var idCounter = 0;
|
|
3897
|
+
function generateId() {
|
|
3898
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
3899
|
+
return crypto.randomUUID();
|
|
3900
|
+
}
|
|
3901
|
+
idCounter += 1;
|
|
3902
|
+
return `file-${Date.now().toString(36)}-${idCounter}-${Math.random().toString(36).slice(2, 8)}`;
|
|
3903
|
+
}
|
|
3904
|
+
function validateFiles(files, { accept, maxSize, maxFiles, existingCount = 0, multiple = true }) {
|
|
3905
|
+
const accepted = [];
|
|
3906
|
+
const rejected = [];
|
|
3907
|
+
const effectiveExisting = multiple ? existingCount : 0;
|
|
3908
|
+
for (const file of files) {
|
|
3909
|
+
if (!matchesAccept(file, accept)) {
|
|
3910
|
+
rejected.push({ file, reason: "type" });
|
|
3911
|
+
continue;
|
|
3912
|
+
}
|
|
3913
|
+
if (maxSize != null && file.size > maxSize) {
|
|
3914
|
+
rejected.push({ file, reason: "size" });
|
|
3915
|
+
continue;
|
|
3916
|
+
}
|
|
3917
|
+
if (!multiple) {
|
|
3918
|
+
if (accepted.length === 0) accepted.push(file);
|
|
3919
|
+
else rejected.push({ file, reason: "count" });
|
|
3920
|
+
continue;
|
|
3921
|
+
}
|
|
3922
|
+
const capacity = maxFiles != null ? maxFiles - effectiveExisting - accepted.length : Infinity;
|
|
3923
|
+
if (capacity <= 0) {
|
|
3924
|
+
rejected.push({ file, reason: "count" });
|
|
3925
|
+
continue;
|
|
3926
|
+
}
|
|
3927
|
+
accepted.push(file);
|
|
3928
|
+
}
|
|
3929
|
+
return { accepted, rejected };
|
|
3930
|
+
}
|
|
3931
|
+
function FileIcon({ className }) {
|
|
3932
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", className, fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
3933
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
3934
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2v6h6" })
|
|
3935
|
+
] });
|
|
3936
|
+
}
|
|
3937
|
+
var FileUpload = React52__namespace.forwardRef(
|
|
3938
|
+
function FileUpload2({
|
|
3939
|
+
value,
|
|
3940
|
+
defaultValue,
|
|
3941
|
+
onChange,
|
|
3942
|
+
onReject,
|
|
3943
|
+
accept,
|
|
3944
|
+
maxSize,
|
|
3945
|
+
maxFiles,
|
|
3946
|
+
multiple = true,
|
|
3947
|
+
disabled = false,
|
|
3948
|
+
error = false,
|
|
3949
|
+
required = false,
|
|
3950
|
+
className,
|
|
3951
|
+
id,
|
|
3952
|
+
"aria-describedby": describedBy
|
|
3953
|
+
}, ref) {
|
|
3954
|
+
const controlled = value !== void 0;
|
|
3955
|
+
const [internalItems, setInternalItems] = React52__namespace.useState(defaultValue ?? []);
|
|
3956
|
+
const items = controlled ? value : internalItems;
|
|
3957
|
+
const commit = (next) => {
|
|
3958
|
+
if (!controlled) setInternalItems(next);
|
|
3959
|
+
onChange?.(next);
|
|
3960
|
+
};
|
|
3961
|
+
const handleFiles = (files) => {
|
|
3962
|
+
const { accepted, rejected } = validateFiles(files, {
|
|
3963
|
+
accept,
|
|
3964
|
+
maxSize,
|
|
3965
|
+
maxFiles,
|
|
3966
|
+
existingCount: items.length,
|
|
3967
|
+
multiple
|
|
3968
|
+
});
|
|
3969
|
+
if (rejected.length > 0) onReject?.(rejected);
|
|
3970
|
+
if (accepted.length === 0) return;
|
|
3971
|
+
const newItems = accepted.map((file) => ({
|
|
3972
|
+
id: generateId(),
|
|
3973
|
+
file,
|
|
3974
|
+
status: "pending"
|
|
3975
|
+
}));
|
|
3976
|
+
commit(multiple ? [...items, ...newItems] : newItems.slice(0, 1));
|
|
3977
|
+
};
|
|
3978
|
+
const removeItem = (itemId) => {
|
|
3979
|
+
commit(items.filter((it) => it.id !== itemId));
|
|
3980
|
+
};
|
|
3981
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full flex flex-col gap-3", className), children: [
|
|
3982
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3983
|
+
Dropzone,
|
|
3984
|
+
{
|
|
3985
|
+
ref,
|
|
3986
|
+
onFiles: handleFiles,
|
|
3987
|
+
accept,
|
|
3988
|
+
multiple,
|
|
3989
|
+
disabled,
|
|
3990
|
+
id,
|
|
3991
|
+
"aria-describedby": describedBy,
|
|
3992
|
+
"aria-invalid": error || void 0,
|
|
3993
|
+
"aria-required": required || void 0
|
|
3994
|
+
}
|
|
3995
|
+
),
|
|
3996
|
+
items.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-2", children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3997
|
+
"li",
|
|
3998
|
+
{
|
|
3999
|
+
className: "flex items-center gap-3 rounded-kj-md border border-border bg-surface px-3 py-2",
|
|
4000
|
+
children: [
|
|
4001
|
+
/* @__PURE__ */ jsxRuntime.jsx(FileIcon, { className: "h-5 w-5 shrink-0 text-muted-foreground" }),
|
|
4002
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
4003
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
4004
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm text-foreground", children: item.file.name }),
|
|
4005
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatBytes(item.file.size) })
|
|
4006
|
+
] }),
|
|
4007
|
+
item.status === "uploading" && item.progress != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 flex items-center gap-2", children: [
|
|
4008
|
+
/* @__PURE__ */ jsxRuntime.jsx(Progress, { value: item.progress, className: "h-1.5" }),
|
|
4009
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 text-xs text-muted-foreground", children: [
|
|
4010
|
+
Math.round(item.progress),
|
|
4011
|
+
"%"
|
|
4012
|
+
] })
|
|
4013
|
+
] }),
|
|
4014
|
+
item.status === "success" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-0.5 block text-xs text-success", children: "Uploaded" }),
|
|
4015
|
+
item.status === "error" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-0.5 block text-xs text-danger", children: item.error ?? "Upload failed" })
|
|
4016
|
+
] }),
|
|
4017
|
+
!disabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4018
|
+
"button",
|
|
4019
|
+
{
|
|
4020
|
+
type: "button",
|
|
4021
|
+
"aria-label": `Remove ${item.file.name}`,
|
|
4022
|
+
onClick: () => removeItem(item.id),
|
|
4023
|
+
className: "shrink-0 rounded-kj-sm p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
4024
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
4025
|
+
}
|
|
4026
|
+
)
|
|
4027
|
+
]
|
|
4028
|
+
},
|
|
4029
|
+
item.id
|
|
4030
|
+
)) })
|
|
4031
|
+
] });
|
|
4032
|
+
}
|
|
4033
|
+
);
|
|
4034
|
+
FileUpload.displayName = "FileUpload";
|
|
4035
|
+
var FileUploadField = React52__namespace.forwardRef(
|
|
4036
|
+
function FileUploadField2({ label, hint, error, required, className, ...props }, ref) {
|
|
4037
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsxRuntime.jsx(FileUpload, { ref, error: !!error, ...props }) });
|
|
4038
|
+
}
|
|
4039
|
+
);
|
|
4040
|
+
FileUploadField.displayName = "FileUploadField";
|
|
4041
|
+
var TimelineContext = React52__namespace.createContext(null);
|
|
4042
|
+
var TimelineItemContext = React52__namespace.createContext(null);
|
|
4043
|
+
var Timeline = React52__namespace.forwardRef(
|
|
4044
|
+
({ align = "left", className, children, ...props }, ref) => {
|
|
4045
|
+
const validChildren = React52__namespace.Children.toArray(children).filter(React52__namespace.isValidElement);
|
|
4046
|
+
const count = validChildren.length;
|
|
4047
|
+
const childrenWithIndex = validChildren.map((child, index) => {
|
|
4048
|
+
return React52__namespace.cloneElement(child, {
|
|
4049
|
+
index
|
|
4050
|
+
});
|
|
4051
|
+
});
|
|
4052
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TimelineContext.Provider, { value: { align, count }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4053
|
+
"div",
|
|
4054
|
+
{
|
|
4055
|
+
ref,
|
|
4056
|
+
role: "list",
|
|
4057
|
+
className: cn("flex flex-col gap-6 w-full", className),
|
|
4058
|
+
...props,
|
|
4059
|
+
children: childrenWithIndex
|
|
4060
|
+
}
|
|
4061
|
+
) });
|
|
4062
|
+
}
|
|
4063
|
+
);
|
|
4064
|
+
Timeline.displayName = "Timeline";
|
|
4065
|
+
var TimelineItem = React52__namespace.forwardRef(
|
|
4066
|
+
({ className, index = 0, children, ...props }, ref) => {
|
|
4067
|
+
const ctx = React52__namespace.useContext(TimelineContext);
|
|
4068
|
+
if (!ctx) throw new Error("TimelineItem must be used within a Timeline");
|
|
4069
|
+
const { align, count } = ctx;
|
|
4070
|
+
const isEven = index % 2 === 0;
|
|
4071
|
+
const isLast = index === count - 1;
|
|
4072
|
+
const gridClass = cn(
|
|
4073
|
+
"grid w-full gap-4 items-start group/timeline-item",
|
|
4074
|
+
align === "left" && "grid-cols-[auto_1fr]",
|
|
4075
|
+
align === "right" && "grid-cols-[1fr_auto] text-right",
|
|
4076
|
+
align === "alternate" && "md:grid-cols-[1fr_auto_1fr] grid-cols-[auto_1fr]"
|
|
4077
|
+
);
|
|
4078
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TimelineItemContext.Provider, { value: { isEven, align, isLast }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4079
|
+
"div",
|
|
4080
|
+
{
|
|
4081
|
+
ref,
|
|
4082
|
+
role: "listitem",
|
|
4083
|
+
className: cn(gridClass, className),
|
|
4084
|
+
...props,
|
|
4085
|
+
children
|
|
4086
|
+
}
|
|
4087
|
+
) });
|
|
4088
|
+
}
|
|
4089
|
+
);
|
|
4090
|
+
TimelineItem.displayName = "TimelineItem";
|
|
4091
|
+
var TimelineSeparator = React52__namespace.forwardRef(
|
|
4092
|
+
({ className, align: propAlign, ...props }, ref) => {
|
|
4093
|
+
const ctx = React52__namespace.useContext(TimelineItemContext);
|
|
4094
|
+
const align = propAlign ?? ctx?.align ?? "left";
|
|
4095
|
+
const separatorClass = cn(
|
|
4096
|
+
"flex flex-col items-center justify-self-center h-full min-h-[40px]",
|
|
4097
|
+
align === "alternate" && "md:col-start-2 col-start-1",
|
|
4098
|
+
align === "left" && "col-start-1",
|
|
4099
|
+
align === "right" && "col-start-2",
|
|
4100
|
+
className
|
|
4101
|
+
);
|
|
4102
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: separatorClass, ...props });
|
|
4103
|
+
}
|
|
4104
|
+
);
|
|
4105
|
+
TimelineSeparator.displayName = "TimelineSeparator";
|
|
4106
|
+
var TimelineConnector = React52__namespace.forwardRef(
|
|
4107
|
+
({ className, dashed, ...props }, ref) => {
|
|
4108
|
+
const ctx = React52__namespace.useContext(TimelineItemContext);
|
|
4109
|
+
const isLast = ctx?.isLast ?? false;
|
|
4110
|
+
const connectorClass = cn(
|
|
4111
|
+
"grow",
|
|
4112
|
+
isLast && "hidden",
|
|
4113
|
+
dashed ? "w-0 border-l border-dashed border-border" : "w-0.5 bg-border",
|
|
4114
|
+
className
|
|
4115
|
+
);
|
|
4116
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: connectorClass, ...props });
|
|
4117
|
+
}
|
|
4118
|
+
);
|
|
4119
|
+
TimelineConnector.displayName = "TimelineConnector";
|
|
4120
|
+
var TimelineDot = React52__namespace.forwardRef(
|
|
4121
|
+
({ className, variant = "default", size = "md", ...props }, ref) => {
|
|
4122
|
+
const sizeClasses2 = {
|
|
4123
|
+
sm: "w-2.5 h-2.5 rounded-full my-1.5",
|
|
4124
|
+
md: "w-4 h-4 rounded-full my-1 border-2 bg-background border-border",
|
|
4125
|
+
lg: "w-8 h-8 rounded-full border flex items-center justify-center bg-background text-[0.8rem]"
|
|
4126
|
+
};
|
|
4127
|
+
const variantClasses = {
|
|
4128
|
+
default: "border-border text-muted-foreground",
|
|
4129
|
+
primary: "border-primary bg-primary/5 text-primary",
|
|
4130
|
+
secondary: "border-secondary bg-secondary/5 text-secondary",
|
|
4131
|
+
success: "border-success bg-success-surface text-success",
|
|
4132
|
+
warning: "border-warning bg-warning-surface text-warning",
|
|
4133
|
+
danger: "border-danger bg-danger-surface text-danger"
|
|
4134
|
+
};
|
|
4135
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4136
|
+
"div",
|
|
4137
|
+
{
|
|
4138
|
+
ref,
|
|
4139
|
+
className: cn(
|
|
4140
|
+
"shrink-0 select-none",
|
|
4141
|
+
sizeClasses2[size],
|
|
4142
|
+
variantClasses[variant],
|
|
4143
|
+
className
|
|
4144
|
+
),
|
|
4145
|
+
...props
|
|
4146
|
+
}
|
|
4147
|
+
);
|
|
4148
|
+
}
|
|
4149
|
+
);
|
|
4150
|
+
TimelineDot.displayName = "TimelineDot";
|
|
4151
|
+
var TimelineContent = React52__namespace.forwardRef(
|
|
4152
|
+
({ className, isEven: propIsEven, align: propAlign, ...props }, ref) => {
|
|
4153
|
+
const ctx = React52__namespace.useContext(TimelineItemContext);
|
|
4154
|
+
const isEven = propIsEven ?? ctx?.isEven ?? false;
|
|
4155
|
+
const align = propAlign ?? ctx?.align ?? "left";
|
|
4156
|
+
const contentClass = cn(
|
|
4157
|
+
"pb-8 flex flex-col gap-1 w-full",
|
|
4158
|
+
align === "left" && "col-start-2 text-left",
|
|
4159
|
+
align === "right" && "col-start-1 text-right",
|
|
4160
|
+
align === "alternate" && (isEven ? "md:col-start-3 col-start-2 text-left" : "md:col-start-1 col-start-2 md:text-right text-left"),
|
|
4161
|
+
className
|
|
4162
|
+
);
|
|
4163
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: contentClass, ...props });
|
|
4164
|
+
}
|
|
4165
|
+
);
|
|
4166
|
+
TimelineContent.displayName = "TimelineContent";
|
|
4167
|
+
var TimelineTitle = React52__namespace.forwardRef(
|
|
4168
|
+
({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4169
|
+
"h4",
|
|
4170
|
+
{
|
|
4171
|
+
ref,
|
|
4172
|
+
className: cn("m-0 text-sm font-semibold tracking-[-0.01em] text-foreground", className),
|
|
4173
|
+
...props,
|
|
4174
|
+
children
|
|
4175
|
+
}
|
|
4176
|
+
)
|
|
4177
|
+
);
|
|
4178
|
+
TimelineTitle.displayName = "TimelineTitle";
|
|
4179
|
+
var TimelineTime = React52__namespace.forwardRef(
|
|
4180
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4181
|
+
"time",
|
|
4182
|
+
{
|
|
4183
|
+
ref,
|
|
4184
|
+
className: cn("text-[0.75rem] text-muted-foreground font-normal", className),
|
|
4185
|
+
...props
|
|
4186
|
+
}
|
|
4187
|
+
)
|
|
4188
|
+
);
|
|
4189
|
+
TimelineTime.displayName = "TimelineTime";
|
|
4190
|
+
function useStepper({ initialStep = 0, stepsCount }) {
|
|
4191
|
+
const safeStepsCount = Math.max(1, stepsCount);
|
|
4192
|
+
const [activeStep, setActiveStep] = React52__namespace.useState(initialStep);
|
|
4193
|
+
const [completedSteps, setCompletedSteps] = React52__namespace.useState([]);
|
|
4194
|
+
const setStep = React52__namespace.useCallback((step) => {
|
|
4195
|
+
if (step >= 0 && step < safeStepsCount) {
|
|
4196
|
+
setActiveStep(step);
|
|
4197
|
+
}
|
|
4198
|
+
}, [safeStepsCount]);
|
|
4199
|
+
const nextStep = React52__namespace.useCallback(() => {
|
|
4200
|
+
setActiveStep((prev) => Math.min(prev + 1, safeStepsCount - 1));
|
|
4201
|
+
}, [safeStepsCount]);
|
|
4202
|
+
const prevStep = React52__namespace.useCallback(() => {
|
|
4203
|
+
setActiveStep((prev) => Math.max(prev - 1, 0));
|
|
4204
|
+
}, []);
|
|
4205
|
+
const completeStep = React52__namespace.useCallback((step) => {
|
|
4206
|
+
setCompletedSteps((prev) => {
|
|
4207
|
+
if (step < 0 || step >= safeStepsCount) return prev;
|
|
4208
|
+
if (prev.includes(step)) return prev;
|
|
4209
|
+
return [...prev, step].sort((a, b) => a - b);
|
|
4210
|
+
});
|
|
4211
|
+
}, [safeStepsCount]);
|
|
4212
|
+
const uncompleteStep = React52__namespace.useCallback((step) => {
|
|
4213
|
+
setCompletedSteps((prev) => prev.filter((s) => s !== step));
|
|
4214
|
+
}, []);
|
|
4215
|
+
const reset = React52__namespace.useCallback(() => {
|
|
4216
|
+
setActiveStep(initialStep);
|
|
4217
|
+
setCompletedSteps([]);
|
|
4218
|
+
}, [initialStep]);
|
|
4219
|
+
return {
|
|
4220
|
+
activeStep,
|
|
4221
|
+
completedSteps,
|
|
4222
|
+
setStep,
|
|
4223
|
+
nextStep,
|
|
4224
|
+
prevStep,
|
|
4225
|
+
completeStep,
|
|
4226
|
+
uncompleteStep,
|
|
4227
|
+
reset,
|
|
4228
|
+
isFirstStep: activeStep === 0,
|
|
4229
|
+
isLastStep: activeStep === safeStepsCount - 1
|
|
4230
|
+
};
|
|
4231
|
+
}
|
|
4232
|
+
var StepperContext = React52__namespace.createContext(null);
|
|
4233
|
+
var StepperItemContext = React52__namespace.createContext(null);
|
|
4234
|
+
var Stepper = React52__namespace.forwardRef(
|
|
4235
|
+
({ value, defaultValue, onValueChange, orientation = "horizontal", linear = true, children, className, ...props }, ref) => {
|
|
4236
|
+
const [localValue, setLocalValue] = React52__namespace.useState(defaultValue ?? 0);
|
|
4237
|
+
const isControlled = value !== void 0;
|
|
4238
|
+
const activeStep = isControlled ? value : localValue;
|
|
4239
|
+
const [steps, setSteps] = React52__namespace.useState([]);
|
|
4240
|
+
const [completedSteps, setCompletedSteps] = React52__namespace.useState([]);
|
|
4241
|
+
const registerStep = React52__namespace.useCallback((val) => {
|
|
4242
|
+
setSteps((prev) => prev.includes(val) ? prev : [...prev, val].sort((a, b) => a - b));
|
|
4243
|
+
}, []);
|
|
4244
|
+
const unregisterStep = React52__namespace.useCallback((val) => {
|
|
4245
|
+
setSteps((prev) => prev.filter((v) => v !== val));
|
|
4246
|
+
}, []);
|
|
4247
|
+
const setStep = React52__namespace.useCallback(
|
|
4248
|
+
(step) => {
|
|
4249
|
+
if (!isControlled) {
|
|
4250
|
+
setLocalValue(step);
|
|
4251
|
+
}
|
|
4252
|
+
onValueChange?.(step);
|
|
4253
|
+
if (linear) {
|
|
4254
|
+
setCompletedSteps((prev) => {
|
|
4255
|
+
const priorSteps = steps.filter((s) => s < step);
|
|
4256
|
+
const nextCompleted = Array.from(/* @__PURE__ */ new Set([...prev, ...priorSteps])).sort((a, b) => a - b);
|
|
4257
|
+
return nextCompleted;
|
|
4258
|
+
});
|
|
4259
|
+
}
|
|
4260
|
+
},
|
|
4261
|
+
[isControlled, onValueChange, linear, steps]
|
|
4262
|
+
);
|
|
4263
|
+
const contextValue = React52__namespace.useMemo(
|
|
4264
|
+
() => ({
|
|
4265
|
+
activeStep,
|
|
4266
|
+
orientation,
|
|
4267
|
+
linear,
|
|
4268
|
+
setStep,
|
|
4269
|
+
completedSteps,
|
|
4270
|
+
registerStep,
|
|
4271
|
+
unregisterStep,
|
|
4272
|
+
steps
|
|
4273
|
+
}),
|
|
4274
|
+
[activeStep, orientation, linear, setStep, completedSteps, registerStep, unregisterStep, steps]
|
|
4275
|
+
);
|
|
4276
|
+
return /* @__PURE__ */ jsxRuntime.jsx(StepperContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4277
|
+
"div",
|
|
4278
|
+
{
|
|
4279
|
+
ref,
|
|
4280
|
+
className: cn(
|
|
4281
|
+
"w-full",
|
|
4282
|
+
orientation === "vertical" ? "flex flex-col gap-6" : "space-y-6",
|
|
4283
|
+
className
|
|
4284
|
+
),
|
|
4285
|
+
...props,
|
|
4286
|
+
children
|
|
4287
|
+
}
|
|
4288
|
+
) });
|
|
4289
|
+
}
|
|
4290
|
+
);
|
|
4291
|
+
Stepper.displayName = "Stepper";
|
|
4292
|
+
var StepperContent = React52__namespace.forwardRef(
|
|
4293
|
+
({ value, className, children, ...props }, ref) => {
|
|
4294
|
+
const ctx = React52__namespace.useContext(StepperContext);
|
|
4295
|
+
if (!ctx) throw new Error("StepperContent must be used within a Stepper");
|
|
4296
|
+
const isActive = ctx.activeStep === value;
|
|
4297
|
+
if (!isActive) return null;
|
|
4298
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4299
|
+
"div",
|
|
4300
|
+
{
|
|
4301
|
+
ref,
|
|
4302
|
+
role: "tabpanel",
|
|
4303
|
+
tabIndex: 0,
|
|
4304
|
+
className: cn("focus-visible:outline-none w-full", className),
|
|
4305
|
+
...props,
|
|
4306
|
+
children
|
|
4307
|
+
}
|
|
4308
|
+
);
|
|
4309
|
+
}
|
|
4310
|
+
);
|
|
4311
|
+
StepperContent.displayName = "StepperContent";
|
|
4312
|
+
var StepperList = React52__namespace.forwardRef(
|
|
4313
|
+
({ className, children, ...props }, ref) => {
|
|
4314
|
+
const ctx = React52__namespace.useContext(StepperContext);
|
|
4315
|
+
if (!ctx) throw new Error("StepperList must be used within a Stepper");
|
|
4316
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4317
|
+
"div",
|
|
4318
|
+
{
|
|
4319
|
+
ref,
|
|
4320
|
+
role: "tablist",
|
|
4321
|
+
"aria-orientation": ctx.orientation,
|
|
4322
|
+
className: cn(
|
|
4323
|
+
ctx.orientation === "horizontal" ? "flex items-center justify-between w-full relative gap-4" : "flex flex-col items-start gap-6 relative w-full",
|
|
4324
|
+
className
|
|
4325
|
+
),
|
|
4326
|
+
...props,
|
|
4327
|
+
children
|
|
4328
|
+
}
|
|
4329
|
+
);
|
|
4330
|
+
}
|
|
4331
|
+
);
|
|
4332
|
+
StepperList.displayName = "StepperList";
|
|
4333
|
+
var StepperItem = React52__namespace.forwardRef(
|
|
4334
|
+
({ value, disabled = false, className, children, ...props }, ref) => {
|
|
4335
|
+
const ctx = React52__namespace.useContext(StepperContext);
|
|
4336
|
+
if (!ctx) throw new Error("StepperItem must be used within a Stepper");
|
|
4337
|
+
const { registerStep, unregisterStep } = ctx;
|
|
4338
|
+
React52__namespace.useEffect(() => {
|
|
4339
|
+
registerStep(value);
|
|
4340
|
+
return () => unregisterStep(value);
|
|
4341
|
+
}, [value, registerStep, unregisterStep]);
|
|
4342
|
+
const isLast = ctx.steps[ctx.steps.length - 1] === value;
|
|
4343
|
+
return /* @__PURE__ */ jsxRuntime.jsx(StepperItemContext.Provider, { value: { value, disabled, isLast }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4344
|
+
"div",
|
|
4345
|
+
{
|
|
4346
|
+
ref,
|
|
4347
|
+
className: cn(
|
|
4348
|
+
"group relative flex items-center gap-3 z-10",
|
|
4349
|
+
ctx.orientation === "vertical" ? "flex items-start w-full" : "",
|
|
4350
|
+
className
|
|
4351
|
+
),
|
|
4352
|
+
...props,
|
|
4353
|
+
children
|
|
4354
|
+
}
|
|
4355
|
+
) });
|
|
4356
|
+
}
|
|
4357
|
+
);
|
|
4358
|
+
StepperItem.displayName = "StepperItem";
|
|
4359
|
+
var StepperSeparator = React52__namespace.forwardRef(
|
|
4360
|
+
({ className, ...props }, ref) => {
|
|
4361
|
+
const ctx = React52__namespace.useContext(StepperContext);
|
|
4362
|
+
if (!ctx) throw new Error("StepperSeparator must be used within a Stepper");
|
|
4363
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4364
|
+
"div",
|
|
4365
|
+
{
|
|
4366
|
+
ref,
|
|
4367
|
+
className: cn(
|
|
4368
|
+
ctx.orientation === "horizontal" ? "flex-1 h-[2px] bg-border transition-all duration-300" : "w-[2px] bg-border absolute left-[17px] top-8 bottom-0 -ml-px z-0",
|
|
4369
|
+
className
|
|
4370
|
+
),
|
|
4371
|
+
...props
|
|
4372
|
+
}
|
|
4373
|
+
);
|
|
4374
|
+
}
|
|
4375
|
+
);
|
|
4376
|
+
StepperSeparator.displayName = "StepperSeparator";
|
|
4377
|
+
var StepperTrigger = React52__namespace.forwardRef(
|
|
4378
|
+
({ className, children, onClick, onKeyDown, ...props }, ref) => {
|
|
4379
|
+
const ctx = React52__namespace.useContext(StepperContext);
|
|
4380
|
+
const itemCtx = React52__namespace.useContext(StepperItemContext);
|
|
4381
|
+
if (!ctx || !itemCtx) {
|
|
4382
|
+
throw new Error("StepperTrigger must be used within a StepperItem inside a Stepper");
|
|
4383
|
+
}
|
|
4384
|
+
const isCompleted = ctx.completedSteps.includes(itemCtx.value) || itemCtx.value < ctx.activeStep;
|
|
4385
|
+
const isActive = ctx.activeStep === itemCtx.value;
|
|
4386
|
+
const isClickable = !ctx.linear || isCompleted || isActive;
|
|
4387
|
+
const disabled = itemCtx.disabled || !isClickable;
|
|
4388
|
+
const handleClick = (e) => {
|
|
4389
|
+
if (disabled) {
|
|
4390
|
+
e.preventDefault();
|
|
4391
|
+
return;
|
|
4392
|
+
}
|
|
4393
|
+
ctx.setStep(itemCtx.value);
|
|
4394
|
+
onClick?.(e);
|
|
4395
|
+
};
|
|
4396
|
+
const handleKeyDown = (e) => {
|
|
4397
|
+
onKeyDown?.(e);
|
|
4398
|
+
const triggers = Array.from(
|
|
4399
|
+
e.currentTarget.closest('[role="tablist"]')?.querySelectorAll('[role="tab"]') || []
|
|
4400
|
+
);
|
|
4401
|
+
const currentIndex = triggers.indexOf(e.currentTarget);
|
|
4402
|
+
if (currentIndex === -1) return;
|
|
4403
|
+
let targetIndex = -1;
|
|
4404
|
+
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
4405
|
+
targetIndex = Math.min(currentIndex + 1, triggers.length - 1);
|
|
4406
|
+
} else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
4407
|
+
targetIndex = Math.max(currentIndex - 1, 0);
|
|
4408
|
+
}
|
|
4409
|
+
if (targetIndex !== -1 && triggers[targetIndex]) {
|
|
4410
|
+
e.preventDefault();
|
|
4411
|
+
triggers[targetIndex].focus();
|
|
4412
|
+
}
|
|
4413
|
+
};
|
|
4414
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4415
|
+
"button",
|
|
4416
|
+
{
|
|
4417
|
+
ref,
|
|
4418
|
+
type: "button",
|
|
4419
|
+
role: "tab",
|
|
4420
|
+
"aria-selected": isActive,
|
|
4421
|
+
"aria-disabled": disabled,
|
|
4422
|
+
tabIndex: isActive ? 0 : -1,
|
|
4423
|
+
onClick: handleClick,
|
|
4424
|
+
onKeyDown: handleKeyDown,
|
|
4425
|
+
className: cn(
|
|
4426
|
+
"flex items-center gap-3 bg-transparent border-0 p-0 text-left cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary rounded-md disabled:cursor-not-allowed disabled:opacity-50",
|
|
4427
|
+
ctx.orientation === "vertical" ? "w-full" : "",
|
|
4428
|
+
className
|
|
4429
|
+
),
|
|
4430
|
+
...props,
|
|
4431
|
+
children
|
|
4432
|
+
}
|
|
4433
|
+
);
|
|
4434
|
+
}
|
|
4435
|
+
);
|
|
4436
|
+
StepperTrigger.displayName = "StepperTrigger";
|
|
4437
|
+
var StepperIndicator = React52__namespace.forwardRef(
|
|
4438
|
+
({ className, children, ...props }, ref) => {
|
|
4439
|
+
const ctx = React52__namespace.useContext(StepperContext);
|
|
4440
|
+
const itemCtx = React52__namespace.useContext(StepperItemContext);
|
|
4441
|
+
if (!ctx || !itemCtx) {
|
|
4442
|
+
throw new Error("StepperIndicator must be used within a StepperItem inside a Stepper");
|
|
4443
|
+
}
|
|
4444
|
+
const isCompleted = ctx.completedSteps.includes(itemCtx.value) || itemCtx.value < ctx.activeStep;
|
|
4445
|
+
const isActive = ctx.activeStep === itemCtx.value;
|
|
4446
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4447
|
+
"span",
|
|
4448
|
+
{
|
|
4449
|
+
ref,
|
|
4450
|
+
className: cn(
|
|
4451
|
+
"flex h-9 w-9 shrink-0 items-center justify-center rounded-full border text-sm font-semibold transition-all duration-200",
|
|
4452
|
+
isCompleted ? "bg-primary border-primary text-primary-foreground" : isActive ? "border-primary text-primary bg-primary/10 ring-2 ring-primary/20" : "border-border text-muted-foreground bg-muted/40",
|
|
4453
|
+
className
|
|
4454
|
+
),
|
|
4455
|
+
...props,
|
|
4456
|
+
children: children ?? (isCompleted ? "\u2713" : itemCtx.value + 1)
|
|
4457
|
+
}
|
|
4458
|
+
);
|
|
4459
|
+
}
|
|
4460
|
+
);
|
|
4461
|
+
StepperIndicator.displayName = "StepperIndicator";
|
|
4462
|
+
var StepperTitle = React52__namespace.forwardRef(
|
|
4463
|
+
({ className, ...props }, ref) => {
|
|
4464
|
+
const ctx = React52__namespace.useContext(StepperContext);
|
|
4465
|
+
const itemCtx = React52__namespace.useContext(StepperItemContext);
|
|
4466
|
+
if (!ctx || !itemCtx) {
|
|
4467
|
+
throw new Error("StepperTitle must be used within a StepperItem inside a Stepper");
|
|
4468
|
+
}
|
|
4469
|
+
const isActive = ctx.activeStep === itemCtx.value;
|
|
4470
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4471
|
+
"span",
|
|
4472
|
+
{
|
|
4473
|
+
ref,
|
|
4474
|
+
className: cn(
|
|
4475
|
+
"text-sm font-medium transition-colors duration-200",
|
|
4476
|
+
isActive ? "text-foreground font-semibold" : "text-muted-foreground",
|
|
4477
|
+
className
|
|
4478
|
+
),
|
|
4479
|
+
...props
|
|
4480
|
+
}
|
|
4481
|
+
);
|
|
4482
|
+
}
|
|
4483
|
+
);
|
|
4484
|
+
StepperTitle.displayName = "StepperTitle";
|
|
4485
|
+
var StepperDescription = React52__namespace.forwardRef(
|
|
4486
|
+
({ className, ...props }, ref) => {
|
|
4487
|
+
const itemCtx = React52__namespace.useContext(StepperItemContext);
|
|
4488
|
+
if (!itemCtx) throw new Error("StepperDescription must be used within a StepperItem");
|
|
4489
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4490
|
+
"span",
|
|
4491
|
+
{
|
|
4492
|
+
ref,
|
|
4493
|
+
className: cn("text-xs text-muted-foreground text-left block", className),
|
|
4494
|
+
...props
|
|
4495
|
+
}
|
|
4496
|
+
);
|
|
4497
|
+
}
|
|
4498
|
+
);
|
|
4499
|
+
StepperDescription.displayName = "StepperDescription";
|
|
4500
|
+
var AppShellBanner = React52__namespace.forwardRef(
|
|
4501
|
+
({ className, variant = "primary", closable, onClose, children, ...props }, ref) => {
|
|
4502
|
+
const variantClass = {
|
|
4503
|
+
primary: "bg-primary text-primary-foreground",
|
|
4504
|
+
accent: "bg-secondary text-secondary-foreground",
|
|
4505
|
+
muted: "bg-surface border-b border-border text-muted-foreground"
|
|
4506
|
+
}[variant];
|
|
4507
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4508
|
+
"div",
|
|
4509
|
+
{
|
|
4510
|
+
ref,
|
|
4511
|
+
className: cn("px-4 py-2 text-sm font-medium text-center flex items-center justify-center relative z-30", variantClass, className),
|
|
4512
|
+
...props,
|
|
4513
|
+
children: [
|
|
4514
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children }),
|
|
4515
|
+
closable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4516
|
+
"button",
|
|
4517
|
+
{
|
|
4518
|
+
type: "button",
|
|
4519
|
+
onClick: onClose,
|
|
4520
|
+
className: "p-1 rounded opacity-80 hover:opacity-100 transition-opacity ml-2 cursor-pointer",
|
|
4521
|
+
"aria-label": "Close banner",
|
|
4522
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
4523
|
+
}
|
|
4524
|
+
)
|
|
4525
|
+
]
|
|
4526
|
+
}
|
|
4527
|
+
);
|
|
4528
|
+
}
|
|
4529
|
+
);
|
|
4530
|
+
AppShellBanner.displayName = "AppShellBanner";
|
|
4531
|
+
var AppShellHeader = React52__namespace.forwardRef(
|
|
4532
|
+
({
|
|
4533
|
+
className,
|
|
4534
|
+
variant = "glass",
|
|
4535
|
+
position = "sticky",
|
|
4536
|
+
bordered = true,
|
|
4537
|
+
children,
|
|
4538
|
+
mobileNav,
|
|
4539
|
+
...props
|
|
4540
|
+
}, ref) => {
|
|
4541
|
+
const [mobileOpen, setMobileOpen] = React52__namespace.useState(false);
|
|
4542
|
+
React52__namespace.useEffect(() => {
|
|
4543
|
+
const handleKeyDown = (e) => {
|
|
4544
|
+
if (e.key === "Escape" && mobileOpen) {
|
|
4545
|
+
setMobileOpen(false);
|
|
4546
|
+
}
|
|
4547
|
+
};
|
|
4548
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
4549
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
4550
|
+
}, [mobileOpen]);
|
|
4551
|
+
const positionClass = {
|
|
4552
|
+
sticky: "sticky top-0 z-40",
|
|
4553
|
+
fixed: "fixed top-0 left-0 right-0 z-40",
|
|
4554
|
+
static: "relative z-40"
|
|
4555
|
+
}[position];
|
|
4556
|
+
const variantClass = {
|
|
4557
|
+
glass: "bg-surface/80 backdrop-blur-md text-foreground",
|
|
4558
|
+
solid: "bg-surface text-foreground",
|
|
4559
|
+
transparent: "bg-transparent text-foreground"
|
|
4560
|
+
}[variant];
|
|
4561
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4562
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4563
|
+
"header",
|
|
4564
|
+
{
|
|
4565
|
+
ref,
|
|
4566
|
+
className: cn(
|
|
4567
|
+
"w-full transition-colors",
|
|
4568
|
+
positionClass,
|
|
4569
|
+
variantClass,
|
|
4570
|
+
bordered && "border-b border-border/60",
|
|
4571
|
+
className
|
|
4572
|
+
),
|
|
4573
|
+
...props,
|
|
4574
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between gap-4", children: [
|
|
4575
|
+
mobileNav && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4576
|
+
"button",
|
|
4577
|
+
{
|
|
4578
|
+
type: "button",
|
|
4579
|
+
onClick: () => setMobileOpen(true),
|
|
4580
|
+
className: "md:hidden p-2 -ml-2 rounded-lg text-muted-foreground hover:text-foreground hover:bg-muted transition-colors cursor-pointer",
|
|
4581
|
+
"aria-label": "Open navigation",
|
|
4582
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
4583
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "12", x2: "21", y2: "12" }),
|
|
4584
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "6", x2: "21", y2: "6" }),
|
|
4585
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "18", x2: "21", y2: "18" })
|
|
4586
|
+
] })
|
|
4587
|
+
}
|
|
4588
|
+
),
|
|
4589
|
+
children
|
|
4590
|
+
] })
|
|
4591
|
+
}
|
|
4592
|
+
),
|
|
4593
|
+
mobileNav && mobileOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50 md:hidden flex", children: [
|
|
4594
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4595
|
+
"div",
|
|
4596
|
+
{
|
|
4597
|
+
"aria-hidden": "true",
|
|
4598
|
+
onClick: () => setMobileOpen(false),
|
|
4599
|
+
className: "fixed inset-0 bg-overlay backdrop-blur-[2px] transition-opacity duration-300"
|
|
4600
|
+
}
|
|
4601
|
+
),
|
|
4602
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4603
|
+
"aside",
|
|
4604
|
+
{
|
|
4605
|
+
role: "dialog",
|
|
4606
|
+
"aria-modal": "true",
|
|
4607
|
+
"aria-label": "Mobile Navigation",
|
|
4608
|
+
className: "relative z-10 w-72 h-full bg-surface border-r border-border flex flex-col shadow-kj-lg",
|
|
4609
|
+
children: [
|
|
4610
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-4 border-b border-border", children: [
|
|
4611
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-bold uppercase tracking-wider text-muted-foreground", children: "Navigation" }),
|
|
4612
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4613
|
+
"button",
|
|
4614
|
+
{
|
|
4615
|
+
type: "button",
|
|
4616
|
+
onClick: () => setMobileOpen(false),
|
|
4617
|
+
className: "p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors cursor-pointer",
|
|
4618
|
+
"aria-label": "Close navigation",
|
|
4619
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
4620
|
+
}
|
|
4621
|
+
)
|
|
4622
|
+
] }),
|
|
4623
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto p-4", children: mobileNav })
|
|
4624
|
+
]
|
|
4625
|
+
}
|
|
4626
|
+
)
|
|
4627
|
+
] })
|
|
4628
|
+
] });
|
|
4629
|
+
}
|
|
4630
|
+
);
|
|
4631
|
+
AppShellHeader.displayName = "AppShellHeader";
|
|
4632
|
+
var AppShellMain = React52__namespace.forwardRef(
|
|
4633
|
+
({ className, width = "default", padded = true, children, ...props }, ref) => {
|
|
4634
|
+
const widthClass = {
|
|
4635
|
+
default: "max-w-7xl mx-auto w-full",
|
|
4636
|
+
narrow: "max-w-5xl mx-auto w-full",
|
|
4637
|
+
wide: "max-w-screen-2xl mx-auto w-full",
|
|
4638
|
+
full: "max-w-none w-full"
|
|
4639
|
+
}[width];
|
|
4640
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4641
|
+
"main",
|
|
4642
|
+
{
|
|
4643
|
+
ref,
|
|
4644
|
+
className: cn("flex-1", padded && "px-4 sm:px-6 lg:px-8 py-8 md:py-12", widthClass, className),
|
|
4645
|
+
...props,
|
|
4646
|
+
children
|
|
4647
|
+
}
|
|
4648
|
+
);
|
|
4649
|
+
}
|
|
4650
|
+
);
|
|
4651
|
+
AppShellMain.displayName = "AppShellMain";
|
|
4652
|
+
var AppShellFooter = React52__namespace.forwardRef(
|
|
4653
|
+
({ className, bordered = true, children, ...props }, ref) => {
|
|
4654
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4655
|
+
"footer",
|
|
4656
|
+
{
|
|
4657
|
+
ref,
|
|
4658
|
+
className: cn(
|
|
4659
|
+
"w-full bg-surface text-foreground py-12 mt-auto",
|
|
4660
|
+
bordered && "border-t border-border",
|
|
4661
|
+
className
|
|
4662
|
+
),
|
|
4663
|
+
...props,
|
|
4664
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children })
|
|
4665
|
+
}
|
|
4666
|
+
);
|
|
4667
|
+
}
|
|
4668
|
+
);
|
|
4669
|
+
AppShellFooter.displayName = "AppShellFooter";
|
|
4670
|
+
var AppShell = React52__namespace.forwardRef(
|
|
4671
|
+
({
|
|
4672
|
+
className,
|
|
4673
|
+
banner,
|
|
4674
|
+
header,
|
|
4675
|
+
children,
|
|
4676
|
+
footer,
|
|
4677
|
+
contentWidth = "default",
|
|
4678
|
+
headerPosition = "sticky",
|
|
4679
|
+
headerVariant = "glass",
|
|
4680
|
+
paddedContent = true,
|
|
4681
|
+
mobileNav,
|
|
4682
|
+
...props
|
|
4683
|
+
}, ref) => {
|
|
4684
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4685
|
+
"div",
|
|
4686
|
+
{
|
|
4687
|
+
ref,
|
|
4688
|
+
className: cn("min-h-screen bg-canvas text-foreground flex flex-col antialiased", className),
|
|
4689
|
+
...props,
|
|
4690
|
+
children: [
|
|
4691
|
+
banner && /* @__PURE__ */ jsxRuntime.jsx(AppShellBanner, { children: banner }),
|
|
4692
|
+
header && /* @__PURE__ */ jsxRuntime.jsx(AppShellHeader, { variant: headerVariant, position: headerPosition, mobileNav, children: header }),
|
|
4693
|
+
/* @__PURE__ */ jsxRuntime.jsx(AppShellMain, { width: contentWidth, padded: paddedContent, children }),
|
|
4694
|
+
footer && /* @__PURE__ */ jsxRuntime.jsx(AppShellFooter, { children: footer })
|
|
4695
|
+
]
|
|
4696
|
+
}
|
|
4697
|
+
);
|
|
4698
|
+
}
|
|
4699
|
+
);
|
|
4700
|
+
AppShell.displayName = "AppShell";
|
|
4701
|
+
AppShell.Banner = AppShellBanner;
|
|
4702
|
+
AppShell.Header = AppShellHeader;
|
|
4703
|
+
AppShell.Main = AppShellMain;
|
|
4704
|
+
AppShell.Footer = AppShellFooter;
|
|
4705
|
+
var sizeClasses = {
|
|
4706
|
+
sm: { wrapper: "kj-rating-sm gap-1", star: "w-4 h-4", text: "text-xs" },
|
|
4707
|
+
md: { wrapper: "kj-rating-md gap-1.5", star: "w-5 h-5", text: "text-sm" },
|
|
4708
|
+
lg: { wrapper: "kj-rating-lg gap-2", star: "w-6 h-6", text: "text-base" },
|
|
4709
|
+
xl: { wrapper: "kj-rating-xl gap-2.5", star: "w-8 h-8", text: "text-lg" }
|
|
4710
|
+
};
|
|
4711
|
+
var iconPaths = {
|
|
4712
|
+
star: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z",
|
|
4713
|
+
heart: "M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z",
|
|
4714
|
+
flame: "M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z",
|
|
4715
|
+
shield: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67 0C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",
|
|
4716
|
+
thumb: "M7 10v12M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z"
|
|
4717
|
+
};
|
|
4718
|
+
function roundToPrecision(value, precision) {
|
|
4719
|
+
const inv = 1 / precision;
|
|
4720
|
+
return Math.round(value * inv) / inv;
|
|
4721
|
+
}
|
|
4722
|
+
function isCssColor(str) {
|
|
4723
|
+
return str.startsWith("#") || str.startsWith("rgb") || str.startsWith("hsl");
|
|
4724
|
+
}
|
|
4725
|
+
var Rating = React52__namespace.forwardRef(
|
|
4726
|
+
({
|
|
4727
|
+
value: controlledValue,
|
|
4728
|
+
defaultValue = 0,
|
|
4729
|
+
max = 5,
|
|
4730
|
+
precision = 1,
|
|
4731
|
+
size = "md",
|
|
4732
|
+
icon = "star",
|
|
4733
|
+
color = "#f59e0b",
|
|
4734
|
+
emptyColor = "#e5e7eb",
|
|
4735
|
+
allowClear = true,
|
|
4736
|
+
disabled = false,
|
|
4737
|
+
readOnly = false,
|
|
4738
|
+
hoverPreview = true,
|
|
4739
|
+
showValue = false,
|
|
4740
|
+
showCount = false,
|
|
4741
|
+
count,
|
|
4742
|
+
name,
|
|
4743
|
+
onChange,
|
|
4744
|
+
onHoverChange,
|
|
4745
|
+
className,
|
|
4746
|
+
onKeyDown,
|
|
4747
|
+
onMouseLeave,
|
|
4748
|
+
"aria-label": ariaLabel,
|
|
4749
|
+
...props
|
|
4750
|
+
}, ref) => {
|
|
4751
|
+
const isControlled = controlledValue !== void 0;
|
|
4752
|
+
const [internalValue, setInternalValue] = React52__namespace.useState(
|
|
4753
|
+
controlledValue ?? defaultValue
|
|
4754
|
+
);
|
|
4755
|
+
const [hoverValue, setHoverValue] = React52__namespace.useState(null);
|
|
4756
|
+
const instanceId = React52__namespace.useId();
|
|
4757
|
+
React52__namespace.useEffect(() => {
|
|
4758
|
+
if (isControlled) {
|
|
4759
|
+
setInternalValue(controlledValue);
|
|
4760
|
+
}
|
|
4761
|
+
}, [isControlled, controlledValue]);
|
|
4762
|
+
const currentValue = isControlled ? controlledValue : internalValue;
|
|
4763
|
+
const displayValue = hoverPreview && hoverValue !== null ? hoverValue : currentValue;
|
|
4764
|
+
const handleValueChange = (newValue) => {
|
|
4765
|
+
if (disabled || readOnly) return;
|
|
4766
|
+
const clamped = Math.max(0, Math.min(max, roundToPrecision(newValue, precision)));
|
|
4767
|
+
if (!isControlled) {
|
|
4768
|
+
setInternalValue(clamped);
|
|
4769
|
+
}
|
|
4770
|
+
onChange?.(clamped);
|
|
4771
|
+
};
|
|
4772
|
+
const getEventValue = (e, starIndex) => {
|
|
4773
|
+
const target = e.currentTarget;
|
|
4774
|
+
const width = target.offsetWidth;
|
|
4775
|
+
const nativeEv = e.nativeEvent;
|
|
4776
|
+
const offsetX = nativeEv?.offsetX ?? nativeEv?.nativeEvent?.offsetX ?? e.offsetX;
|
|
4777
|
+
if (width > 0 && offsetX !== void 0 && offsetX !== null) {
|
|
4778
|
+
const ratio = Math.max(1e-3, Math.min(1, offsetX / width));
|
|
4779
|
+
const stepInStar = Math.ceil(ratio / precision) * precision;
|
|
4780
|
+
return Math.min(max, Math.max(precision, starIndex - 1 + stepInStar));
|
|
4781
|
+
}
|
|
4782
|
+
return starIndex;
|
|
4783
|
+
};
|
|
4784
|
+
const handleStarClick = (e, starIndex) => {
|
|
4785
|
+
if (disabled || readOnly) return;
|
|
4786
|
+
const targetValue = getEventValue(e, starIndex);
|
|
4787
|
+
let nextValue = targetValue;
|
|
4788
|
+
if (allowClear && targetValue === currentValue) {
|
|
4789
|
+
nextValue = 0;
|
|
4790
|
+
}
|
|
4791
|
+
handleValueChange(nextValue);
|
|
4792
|
+
};
|
|
4793
|
+
const handleStarMouseMove = (e, starIndex) => {
|
|
4794
|
+
if (disabled || readOnly) return;
|
|
4795
|
+
if (hoverPreview) {
|
|
4796
|
+
const hoveredVal = getEventValue(e, starIndex);
|
|
4797
|
+
setHoverValue(hoveredVal);
|
|
4798
|
+
onHoverChange?.(hoveredVal);
|
|
4799
|
+
}
|
|
4800
|
+
};
|
|
4801
|
+
const handleKeyDown = (e) => {
|
|
4802
|
+
if (disabled || readOnly) {
|
|
4803
|
+
onKeyDown?.(e);
|
|
4804
|
+
return;
|
|
4805
|
+
}
|
|
4806
|
+
let nextVal = null;
|
|
4807
|
+
switch (e.key) {
|
|
4808
|
+
case "ArrowRight":
|
|
4809
|
+
case "ArrowUp":
|
|
4810
|
+
nextVal = Math.min(max, currentValue + precision);
|
|
4811
|
+
break;
|
|
4812
|
+
case "ArrowLeft":
|
|
4813
|
+
case "ArrowDown":
|
|
4814
|
+
nextVal = Math.max(0, currentValue - precision);
|
|
4815
|
+
break;
|
|
4816
|
+
case "Home":
|
|
4817
|
+
nextVal = 0;
|
|
4818
|
+
break;
|
|
4819
|
+
case "End":
|
|
4820
|
+
nextVal = max;
|
|
4821
|
+
break;
|
|
4822
|
+
}
|
|
4823
|
+
if (nextVal !== null) {
|
|
4824
|
+
e.preventDefault();
|
|
4825
|
+
handleValueChange(nextVal);
|
|
4826
|
+
}
|
|
4827
|
+
onKeyDown?.(e);
|
|
4828
|
+
};
|
|
4829
|
+
const handleContainerMouseLeave = (e) => {
|
|
4830
|
+
if (hoverPreview) {
|
|
4831
|
+
setHoverValue(null);
|
|
4832
|
+
onHoverChange?.(null);
|
|
4833
|
+
}
|
|
4834
|
+
onMouseLeave?.(e);
|
|
4835
|
+
};
|
|
4836
|
+
const sizing = sizeClasses[size] || sizeClasses.md;
|
|
4837
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4838
|
+
"div",
|
|
4839
|
+
{
|
|
4840
|
+
ref,
|
|
4841
|
+
role: readOnly ? "img" : "radiogroup",
|
|
4842
|
+
tabIndex: disabled || readOnly ? -1 : 0,
|
|
4843
|
+
"aria-valuenow": displayValue,
|
|
4844
|
+
"aria-valuemin": 0,
|
|
4845
|
+
"aria-valuemax": max,
|
|
4846
|
+
"aria-disabled": disabled || void 0,
|
|
4847
|
+
"aria-readonly": readOnly || void 0,
|
|
4848
|
+
"aria-label": ariaLabel || (readOnly ? `Rated ${displayValue} out of ${max}` : "Rating"),
|
|
4849
|
+
onKeyDown: handleKeyDown,
|
|
4850
|
+
onMouseLeave: handleContainerMouseLeave,
|
|
4851
|
+
className: cn(
|
|
4852
|
+
"inline-flex items-center select-none focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-md",
|
|
4853
|
+
disabled && "opacity-50 cursor-not-allowed",
|
|
4854
|
+
readOnly && "cursor-default",
|
|
4855
|
+
!disabled && !readOnly && "cursor-pointer",
|
|
4856
|
+
sizing.wrapper,
|
|
4857
|
+
className
|
|
4858
|
+
),
|
|
4859
|
+
...props,
|
|
4860
|
+
children: [
|
|
4861
|
+
name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: currentValue }),
|
|
4862
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center gap-0.5", children: Array.from({ length: max }, (_, index) => {
|
|
4863
|
+
const starIndex = index + 1;
|
|
4864
|
+
const fillFraction = Math.max(
|
|
4865
|
+
0,
|
|
4866
|
+
Math.min(1, displayValue - index)
|
|
4867
|
+
);
|
|
4868
|
+
const gradientId = `rating-grad-${instanceId}-${index}-${Math.round(
|
|
4869
|
+
fillFraction * 100
|
|
4870
|
+
)}`;
|
|
4871
|
+
const CustomIconComponent = typeof icon === "function" || typeof icon === "object" ? icon : null;
|
|
4872
|
+
const builtInIconType = typeof icon === "string" ? icon : "star";
|
|
4873
|
+
const pathD = iconPaths[builtInIconType] || iconPaths.star;
|
|
4874
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4875
|
+
"button",
|
|
4876
|
+
{
|
|
4877
|
+
type: "button",
|
|
4878
|
+
tabIndex: -1,
|
|
4879
|
+
"data-testid": "rating-star",
|
|
4880
|
+
role: readOnly ? void 0 : "radio",
|
|
4881
|
+
"aria-checked": readOnly ? void 0 : displayValue >= starIndex,
|
|
4882
|
+
"aria-label": `${starIndex} of ${max} stars`,
|
|
4883
|
+
disabled,
|
|
4884
|
+
onClick: (e) => handleStarClick(e, starIndex),
|
|
4885
|
+
onMouseMove: (e) => handleStarMouseMove(e, starIndex),
|
|
4886
|
+
onMouseEnter: (e) => handleStarMouseMove(e, starIndex),
|
|
4887
|
+
className: cn(
|
|
4888
|
+
"p-0.5 focus:outline-none transition-transform active:scale-95 disabled:scale-100",
|
|
4889
|
+
sizing.star
|
|
4890
|
+
),
|
|
4891
|
+
children: CustomIconComponent ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4892
|
+
CustomIconComponent,
|
|
4893
|
+
{
|
|
4894
|
+
className: cn(
|
|
4895
|
+
"w-full h-full",
|
|
4896
|
+
fillFraction >= 0.5 ? !isCssColor(color) && color : !isCssColor(emptyColor) && emptyColor
|
|
4897
|
+
)
|
|
4898
|
+
}
|
|
4899
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4900
|
+
"svg",
|
|
4901
|
+
{
|
|
4902
|
+
viewBox: "0 0 24 24",
|
|
4903
|
+
className: "w-full h-full",
|
|
4904
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4905
|
+
children: [
|
|
4906
|
+
fillFraction > 0 && fillFraction < 1 && /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4907
|
+
"linearGradient",
|
|
4908
|
+
{
|
|
4909
|
+
id: gradientId,
|
|
4910
|
+
x1: "0%",
|
|
4911
|
+
y1: "0%",
|
|
4912
|
+
x2: "100%",
|
|
4913
|
+
y2: "0%",
|
|
4914
|
+
children: [
|
|
4915
|
+
isCssColor(color) ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4916
|
+
"stop",
|
|
4917
|
+
{
|
|
4918
|
+
offset: `${fillFraction * 100}%`,
|
|
4919
|
+
stopColor: color
|
|
4920
|
+
}
|
|
4921
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4922
|
+
"stop",
|
|
4923
|
+
{
|
|
4924
|
+
offset: `${fillFraction * 100}%`,
|
|
4925
|
+
stopColor: "currentColor",
|
|
4926
|
+
className: color
|
|
4927
|
+
}
|
|
4928
|
+
),
|
|
4929
|
+
isCssColor(emptyColor) ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4930
|
+
"stop",
|
|
4931
|
+
{
|
|
4932
|
+
offset: `${fillFraction * 100}%`,
|
|
4933
|
+
stopColor: emptyColor
|
|
4934
|
+
}
|
|
4935
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4936
|
+
"stop",
|
|
4937
|
+
{
|
|
4938
|
+
offset: `${fillFraction * 100}%`,
|
|
4939
|
+
stopColor: "currentColor",
|
|
4940
|
+
className: emptyColor
|
|
4941
|
+
}
|
|
4942
|
+
)
|
|
4943
|
+
]
|
|
4944
|
+
}
|
|
4945
|
+
) }),
|
|
4946
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4947
|
+
"path",
|
|
4948
|
+
{
|
|
4949
|
+
d: pathD,
|
|
4950
|
+
fill: fillFraction === 1 ? isCssColor(color) ? color : void 0 : fillFraction === 0 ? isCssColor(emptyColor) ? emptyColor : void 0 : `url(#${gradientId})`,
|
|
4951
|
+
className: fillFraction === 1 ? !isCssColor(color) ? color : void 0 : fillFraction === 0 ? !isCssColor(emptyColor) ? emptyColor : void 0 : void 0,
|
|
4952
|
+
stroke: "none"
|
|
4953
|
+
}
|
|
4954
|
+
)
|
|
4955
|
+
]
|
|
4956
|
+
}
|
|
4957
|
+
)
|
|
4958
|
+
},
|
|
4959
|
+
index
|
|
4960
|
+
);
|
|
4961
|
+
}) }),
|
|
4962
|
+
showValue && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-medium text-foreground ml-1.5", sizing.text), children: displayValue }),
|
|
4963
|
+
showCount && count !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("text-muted-foreground ml-1", sizing.text), children: [
|
|
4964
|
+
"(",
|
|
4965
|
+
count,
|
|
4966
|
+
")"
|
|
4967
|
+
] })
|
|
4968
|
+
]
|
|
4969
|
+
}
|
|
4970
|
+
);
|
|
4971
|
+
}
|
|
4972
|
+
);
|
|
4973
|
+
Rating.displayName = "Rating";
|
|
4974
|
+
var RatingField = React52__namespace.forwardRef(
|
|
4975
|
+
({
|
|
4976
|
+
id: customId,
|
|
4977
|
+
label,
|
|
4978
|
+
helperText,
|
|
4979
|
+
errorMessage,
|
|
4980
|
+
required,
|
|
4981
|
+
className,
|
|
4982
|
+
containerClassName,
|
|
4983
|
+
"aria-describedby": ariaDescribedBy,
|
|
4984
|
+
...ratingProps
|
|
4985
|
+
}, ref) => {
|
|
4986
|
+
const generatedId = React52__namespace.useId();
|
|
4987
|
+
const id = customId || generatedId;
|
|
4988
|
+
const helperId = helperText ? `${id}-helper` : void 0;
|
|
4989
|
+
const errorId = errorMessage ? `${id}-error` : void 0;
|
|
4990
|
+
const describedBy = [ariaDescribedBy, helperId, errorId].filter(Boolean).join(" ") || void 0;
|
|
4991
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1.5", containerClassName), children: [
|
|
4992
|
+
label && /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: id, required, children: label }),
|
|
4993
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4994
|
+
Rating,
|
|
4995
|
+
{
|
|
4996
|
+
ref,
|
|
4997
|
+
id,
|
|
4998
|
+
className,
|
|
4999
|
+
"aria-describedby": describedBy,
|
|
5000
|
+
...ratingProps
|
|
5001
|
+
}
|
|
5002
|
+
),
|
|
5003
|
+
helperText && /* @__PURE__ */ jsxRuntime.jsx(Hint, { id: helperId, children: helperText }),
|
|
5004
|
+
errorMessage && /* @__PURE__ */ jsxRuntime.jsx(Hint, { id: errorId, error: true, children: errorMessage })
|
|
5005
|
+
] });
|
|
5006
|
+
}
|
|
5007
|
+
);
|
|
5008
|
+
RatingField.displayName = "RatingField";
|
|
5009
|
+
var RatingSummary = React52__namespace.forwardRef(
|
|
5010
|
+
({
|
|
5011
|
+
average,
|
|
5012
|
+
totalCount,
|
|
5013
|
+
distribution,
|
|
5014
|
+
max = 5,
|
|
5015
|
+
size = "md",
|
|
5016
|
+
icon = "star",
|
|
5017
|
+
className,
|
|
5018
|
+
...props
|
|
5019
|
+
}, ref) => {
|
|
5020
|
+
const formattedAverage = Number.isInteger(average) ? average.toString() : average.toFixed(1);
|
|
5021
|
+
const formattedTotalCount = totalCount.toLocaleString();
|
|
5022
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5023
|
+
"div",
|
|
5024
|
+
{
|
|
5025
|
+
ref,
|
|
5026
|
+
className: cn(
|
|
5027
|
+
"flex flex-col gap-6 sm:flex-row sm:items-center sm:gap-8 p-4 rounded-xl border bg-card text-card-foreground shadow-sm",
|
|
5028
|
+
className
|
|
5029
|
+
),
|
|
5030
|
+
...props,
|
|
5031
|
+
children: [
|
|
5032
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center p-4 rounded-lg bg-muted/40 text-center min-w-[140px]", children: [
|
|
5033
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-4xl font-bold tracking-tight text-foreground", children: formattedAverage }),
|
|
5034
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "my-1.5", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5035
|
+
Rating,
|
|
5036
|
+
{
|
|
5037
|
+
value: average,
|
|
5038
|
+
max,
|
|
5039
|
+
size,
|
|
5040
|
+
icon,
|
|
5041
|
+
readOnly: true,
|
|
5042
|
+
allowClear: false,
|
|
5043
|
+
hoverPreview: false
|
|
5044
|
+
}
|
|
5045
|
+
) }),
|
|
5046
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
|
|
5047
|
+
formattedTotalCount,
|
|
5048
|
+
" total ratings"
|
|
5049
|
+
] })
|
|
5050
|
+
] }),
|
|
5051
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex flex-col gap-2.5", children: distribution.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm", children: [
|
|
5052
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "w-12 text-right font-medium text-foreground whitespace-nowrap", children: [
|
|
5053
|
+
item.stars,
|
|
5054
|
+
" star"
|
|
5055
|
+
] }),
|
|
5056
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5057
|
+
Progress,
|
|
5058
|
+
{
|
|
5059
|
+
value: item.percentage,
|
|
5060
|
+
"aria-label": `${item.stars} star ratings: ${item.percentage}%`,
|
|
5061
|
+
className: "h-2.5 flex-1"
|
|
5062
|
+
}
|
|
5063
|
+
),
|
|
5064
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "w-12 text-right text-xs text-muted-foreground font-mono", children: [
|
|
5065
|
+
item.percentage,
|
|
5066
|
+
"%"
|
|
5067
|
+
] })
|
|
5068
|
+
] }, item.stars)) })
|
|
5069
|
+
]
|
|
5070
|
+
}
|
|
5071
|
+
);
|
|
5072
|
+
}
|
|
5073
|
+
);
|
|
5074
|
+
RatingSummary.displayName = "RatingSummary";
|
|
5075
|
+
var PricingCard = React52__namespace.forwardRef(
|
|
5076
|
+
({
|
|
5077
|
+
className,
|
|
5078
|
+
name,
|
|
5079
|
+
price,
|
|
5080
|
+
period,
|
|
5081
|
+
description,
|
|
5082
|
+
features = [],
|
|
5083
|
+
variant,
|
|
5084
|
+
badge,
|
|
5085
|
+
popular = false,
|
|
5086
|
+
ctaText = "Get Started",
|
|
5087
|
+
onCtaClick,
|
|
5088
|
+
ctaHref,
|
|
5089
|
+
cta,
|
|
5090
|
+
disabled = false,
|
|
5091
|
+
...props
|
|
5092
|
+
}, ref) => {
|
|
5093
|
+
const resolvedVariant = variant || (popular ? "featured" : "default");
|
|
5094
|
+
const displayBadge = badge || (popular ? "Most Popular" : void 0);
|
|
5095
|
+
const isFeatured = resolvedVariant === "featured";
|
|
5096
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5097
|
+
Card,
|
|
5098
|
+
{
|
|
5099
|
+
ref,
|
|
5100
|
+
className: cn(
|
|
5101
|
+
"relative flex flex-col p-6 transition-all duration-300",
|
|
5102
|
+
isFeatured ? "border-amber-500/80 shadow-kj-lg ring-1 ring-amber-500/30" : resolvedVariant === "outline" ? "border-border/80 bg-transparent shadow-none" : "border-border shadow-kj-sm",
|
|
5103
|
+
className
|
|
5104
|
+
),
|
|
5105
|
+
...props,
|
|
5106
|
+
children: [
|
|
5107
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4 flex items-start justify-between gap-3", children: [
|
|
5108
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
5109
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-bold tracking-tight text-foreground", children: name }),
|
|
5110
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: description })
|
|
5111
|
+
] }),
|
|
5112
|
+
displayBadge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-amber-500 px-3 py-0.5 text-[0.7rem] font-bold uppercase tracking-wider text-black shadow-sm shrink-0 mt-0.5", children: displayBadge })
|
|
5113
|
+
] }),
|
|
5114
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 flex items-baseline gap-1", children: [
|
|
5115
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-3xl font-extrabold tracking-tight text-foreground", children: price }),
|
|
5116
|
+
period && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: period })
|
|
5117
|
+
] }),
|
|
5118
|
+
features.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mb-6 flex flex-1 flex-col gap-2.5 p-0 text-xs list-none", children: features.map((feature, idx) => {
|
|
5119
|
+
const text = typeof feature === "string" ? feature : feature.text;
|
|
5120
|
+
const included = typeof feature === "string" ? true : feature.included ?? true;
|
|
5121
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center gap-2.5", children: [
|
|
5122
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5123
|
+
"span",
|
|
5124
|
+
{
|
|
5125
|
+
className: cn(
|
|
5126
|
+
"flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[0.65rem] font-bold",
|
|
5127
|
+
included ? "bg-amber-500/15 text-amber-600 dark:text-amber-400" : "bg-muted text-muted-foreground/60"
|
|
5128
|
+
),
|
|
5129
|
+
children: included ? "\u2713" : "\u2715"
|
|
5130
|
+
}
|
|
5131
|
+
),
|
|
5132
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(included ? "text-foreground" : "text-muted-foreground line-through opacity-70"), children: text })
|
|
5133
|
+
] }, idx);
|
|
5134
|
+
}) }),
|
|
5135
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto pt-2", children: cta ? cta : ctaHref ? (
|
|
5136
|
+
/* eslint-disable-next-line jsx-a11y/anchor-is-valid */
|
|
5137
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5138
|
+
"a",
|
|
5139
|
+
{
|
|
5140
|
+
href: disabled ? void 0 : ctaHref,
|
|
5141
|
+
"aria-disabled": disabled || void 0,
|
|
5142
|
+
tabIndex: disabled ? -1 : void 0,
|
|
5143
|
+
className: cn(
|
|
5144
|
+
buttonVariants({ variant: isFeatured ? "primary" : "outline" }),
|
|
5145
|
+
"w-full justify-center",
|
|
5146
|
+
disabled && "pointer-events-none opacity-50"
|
|
5147
|
+
),
|
|
5148
|
+
children: ctaText
|
|
5149
|
+
}
|
|
5150
|
+
)
|
|
5151
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
5152
|
+
Button,
|
|
5153
|
+
{
|
|
5154
|
+
variant: isFeatured ? "primary" : "outline",
|
|
5155
|
+
className: "w-full justify-center",
|
|
5156
|
+
onClick: onCtaClick,
|
|
5157
|
+
disabled,
|
|
5158
|
+
children: ctaText
|
|
5159
|
+
}
|
|
5160
|
+
) })
|
|
5161
|
+
]
|
|
5162
|
+
}
|
|
5163
|
+
);
|
|
5164
|
+
}
|
|
5165
|
+
);
|
|
5166
|
+
PricingCard.displayName = "PricingCard";
|
|
5167
|
+
var BlogCard = React52__namespace.forwardRef(
|
|
5168
|
+
({
|
|
5169
|
+
className,
|
|
5170
|
+
title,
|
|
5171
|
+
description,
|
|
5172
|
+
coverUrl,
|
|
5173
|
+
coverAlt,
|
|
5174
|
+
category,
|
|
5175
|
+
readTime,
|
|
5176
|
+
publishedAt,
|
|
5177
|
+
author,
|
|
5178
|
+
orientation = "vertical",
|
|
5179
|
+
href,
|
|
5180
|
+
...props
|
|
5181
|
+
}, ref) => {
|
|
5182
|
+
const isHorizontal = orientation === "horizontal";
|
|
5183
|
+
const isInteractive = Boolean(href || props.onClick);
|
|
5184
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5185
|
+
Card,
|
|
5186
|
+
{
|
|
5187
|
+
ref,
|
|
5188
|
+
as: href ? "a" : "div",
|
|
5189
|
+
href,
|
|
5190
|
+
interactive: isInteractive,
|
|
5191
|
+
className: cn(
|
|
5192
|
+
"group flex overflow-hidden transition-all duration-300",
|
|
5193
|
+
isHorizontal ? "flex-col sm:flex-row" : "flex-col",
|
|
5194
|
+
className
|
|
5195
|
+
),
|
|
5196
|
+
...props,
|
|
5197
|
+
children: [
|
|
5198
|
+
coverUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5199
|
+
"div",
|
|
5200
|
+
{
|
|
5201
|
+
className: cn(
|
|
5202
|
+
"relative overflow-hidden bg-muted shrink-0",
|
|
5203
|
+
isHorizontal ? "w-full sm:w-2/5 min-h-[160px]" : "w-full aspect-[16/9]"
|
|
5204
|
+
),
|
|
5205
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5206
|
+
"img",
|
|
5207
|
+
{
|
|
5208
|
+
src: coverUrl,
|
|
5209
|
+
alt: coverAlt || title,
|
|
5210
|
+
className: "h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"
|
|
5211
|
+
}
|
|
5212
|
+
)
|
|
5213
|
+
}
|
|
5214
|
+
),
|
|
5215
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col justify-between p-5", children: [
|
|
5216
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
5217
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center gap-2 text-[0.75rem] text-muted-foreground", children: [
|
|
5218
|
+
category && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "secondary", children: category }),
|
|
5219
|
+
(readTime || publishedAt) && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
5220
|
+
publishedAt,
|
|
5221
|
+
" ",
|
|
5222
|
+
publishedAt && readTime && "\u2022",
|
|
5223
|
+
" ",
|
|
5224
|
+
readTime
|
|
5225
|
+
] })
|
|
5226
|
+
] }),
|
|
5227
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-bold tracking-tight text-foreground transition-colors group-hover:text-primary", children: title }),
|
|
5228
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-xs text-muted-foreground line-clamp-2", children: description })
|
|
5229
|
+
] }),
|
|
5230
|
+
author && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex items-center gap-2.5 border-t border-border/60 pt-3", children: [
|
|
5231
|
+
/* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: author.avatarUrl, alt: author.name, size: "sm", children: author.name.charAt(0) }),
|
|
5232
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col text-xs", children: [
|
|
5233
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: author.name }),
|
|
5234
|
+
author.role && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.7rem] text-muted-foreground", children: author.role })
|
|
5235
|
+
] })
|
|
5236
|
+
] })
|
|
5237
|
+
] })
|
|
5238
|
+
]
|
|
5239
|
+
}
|
|
5240
|
+
);
|
|
5241
|
+
}
|
|
5242
|
+
);
|
|
5243
|
+
BlogCard.displayName = "BlogCard";
|
|
5244
|
+
var ProjectCard = React52__namespace.forwardRef(
|
|
5245
|
+
({
|
|
5246
|
+
className,
|
|
5247
|
+
title,
|
|
5248
|
+
description,
|
|
5249
|
+
status,
|
|
5250
|
+
techStack = [],
|
|
5251
|
+
metrics = [],
|
|
5252
|
+
updatedAt,
|
|
5253
|
+
actions,
|
|
5254
|
+
href,
|
|
5255
|
+
...props
|
|
5256
|
+
}, ref) => {
|
|
5257
|
+
const isInteractive = Boolean(href || props.onClick);
|
|
5258
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5259
|
+
Card,
|
|
5260
|
+
{
|
|
5261
|
+
ref,
|
|
5262
|
+
as: href ? "a" : "div",
|
|
5263
|
+
href,
|
|
5264
|
+
interactive: isInteractive,
|
|
5265
|
+
className: cn(
|
|
5266
|
+
"group flex flex-col justify-between p-5 transition-all duration-300",
|
|
5267
|
+
className
|
|
5268
|
+
),
|
|
5269
|
+
...props,
|
|
5270
|
+
children: [
|
|
5271
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
5272
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
5273
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-bold tracking-tight text-foreground transition-colors group-hover:text-primary", children: title }),
|
|
5274
|
+
status && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: status.variant || "neutral", className: "shrink-0 text-[0.65rem]", children: status.label })
|
|
5275
|
+
] }),
|
|
5276
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-xs text-muted-foreground line-clamp-2", children: description }),
|
|
5277
|
+
techStack.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3.5 flex flex-wrap gap-1.5", children: techStack.map((tech) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "neutral", className: "text-[0.65rem] py-0 px-2 font-mono", children: tech }, tech)) })
|
|
5278
|
+
] }),
|
|
5279
|
+
(metrics.length > 0 || updatedAt || actions) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex items-center justify-between border-t border-border/60 pt-3 text-[0.75rem] text-muted-foreground", children: [
|
|
5280
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
5281
|
+
metrics.map((metric, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5282
|
+
"span",
|
|
5283
|
+
{
|
|
5284
|
+
className: "flex items-center gap-1 font-mono font-medium",
|
|
5285
|
+
children: [
|
|
5286
|
+
metric.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: metric.icon }),
|
|
5287
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: metric.value }),
|
|
5288
|
+
metric.label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/70", children: metric.label })
|
|
5289
|
+
]
|
|
5290
|
+
},
|
|
5291
|
+
metric.label ? `${metric.label}-${idx}` : idx
|
|
5292
|
+
)),
|
|
5293
|
+
updatedAt && /* @__PURE__ */ jsxRuntime.jsx("span", { children: updatedAt })
|
|
5294
|
+
] }),
|
|
5295
|
+
actions && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5296
|
+
"div",
|
|
5297
|
+
{
|
|
5298
|
+
onClick: (e) => e.stopPropagation(),
|
|
5299
|
+
className: "flex items-center gap-1 shrink-0",
|
|
5300
|
+
children: actions
|
|
5301
|
+
}
|
|
5302
|
+
)
|
|
5303
|
+
] })
|
|
5304
|
+
]
|
|
5305
|
+
}
|
|
5306
|
+
);
|
|
5307
|
+
}
|
|
5308
|
+
);
|
|
5309
|
+
ProjectCard.displayName = "ProjectCard";
|
|
5310
|
+
function formatRelativeTime(date) {
|
|
5311
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
5312
|
+
if (isNaN(d.getTime())) return "";
|
|
5313
|
+
const diffMs = Date.now() - d.getTime();
|
|
5314
|
+
const diffMin = Math.floor(diffMs / 6e4);
|
|
5315
|
+
const diffH = Math.floor(diffMs / 36e5);
|
|
5316
|
+
const diffD = Math.floor(diffMs / 864e5);
|
|
5317
|
+
if (diffMin < 1) return "Just now";
|
|
5318
|
+
if (diffMin < 60) return `${diffMin} min ago`;
|
|
5319
|
+
if (diffH < 24) return diffH === 1 ? "1 hour ago" : `${diffH} hours ago`;
|
|
5320
|
+
if (diffD === 1) return "Yesterday";
|
|
5321
|
+
if (diffD < 7) return `${diffD} days ago`;
|
|
5322
|
+
return d.toLocaleDateString(void 0, { month: "short", day: "numeric" });
|
|
5323
|
+
}
|
|
5324
|
+
function useInboxState(initial) {
|
|
5325
|
+
const [items, setItems] = React52__namespace.useState(initial);
|
|
5326
|
+
const unreadCount = items.filter((i) => !i.read).length;
|
|
5327
|
+
const markRead = React52__namespace.useCallback((id) => {
|
|
5328
|
+
setItems(
|
|
5329
|
+
(prev) => prev.map((item) => item.id === id ? { ...item, read: true } : item)
|
|
5330
|
+
);
|
|
5331
|
+
}, []);
|
|
5332
|
+
const markAllRead = React52__namespace.useCallback(() => {
|
|
5333
|
+
setItems((prev) => prev.map((item) => ({ ...item, read: true })));
|
|
5334
|
+
}, []);
|
|
5335
|
+
const dismiss = React52__namespace.useCallback((id) => {
|
|
5336
|
+
setItems((prev) => prev.filter((item) => item.id !== id));
|
|
5337
|
+
}, []);
|
|
5338
|
+
return { items, unreadCount, markRead, markAllRead, dismiss };
|
|
5339
|
+
}
|
|
5340
|
+
var InboxContext = React52__namespace.createContext(null);
|
|
5341
|
+
function useInboxContext(part) {
|
|
5342
|
+
const ctx = React52__namespace.useContext(InboxContext);
|
|
5343
|
+
if (!ctx) throw new Error(`${part} must be used inside <InboxPopover>`);
|
|
5344
|
+
return ctx;
|
|
5345
|
+
}
|
|
5346
|
+
function InboxPopover({
|
|
5347
|
+
children,
|
|
5348
|
+
className,
|
|
5349
|
+
open: openProp,
|
|
5350
|
+
onOpenChange
|
|
5351
|
+
}) {
|
|
5352
|
+
const [openState, setOpenState] = React52__namespace.useState(false);
|
|
5353
|
+
const controlled = openProp !== void 0;
|
|
5354
|
+
const open = controlled ? openProp : openState;
|
|
5355
|
+
const triggerRef = React52__namespace.useRef(null);
|
|
5356
|
+
const ref = React52__namespace.useRef(null);
|
|
5357
|
+
const setOpen = React52__namespace.useCallback(
|
|
5358
|
+
(v) => {
|
|
5359
|
+
if (!controlled) setOpenState(v);
|
|
5360
|
+
onOpenChange?.(v);
|
|
5361
|
+
},
|
|
5362
|
+
[controlled, onOpenChange]
|
|
5363
|
+
);
|
|
5364
|
+
React52__namespace.useEffect(() => {
|
|
5365
|
+
if (!open) return;
|
|
5366
|
+
const onDoc = (e) => {
|
|
5367
|
+
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
5368
|
+
};
|
|
5369
|
+
const onEsc = (e) => {
|
|
5370
|
+
if (e.key === "Escape") {
|
|
5371
|
+
setOpen(false);
|
|
5372
|
+
triggerRef.current?.focus();
|
|
5373
|
+
}
|
|
5374
|
+
};
|
|
5375
|
+
document.addEventListener("mousedown", onDoc);
|
|
5376
|
+
document.addEventListener("keydown", onEsc);
|
|
5377
|
+
return () => {
|
|
5378
|
+
document.removeEventListener("mousedown", onDoc);
|
|
5379
|
+
document.removeEventListener("keydown", onEsc);
|
|
5380
|
+
};
|
|
5381
|
+
}, [open, setOpen]);
|
|
5382
|
+
const ctxValue = React52__namespace.useMemo(() => ({ open, setOpen, triggerRef }), [open, setOpen]);
|
|
5383
|
+
return /* @__PURE__ */ jsxRuntime.jsx(InboxContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("relative inline-block", className), children }) });
|
|
5384
|
+
}
|
|
5385
|
+
function InboxTrigger({
|
|
5386
|
+
unreadCount,
|
|
5387
|
+
label = "Notifications",
|
|
5388
|
+
className,
|
|
5389
|
+
onClick,
|
|
5390
|
+
...props
|
|
5391
|
+
}) {
|
|
5392
|
+
const ctx = useInboxContext("InboxTrigger");
|
|
5393
|
+
const setRef = (node) => {
|
|
5394
|
+
ctx.triggerRef.current = node;
|
|
5395
|
+
};
|
|
5396
|
+
const displayCount = unreadCount == null || unreadCount <= 0 ? null : unreadCount > 99 ? "99+" : String(unreadCount);
|
|
5397
|
+
const defaultLabel = displayCount ? `${label} (${displayCount} unread)` : label;
|
|
5398
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5399
|
+
"button",
|
|
5400
|
+
{
|
|
5401
|
+
ref: setRef,
|
|
5402
|
+
type: "button",
|
|
5403
|
+
"aria-label": defaultLabel,
|
|
5404
|
+
"aria-haspopup": "dialog",
|
|
5405
|
+
"aria-expanded": ctx.open,
|
|
5406
|
+
className: cn(
|
|
5407
|
+
"relative inline-flex items-center justify-center w-9 h-9 rounded-full",
|
|
5408
|
+
"bg-surface border border-border text-muted-foreground",
|
|
5409
|
+
"hover:bg-muted hover:text-foreground transition-colors",
|
|
5410
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",
|
|
5411
|
+
className
|
|
5412
|
+
),
|
|
5413
|
+
onClick: (e) => {
|
|
5414
|
+
ctx.setOpen(!ctx.open);
|
|
5415
|
+
onClick?.(e);
|
|
5416
|
+
},
|
|
5417
|
+
...props,
|
|
5418
|
+
children: [
|
|
5419
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5420
|
+
"svg",
|
|
5421
|
+
{
|
|
5422
|
+
width: 16,
|
|
5423
|
+
height: 16,
|
|
5424
|
+
viewBox: "0 0 24 24",
|
|
5425
|
+
fill: "none",
|
|
5426
|
+
stroke: "currentColor",
|
|
5427
|
+
strokeWidth: 2,
|
|
5428
|
+
strokeLinecap: "round",
|
|
5429
|
+
strokeLinejoin: "round",
|
|
5430
|
+
"aria-hidden": "true",
|
|
5431
|
+
children: [
|
|
5432
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" }),
|
|
5433
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M13.73 21a2 2 0 0 1-3.46 0" })
|
|
5434
|
+
]
|
|
5435
|
+
}
|
|
5436
|
+
),
|
|
5437
|
+
displayCount != null && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5438
|
+
"span",
|
|
5439
|
+
{
|
|
5440
|
+
"aria-hidden": "true",
|
|
5441
|
+
className: cn(
|
|
5442
|
+
"absolute -top-0.5 -right-0.5 min-w-[16px] h-4 px-1",
|
|
5443
|
+
"rounded-full bg-primary text-primary-foreground",
|
|
5444
|
+
"text-[9px] font-bold leading-4 flex items-center justify-center"
|
|
5445
|
+
),
|
|
5446
|
+
children: displayCount
|
|
5447
|
+
}
|
|
5448
|
+
)
|
|
5449
|
+
]
|
|
5450
|
+
}
|
|
5451
|
+
);
|
|
5452
|
+
}
|
|
5453
|
+
function NotificationItem({ item, onDismiss, className }) {
|
|
5454
|
+
const leadingSlot = item.avatarSrc ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5455
|
+
"img",
|
|
5456
|
+
{
|
|
5457
|
+
src: item.avatarSrc,
|
|
5458
|
+
alt: item.avatarFallback ?? "",
|
|
5459
|
+
className: "w-7 h-7 rounded-full object-cover flex-shrink-0"
|
|
5460
|
+
}
|
|
5461
|
+
) : item.avatarFallback ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-7 h-7 rounded-full bg-primary/20 text-primary text-[10px] font-bold flex items-center justify-center flex-shrink-0 select-none", children: item.avatarFallback }) : item.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-7 h-7 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0 text-primary", children: item.icon }) : null;
|
|
5462
|
+
const textBlock = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
5463
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("text-sm leading-snug", item.read ? "text-muted-foreground" : "text-foreground"), children: item.title }),
|
|
5464
|
+
item.body && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-0.5 truncate", children: item.body }),
|
|
5465
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-1", children: formatRelativeTime(item.timestamp) })
|
|
5466
|
+
] });
|
|
5467
|
+
const sharedClass = cn(
|
|
5468
|
+
"group relative flex items-start gap-2.5 px-3.5 py-2.5 w-full text-left",
|
|
5469
|
+
"border-b border-border last:border-0",
|
|
5470
|
+
!item.read && "bg-primary/[0.04]",
|
|
5471
|
+
"hover:bg-muted/50 transition-colors",
|
|
5472
|
+
className
|
|
5473
|
+
);
|
|
5474
|
+
const mainContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5475
|
+
leadingSlot,
|
|
5476
|
+
textBlock
|
|
5477
|
+
] });
|
|
5478
|
+
const mainAction = item.href ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5479
|
+
"a",
|
|
5480
|
+
{
|
|
5481
|
+
href: item.href,
|
|
5482
|
+
onClick: () => item.onClick?.(item.id),
|
|
5483
|
+
className: "flex-1 flex items-start gap-2.5 min-w-0 text-left outline-none",
|
|
5484
|
+
children: mainContent
|
|
5485
|
+
}
|
|
5486
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
5487
|
+
"button",
|
|
5488
|
+
{
|
|
5489
|
+
type: "button",
|
|
5490
|
+
onClick: () => item.onClick?.(item.id),
|
|
5491
|
+
className: "flex-1 flex items-start gap-2.5 min-w-0 text-left outline-none",
|
|
5492
|
+
children: mainContent
|
|
5493
|
+
}
|
|
5494
|
+
);
|
|
5495
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: sharedClass, children: [
|
|
5496
|
+
mainAction,
|
|
5497
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 flex-shrink-0 mt-0.5", children: [
|
|
5498
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5499
|
+
"button",
|
|
5500
|
+
{
|
|
5501
|
+
type: "button",
|
|
5502
|
+
"aria-label": "Dismiss",
|
|
5503
|
+
onClick: (e) => {
|
|
5504
|
+
e.preventDefault();
|
|
5505
|
+
e.stopPropagation();
|
|
5506
|
+
onDismiss?.(item.id);
|
|
5507
|
+
},
|
|
5508
|
+
className: cn(
|
|
5509
|
+
"text-muted-foreground hover:text-foreground transition-colors",
|
|
5510
|
+
"opacity-0 group-hover:opacity-100 focus:opacity-100",
|
|
5511
|
+
"text-base leading-none p-0.5 rounded"
|
|
5512
|
+
),
|
|
5513
|
+
children: "\xD7"
|
|
5514
|
+
}
|
|
5515
|
+
),
|
|
5516
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5517
|
+
"span",
|
|
5518
|
+
{
|
|
5519
|
+
"aria-label": item.read ? void 0 : "Unread",
|
|
5520
|
+
"aria-hidden": item.read ? true : void 0,
|
|
5521
|
+
className: cn(
|
|
5522
|
+
"w-[7px] h-[7px] rounded-full flex-shrink-0 mt-1",
|
|
5523
|
+
item.read ? "border border-border" : "bg-primary"
|
|
5524
|
+
)
|
|
5525
|
+
}
|
|
5526
|
+
)
|
|
5527
|
+
] })
|
|
5528
|
+
] });
|
|
5529
|
+
}
|
|
5530
|
+
function InboxContent({
|
|
5531
|
+
items,
|
|
5532
|
+
onMarkAllRead,
|
|
5533
|
+
onDismiss,
|
|
5534
|
+
viewAllHref,
|
|
5535
|
+
viewAllLabel = "View all notifications",
|
|
5536
|
+
emptyState,
|
|
5537
|
+
width = 360,
|
|
5538
|
+
maxHeight = 320,
|
|
5539
|
+
className
|
|
5540
|
+
}) {
|
|
5541
|
+
const ctx = useInboxContext("InboxContent");
|
|
5542
|
+
const ref = React52__namespace.useRef(null);
|
|
5543
|
+
React52__namespace.useEffect(() => {
|
|
5544
|
+
if (ctx.open) ref.current?.focus();
|
|
5545
|
+
}, [ctx.open]);
|
|
5546
|
+
if (!ctx.open) return null;
|
|
5547
|
+
const allRead = items.length === 0 || items.every((i) => i.read);
|
|
5548
|
+
const defaultEmptyState = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-10 px-5 text-center", children: [
|
|
5549
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-10 h-10 rounded-full bg-muted flex items-center justify-center mb-3 text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
5550
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" }),
|
|
5551
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M13.73 21a2 2 0 0 1-3.46 0" })
|
|
5552
|
+
] }) }),
|
|
5553
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-foreground", children: "All caught up" }),
|
|
5554
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: "No new notifications" })
|
|
5555
|
+
] });
|
|
5556
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5557
|
+
"div",
|
|
5558
|
+
{
|
|
5559
|
+
ref,
|
|
5560
|
+
role: "dialog",
|
|
5561
|
+
"aria-label": "Notifications",
|
|
5562
|
+
tabIndex: -1,
|
|
5563
|
+
style: { width },
|
|
5564
|
+
className: cn(
|
|
5565
|
+
"absolute right-0 top-[calc(100%+6px)] z-40",
|
|
5566
|
+
"bg-surface border border-border rounded-kj-md shadow-kj-lg outline-none",
|
|
5567
|
+
"animate-[kjpop_.12s_ease]",
|
|
5568
|
+
className
|
|
5569
|
+
),
|
|
5570
|
+
children: [
|
|
5571
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-3.5 py-2.5 border-b border-border", children: [
|
|
5572
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-foreground", children: "Notifications" }),
|
|
5573
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5574
|
+
"button",
|
|
5575
|
+
{
|
|
5576
|
+
type: "button",
|
|
5577
|
+
disabled: allRead,
|
|
5578
|
+
"aria-disabled": allRead,
|
|
5579
|
+
onClick: allRead ? void 0 : onMarkAllRead,
|
|
5580
|
+
className: cn(
|
|
5581
|
+
"text-xs font-medium transition-colors",
|
|
5582
|
+
allRead ? "text-muted-foreground cursor-not-allowed" : "text-primary hover:text-primary/80"
|
|
5583
|
+
),
|
|
5584
|
+
children: "Mark all read"
|
|
5585
|
+
}
|
|
5586
|
+
)
|
|
5587
|
+
] }),
|
|
5588
|
+
items.length === 0 ? emptyState ?? defaultEmptyState : /* @__PURE__ */ jsxRuntime.jsx(
|
|
5589
|
+
"div",
|
|
5590
|
+
{
|
|
5591
|
+
className: "overflow-y-auto",
|
|
5592
|
+
style: { maxHeight },
|
|
5593
|
+
children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5594
|
+
NotificationItem,
|
|
5595
|
+
{
|
|
5596
|
+
item,
|
|
5597
|
+
onDismiss
|
|
5598
|
+
},
|
|
5599
|
+
item.id
|
|
5600
|
+
))
|
|
5601
|
+
}
|
|
5602
|
+
),
|
|
5603
|
+
items.length > 0 && viewAllHref && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border px-3.5 py-2.5 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5604
|
+
"a",
|
|
5605
|
+
{
|
|
5606
|
+
href: viewAllHref,
|
|
5607
|
+
className: "text-xs font-medium text-primary hover:text-primary/80 transition-colors",
|
|
5608
|
+
children: [
|
|
5609
|
+
viewAllLabel,
|
|
5610
|
+
" \u2192"
|
|
5611
|
+
]
|
|
5612
|
+
}
|
|
5613
|
+
) })
|
|
5614
|
+
]
|
|
5615
|
+
}
|
|
5616
|
+
);
|
|
5617
|
+
}
|
|
5618
|
+
var DEFAULT_COLOR_SWATCHES = [
|
|
5619
|
+
"#EF4444",
|
|
5620
|
+
// Red
|
|
5621
|
+
"#F97316",
|
|
5622
|
+
// Orange
|
|
5623
|
+
"#F59E0B",
|
|
5624
|
+
// Amber
|
|
5625
|
+
"#10B981",
|
|
5626
|
+
// Emerald
|
|
5627
|
+
"#14B8A6",
|
|
5628
|
+
// Teal
|
|
5629
|
+
"#06B6D4",
|
|
5630
|
+
// Sky
|
|
5631
|
+
"#3B82F6",
|
|
5632
|
+
// Blue
|
|
5633
|
+
"#6366F1",
|
|
5634
|
+
// Indigo
|
|
5635
|
+
"#8B5CF6",
|
|
5636
|
+
// Purple
|
|
5637
|
+
"#EC4899",
|
|
5638
|
+
// Pink
|
|
5639
|
+
"#64748B",
|
|
5640
|
+
// Slate
|
|
5641
|
+
"#1E293B"
|
|
5642
|
+
// Charcoal
|
|
5643
|
+
];
|
|
5644
|
+
function isValidHex(hex) {
|
|
5645
|
+
const trimmed = hex.trim();
|
|
5646
|
+
const clean = trimmed.startsWith("#") ? trimmed.slice(1) : trimmed;
|
|
5647
|
+
return /^[0-9A-Fa-f]{3}$|^[0-9A-Fa-f]{6}$/.test(clean);
|
|
5648
|
+
}
|
|
5649
|
+
function normalizeHex(hex) {
|
|
5650
|
+
let clean = hex.trim();
|
|
5651
|
+
if (!clean.startsWith("#")) clean = `#${clean}`;
|
|
5652
|
+
if (/^#[0-9A-Fa-f]{3}$/.test(clean)) {
|
|
5653
|
+
clean = `#${clean[1]}${clean[1]}${clean[2]}${clean[2]}${clean[3]}${clean[3]}`;
|
|
5654
|
+
}
|
|
5655
|
+
return clean.toUpperCase();
|
|
5656
|
+
}
|
|
5657
|
+
function hexToHsl(hex) {
|
|
5658
|
+
if (!isValidHex(hex)) return { h: 0, s: 0, l: 0 };
|
|
5659
|
+
const normalized = normalizeHex(hex);
|
|
5660
|
+
const r = parseInt(normalized.slice(1, 3), 16) / 255;
|
|
5661
|
+
const g = parseInt(normalized.slice(3, 5), 16) / 255;
|
|
5662
|
+
const b = parseInt(normalized.slice(5, 7), 16) / 255;
|
|
5663
|
+
const max = Math.max(r, g, b);
|
|
5664
|
+
const min = Math.min(r, g, b);
|
|
5665
|
+
let h = 0;
|
|
5666
|
+
let s = 0;
|
|
5667
|
+
const l = (max + min) / 2;
|
|
5668
|
+
if (max !== min) {
|
|
5669
|
+
const d = max - min;
|
|
5670
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
5671
|
+
switch (max) {
|
|
5672
|
+
case r:
|
|
5673
|
+
h = (g - b) / d + (g < b ? 6 : 0);
|
|
5674
|
+
break;
|
|
5675
|
+
case g:
|
|
5676
|
+
h = (b - r) / d + 2;
|
|
5677
|
+
break;
|
|
5678
|
+
case b:
|
|
5679
|
+
h = (r - g) / d + 4;
|
|
5680
|
+
break;
|
|
5681
|
+
}
|
|
5682
|
+
h /= 6;
|
|
5683
|
+
}
|
|
5684
|
+
return {
|
|
5685
|
+
h: Math.round(h * 360),
|
|
5686
|
+
s: Math.round(s * 100),
|
|
5687
|
+
l: Math.round(l * 100)
|
|
5688
|
+
};
|
|
5689
|
+
}
|
|
5690
|
+
function hslToHex(h, s, l) {
|
|
5691
|
+
const normalizedH = (h % 360 + 360) % 360;
|
|
5692
|
+
const sPct = s / 100;
|
|
5693
|
+
const lPct = l / 100;
|
|
5694
|
+
const c = (1 - Math.abs(2 * lPct - 1)) * sPct;
|
|
5695
|
+
const x = c * (1 - Math.abs(normalizedH / 60 % 2 - 1));
|
|
5696
|
+
const m = lPct - c / 2;
|
|
5697
|
+
let r = 0;
|
|
5698
|
+
let g = 0;
|
|
5699
|
+
let b = 0;
|
|
5700
|
+
if (0 <= normalizedH && normalizedH < 60) {
|
|
5701
|
+
r = c;
|
|
5702
|
+
g = x;
|
|
5703
|
+
b = 0;
|
|
5704
|
+
} else if (60 <= normalizedH && normalizedH < 120) {
|
|
5705
|
+
r = x;
|
|
5706
|
+
g = c;
|
|
5707
|
+
b = 0;
|
|
5708
|
+
} else if (120 <= normalizedH && normalizedH < 180) {
|
|
5709
|
+
r = 0;
|
|
5710
|
+
g = c;
|
|
5711
|
+
b = x;
|
|
5712
|
+
} else if (180 <= normalizedH && normalizedH < 240) {
|
|
5713
|
+
r = 0;
|
|
5714
|
+
g = x;
|
|
5715
|
+
b = c;
|
|
5716
|
+
} else if (240 <= normalizedH && normalizedH < 300) {
|
|
5717
|
+
r = x;
|
|
5718
|
+
g = 0;
|
|
5719
|
+
b = c;
|
|
5720
|
+
} else if (300 <= normalizedH && normalizedH < 360) {
|
|
5721
|
+
r = c;
|
|
5722
|
+
g = 0;
|
|
5723
|
+
b = x;
|
|
5724
|
+
}
|
|
5725
|
+
const toHex = (n) => {
|
|
5726
|
+
const hex = Math.round((n + m) * 255).toString(16);
|
|
5727
|
+
return hex.length === 1 ? `0${hex}` : hex;
|
|
5728
|
+
};
|
|
5729
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();
|
|
5730
|
+
}
|
|
5731
|
+
var ColorPickerSwatch = React52__namespace.forwardRef(({ color, selected = false, size = "md", className, style, ...props }, ref) => {
|
|
5732
|
+
const sizeClasses2 = {
|
|
5733
|
+
sm: "w-5 h-5",
|
|
5734
|
+
md: "w-7 h-7",
|
|
5735
|
+
lg: "w-9 h-9"
|
|
5736
|
+
};
|
|
5737
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5738
|
+
"button",
|
|
5739
|
+
{
|
|
5740
|
+
ref,
|
|
5741
|
+
type: "button",
|
|
5742
|
+
"aria-pressed": selected,
|
|
5743
|
+
style: { backgroundColor: color, ...style },
|
|
5744
|
+
className: cn(
|
|
5745
|
+
"relative shrink-0 rounded-full border border-border/50 shadow-sm transition-transform hover:scale-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary flex items-center justify-center text-white text-xs font-bold",
|
|
5746
|
+
sizeClasses2[size],
|
|
5747
|
+
selected && "ring-2 ring-primary ring-offset-2 ring-offset-surface",
|
|
5748
|
+
className
|
|
5749
|
+
),
|
|
5750
|
+
...props,
|
|
5751
|
+
children: selected && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2713" })
|
|
5752
|
+
}
|
|
5753
|
+
);
|
|
5754
|
+
});
|
|
5755
|
+
ColorPickerSwatch.displayName = "ColorPickerSwatch";
|
|
5756
|
+
var ColorPicker = React52__namespace.forwardRef(
|
|
5757
|
+
({
|
|
5758
|
+
value,
|
|
5759
|
+
defaultValue = "#3B82F6",
|
|
5760
|
+
onChange,
|
|
5761
|
+
swatches = DEFAULT_COLOR_SWATCHES,
|
|
5762
|
+
disabled = false,
|
|
5763
|
+
showHexInput = true,
|
|
5764
|
+
className,
|
|
5765
|
+
...props
|
|
5766
|
+
}, ref) => {
|
|
5767
|
+
const isControlled = value !== void 0;
|
|
5768
|
+
const [localColor, setLocalColor] = React52__namespace.useState(
|
|
5769
|
+
normalizeHex(defaultValue)
|
|
5770
|
+
);
|
|
5771
|
+
const color = isControlled ? normalizeHex(value) : localColor;
|
|
5772
|
+
const [hexInputValue, setHexInputValue] = React52__namespace.useState(color);
|
|
5773
|
+
React52__namespace.useEffect(() => {
|
|
5774
|
+
setHexInputValue(color);
|
|
5775
|
+
}, [color]);
|
|
5776
|
+
const handleColorChange = React52__namespace.useCallback(
|
|
5777
|
+
(newHex) => {
|
|
5778
|
+
const normalized = normalizeHex(newHex);
|
|
5779
|
+
if (!isControlled) {
|
|
5780
|
+
setLocalColor(normalized);
|
|
5781
|
+
}
|
|
5782
|
+
onChange?.(normalized);
|
|
5783
|
+
},
|
|
5784
|
+
[isControlled, onChange]
|
|
5785
|
+
);
|
|
5786
|
+
const hsl = React52__namespace.useMemo(() => hexToHsl(color), [color]);
|
|
5787
|
+
const handleHueChange = (e) => {
|
|
5788
|
+
const h = Number(e.target.value);
|
|
5789
|
+
const s = hsl.s === 0 ? 100 : hsl.s;
|
|
5790
|
+
const l = hsl.s === 0 ? 50 : hsl.l;
|
|
5791
|
+
const newHex = hslToHex(h, s, l);
|
|
5792
|
+
handleColorChange(newHex);
|
|
5793
|
+
};
|
|
5794
|
+
const handleHexSubmit = () => {
|
|
5795
|
+
if (isValidHex(hexInputValue)) {
|
|
5796
|
+
handleColorChange(hexInputValue);
|
|
5797
|
+
} else {
|
|
5798
|
+
setHexInputValue(color);
|
|
5799
|
+
}
|
|
5800
|
+
};
|
|
5801
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("inline-block", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsxs(Popover, { children: [
|
|
5802
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5803
|
+
"button",
|
|
5804
|
+
{
|
|
5805
|
+
type: "button",
|
|
5806
|
+
disabled,
|
|
5807
|
+
"aria-label": `Select color, current ${color}`,
|
|
5808
|
+
className: cn(
|
|
5809
|
+
"inline-flex items-center gap-2.5 px-3 py-1.5 rounded-kj-md border border-border bg-surface text-sm font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary disabled:cursor-not-allowed disabled:opacity-50"
|
|
5810
|
+
),
|
|
5811
|
+
children: [
|
|
5812
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5813
|
+
"span",
|
|
5814
|
+
{
|
|
5815
|
+
style: { backgroundColor: color },
|
|
5816
|
+
className: "w-5 h-5 rounded-full border border-border/50 shadow-sm shrink-0"
|
|
5817
|
+
}
|
|
5818
|
+
),
|
|
5819
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-xs uppercase", children: color }),
|
|
5820
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5821
|
+
"svg",
|
|
5822
|
+
{
|
|
5823
|
+
width: 12,
|
|
5824
|
+
height: 12,
|
|
5825
|
+
viewBox: "0 0 24 24",
|
|
5826
|
+
fill: "none",
|
|
5827
|
+
stroke: "currentColor",
|
|
5828
|
+
strokeWidth: 2,
|
|
5829
|
+
className: "text-muted-foreground ml-auto",
|
|
5830
|
+
"aria-hidden": "true",
|
|
5831
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" })
|
|
5832
|
+
}
|
|
5833
|
+
)
|
|
5834
|
+
]
|
|
5835
|
+
}
|
|
5836
|
+
) }),
|
|
5837
|
+
/* @__PURE__ */ jsxRuntime.jsxs(PopoverContent, { side: "bottom", align: "start", className: "w-64 p-3.5 space-y-3.5", children: [
|
|
5838
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 p-2 rounded-kj-md bg-muted/40 border border-border", children: [
|
|
5839
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5840
|
+
"span",
|
|
5841
|
+
{
|
|
5842
|
+
style: { backgroundColor: color },
|
|
5843
|
+
className: "w-8 h-8 rounded-full border border-border/50 shadow-sm shrink-0"
|
|
5844
|
+
}
|
|
5845
|
+
),
|
|
5846
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
5847
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Selected Color" }),
|
|
5848
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-mono font-bold text-foreground uppercase", children: color })
|
|
5849
|
+
] })
|
|
5850
|
+
] }),
|
|
5851
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
|
|
5852
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold text-muted-foreground", children: "Preset Swatches" }),
|
|
5853
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-6 gap-2", children: swatches.map((swatch) => {
|
|
5854
|
+
const normalizedSwatch = normalizeHex(swatch);
|
|
5855
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5856
|
+
ColorPickerSwatch,
|
|
5857
|
+
{
|
|
5858
|
+
color: swatch,
|
|
5859
|
+
selected: normalizedSwatch === color,
|
|
5860
|
+
"aria-label": `Select color ${swatch}`,
|
|
5861
|
+
onClick: () => handleColorChange(swatch)
|
|
5862
|
+
},
|
|
5863
|
+
swatch
|
|
5864
|
+
);
|
|
5865
|
+
}) })
|
|
5866
|
+
] }),
|
|
5867
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
|
|
5868
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold text-muted-foreground", children: "Hue" }),
|
|
5869
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5870
|
+
"input",
|
|
5871
|
+
{
|
|
5872
|
+
type: "range",
|
|
5873
|
+
min: 0,
|
|
5874
|
+
max: 360,
|
|
5875
|
+
value: hsl.h,
|
|
5876
|
+
onChange: handleHueChange,
|
|
5877
|
+
"aria-label": "Hue slider",
|
|
5878
|
+
className: "w-full h-3 rounded-full appearance-none cursor-pointer",
|
|
5879
|
+
style: {
|
|
5880
|
+
background: "linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%)"
|
|
5881
|
+
}
|
|
5882
|
+
}
|
|
5883
|
+
)
|
|
5884
|
+
] }),
|
|
5885
|
+
showHexInput && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
|
|
5886
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold text-muted-foreground", children: "Hex Code" }),
|
|
5887
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5888
|
+
"input",
|
|
5889
|
+
{
|
|
5890
|
+
type: "text",
|
|
5891
|
+
"aria-label": "Hex Code",
|
|
5892
|
+
value: hexInputValue,
|
|
5893
|
+
onChange: (e) => setHexInputValue(e.target.value),
|
|
5894
|
+
onBlur: handleHexSubmit,
|
|
5895
|
+
onKeyDown: (e) => {
|
|
5896
|
+
if (e.key === "Enter") handleHexSubmit();
|
|
5897
|
+
},
|
|
5898
|
+
placeholder: "#000000",
|
|
5899
|
+
className: "flex-1 px-2.5 py-1 text-xs font-mono rounded-kj-md border border-border bg-surface text-foreground uppercase focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary"
|
|
5900
|
+
}
|
|
5901
|
+
) })
|
|
5902
|
+
] })
|
|
5903
|
+
] })
|
|
5904
|
+
] }) });
|
|
5905
|
+
}
|
|
5906
|
+
);
|
|
5907
|
+
ColorPicker.displayName = "ColorPicker";
|
|
5908
|
+
var ColorPickerField = React52__namespace.forwardRef(({ label, hint, error, required, ...props }, ref) => {
|
|
5909
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Field, { children: [
|
|
5910
|
+
label && /* @__PURE__ */ jsxRuntime.jsx(Label, { required, children: label }),
|
|
5911
|
+
/* @__PURE__ */ jsxRuntime.jsx(ColorPicker, { ref, ...props }),
|
|
5912
|
+
hint && /* @__PURE__ */ jsxRuntime.jsx(Hint, { children: hint }),
|
|
5913
|
+
error && /* @__PURE__ */ jsxRuntime.jsx(Hint, { error: true, children: error })
|
|
5914
|
+
] });
|
|
5915
|
+
});
|
|
5916
|
+
ColorPickerField.displayName = "ColorPickerField";
|
|
5917
|
+
var COLUMN_CLASSES = {
|
|
5918
|
+
2: "grid-cols-2",
|
|
5919
|
+
3: "grid-cols-3",
|
|
5920
|
+
4: "grid-cols-4",
|
|
5921
|
+
5: "grid-cols-5"
|
|
5922
|
+
};
|
|
5923
|
+
var ASPECT_CLASSES = {
|
|
5924
|
+
square: "aspect-square",
|
|
5925
|
+
video: "aspect-video",
|
|
5926
|
+
"4/3": "aspect-[4/3]",
|
|
5927
|
+
auto: "aspect-auto"
|
|
5928
|
+
};
|
|
5929
|
+
function ImageGallery({
|
|
5930
|
+
images = [],
|
|
5931
|
+
columns = 3,
|
|
5932
|
+
aspectRatio = "square",
|
|
5933
|
+
maxVisible,
|
|
5934
|
+
className,
|
|
5935
|
+
thumbnailClassName,
|
|
5936
|
+
lightboxClassName,
|
|
5937
|
+
onImageClick
|
|
5938
|
+
}) {
|
|
5939
|
+
const [selectedIndex, setSelectedIndex] = React52__namespace.useState(null);
|
|
5940
|
+
const columnClass = COLUMN_CLASSES[columns] || "grid-cols-3";
|
|
5941
|
+
const aspectClass = ASPECT_CLASSES[aspectRatio] || (aspectRatio.startsWith("aspect-") ? aspectRatio : `aspect-[${aspectRatio}]`);
|
|
5942
|
+
const hasMaxVisible = typeof maxVisible === "number" && maxVisible > 0 && images.length > maxVisible;
|
|
5943
|
+
const visibleImages = hasMaxVisible ? images.slice(0, maxVisible) : images;
|
|
5944
|
+
const remainingCount = hasMaxVisible ? images.length - maxVisible + 1 : 0;
|
|
5945
|
+
const handleThumbnailClick = (index) => {
|
|
5946
|
+
setSelectedIndex(index);
|
|
5947
|
+
if (onImageClick) {
|
|
5948
|
+
onImageClick(index);
|
|
5949
|
+
}
|
|
5950
|
+
};
|
|
5951
|
+
const handleClose = React52__namespace.useCallback(() => {
|
|
5952
|
+
setSelectedIndex(null);
|
|
5953
|
+
}, []);
|
|
5954
|
+
const handleNext = React52__namespace.useCallback(() => {
|
|
5955
|
+
setSelectedIndex((prev) => prev === null ? null : (prev + 1) % images.length);
|
|
5956
|
+
}, [images.length]);
|
|
5957
|
+
const handlePrev = React52__namespace.useCallback(() => {
|
|
5958
|
+
setSelectedIndex((prev) => prev === null ? null : (prev - 1 + images.length) % images.length);
|
|
5959
|
+
}, [images.length]);
|
|
5960
|
+
React52__namespace.useEffect(() => {
|
|
5961
|
+
if (selectedIndex === null) return;
|
|
5962
|
+
const originalOverflow = document.body.style.overflow;
|
|
5963
|
+
const handleKeyDown = (e) => {
|
|
5964
|
+
if (e.key === "Escape") {
|
|
5965
|
+
handleClose();
|
|
5966
|
+
} else if (e.key === "ArrowRight") {
|
|
5967
|
+
handleNext();
|
|
5968
|
+
} else if (e.key === "ArrowLeft") {
|
|
5969
|
+
handlePrev();
|
|
5970
|
+
}
|
|
5971
|
+
};
|
|
5972
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
5973
|
+
document.body.style.overflow = "hidden";
|
|
5974
|
+
return () => {
|
|
5975
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
5976
|
+
document.body.style.overflow = originalOverflow;
|
|
5977
|
+
};
|
|
5978
|
+
}, [selectedIndex, handleClose, handleNext, handlePrev]);
|
|
5979
|
+
const activeImage = selectedIndex !== null ? images[selectedIndex] : null;
|
|
5980
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5981
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("grid gap-3 w-full", columnClass, className), children: visibleImages.map((img, idx) => {
|
|
5982
|
+
const isLastOverlay = hasMaxVisible && idx === maxVisible - 1;
|
|
5983
|
+
const thumbSrc = img.thumbnailSrc || img.src;
|
|
5984
|
+
const defaultAlt = img.alt || `Thumbnail ${idx + 1}`;
|
|
5985
|
+
const buttonAriaLabel = isLastOverlay ? `View all ${images.length} images` : defaultAlt;
|
|
5986
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5987
|
+
"button",
|
|
5988
|
+
{
|
|
5989
|
+
type: "button",
|
|
5990
|
+
"aria-label": buttonAriaLabel,
|
|
5991
|
+
onClick: () => handleThumbnailClick(idx),
|
|
5992
|
+
className: cn(
|
|
5993
|
+
"relative group overflow-hidden rounded-kj-lg bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 cursor-pointer transition-all duration-200",
|
|
5994
|
+
aspectClass,
|
|
5995
|
+
thumbnailClassName
|
|
5996
|
+
),
|
|
5997
|
+
children: [
|
|
5998
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5999
|
+
"img",
|
|
6000
|
+
{
|
|
6001
|
+
src: thumbSrc,
|
|
6002
|
+
alt: img.alt || `Thumbnail ${idx + 1}`,
|
|
6003
|
+
className: "w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
|
|
6004
|
+
}
|
|
6005
|
+
),
|
|
6006
|
+
isLastOverlay && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 bg-black/60 backdrop-blur-[2px] flex items-center justify-center text-white font-bold text-xl group-hover:bg-black/70 transition-colors", children: [
|
|
6007
|
+
"+",
|
|
6008
|
+
remainingCount
|
|
6009
|
+
] })
|
|
6010
|
+
]
|
|
6011
|
+
},
|
|
6012
|
+
idx
|
|
6013
|
+
);
|
|
6014
|
+
}) }),
|
|
6015
|
+
selectedIndex !== null && activeImage && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6016
|
+
"div",
|
|
6017
|
+
{
|
|
6018
|
+
role: "dialog",
|
|
6019
|
+
"aria-modal": "true",
|
|
6020
|
+
"aria-label": "Image gallery lightbox",
|
|
6021
|
+
onClick: (e) => e.target === e.currentTarget && handleClose(),
|
|
6022
|
+
className: cn(
|
|
6023
|
+
"fixed inset-0 z-[100] bg-black/85 backdrop-blur-md flex flex-col justify-between p-4 sm:p-6 transition-opacity duration-200 animate-in fade-in-0",
|
|
6024
|
+
lightboxClassName
|
|
6025
|
+
),
|
|
6026
|
+
children: [
|
|
6027
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between w-full text-white z-10", children: [
|
|
6028
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium text-white/80 select-none", children: [
|
|
6029
|
+
selectedIndex + 1,
|
|
6030
|
+
" of ",
|
|
6031
|
+
images.length
|
|
6032
|
+
] }),
|
|
6033
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6034
|
+
"button",
|
|
6035
|
+
{
|
|
6036
|
+
type: "button",
|
|
6037
|
+
onClick: handleClose,
|
|
6038
|
+
"aria-label": "Close",
|
|
6039
|
+
className: "p-2 rounded-full text-white/80 hover:text-white hover:bg-white/10 transition-colors cursor-pointer",
|
|
6040
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
6041
|
+
}
|
|
6042
|
+
)
|
|
6043
|
+
] }),
|
|
6044
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 flex items-center justify-between gap-4 my-auto min-h-0 w-full", children: [
|
|
6045
|
+
images.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6046
|
+
"button",
|
|
6047
|
+
{
|
|
6048
|
+
type: "button",
|
|
6049
|
+
onClick: handlePrev,
|
|
6050
|
+
"aria-label": "Previous image",
|
|
6051
|
+
className: "p-3 rounded-full text-white/80 hover:text-white hover:bg-white/10 transition-colors cursor-pointer z-10 shrink-0",
|
|
6052
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) })
|
|
6053
|
+
}
|
|
6054
|
+
),
|
|
6055
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex flex-col items-center justify-center h-full min-h-0 px-2 select-none", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6056
|
+
"img",
|
|
6057
|
+
{
|
|
6058
|
+
src: activeImage.src,
|
|
6059
|
+
alt: activeImage.alt || `Image ${selectedIndex + 1}`,
|
|
6060
|
+
className: "max-h-[70vh] max-w-full object-contain rounded-kj-md shadow-2xl transition-transform"
|
|
6061
|
+
}
|
|
6062
|
+
) }),
|
|
6063
|
+
images.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6064
|
+
"button",
|
|
6065
|
+
{
|
|
6066
|
+
type: "button",
|
|
6067
|
+
onClick: handleNext,
|
|
6068
|
+
"aria-label": "Next image",
|
|
6069
|
+
className: "p-3 rounded-full text-white/80 hover:text-white hover:bg-white/10 transition-colors cursor-pointer z-10 shrink-0",
|
|
6070
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) })
|
|
6071
|
+
}
|
|
6072
|
+
)
|
|
6073
|
+
] }),
|
|
6074
|
+
(activeImage.title || activeImage.caption) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center text-center text-white pb-2 z-10", children: [
|
|
6075
|
+
activeImage.title && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-semibold text-white", children: activeImage.title }),
|
|
6076
|
+
activeImage.caption && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-white/70 max-w-lg mt-0.5", children: activeImage.caption })
|
|
6077
|
+
] })
|
|
6078
|
+
]
|
|
6079
|
+
}
|
|
6080
|
+
)
|
|
6081
|
+
] });
|
|
6082
|
+
}
|
|
2499
6083
|
|
|
2500
6084
|
exports.Accordion = Accordion;
|
|
2501
6085
|
exports.AccordionContent = AccordionContent;
|
|
2502
6086
|
exports.AccordionItem = AccordionItem;
|
|
2503
6087
|
exports.AccordionTrigger = AccordionTrigger;
|
|
2504
6088
|
exports.Alert = Alert;
|
|
6089
|
+
exports.AppShell = AppShell;
|
|
6090
|
+
exports.AppShellBanner = AppShellBanner;
|
|
6091
|
+
exports.AppShellFooter = AppShellFooter;
|
|
6092
|
+
exports.AppShellHeader = AppShellHeader;
|
|
6093
|
+
exports.AppShellMain = AppShellMain;
|
|
2505
6094
|
exports.Avatar = Avatar;
|
|
2506
6095
|
exports.AvatarGroup = AvatarGroup;
|
|
2507
6096
|
exports.Badge = Badge;
|
|
6097
|
+
exports.BlogCard = BlogCard;
|
|
2508
6098
|
exports.BottomNavigation = BottomNavigation;
|
|
2509
6099
|
exports.BottomSheet = BottomSheet;
|
|
2510
6100
|
exports.BottomSheetContent = BottomSheetContent;
|
|
@@ -2516,6 +6106,7 @@ exports.Breadcrumb = Breadcrumb;
|
|
|
2516
6106
|
exports.BreadcrumbItem = BreadcrumbItem;
|
|
2517
6107
|
exports.BreadcrumbSeparator = BreadcrumbSeparator;
|
|
2518
6108
|
exports.Button = Button;
|
|
6109
|
+
exports.Calendar = Calendar;
|
|
2519
6110
|
exports.Card = Card;
|
|
2520
6111
|
exports.CardContent = CardContent;
|
|
2521
6112
|
exports.CardDescription = CardDescription;
|
|
@@ -2525,10 +6116,20 @@ exports.CardTitle = CardTitle;
|
|
|
2525
6116
|
exports.Checkbox = Checkbox;
|
|
2526
6117
|
exports.CheckboxField = CheckboxField;
|
|
2527
6118
|
exports.CodeBlock = CodeBlock;
|
|
6119
|
+
exports.ColorPicker = ColorPicker;
|
|
6120
|
+
exports.ColorPickerField = ColorPickerField;
|
|
6121
|
+
exports.ColorPickerSwatch = ColorPickerSwatch;
|
|
6122
|
+
exports.Combobox = Combobox;
|
|
6123
|
+
exports.ComboboxField = ComboboxField;
|
|
2528
6124
|
exports.CommandPalette = CommandPalette;
|
|
2529
6125
|
exports.ConfirmDialog = ConfirmDialog;
|
|
6126
|
+
exports.DEFAULT_COLOR_SWATCHES = DEFAULT_COLOR_SWATCHES;
|
|
2530
6127
|
exports.DashboardShell = DashboardShell;
|
|
2531
6128
|
exports.DataTable = DataTable;
|
|
6129
|
+
exports.DatePicker = DatePicker;
|
|
6130
|
+
exports.DatePickerField = DatePickerField;
|
|
6131
|
+
exports.DateRangePicker = DateRangePicker;
|
|
6132
|
+
exports.DateRangePickerField = DateRangePickerField;
|
|
2532
6133
|
exports.DetailPageLayout = DetailPageLayout;
|
|
2533
6134
|
exports.Drawer = Drawer;
|
|
2534
6135
|
exports.DropdownMenu = DropdownMenu;
|
|
@@ -2536,12 +6137,19 @@ exports.DropdownMenuContent = DropdownMenuContent;
|
|
|
2536
6137
|
exports.DropdownMenuItem = DropdownMenuItem;
|
|
2537
6138
|
exports.DropdownMenuSeparator = DropdownMenuSeparator;
|
|
2538
6139
|
exports.DropdownMenuTrigger = DropdownMenuTrigger;
|
|
6140
|
+
exports.Dropzone = Dropzone;
|
|
2539
6141
|
exports.EmptyState = EmptyState;
|
|
2540
6142
|
exports.ErrorState = ErrorState;
|
|
2541
6143
|
exports.Fab = Fab;
|
|
2542
6144
|
exports.Field = Field;
|
|
6145
|
+
exports.FileUpload = FileUpload;
|
|
6146
|
+
exports.FileUploadField = FileUploadField;
|
|
2543
6147
|
exports.FormField = FormField;
|
|
2544
6148
|
exports.Hint = Hint;
|
|
6149
|
+
exports.ImageGallery = ImageGallery;
|
|
6150
|
+
exports.InboxContent = InboxContent;
|
|
6151
|
+
exports.InboxPopover = InboxPopover;
|
|
6152
|
+
exports.InboxTrigger = InboxTrigger;
|
|
2545
6153
|
exports.Input = Input;
|
|
2546
6154
|
exports.Kbd = Kbd;
|
|
2547
6155
|
exports.Label = Label;
|
|
@@ -2550,22 +6158,42 @@ exports.Modal = Modal;
|
|
|
2550
6158
|
exports.ModalActions = ModalActions;
|
|
2551
6159
|
exports.ModalDescription = ModalDescription;
|
|
2552
6160
|
exports.ModalTitle = ModalTitle;
|
|
6161
|
+
exports.NotificationItem = NotificationItem;
|
|
2553
6162
|
exports.PageHeader = PageHeader;
|
|
2554
6163
|
exports.Pagination = Pagination;
|
|
2555
6164
|
exports.Popover = Popover;
|
|
2556
6165
|
exports.PopoverContent = PopoverContent;
|
|
2557
6166
|
exports.PopoverTrigger = PopoverTrigger;
|
|
6167
|
+
exports.PricingCard = PricingCard;
|
|
2558
6168
|
exports.Progress = Progress;
|
|
6169
|
+
exports.ProgressRing = ProgressRing;
|
|
6170
|
+
exports.ProgressRingField = ProgressRingField;
|
|
6171
|
+
exports.ProjectCard = ProjectCard;
|
|
2559
6172
|
exports.Radio = Radio;
|
|
6173
|
+
exports.RangeCalendar = RangeCalendar;
|
|
6174
|
+
exports.Rating = Rating;
|
|
6175
|
+
exports.RatingField = RatingField;
|
|
6176
|
+
exports.RatingSummary = RatingSummary;
|
|
6177
|
+
exports.SectionHeader = SectionHeader;
|
|
2560
6178
|
exports.Segmented = Segmented;
|
|
2561
6179
|
exports.Select = Select;
|
|
2562
6180
|
exports.SelectField = SelectField;
|
|
6181
|
+
exports.Separator = Separator;
|
|
2563
6182
|
exports.SettingsLayout = SettingsLayout;
|
|
2564
6183
|
exports.SidebarNav = SidebarNav;
|
|
2565
6184
|
exports.Skeleton = Skeleton;
|
|
2566
6185
|
exports.Slider = Slider;
|
|
2567
6186
|
exports.Spinner = Spinner;
|
|
2568
6187
|
exports.Stat = Stat;
|
|
6188
|
+
exports.Stepper = Stepper;
|
|
6189
|
+
exports.StepperContent = StepperContent;
|
|
6190
|
+
exports.StepperDescription = StepperDescription;
|
|
6191
|
+
exports.StepperIndicator = StepperIndicator;
|
|
6192
|
+
exports.StepperItem = StepperItem;
|
|
6193
|
+
exports.StepperList = StepperList;
|
|
6194
|
+
exports.StepperSeparator = StepperSeparator;
|
|
6195
|
+
exports.StepperTitle = StepperTitle;
|
|
6196
|
+
exports.StepperTrigger = StepperTrigger;
|
|
2569
6197
|
exports.Switch = Switch;
|
|
2570
6198
|
exports.Table = Table;
|
|
2571
6199
|
exports.TableBody = TableBody;
|
|
@@ -2581,12 +6209,28 @@ exports.TabsList = TabsList;
|
|
|
2581
6209
|
exports.TabsTrigger = TabsTrigger;
|
|
2582
6210
|
exports.TextField = TextField;
|
|
2583
6211
|
exports.Textarea = Textarea;
|
|
6212
|
+
exports.Timeline = Timeline;
|
|
6213
|
+
exports.TimelineConnector = TimelineConnector;
|
|
6214
|
+
exports.TimelineContent = TimelineContent;
|
|
6215
|
+
exports.TimelineDot = TimelineDot;
|
|
6216
|
+
exports.TimelineItem = TimelineItem;
|
|
6217
|
+
exports.TimelineSeparator = TimelineSeparator;
|
|
6218
|
+
exports.TimelineTime = TimelineTime;
|
|
6219
|
+
exports.TimelineTitle = TimelineTitle;
|
|
2584
6220
|
exports.ToastProvider = ToastProvider;
|
|
6221
|
+
exports.ToggleGroup = ToggleGroup;
|
|
2585
6222
|
exports.Tooltip = Tooltip;
|
|
2586
6223
|
exports.badgeVariants = badgeVariants;
|
|
2587
6224
|
exports.buttonVariants = buttonVariants;
|
|
2588
6225
|
exports.cn = cn;
|
|
6226
|
+
exports.formatRelativeTime = formatRelativeTime;
|
|
6227
|
+
exports.hexToHsl = hexToHsl;
|
|
6228
|
+
exports.hslToHex = hslToHex;
|
|
6229
|
+
exports.isValidHex = isValidHex;
|
|
6230
|
+
exports.normalizeHex = normalizeHex;
|
|
2589
6231
|
exports.sliderThumbCSS = sliderThumbCSS;
|
|
6232
|
+
exports.useInboxState = useInboxState;
|
|
6233
|
+
exports.useStepper = useStepper;
|
|
2590
6234
|
exports.useToast = useToast;
|
|
2591
6235
|
//# sourceMappingURL=index.cjs.map
|
|
2592
6236
|
//# sourceMappingURL=index.cjs.map
|