@olympusoss/canvas 2.6.19

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 (128) hide show
  1. package/package.json +179 -0
  2. package/src/components/atoms/README.md +11 -0
  3. package/src/components/atoms/aspect-ratio.tsx +32 -0
  4. package/src/components/atoms/avatar.tsx +98 -0
  5. package/src/components/atoms/badge.tsx +44 -0
  6. package/src/components/atoms/brand-mark.tsx +74 -0
  7. package/src/components/atoms/button.tsx +104 -0
  8. package/src/components/atoms/checkbox.tsx +63 -0
  9. package/src/components/atoms/flex-box.tsx +105 -0
  10. package/src/components/atoms/icon.tsx +34 -0
  11. package/src/components/atoms/input.tsx +91 -0
  12. package/src/components/atoms/label.tsx +41 -0
  13. package/src/components/atoms/logo.tsx +89 -0
  14. package/src/components/atoms/progress.tsx +55 -0
  15. package/src/components/atoms/radio-group.tsx +122 -0
  16. package/src/components/atoms/scroll-area.tsx +106 -0
  17. package/src/components/atoms/section.tsx +48 -0
  18. package/src/components/atoms/separator.tsx +45 -0
  19. package/src/components/atoms/skeleton.tsx +17 -0
  20. package/src/components/atoms/slider.tsx +93 -0
  21. package/src/components/atoms/switch.tsx +60 -0
  22. package/src/components/atoms/textarea.tsx +78 -0
  23. package/src/components/atoms/toggle.tsx +80 -0
  24. package/src/components/charts/activity-heatmap.tsx +96 -0
  25. package/src/components/charts/axes.tsx +21 -0
  26. package/src/components/charts/chart-container.tsx +195 -0
  27. package/src/components/charts/chart-legend.tsx +67 -0
  28. package/src/components/charts/chart-tooltip.tsx +161 -0
  29. package/src/components/charts/chart-types.tsx +49 -0
  30. package/src/components/charts/containers.tsx +11 -0
  31. package/src/components/charts/data.tsx +16 -0
  32. package/src/components/charts/details.tsx +25 -0
  33. package/src/components/charts/gauge.tsx +106 -0
  34. package/src/components/charts/grids.tsx +8 -0
  35. package/src/components/charts/index.ts +62 -0
  36. package/src/components/charts/labeled-bar-list.tsx +85 -0
  37. package/src/components/charts/references.tsx +8 -0
  38. package/src/components/charts/service-health-list.tsx +73 -0
  39. package/src/components/charts/sparkline.tsx +52 -0
  40. package/src/components/charts/stacked-bar.tsx +104 -0
  41. package/src/components/charts/text.tsx +10 -0
  42. package/src/components/charts/world-heat-map-inner.tsx +317 -0
  43. package/src/components/charts/world-heat-map.tsx +184 -0
  44. package/src/components/molecules/README.md +12 -0
  45. package/src/components/molecules/action-bar.tsx +73 -0
  46. package/src/components/molecules/activity-item.tsx +74 -0
  47. package/src/components/molecules/alert.tsx +80 -0
  48. package/src/components/molecules/animated-background.tsx +92 -0
  49. package/src/components/molecules/brand-lockup.tsx +48 -0
  50. package/src/components/molecules/breadcrumb.tsx +161 -0
  51. package/src/components/molecules/button-group.tsx +104 -0
  52. package/src/components/molecules/calendar.tsx +216 -0
  53. package/src/components/molecules/card.tsx +101 -0
  54. package/src/components/molecules/code-block.tsx +48 -0
  55. package/src/components/molecules/empty-state.tsx +55 -0
  56. package/src/components/molecules/error-state.tsx +42 -0
  57. package/src/components/molecules/field-display.tsx +35 -0
  58. package/src/components/molecules/input-otp.tsx +74 -0
  59. package/src/components/molecules/loading-state.tsx +36 -0
  60. package/src/components/molecules/notification-item.tsx +67 -0
  61. package/src/components/molecules/notification-list.tsx +45 -0
  62. package/src/components/molecules/number-badge.tsx +53 -0
  63. package/src/components/molecules/page-header.tsx +88 -0
  64. package/src/components/molecules/page-tabs.tsx +94 -0
  65. package/src/components/molecules/pagination.tsx +150 -0
  66. package/src/components/molecules/phone-input.tsx +200 -0
  67. package/src/components/molecules/search-bar.tsx +64 -0
  68. package/src/components/molecules/secret-field.tsx +158 -0
  69. package/src/components/molecules/section-card.tsx +91 -0
  70. package/src/components/molecules/stat-card.tsx +96 -0
  71. package/src/components/molecules/status-badge.tsx +42 -0
  72. package/src/components/molecules/stepper.tsx +96 -0
  73. package/src/components/molecules/table.tsx +157 -0
  74. package/src/components/molecules/toggle-group.tsx +145 -0
  75. package/src/components/molecules/tooltip.tsx +150 -0
  76. package/src/components/molecules/user-avatar-chip.tsx +71 -0
  77. package/src/components/organisms/README.md +14 -0
  78. package/src/components/organisms/accordion.tsx +149 -0
  79. package/src/components/organisms/alert-dialog.tsx +269 -0
  80. package/src/components/organisms/carousel.tsx +244 -0
  81. package/src/components/organisms/collapsible.tsx +69 -0
  82. package/src/components/organisms/command.tsx +143 -0
  83. package/src/components/organisms/context-menu.tsx +333 -0
  84. package/src/components/organisms/dashboard-grid.tsx +360 -0
  85. package/src/components/organisms/data-table.tsx +330 -0
  86. package/src/components/organisms/dialog.tsx +304 -0
  87. package/src/components/organisms/drawer.tsx +100 -0
  88. package/src/components/organisms/dropdown-menu.tsx +434 -0
  89. package/src/components/organisms/editors/code-editor.tsx +144 -0
  90. package/src/components/organisms/editors/index.ts +4 -0
  91. package/src/components/organisms/editors/markdown-editor.tsx +153 -0
  92. package/src/components/organisms/editors/markdown-renderer.ts +27 -0
  93. package/src/components/organisms/editors/prose-canvas-classes.ts +45 -0
  94. package/src/components/organisms/editors/rich-text-editor.tsx +126 -0
  95. package/src/components/organisms/editors/toolbar/md-toolbar.tsx +129 -0
  96. package/src/components/organisms/editors/toolbar/rte-toolbar.tsx +211 -0
  97. package/src/components/organisms/editors/toolbar/toolbar-shell.tsx +45 -0
  98. package/src/components/organisms/editors/use-codemirror-theme.ts +61 -0
  99. package/src/components/organisms/error-boundary.tsx +61 -0
  100. package/src/components/organisms/form.tsx +174 -0
  101. package/src/components/organisms/hover-card.tsx +114 -0
  102. package/src/components/organisms/menubar.tsx +491 -0
  103. package/src/components/organisms/navbar.tsx +101 -0
  104. package/src/components/organisms/navigation-menu.tsx +234 -0
  105. package/src/components/organisms/popover.tsx +144 -0
  106. package/src/components/organisms/resizable.tsx +39 -0
  107. package/src/components/organisms/schema-form.tsx +232 -0
  108. package/src/components/organisms/select.tsx +303 -0
  109. package/src/components/organisms/sheet.tsx +256 -0
  110. package/src/components/organisms/sidebar.tsx +1037 -0
  111. package/src/components/organisms/sonner.tsx +96 -0
  112. package/src/components/organisms/tabs.tsx +132 -0
  113. package/src/components/organisms/theme-provider.tsx +101 -0
  114. package/src/hooks/use-mobile.tsx +19 -0
  115. package/src/index.ts +547 -0
  116. package/src/lib/portal-container.tsx +35 -0
  117. package/src/lib/utils.ts +6 -0
  118. package/src/native.ts +23 -0
  119. package/src/tokens/colors.ts +91 -0
  120. package/src/tokens/index.ts +3 -0
  121. package/src/tokens/spacing.ts +55 -0
  122. package/src/tokens/typography.ts +27 -0
  123. package/styles/canvas.css +55 -0
  124. package/styles/dashboard-grid.css +47 -0
  125. package/styles/leaflet.css +13 -0
  126. package/styles/tokens.css +234 -0
  127. package/tailwind.config.ts +70 -0
  128. package/tsconfig.json +23 -0
