@shadow-js/ui 0.0.0-stage → 1.0.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.
- package/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README.md +598 -2
- package/dist/cli.mjs +2293 -0
- package/dist/dev/cli/schema.d.ts +73 -0
- package/dist/dev/index.d.ts +6 -0
- package/dist/dev/index.js +5 -0
- package/dist/dev/locales/ar.d.ts +141 -0
- package/dist/dev/locales/ar.js +128 -0
- package/dist/dev/locales/ar.js.map +1 -0
- package/dist/dev/locales/en.d.ts +141 -0
- package/dist/dev/locales/en.js +128 -0
- package/dist/dev/locales/en.js.map +1 -0
- package/dist/dev/registry/utils/utils.d.ts +29 -0
- package/dist/dev/registry/utils/utils.js +27 -0
- package/dist/dev/registry/utils/utils.js.map +1 -0
- package/dist/dev/theme/theme-logic.d.ts +187 -0
- package/dist/dev/theme/theme-logic.js +184 -0
- package/dist/dev/theme/theme-logic.js.map +1 -0
- package/dist/dev/theme/theme-provider.d.ts +90 -0
- package/dist/dev/theme/theme-provider.js +150 -0
- package/dist/dev/theme/theme-provider.js.map +1 -0
- package/dist/prod/index.js +1 -0
- package/dist/prod/locales/ar.js +2 -0
- package/dist/prod/locales/ar.js.map +1 -0
- package/dist/prod/locales/en.js +2 -0
- package/dist/prod/locales/en.js.map +1 -0
- package/dist/prod/registry/utils/utils.js +2 -0
- package/dist/prod/registry/utils/utils.js.map +1 -0
- package/dist/prod/theme/theme-logic.js +2 -0
- package/dist/prod/theme/theme-logic.js.map +1 -0
- package/dist/prod/theme/theme-provider.js +2 -0
- package/dist/prod/theme/theme-provider.js.map +1 -0
- package/package.json +102 -4
- package/registry/accordion/accordion.tsx +210 -0
- package/registry/accordion/item.json +4 -0
- package/registry/alert/alert.tsx +200 -0
- package/registry/alert/item.json +4 -0
- package/registry/alert-dialog/alert-dialog.tsx +530 -0
- package/registry/alert-dialog/item.json +4 -0
- package/registry/aspect-ratio/aspect-ratio.tsx +71 -0
- package/registry/aspect-ratio/item.json +4 -0
- package/registry/attachment/attachment.tsx +459 -0
- package/registry/attachment/item.json +4 -0
- package/registry/avatar/avatar.tsx +385 -0
- package/registry/avatar/item.json +4 -0
- package/registry/badge/badge.tsx +108 -0
- package/registry/badge/item.json +4 -0
- package/registry/breadcrumb/breadcrumb.tsx +354 -0
- package/registry/breadcrumb/item.json +4 -0
- package/registry/bubble/bubble.tsx +260 -0
- package/registry/bubble/item.json +4 -0
- package/registry/button/button.tsx +125 -0
- package/registry/button/item.json +4 -0
- package/registry/button-group/button-group.tsx +189 -0
- package/registry/button-group/item.json +4 -0
- package/registry/calendar/calendar.tsx +348 -0
- package/registry/calendar/item.json +4 -0
- package/registry/card/card.tsx +311 -0
- package/registry/card/item.json +4 -0
- package/registry/carousel/carousel.tsx +851 -0
- package/registry/carousel/item.json +4 -0
- package/registry/chart/chart.tsx +1956 -0
- package/registry/chart/item.json +4 -0
- package/registry/chart-scale/chart-scale.ts +670 -0
- package/registry/chart-scale/item.json +5 -0
- package/registry/checkbox/checkbox.tsx +79 -0
- package/registry/checkbox/item.json +4 -0
- package/registry/code-block/code-block.tsx +470 -0
- package/registry/code-block/item.json +4 -0
- package/registry/collapsible/collapsible.tsx +117 -0
- package/registry/collapsible/item.json +4 -0
- package/registry/combobox/combobox.tsx +977 -0
- package/registry/combobox/item.json +4 -0
- package/registry/command/command.tsx +757 -0
- package/registry/command/item.json +4 -0
- package/registry/context-menu/context-menu.tsx +697 -0
- package/registry/context-menu/item.json +4 -0
- package/registry/data-table/data-table.tsx +437 -0
- package/registry/data-table/item.json +4 -0
- package/registry/date-picker/date-picker.tsx +349 -0
- package/registry/date-picker/item.json +4 -0
- package/registry/dialog/dialog.tsx +412 -0
- package/registry/dialog/item.json +4 -0
- package/registry/direction/direction.tsx +88 -0
- package/registry/direction/item.json +4 -0
- package/registry/drawer/drawer.tsx +787 -0
- package/registry/drawer/item.json +4 -0
- package/registry/dropdown-menu/dropdown-menu.tsx +692 -0
- package/registry/dropdown-menu/item.json +4 -0
- package/registry/empty/empty.tsx +240 -0
- package/registry/empty/item.json +4 -0
- package/registry/field/field.tsx +624 -0
- package/registry/field/item.json +4 -0
- package/registry/form/form.tsx +1112 -0
- package/registry/form/item.json +4 -0
- package/registry/hover-card/hover-card.tsx +144 -0
- package/registry/hover-card/item.json +4 -0
- package/registry/icons/icons.tsx +1691 -0
- package/registry/icons/item.json +4 -0
- package/registry/input/input.tsx +43 -0
- package/registry/input/item.json +4 -0
- package/registry/input-group/input-group.tsx +315 -0
- package/registry/input-group/item.json +4 -0
- package/registry/input-otp/input-otp.tsx +329 -0
- package/registry/input-otp/item.json +4 -0
- package/registry/item/item.json +4 -0
- package/registry/item/item.tsx +439 -0
- package/registry/kbd/item.json +4 -0
- package/registry/kbd/kbd.tsx +65 -0
- package/registry/label/item.json +4 -0
- package/registry/label/label.tsx +60 -0
- package/registry/marker/item.json +4 -0
- package/registry/marker/marker.tsx +175 -0
- package/registry/menubar/item.json +4 -0
- package/registry/menubar/menubar.tsx +694 -0
- package/registry/message/item.json +4 -0
- package/registry/message/message.tsx +280 -0
- package/registry/message-scroller/item.json +4 -0
- package/registry/message-scroller/message-scroller.tsx +262 -0
- package/registry/native-select/item.json +4 -0
- package/registry/native-select/native-select.tsx +113 -0
- package/registry/navigation-menu/item.json +4 -0
- package/registry/navigation-menu/navigation-menu.tsx +362 -0
- package/registry/pagination/item.json +4 -0
- package/registry/pagination/pagination.tsx +460 -0
- package/registry/password-input/item.json +5 -0
- package/registry/password-input/password-input.tsx +494 -0
- package/registry/popover/item.json +4 -0
- package/registry/popover/popover.tsx +284 -0
- package/registry/progress/item.json +4 -0
- package/registry/progress/progress.tsx +190 -0
- package/registry/questionnaire/item.json +4 -0
- package/registry/questionnaire/questionnaire.tsx +569 -0
- package/registry/radio-group/item.json +4 -0
- package/registry/radio-group/radio-group.tsx +101 -0
- package/registry/resizable/item.json +4 -0
- package/registry/resizable/resizable.tsx +455 -0
- package/registry/scroll-area/item.json +4 -0
- package/registry/scroll-area/scroll-area.tsx +149 -0
- package/registry/select/item.json +4 -0
- package/registry/select/select.tsx +571 -0
- package/registry/separator/item.json +4 -0
- package/registry/separator/separator.tsx +52 -0
- package/registry/sheet/item.json +4 -0
- package/registry/sheet/sheet.tsx +476 -0
- package/registry/sidebar/item.json +4 -0
- package/registry/sidebar/sidebar.tsx +1870 -0
- package/registry/skeleton/item.json +4 -0
- package/registry/skeleton/skeleton.tsx +47 -0
- package/registry/slider/item.json +4 -0
- package/registry/slider/slider.tsx +149 -0
- package/registry/spinner/item.json +4 -0
- package/registry/spinner/spinner.tsx +51 -0
- package/registry/switch/item.json +4 -0
- package/registry/switch/switch.tsx +93 -0
- package/registry/table/item.json +4 -0
- package/registry/table/table.tsx +373 -0
- package/registry/tabs/item.json +4 -0
- package/registry/tabs/tabs.tsx +209 -0
- package/registry/textarea/item.json +4 -0
- package/registry/textarea/textarea.tsx +51 -0
- package/registry/toast/item.json +4 -0
- package/registry/toast/toast.tsx +949 -0
- package/registry/toggle/item.json +4 -0
- package/registry/toggle/toggle.tsx +110 -0
- package/registry/toggle-group/item.json +4 -0
- package/registry/toggle-group/toggle-group.tsx +189 -0
- package/registry/tooltip/item.json +4 -0
- package/registry/tooltip/tooltip.tsx +169 -0
- package/registry/trace/item.json +4 -0
- package/registry/trace/trace.tsx +356 -0
- package/registry/ui-strings/item.json +5 -0
- package/registry/ui-strings/ui-strings.tsx +454 -0
- package/registry/use-highlighted-code/item.json +5 -0
- package/registry/use-highlighted-code/use-highlighted-code.tsx +145 -0
- package/registry/use-mobile/item.json +5 -0
- package/registry/use-mobile/use-mobile.ts +46 -0
- package/registry/utils/item.json +5 -0
- package/registry/utils/utils.ts +38 -0
- package/registry.json +3274 -0
- package/styles/animations.css +321 -0
- package/styles/theme-core.css +55 -0
- package/styles/theme.css +12 -0
- package/styles/themes/gray.css +69 -0
- package/styles/themes/neutral.css +69 -0
- package/styles/themes/slate.css +69 -0
- package/styles/themes/stone.css +69 -0
- package/styles/themes/zinc.css +69 -0
- package/styles/typeset.css +251 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import { splitProps } from "@shadow-js/core";
|
|
2
|
+
import {
|
|
3
|
+
type DialogCloseProps,
|
|
4
|
+
type DialogContentProps,
|
|
5
|
+
type DialogDescriptionProps,
|
|
6
|
+
type DialogOverlayProps,
|
|
7
|
+
type DialogPortalProps,
|
|
8
|
+
Dialog as DialogPrimitive,
|
|
9
|
+
type DialogProps,
|
|
10
|
+
type DialogTitleProps,
|
|
11
|
+
type DialogTriggerProps,
|
|
12
|
+
type PolymorphicTarget,
|
|
13
|
+
} from "@shadow-js/primitives";
|
|
14
|
+
import type { ComponentProps, JSX } from "@shadow-js/web";
|
|
15
|
+
import { XIcon } from "@/components/ui/icons";
|
|
16
|
+
import { useUiStrings } from "@/lib/ui-strings";
|
|
17
|
+
import { cn } from "@/lib/utils";
|
|
18
|
+
|
|
19
|
+
/** The positioning, border and slide animation of each side. */
|
|
20
|
+
const SIDES: Record<SheetSide, string> = {
|
|
21
|
+
right:
|
|
22
|
+
"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",
|
|
23
|
+
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",
|
|
24
|
+
top: "inset-x-0 top-0 h-auto border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
|
25
|
+
bottom:
|
|
26
|
+
"inset-x-0 bottom-0 h-auto border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
|
27
|
+
start:
|
|
28
|
+
"inset-y-0 start-0 h-full w-3/4 border-e data-[state=closed]:ltr:slide-out-to-left data-[state=closed]:rtl:slide-out-to-right data-[state=open]:ltr:slide-in-from-left data-[state=open]:rtl:slide-in-from-right sm:max-w-sm",
|
|
29
|
+
end: "inset-y-0 end-0 h-full w-3/4 border-s data-[state=closed]:ltr:slide-out-to-right data-[state=closed]:rtl:slide-out-to-left data-[state=open]:ltr:slide-in-from-right data-[state=open]:rtl:slide-in-from-left sm:max-w-sm",
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The edge a {@link SheetContent} slides in from. `left` and `right` are the physical edges, as in
|
|
34
|
+
* shadcn/ui. `start` and `end` are the inline-start and inline-end edges, which swap in
|
|
35
|
+
* right-to-left layouts (the border, the position and the slide animation included).
|
|
36
|
+
* @since 1.0.0
|
|
37
|
+
* @see {@link SheetContent}
|
|
38
|
+
*/
|
|
39
|
+
export type SheetSide = "top" | "right" | "bottom" | "left" | "start" | "end";
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A modal panel that slides in from an edge of the screen, built on the dialog primitive. Put a
|
|
43
|
+
* {@link SheetTrigger} and a {@link SheetContent} inside it. Control it with `open` and
|
|
44
|
+
* `onOpenChange`, or start it open with `defaultOpen`.
|
|
45
|
+
*
|
|
46
|
+
* Keyboard and ARIA: focus moves into the sheet when it opens and returns to the trigger when it
|
|
47
|
+
* closes. Tab and Shift+Tab cycle inside the sheet. Escape closes it, and so does a press outside
|
|
48
|
+
* the panel (on the overlay). The panel is a `role="dialog"` with `aria-modal="true"`, named by its
|
|
49
|
+
* {@link SheetTitle} and described by its {@link SheetDescription}; while it is open the rest of the
|
|
50
|
+
* page is hidden from assistive technology. A sheet with no title needs an `aria-label` on its
|
|
51
|
+
* content to have a name.
|
|
52
|
+
*
|
|
53
|
+
* shadcn/ui differences: `as` replaces `asChild` on the trigger and the close buttons, and `class`
|
|
54
|
+
* replaces `className`. `side` also takes `"start"` and `"end"` for right-to-left layouts.
|
|
55
|
+
*
|
|
56
|
+
* @param props - The props: `open`, `defaultOpen` and `onOpenChange`, see {@link DialogProps}.
|
|
57
|
+
* @returns The dialog context around the sheet's parts. It renders no element of its own.
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* import { Button } from "@/components/ui/button";
|
|
61
|
+
* import {
|
|
62
|
+
* Sheet,
|
|
63
|
+
* SheetContent,
|
|
64
|
+
* SheetDescription,
|
|
65
|
+
* SheetHeader,
|
|
66
|
+
* SheetTitle,
|
|
67
|
+
* SheetTrigger,
|
|
68
|
+
* } from "@/components/ui/sheet";
|
|
69
|
+
*
|
|
70
|
+
* export function ProfileSheet() {
|
|
71
|
+
* return (
|
|
72
|
+
* <Sheet>
|
|
73
|
+
* <SheetTrigger as={Button} variant="outline">
|
|
74
|
+
* Edit profile
|
|
75
|
+
* </SheetTrigger>
|
|
76
|
+
* <SheetContent side="right">
|
|
77
|
+
* <SheetHeader>
|
|
78
|
+
* <SheetTitle>Edit profile</SheetTitle>
|
|
79
|
+
* <SheetDescription>Make changes to your profile here.</SheetDescription>
|
|
80
|
+
* </SheetHeader>
|
|
81
|
+
* </SheetContent>
|
|
82
|
+
* </Sheet>
|
|
83
|
+
* );
|
|
84
|
+
* }
|
|
85
|
+
* ```
|
|
86
|
+
* @since 1.0.0
|
|
87
|
+
* @see {@link SheetContent}
|
|
88
|
+
*/
|
|
89
|
+
function Sheet(props: DialogProps): JSX.Element {
|
|
90
|
+
return <DialogPrimitive {...props} />;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The button that opens the sheet. It renders a `button` by default; `as` renders another element,
|
|
95
|
+
* such as a shadcn/ui `Button`.
|
|
96
|
+
*
|
|
97
|
+
* Keyboard and ARIA: Enter and Space activate it. It has `aria-haspopup="dialog"`, `aria-expanded`
|
|
98
|
+
* (`"true"` while the sheet is open) and `aria-controls` pointing at the sheet.
|
|
99
|
+
*
|
|
100
|
+
* shadcn/ui differences: `as` replaces `asChild`, and `class` replaces `className`.
|
|
101
|
+
*
|
|
102
|
+
* @param props - The props: `as` and the attributes of the trigger element.
|
|
103
|
+
* @returns The trigger element.
|
|
104
|
+
* @example
|
|
105
|
+
* ```tsx
|
|
106
|
+
* import { Button } from "@/components/ui/button";
|
|
107
|
+
* import { Sheet, SheetContent, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
|
|
108
|
+
*
|
|
109
|
+
* export function MenuSheet() {
|
|
110
|
+
* return (
|
|
111
|
+
* <Sheet>
|
|
112
|
+
* <SheetTrigger as={Button}>Open</SheetTrigger>
|
|
113
|
+
* <SheetContent>
|
|
114
|
+
* <SheetTitle>Menu</SheetTitle>
|
|
115
|
+
* </SheetContent>
|
|
116
|
+
* </Sheet>
|
|
117
|
+
* );
|
|
118
|
+
* }
|
|
119
|
+
* ```
|
|
120
|
+
* @since 1.0.0
|
|
121
|
+
*/
|
|
122
|
+
function SheetTrigger<T extends PolymorphicTarget = "button">(
|
|
123
|
+
props: DialogTriggerProps<T>,
|
|
124
|
+
): JSX.Element {
|
|
125
|
+
return <DialogPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* A button that closes the sheet. It renders a `button` by default; `as` renders another element,
|
|
130
|
+
* such as a shadcn/ui `Button`.
|
|
131
|
+
*
|
|
132
|
+
* Keyboard and ARIA: Enter and Space close the sheet. Its name is its text; pass `aria-label` when
|
|
133
|
+
* the text is not descriptive.
|
|
134
|
+
*
|
|
135
|
+
* shadcn/ui differences: `as` replaces `asChild`, and `class` replaces `className`.
|
|
136
|
+
*
|
|
137
|
+
* @param props - The props: `as` and the attributes of the close element.
|
|
138
|
+
* @returns The close element.
|
|
139
|
+
* @example
|
|
140
|
+
* ```tsx
|
|
141
|
+
* import { Button } from "@/components/ui/button";
|
|
142
|
+
* import { Sheet, SheetClose, SheetContent, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
|
|
143
|
+
*
|
|
144
|
+
* export function CancelSheet() {
|
|
145
|
+
* return (
|
|
146
|
+
* <Sheet defaultOpen>
|
|
147
|
+
* <SheetContent>
|
|
148
|
+
* <SheetTitle>Discard changes</SheetTitle>
|
|
149
|
+
* <SheetClose as={Button} variant="outline">
|
|
150
|
+
* Cancel
|
|
151
|
+
* </SheetClose>
|
|
152
|
+
* </SheetContent>
|
|
153
|
+
* </Sheet>
|
|
154
|
+
* );
|
|
155
|
+
* }
|
|
156
|
+
* ```
|
|
157
|
+
* @since 1.0.0
|
|
158
|
+
*/
|
|
159
|
+
function SheetClose<T extends PolymorphicTarget = "button">(
|
|
160
|
+
props: DialogCloseProps<T>,
|
|
161
|
+
): JSX.Element {
|
|
162
|
+
return <DialogPrimitive.Close data-slot="sheet-close" {...props} />;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Renders the overlay and the content into `document.body` while the sheet is open. {@link SheetContent}
|
|
167
|
+
* already includes one, so you rarely render it yourself. A sheet that is open at render time is
|
|
168
|
+
* server-rendered as well.
|
|
169
|
+
*
|
|
170
|
+
* @param props - The props: `container`, `forceMount`, and `children`.
|
|
171
|
+
* @returns The portal, or nothing while the sheet is closed.
|
|
172
|
+
* @example
|
|
173
|
+
* ```tsx
|
|
174
|
+
* import { Sheet, SheetOverlay, SheetPortal } from "@/components/ui/sheet";
|
|
175
|
+
*
|
|
176
|
+
* export function BackdropOnly() {
|
|
177
|
+
* return (
|
|
178
|
+
* <Sheet defaultOpen>
|
|
179
|
+
* <SheetPortal>
|
|
180
|
+
* <SheetOverlay class="bg-black/70" />
|
|
181
|
+
* </SheetPortal>
|
|
182
|
+
* </Sheet>
|
|
183
|
+
* );
|
|
184
|
+
* }
|
|
185
|
+
* ```
|
|
186
|
+
* @since 1.0.0
|
|
187
|
+
*/
|
|
188
|
+
function SheetPortal(props: DialogPortalProps): JSX.Element {
|
|
189
|
+
return <DialogPrimitive.Portal {...props} />;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* The dimmed backdrop behind the sheet. Pressing it closes the sheet.
|
|
194
|
+
*
|
|
195
|
+
* Keyboard and ARIA: `aria-hidden="true"`, and no keys, so assistive technology skips it.
|
|
196
|
+
*
|
|
197
|
+
* shadcn/ui differences: `class` replaces `className`. Its default is `bg-black/50`.
|
|
198
|
+
*
|
|
199
|
+
* @param props - The props: `class`, and the attributes of the overlay element.
|
|
200
|
+
* @returns The overlay element.
|
|
201
|
+
* @example
|
|
202
|
+
* ```tsx
|
|
203
|
+
* import { Sheet, SheetOverlay, SheetPortal } from "@/components/ui/sheet";
|
|
204
|
+
*
|
|
205
|
+
* export function DarkBackdrop() {
|
|
206
|
+
* return (
|
|
207
|
+
* <Sheet defaultOpen>
|
|
208
|
+
* <SheetPortal>
|
|
209
|
+
* <SheetOverlay class="bg-black/70" />
|
|
210
|
+
* </SheetPortal>
|
|
211
|
+
* </Sheet>
|
|
212
|
+
* );
|
|
213
|
+
* }
|
|
214
|
+
* ```
|
|
215
|
+
* @since 1.0.0
|
|
216
|
+
* @see {@link SheetPortal}
|
|
217
|
+
*/
|
|
218
|
+
function SheetOverlay(props: DialogOverlayProps): JSX.Element {
|
|
219
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
220
|
+
return (
|
|
221
|
+
<DialogPrimitive.Overlay
|
|
222
|
+
data-slot="sheet-overlay"
|
|
223
|
+
class={cn(
|
|
224
|
+
"fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
|
|
225
|
+
local.class,
|
|
226
|
+
)}
|
|
227
|
+
{...rest}
|
|
228
|
+
/>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Own props of {@link SheetContent}.
|
|
234
|
+
* @since 1.0.0
|
|
235
|
+
* @see {@link SheetContent}
|
|
236
|
+
*/
|
|
237
|
+
export interface SheetContentExtraProps {
|
|
238
|
+
/**
|
|
239
|
+
* The edge the sheet slides in from.
|
|
240
|
+
* @default "right"
|
|
241
|
+
*/
|
|
242
|
+
readonly side?: SheetSide | undefined;
|
|
243
|
+
/**
|
|
244
|
+
* Show the close button in the corner.
|
|
245
|
+
* @default true
|
|
246
|
+
*/
|
|
247
|
+
readonly showCloseButton?: boolean | undefined;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* The sheet panel: the portal, the overlay, and the content anchored to `side`. It holds the
|
|
252
|
+
* header, the body and the footer. A close button sits in the top corner on the end edge unless
|
|
253
|
+
* `showCloseButton` is `false`.
|
|
254
|
+
*
|
|
255
|
+
* Keyboard and ARIA: see {@link Sheet}. The panel is a `role="dialog"`. The close button is named
|
|
256
|
+
* "Close" (a visually hidden label) and closes the sheet on Enter or Space.
|
|
257
|
+
*
|
|
258
|
+
* shadcn/ui differences: `side` also takes `"start"` and `"end"`, and `showCloseButton` (default
|
|
259
|
+
* `true`) removes the built-in close button when `false`.
|
|
260
|
+
*
|
|
261
|
+
* @param props - The props: `side`, `showCloseButton`, and the attributes of the dialog content.
|
|
262
|
+
* @returns The portal, with the overlay and the content inside.
|
|
263
|
+
* @example
|
|
264
|
+
* ```tsx
|
|
265
|
+
* import { Sheet, SheetContent, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
|
|
266
|
+
*
|
|
267
|
+
* export function MenuSheet() {
|
|
268
|
+
* return (
|
|
269
|
+
* <Sheet>
|
|
270
|
+
* <SheetTrigger>Menu</SheetTrigger>
|
|
271
|
+
* <SheetContent side="left" showCloseButton={false}>
|
|
272
|
+
* <SheetTitle>Menu</SheetTitle>
|
|
273
|
+
* </SheetContent>
|
|
274
|
+
* </Sheet>
|
|
275
|
+
* );
|
|
276
|
+
* }
|
|
277
|
+
* ```
|
|
278
|
+
* @since 1.0.0
|
|
279
|
+
*/
|
|
280
|
+
function SheetContent(props: DialogContentProps & SheetContentExtraProps): JSX.Element {
|
|
281
|
+
const [local, rest] = splitProps(props, ["class", "children", "side", "showCloseButton"]);
|
|
282
|
+
const t = useUiStrings();
|
|
283
|
+
return (
|
|
284
|
+
<SheetPortal>
|
|
285
|
+
<SheetOverlay />
|
|
286
|
+
<DialogPrimitive.Content
|
|
287
|
+
data-slot="sheet-content"
|
|
288
|
+
class={cn(
|
|
289
|
+
"fixed z-50 flex flex-col gap-4 bg-background shadow-lg transition ease-in-out outline-none motion-reduce:transition-none data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500",
|
|
290
|
+
SIDES[local.side ?? "right"],
|
|
291
|
+
local.class,
|
|
292
|
+
)}
|
|
293
|
+
{...rest}
|
|
294
|
+
>
|
|
295
|
+
{local.children}
|
|
296
|
+
{local.showCloseButton !== false && (
|
|
297
|
+
<DialogPrimitive.Close
|
|
298
|
+
data-slot="sheet-close"
|
|
299
|
+
class="absolute end-4 top-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 outline-none focus:outline-solid focus:outline-2 focus:outline-offset-2 focus:outline-transparent disabled:pointer-events-none data-[state=open]:bg-secondary motion-reduce:transition-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
|
300
|
+
>
|
|
301
|
+
<XIcon />
|
|
302
|
+
<span class="sr-only">{t("sheet.close", "Close")}</span>
|
|
303
|
+
</DialogPrimitive.Close>
|
|
304
|
+
)}
|
|
305
|
+
</DialogPrimitive.Content>
|
|
306
|
+
</SheetPortal>
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* The layout of the title and the description at the top of the sheet.
|
|
312
|
+
*
|
|
313
|
+
* Keyboard and ARIA: no keys and no role of its own.
|
|
314
|
+
*
|
|
315
|
+
* shadcn/ui differences: `class` replaces `className`.
|
|
316
|
+
*
|
|
317
|
+
* @param props - The props: the attributes of the `div`, and `class`.
|
|
318
|
+
* @returns The header `div`.
|
|
319
|
+
* @example
|
|
320
|
+
* ```tsx
|
|
321
|
+
* import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
|
|
322
|
+
*
|
|
323
|
+
* export function Header() {
|
|
324
|
+
* return (
|
|
325
|
+
* <Sheet>
|
|
326
|
+
* <SheetTrigger>Open</SheetTrigger>
|
|
327
|
+
* <SheetContent>
|
|
328
|
+
* <SheetHeader>
|
|
329
|
+
* <SheetTitle>Edit profile</SheetTitle>
|
|
330
|
+
* <SheetDescription>Make changes to your profile here.</SheetDescription>
|
|
331
|
+
* </SheetHeader>
|
|
332
|
+
* </SheetContent>
|
|
333
|
+
* </Sheet>
|
|
334
|
+
* );
|
|
335
|
+
* }
|
|
336
|
+
* ```
|
|
337
|
+
* @since 1.0.0
|
|
338
|
+
*/
|
|
339
|
+
function SheetHeader(props: ComponentProps<"div">): JSX.Element {
|
|
340
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
341
|
+
return (
|
|
342
|
+
<div data-slot="sheet-header" class={cn("flex flex-col gap-1.5 p-4", local.class)} {...rest} />
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* The layout of the action buttons at the bottom of the sheet. It is pushed to the bottom of the
|
|
348
|
+
* panel.
|
|
349
|
+
*
|
|
350
|
+
* Keyboard and ARIA: no keys and no role of its own.
|
|
351
|
+
*
|
|
352
|
+
* shadcn/ui differences: `class` replaces `className`.
|
|
353
|
+
*
|
|
354
|
+
* @param props - The props: the attributes of the `div`, and `class`.
|
|
355
|
+
* @returns The footer `div`.
|
|
356
|
+
* @example
|
|
357
|
+
* ```tsx
|
|
358
|
+
* import { Button } from "@/components/ui/button";
|
|
359
|
+
* import { Sheet, SheetClose, SheetContent, SheetFooter, SheetTrigger } from "@/components/ui/sheet";
|
|
360
|
+
*
|
|
361
|
+
* export function Actions() {
|
|
362
|
+
* return (
|
|
363
|
+
* <Sheet>
|
|
364
|
+
* <SheetTrigger>Open</SheetTrigger>
|
|
365
|
+
* <SheetContent>
|
|
366
|
+
* <SheetFooter>
|
|
367
|
+
* <SheetClose as={Button}>Save</SheetClose>
|
|
368
|
+
* </SheetFooter>
|
|
369
|
+
* </SheetContent>
|
|
370
|
+
* </Sheet>
|
|
371
|
+
* );
|
|
372
|
+
* }
|
|
373
|
+
* ```
|
|
374
|
+
* @since 1.0.0
|
|
375
|
+
*/
|
|
376
|
+
function SheetFooter(props: ComponentProps<"div">): JSX.Element {
|
|
377
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
378
|
+
return (
|
|
379
|
+
<div
|
|
380
|
+
data-slot="sheet-footer"
|
|
381
|
+
class={cn("mt-auto flex flex-col gap-2 p-4", local.class)}
|
|
382
|
+
{...rest}
|
|
383
|
+
/>
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* The title of the sheet. It is the sheet's accessible name, so give every sheet a title.
|
|
389
|
+
*
|
|
390
|
+
* Keyboard and ARIA: no keys. The sheet's `aria-labelledby` points at this title.
|
|
391
|
+
*
|
|
392
|
+
* shadcn/ui differences: `class` replaces `className`.
|
|
393
|
+
*
|
|
394
|
+
* @param props - The props: the attributes of the title element, and `class`.
|
|
395
|
+
* @returns The title element.
|
|
396
|
+
* @example
|
|
397
|
+
* ```tsx
|
|
398
|
+
* import { Sheet, SheetContent, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
|
|
399
|
+
*
|
|
400
|
+
* export function TitledSheet() {
|
|
401
|
+
* return (
|
|
402
|
+
* <Sheet>
|
|
403
|
+
* <SheetTrigger>Open</SheetTrigger>
|
|
404
|
+
* <SheetContent>
|
|
405
|
+
* <SheetTitle>Edit profile</SheetTitle>
|
|
406
|
+
* </SheetContent>
|
|
407
|
+
* </Sheet>
|
|
408
|
+
* );
|
|
409
|
+
* }
|
|
410
|
+
* ```
|
|
411
|
+
* @since 1.0.0
|
|
412
|
+
* @see {@link SheetDescription}
|
|
413
|
+
*/
|
|
414
|
+
function SheetTitle(props: DialogTitleProps): JSX.Element {
|
|
415
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
416
|
+
return (
|
|
417
|
+
<DialogPrimitive.Title
|
|
418
|
+
data-slot="sheet-title"
|
|
419
|
+
class={cn("font-semibold text-foreground", local.class)}
|
|
420
|
+
{...rest}
|
|
421
|
+
/>
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* The description of the sheet, read after its title.
|
|
427
|
+
*
|
|
428
|
+
* Keyboard and ARIA: no keys. The sheet's `aria-describedby` points at this description while it is
|
|
429
|
+
* rendered.
|
|
430
|
+
*
|
|
431
|
+
* shadcn/ui differences: `class` replaces `className`.
|
|
432
|
+
*
|
|
433
|
+
* @param props - The props: the attributes of the description element, and `class`.
|
|
434
|
+
* @returns The description element.
|
|
435
|
+
* @example
|
|
436
|
+
* ```tsx
|
|
437
|
+
* import { Sheet, SheetContent, SheetDescription, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
|
|
438
|
+
*
|
|
439
|
+
* export function DescribedSheet() {
|
|
440
|
+
* return (
|
|
441
|
+
* <Sheet>
|
|
442
|
+
* <SheetTrigger>Open</SheetTrigger>
|
|
443
|
+
* <SheetContent>
|
|
444
|
+
* <SheetTitle>Edit profile</SheetTitle>
|
|
445
|
+
* <SheetDescription>Make changes here.</SheetDescription>
|
|
446
|
+
* </SheetContent>
|
|
447
|
+
* </Sheet>
|
|
448
|
+
* );
|
|
449
|
+
* }
|
|
450
|
+
* ```
|
|
451
|
+
* @since 1.0.0
|
|
452
|
+
* @see {@link SheetTitle}
|
|
453
|
+
*/
|
|
454
|
+
function SheetDescription(props: DialogDescriptionProps): JSX.Element {
|
|
455
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
456
|
+
return (
|
|
457
|
+
<DialogPrimitive.Description
|
|
458
|
+
data-slot="sheet-description"
|
|
459
|
+
class={cn("text-sm text-muted-foreground", local.class)}
|
|
460
|
+
{...rest}
|
|
461
|
+
/>
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
export {
|
|
466
|
+
Sheet,
|
|
467
|
+
SheetClose,
|
|
468
|
+
SheetContent,
|
|
469
|
+
SheetDescription,
|
|
470
|
+
SheetFooter,
|
|
471
|
+
SheetHeader,
|
|
472
|
+
SheetOverlay,
|
|
473
|
+
SheetPortal,
|
|
474
|
+
SheetTitle,
|
|
475
|
+
SheetTrigger,
|
|
476
|
+
};
|