@kjaniec-dev/ui 0.6.0 → 0.7.1

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.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { twMerge } from 'tailwind-merge';
3
- import * as React17 from 'react';
3
+ import * as React18 from 'react';
4
4
  import { cva } from 'class-variance-authority';
5
- import { jsxs, jsx } from 'react/jsx-runtime';
5
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
6
 
7
7
  // src/lib/cn.ts
8
8
  function cn(...inputs) {
@@ -38,7 +38,7 @@ var buttonVariants = cva(
38
38
  defaultVariants: { variant: "primary", size: "md" }
39
39
  }
40
40
  );
41
- var Button = React17.forwardRef(
41
+ var Button = React18.forwardRef(
42
42
  ({ className, variant, size, loading, leadingIcon, trailingIcon, children, disabled, ...props }, ref) => {
43
43
  return /* @__PURE__ */ jsxs(
44
44
  "button",
@@ -85,7 +85,7 @@ var badgeVariants = cva(
85
85
  defaultVariants: { variant: "neutral" }
86
86
  }
87
87
  );
88
- var Badge = React17.forwardRef(
88
+ var Badge = React18.forwardRef(
89
89
  ({ className, variant, dot, children, ...props }, ref) => /* @__PURE__ */ jsxs("span", { ref, className: cn(badgeVariants({ variant }), className), ...props, children: [
90
90
  dot && /* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-current", "aria-hidden": true }),
91
91
  children
@@ -112,7 +112,7 @@ var iconColor = {
112
112
  warning: "text-warning",
113
113
  danger: "text-danger"
114
114
  };
115
- var Alert = React17.forwardRef(
115
+ var Alert = React18.forwardRef(
116
116
  ({ className, variant = "info", icon, title, children, ...props }, ref) => /* @__PURE__ */ jsxs("div", { ref, role: "alert", className: cn(alertVariants({ variant }), className), ...props, children: [
117
117
  icon && /* @__PURE__ */ jsx("span", { className: cn("shrink-0 mt-0.5 [&_svg]:h-[1.15rem] [&_svg]:w-[1.15rem]", iconColor[variant ?? "info"]), children: icon }),
118
118
  /* @__PURE__ */ jsxs("div", { className: "text-foreground", children: [
@@ -122,7 +122,7 @@ var Alert = React17.forwardRef(
122
122
  ] })
123
123
  );
124
124
  Alert.displayName = "Alert";
125
- var Spinner = React17.forwardRef(
125
+ var Spinner = React18.forwardRef(
126
126
  ({ className, size = 24, style, ...props }, ref) => /* @__PURE__ */ jsx(
127
127
  "span",
128
128
  {
@@ -139,7 +139,7 @@ var Spinner = React17.forwardRef(
139
139
  )
140
140
  );
141
141
  Spinner.displayName = "Spinner";
142
- var Progress = React17.forwardRef(
142
+ var Progress = React18.forwardRef(
143
143
  ({ className, value = 0, tone = "primary", barClassName, ...props }, ref) => {
144
144
  const pct = Math.max(0, Math.min(100, value));
145
145
  return /* @__PURE__ */ jsx(
@@ -169,8 +169,55 @@ var Progress = React17.forwardRef(
169
169
  }
170
170
  );
171
171
  Progress.displayName = "Progress";
172
+ var Label = React18.forwardRef(
173
+ ({ className, required, children, ...props }, ref) => /* @__PURE__ */ jsxs("label", { ref, className: cn("text-[0.8rem] font-semibold text-foreground", className), ...props, children: [
174
+ children,
175
+ required && /* @__PURE__ */ jsx("span", { className: "text-danger", children: " *" })
176
+ ] })
177
+ );
178
+ Label.displayName = "Label";
179
+ var Hint = React18.forwardRef(
180
+ ({ className, error, ...props }, ref) => /* @__PURE__ */ jsx(
181
+ "span",
182
+ {
183
+ ref,
184
+ className: cn("text-[0.76rem]", error ? "text-danger" : "text-muted-foreground", className),
185
+ ...props
186
+ }
187
+ )
188
+ );
189
+ Hint.displayName = "Hint";
190
+ var Field = React18.forwardRef(
191
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex flex-col gap-1.5", className), ...props })
192
+ );
193
+ Field.displayName = "Field";
194
+ var FormField = React18.forwardRef(
195
+ ({ className, label, hint, error, required, children, ...props }, ref) => {
196
+ const id = React18.useId();
197
+ const hintId = `${id}-hint`;
198
+ const errorId = `${id}-error`;
199
+ const child = React18.Children.only(children);
200
+ const clonedChild = React18.cloneElement(child, {
201
+ id: child.props.id ?? id,
202
+ "aria-describedby": cn(
203
+ hint && hintId,
204
+ error && errorId,
205
+ child.props["aria-describedby"]
206
+ ) || void 0,
207
+ "aria-invalid": error ? "true" : void 0,
208
+ required: child.props.required ?? required
209
+ });
210
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex flex-col gap-1.5 w-full", className), ...props, children: [
211
+ /* @__PURE__ */ jsx(Label, { htmlFor: id, required, children: label }),
212
+ clonedChild,
213
+ hint && !error && /* @__PURE__ */ jsx(Hint, { id: hintId, children: hint }),
214
+ error && /* @__PURE__ */ jsx(Hint, { id: errorId, error: true, children: error })
215
+ ] });
216
+ }
217
+ );
218
+ FormField.displayName = "FormField";
172
219
  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";
173
- var Input = React17.forwardRef(
220
+ var Input = React18.forwardRef(
174
221
  ({ className, error, leadingIcon, style, ...props }, ref) => {
175
222
  const field = /* @__PURE__ */ jsx(
176
223
  "input",
@@ -195,7 +242,7 @@ var Input = React17.forwardRef(
195
242
  }
196
243
  );
197
244
  Input.displayName = "Input";
198
- var Textarea = React17.forwardRef(
245
+ var Textarea = React18.forwardRef(
199
246
  ({ className, error, ...props }, ref) => /* @__PURE__ */ jsx(
200
247
  "textarea",
201
248
  {
@@ -212,30 +259,14 @@ var Textarea = React17.forwardRef(
212
259
  )
213
260
  );
214
261
  Textarea.displayName = "Textarea";
215
- var Label = React17.forwardRef(
216
- ({ className, required, children, ...props }, ref) => /* @__PURE__ */ jsxs("label", { ref, className: cn("text-[0.8rem] font-semibold text-foreground", className), ...props, children: [
217
- children,
218
- required && /* @__PURE__ */ jsx("span", { className: "text-danger", children: " *" })
219
- ] })
220
- );
221
- Label.displayName = "Label";
222
- var Hint = React17.forwardRef(
223
- ({ className, error, ...props }, ref) => /* @__PURE__ */ jsx(
224
- "span",
225
- {
226
- ref,
227
- className: cn("text-[0.76rem]", error ? "text-danger" : "text-muted-foreground", className),
228
- ...props
229
- }
230
- )
231
- );
232
- Hint.displayName = "Hint";
233
- var Field = React17.forwardRef(
234
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex flex-col gap-1.5", className), ...props })
262
+ var TextField = React18.forwardRef(
263
+ ({ label, hint, error, required, className, ...props }, ref) => {
264
+ return /* @__PURE__ */ jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsx(Input, { ref, error: !!error, ...props }) });
265
+ }
235
266
  );
236
- Field.displayName = "Field";
267
+ TextField.displayName = "TextField";
237
268
  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";
238
- var Select = React17.forwardRef(
269
+ var Select = React18.forwardRef(
239
270
  ({ className, error, style, children, ...props }, ref) => /* @__PURE__ */ jsx(
240
271
  "select",
241
272
  {
@@ -263,9 +294,15 @@ var Select = React17.forwardRef(
263
294
  )
264
295
  );
265
296
  Select.displayName = "Select";
266
- var Checkbox = React17.forwardRef(
297
+ var SelectField = React18.forwardRef(
298
+ ({ label, hint, error, required, className, children, ...props }, ref) => {
299
+ return /* @__PURE__ */ jsx(FormField, { label, hint, error, required, className, children: /* @__PURE__ */ jsx(Select, { ref, error: !!error, ...props, children }) });
300
+ }
301
+ );
302
+ SelectField.displayName = "SelectField";
303
+ var Checkbox = React18.forwardRef(
267
304
  ({ className, label, id, ...props }, ref) => {
268
- const autoId = React17.useId();
305
+ const autoId = React18.useId();
269
306
  const inputId = id ?? autoId;
270
307
  return /* @__PURE__ */ jsxs("label", { htmlFor: inputId, className: cn("inline-flex items-center gap-2.5 cursor-pointer text-sm select-none", className), children: [
271
308
  /* @__PURE__ */ jsx("input", { ref, id: inputId, type: "checkbox", className: "peer sr-only", ...props }),
@@ -275,9 +312,9 @@ var Checkbox = React17.forwardRef(
275
312
  }
276
313
  );
277
314
  Checkbox.displayName = "Checkbox";
278
- var Radio = React17.forwardRef(
315
+ var Radio = React18.forwardRef(
279
316
  ({ className, label, id, ...props }, ref) => {
280
- const autoId = React17.useId();
317
+ const autoId = React18.useId();
281
318
  const inputId = id ?? autoId;
282
319
  return /* @__PURE__ */ jsxs("label", { htmlFor: inputId, className: cn("inline-flex items-center gap-2.5 cursor-pointer text-sm select-none", className), children: [
283
320
  /* @__PURE__ */ jsx("input", { ref, id: inputId, type: "radio", className: "peer sr-only", ...props }),
@@ -287,9 +324,32 @@ var Radio = React17.forwardRef(
287
324
  }
288
325
  );
289
326
  Radio.displayName = "Radio";
290
- var Switch = React17.forwardRef(
327
+ var CheckboxField = React18.forwardRef(
328
+ ({ label, hint, error, className, ...props }, ref) => {
329
+ const id = React18.useId();
330
+ const hintId = `${id}-hint`;
331
+ const errorId = `${id}-error`;
332
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 w-full", className), children: [
333
+ /* @__PURE__ */ jsx(
334
+ Checkbox,
335
+ {
336
+ ref,
337
+ id,
338
+ label,
339
+ "aria-describedby": cn(hint && hintId, error && errorId) || void 0,
340
+ "aria-invalid": error ? "true" : void 0,
341
+ ...props
342
+ }
343
+ ),
344
+ hint && !error && /* @__PURE__ */ jsx(Hint, { id: hintId, className: "pl-[1.8rem]", children: hint }),
345
+ error && /* @__PURE__ */ jsx(Hint, { id: errorId, error: true, className: "pl-[1.8rem]", children: error })
346
+ ] });
347
+ }
348
+ );
349
+ CheckboxField.displayName = "CheckboxField";
350
+ var Switch = React18.forwardRef(
291
351
  ({ className, label, id, ...props }, ref) => {
292
- const autoId = React17.useId();
352
+ const autoId = React18.useId();
293
353
  const inputId = id ?? autoId;
294
354
  return /* @__PURE__ */ jsxs("label", { htmlFor: inputId, className: cn("inline-flex items-center gap-2.5 cursor-pointer text-sm select-none", className), children: [
295
355
  /* @__PURE__ */ jsx("input", { ref, id: inputId, type: "checkbox", role: "switch", className: "peer sr-only", ...props }),
@@ -299,7 +359,7 @@ var Switch = React17.forwardRef(
299
359
  }
300
360
  );
301
361
  Switch.displayName = "Switch";
302
- var Slider = React17.forwardRef(
362
+ var Slider = React18.forwardRef(
303
363
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
304
364
  "input",
305
365
  {
@@ -352,7 +412,7 @@ function Segmented({
352
412
  }
353
413
  );
354
414
  }
355
- var Card = React17.forwardRef(
415
+ var Card = React18.forwardRef(
356
416
  ({ as: Tag = "div", className, elevated, interactive, ...props }, ref) => /* @__PURE__ */ jsx(
357
417
  Tag,
358
418
  {
@@ -368,23 +428,23 @@ var Card = React17.forwardRef(
368
428
  )
369
429
  );
370
430
  Card.displayName = "Card";
371
- var CardHeader = React17.forwardRef(
431
+ var CardHeader = React18.forwardRef(
372
432
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-[1.35rem] flex flex-col gap-1", className), ...props })
373
433
  );
374
434
  CardHeader.displayName = "CardHeader";
375
- var CardTitle = React17.forwardRef(
435
+ var CardTitle = React18.forwardRef(
376
436
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("h3", { ref, className: cn("m-0 text-base font-bold tracking-[-0.01em]", className), ...props })
377
437
  );
378
438
  CardTitle.displayName = "CardTitle";
379
- var CardDescription = React17.forwardRef(
439
+ var CardDescription = React18.forwardRef(
380
440
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("p", { ref, className: cn("m-0 text-[0.85rem] text-muted-foreground", className), ...props })
381
441
  );
382
442
  CardDescription.displayName = "CardDescription";
383
- var CardContent = React17.forwardRef(
443
+ var CardContent = React18.forwardRef(
384
444
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("px-[1.35rem] pb-[1.35rem]", className), ...props })
385
445
  );
386
446
  CardContent.displayName = "CardContent";
387
- var CardFooter = React17.forwardRef(
447
+ var CardFooter = React18.forwardRef(
388
448
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
389
449
  "div",
390
450
  {
@@ -395,7 +455,7 @@ var CardFooter = React17.forwardRef(
395
455
  )
396
456
  );
397
457
  CardFooter.displayName = "CardFooter";
398
- var Stat = React17.forwardRef(
458
+ var Stat = React18.forwardRef(
399
459
  ({ className, label, value, delta, trend, ...props }, ref) => /* @__PURE__ */ jsxs(Card, { ref, className: cn("p-[1.35rem] flex flex-col gap-2", className), ...props, children: [
400
460
  /* @__PURE__ */ jsx("span", { className: "text-[0.78rem] font-semibold uppercase tracking-[0.05em] text-muted-foreground", children: label }),
401
461
  /* @__PURE__ */ jsx("span", { className: "text-[2rem] font-bold tracking-[-0.03em] tabular-nums leading-none", children: value }),
@@ -435,7 +495,7 @@ var avatarVariants = cva(
435
495
  defaultVariants: { size: "md", tone: "secondary" }
436
496
  }
437
497
  );
438
- var Avatar = React17.forwardRef(
498
+ var Avatar = React18.forwardRef(
439
499
  ({ className, size, tone, src, alt, status, children, ...props }, ref) => {
440
500
  const node = /* @__PURE__ */ jsx("span", { ref, className: cn(avatarVariants({ size, tone }), "overflow-hidden", className), ...props, children: src ? /* @__PURE__ */ jsx("img", { src, alt, className: "h-full w-full object-cover" }) : children });
441
501
  if (!status) return node;
@@ -446,20 +506,20 @@ var Avatar = React17.forwardRef(
446
506
  }
447
507
  );
448
508
  Avatar.displayName = "Avatar";
449
- var AvatarGroup = React17.forwardRef(
509
+ var AvatarGroup = React18.forwardRef(
450
510
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex [&>*:not(:first-child)]:-ml-2.5", className), ...props })
451
511
  );
452
512
  AvatarGroup.displayName = "AvatarGroup";
453
- var TabsContext = React17.createContext(null);
513
+ var TabsContext = React18.createContext(null);
454
514
  function useTabs() {
455
- const ctx = React17.useContext(TabsContext);
515
+ const ctx = React18.useContext(TabsContext);
456
516
  if (!ctx) throw new Error("Tabs.* must be used within <Tabs>");
457
517
  return ctx;
458
518
  }
459
519
  function Tabs({ value, defaultValue, onValueChange, className, children, ...props }) {
460
- const [internal, setInternal] = React17.useState(defaultValue ?? "");
520
+ const [internal, setInternal] = React18.useState(defaultValue ?? "");
461
521
  const current = value ?? internal;
462
- const setValue = React17.useCallback(
522
+ const setValue = React18.useCallback(
463
523
  (v) => {
464
524
  if (value === void 0) setInternal(v);
465
525
  onValueChange?.(v);
@@ -468,7 +528,7 @@ function Tabs({ value, defaultValue, onValueChange, className, children, ...prop
468
528
  );
469
529
  return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { value: current, setValue }, children: /* @__PURE__ */ jsx("div", { className, ...props, children }) });
470
530
  }
471
- var TabsList = React17.forwardRef(
531
+ var TabsList = React18.forwardRef(
472
532
  ({ className, onKeyDown, ...props }, ref) => {
473
533
  const handleKeyDown = (e) => {
474
534
  const container = e.currentTarget;
@@ -505,14 +565,17 @@ var TabsList = React17.forwardRef(
505
565
  ref,
506
566
  role: "tablist",
507
567
  onKeyDown: handleKeyDown,
508
- className: cn("flex gap-1 border-b border-border", className),
568
+ className: cn(
569
+ "flex gap-1 border-b border-border overflow-x-auto whitespace-nowrap [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
570
+ className
571
+ ),
509
572
  ...props
510
573
  }
511
574
  );
512
575
  }
513
576
  );
514
577
  TabsList.displayName = "TabsList";
515
- var TabsTrigger = React17.forwardRef(
578
+ var TabsTrigger = React18.forwardRef(
516
579
  ({ className, value, children, ...props }, ref) => {
517
580
  const { value: current, setValue } = useTabs();
518
581
  const active = current === value;
@@ -528,7 +591,7 @@ var TabsTrigger = React17.forwardRef(
528
591
  tabIndex: active ? 0 : -1,
529
592
  onClick: () => setValue(value),
530
593
  className: cn(
531
- "relative px-[0.9rem] py-2.5 text-sm font-semibold cursor-pointer transition-colors duration-150 outline-none",
594
+ "relative px-[0.9rem] py-2.5 text-sm font-semibold cursor-pointer transition-colors duration-150 outline-none shrink-0 whitespace-nowrap",
532
595
  "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:rounded-sm",
533
596
  "after:content-[''] after:absolute after:left-[0.9rem] after:right-[0.9rem] after:-bottom-px after:h-0.5 after:rounded-sm after:transition-colors",
534
597
  active ? "text-foreground after:bg-primary" : "text-muted-foreground hover:text-foreground after:bg-transparent",
@@ -541,7 +604,7 @@ var TabsTrigger = React17.forwardRef(
541
604
  }
542
605
  );
543
606
  TabsTrigger.displayName = "TabsTrigger";
544
- var TabsContent = React17.forwardRef(
607
+ var TabsContent = React18.forwardRef(
545
608
  ({ className, value, ...props }, ref) => {
546
609
  const { value: current } = useTabs();
547
610
  const active = current === value;
@@ -561,10 +624,10 @@ var TabsContent = React17.forwardRef(
561
624
  }
562
625
  );
563
626
  TabsContent.displayName = "TabsContent";
564
- var AccordionContext = React17.createContext(null);
627
+ var AccordionContext = React18.createContext(null);
565
628
  function Accordion({ type = "single", defaultValue = [], className, children, ...props }) {
566
- const [open, setOpen] = React17.useState(defaultValue);
567
- const toggle = React17.useCallback(
629
+ const [open, setOpen] = React18.useState(defaultValue);
630
+ const toggle = React18.useCallback(
568
631
  (v) => {
569
632
  setOpen((prev) => {
570
633
  const isOpen = prev.includes(v);
@@ -576,15 +639,15 @@ function Accordion({ type = "single", defaultValue = [], className, children, ..
576
639
  );
577
640
  return /* @__PURE__ */ jsx(AccordionContext.Provider, { value: { open, toggle }, children: /* @__PURE__ */ jsx("div", { className: cn("border border-border rounded-kj-lg overflow-hidden", className), ...props, children }) });
578
641
  }
579
- var ItemContext = React17.createContext("");
580
- var AccordionItem = React17.forwardRef(
642
+ var ItemContext = React18.createContext("");
643
+ var AccordionItem = React18.forwardRef(
581
644
  ({ className, value, ...props }, ref) => /* @__PURE__ */ jsx(ItemContext.Provider, { value, children: /* @__PURE__ */ jsx("div", { ref, className: cn("border-t border-border first:border-t-0", className), ...props }) })
582
645
  );
583
646
  AccordionItem.displayName = "AccordionItem";
584
- var AccordionTrigger = React17.forwardRef(
647
+ var AccordionTrigger = React18.forwardRef(
585
648
  ({ className, children, ...props }, ref) => {
586
- const ctx = React17.useContext(AccordionContext);
587
- const value = React17.useContext(ItemContext);
649
+ const ctx = React18.useContext(AccordionContext);
650
+ const value = React18.useContext(ItemContext);
588
651
  const isOpen = ctx.open.includes(value);
589
652
  return /* @__PURE__ */ jsxs(
590
653
  "button",
@@ -621,10 +684,10 @@ var AccordionTrigger = React17.forwardRef(
621
684
  }
622
685
  );
623
686
  AccordionTrigger.displayName = "AccordionTrigger";
624
- var AccordionContent = React17.forwardRef(
687
+ var AccordionContent = React18.forwardRef(
625
688
  ({ className, children, ...props }, ref) => {
626
- const ctx = React17.useContext(AccordionContext);
627
- const value = React17.useContext(ItemContext);
689
+ const ctx = React18.useContext(AccordionContext);
690
+ const value = React18.useContext(ItemContext);
628
691
  const isOpen = ctx.open.includes(value);
629
692
  return /* @__PURE__ */ jsx(
630
693
  "div",
@@ -638,11 +701,11 @@ var AccordionContent = React17.forwardRef(
638
701
  }
639
702
  );
640
703
  AccordionContent.displayName = "AccordionContent";
641
- var MenuContext = React17.createContext(null);
704
+ var MenuContext = React18.createContext(null);
642
705
  function DropdownMenu({ children, className }) {
643
- const [open, setOpen] = React17.useState(false);
644
- const ref = React17.useRef(null);
645
- React17.useEffect(() => {
706
+ const [open, setOpen] = React18.useState(false);
707
+ const ref = React18.useRef(null);
708
+ React18.useEffect(() => {
646
709
  if (!open) return;
647
710
  const onDoc = (e) => {
648
711
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -657,11 +720,11 @@ function DropdownMenu({ children, className }) {
657
720
  }, [open]);
658
721
  return /* @__PURE__ */ jsx(MenuContext.Provider, { value: { open, setOpen }, children: /* @__PURE__ */ jsx("div", { ref, className: cn("relative inline-block", className), children }) });
659
722
  }
660
- var DropdownMenuTrigger = React17.forwardRef(({ onClick, asChild, ...props }, ref) => {
661
- const ctx = React17.useContext(MenuContext);
723
+ var DropdownMenuTrigger = React18.forwardRef(({ onClick, asChild, ...props }, ref) => {
724
+ const ctx = React18.useContext(MenuContext);
662
725
  if (asChild) {
663
- const child = React17.Children.only(props.children);
664
- return React17.cloneElement(child, {
726
+ const child = React18.Children.only(props.children);
727
+ return React18.cloneElement(child, {
665
728
  ref,
666
729
  ...props,
667
730
  ...child.props,
@@ -691,9 +754,9 @@ var DropdownMenuTrigger = React17.forwardRef(({ onClick, asChild, ...props }, re
691
754
  });
692
755
  DropdownMenuTrigger.displayName = "DropdownMenuTrigger";
693
756
  function DropdownMenuContent({ className, align = "start", children, ...props }) {
694
- const ctx = React17.useContext(MenuContext);
695
- const ref = React17.useRef(null);
696
- React17.useEffect(() => {
757
+ const ctx = React18.useContext(MenuContext);
758
+ const ref = React18.useRef(null);
759
+ React18.useEffect(() => {
697
760
  if (!ctx.open) return;
698
761
  const container = ref.current;
699
762
  if (container) {
@@ -740,9 +803,9 @@ function DropdownMenuContent({ className, align = "start", children, ...props })
740
803
  }
741
804
  );
742
805
  }
743
- var DropdownMenuItem = React17.forwardRef(
806
+ var DropdownMenuItem = React18.forwardRef(
744
807
  ({ className, danger, icon, children, onClick, ...props }, ref) => {
745
- const ctx = React17.useContext(MenuContext);
808
+ const ctx = React18.useContext(MenuContext);
746
809
  return /* @__PURE__ */ jsxs(
747
810
  "button",
748
811
  {
@@ -772,11 +835,11 @@ DropdownMenuItem.displayName = "DropdownMenuItem";
772
835
  function DropdownMenuSeparator({ className }) {
773
836
  return /* @__PURE__ */ jsx("div", { className: cn("h-px bg-border my-1.5", className), role: "separator" });
774
837
  }
775
- var Breadcrumb = React17.forwardRef(
838
+ var Breadcrumb = React18.forwardRef(
776
839
  ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx("nav", { ref, "aria-label": "Breadcrumb", className: cn("flex items-center gap-1.5 text-[0.85rem] text-muted-foreground", className), ...props, children })
777
840
  );
778
841
  Breadcrumb.displayName = "Breadcrumb";
779
- var BreadcrumbItem = React17.forwardRef(
842
+ var BreadcrumbItem = React18.forwardRef(
780
843
  ({ className, current, children, ...props }, ref) => {
781
844
  if (current) {
782
845
  return /* @__PURE__ */ jsx("span", { "aria-current": "page", className: cn("text-foreground font-semibold", className), children });
@@ -823,27 +886,99 @@ function Pagination({ page, pageCount, onPageChange, className }) {
823
886
  /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Next", disabled: page >= pageCount, onClick: () => onPageChange(page + 1), children: /* @__PURE__ */ jsx(Chevron, { dir: "right" }) })
824
887
  ] });
825
888
  }
826
- var TableWrap = React17.forwardRef(
827
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("border border-border rounded-kj-lg overflow-hidden", className), ...props })
889
+ var BottomNavigation = React18.forwardRef(
890
+ ({ className, items, showLabels = "always", fixed = true, ...props }, ref) => {
891
+ return /* @__PURE__ */ jsx(
892
+ "nav",
893
+ {
894
+ ref,
895
+ className: cn(
896
+ "bg-surface/90 border-t border-border flex items-center justify-around px-4 pt-2 pb-[calc(0.75rem+env(safe-area-inset-bottom,0))] shadow-kj-lg",
897
+ fixed ? "fixed bottom-0 left-0 right-0 z-40 backdrop-blur-md" : "relative w-full",
898
+ className
899
+ ),
900
+ ...props,
901
+ children: items.map((item) => {
902
+ const isActive = item.active;
903
+ const showLabel = showLabels !== "never" && (showLabels === "always" || isActive);
904
+ const content = /* @__PURE__ */ jsxs("span", { className: "flex flex-col items-center justify-center gap-1 w-full relative", children: [
905
+ /* @__PURE__ */ jsxs(
906
+ "span",
907
+ {
908
+ className: cn(
909
+ "relative flex items-center justify-center p-1 rounded-full transition-all duration-200",
910
+ isActive ? "text-primary scale-110" : "text-muted-foreground group-hover:text-foreground group-active:scale-95"
911
+ ),
912
+ children: [
913
+ item.icon,
914
+ item.badge !== void 0 && item.badge !== null && /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1.5 min-w-[16px] h-[16px] px-1 rounded-full bg-primary text-primary-foreground text-[9px] font-bold flex items-center justify-center ring-2 ring-surface", children: item.badge })
915
+ ]
916
+ }
917
+ ),
918
+ /* @__PURE__ */ jsx(
919
+ "span",
920
+ {
921
+ className: cn(
922
+ "text-[10px] font-semibold tracking-wide transition-all duration-200 select-none",
923
+ showLabel ? "opacity-100 scale-100 h-auto" : "opacity-0 scale-75 h-0 overflow-hidden",
924
+ isActive ? "text-primary font-bold" : "text-muted-foreground group-hover:text-foreground"
925
+ ),
926
+ children: item.label
927
+ }
928
+ ),
929
+ isActive && /* @__PURE__ */ jsx("span", { className: "absolute -bottom-1.5 w-1 h-1 rounded-full bg-primary animate-fade-in" })
930
+ ] });
931
+ const itemClass = "group flex-1 flex flex-col items-center justify-center py-1 cursor-pointer transition-all duration-150 relative focus:outline-none";
932
+ if (item.href) {
933
+ return /* @__PURE__ */ jsx(
934
+ "a",
935
+ {
936
+ href: item.href,
937
+ className: itemClass,
938
+ "aria-current": isActive ? "page" : void 0,
939
+ children: content
940
+ },
941
+ item.id
942
+ );
943
+ }
944
+ return /* @__PURE__ */ jsx(
945
+ "button",
946
+ {
947
+ type: "button",
948
+ onClick: item.onClick,
949
+ className: itemClass,
950
+ "aria-pressed": isActive,
951
+ children: content
952
+ },
953
+ item.id
954
+ );
955
+ })
956
+ }
957
+ );
958
+ }
959
+ );
960
+ BottomNavigation.displayName = "BottomNavigation";
961
+ var TableWrap = React18.forwardRef(
962
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("border border-border rounded-kj-lg overflow-x-auto w-full", className), ...props })
828
963
  );
829
964
  TableWrap.displayName = "TableWrap";
830
- var Table = React17.forwardRef(
965
+ var Table = React18.forwardRef(
831
966
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("table", { ref, className: cn("w-full border-collapse text-[0.85rem]", className), ...props })
832
967
  );
833
968
  Table.displayName = "Table";
834
- var TableHeader = React17.forwardRef(
969
+ var TableHeader = React18.forwardRef(
835
970
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { ref, className, ...props })
836
971
  );
837
972
  TableHeader.displayName = "TableHeader";
838
- var TableBody = React17.forwardRef(
973
+ var TableBody = React18.forwardRef(
839
974
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("tbody", { ref, className, ...props })
840
975
  );
841
976
  TableBody.displayName = "TableBody";
842
- var TableRow = React17.forwardRef(
977
+ var TableRow = React18.forwardRef(
843
978
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("tr", { ref, className: cn("transition-colors hover:bg-muted/50", className), ...props })
844
979
  );
845
980
  TableRow.displayName = "TableRow";
846
- var TableHead = React17.forwardRef(
981
+ var TableHead = React18.forwardRef(
847
982
  ({ className, numeric, ...props }, ref) => /* @__PURE__ */ jsx(
848
983
  "th",
849
984
  {
@@ -858,7 +993,7 @@ var TableHead = React17.forwardRef(
858
993
  )
859
994
  );
860
995
  TableHead.displayName = "TableHead";
861
- var TableCell = React17.forwardRef(
996
+ var TableCell = React18.forwardRef(
862
997
  ({ className, numeric, ...props }, ref) => /* @__PURE__ */ jsx(
863
998
  "td",
864
999
  {
@@ -891,13 +1026,13 @@ function Tooltip({ content, children, className }) {
891
1026
  )
892
1027
  ] });
893
1028
  }
894
- var ModalContext = React17.createContext(null);
1029
+ var ModalContext = React18.createContext(null);
895
1030
  function Modal({ open, onClose, children, width = 440, className, showClose = true }) {
896
- const titleId = React17.useId();
897
- const descId = React17.useId();
898
- const containerRef = React17.useRef(null);
899
- const lastActiveElement = React17.useRef(null);
900
- React17.useEffect(() => {
1031
+ const titleId = React18.useId();
1032
+ const descId = React18.useId();
1033
+ const containerRef = React18.useRef(null);
1034
+ const lastActiveElement = React18.useRef(null);
1035
+ React18.useEffect(() => {
901
1036
  if (!open) {
902
1037
  if (lastActiveElement.current) {
903
1038
  lastActiveElement.current.focus();
@@ -999,19 +1134,19 @@ function Modal({ open, onClose, children, width = 440, className, showClose = tr
999
1134
  );
1000
1135
  }
1001
1136
  function ModalTitle({ className, id, ...props }) {
1002
- const ctx = React17.useContext(ModalContext);
1137
+ const ctx = React18.useContext(ModalContext);
1003
1138
  return /* @__PURE__ */ jsx("h3", { id: id ?? ctx?.titleId, className: cn("m-0 mb-2 text-[1.15rem] font-bold tracking-[-0.01em]", className), ...props });
1004
1139
  }
1005
1140
  function ModalDescription({ className, id, ...props }) {
1006
- const ctx = React17.useContext(ModalContext);
1141
+ const ctx = React18.useContext(ModalContext);
1007
1142
  return /* @__PURE__ */ jsx("p", { id: id ?? ctx?.descId, className: cn("m-0 text-[0.9rem] text-muted-foreground", className), ...props });
1008
1143
  }
1009
1144
  function ModalActions({ className, ...props }) {
1010
1145
  return /* @__PURE__ */ jsx("div", { className: cn("flex gap-2.5 justify-end mt-6", className), ...props });
1011
1146
  }
1012
- var ToastContext = React17.createContext(null);
1147
+ var ToastContext = React18.createContext(null);
1013
1148
  function useToast() {
1014
- const ctx = React17.useContext(ToastContext);
1149
+ const ctx = React18.useContext(ToastContext);
1015
1150
  if (!ctx) throw new Error("useToast must be used within <ToastProvider>");
1016
1151
  return ctx;
1017
1152
  }
@@ -1032,13 +1167,13 @@ var toneBorder = {
1032
1167
  danger: "border-l-danger"
1033
1168
  };
1034
1169
  function ToastProvider({ children }) {
1035
- const [items, setItems] = React17.useState([]);
1036
- const idRef = React17.useRef(0);
1037
- const remove = React17.useCallback((id) => {
1170
+ const [items, setItems] = React18.useState([]);
1171
+ const idRef = React18.useRef(0);
1172
+ const remove = React18.useCallback((id) => {
1038
1173
  setItems((prev) => prev.map((t) => t.id === id ? { ...t, leaving: true } : t));
1039
1174
  setTimeout(() => setItems((prev) => prev.filter((t) => t.id !== id)), 250);
1040
1175
  }, []);
1041
- const toast = React17.useCallback(
1176
+ const toast = React18.useCallback(
1042
1177
  ({ message, tone = "default", duration = 3200 }) => {
1043
1178
  const id = ++idRef.current;
1044
1179
  setItems((prev) => [...prev, { id, message, tone, duration }]);
@@ -1068,7 +1203,7 @@ function ToastProvider({ children }) {
1068
1203
  )) })
1069
1204
  ] });
1070
1205
  }
1071
- var PageHeader = React17.forwardRef(
1206
+ var PageHeader = React18.forwardRef(
1072
1207
  ({ eyebrow, title, description, actions }, ref) => /* @__PURE__ */ jsx("header", { ref, className: "py-12 md:py-16", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6 md:flex-row md:items-end md:justify-between", children: [
1073
1208
  /* @__PURE__ */ jsxs("div", { className: "space-y-3 max-w-2xl", children: [
1074
1209
  eyebrow && /* @__PURE__ */ jsx("p", { className: "font-mono text-xs font-bold uppercase tracking-[0.2em] text-primary", children: eyebrow }),
@@ -1079,7 +1214,7 @@ var PageHeader = React17.forwardRef(
1079
1214
  ] }) })
1080
1215
  );
1081
1216
  PageHeader.displayName = "PageHeader";
1082
- var EmptyState = React17.forwardRef(
1217
+ var EmptyState = React18.forwardRef(
1083
1218
  ({ className, icon, title, description, action, ...props }, ref) => /* @__PURE__ */ jsxs(
1084
1219
  "div",
1085
1220
  {
@@ -1099,7 +1234,7 @@ var EmptyState = React17.forwardRef(
1099
1234
  )
1100
1235
  );
1101
1236
  EmptyState.displayName = "EmptyState";
1102
- var MetricCard = React17.forwardRef(
1237
+ var MetricCard = React18.forwardRef(
1103
1238
  ({ className, title, value, trend, trendDirection = "neutral", description, icon, ...props }, ref) => {
1104
1239
  const trendColor = {
1105
1240
  up: "text-success bg-success-surface border-success/20",
@@ -1129,54 +1264,171 @@ function DataTable({
1129
1264
  emptyTitle = "No data available",
1130
1265
  emptyDescription = "There are no records to display at this time.",
1131
1266
  emptyAction,
1267
+ getRowKey,
1268
+ onRowClick,
1269
+ toolbar,
1270
+ pagination,
1271
+ selectedRows,
1272
+ onSelectionChange,
1273
+ sortBy,
1274
+ sortDirection,
1275
+ onSort,
1132
1276
  ...props
1133
1277
  }) {
1134
- return /* @__PURE__ */ jsxs(TableWrap, { className: cn("relative overflow-hidden", className), ...props, children: [
1135
- /* @__PURE__ */ jsxs(Table, { children: [
1136
- /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsx(TableRow, { children: columns.map((col, idx) => /* @__PURE__ */ jsx(TableHead, { className: col.className, children: col.header }, idx)) }) }),
1137
- /* @__PURE__ */ jsx(TableBody, { children: loading && data.length === 0 ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: columns.length, className: "h-64 text-center", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-3", children: [
1138
- /* @__PURE__ */ jsx(Spinner, { size: 32 }),
1139
- /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Loading dataset..." })
1140
- ] }) }) }) : error ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: columns.length, className: "p-8", children: /* @__PURE__ */ jsx(Alert, { variant: "danger", title: "Error loading data", children: error }) }) }) : data.length === 0 ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: columns.length, className: "p-0", children: /* @__PURE__ */ jsx(
1141
- EmptyState,
1142
- {
1143
- title: emptyTitle,
1144
- description: emptyDescription,
1145
- action: emptyAction,
1146
- className: "border-none bg-transparent rounded-none py-16"
1147
- }
1148
- ) }) }) : data.map((row, rowIdx) => /* @__PURE__ */ jsx(TableRow, { children: columns.map((col, colIdx) => /* @__PURE__ */ jsx(TableCell, { className: col.className, children: col.accessor(row) }, colIdx)) }, rowIdx)) })
1278
+ const getRowId = React18.useCallback(
1279
+ (row, index) => getRowKey ? getRowKey(row, index) : index,
1280
+ [getRowKey]
1281
+ );
1282
+ const isSelectionActive = selectedRows !== void 0 && onSelectionChange !== void 0;
1283
+ const allSelected = React18.useMemo(() => {
1284
+ if (!isSelectionActive || data.length === 0) return false;
1285
+ return data.every((row, idx) => selectedRows.has(getRowId(row, idx)));
1286
+ }, [isSelectionActive, data, selectedRows, getRowId]);
1287
+ const someSelected = React18.useMemo(() => {
1288
+ if (!isSelectionActive || data.length === 0) return false;
1289
+ const selectedCount = data.filter((row, idx) => selectedRows.has(getRowId(row, idx))).length;
1290
+ return selectedCount > 0 && selectedCount < data.length;
1291
+ }, [isSelectionActive, data, selectedRows, getRowId]);
1292
+ const headerCheckboxRef = React18.useRef(null);
1293
+ React18.useEffect(() => {
1294
+ if (headerCheckboxRef.current) {
1295
+ headerCheckboxRef.current.indeterminate = someSelected;
1296
+ }
1297
+ }, [someSelected]);
1298
+ const handleSelectAll = (e) => {
1299
+ if (!onSelectionChange) return;
1300
+ const checked = e.target.checked;
1301
+ const next = new Set(selectedRows);
1302
+ data.forEach((row, idx) => {
1303
+ const id = getRowId(row, idx);
1304
+ if (checked) {
1305
+ next.add(id);
1306
+ } else {
1307
+ next.delete(id);
1308
+ }
1309
+ });
1310
+ onSelectionChange(next);
1311
+ };
1312
+ const handleSelectRow = (row, idx, checked) => {
1313
+ if (!onSelectionChange || !selectedRows) return;
1314
+ const id = getRowId(row, idx);
1315
+ const next = new Set(selectedRows);
1316
+ if (checked) {
1317
+ next.add(id);
1318
+ } else {
1319
+ next.delete(id);
1320
+ }
1321
+ onSelectionChange(next);
1322
+ };
1323
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-4 w-full", className), children: [
1324
+ toolbar && /* @__PURE__ */ jsx("div", { className: "flex flex-col sm:flex-row items-stretch sm:items-center justify-between gap-3", children: toolbar }),
1325
+ /* @__PURE__ */ jsxs(TableWrap, { className: "relative overflow-hidden", ...props, children: [
1326
+ /* @__PURE__ */ jsxs(Table, { children: [
1327
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
1328
+ isSelectionActive && /* @__PURE__ */ jsx(TableHead, { className: "w-12 px-4 text-center", children: /* @__PURE__ */ jsx("div", { className: "inline-flex items-center justify-center", children: /* @__PURE__ */ jsx(
1329
+ "input",
1330
+ {
1331
+ type: "checkbox",
1332
+ ref: headerCheckboxRef,
1333
+ checked: allSelected,
1334
+ onChange: handleSelectAll,
1335
+ "aria-label": "Select all rows",
1336
+ className: "h-4 w-4 rounded border-input text-primary focus:ring-ring"
1337
+ }
1338
+ ) }) }),
1339
+ columns.map((col, idx) => {
1340
+ const alignClass = {
1341
+ left: "text-left",
1342
+ center: "text-center",
1343
+ right: "text-right"
1344
+ }[col.align || "left"];
1345
+ const isSortable = col.sortable && onSort && col.sortKey;
1346
+ const isSortedActive = sortBy && col.sortKey === sortBy;
1347
+ return /* @__PURE__ */ jsx(
1348
+ TableHead,
1349
+ {
1350
+ className: cn(
1351
+ alignClass,
1352
+ isSortable && "cursor-pointer select-none hover:bg-muted/30 transition-colors",
1353
+ col.className
1354
+ ),
1355
+ onClick: () => {
1356
+ if (!isSortable || !col.sortKey) return;
1357
+ const nextDirection = isSortedActive && sortDirection === "asc" ? "desc" : "asc";
1358
+ onSort(col.sortKey, nextDirection);
1359
+ },
1360
+ children: /* @__PURE__ */ jsxs("div", { className: cn("inline-flex items-center gap-1.5", alignClass === "text-right" && "justify-end w-full"), children: [
1361
+ /* @__PURE__ */ jsx("span", { children: col.header }),
1362
+ isSortable && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground shrink-0 select-none", children: isSortedActive ? sortDirection === "asc" ? "\u25B2" : "\u25BC" : "\u21C5" })
1363
+ ] })
1364
+ },
1365
+ idx
1366
+ );
1367
+ })
1368
+ ] }) }),
1369
+ /* @__PURE__ */ jsx(TableBody, { children: loading && data.length === 0 ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: columns.length + (isSelectionActive ? 1 : 0), className: "h-64 text-center", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-3", children: [
1370
+ /* @__PURE__ */ jsx(Spinner, { size: 32 }),
1371
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Loading dataset..." })
1372
+ ] }) }) }) : error ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: columns.length + (isSelectionActive ? 1 : 0), className: "p-8", children: /* @__PURE__ */ jsx(Alert, { variant: "danger", title: "Error loading data", children: error }) }) }) : data.length === 0 ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: columns.length + (isSelectionActive ? 1 : 0), className: "p-0", children: /* @__PURE__ */ jsx(
1373
+ EmptyState,
1374
+ {
1375
+ title: emptyTitle,
1376
+ description: emptyDescription,
1377
+ action: emptyAction,
1378
+ className: "border-none bg-transparent rounded-none py-16"
1379
+ }
1380
+ ) }) }) : data.map((row, rowIdx) => {
1381
+ const rowKey = getRowId(row, rowIdx);
1382
+ const isSelected = isSelectionActive && selectedRows.has(rowKey);
1383
+ return /* @__PURE__ */ jsxs(
1384
+ TableRow,
1385
+ {
1386
+ onClick: () => onRowClick && onRowClick(row),
1387
+ className: cn(
1388
+ onRowClick && "cursor-pointer hover:bg-muted/40 transition-colors",
1389
+ isSelected && "bg-primary/5 hover:bg-primary/10"
1390
+ ),
1391
+ children: [
1392
+ isSelectionActive && /* @__PURE__ */ jsx(
1393
+ TableCell,
1394
+ {
1395
+ className: "w-12 px-4 text-center",
1396
+ onClick: (e) => {
1397
+ e.stopPropagation();
1398
+ },
1399
+ children: /* @__PURE__ */ jsx("div", { className: "inline-flex items-center justify-center", children: /* @__PURE__ */ jsx(
1400
+ "input",
1401
+ {
1402
+ type: "checkbox",
1403
+ checked: isSelected,
1404
+ onChange: (e) => handleSelectRow(row, rowIdx, e.target.checked),
1405
+ "aria-label": `Select row ${rowIdx + 1}`,
1406
+ className: "h-4 w-4 rounded border-input text-primary focus:ring-ring"
1407
+ }
1408
+ ) })
1409
+ }
1410
+ ),
1411
+ columns.map((col, colIdx) => {
1412
+ const alignClass = {
1413
+ left: "text-left",
1414
+ center: "text-center",
1415
+ right: "text-right"
1416
+ }[col.align || "left"];
1417
+ return /* @__PURE__ */ jsx(TableCell, { className: cn(alignClass, col.className), children: col.accessor(row) }, colIdx);
1418
+ })
1419
+ ]
1420
+ },
1421
+ rowKey
1422
+ );
1423
+ }) })
1424
+ ] }),
1425
+ loading && data.length > 0 && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-background/50 backdrop-blur-[1px] grid place-items-center z-10 transition-opacity duration-150", children: /* @__PURE__ */ jsx(Spinner, { size: 36 }) })
1149
1426
  ] }),
1150
- loading && data.length > 0 && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-background/50 backdrop-blur-[1px] grid place-items-center z-10 transition-opacity duration-150", children: /* @__PURE__ */ jsx(Spinner, { size: 36 }) })
1427
+ pagination && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end w-full", children: pagination })
1151
1428
  ] });
1152
1429
  }
1153
1430
  DataTable.displayName = "DataTable";
1154
- var FormField = React17.forwardRef(
1155
- ({ className, label, hint, error, required, children, ...props }, ref) => {
1156
- const id = React17.useId();
1157
- const hintId = `${id}-hint`;
1158
- const errorId = `${id}-error`;
1159
- const child = React17.Children.only(children);
1160
- const clonedChild = React17.cloneElement(child, {
1161
- id: child.props.id ?? id,
1162
- "aria-describedby": cn(
1163
- hint && hintId,
1164
- error && errorId,
1165
- child.props["aria-describedby"]
1166
- ) || void 0,
1167
- "aria-invalid": error ? "true" : void 0,
1168
- required: child.props.required ?? required
1169
- });
1170
- return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex flex-col gap-1.5 w-full", className), ...props, children: [
1171
- /* @__PURE__ */ jsx(Label, { htmlFor: id, required, children: label }),
1172
- clonedChild,
1173
- hint && !error && /* @__PURE__ */ jsx(Hint, { id: hintId, children: hint }),
1174
- error && /* @__PURE__ */ jsx(Hint, { id: errorId, error: true, children: error })
1175
- ] });
1176
- }
1177
- );
1178
- FormField.displayName = "FormField";
1179
- var ErrorState = React17.forwardRef(
1431
+ var ErrorState = React18.forwardRef(
1180
1432
  ({ className, title = "Wyst\u0105pi\u0142 b\u0142\u0105d", message, onRetry, retryLabel = "Spr\xF3buj ponownie", ...props }, ref) => /* @__PURE__ */ jsxs(
1181
1433
  "div",
1182
1434
  {
@@ -1196,7 +1448,7 @@ var ErrorState = React17.forwardRef(
1196
1448
  )
1197
1449
  );
1198
1450
  ErrorState.displayName = "ErrorState";
1199
- var Skeleton = React17.forwardRef(
1451
+ var Skeleton = React18.forwardRef(
1200
1452
  ({ className, variant = "rectangular", width, height, style, ...props }, ref) => /* @__PURE__ */ jsx(
1201
1453
  "div",
1202
1454
  {
@@ -1218,28 +1470,550 @@ var Skeleton = React17.forwardRef(
1218
1470
  )
1219
1471
  );
1220
1472
  Skeleton.displayName = "Skeleton";
1221
- var DashboardShell = React17.forwardRef(
1222
- ({ className, sidebar, topbar, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1473
+ var DashboardShell = React18.forwardRef(
1474
+ ({
1475
+ className,
1476
+ sidebar,
1477
+ topbar,
1478
+ children,
1479
+ sidebarWidth = "md:w-64",
1480
+ contentWidth = "default",
1481
+ stickyTopbar = true,
1482
+ mobileSidebar,
1483
+ ...props
1484
+ }, ref) => {
1485
+ const [mobileOpen, setMobileOpen] = React18.useState(false);
1486
+ const contentWidthClass = {
1487
+ default: "max-w-7xl w-full mx-auto",
1488
+ wide: "max-w-screen-2xl w-full mx-auto",
1489
+ full: "max-w-none w-full"
1490
+ }[contentWidth];
1491
+ return /* @__PURE__ */ jsxs(
1492
+ "div",
1493
+ {
1494
+ ref,
1495
+ className: cn(
1496
+ "min-h-screen bg-canvas text-foreground flex flex-col md:flex-row",
1497
+ className
1498
+ ),
1499
+ ...props,
1500
+ children: [
1501
+ sidebar && /* @__PURE__ */ jsx(
1502
+ "aside",
1503
+ {
1504
+ className: cn(
1505
+ "border-r border-border bg-surface shrink-0 z-20",
1506
+ mobileSidebar ? "hidden md:flex" : "w-full md:flex",
1507
+ sidebarWidth
1508
+ ),
1509
+ children: /* @__PURE__ */ jsx("div", { className: cn("sticky top-0 w-full flex flex-col", mobileSidebar ? "h-screen" : "h-auto md:h-screen"), children: sidebar })
1510
+ }
1511
+ ),
1512
+ mobileSidebar && mobileOpen && /* @__PURE__ */ jsx(
1513
+ "div",
1514
+ {
1515
+ onClick: () => setMobileOpen(false),
1516
+ className: "fixed inset-0 z-50 md:hidden bg-[color-mix(in_oklch,#09090b_45%,transparent)] backdrop-blur-[2px] transition-opacity duration-300",
1517
+ children: /* @__PURE__ */ jsxs(
1518
+ "aside",
1519
+ {
1520
+ onClick: (e) => e.stopPropagation(),
1521
+ className: "w-72 h-full bg-surface border-r border-border flex flex-col shadow-kj-lg",
1522
+ children: [
1523
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border-b border-border", children: [
1524
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-bold uppercase tracking-wider text-muted-foreground", children: "Navigation" }),
1525
+ /* @__PURE__ */ jsx(
1526
+ "button",
1527
+ {
1528
+ type: "button",
1529
+ onClick: () => setMobileOpen(false),
1530
+ className: "p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors cursor-pointer",
1531
+ children: /* @__PURE__ */ jsx("svg", { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
1532
+ }
1533
+ )
1534
+ ] }),
1535
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: mobileSidebar })
1536
+ ]
1537
+ }
1538
+ )
1539
+ }
1540
+ ),
1541
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-w-0", children: [
1542
+ topbar && /* @__PURE__ */ jsxs(
1543
+ "header",
1544
+ {
1545
+ className: cn(
1546
+ "h-14 border-b border-border bg-surface flex items-center px-6 z-10 shrink-0 gap-4",
1547
+ stickyTopbar && "sticky top-0"
1548
+ ),
1549
+ children: [
1550
+ mobileSidebar && /* @__PURE__ */ jsx(
1551
+ "button",
1552
+ {
1553
+ type: "button",
1554
+ onClick: () => setMobileOpen(true),
1555
+ className: "md:hidden p-1.5 -ml-1.5 rounded-kj-sm text-muted-foreground hover:text-foreground hover:bg-muted transition-colors cursor-pointer",
1556
+ "aria-label": "Open navigation",
1557
+ children: /* @__PURE__ */ jsxs("svg", { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
1558
+ /* @__PURE__ */ jsx("line", { x1: "3", y1: "12", x2: "21", y2: "12" }),
1559
+ /* @__PURE__ */ jsx("line", { x1: "3", y1: "6", x2: "21", y2: "6" }),
1560
+ /* @__PURE__ */ jsx("line", { x1: "3", y1: "18", x2: "21", y2: "18" })
1561
+ ] })
1562
+ }
1563
+ ),
1564
+ topbar
1565
+ ]
1566
+ }
1567
+ ),
1568
+ /* @__PURE__ */ jsx("main", { className: cn("flex-1 p-6 md:p-8", contentWidthClass), children })
1569
+ ] })
1570
+ ]
1571
+ }
1572
+ );
1573
+ }
1574
+ );
1575
+ DashboardShell.displayName = "DashboardShell";
1576
+ var SettingsLayout = React18.forwardRef(
1577
+ ({ className, sidebar, children, title, description, ...props }, ref) => {
1578
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("space-y-6 w-full", className), ...props, children: [
1579
+ (title || description) && /* @__PURE__ */ jsxs("div", { className: "border-b border-border pb-4", children: [
1580
+ title && /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight text-foreground", children: title }),
1581
+ description && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: description })
1582
+ ] }),
1583
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col lg:flex-row gap-8", children: [
1584
+ /* @__PURE__ */ jsx("aside", { className: "lg:w-1/4 shrink-0", children: /* @__PURE__ */ jsx("nav", { className: "flex flex-row lg:flex-col gap-1 overflow-x-auto lg:overflow-x-visible pb-2 lg:pb-0", children: sidebar }) }),
1585
+ /* @__PURE__ */ jsx("div", { className: "flex-1 max-w-3xl", children })
1586
+ ] })
1587
+ ] });
1588
+ }
1589
+ );
1590
+ SettingsLayout.displayName = "SettingsLayout";
1591
+ var DetailPageLayout = React18.forwardRef(
1592
+ ({ className, title, description, backHref, backLabel = "Back", onBackClick, actions, aside, children, ...props }, ref) => {
1593
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("space-y-6 w-full", className), ...props, children: [
1594
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
1595
+ (backHref || onBackClick) && /* @__PURE__ */ jsx("div", { children: backHref ? /* @__PURE__ */ jsxs(
1596
+ "a",
1597
+ {
1598
+ href: backHref,
1599
+ className: cn(
1600
+ buttonVariants({ variant: "ghost", size: "sm" }),
1601
+ "-ml-3 h-8 text-muted-foreground hover:text-foreground inline-flex items-center gap-1.5"
1602
+ ),
1603
+ children: [
1604
+ /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", className: "h-4 w-4", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 19.5 8.25 12l7.5-7.5" }) }),
1605
+ backLabel
1606
+ ]
1607
+ }
1608
+ ) : /* @__PURE__ */ jsxs(
1609
+ Button,
1610
+ {
1611
+ variant: "ghost",
1612
+ size: "sm",
1613
+ className: "-ml-3 h-8 text-muted-foreground hover:text-foreground",
1614
+ onClick: onBackClick,
1615
+ children: [
1616
+ /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", className: "h-4 w-4 mr-1.5", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 19.5 8.25 12l7.5-7.5" }) }),
1617
+ backLabel
1618
+ ]
1619
+ }
1620
+ ) }),
1621
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col md:flex-row md:items-center md:justify-between gap-4", children: [
1622
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1623
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight text-foreground", children: title }),
1624
+ description && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description })
1625
+ ] }),
1626
+ actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 shrink-0", children: actions })
1627
+ ] })
1628
+ ] }),
1629
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-8 items-start", children: [
1630
+ /* @__PURE__ */ jsx("div", { className: cn("space-y-6", aside ? "lg:col-span-2" : "lg:col-span-3"), children }),
1631
+ aside && /* @__PURE__ */ jsx("aside", { className: "space-y-6 lg:col-span-1 bg-surface border border-border rounded-kj-xl p-6 shadow-kj-xs", children: aside })
1632
+ ] })
1633
+ ] });
1634
+ }
1635
+ );
1636
+ DetailPageLayout.displayName = "DetailPageLayout";
1637
+ var TableToolbar = React18.forwardRef(
1638
+ ({ className, searchQuery, onSearchChange, searchPlaceholder = "Search...", actions, filters, ...props }, ref) => {
1639
+ return /* @__PURE__ */ jsxs(
1640
+ "div",
1641
+ {
1642
+ ref,
1643
+ className: cn(
1644
+ "flex flex-col sm:flex-row items-stretch sm:items-center justify-between gap-3 w-full pb-1",
1645
+ className
1646
+ ),
1647
+ ...props,
1648
+ children: [
1649
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col sm:flex-row items-stretch sm:items-center gap-2 max-w-xl", children: [
1650
+ onSearchChange && /* @__PURE__ */ jsx(
1651
+ Input,
1652
+ {
1653
+ type: "search",
1654
+ placeholder: searchPlaceholder,
1655
+ value: searchQuery,
1656
+ onChange: (e) => onSearchChange(e.target.value),
1657
+ className: "sm:w-64",
1658
+ leadingIcon: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", className: "h-4 w-4", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" }) })
1659
+ }
1660
+ ),
1661
+ filters && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: filters })
1662
+ ] }),
1663
+ actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 shrink-0 justify-end", children: actions })
1664
+ ]
1665
+ }
1666
+ );
1667
+ }
1668
+ );
1669
+ TableToolbar.displayName = "TableToolbar";
1670
+ function ConfirmDialog({
1671
+ open,
1672
+ onClose,
1673
+ onConfirm,
1674
+ title,
1675
+ description,
1676
+ confirmLabel = "Confirm",
1677
+ cancelLabel = "Cancel",
1678
+ tone = "primary",
1679
+ loading = false
1680
+ }) {
1681
+ const toneButtonVariant = {
1682
+ danger: "danger",
1683
+ primary: "primary",
1684
+ success: "secondary"
1685
+ // standard secondary in our system is teal (success-aligned)
1686
+ }[tone];
1687
+ return /* @__PURE__ */ jsxs(Modal, { open, onClose, width: 400, showClose: !loading, children: [
1688
+ /* @__PURE__ */ jsx(ModalTitle, { children: title }),
1689
+ /* @__PURE__ */ jsx(ModalDescription, { children: description }),
1690
+ /* @__PURE__ */ jsxs(ModalActions, { children: [
1691
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onClose, disabled: loading, children: cancelLabel }),
1692
+ /* @__PURE__ */ jsx(Button, { variant: toneButtonVariant, onClick: onConfirm, loading, children: confirmLabel })
1693
+ ] })
1694
+ ] });
1695
+ }
1696
+ ConfirmDialog.displayName = "ConfirmDialog";
1697
+ function Drawer({
1698
+ open,
1699
+ onClose,
1700
+ children,
1701
+ title,
1702
+ description,
1703
+ width = "max-w-md",
1704
+ side = "right"
1705
+ }) {
1706
+ const containerRef = React18.useRef(null);
1707
+ const lastActiveElement = React18.useRef(null);
1708
+ React18.useEffect(() => {
1709
+ if (!open) {
1710
+ if (lastActiveElement.current) {
1711
+ lastActiveElement.current.focus();
1712
+ lastActiveElement.current = null;
1713
+ }
1714
+ return;
1715
+ }
1716
+ lastActiveElement.current = document.activeElement;
1717
+ const container = containerRef.current;
1718
+ if (container) {
1719
+ const focusables = container.querySelectorAll(
1720
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
1721
+ );
1722
+ if (focusables.length > 0) {
1723
+ setTimeout(() => focusables[0].focus(), 50);
1724
+ } else {
1725
+ container.focus();
1726
+ }
1727
+ }
1728
+ const handleKeyDown = (e) => {
1729
+ if (e.key === "Escape") {
1730
+ onClose();
1731
+ return;
1732
+ }
1733
+ if (e.key === "Tab") {
1734
+ const container2 = containerRef.current;
1735
+ if (!container2) return;
1736
+ const focusables = Array.from(
1737
+ container2.querySelectorAll(
1738
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
1739
+ )
1740
+ );
1741
+ if (focusables.length === 0) {
1742
+ e.preventDefault();
1743
+ return;
1744
+ }
1745
+ const first = focusables[0];
1746
+ const last = focusables[focusables.length - 1];
1747
+ if (e.shiftKey) {
1748
+ if (document.activeElement === first || document.activeElement === container2) {
1749
+ last.focus();
1750
+ e.preventDefault();
1751
+ }
1752
+ } else {
1753
+ if (document.activeElement === last) {
1754
+ first.focus();
1755
+ e.preventDefault();
1756
+ }
1757
+ }
1758
+ }
1759
+ };
1760
+ document.addEventListener("keydown", handleKeyDown);
1761
+ document.body.style.overflow = "hidden";
1762
+ return () => {
1763
+ document.removeEventListener("keydown", handleKeyDown);
1764
+ document.body.style.overflow = "";
1765
+ };
1766
+ }, [open, onClose]);
1767
+ const sideClasses = {
1768
+ right: cn(
1769
+ "right-0 h-full border-l",
1770
+ open ? "translate-x-0" : "translate-x-full"
1771
+ ),
1772
+ left: cn(
1773
+ "left-0 h-full border-r",
1774
+ open ? "translate-x-0" : "-translate-x-full"
1775
+ )
1776
+ }[side];
1777
+ return /* @__PURE__ */ jsx(
1223
1778
  "div",
1224
1779
  {
1225
- ref,
1780
+ onClick: (e) => e.target === e.currentTarget && onClose(),
1226
1781
  className: cn(
1227
- "min-h-screen bg-canvas text-foreground flex flex-col md:flex-row",
1228
- className
1782
+ "fixed inset-0 z-[100] transition-opacity duration-300 backdrop-blur-[2px]",
1783
+ "bg-[color-mix(in_oklch,#09090b_45%,transparent)]",
1784
+ open ? "opacity-100 pointer-events-auto" : "opacity-0 pointer-events-none"
1229
1785
  ),
1230
- ...props,
1231
- children: [
1232
- sidebar && /* @__PURE__ */ jsx("aside", { className: "w-full md:w-64 border-r border-border bg-surface shrink-0 z-20", children: /* @__PURE__ */ jsx("div", { className: "sticky top-0 h-auto md:h-screen flex flex-col", children: sidebar }) }),
1233
- /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-w-0", children: [
1234
- topbar && /* @__PURE__ */ jsx("header", { className: "sticky top-0 h-14 border-b border-border bg-surface flex items-center px-6 z-10 shrink-0", children: topbar }),
1235
- /* @__PURE__ */ jsx("main", { className: "flex-1 p-6 md:p-8 max-w-7xl w-full mx-auto", children })
1236
- ] })
1237
- ]
1786
+ children: /* @__PURE__ */ jsxs(
1787
+ "div",
1788
+ {
1789
+ ref: containerRef,
1790
+ role: "dialog",
1791
+ "aria-modal": "true",
1792
+ "aria-label": !title ? "Drawer" : void 0,
1793
+ "aria-labelledby": title ? "drawer-title" : void 0,
1794
+ "aria-describedby": description ? "drawer-description" : void 0,
1795
+ tabIndex: -1,
1796
+ className: cn(
1797
+ "fixed top-0 bottom-0 bg-surface border-border flex flex-col w-full shadow-kj-lg transition-transform duration-300 ease-spring outline-none",
1798
+ width,
1799
+ sideClasses
1800
+ ),
1801
+ children: [
1802
+ (title || description) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-6 border-b border-border", children: [
1803
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1804
+ title && /* @__PURE__ */ jsx("h2", { id: "drawer-title", className: "text-lg font-bold tracking-tight text-foreground", children: title }),
1805
+ description && /* @__PURE__ */ jsx("p", { id: "drawer-description", className: "text-xs text-muted-foreground", children: description })
1806
+ ] }),
1807
+ /* @__PURE__ */ jsx(
1808
+ "button",
1809
+ {
1810
+ type: "button",
1811
+ onClick: onClose,
1812
+ "aria-label": "Close",
1813
+ className: "p-1.5 rounded-kj-sm text-muted-foreground hover:text-foreground hover:bg-muted transition-colors cursor-pointer",
1814
+ children: /* @__PURE__ */ jsx("svg", { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
1815
+ }
1816
+ )
1817
+ ] }),
1818
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto p-6", children })
1819
+ ]
1820
+ }
1821
+ )
1238
1822
  }
1239
- )
1240
- );
1241
- DashboardShell.displayName = "DashboardShell";
1823
+ );
1824
+ }
1825
+ Drawer.displayName = "Drawer";
1826
+ function CommandPalette({ open, onClose, items, placeholder = "Type a command or search..." }) {
1827
+ const [search, setSearch] = React18.useState("");
1828
+ const [activeIndex, setActiveIndex] = React18.useState(0);
1829
+ const containerRef = React18.useRef(null);
1830
+ const listRef = React18.useRef(null);
1831
+ React18.useEffect(() => {
1832
+ if (open) {
1833
+ setSearch("");
1834
+ setActiveIndex(0);
1835
+ document.body.style.overflow = "hidden";
1836
+ } else {
1837
+ document.body.style.overflow = "";
1838
+ }
1839
+ }, [open]);
1840
+ const filteredItems = React18.useMemo(() => {
1841
+ if (!search) return items;
1842
+ const cleanSearch = search.toLowerCase();
1843
+ return items.filter(
1844
+ (item) => item.title.toLowerCase().includes(cleanSearch) || item.subtitle?.toLowerCase().includes(cleanSearch) || item.category?.toLowerCase().includes(cleanSearch)
1845
+ );
1846
+ }, [search, items]);
1847
+ React18.useEffect(() => {
1848
+ setActiveIndex(0);
1849
+ }, [filteredItems]);
1850
+ React18.useEffect(() => {
1851
+ if (!open) return;
1852
+ const handleKeyDown = (e) => {
1853
+ if (e.key === "Escape") {
1854
+ onClose();
1855
+ return;
1856
+ }
1857
+ if (e.key === "ArrowDown") {
1858
+ e.preventDefault();
1859
+ setActiveIndex((prev) => filteredItems.length === 0 ? 0 : (prev + 1) % filteredItems.length);
1860
+ } else if (e.key === "ArrowUp") {
1861
+ e.preventDefault();
1862
+ setActiveIndex((prev) => filteredItems.length === 0 ? 0 : (prev - 1 + filteredItems.length) % filteredItems.length);
1863
+ } else if (e.key === "Enter") {
1864
+ e.preventDefault();
1865
+ if (filteredItems[activeIndex]) {
1866
+ filteredItems[activeIndex].action();
1867
+ onClose();
1868
+ }
1869
+ }
1870
+ };
1871
+ document.addEventListener("keydown", handleKeyDown);
1872
+ return () => document.removeEventListener("keydown", handleKeyDown);
1873
+ }, [open, filteredItems, activeIndex, onClose]);
1874
+ React18.useEffect(() => {
1875
+ if (listRef.current) {
1876
+ const activeEl = listRef.current.children[activeIndex];
1877
+ if (activeEl) {
1878
+ activeEl.scrollIntoView({ block: "nearest" });
1879
+ }
1880
+ }
1881
+ }, [activeIndex]);
1882
+ if (!open) return null;
1883
+ const groups = {};
1884
+ filteredItems.forEach((item) => {
1885
+ const cat = item.category || "General";
1886
+ if (!groups[cat]) groups[cat] = [];
1887
+ groups[cat].push(item);
1888
+ });
1889
+ let absoluteItemIndex = 0;
1890
+ return /* @__PURE__ */ jsx(
1891
+ "div",
1892
+ {
1893
+ onClick: (e) => e.target === e.currentTarget && onClose(),
1894
+ className: "fixed inset-0 z-[100] grid place-items-start justify-center p-6 md:p-24 backdrop-blur-[3px] bg-[color-mix(in_oklch,#09090b_60%,transparent)]",
1895
+ children: /* @__PURE__ */ jsxs(
1896
+ "div",
1897
+ {
1898
+ ref: containerRef,
1899
+ className: "w-[95vw] max-w-lg bg-surface border border-border rounded-kj-xl shadow-kj-lg flex flex-col overflow-hidden max-h-[500px]",
1900
+ children: [
1901
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border-b border-border flex items-center gap-2", children: [
1902
+ /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", className: "h-5 w-5 text-muted-foreground shrink-0 ml-1", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" }) }),
1903
+ /* @__PURE__ */ jsx(
1904
+ "input",
1905
+ {
1906
+ type: "text",
1907
+ placeholder,
1908
+ value: search,
1909
+ onChange: (e) => setSearch(e.target.value),
1910
+ className: "flex-1 font-sans text-[0.95rem] bg-transparent text-foreground placeholder:text-muted-foreground outline-none border-none focus:ring-0",
1911
+ autoFocus: true
1912
+ }
1913
+ )
1914
+ ] }),
1915
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto p-2 min-h-[150px]", children: filteredItems.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "py-12 text-center text-sm text-muted-foreground", children: [
1916
+ 'No results found for "',
1917
+ search,
1918
+ '"'
1919
+ ] }) : /* @__PURE__ */ jsx("div", { ref: listRef, className: "space-y-4", children: Object.entries(groups).map(([cat, itemsInCat]) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1920
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-1 text-[0.65rem] font-bold uppercase tracking-wider text-muted-foreground", children: cat }),
1921
+ itemsInCat.map((item) => {
1922
+ const currentIdx = absoluteItemIndex++;
1923
+ const isActive = currentIdx === activeIndex;
1924
+ return /* @__PURE__ */ jsxs(
1925
+ "div",
1926
+ {
1927
+ onClick: () => {
1928
+ item.action();
1929
+ onClose();
1930
+ },
1931
+ className: cn(
1932
+ "flex items-center justify-between gap-3 px-3 py-2.5 rounded-kj-md cursor-pointer select-none transition-colors",
1933
+ isActive ? "bg-primary/10 text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
1934
+ ),
1935
+ children: [
1936
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
1937
+ item.icon && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground [&_svg]:h-[1.1rem] [&_svg]:w-[1.1rem]", children: item.icon }),
1938
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex flex-col", children: [
1939
+ /* @__PURE__ */ jsx("span", { className: cn("text-[0.85rem] font-semibold", isActive ? "text-primary" : "text-foreground"), children: item.title }),
1940
+ item.subtitle && /* @__PURE__ */ jsx("span", { className: "text-[0.75rem] text-muted-foreground truncate", children: item.subtitle })
1941
+ ] })
1942
+ ] }),
1943
+ item.shortcut && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: item.shortcut.map((sc, scIdx) => /* @__PURE__ */ jsx(
1944
+ "kbd",
1945
+ {
1946
+ className: "px-1.5 py-0.5 rounded border border-border bg-subtle text-[10px] font-mono leading-none shadow-kj-xs text-muted-foreground",
1947
+ children: sc
1948
+ },
1949
+ scIdx
1950
+ )) })
1951
+ ]
1952
+ },
1953
+ item.id
1954
+ );
1955
+ })
1956
+ ] }, cat)) }) }),
1957
+ /* @__PURE__ */ jsxs("div", { className: "px-4 py-2.5 border-t border-border bg-subtle flex items-center justify-between text-[11px] text-muted-foreground font-medium", children: [
1958
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1959
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
1960
+ /* @__PURE__ */ jsx("kbd", { className: "font-mono text-[9px] px-1 border rounded bg-surface", children: "\u2191\u2193" }),
1961
+ " Navigate"
1962
+ ] }),
1963
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
1964
+ /* @__PURE__ */ jsx("kbd", { className: "font-mono text-[9px] px-1 border rounded bg-surface", children: "Enter" }),
1965
+ " Select"
1966
+ ] })
1967
+ ] }),
1968
+ /* @__PURE__ */ jsxs("div", { children: [
1969
+ /* @__PURE__ */ jsx("kbd", { className: "font-mono text-[9px] px-1 border rounded bg-surface", children: "Esc" }),
1970
+ " Close"
1971
+ ] })
1972
+ ] })
1973
+ ]
1974
+ }
1975
+ )
1976
+ }
1977
+ );
1978
+ }
1979
+ CommandPalette.displayName = "CommandPalette";
1980
+ function SidebarNav({ className, groups, currentHref, ...props }) {
1981
+ return /* @__PURE__ */ jsx("div", { className: cn("space-y-6 py-4 px-3 w-full", className), ...props, children: groups.map((group, groupIdx) => /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1982
+ group.title && /* @__PURE__ */ jsx("h4", { className: "px-3 text-[10px] font-bold uppercase tracking-widest text-muted-foreground/85", children: group.title }),
1983
+ /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: group.items.map((item) => {
1984
+ const isActive = item.active || item.href && currentHref && currentHref === item.href;
1985
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
1986
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2.5 min-w-0", children: [
1987
+ item.icon && /* @__PURE__ */ jsx("span", { className: cn(
1988
+ "[&_svg]:h-[1.1rem] [&_svg]:w-[1.1rem] shrink-0",
1989
+ isActive ? "text-primary" : "text-muted-foreground group-hover:text-foreground"
1990
+ ), children: item.icon }),
1991
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: item.label })
1992
+ ] }),
1993
+ item.badge && /* @__PURE__ */ jsx("span", { className: "shrink-0 flex items-center justify-center", children: item.badge })
1994
+ ] });
1995
+ const itemClass = cn(
1996
+ "group flex items-center justify-between gap-3 px-3 py-2 rounded-kj-md text-[0.85rem] font-semibold select-none cursor-pointer transition-all duration-150",
1997
+ isActive ? "bg-primary/10 text-primary border-l-2 border-primary rounded-l-none pl-2.5" : "text-muted-foreground hover:bg-muted hover:text-foreground border-l-2 border-transparent"
1998
+ );
1999
+ if (item.href) {
2000
+ return /* @__PURE__ */ jsx("a", { href: item.href, className: itemClass, children: content }, item.id);
2001
+ }
2002
+ return /* @__PURE__ */ jsx(
2003
+ "button",
2004
+ {
2005
+ type: "button",
2006
+ onClick: item.onClick,
2007
+ className: itemClass,
2008
+ children: content
2009
+ },
2010
+ item.id
2011
+ );
2012
+ }) })
2013
+ ] }, groupIdx)) });
2014
+ }
2015
+ SidebarNav.displayName = "SidebarNav";
1242
2016
 