@@ -0,0 +1,145 @@
1
+ "use client";
2
+
3
+ import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
4
+ import type { VariantProps } from "class-variance-authority";
5
+ import * as React from "react";
6
+
7
+ import { cn } from "../../lib/utils";
8
+ import { toggleVariants } from "../atoms/toggle";
9
+
10
+ const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariants>>({
11
+ size: "default",
12
+ variant: "default",
13
+ });
14
+
15
+ export interface ToggleGroupProps {
16
+ /**
17
+ * Selection mode. `"single"` allows one item active at a time;
18
+ * `"multiple"` allows independent toggles.
19
+ */
20
+ type: "single" | "multiple";
21
+ /**
22
+ * Controlled value. For `type="single"` it's a string; for
23
+ * `type="multiple"` it's an array of strings.
24
+ */
25
+ value?: string | string[];
26
+ /** Initial value for uncontrolled usage. */
27
+ defaultValue?: string | string[];
28
+ /** Fires when the user toggles an item. */
29
+ onValueChange?: (value: string & string[]) => void;
30
+ /**
31
+ * Disable every toggle in the group.
32
+ * @default false
33
+ */
34
+ disabled?: boolean;
35
+ /**
36
+ * Layout direction.
37
+ * @default "horizontal"
38
+ */
39
+ orientation?: "horizontal" | "vertical";
40
+ /**
41
+ * Reading direction. Affects keyboard arrow navigation.
42
+ * @default "ltr"
43
+ */
44
+ dir?: "ltr" | "rtl";
45
+ /**
46
+ * When true, arrow-key navigation wraps from the last item to the first.
47
+ * @default true
48
+ */
49
+ loop?: boolean;
50
+ /**
51
+ * Filled vs outlined preset (inherits from `<Toggle>`).
52
+ * @default "default"
53
+ */
54
+ variant?: "default" | "outline";
55
+ /**
56
+ * Size preset (inherits from `<Toggle>`).
57
+ * @default "default"
58
+ */
59
+ size?: "default" | "sm" | "lg";
60
+ /**
61
+ * Render as a Radix Slot — forwards props onto the immediate child.
62
+ * @default false
63
+ */
64
+ asChild?: boolean;
65
+ /** A flat list of `<ToggleGroupItem>`s. */
66
+ children?: React.ReactNode;
67
+ /** Tailwind / CSS classes merged onto the group via `cn()`. */
68
+ className?: string;
69
+ }
70
+
71
+ const ToggleGroupImpl = React.forwardRef<
72
+ React.ElementRef<typeof ToggleGroupPrimitive.Root>,
73
+ ToggleGroupProps
74
+ >(({ className, variant, size, children, ...props }, ref) => (
75
+ <ToggleGroupPrimitive.Root
76
+ ref={ref}
77
+ {...(props as React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root>)}
78
+ className={cn("flex items-center justify-center gap-1", className)}
79
+ >
80
+ <ToggleGroupContext.Provider value={{ variant, size }}>{children}</ToggleGroupContext.Provider>
81
+ </ToggleGroupPrimitive.Root>
82
+ ));
83
+
84
+ ToggleGroupImpl.displayName = ToggleGroupPrimitive.Root.displayName;
85
+
86
+ const ToggleGroup = ToggleGroupImpl as React.ForwardRefExoticComponent<
87
+ ToggleGroupProps & React.RefAttributes<HTMLDivElement>
88
+ >;
89
+
90
+ export interface ToggleGroupItemProps
91
+ extends React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item>,
92
+ VariantProps<typeof toggleVariants> {
93
+ /** Required — value reported when this toggle is active. */
94
+ value: string;
95
+ /**
96
+ * Disable only this toggle.
97
+ * @default false
98
+ */
99
+ disabled?: boolean;
100
+ /**
101
+ * Filled vs outlined. Defaults to inheriting from the parent
102
+ * `<ToggleGroup>`.
103
+ */
104
+ variant?: "default" | "outline";
105
+ /**
106
+ * Size preset. Defaults to inheriting from the parent `<ToggleGroup>`.
107
+ */
108
+ size?: "default" | "sm" | "lg";
109
+ /**
110
+ * Render as a Radix Slot — forwards props onto the immediate child.
111
+ * @default false
112
+ */
113
+ asChild?: boolean;
114
+ /** Toggle label or icon. */
115
+ children?: React.ReactNode;
116
+ /** Tailwind / CSS classes merged onto the toggle via `cn()`. */
117
+ className?: string;
118
+ }
119
+
120
+ const ToggleGroupItem = React.forwardRef<
121
+ React.ElementRef<typeof ToggleGroupPrimitive.Item>,
122
+ ToggleGroupItemProps
123
+ >(({ className, children, variant, size, ...props }, ref) => {
124
+ const context = React.useContext(ToggleGroupContext);
125
+
126
+ return (
127
+ <ToggleGroupPrimitive.Item
128
+ ref={ref}
129
+ className={cn(
130
+ toggleVariants({
131
+ variant: context.variant || variant,
132
+ size: context.size || size,
133
+ }),
134
+ className,
135
+ )}
136
+ {...props}
137
+ >
138
+ {children}
139
+ </ToggleGroupPrimitive.Item>
140
+ );
141
+ });
142
+
143
+ ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
144
+
145
+ export { ToggleGroup, ToggleGroupItem };
@@ -0,0 +1,150 @@
1
+ "use client";
2
+
3
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
4
+ import * as React from "react";
5
+
6
+ import { cn } from "../../lib/utils";
7
+
8
+ export interface TooltipProviderProps
9
+ extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Provider> {
10
+ /**
11
+ * Delay in ms before any tooltip in the provider opens. Set to 0 for
12
+ * instant tooltips (e.g. icon rails).
13
+ * @default 700
14
+ */
15
+ delayDuration?: number;
16
+ /**
17
+ * Delay in ms before a tooltip closes after the cursor leaves. Useful
18
+ * for letting users drag from the trigger to the content.
19
+ * @default 300
20
+ */
21
+ skipDelayDuration?: number;
22
+ /**
23
+ * When true, the tooltip will not close while the user is interacting
24
+ * with content inside it (e.g. hover, focus).
25
+ * @default false
26
+ */
27
+ disableHoverableContent?: boolean;
28
+ /** All `<Tooltip>`s in the subtree share this provider's delays. */
29
+ children: React.ReactNode;
30
+ }
31
+
32
+ const TooltipProvider = TooltipPrimitive.Provider as React.FC<TooltipProviderProps>;
33
+
34
+ export interface TooltipProps extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root> {
35
+ /** Controlled open state. */
36
+ open?: boolean;
37
+ /** Initial open state for uncontrolled usage. */
38
+ defaultOpen?: boolean;
39
+ /** Fires whenever the tooltip opens or closes. */
40
+ onOpenChange?: (open: boolean) => void;
41
+ /**
42
+ * Override the parent provider's `delayDuration` for this tooltip
43
+ * specifically.
44
+ */
45
+ delayDuration?: number;
46
+ /**
47
+ * Override the parent provider's `disableHoverableContent` for this
48
+ * tooltip.
49
+ */
50
+ disableHoverableContent?: boolean;
51
+ /** Trigger + Content. */
52
+ children?: React.ReactNode;
53
+ }
54
+
55
+ const Tooltip = TooltipPrimitive.Root as React.FC<TooltipProps>;
56
+
57
+ export interface TooltipTriggerProps
58
+ extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger> {
59
+ /**
60
+ * Render as a Radix Slot — forwards props onto the immediate child.
61
+ * Common pattern for wrapping a `<Button>` or icon.
62
+ * @default false
63
+ */
64
+ asChild?: boolean;
65
+ /** The element that opens the tooltip on hover/focus. */
66
+ children?: React.ReactNode;
67
+ }
68
+
69
+ const TooltipTrigger = TooltipPrimitive.Trigger as React.ForwardRefExoticComponent<
70
+ TooltipTriggerProps & React.RefAttributes<HTMLButtonElement>
71
+ >;
72
+
73
+ export interface TooltipContentProps
74
+ extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> {
75
+ /**
76
+ * Distance in pixels between the trigger and the tooltip content.
77
+ * @default 4
78
+ */
79
+ sideOffset?: number;
80
+ /**
81
+ * Distance from the alignment edge.
82
+ * @default 0
83
+ */
84
+ alignOffset?: number;
85
+ /**
86
+ * Preferred side of the trigger to render on.
87
+ * @default "top"
88
+ */
89
+ side?: "top" | "right" | "bottom" | "left";
90
+ /**
91
+ * Alignment along the chosen side.
92
+ * @default "center"
93
+ */
94
+ align?: "start" | "center" | "end";
95
+ /**
96
+ * Avoid colliding with the viewport edges by flipping/shifting.
97
+ * @default true
98
+ */
99
+ avoidCollisions?: boolean;
100
+ /**
101
+ * Padding kept from collision boundaries.
102
+ * @default 0
103
+ */
104
+ collisionPadding?: number | { top?: number; right?: number; bottom?: number; left?: number };
105
+ /**
106
+ * Stick to the trigger or partially follow on scroll.
107
+ * @default "partial"
108
+ */
109
+ sticky?: "partial" | "always";
110
+ /** Hide the content when the trigger is detached or covered. */
111
+ hideWhenDetached?: boolean;
112
+ /**
113
+ * Force the content to mount even when closed. Pair with a CSS
114
+ * animation that fades in/out based on `data-state`.
115
+ * @default false
116
+ */
117
+ forceMount?: true;
118
+ /**
119
+ * Render as a Radix Slot — forwards props onto the immediate child.
120
+ * @default false
121
+ */
122
+ asChild?: boolean;
123
+ /** Tooltip body. Keep terse — one short line is the convention. */
124
+ children?: React.ReactNode;
125
+ /** Tailwind / CSS classes merged onto the content via `cn()`. */
126
+ className?: string;
127
+ }
128
+
129
+ const TooltipContent = React.forwardRef<
130
+ React.ElementRef<typeof TooltipPrimitive.Content>,
131
+ TooltipContentProps
132
+ >(({ className, sideOffset = 6, children, ...props }, ref) => (
133
+ <TooltipPrimitive.Portal>
134
+ <TooltipPrimitive.Content
135
+ ref={ref}
136
+ sideOffset={sideOffset}
137
+ className={cn(
138
+ "z-50 max-w-xs overflow-hidden rounded-md border border-border/50 bg-popover px-2 py-1 text-[11px] font-medium text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 origin-[var(--radix-tooltip-content-transform-origin)]",
139
+ className,
140
+ )}
141
+ {...props}
142
+ >
143
+ {children}
144
+ <TooltipPrimitive.Arrow width={10} height={5} style={{ fill: "hsl(var(--popover))" }} />
145
+ </TooltipPrimitive.Content>
146
+ </TooltipPrimitive.Portal>
147
+ ));
148
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
149
+
150
+ export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
@@ -0,0 +1,71 @@
1
+ "use client";
2
+
3
+ import { ChevronDown } from "lucide-react";
4
+ import * as React from "react";
5
+
6
+ import { cn } from "../../lib/utils";
7
+ import { Avatar, AvatarFallback, AvatarImage } from "../atoms/avatar";
8
+
9
+ export interface UserAvatarChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
10
+ /** Display name (rendered next to the avatar). */
11
+ name: string;
12
+ /** Optional secondary line. Hidden when `collapsed`. */
13
+ email?: string;
14
+ /** Initials shown by AvatarFallback when no image is provided. */
15
+ fallback?: string;
16
+ /** Avatar image src. */
17
+ imageSrc?: string;
18
+ /** When true, renders only the avatar without name + chevron. */
19
+ collapsed?: boolean;
20
+ /** Set to false to hide the trailing ChevronDown affordance. */
21
+ chevron?: boolean;
22
+ }
23
+
24
+ export const UserAvatarChip = React.forwardRef<HTMLButtonElement, UserAvatarChipProps>(
25
+ (
26
+ { name, email, fallback, imageSrc, collapsed = false, chevron = true, className, ...props },
27
+ ref,
28
+ ) => {
29
+ const initials =
30
+ fallback ??
31
+ name
32
+ .split(" ")
33
+ .map((part) => part[0])
34
+ .filter(Boolean)
35
+ .slice(0, 2)
36
+ .join("")
37
+ .toUpperCase();
38
+ return (
39
+ <button
40
+ ref={ref}
41
+ type="button"
42
+ aria-label={collapsed ? name : undefined}
43
+ className={cn(
44
+ "inline-flex items-center gap-2 rounded-full border border-border bg-card text-[13px] font-medium text-foreground transition-colors hover:bg-accent",
45
+ collapsed ? "p-1" : "py-1 pl-1 pr-3",
46
+ className,
47
+ )}
48
+ {...props}
49
+ >
50
+ <Avatar className="h-7 w-7">
51
+ {imageSrc && <AvatarImage src={imageSrc} alt={name} />}
52
+ <AvatarFallback className="text-[11px] font-semibold">{initials}</AvatarFallback>
53
+ </Avatar>
54
+ {!collapsed && (
55
+ <>
56
+ <div className="flex flex-col items-start leading-tight">
57
+ <span className="truncate">{name}</span>
58
+ {email && (
59
+ <span className="truncate text-[11px] font-normal text-muted-foreground">
60
+ {email}
61
+ </span>
62
+ )}
63
+ </div>
64
+ {chevron && <ChevronDown className="h-3 w-3 text-muted-foreground" aria-hidden />}
65
+ </>
66
+ )}
67
+ </button>
68
+ );
69
+ },
70
+ );
71
+ UserAvatarChip.displayName = "UserAvatarChip";
@@ -0,0 +1,14 @@
1
+ # Organisms
2
+
3
+ Stateful surfaces. Compositions of atoms + molecules that own interactive
4
+ state (open/close, selection, form state) or complete complex UX.
5
+
6
+ **Can import**: `tokens/`, `lib/utils`, `atoms/`, `molecules/`, React.
7
+
8
+ **Cannot import**: anything from `templates/`.
9
+
10
+ Organisms are reusable — they don't know about specific app routes or domain
11
+ data. `DataTable` is an organism; `IdentitiesTable` (which knows how to render
12
+ a `Kratos.Identity`) is app-specific and belongs in that app's `features/`.
13
+
14
+ See [CONTRIBUTING.md](../../../CONTRIBUTING.md) for the full atomic-design rules.
@@ -0,0 +1,149 @@
1
+ "use client";
2
+
3
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
4
+ import { ChevronDown } from "lucide-react";
5
+ import * as React from "react";
6
+
7
+ import { cn } from "../../lib/utils";
8
+
9
+ export interface AccordionProps {
10
+ /**
11
+ * Selection mode. `"single"` allows one item open at a time;
12
+ * `"multiple"` allows multiple items open simultaneously.
13
+ */
14
+ type: "single" | "multiple";
15
+ /**
16
+ * Controlled value. For `type="single"` it's a string (id of the open
17
+ * item); for `type="multiple"` it's a string array.
18
+ */
19
+ value?: string | string[];
20
+ /** Initial value for uncontrolled usage. */
21
+ defaultValue?: string | string[];
22
+ /** Fires when the user opens/closes an item. */
23
+ onValueChange?: (value: string & string[]) => void;
24
+ /**
25
+ * For `type="single"` only — when true, an open item can be collapsed
26
+ * by clicking it again.
27
+ * @default false
28
+ */
29
+ collapsible?: boolean;
30
+ /**
31
+ * Disable the entire accordion.
32
+ * @default false
33
+ */
34
+ disabled?: boolean;
35
+ /**
36
+ * Reading direction. Affects keyboard arrow navigation.
37
+ * @default "ltr"
38
+ */
39
+ dir?: "ltr" | "rtl";
40
+ /**
41
+ * Layout direction.
42
+ * @default "vertical"
43
+ */
44
+ orientation?: "vertical" | "horizontal";
45
+ /**
46
+ * Render as a Radix Slot.
47
+ * @default false
48
+ */
49
+ asChild?: boolean;
50
+ /** A list of `<AccordionItem>`s. */
51
+ children?: React.ReactNode;
52
+ className?: string;
53
+ }
54
+
55
+ const Accordion = AccordionPrimitive.Root as React.ForwardRefExoticComponent<
56
+ AccordionProps & React.RefAttributes<HTMLDivElement>
57
+ >;
58
+
59
+ export interface AccordionItemProps
60
+ extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item> {
61
+ /** Required — unique value identifying this item. */
62
+ value: string;
63
+ /**
64
+ * Disable only this item.
65
+ * @default false
66
+ */
67
+ disabled?: boolean;
68
+ /**
69
+ * Render as a Radix Slot.
70
+ * @default false
71
+ */
72
+ asChild?: boolean;
73
+ /** A `<AccordionTrigger>` + `<AccordionContent>`. */
74
+ children?: React.ReactNode;
75
+ className?: string;
76
+ }
77
+
78
+ const AccordionItem = React.forwardRef<
79
+ React.ElementRef<typeof AccordionPrimitive.Item>,
80
+ AccordionItemProps
81
+ >(({ className, ...props }, ref) => (
82
+ <AccordionPrimitive.Item ref={ref} className={cn("border-b", className)} {...props} />
83
+ ));
84
+ AccordionItem.displayName = "AccordionItem";
85
+
86
+ export interface AccordionTriggerProps
87
+ extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger> {
88
+ /**
89
+ * Render as a Radix Slot.
90
+ * @default false
91
+ */
92
+ asChild?: boolean;
93
+ /** Trigger label — typically a section heading. */
94
+ children?: React.ReactNode;
95
+ className?: string;
96
+ }
97
+
98
+ const AccordionTrigger = React.forwardRef<
99
+ React.ElementRef<typeof AccordionPrimitive.Trigger>,
100
+ AccordionTriggerProps
101
+ >(({ className, children, ...props }, ref) => (
102
+ <AccordionPrimitive.Header className="flex">
103
+ <AccordionPrimitive.Trigger
104
+ ref={ref}
105
+ className={cn(
106
+ "flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline text-left [&[data-state=open]>svg]:rotate-180",
107
+ className,
108
+ )}
109
+ {...props}
110
+ >
111
+ {children}
112
+ <ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
113
+ </AccordionPrimitive.Trigger>
114
+ </AccordionPrimitive.Header>
115
+ ));
116
+ AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
117
+
118
+ export interface AccordionContentProps
119
+ extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content> {
120
+ /**
121
+ * Force the content to mount even when collapsed.
122
+ * @default false
123
+ */
124
+ forceMount?: true;
125
+ /**
126
+ * Render as a Radix Slot.
127
+ * @default false
128
+ */
129
+ asChild?: boolean;
130
+ /** Item body. */
131
+ children?: React.ReactNode;
132
+ className?: string;
133
+ }
134
+
135
+ const AccordionContent = React.forwardRef<
136
+ React.ElementRef<typeof AccordionPrimitive.Content>,
137
+ AccordionContentProps
138
+ >(({ className, children, ...props }, ref) => (
139
+ <AccordionPrimitive.Content
140
+ ref={ref}
141
+ className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
142
+ {...props}
143
+ >
144
+ <div className={cn("pb-4 pt-0", className)}>{children}</div>
145
+ </AccordionPrimitive.Content>
146
+ ));
147
+ AccordionContent.displayName = AccordionPrimitive.Content.displayName;
148
+
149
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };