@turtleclub/ui 0.3.0 → 0.4.0-beta.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.
Files changed (190) hide show
  1. package/.turbo/turbo-build.log +46 -44
  2. package/CHANGELOG.md +12 -0
  3. package/dist/index.cjs +72 -43
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.js +8872 -7439
  6. package/dist/index.js.map +1 -1
  7. package/dist/styles.css +1 -1
  8. package/dist/types/components/features/data-table/data-table.d.ts +19 -0
  9. package/dist/types/components/features/data-table/data-table.d.ts.map +1 -0
  10. package/dist/types/components/features/data-table/expand-toggle.d.ts +5 -0
  11. package/dist/types/components/features/data-table/expand-toggle.d.ts.map +1 -0
  12. package/dist/types/components/features/data-table/fuzzy-filter.d.ts +4 -0
  13. package/dist/types/components/features/data-table/fuzzy-filter.d.ts.map +1 -0
  14. package/dist/types/components/features/data-table/index.d.ts +3 -0
  15. package/dist/types/components/features/data-table/index.d.ts.map +1 -0
  16. package/dist/types/components/features/data-table/sortable-header.d.ts +5 -0
  17. package/dist/types/components/features/data-table/sortable-header.d.ts.map +1 -0
  18. package/dist/types/components/features/page-heading.d.ts +1 -1
  19. package/dist/types/components/features/page-heading.d.ts.map +1 -1
  20. package/dist/types/components/features/sidebar-layout.d.ts.map +1 -1
  21. package/dist/types/components/icons/beta.d.ts.map +1 -1
  22. package/dist/types/components/icons/dot.d.ts.map +1 -1
  23. package/dist/types/components/icons/issue.d.ts.map +1 -1
  24. package/dist/types/components/icons/turtle.d.ts.map +1 -1
  25. package/dist/types/components/icons/update.d.ts.map +1 -1
  26. package/dist/types/components/icons/warning.d.ts.map +1 -1
  27. package/dist/types/components/molecules/opportunity/opportunity-disclaimer.d.ts.map +1 -1
  28. package/dist/types/components/molecules/opportunity/opportunity-list/hooks/use-opportunity-grouping.d.ts.map +1 -1
  29. package/dist/types/components/molecules/opportunity/opportunity-list/opportunity-list.d.ts.map +1 -1
  30. package/dist/types/components/molecules/opportunity/opportunity-rate-estimator.d.ts.map +1 -1
  31. package/dist/types/components/molecules/opportunity/opportunity-section.d.ts.map +1 -1
  32. package/dist/types/components/molecules/opportunity/opportunity-selector.d.ts +1 -1
  33. package/dist/types/components/molecules/opportunity/opportunity-selector.d.ts.map +1 -1
  34. package/dist/types/components/molecules/slippage-selector.d.ts.map +1 -1
  35. package/dist/types/components/molecules/swap-details.d.ts.map +1 -1
  36. package/dist/types/components/molecules/swap-input.d.ts.map +1 -1
  37. package/dist/types/components/molecules/tabs.d.ts +1 -1
  38. package/dist/types/components/molecules/tabs.d.ts.map +1 -1
  39. package/dist/types/components/molecules/token-selector.d.ts.map +1 -1
  40. package/dist/types/components/molecules/tx-status.d.ts.map +1 -1
  41. package/dist/types/components/molecules/widget/asset-list/asset-filters.d.ts.map +1 -1
  42. package/dist/types/components/molecules/widget/asset-list/asset-list.d.ts.map +1 -1
  43. package/dist/types/components/molecules/widget/asset-list/hooks/use-asset-filtering.d.ts.map +1 -1
  44. package/dist/types/components/molecules/widget/asset-list/hooks/use-asset-grouping.d.ts.map +1 -1
  45. package/dist/types/components/molecules/widget/campaign-item.d.ts.map +1 -1
  46. package/dist/types/components/molecules/widget/deal-item.d.ts.map +1 -1
  47. package/dist/types/components/molecules/widget/index.d.ts +1 -1
  48. package/dist/types/components/molecules/widget/index.d.ts.map +1 -1
  49. package/dist/types/components/molecules/widget/opportunity-item.d.ts.map +1 -1
  50. package/dist/types/components/ui/alert-dialog.d.ts.map +1 -1
  51. package/dist/types/components/ui/avatar.d.ts.map +1 -1
  52. package/dist/types/components/ui/badge.d.ts.map +1 -1
  53. package/dist/types/components/ui/banner.d.ts.map +1 -1
  54. package/dist/types/components/ui/button.d.ts.map +1 -1
  55. package/dist/types/components/ui/card.d.ts +1 -1
  56. package/dist/types/components/ui/card.d.ts.map +1 -1
  57. package/dist/types/components/ui/checkbox.d.ts.map +1 -1
  58. package/dist/types/components/ui/chip.d.ts.map +1 -1
  59. package/dist/types/components/ui/collapsible.d.ts.map +1 -1
  60. package/dist/types/components/ui/combobox.d.ts.map +1 -1
  61. package/dist/types/components/ui/command.d.ts.map +1 -1
  62. package/dist/types/components/ui/dialog.d.ts.map +1 -1
  63. package/dist/types/components/ui/dropdown.d.ts.map +1 -1
  64. package/dist/types/components/ui/field.d.ts.map +1 -1
  65. package/dist/types/components/ui/heading.d.ts.map +1 -1
  66. package/dist/types/components/ui/hover-card.d.ts +1 -1
  67. package/dist/types/components/ui/hover-card.d.ts.map +1 -1
  68. package/dist/types/components/ui/icon-list.d.ts.map +1 -1
  69. package/dist/types/components/ui/info-card.d.ts.map +1 -1
  70. package/dist/types/components/ui/input-group.d.ts.map +1 -1
  71. package/dist/types/components/ui/input.d.ts.map +1 -1
  72. package/dist/types/components/ui/label.d.ts.map +1 -1
  73. package/dist/types/components/ui/multi-select.d.ts.map +1 -1
  74. package/dist/types/components/ui/navigation-bar.d.ts +1 -1
  75. package/dist/types/components/ui/navigation-bar.d.ts.map +1 -1
  76. package/dist/types/components/ui/navigation-menu.d.ts.map +1 -1
  77. package/dist/types/components/ui/opportunity-details-v1.d.ts.map +1 -1
  78. package/dist/types/components/ui/popover.d.ts.map +1 -1
  79. package/dist/types/components/ui/scroll-area.d.ts.map +1 -1
  80. package/dist/types/components/ui/select.d.ts.map +1 -1
  81. package/dist/types/components/ui/separator.d.ts.map +1 -1
  82. package/dist/types/components/ui/sheet.d.ts.map +1 -1
  83. package/dist/types/components/ui/sidebar.d.ts.map +1 -1
  84. package/dist/types/components/ui/slider.d.ts.map +1 -1
  85. package/dist/types/components/ui/switch.d.ts.map +1 -1
  86. package/dist/types/components/ui/table-shadcn.d.ts.map +1 -1
  87. package/dist/types/components/ui/table.d.ts.map +1 -1
  88. package/dist/types/components/ui/toggle-group.d.ts.map +1 -1
  89. package/dist/types/components/ui/toggle.d.ts.map +1 -1
  90. package/dist/types/components/ui/tooltip.d.ts.map +1 -1
  91. package/dist/types/hooks/useIsMobile.d.ts.map +1 -1
  92. package/dist/types/lib/utils.d.ts.map +1 -1
  93. package/dist/types/tokens/index.d.ts +5 -5
  94. package/dist/types/tokens/index.d.ts.map +1 -1
  95. package/package.json +3 -2
  96. package/src/components/features/data-table/data-table.tsx +150 -0
  97. package/src/components/features/data-table/expand-toggle.tsx +17 -0
  98. package/src/components/features/data-table/fuzzy-filter.tsx +34 -0
  99. package/src/components/features/data-table/index.ts +2 -0
  100. package/src/components/features/data-table/sortable-header.tsx +37 -0
  101. package/src/components/features/page-heading.tsx +6 -1
  102. package/src/components/features/search-bar.tsx +1 -1
  103. package/src/components/features/sidebar-layout.tsx +6 -3
  104. package/src/components/icons/beta.tsx +11 -2
  105. package/src/components/icons/dot.tsx +16 -3
  106. package/src/components/icons/issue.tsx +11 -2
  107. package/src/components/icons/turtle.tsx +16 -3
  108. package/src/components/icons/update.tsx +6 -1
  109. package/src/components/icons/warning.tsx +11 -2
  110. package/src/components/molecules/opportunity/opportunity-disclaimer.tsx +13 -5
  111. package/src/components/molecules/opportunity/opportunity-list/hooks/index.ts +1 -1
  112. package/src/components/molecules/opportunity/opportunity-list/hooks/use-opportunity-filtering.ts +3 -3
  113. package/src/components/molecules/opportunity/opportunity-list/hooks/use-opportunity-grouping.ts +7 -3
  114. package/src/components/molecules/opportunity/opportunity-list/index.ts +1 -1
  115. package/src/components/molecules/opportunity/opportunity-list/opportunity-list.tsx +10 -4
  116. package/src/components/molecules/opportunity/opportunity-rate-estimator.tsx +5 -6
  117. package/src/components/molecules/opportunity/opportunity-section.tsx +23 -6
  118. package/src/components/molecules/opportunity/opportunity-selector.tsx +7 -3
  119. package/src/components/molecules/slippage-selector.tsx +44 -20
  120. package/src/components/molecules/swap-details.tsx +14 -5
  121. package/src/components/molecules/swap-input.tsx +12 -6
  122. package/src/components/molecules/tabs.tsx +16 -4
  123. package/src/components/molecules/token-selector.tsx +38 -20
  124. package/src/components/molecules/tx-status.tsx +105 -54
  125. package/src/components/molecules/widget/asset-list/asset-filters.tsx +4 -2
  126. package/src/components/molecules/widget/asset-list/asset-list.tsx +8 -3
  127. package/src/components/molecules/widget/asset-list/asset-row.tsx +1 -1
  128. package/src/components/molecules/widget/asset-list/hooks/index.ts +1 -1
  129. package/src/components/molecules/widget/asset-list/hooks/use-asset-filtering.ts +4 -2
  130. package/src/components/molecules/widget/asset-list/hooks/use-asset-grouping.ts +15 -6
  131. package/src/components/molecules/widget/base-selector.tsx +5 -5
  132. package/src/components/molecules/widget/campaign-item.tsx +12 -6
  133. package/src/components/molecules/widget/deal-item.tsx +20 -8
  134. package/src/components/molecules/widget/index.ts +4 -1
  135. package/src/components/molecules/widget/opportunity-item.tsx +22 -8
  136. package/src/components/molecules/widget/widget-item-stats.tsx +2 -2
  137. package/src/components/ui/alert-dialog.tsx +26 -9
  138. package/src/components/ui/animated-background/animated-background.tsx +14 -6
  139. package/src/components/ui/animated-background/index.ts +1 -1
  140. package/src/components/ui/avatar.tsx +12 -3
  141. package/src/components/ui/badge.tsx +5 -3
  142. package/src/components/ui/banner.tsx +9 -3
  143. package/src/components/ui/button.tsx +10 -5
  144. package/src/components/ui/card.tsx +32 -5
  145. package/src/components/ui/checkbox.tsx +5 -2
  146. package/src/components/ui/chip.tsx +10 -6
  147. package/src/components/ui/collapsible.tsx +15 -3
  148. package/src/components/ui/combobox.tsx +52 -25
  149. package/src/components/ui/command.tsx +31 -11
  150. package/src/components/ui/dialog.tsx +22 -8
  151. package/src/components/ui/dropdown.tsx +57 -20
  152. package/src/components/ui/field.tsx +40 -28
  153. package/src/components/ui/heading.tsx +31 -6
  154. package/src/components/ui/hover-card.tsx +35 -10
  155. package/src/components/ui/icon-animation.tsx +12 -12
  156. package/src/components/ui/icon-list.tsx +45 -18
  157. package/src/components/ui/info-card.tsx +13 -5
  158. package/src/components/ui/input-group.tsx +32 -20
  159. package/src/components/ui/input.tsx +5 -3
  160. package/src/components/ui/label.tsx +5 -2
  161. package/src/components/ui/multi-select.tsx +133 -61
  162. package/src/components/ui/navigation-bar.tsx +39 -22
  163. package/src/components/ui/navigation-menu.tsx +16 -9
  164. package/src/components/ui/opportunity-details-v1.tsx +9 -5
  165. package/src/components/ui/popover.tsx +10 -4
  166. package/src/components/ui/scroll-area.tsx +5 -3
  167. package/src/components/ui/select.tsx +25 -10
  168. package/src/components/ui/separator.tsx +6 -6
  169. package/src/components/ui/sheet.tsx +15 -6
  170. package/src/components/ui/sidebar.tsx +62 -26
  171. package/src/components/ui/slider.tsx +10 -5
  172. package/src/components/ui/switch.tsx +6 -3
  173. package/src/components/ui/table-shadcn.tsx +19 -9
  174. package/src/components/ui/table.tsx +12 -5
  175. package/src/components/ui/textarea.tsx +1 -1
  176. package/src/components/ui/toggle-group.tsx +12 -12
  177. package/src/components/ui/toggle.tsx +14 -14
  178. package/src/components/ui/tooltip.tsx +7 -3
  179. package/src/hooks/useIsMobile.ts +5 -2
  180. package/src/lib/utils.ts +3 -3
  181. package/src/styles/themes/index.css +1 -1
  182. package/src/styles/themes/semantic.css +51 -17
  183. package/src/styles/tokens/colors.css +54 -18
  184. package/src/styles/tokens/index.css +1 -1
  185. package/src/styles/tokens/spacing.css +39 -33
  186. package/src/styles/tokens/typography.css +61 -60
  187. package/src/tokens/index.ts +82 -82
  188. package/dist/types/components/features/data-table.d.ts +0 -9
  189. package/dist/types/components/features/data-table.d.ts.map +0 -1
  190. package/src/components/features/data-table.tsx +0 -96