1243
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, Avatar, AvatarGroup, Badge, Breadcrumb, BreadcrumbItem, BreadcrumbSeparator, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, DashboardShell, DataTable, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, EmptyState, ErrorState, Field, FormField, Hint, Input, Label, MetricCard, Modal, ModalActions, ModalDescription, ModalTitle, PageHeader, Pagination, Progress, Radio, Segmented, Select, Skeleton, Slider, Spinner, Stat, Switch, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, TableWrap, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ToastProvider, Tooltip, badgeVariants, buttonVariants, cn, sliderThumbCSS, useToast };
2017
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, Avatar, AvatarGroup, Badge, BottomNavigation, Breadcrumb, BreadcrumbItem, BreadcrumbSeparator, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, CheckboxField, CommandPalette, ConfirmDialog, DashboardShell, DataTable, DetailPageLayout, Drawer, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, EmptyState, ErrorState, Field, FormField, Hint, Input, Label, MetricCard, Modal, ModalActions, ModalDescription, ModalTitle, PageHeader, Pagination, Progress, Radio, Segmented, Select, SelectField, SettingsLayout, SidebarNav, Skeleton, Slider, Spinner, Stat, Switch, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, TableToolbar, TableWrap, Tabs, TabsContent, TabsList, TabsTrigger, TextField, Textarea, ToastProvider, Tooltip, badgeVariants, buttonVariants, cn, sliderThumbCSS, useToast };
1244
2018
  //# sourceMappingURL=index.js.map
1245
2019
  //# sourceMappingURL=index.js.map