@turtleclub/ui 0.7.0-beta.3 → 0.7.0-beta.30

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 (69) hide show
  1. package/.turbo/turbo-build.log +143 -132
  2. package/CHANGELOG.md +152 -0
  3. package/dist/index.cjs +76 -36
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.js +36068 -17674
  6. package/dist/index.js.map +1 -1
  7. package/dist/styles.css +1 -1
  8. package/dist/types/components/charts/area-chart.d.ts +108 -0
  9. package/dist/types/components/charts/area-chart.d.ts.map +1 -0
  10. package/dist/types/components/charts/bar-chart.d.ts +110 -0
  11. package/dist/types/components/charts/bar-chart.d.ts.map +1 -0
  12. package/dist/types/components/charts/index.d.ts +5 -0
  13. package/dist/types/components/charts/index.d.ts.map +1 -0
  14. package/dist/types/components/charts/pie-chart.d.ts +94 -0
  15. package/dist/types/components/charts/pie-chart.d.ts.map +1 -0
  16. package/dist/types/components/charts/radial-chart.d.ts +151 -0
  17. package/dist/types/components/charts/radial-chart.d.ts.map +1 -0
  18. package/dist/types/components/features/data-table/data-table.d.ts +7 -4
  19. package/dist/types/components/features/data-table/data-table.d.ts.map +1 -1
  20. package/dist/types/components/features/data-table/sort-dropdown.d.ts.map +1 -1
  21. package/dist/types/components/features/search-bar.d.ts +1 -0
  22. package/dist/types/components/features/search-bar.d.ts.map +1 -1
  23. package/dist/types/components/molecules/swap-input.d.ts +3 -0
  24. package/dist/types/components/molecules/swap-input.d.ts.map +1 -1
  25. package/dist/types/components/molecules/token-selector.d.ts +2 -1
  26. package/dist/types/components/molecules/token-selector.d.ts.map +1 -1
  27. package/dist/types/components/ui/avatar.d.ts +2 -2
  28. package/dist/types/components/ui/avatar.d.ts.map +1 -1
  29. package/dist/types/components/ui/chart.d.ts +18 -4
  30. package/dist/types/components/ui/chart.d.ts.map +1 -1
  31. package/dist/types/components/ui/combobox.d.ts +21 -0
  32. package/dist/types/components/ui/combobox.d.ts.map +1 -1
  33. package/dist/types/components/ui/dialog.d.ts.map +1 -1
  34. package/dist/types/components/ui/dropdown.d.ts +2 -1
  35. package/dist/types/components/ui/dropdown.d.ts.map +1 -1
  36. package/dist/types/components/ui/index.d.ts +1 -0
  37. package/dist/types/components/ui/index.d.ts.map +1 -1
  38. package/dist/types/components/ui/multi-select.d.ts.map +1 -1
  39. package/dist/types/components/ui/segment-control.d.ts +1 -0
  40. package/dist/types/components/ui/segment-control.d.ts.map +1 -1
  41. package/dist/types/components/ui/slider.d.ts.map +1 -1
  42. package/dist/types/index.d.ts +1 -0
  43. package/dist/types/index.d.ts.map +1 -1
  44. package/package.json +3 -3
  45. package/src/components/charts/QUICK_REFERENCE.md +323 -0
  46. package/src/components/charts/README.md +658 -0
  47. package/src/components/charts/RECHARTS_FEATURES.md +458 -0
  48. package/src/components/charts/area-chart.tsx +248 -0
  49. package/src/components/charts/bar-chart.tsx +362 -0
  50. package/src/components/charts/index.ts +4 -0
  51. package/src/components/charts/pie-chart.tsx +277 -0
  52. package/src/components/charts/radial-chart.tsx +312 -0
  53. package/src/components/features/data-table/data-table.tsx +136 -125
  54. package/src/components/features/data-table/sort-dropdown.tsx +8 -11
  55. package/src/components/features/search-bar.tsx +6 -1
  56. package/src/components/molecules/swap-input.tsx +44 -30
  57. package/src/components/molecules/token-selector.tsx +10 -1
  58. package/src/components/ui/avatar.tsx +8 -15
  59. package/src/components/ui/chart.tsx +100 -109
  60. package/src/components/ui/combobox.tsx +150 -137
  61. package/src/components/ui/dialog.tsx +9 -23
  62. package/src/components/ui/dropdown.tsx +3 -1
  63. package/src/components/ui/index.ts +1 -0
  64. package/src/components/ui/multi-select.tsx +325 -307
  65. package/src/components/ui/segment-control.tsx +7 -2
  66. package/src/components/ui/slider.tsx +6 -11
  67. package/src/index.ts +1 -0
  68. package/src/styles/globals.css +4 -0
  69. package/src/styles/themes/semantic.css +26 -56
@@ -1,9 +1,8 @@
1
1
  "use client";
2
2
 
3
3
  import * as React from "react";
4
- import { CheckIcon, ChevronDown, WandSparkles, XIcon } from "lucide-react";
5
-
6
- import { Button } from "@/components/ui/button";
4
+ import { Check as CheckIcon, ChevronDown, WandSparkles, X as XIcon } from "lucide-react";
5
+ import { buttonVariants } from "@/components/ui/button";
7
6
  import {
8
7
  Command,
9
8
  CommandEmpty,
@@ -12,11 +11,7 @@ import {
12
11
  CommandItem,
13
12
  CommandList,
14
13
  } from "@/components/ui/command";
15
- import {
16
- Popover,
17
- PopoverContent,
18
- PopoverTrigger,
19
- } from "@/components/ui/popover";
14
+ import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
20
15
  import { Separator } from "@/components/ui/separator";
21
16
  import { cn } from "@/lib/utils";
22
17
 
@@ -89,23 +84,40 @@ interface ComboboxOption<T = string> {
89
84
  * />
90
85
  */
91
86
  interface ComboboxProps<T = string>
92
- extends Omit<
93
- React.ButtonHTMLAttributes<HTMLButtonElement>,
94
- "animationConfig" | "defaultValue"
95
- > {
87
+ extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "animationConfig" | "defaultValue"> {
96
88
  /**
97
89
  * An array of option objects or groups to be displayed in the multi-select component.
98
90
  */
99
91
  options: ComboboxOption<T>[];
92
+
100
93
  /**
101
94
  * Callback function triggered when the selected values change.
102
95
  * Receives an array of the new selected values.
103
96
  */
104
97
  onValueChange: (value: T) => void;
105
98
 
99
+ /**
100
+ * Custom renderer for the selected value displayed in the input.
101
+ * @param option The currently selected option object.
102
+ */
103
+ renderValue?: (option: ComboboxOption<T>) => React.ReactNode;
104
+
106
105
  /** The default selected values when the component mounts. */
107
106
  defaultValue?: T;
108
107
 
108
+ /**
109
+ * Callback function triggered when the search input value changes.
110
+ * Useful for server-side filtering or handling large datasets externally.
111
+ */
112
+ onInputValueChange?: (value: string) => void;
113
+
114
+ /**
115
+ * If true, disables the built-in filtering logic.
116
+ * Use this when you filter options externally (e.g. server-side search).
117
+ * Optional, defaults to false.
118
+ */
119
+ disableLocalFiltering?: boolean;
120
+
109
121
  /**
110
122
  * Placeholder text to be displayed when no values are selected.
111
123
  * Optional, defaults to "Select options".
@@ -144,6 +156,12 @@ interface ComboboxProps<T = string>
144
156
  */
145
157
  searchable?: boolean;
146
158
 
159
+ /**
160
+ * If true, searching will also check the 'value' field in addition to 'label'.
161
+ * Optional, defaults to false.
162
+ */
163
+ searchByValue?: boolean;
164
+
147
165
  /**
148
166
  * Custom empty state message when no options match search.
149
167
  * Optional, defaults to "No results found."
@@ -237,10 +255,7 @@ export interface ComboboxRef {
237
255
  focus: () => void;
238
256
  }
239
257
 
240
- const ComboboxComponent = <T = string,>(
241
- props: ComboboxProps<T>,
242
- ref: React.Ref<ComboboxRef>,
243
- ) => {
258
+ const ComboboxComponent = <T = string,>(props: ComboboxProps<T>, ref: React.Ref<ComboboxRef>) => {
244
259
  const {
245
260
  options,
246
261
  onValueChange,
@@ -258,6 +273,10 @@ const ComboboxComponent = <T = string,>(
258
273
  minWidth,
259
274
  maxWidth,
260
275
  closeOnSelect = false,
276
+ renderValue,
277
+ searchByValue = false,
278
+ onInputValueChange,
279
+ disableLocalFiltering = false,
261
280
  ...restProps
262
281
  } = props;
263
282
 
@@ -293,7 +312,7 @@ const ComboboxComponent = <T = string,>(
293
312
  setTimeout(() => setPoliteMessage(""), 100);
294
313
  }
295
314
  },
296
- [],
315
+ []
297
316
  );
298
317
 
299
318
  const multiSelectId = React.useId();
@@ -334,12 +353,10 @@ const ComboboxComponent = <T = string,>(
334
353
  }
335
354
  },
336
355
  }),
337
- [resetToDefault, onValueChange],
356
+ [resetToDefault, onValueChange]
338
357
  );
339
358
 
340
- const [screenSize, setScreenSize] = React.useState<
341
- "mobile" | "tablet" | "desktop"
342
- >("desktop");
359
+ const [screenSize, setScreenSize] = React.useState<"mobile" | "tablet" | "desktop">("desktop");
343
360
 
344
361
  React.useEffect(() => {
345
362
  if (typeof window === "undefined") return;
@@ -410,25 +427,31 @@ const ComboboxComponent = <T = string,>(
410
427
  (value: T): ComboboxOption<T> | undefined => {
411
428
  const option = getAllOptions().find((option) => option.value === value);
412
429
  if (!option && process.env.NODE_ENV === "development") {
413
- console.warn(
414
- `Combobox: Option with value "${value}" not found in options list`,
415
- );
430
+ console.warn(`Combobox: Option with value "${value}" not found in options list`);
416
431
  }
417
432
  return option;
418
433
  },
419
- [getAllOptions],
434
+ [getAllOptions]
420
435
  );
421
436
 
422
437
  const filteredOptions = React.useMemo(() => {
438
+ if (disableLocalFiltering) return options;
423
439
  if (!searchable || !searchValue) return options;
424
440
  if (options.length === 0) return [];
425
441
 
426
- return options.filter(
427
- (option) =>
428
- option.label.toLowerCase().includes(searchValue.toLowerCase()) ||
429
- String(option.value).toLowerCase().includes(searchValue.toLowerCase()),
430
- );
431
- }, [options, searchValue, searchable]);
442
+ return options.filter((option) => {
443
+ const labelMatch = option.label.toLowerCase().includes(searchValue.toLowerCase());
444
+ if (!searchByValue) return labelMatch;
445
+
446
+ const val = option.value;
447
+ const valueMatch =
448
+ typeof val === "string" || typeof val === "number"
449
+ ? String(val).toLowerCase().includes(searchValue.toLowerCase())
450
+ : false;
451
+
452
+ return labelMatch || valueMatch;
453
+ });
454
+ }, [disableLocalFiltering, options, searchable, searchValue, searchByValue]);
432
455
 
433
456
  // const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
434
457
  // if (event.key === "Enter") {
@@ -477,9 +500,7 @@ const ComboboxComponent = <T = string,>(
477
500
 
478
501
  if (isPopoverOpen !== prevIsOpen.current) {
479
502
  if (isPopoverOpen) {
480
- announce(
481
- `Dropdown opened. ${totalOptions} options available. Use arrow keys to navigate.`,
482
- );
503
+ announce(`Dropdown opened. ${totalOptions} options available. Use arrow keys to navigate.`);
483
504
  } else {
484
505
  announce("Dropdown closed.");
485
506
  }
@@ -491,11 +512,11 @@ const ComboboxComponent = <T = string,>(
491
512
  const filteredCount = allOptions.filter(
492
513
  (opt) =>
493
514
  opt.label.toLowerCase().includes(searchValue.toLowerCase()) ||
494
- String(opt.value).toLowerCase().includes(searchValue.toLowerCase()),
515
+ String(opt.value).toLowerCase().includes(searchValue.toLowerCase())
495
516
  ).length;
496
517
 
497
518
  announce(
498
- `${filteredCount} option${filteredCount === 1 ? "" : "s"} found for "${searchValue}"`,
519
+ `${filteredCount} option${filteredCount === 1 ? "" : "s"} found for "${searchValue}"`
499
520
  );
500
521
  }
501
522
  prevSearchValue.current = searchValue;
@@ -513,101 +534,94 @@ const ComboboxComponent = <T = string,>(
513
534
  </div>
514
535
  </div>
515
536
 
516
- <Popover
517
- open={isPopoverOpen}
518
- onOpenChange={setIsPopoverOpen}
519
- modal={modalPopover}
520
- >
537
+ <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen} modal={modalPopover}>
521
538
  <div id={triggerDescriptionId} className="sr-only">
522
- Multi-select dropdown. Use arrow keys to navigate, Enter to select,
523
- and Escape to close.
539
+ Multi-select dropdown. Use arrow keys to navigate, Enter to select, and Escape to close.
524
540
  </div>
525
- <PopoverTrigger asChild>
526
- <Button
527
- ref={buttonRef}
528
- {...restProps}
529
- onClick={handleTogglePopover}
530
- disabled={disabled}
531
- role="combobox"
532
- aria-expanded={isPopoverOpen}
533
- aria-haspopup="listbox"
534
- aria-controls={isPopoverOpen ? listboxId : undefined}
535
- aria-describedby={`${triggerDescriptionId} ${selectedCountId}`}
536
- border="plain"
537
- className={cn(
538
- "flex h-10 items-center justify-between p-1 [&_svg]:pointer-events-auto",
539
- "!bg-neutral-alpha-2 text-base !font-normal shadow md:text-sm",
540
- autoSize ? "w-auto" : "w-full",
541
- responsiveSettings.compactMode && "h-8 text-sm",
542
- screenSize === "mobile" && "h-12 text-base",
543
- disabled && "cursor-not-allowed opacity-50",
544
- className,
545
- )}
546
- style={{
547
- ...widthConstraints,
548
- maxWidth: `min(${widthConstraints.maxWidth}, 100%)`,
549
- }}
550
- >
551
- {selectedValue ? (
552
- <div className="mx-auto flex w-full items-center justify-between">
553
- <div className="flex items-center gap-2">
554
- {(() => {
555
- const selectedOption = options.find(
556
- (op) => op.value === selectedValue,
557
- );
558
- return (
559
- <>
560
- {selectedOption?.icon && (
561
- <selectedOption.icon
562
- className="text-muted-foreground size-3.5"
563
- aria-hidden="true"
564
- />
565
- )}
566
- <span className="text-foreground text-sm">
567
- {selectedOption?.label}
568
- </span>
569
- </>
570
- );
571
- })()}
572
- </div>
573
- <div className="flex items-center justify-between">
574
- <div
575
- role="button"
576
- tabIndex={0}
577
- onClick={(event) => {
541
+ <PopoverTrigger
542
+ ref={buttonRef}
543
+ {...restProps}
544
+ onClick={handleTogglePopover}
545
+ disabled={disabled}
546
+ role="combobox"
547
+ aria-expanded={isPopoverOpen}
548
+ aria-haspopup="listbox"
549
+ aria-controls={isPopoverOpen ? listboxId : undefined}
550
+ aria-describedby={`${triggerDescriptionId} ${selectedCountId}`}
551
+ className={cn(
552
+ buttonVariants({
553
+ variant: "default",
554
+ size: "default",
555
+ border: "plain",
556
+ }),
557
+ "flex h-10 items-center justify-between [&_svg]:pointer-events-auto",
558
+ "!bg-neutral-alpha-2 text-base !font-normal shadow md:text-sm",
559
+ autoSize ? "w-auto" : "w-full",
560
+ responsiveSettings.compactMode && "h-8 text-sm",
561
+ screenSize === "mobile" && "h-12 text-base",
562
+ disabled && "cursor-not-allowed opacity-50",
563
+ className
564
+ )}
565
+ style={{
566
+ ...widthConstraints,
567
+ maxWidth: `min(${widthConstraints.maxWidth}, 100%)`,
568
+ }}
569
+ >
570
+ {selectedValue ? (
571
+ <div className="mx-auto flex w-full items-center justify-between">
572
+ <div className="flex items-center gap-2">
573
+ {(() => {
574
+ const selectedOption = options.find((op) => op.value === selectedValue);
575
+
576
+ if (renderValue && selectedOption) {
577
+ return renderValue(selectedOption);
578
+ }
579
+
580
+ return (
581
+ <>
582
+ {selectedOption?.icon && (
583
+ <selectedOption.icon
584
+ className="text-muted-foreground size-3.5"
585
+ aria-hidden="true"
586
+ />
587
+ )}
588
+ <span className="text-foreground text-sm">{selectedOption?.label}</span>
589
+ </>
590
+ );
591
+ })()}
592
+ </div>
593
+ <div className="flex items-center justify-between">
594
+ <div
595
+ role="button"
596
+ tabIndex={0}
597
+ onClick={(event) => {
598
+ event.stopPropagation();
599
+ handleClear();
600
+ }}
601
+ onKeyDown={(event) => {
602
+ if (event.key === "Enter" || event.key === " ") {
603
+ event.preventDefault();
578
604
  event.stopPropagation();
579
605
  handleClear();
580
- }}
581
- onKeyDown={(event) => {
582
- if (event.key === "Enter" || event.key === " ") {
583
- event.preventDefault();
584
- event.stopPropagation();
585
- handleClear();
586
- }
587
- }}
588
- className="text-muted-foreground hover:text-foreground focus:ring-ring mx-2 flex size-3.5 cursor-pointer items-center justify-center rounded-sm focus:ring-2 focus:ring-offset-1 focus:outline-none"
589
- >
590
- <XIcon className="size-3.5" />
591
- </div>
592
- <Separator
593
- orientation="vertical"
594
- className="flex h-full min-h-6"
595
- />
596
- <ChevronDown
597
- className="text-muted-foreground mx-2 h-4 cursor-pointer"
598
- aria-hidden="true"
599
- />
606
+ }
607
+ }}
608
+ className="text-muted-foreground hover:text-foreground focus:ring-ring mx-2 flex size-3.5 cursor-pointer items-center justify-center rounded-sm focus:ring-2 focus:ring-offset-1 focus:outline-none"
609
+ >
610
+ <XIcon className="size-3.5" />
600
611
  </div>
612
+ <Separator orientation="vertical" className="flex h-full min-h-6" />
613
+ <ChevronDown
614
+ className="text-muted-foreground mx-2 h-4 cursor-pointer"
615
+ aria-hidden="true"
616
+ />
601
617
  </div>
602
- ) : (
603
- <div className="mx-auto flex w-full items-center justify-between">
604
- <span className="text-muted-foreground text-sm">
605
- {placeholder}
606
- </span>
607
- <ChevronDown className="text-muted-foreground mx-2 h-4 cursor-pointer" />
608
- </div>
609
- )}
610
- </Button>
618
+ </div>
619
+ ) : (
620
+ <div className="mx-auto flex w-full items-center justify-between">
621
+ <span className="text-muted-foreground text-sm">{placeholder}</span>
622
+ <ChevronDown className="text-muted-foreground mx-2 h-4 cursor-pointer" />
623
+ </div>
624
+ )}
611
625
  </PopoverTrigger>
612
626
  <PopoverContent
613
627
  id={listboxId}
@@ -619,7 +633,7 @@ const ComboboxComponent = <T = string,>(
619
633
  screenSize === "mobile" && "w-[85vw] max-w-[280px]",
620
634
  screenSize === "tablet" && "w-[70vw] max-w-md",
621
635
  screenSize === "desktop" && "min-w-[300px]",
622
- popoverClassName,
636
+ popoverClassName
623
637
  )}
624
638
  style={{
625
639
  maxWidth: `min(${widthConstraints.maxWidth}, 85vw)`,
@@ -635,7 +649,10 @@ const ComboboxComponent = <T = string,>(
635
649
  placeholder="Search options..."
636
650
  // onKeyDown={handleInputKeyDown}
637
651
  value={searchValue}
638
- onValueChange={setSearchValue}
652
+ onValueChange={(val) => {
653
+ setSearchValue(val);
654
+ onInputValueChange?.(val);
655
+ }}
639
656
  aria-label="Search through available options"
640
657
  aria-describedby={`${multiSelectId}-search-help`}
641
658
  />
@@ -649,12 +666,10 @@ const ComboboxComponent = <T = string,>(
649
666
  className={cn(
650
667
  "multiselect-scrollbar max-h-[40vh] overflow-y-auto",
651
668
  screenSize === "mobile" && "max-h-[50vh]",
652
- "overscroll-behavior-y-contain",
669
+ "overscroll-behavior-y-contain"
653
670
  )}
654
671
  >
655
- <CommandEmpty>
656
- {emptyIndicator || "No results found."}
657
- </CommandEmpty>{" "}
672
+ <CommandEmpty>{emptyIndicator || "No results found."}</CommandEmpty>{" "}
658
673
  <CommandGroup>
659
674
  {filteredOptions.map((option) => {
660
675
  const isSelected = selectedValue === option.value;
@@ -670,7 +685,7 @@ const ComboboxComponent = <T = string,>(
670
685
  }${option.disabled ? ", disabled" : ""}`}
671
686
  className={cn(
672
687
  "cursor-pointer",
673
- option.disabled && "cursor-not-allowed opacity-50",
688
+ option.disabled && "cursor-not-allowed opacity-50"
674
689
  )}
675
690
  disabled={option.disabled}
676
691
  >
@@ -681,9 +696,7 @@ const ComboboxComponent = <T = string,>(
681
696
  />
682
697
  )}
683
698
  <span className="grow">{option.label}</span>
684
- {isSelected ? (
685
- <CheckIcon className="text-muted-foreground size-3.5" />
686
- ) : null}
699
+ {isSelected ? <CheckIcon className="text-muted-foreground size-3.5" /> : null}
687
700
  </CommandItem>
688
701
  );
689
702
  })}
@@ -695,7 +708,7 @@ const ComboboxComponent = <T = string,>(
695
708
  <WandSparkles
696
709
  className={cn(
697
710
  "text-foreground bg-background my-2 h-3 w-3 cursor-pointer",
698
- isAnimating ? "" : "text-muted-foreground",
711
+ isAnimating ? "" : "text-muted-foreground"
699
712
  )}
700
713
  onClick={() => setIsAnimating(!isAnimating)}
701
714
  />
@@ -707,7 +720,7 @@ const ComboboxComponent = <T = string,>(
707
720
 
708
721
  // Create the forwardRef wrapper with proper generic typing
709
722
  const ComboboxForwardRef = React.forwardRef(ComboboxComponent) as <T = string>(
710
- props: ComboboxProps<T> & { ref?: React.Ref<ComboboxRef> },
723
+ props: ComboboxProps<T> & { ref?: React.Ref<ComboboxRef> }
711
724
  ) => React.ReactElement;
712
725
 
713
726
  // Set displayName on a mutable object
@@ -6,27 +6,19 @@ import { XIcon } from "lucide-react";
6
6
 
7
7
  import { cn } from "@/lib/utils";
8
8
 
9
- function Dialog({
10
- ...props
11
- }: React.ComponentProps<typeof DialogPrimitive.Root>) {
9
+ function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {
12
10
  return <DialogPrimitive.Root data-slot="dialog" {...props} />;
13
11
  }
14
12
 
15
- function DialogTrigger({
16
- ...props
17
- }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
13
+ function DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
18
14
  return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
19
15
  }
20
16
 
21
- function DialogPortal({
22
- ...props
23
- }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
17
+ function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
24
18
  return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
25
19
  }
26
20
 
27
- function DialogClose({
28
- ...props
29
- }: React.ComponentProps<typeof DialogPrimitive.Close>) {
21
+ function DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>) {
30
22
  return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
31
23
  }
32
24
 
@@ -38,8 +30,8 @@ function DialogOverlay({
38
30
  <DialogPrimitive.Overlay
39
31
  data-slot="dialog-overlay"
40
32
  className={cn(
41
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
42
- className,
33
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-black/50",
34
+ className
43
35
  )}
44
36
  {...props}
45
37
  />
@@ -61,7 +53,7 @@ function DialogContent({
61
53
  data-slot="dialog-content"
62
54
  className={cn(
63
55
  "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 border-gradient-soft fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg p-6 shadow-lg duration-200 sm:max-w-lg",
64
- className,
56
+ className
65
57
  )}
66
58
  {...props}
67
59
  >
@@ -94,19 +86,13 @@ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
94
86
  return (
95
87
  <div
96
88
  data-slot="dialog-footer"
97
- className={cn(
98
- "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
99
- className,
100
- )}
89
+ className={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}
101
90
  {...props}
102
91
  />
103
92
  );
104
93
  }
105
94
 
106
- function DialogTitle({
107
- className,
108
- ...props
109
- }: React.ComponentProps<typeof DialogPrimitive.Title>) {
95
+ function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {
110
96
  return (
111
97
  <DialogPrimitive.Title
112
98
  data-slot="dialog-title"
@@ -43,10 +43,12 @@ function DropdownMenuTrigger({
43
43
  children,
44
44
  size = "default",
45
45
  src,
46
+ compact = false,
46
47
  ...props
47
48
  }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger> & {
48
49
  src?: string;
49
50
  size?: "default" | "sm" | "lg";
51
+ compact?: boolean;
50
52
  }) {
51
53
  return (
52
54
  <DropdownMenuPrimitive.Trigger
@@ -76,7 +78,7 @@ function DropdownMenuTrigger({
76
78
  )}
77
79
  />
78
80
  ) : undefined}
79
- <div className={cn("grow py-2 pr-2.5", src ? "pl-2.5" : "pl-4")}>
81
+ <div className={cn("grow py-2 pr-2.5", src ? "pl-2.5" : compact ? "pl-2.5" : "pl-4")}>
80
82
  {children}
81
83
  </div>
82
84
  <ChevronDownIcon className="mr-2.5 size-4" />
@@ -45,3 +45,4 @@ export * from "./collapsible";
45
45
  export * from "./banner";
46
46
  export * from "./skeleton";
47
47
  export * from "./pagination";
48
+ export * from "./sheet";