@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,303 @@
1
+ "use client";
2
+
3
+ import * as SelectPrimitive from "@radix-ui/react-select";
4
+ import { Check, ChevronDown, ChevronUp } from "lucide-react";
5
+ import * as React from "react";
6
+
7
+ import { usePortalContainer } from "../../lib/portal-container";
8
+ import { cn } from "../../lib/utils";
9
+
10
+ export interface SelectProps extends React.ComponentProps<typeof SelectPrimitive.Root> {
11
+ /** Controlled value. Pair with `onValueChange`. */
12
+ value?: string;
13
+ /** Initial value for uncontrolled usage. */
14
+ defaultValue?: string;
15
+ /** Fires when the user picks an option. */
16
+ onValueChange?: (value: string) => void;
17
+ /** Controlled open state. */
18
+ open?: boolean;
19
+ /** Initial open state. */
20
+ defaultOpen?: boolean;
21
+ /** Fires when the dropdown opens/closes. */
22
+ onOpenChange?: (open: boolean) => void;
23
+ /** Form field name. Required for native form submission. */
24
+ name?: string;
25
+ /**
26
+ * Disable the entire select.
27
+ * @default false
28
+ */
29
+ disabled?: boolean;
30
+ /**
31
+ * Required for native form validation.
32
+ * @default false
33
+ */
34
+ required?: boolean;
35
+ /**
36
+ * Reading direction.
37
+ * @default "ltr"
38
+ */
39
+ dir?: "ltr" | "rtl";
40
+ /** Trigger + Content. */
41
+ children?: React.ReactNode;
42
+ }
43
+
44
+ const Select = SelectPrimitive.Root as React.FC<SelectProps>;
45
+
46
+ export interface SelectGroupProps
47
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Group> {
48
+ /** Items grouped together — pair with `<SelectLabel>`. */
49
+ children?: React.ReactNode;
50
+ }
51
+
52
+ const SelectGroup = SelectPrimitive.Group as React.ForwardRefExoticComponent<
53
+ SelectGroupProps & React.RefAttributes<HTMLDivElement>
54
+ >;
55
+
56
+ export interface SelectValueProps
57
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Value> {
58
+ /** Placeholder shown when no value is selected. */
59
+ placeholder?: React.ReactNode;
60
+ /**
61
+ * Render as a Radix Slot — useful when you want to fully customise the
62
+ * value display.
63
+ * @default false
64
+ */
65
+ asChild?: boolean;
66
+ /** Custom display node when a value is selected. */
67
+ children?: React.ReactNode;
68
+ }
69
+
70
+ const SelectValue = SelectPrimitive.Value as React.ForwardRefExoticComponent<
71
+ SelectValueProps & React.RefAttributes<HTMLSpanElement>
72
+ >;
73
+
74
+ export interface SelectTriggerProps
75
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> {
76
+ /**
77
+ * Render as a Radix Slot.
78
+ * @default false
79
+ */
80
+ asChild?: boolean;
81
+ /** Typically a `<SelectValue>`. */
82
+ children?: React.ReactNode;
83
+ className?: string;
84
+ }
85
+
86
+ const SelectTrigger = React.forwardRef<
87
+ React.ElementRef<typeof SelectPrimitive.Trigger>,
88
+ SelectTriggerProps
89
+ >(({ className, children, ...props }, ref) => (
90
+ <SelectPrimitive.Trigger
91
+ ref={ref}
92
+ className={cn(
93
+ "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
94
+ className,
95
+ )}
96
+ {...props}
97
+ >
98
+ {children}
99
+ <SelectPrimitive.Icon asChild>
100
+ <ChevronDown className="h-4 w-4 opacity-50" />
101
+ </SelectPrimitive.Icon>
102
+ </SelectPrimitive.Trigger>
103
+ ));
104
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
105
+
106
+ export interface SelectScrollUpButtonProps
107
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton> {
108
+ asChild?: boolean;
109
+ className?: string;
110
+ }
111
+
112
+ const SelectScrollUpButton = React.forwardRef<
113
+ React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
114
+ SelectScrollUpButtonProps
115
+ >(({ className, ...props }, ref) => (
116
+ <SelectPrimitive.ScrollUpButton
117
+ ref={ref}
118
+ className={cn("flex cursor-default items-center justify-center py-1", className)}
119
+ {...props}
120
+ >
121
+ <ChevronUp className="h-4 w-4" />
122
+ </SelectPrimitive.ScrollUpButton>
123
+ ));
124
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
125
+
126
+ export interface SelectScrollDownButtonProps
127
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton> {
128
+ asChild?: boolean;
129
+ className?: string;
130
+ }
131
+
132
+ const SelectScrollDownButton = React.forwardRef<
133
+ React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
134
+ SelectScrollDownButtonProps
135
+ >(({ className, ...props }, ref) => (
136
+ <SelectPrimitive.ScrollDownButton
137
+ ref={ref}
138
+ className={cn("flex cursor-default items-center justify-center py-1", className)}
139
+ {...props}
140
+ >
141
+ <ChevronDown className="h-4 w-4" />
142
+ </SelectPrimitive.ScrollDownButton>
143
+ ));
144
+ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
145
+
146
+ export interface SelectContentProps
147
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> {
148
+ /**
149
+ * Whether to use trigger-anchored ("popper") or item-anchored
150
+ * ("item-aligned") positioning.
151
+ * @default "popper"
152
+ */
153
+ position?: "popper" | "item-aligned";
154
+ /** Distance from the trigger (px). Only when `position="popper"`. */
155
+ sideOffset?: number;
156
+ /** Distance from the alignment edge (px). */
157
+ alignOffset?: number;
158
+ /**
159
+ * Preferred side. Only when `position="popper"`.
160
+ * @default "bottom"
161
+ */
162
+ side?: "top" | "right" | "bottom" | "left";
163
+ /**
164
+ * Alignment along the chosen side.
165
+ * @default "start"
166
+ */
167
+ align?: "start" | "center" | "end";
168
+ /** Avoid colliding with viewport edges. */
169
+ avoidCollisions?: boolean;
170
+ /** Padding kept from collision boundaries. */
171
+ collisionPadding?: number | { top?: number; right?: number; bottom?: number; left?: number };
172
+ /** Force the content to mount even when closed. */
173
+ forceMount?: true;
174
+ /** Render as a Radix Slot. */
175
+ asChild?: boolean;
176
+ /** Items + groups + separators. */
177
+ children?: React.ReactNode;
178
+ className?: string;
179
+ }
180
+
181
+ const SelectContent = React.forwardRef<
182
+ React.ElementRef<typeof SelectPrimitive.Content>,
183
+ SelectContentProps
184
+ >(({ className, children, position = "popper", ...props }, ref) => {
185
+ const container = usePortalContainer();
186
+ return (
187
+ <SelectPrimitive.Portal container={container ?? undefined}>
188
+ <SelectPrimitive.Content
189
+ ref={ref}
190
+ className={cn(
191
+ "relative z-50 max-h-[var(--radix-select-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[var(--radix-select-content-transform-origin)]",
192
+ position === "popper" &&
193
+ "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
194
+ className,
195
+ )}
196
+ position={position}
197
+ {...props}
198
+ >
199
+ <SelectScrollUpButton />
200
+ <SelectPrimitive.Viewport
201
+ className={cn(
202
+ "p-1",
203
+ position === "popper" &&
204
+ "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
205
+ )}
206
+ >
207
+ {children}
208
+ </SelectPrimitive.Viewport>
209
+ <SelectScrollDownButton />
210
+ </SelectPrimitive.Content>
211
+ </SelectPrimitive.Portal>
212
+ );
213
+ });
214
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
215
+
216
+ export interface SelectLabelProps
217
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label> {
218
+ asChild?: boolean;
219
+ /** Section heading text. */
220
+ children?: React.ReactNode;
221
+ className?: string;
222
+ }
223
+
224
+ const SelectLabel = React.forwardRef<
225
+ React.ElementRef<typeof SelectPrimitive.Label>,
226
+ SelectLabelProps
227
+ >(({ className, ...props }, ref) => (
228
+ <SelectPrimitive.Label
229
+ ref={ref}
230
+ className={cn("px-2 py-1.5 text-sm font-semibold", className)}
231
+ {...props}
232
+ />
233
+ ));
234
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
235
+
236
+ export interface SelectItemProps
237
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item> {
238
+ /** Required — value reported when this option is picked. */
239
+ value: string;
240
+ /**
241
+ * Disable this option.
242
+ * @default false
243
+ */
244
+ disabled?: boolean;
245
+ /** Override what's used as text for typeahead/search. */
246
+ textValue?: string;
247
+ asChild?: boolean;
248
+ /** Item label. */
249
+ children?: React.ReactNode;
250
+ className?: string;
251
+ }
252
+
253
+ const SelectItem = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Item>, SelectItemProps>(
254
+ ({ className, children, ...props }, ref) => (
255
+ <SelectPrimitive.Item
256
+ ref={ref}
257
+ className={cn(
258
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
259
+ className,
260
+ )}
261
+ {...props}
262
+ >
263
+ <span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
264
+ <SelectPrimitive.ItemIndicator>
265
+ <Check className="h-4 w-4" />
266
+ </SelectPrimitive.ItemIndicator>
267
+ </span>
268
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
269
+ </SelectPrimitive.Item>
270
+ ),
271
+ );
272
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
273
+
274
+ export interface SelectSeparatorProps
275
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator> {
276
+ asChild?: boolean;
277
+ className?: string;
278
+ }
279
+
280
+ const SelectSeparator = React.forwardRef<
281
+ React.ElementRef<typeof SelectPrimitive.Separator>,
282
+ SelectSeparatorProps
283
+ >(({ className, ...props }, ref) => (
284
+ <SelectPrimitive.Separator
285
+ ref={ref}
286
+ className={cn("-mx-1 my-1 h-px bg-muted", className)}
287
+ {...props}
288
+ />
289
+ ));
290
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
291
+
292
+ export {
293
+ Select,
294
+ SelectContent,
295
+ SelectGroup,
296
+ SelectItem,
297
+ SelectLabel,
298
+ SelectScrollDownButton,
299
+ SelectScrollUpButton,
300
+ SelectSeparator,
301
+ SelectTrigger,
302
+ SelectValue,
303
+ };
@@ -0,0 +1,256 @@
1
+ "use client";
2
+
3
+ import * as SheetPrimitive from "@radix-ui/react-dialog";
4
+ import { cva, type VariantProps } from "class-variance-authority";
5
+ import { X } from "lucide-react";
6
+ import * as React from "react";
7
+
8
+ import { cn } from "../../lib/utils";
9
+
10
+ export interface SheetProps extends React.ComponentProps<typeof SheetPrimitive.Root> {
11
+ /** Controlled open state. Pair with `onOpenChange`. */
12
+ open?: boolean;
13
+ /**
14
+ * Initial open state for uncontrolled usage.
15
+ * @default false
16
+ */
17
+ defaultOpen?: boolean;
18
+ /** Fires whenever the sheet opens or closes. */
19
+ onOpenChange?: (open: boolean) => void;
20
+ /**
21
+ * When true, the sheet traps focus and renders the scrim overlay.
22
+ * @default true
23
+ */
24
+ modal?: boolean;
25
+ /** Trigger + Content. */
26
+ children?: React.ReactNode;
27
+ }
28
+
29
+ const Sheet = SheetPrimitive.Root as React.FC<SheetProps>;
30
+
31
+ export interface SheetTriggerProps
32
+ extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Trigger> {
33
+ /**
34
+ * Render as a Radix Slot.
35
+ * @default false
36
+ */
37
+ asChild?: boolean;
38
+ children?: React.ReactNode;
39
+ className?: string;
40
+ }
41
+
42
+ const SheetTrigger = SheetPrimitive.Trigger as React.ForwardRefExoticComponent<
43
+ SheetTriggerProps & React.RefAttributes<HTMLButtonElement>
44
+ >;
45
+
46
+ export interface SheetCloseProps
47
+ extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Close> {
48
+ /**
49
+ * Render as a Radix Slot.
50
+ * @default false
51
+ */
52
+ asChild?: boolean;
53
+ children?: React.ReactNode;
54
+ className?: string;
55
+ }
56
+
57
+ const SheetClose = SheetPrimitive.Close as React.ForwardRefExoticComponent<
58
+ SheetCloseProps & React.RefAttributes<HTMLButtonElement>
59
+ >;
60
+
61
+ export interface SheetPortalProps
62
+ extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Portal> {
63
+ /** DOM element to portal into. Defaults to `document.body`. */
64
+ container?: HTMLElement | null;
65
+ /**
66
+ * Force the portal to mount even when the sheet is closed.
67
+ * @default false
68
+ */
69
+ forceMount?: true;
70
+ children?: React.ReactNode;
71
+ }
72
+
73
+ const SheetPortal = SheetPrimitive.Portal as React.FC<SheetPortalProps>;
74
+
75
+ export interface SheetOverlayProps
76
+ extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay> {
77
+ /**
78
+ * Render as a Radix Slot.
79
+ * @default false
80
+ */
81
+ asChild?: boolean;
82
+ /**
83
+ * Force the overlay to mount even when closed.
84
+ * @default false
85
+ */
86
+ forceMount?: true;
87
+ className?: string;
88
+ }
89
+
90
+ const SheetOverlay = React.forwardRef<
91
+ React.ElementRef<typeof SheetPrimitive.Overlay>,
92
+ SheetOverlayProps
93
+ >(({ className, ...props }, ref) => (
94
+ <SheetPrimitive.Overlay
95
+ className={cn(
96
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
97
+ className,
98
+ )}
99
+ {...props}
100
+ ref={ref}
101
+ />
102
+ ));
103
+ SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
104
+
105
+ const sheetVariants = cva(
106
+ "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
107
+ {
108
+ variants: {
109
+ side: {
110
+ top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
111
+ bottom:
112
+ "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
113
+ left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
114
+ right:
115
+ "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
116
+ },
117
+ },
118
+ defaultVariants: {
119
+ side: "right",
120
+ },
121
+ },
122
+ );
123
+
124
+ export interface SheetContentProps
125
+ extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
126
+ VariantProps<typeof sheetVariants> {
127
+ /**
128
+ * Which edge of the viewport the sheet slides in from.
129
+ * @default "right"
130
+ */
131
+ side?: "top" | "right" | "bottom" | "left";
132
+ /**
133
+ * Render as a Radix Slot.
134
+ * @default false
135
+ */
136
+ asChild?: boolean;
137
+ /**
138
+ * Force the content to mount even when closed.
139
+ * @default false
140
+ */
141
+ forceMount?: true;
142
+ /** Fires when focus enters the sheet after it opens. */
143
+ onOpenAutoFocus?: (event: Event) => void;
144
+ /** Fires when focus leaves the sheet after it closes. */
145
+ onCloseAutoFocus?: (event: Event) => void;
146
+ /** Fires when Escape is pressed. */
147
+ onEscapeKeyDown?: (event: KeyboardEvent) => void;
148
+ /** Fires on pointer event outside the sheet. */
149
+ onPointerDownOutside?: (event: CustomEvent<{ originalEvent: PointerEvent }>) => void;
150
+ /** Fires on any interaction outside (focus + pointer). */
151
+ onInteractOutside?: (event: Event) => void;
152
+ /** Sheet body — `<SheetHeader>`, content, `<SheetFooter>`. */
153
+ children?: React.ReactNode;
154
+ /** Tailwind / CSS classes merged via `cn()`. */
155
+ className?: string;
156
+ }
157
+
158
+ const SheetContent = React.forwardRef<
159
+ React.ElementRef<typeof SheetPrimitive.Content>,
160
+ SheetContentProps
161
+ >(({ side = "right", className, children, ...props }, ref) => (
162
+ <SheetPortal>
163
+ <SheetOverlay />
164
+ <SheetPrimitive.Content ref={ref} className={cn(sheetVariants({ side }), className)} {...props}>
165
+ <SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
166
+ <X className="h-4 w-4" />
167
+ <span className="sr-only">Close</span>
168
+ </SheetPrimitive.Close>
169
+ {children}
170
+ </SheetPrimitive.Content>
171
+ </SheetPortal>
172
+ ));
173
+ SheetContent.displayName = SheetPrimitive.Content.displayName;
174
+
175
+ export interface SheetHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
176
+ /** Title + optional description. */
177
+ children?: React.ReactNode;
178
+ className?: string;
179
+ }
180
+
181
+ const SheetHeader = ({ className, ...props }: SheetHeaderProps) => (
182
+ <div className={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...props} />
183
+ );
184
+ SheetHeader.displayName = "SheetHeader";
185
+
186
+ export interface SheetFooterProps extends React.HTMLAttributes<HTMLDivElement> {
187
+ /** Action buttons. */
188
+ children?: React.ReactNode;
189
+ className?: string;
190
+ }
191
+
192
+ const SheetFooter = ({ className, ...props }: SheetFooterProps) => (
193
+ <div
194
+ className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
195
+ {...props}
196
+ />
197
+ );
198
+ SheetFooter.displayName = "SheetFooter";
199
+
200
+ export interface SheetTitleProps
201
+ extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title> {
202
+ /**
203
+ * Render as a Radix Slot.
204
+ * @default false
205
+ */
206
+ asChild?: boolean;
207
+ children?: React.ReactNode;
208
+ className?: string;
209
+ }
210
+
211
+ const SheetTitle = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Title>, SheetTitleProps>(
212
+ ({ className, ...props }, ref) => (
213
+ <SheetPrimitive.Title
214
+ ref={ref}
215
+ className={cn("text-lg font-semibold text-foreground", className)}
216
+ {...props}
217
+ />
218
+ ),
219
+ );
220
+ SheetTitle.displayName = SheetPrimitive.Title.displayName;
221
+
222
+ export interface SheetDescriptionProps
223
+ extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description> {
224
+ /**
225
+ * Render as a Radix Slot.
226
+ * @default false
227
+ */
228
+ asChild?: boolean;
229
+ children?: React.ReactNode;
230
+ className?: string;
231
+ }
232
+
233
+ const SheetDescription = React.forwardRef<
234
+ React.ElementRef<typeof SheetPrimitive.Description>,
235
+ SheetDescriptionProps
236
+ >(({ className, ...props }, ref) => (
237
+ <SheetPrimitive.Description
238
+ ref={ref}
239
+ className={cn("text-sm text-muted-foreground", className)}
240
+ {...props}
241
+ />
242
+ ));
243
+ SheetDescription.displayName = SheetPrimitive.Description.displayName;
244
+
245
+ export {
246
+ Sheet,
247
+ SheetClose,
248
+ SheetContent,
249
+ SheetDescription,
250
+ SheetFooter,
251
+ SheetHeader,
252
+ SheetOverlay,
253
+ SheetPortal,
254
+ SheetTitle,
255
+ SheetTrigger,
256
+ };