@@ -26,7 +26,7 @@ const inputVariants = cva(
26
26
  defaultVariants: {
27
27
  variant: "default",
28
28
  },
29
- }
29
+ },
30
30
  );
31
31
 
32
32
  export interface InputProps
@@ -41,7 +41,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
41
41
  if (prompt) {
42
42
  return (
43
43
  <div className="flex items-center gap-2">
44
- <span className="text-primary shrink-0 text-sm font-medium">{prompt}</span>
44
+ <span className="text-primary shrink-0 text-sm font-medium">
45
+ {prompt}
46
+ </span>
45
47
  <input
46
48
  type={type}
47
49
  data-slot="input"
@@ -62,7 +64,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
62
64
  {...props}
63
65
  />
64
66
  );
65
- }
67
+ },
66
68
  );
67
69
 
68
70
  Input.displayName = "Input";
@@ -5,13 +5,16 @@ import * as LabelPrimitive from "@radix-ui/react-label";
5
5
 
6
6
  import { cn } from "@/lib/utils";
7
7
 
8
- function Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {
8
+ function Label({
9
+ className,
10
+ ...props
11
+ }: React.ComponentProps<typeof LabelPrimitive.Root>) {
9
12
  return (
10
13
  <LabelPrimitive.Root
11
14
  data-slot="label"
12
15
  className={cn(
13
16
  "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
14
- className
17
+ className,
15
18
  )}
16
19
  {...props}
17
20
  />
@@ -4,7 +4,11 @@ import { cn } from "@/lib/utils";
4
4
  import { Separator } from "@/components/ui/separator";
5
5
  import { Button } from "@/components/ui/button";
6
6
  import { Badge } from "@/components/ui/badge";
7
- import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
7
+ import {
8
+ Popover,
9
+ PopoverContent,
10
+ PopoverTrigger,
11
+ } from "@/components/ui/popover";
8
12
  import {
9
13
  Command,
10
14
  CommandEmpty,
@@ -44,7 +48,10 @@ interface MultiSelectGroup {
44
48
  * Props for MultiSelect component
45
49
  */
46
50
  interface MultiSelectProps
47
- extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "animationConfig"> {
51
+ extends Omit<
52
+ React.ButtonHTMLAttributes<HTMLButtonElement>,
53
+ "animationConfig"
54
+ > {
48
55
  /**
49
56
  * An array of option objects or groups to be displayed in the multi-select component.
50
57
  */
@@ -256,9 +263,10 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
256
263
  closeOnSelect = false,
257
264
  ...props
258
265
  },
259
- ref
266
+ ref,
260
267
  ) => {
261
- const [selectedValues, setSelectedValues] = React.useState<string[]>(defaultValue);
268
+ const [selectedValues, setSelectedValues] =
269
+ React.useState<string[]>(defaultValue);
262
270
  const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);
263
271
  const [isAnimating, setIsAnimating] = React.useState(false);
264
272
  const [searchValue, setSearchValue] = React.useState("");
@@ -279,7 +287,7 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
279
287
  setTimeout(() => setPoliteMessage(""), 100);
280
288
  }
281
289
  },
282
- []
290
+ [],
283
291
  );
284
292
 
285
293
  const multiSelectId = React.useId();
@@ -290,18 +298,23 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
290
298
  const prevDefaultValueRef = React.useRef<string[]>(defaultValue);
291
299
 
292
300
  const isGroupedOptions = React.useCallback(
293
- (opts: MultiSelectOption[] | MultiSelectGroup[]): opts is MultiSelectGroup[] => {
301
+ (
302
+ opts: MultiSelectOption[] | MultiSelectGroup[],
303
+ ): opts is MultiSelectGroup[] => {
294
304
  return opts.length > 0 && "heading" in opts[0];
295
305
  },
296
- []
306
+ [],
297
307
  );
298
308
 
299
- const arraysEqual = React.useCallback((a: string[], b: string[]): boolean => {
300
- if (a.length !== b.length) return false;
301
- const sortedA = [...a].sort();
302
- const sortedB = [...b].sort();
303
- return sortedA.every((val, index) => val === sortedB[index]);
304
- }, []);
309
+ const arraysEqual = React.useCallback(
310
+ (a: string[], b: string[]): boolean => {
311
+ if (a.length !== b.length) return false;
312
+ const sortedA = [...a].sort();
313
+ const sortedB = [...b].sort();
314
+ return sortedA.every((val, index) => val === sortedB[index]);
315
+ },
316
+ [],
317
+ );
305
318
 
306
319
  const resetToDefault = React.useCallback(() => {
307
320
  setSelectedValues(defaultValue);
@@ -341,10 +354,12 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
341
354
  }
342
355
  },
343
356
  }),
344
- [resetToDefault, selectedValues, onValueChange]
357
+ [resetToDefault, selectedValues, onValueChange],
345
358
  );
346
359
 
347
- const [screenSize, setScreenSize] = React.useState<"mobile" | "tablet" | "desktop">("desktop");
360
+ const [screenSize, setScreenSize] = React.useState<
361
+ "mobile" | "tablet" | "desktop"
362
+ >("desktop");
348
363
 
349
364
  React.useEffect(() => {
350
365
  if (typeof window === "undefined") return;
@@ -421,14 +436,16 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
421
436
  }
422
437
  });
423
438
  if (process.env.NODE_ENV === "development" && duplicates.length > 0) {
424
- const action = deduplicateOptions ? "automatically removed" : "detected";
439
+ const action = deduplicateOptions
440
+ ? "automatically removed"
441
+ : "detected";
425
442
  console.warn(
426
443
  `MultiSelect: Duplicate option values ${action}: ${duplicates.join(", ")}. ` +
427
444
  `${
428
445
  deduplicateOptions
429
446
  ? "Duplicates have been removed automatically."
430
447
  : "This may cause unexpected behavior. Consider setting 'deduplicateOptions={true}' or ensure all option values are unique."
431
- }`
448
+ }`,
432
449
  );
433
450
  }
434
451
  return deduplicateOptions ? uniqueOptions : allOptions;
@@ -438,11 +455,13 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
438
455
  (value: string): MultiSelectOption | undefined => {
439
456
  const option = getAllOptions().find((option) => option.value === value);
440
457
  if (!option && process.env.NODE_ENV === "development") {
441
- console.warn(`MultiSelect: Option with value "${value}" not found in options list`);
458
+ console.warn(
459
+ `MultiSelect: Option with value "${value}" not found in options list`,
460
+ );
442
461
  }
443
462
  return option;
444
463
  },
445
- [getAllOptions]
464
+ [getAllOptions],
446
465
  );
447
466
 
448
467
  const filteredOptions = React.useMemo(() => {
@@ -454,8 +473,10 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
454
473
  ...group,
455
474
  options: group.options.filter(
456
475
  (option) =>
457
- option.label.toLowerCase().includes(searchValue.toLowerCase()) ||
458
- option.value.toLowerCase().includes(searchValue.toLowerCase())
476
+ option.label
477
+ .toLowerCase()
478
+ .includes(searchValue.toLowerCase()) ||
479
+ option.value.toLowerCase().includes(searchValue.toLowerCase()),
459
480
  ),
460
481
  }))
461
482
  .filter((group) => group.options.length > 0);
@@ -463,11 +484,13 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
463
484
  return options.filter(
464
485
  (option) =>
465
486
  option.label.toLowerCase().includes(searchValue.toLowerCase()) ||
466
- option.value.toLowerCase().includes(searchValue.toLowerCase())
487
+ option.value.toLowerCase().includes(searchValue.toLowerCase()),
467
488
  );
468
489
  }, [options, searchValue, searchable, isGroupedOptions]);
469
490
 
470
- const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
491
+ const handleInputKeyDown = (
492
+ event: React.KeyboardEvent<HTMLInputElement>,
493
+ ) => {
471
494
  if (event.key === "Enter") {
472
495
  setIsPopoverOpen(true);
473
496
  } else if (event.key === "Backspace" && !event.currentTarget.value) {
@@ -505,7 +528,10 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
505
528
 
506
529
  const clearExtraOptions = () => {
507
530
  if (disabled) return;
508
- const newSelectedValues = selectedValues.slice(0, responsiveSettings.maxCount);
531
+ const newSelectedValues = selectedValues.slice(
532
+ 0,
533
+ responsiveSettings.maxCount,
534
+ );
509
535
  setSelectedValues(newSelectedValues);
510
536
  onValueChange(newSelectedValues);
511
537
  };
@@ -565,20 +591,24 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
565
591
  if (diff > 0) {
566
592
  const addedItems = selectedValues.slice(-diff);
567
593
  const addedLabels = addedItems
568
- .map((value) => allOptions.find((opt) => opt.value === value)?.label)
594
+ .map(
595
+ (value) => allOptions.find((opt) => opt.value === value)?.label,
596
+ )
569
597
  .filter(Boolean);
570
598
 
571
599
  if (addedLabels.length === 1) {
572
600
  announce(
573
- `${addedLabels[0]} selected. ${selectedCount} of ${totalOptions} options selected.`
601
+ `${addedLabels[0]} selected. ${selectedCount} of ${totalOptions} options selected.`,
574
602
  );
575
603
  } else {
576
604
  announce(
577
- `${addedLabels.length} options selected. ${selectedCount} of ${totalOptions} total selected.`
605
+ `${addedLabels.length} options selected. ${selectedCount} of ${totalOptions} total selected.`,
578
606
  );
579
607
  }
580
608
  } else if (diff < 0) {
581
- announce(`Option removed. ${selectedCount} of ${totalOptions} options selected.`);
609
+ announce(
610
+ `Option removed. ${selectedCount} of ${totalOptions} options selected.`,
611
+ );
582
612
  }
583
613
  prevSelectedCount.current = selectedCount;
584
614
  }
@@ -586,7 +616,7 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
586
616
  if (isPopoverOpen !== prevIsOpen.current) {
587
617
  if (isPopoverOpen) {
588
618
  announce(
589
- `Dropdown opened. ${totalOptions} options available. Use arrow keys to navigate.`
619
+ `Dropdown opened. ${totalOptions} options available. Use arrow keys to navigate.`,
590
620
  );
591
621
  } else {
592
622
  announce("Dropdown closed.");
@@ -594,16 +624,19 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
594
624
  prevIsOpen.current = isPopoverOpen;
595
625
  }
596
626
 
597
- if (searchValue !== prevSearchValue.current && searchValue !== undefined) {
627
+ if (
628
+ searchValue !== prevSearchValue.current &&
629
+ searchValue !== undefined
630
+ ) {
598
631
  if (searchValue && isPopoverOpen) {
599
632
  const filteredCount = allOptions.filter(
600
633
  (opt) =>
601
634
  opt.label.toLowerCase().includes(searchValue.toLowerCase()) ||
602
- opt.value.toLowerCase().includes(searchValue.toLowerCase())
635
+ opt.value.toLowerCase().includes(searchValue.toLowerCase()),
603
636
  ).length;
604
637
 
605
638
  announce(
606
- `${filteredCount} option${filteredCount === 1 ? "" : "s"} found for "${searchValue}"`
639
+ `${filteredCount} option${filteredCount === 1 ? "" : "s"} found for "${searchValue}"`,
607
640
  );
608
641
  }
609
642
  prevSearchValue.current = searchValue;
@@ -621,9 +654,14 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
621
654
  </div>
622
655
  </div>
623
656
 
624
- <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen} modal={modalPopover}>
657
+ <Popover
658
+ open={isPopoverOpen}
659
+ onOpenChange={setIsPopoverOpen}
660
+ modal={modalPopover}
661
+ >
625
662
  <div id={triggerDescriptionId} className="sr-only">
626
- Multi-select dropdown. Use arrow keys to navigate, Enter to select, and Escape to close.
663
+ Multi-select dropdown. Use arrow keys to navigate, Enter to select,
664
+ and Escape to close.
627
665
  </div>
628
666
  <div id={selectedCountId} className="sr-only" aria-live="polite">
629
667
  {selectedValues.length === 0
@@ -658,7 +696,7 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
658
696
  responsiveSettings.compactMode && "h-8 text-sm",
659
697
  screenSize === "mobile" && "h-12 text-base",
660
698
  disabled && "cursor-not-allowed opacity-50",
661
- className
699
+ className,
662
700
  )}
663
701
  style={{
664
702
  ...widthConstraints,
@@ -670,8 +708,10 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
670
708
  <div
671
709
  className={cn(
672
710
  "flex items-center gap-1",
673
- singleLine ? "multiselect-singleline-scroll overflow-x-auto" : "flex-wrap",
674
- responsiveSettings.compactMode && "gap-0.5"
711
+ singleLine
712
+ ? "multiselect-singleline-scroll overflow-x-auto"
713
+ : "flex-wrap",
714
+ responsiveSettings.compactMode && "gap-0.5",
675
715
  )}
676
716
  style={
677
717
  singleLine
@@ -697,10 +737,12 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
697
737
  key={value}
698
738
  className={cn(
699
739
  "!pr-1.5 pl-3.5",
700
- responsiveSettings.compactMode && "px-1.5 py-0.5 text-xs",
701
- screenSize === "mobile" && "max-w-[120px] truncate",
740
+ responsiveSettings.compactMode &&
741
+ "px-1.5 py-0.5 text-xs",
742
+ screenSize === "mobile" &&
743
+ "max-w-[120px] truncate",
702
744
  singleLine && "flex-shrink-0 whitespace-nowrap",
703
- "[&>svg]:pointer-events-auto"
745
+ "[&>svg]:pointer-events-auto",
704
746
  )}
705
747
  style={badgeStyle}
706
748
  >
@@ -708,11 +750,16 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
708
750
  <IconComponent
709
751
  className={cn(
710
752
  "mr-2 size-3.5",
711
- responsiveSettings.compactMode && "mr-1 h-3 w-3"
753
+ responsiveSettings.compactMode &&
754
+ "mr-1 h-3 w-3",
712
755
  )}
713
756
  />
714
757
  )}
715
- <span className={cn(screenSize === "mobile" && "truncate")}>
758
+ <span
759
+ className={cn(
760
+ screenSize === "mobile" && "truncate",
761
+ )}
762
+ >
716
763
  {option.label}
717
764
  </span>
718
765
  <div
@@ -723,7 +770,10 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
723
770
  toggleOption(value);
724
771
  }}
725
772
  onKeyDown={(event) => {
726
- if (event.key === "Enter" || event.key === " ") {
773
+ if (
774
+ event.key === "Enter" ||
775
+ event.key === " "
776
+ ) {
727
777
  event.preventDefault();
728
778
  event.stopPropagation();
729
779
  toggleOption(value);
@@ -742,9 +792,10 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
742
792
  <Badge
743
793
  className={cn(
744
794
  "!pr-1.5 pl-3.5",
745
- responsiveSettings.compactMode && "px-1.5 py-0.5 text-xs",
795
+ responsiveSettings.compactMode &&
796
+ "px-1.5 py-0.5 text-xs",
746
797
  singleLine && "flex-shrink-0 whitespace-nowrap",
747
- "[&>svg]:pointer-events-auto"
798
+ "[&>svg]:pointer-events-auto",
748
799
  )}
749
800
  >
750
801
  {`+ ${selectedValues.length - responsiveSettings.maxCount} more`}
@@ -782,7 +833,10 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
782
833
  >
783
834
  <XIcon className="size-3.5" />
784
835
  </div>
785
- <Separator orientation="vertical" className="flex h-full min-h-6" />
836
+ <Separator
837
+ orientation="vertical"
838
+ className="flex h-full min-h-6"
839
+ />
786
840
  <ChevronDown
787
841
  className="text-muted-foreground mx-2 h-4 cursor-pointer"
788
842
  aria-hidden="true"
@@ -791,7 +845,9 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
791
845
  </div>
792
846
  ) : (
793
847
  <div className="mx-auto flex w-full items-center justify-between">
794
- <span className="text-muted-foreground text-sm">{placeholder}</span>
848
+ <span className="text-muted-foreground text-sm">
849
+ {placeholder}
850
+ </span>
795
851
  <ChevronDown className="text-muted-foreground mx-2 h-4 cursor-pointer" />
796
852
  </div>
797
853
  )}
@@ -807,7 +863,7 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
807
863
  screenSize === "mobile" && "w-[85vw] max-w-[280px]",
808
864
  screenSize === "tablet" && "w-[70vw] max-w-md",
809
865
  screenSize === "desktop" && "min-w-[300px]",
810
- popoverClassName
866
+ popoverClassName,
811
867
  )}
812
868
  style={{
813
869
  maxWidth: `min(${widthConstraints.maxWidth}, 85vw)`,
@@ -837,10 +893,12 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
837
893
  className={cn(
838
894
  "multiselect-scrollbar max-h-[40vh] overflow-y-auto",
839
895
  screenSize === "mobile" && "max-h-[50vh]",
840
- "overscroll-behavior-y-contain"
896
+ "overscroll-behavior-y-contain",
841
897
  )}
842
898
  >
843
- <CommandEmpty>{emptyIndicator || "No results found."}</CommandEmpty>{" "}
899
+ <CommandEmpty>
900
+ {emptyIndicator || "No results found."}
901
+ </CommandEmpty>{" "}
844
902
  {!hideSelectAll && !searchValue && (
845
903
  <CommandGroup>
846
904
  <CommandItem
@@ -858,9 +916,10 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
858
916
  className={cn(
859
917
  "border-border mr-2 flex size-3.5 items-center justify-center rounded-xs border",
860
918
  selectedValues.length ===
861
- getAllOptions().filter((opt) => !opt.disabled).length
919
+ getAllOptions().filter((opt) => !opt.disabled)
920
+ .length
862
921
  ? "bg-primary"
863
- : "opacity-50 [&_svg]:invisible"
922
+ : "opacity-50 [&_svg]:invisible",
864
923
  )}
865
924
  aria-hidden="true"
866
925
  >
@@ -868,7 +927,10 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
868
927
  </div>
869
928
  <span>
870
929
  (Select All
871
- {getAllOptions().length > 20 ? ` - ${getAllOptions().length} options` : ""})
930
+ {getAllOptions().length > 20
931
+ ? ` - ${getAllOptions().length} options`
932
+ : ""}
933
+ )
872
934
  </span>
873
935
  </CommandItem>
874
936
  </CommandGroup>
@@ -877,7 +939,9 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
877
939
  filteredOptions.map((group) => (
878
940
  <CommandGroup key={group.heading} heading={group.heading}>
879
941
  {group.options.map((option) => {
880
- const isSelected = selectedValues.includes(option.value);
942
+ const isSelected = selectedValues.includes(
943
+ option.value,
944
+ );
881
945
  return (
882
946
  <CommandItem
883
947
  key={option.value}
@@ -890,14 +954,17 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
890
954
  }${option.disabled ? ", disabled" : ""}`}
891
955
  className={cn(
892
956
  "cursor-pointer",
893
- option.disabled && "cursor-not-allowed opacity-50"
957
+ option.disabled &&
958
+ "cursor-not-allowed opacity-50",
894
959
  )}
895
960
  disabled={option.disabled}
896
961
  >
897
962
  <div
898
963
  className={cn(
899
964
  "border-border mr-2 flex size-3.5 items-center justify-center rounded-xs border",
900
- isSelected ? "bg-primary" : "opacity-50 [&_svg]:invisible"
965
+ isSelected
966
+ ? "bg-primary"
967
+ : "opacity-50 [&_svg]:invisible",
901
968
  )}
902
969
  aria-hidden="true"
903
970
  >
@@ -931,14 +998,16 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
931
998
  }${option.disabled ? ", disabled" : ""}`}
932
999
  className={cn(
933
1000
  "cursor-pointer",
934
- option.disabled && "cursor-not-allowed opacity-50"
1001
+ option.disabled && "cursor-not-allowed opacity-50",
935
1002
  )}
936
1003
  disabled={option.disabled}
937
1004
  >
938
1005
  <div
939
1006
  className={cn(
940
1007
  "border-border mr-2 flex size-3.5 items-center justify-center rounded-xs border",
941
- isSelected ? "bg-primary" : "opacity-50 [&_svg]:invisible"
1008
+ isSelected
1009
+ ? "bg-primary"
1010
+ : "opacity-50 [&_svg]:invisible",
942
1011
  )}
943
1012
  aria-hidden="true"
944
1013
  >
@@ -967,7 +1036,10 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
967
1036
  >
968
1037
  Clear
969
1038
  </CommandItem>
970
- <Separator orientation="vertical" className="mx-1 flex h-full min-h-6" />
1039
+ <Separator
1040
+ orientation="vertical"
1041
+ className="mx-1 flex h-full min-h-6"
1042
+ />
971
1043
  </>
972
1044
  )}
973
1045
  <CommandItem
@@ -985,7 +1057,7 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
985
1057
  <WandSparkles
986
1058
  className={cn(
987
1059
  "text-foreground bg-background my-2 h-3 w-3 cursor-pointer",
988
- isAnimating ? "" : "text-muted-foreground"
1060
+ isAnimating ? "" : "text-muted-foreground",
989
1061
  )}
990
1062
  onClick={() => setIsAnimating(!isAnimating)}
991
1063
  />
@@ -993,7 +1065,7 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
993
1065
  </Popover>
994
1066
  </>
995
1067
  );
996
- }
1068
+ },
997
1069
  );
998
1070
 
999
1071
  MultiSelect.displayName = "MultiSelect";
@@ -6,9 +6,11 @@ import { cn } from "@/lib/utils";
6
6
  const navigationBarVariants = cva("flex w-full", {
7
7
  variants: {
8
8
  variant: {
9
- default: "justify-between border border-border shadow-sm bg-background",
10
- transparent: "justify-between border border-border shadow-sm bg-transparent",
11
- menuBar: "relative h-9 gap-2 rounded-full border border-border bg-background font-medium shadow-sm",
9
+ default: "border-border bg-background justify-between border shadow-sm",
10
+ transparent:
11
+ "border-border justify-between border bg-transparent shadow-sm",
12
+ menuBar:
13
+ "border-border bg-background relative h-9 gap-2 rounded-full border font-medium shadow-sm",
12
14
  },
13
15
  },
14
16
  defaultVariants: {
@@ -17,20 +19,22 @@ const navigationBarVariants = cva("flex w-full", {
17
19
  });
18
20
 
19
21
  const navigationItemVariants = cva(
20
- "flex items-center justify-center whitespace-nowrap font-medium transition-all disabled:pointer-events-none disabled:opacity-50 cursor-pointer",
22
+ "flex cursor-pointer items-center justify-center font-medium whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50",
21
23
  {
22
24
  variants: {
23
25
  variant: {
24
- default: "text-sm text-muted-foreground hover:text-foreground",
25
- active: "text-sm text-primary bg-muted",
26
- menuBarDefault: "relative z-[1] w-full text-sm text-foreground rounded-full px-3 py-1.5 hover:text-primary",
27
- menuBarActive: "relative z-[1] w-full text-sm text-primary rounded-full px-3 py-1.5",
26
+ default: "text-muted-foreground hover:text-foreground text-sm",
27
+ active: "text-primary bg-muted text-sm",
28
+ menuBarDefault:
29
+ "text-foreground hover:text-primary relative z-[1] w-full rounded-full px-3 py-1.5 text-sm",
30
+ menuBarActive:
31
+ "text-primary relative z-[1] w-full rounded-full px-3 py-1.5 text-sm",
28
32
  },
29
33
  },
30
34
  defaultVariants: {
31
35
  variant: "default",
32
36
  },
33
- }
37
+ },
34
38
  );
35
39
 
36
40
  export interface NavigationBarProps
@@ -53,9 +57,16 @@ const NavigationBar = React.forwardRef<HTMLElement, NavigationBarProps>(
53
57
 
54
58
  // Function to update the indicator position and size based on the active button
55
59
  const updateIndicatorPosition = React.useCallback(() => {
56
- if (variant !== "menuBar" || !containerRef.current || !indicatorRef.current) return;
57
-
58
- const activeButton = containerRef.current.querySelector(`[data-active="true"]`) as HTMLElement;
60
+ if (
61
+ variant !== "menuBar" ||
62
+ !containerRef.current ||
63
+ !indicatorRef.current
64
+ )
65
+ return;
66
+
67
+ const activeButton = containerRef.current.querySelector(
68
+ `[data-active="true"]`,
69
+ ) as HTMLElement;
59
70
  if (activeButton) {
60
71
  indicatorRef.current.style.width = `${activeButton.offsetWidth}px`;
61
72
  indicatorRef.current.style.left = `${activeButton.offsetLeft}px`;
@@ -65,7 +76,7 @@ const NavigationBar = React.forwardRef<HTMLElement, NavigationBarProps>(
65
76
  // Create ResizeObserver to handle indicator container size changes
66
77
  React.useEffect(() => {
67
78
  if (variant !== "menuBar") return;
68
-
79
+
69
80
  updateIndicatorPosition();
70
81
 
71
82
  const resizeObserver = new ResizeObserver(updateIndicatorPosition);
@@ -80,21 +91,21 @@ const NavigationBar = React.forwardRef<HTMLElement, NavigationBarProps>(
80
91
  }, [activeValue, updateIndicatorPosition, variant]);
81
92
 
82
93
  return (
83
- <nav
84
- ref={ref || containerRef}
85
- className={cn(navigationBarVariants({ variant, className }))}
94
+ <nav
95
+ ref={ref || containerRef}
96
+ className={cn(navigationBarVariants({ variant, className }))}
86
97
  {...props}
87
98
  >
88
99
  {variant === "menuBar" && (
89
100
  <div
90
101
  ref={indicatorRef}
91
- className="absolute bottom-0 h-full origin-left rounded-full bg-secondary transition-all duration-300"
102
+ className="bg-secondary absolute bottom-0 h-full origin-left rounded-full transition-all duration-300"
92
103
  />
93
104
  )}
94
105
  {children}
95
106
  </nav>
96
107
  );
97
- }
108
+ },
98
109
  );
99
110
 
100
111
  NavigationBar.displayName = "NavigationBar";
@@ -110,7 +121,8 @@ const NavigationItem = React.forwardRef<HTMLButtonElement, NavigationItemProps>(
110
121
  };
111
122
 
112
123
  const appliedVariant = getItemVariant();
113
- const isMenuBar = appliedVariant === "menuBarDefault" || appliedVariant === "menuBarActive";
124
+ const isMenuBar =
125
+ appliedVariant === "menuBarDefault" || appliedVariant === "menuBarActive";
114
126
 
115
127
  return (
116
128
  <button
@@ -122,14 +134,19 @@ const NavigationItem = React.forwardRef<HTMLButtonElement, NavigationItemProps>(
122
134
  variant: appliedVariant,
123
135
  className,
124
136
  }),
125
- !isMenuBar && "px-4 py-2 rounded-md"
137
+ !isMenuBar && "rounded-md px-4 py-2",
126
138
  )}
127
139
  {...props}
128
140
  />
129
141
  );
130
- }
142
+ },
131
143
  );
132
144
 
133
145
  NavigationItem.displayName = "NavigationItem";
134
146
 
135
- export { NavigationBar, NavigationItem, navigationBarVariants, navigationItemVariants };
147
+ export {
148
+ NavigationBar,
149
+ NavigationItem,
150
+ navigationBarVariants,
151
+ navigationItemVariants,
152
+ };