aural-ui 4.0.1 → 4.2.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/README.md +8 -1
- package/dist/components/aspect-ratio/AspectRatio.stories.tsx +290 -1228
- package/dist/components/avatar/Avatar.stories.tsx +219 -235
- package/dist/components/badge/Badge.stories.tsx +379 -116
- package/dist/components/banner/Banner.stories.tsx +445 -391
- package/dist/components/breadcrumb/Breadcrumb.stories.tsx +453 -199
- package/dist/components/button/Button.stories.tsx +585 -230
- package/dist/components/card/Card.stories.tsx +619 -301
- package/dist/components/char-count/CharCount.stories.tsx +350 -248
- package/dist/components/checkbox/Checkbox.stories.tsx +309 -167
- package/dist/components/chip/Chip.stories.tsx +362 -168
- package/dist/components/circular-loader/CircularLoader.stories.tsx +221 -636
- package/dist/components/clamp-lines/ClampLines.stories.tsx +246 -117
- package/dist/components/collapsible/Collapsible.stories.tsx +391 -252
- package/dist/components/command/Command.stories.tsx +530 -867
- package/dist/components/dialog/Dialog.stories.tsx +501 -950
- package/dist/components/divider/Divider.stories.tsx +264 -527
- package/dist/components/dot-loader/DotLoader.stories.tsx +256 -257
- package/dist/components/drawer/Drawer.stories.tsx +659 -1023
- package/dist/components/dropdown/Dropdown.stories.tsx +643 -1028
- package/dist/components/form/Form.stories.tsx +560 -274
- package/dist/components/helper-text/HelperText.stories.tsx +199 -200
- package/dist/components/hover-card/HoverCard.stories.tsx +318 -1254
- package/dist/components/icon-button/IconButton.stories.tsx +837 -194
- package/dist/components/if-else/if-else.stories.tsx +370 -83
- package/dist/components/input/Input.stories.tsx +436 -368
- package/dist/components/label/Label.stories.tsx +156 -154
- package/dist/components/list/List.stories.tsx +484 -835
- package/dist/components/marquee/Marquee.stories.tsx +356 -712
- package/dist/components/otp-inputs/OtpInputs.stories.tsx +352 -422
- package/dist/components/overlay/Overlay.stories.tsx +452 -824
- package/dist/components/pagination/Pagination.stories.tsx +721 -210
- package/dist/components/popover/Popover.stories.tsx +481 -896
- package/dist/components/radio/Radio.stories.tsx +432 -124
- package/dist/components/resizable/Resizable.stories.tsx +495 -799
- package/dist/components/scroll-area/ScrollArea.stories.tsx +383 -1059
- package/dist/components/search/Search.stories.tsx +312 -595
- package/dist/components/select/Select.stories.tsx +684 -789
- package/dist/components/sheet/Sheet.stories.tsx +671 -950
- package/dist/components/skelton/Skelton.stories.tsx +230 -764
- package/dist/components/slider/Slider.stories.tsx +383 -760
- package/dist/components/stepper/Stepper.stories.tsx +371 -514
- package/dist/components/switch/Switch.stories.tsx +461 -208
- package/dist/components/switch-case/SwitchCase.stories.tsx +367 -188
- package/dist/components/table/Table.stories.tsx +770 -916
- package/dist/components/tabs/Tabs.stories.tsx +458 -1455
- package/dist/components/tag/Tag.stories.tsx +714 -542
- package/dist/components/textarea/TextArea.stories.tsx +621 -562
- package/dist/components/thumbnail-tags/ThumbnailTags.stories.tsx +228 -154
- package/dist/components/toast/Toast.stories.tsx +452 -1339
- package/dist/components/toggle/Toggle.stories.tsx +488 -931
- package/dist/components/tooltip/Tooltip.stories.tsx +344 -1388
- package/dist/components/typography/Typography.stories.tsx +406 -89
- package/dist/hooks/use-change-state/UseChangeState.stories.tsx +309 -606
- package/dist/hooks/use-previous/UsePrevious.stories.tsx +367 -917
- package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +639 -867
- package/dist/icons/Icons.stories.tsx +0 -12
- package/dist/icons/ai-avatar-icon/AiAvatarIcon.stories.tsx +223 -1060
- package/dist/icons/alert-icon/AlertIcon.stories.tsx +106 -968
- package/dist/icons/all-icons.tsx +37 -16
- package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +137 -1010
- package/dist/icons/apple-logo-icon/AppleLogoIcon.stories.tsx +145 -935
- package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +132 -1046
- package/dist/icons/arrow-corner-up-left-icon/ArrowCornerUpLeftIcon.stories.tsx +134 -986
- package/dist/icons/arrow-corner-up-right-icon/ArrowCornerUpRightIcon.stories.tsx +135 -1028
- package/dist/icons/arrow-left-icon/ArrowLeftIcon.stories.tsx +133 -971
- package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +145 -1123
- package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +143 -1252
- package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +123 -632
- package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +141 -1223
- package/dist/icons/backward-ten-seconds-icon/BackwardTenSecondsIcon.stories.tsx +164 -1018
- package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +121 -1236
- package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +121 -1213
- package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +116 -893
- package/dist/icons/camera-icon/CameraIcon.stories.tsx +109 -1254
- package/dist/icons/capital-a-letter-icon/CapitalALetterIcon.stories.tsx +114 -975
- package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +157 -994
- package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +160 -992
- package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +140 -970
- package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +126 -993
- package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +144 -987
- package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +141 -1007
- package/dist/icons/circle-tick-icon/CircleTickIcon.stories.tsx +147 -1187
- package/dist/icons/circular-play-icon/CircularPlayIcon.stories.tsx +110 -476
- package/dist/icons/coin-icon/CoinIcon.stories.tsx +120 -1364
- package/dist/icons/coin-toons-icon/CoinToonsIcon.stories.tsx +113 -1360
- package/dist/icons/column-wide-add-icon/ColumnWideAddIcon.stories.tsx +111 -942
- package/dist/icons/command-icon/CommandIcon.stories.tsx +124 -1087
- package/dist/icons/copy-icon/CopyIcon.stories.tsx +119 -996
- package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +144 -1046
- package/dist/icons/cross-icon/CrossIcon.stories.tsx +136 -999
- package/dist/icons/download-icon/DownloadIcon.stories.tsx +123 -857
- package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +121 -1080
- package/dist/icons/email-icon/EmailIcon.stories.tsx +112 -979
- package/dist/icons/expand-icon/ExpandIcon.stories.tsx +109 -1146
- package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +141 -1068
- package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +140 -1081
- package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +124 -1050
- package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +123 -1091
- package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +122 -633
- package/dist/icons/filter-bar-row-icon/FilterBarRowIcon.stories.tsx +116 -1087
- package/dist/icons/forward-ten-seconds-icon/ForwardTenSecondsIcon.stories.tsx +166 -1020
- package/dist/icons/git-branch-icon/GitBranchIcon.stories.tsx +112 -1182
- package/dist/icons/git-fork-icon/GitForkIcon.stories.tsx +112 -1155
- package/dist/icons/globe-icon/GlobeIcon.stories.tsx +127 -325
- package/dist/icons/google-logo-icon/GoogleLogoIcon.stories.tsx +142 -985
- package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +116 -1217
- package/dist/icons/head-icon/HeadIcon.stories.tsx +108 -953
- package/dist/icons/heart-icon/HeartIcon.stories.tsx +117 -1060
- package/dist/icons/image-avatar-sparkle-icon/ImageAvatarSparkleIcon.stories.tsx +116 -716
- package/dist/icons/image-icon/ImageIcon.stories.tsx +102 -1164
- package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +108 -1233
- package/dist/icons/import-left-arrow-folder-icon/ImportLeftArrowFolderIcon.stories.tsx +133 -1289
- package/dist/icons/indian-flag-icon/IndianFlagIcon.stories.tsx +155 -1012
- package/dist/icons/instagram-icon/InstagramIcon.stories.tsx +158 -1438
- package/dist/icons/layout-column-icon/LayoutColumnIcon.stories.tsx +121 -1011
- package/dist/icons/layout-left-icon/LayoutLeftIcon.stories.tsx +116 -981
- package/dist/icons/layout-right-icon/LayoutRightIcon.stories.tsx +116 -979
- package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +105 -1252
- package/dist/icons/linked-in-icon/LinkedInIcon.stories.tsx +151 -1554
- package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +107 -1227
- package/dist/icons/magic-edit-icon/MagicEditIcon.stories.tsx +116 -707
- package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +119 -1226
- package/dist/icons/message-icon/MessageIcon.stories.tsx +111 -557
- package/dist/icons/minimize-icon/MinimizeIcon.stories.tsx +112 -1198
- package/dist/icons/moon-icon/MoonIcon.stories.tsx +117 -557
- package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +106 -1235
- package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +112 -1185
- package/dist/icons/musical-note-icon/MusicalNoteIcon.stories.tsx +116 -1012
- package/dist/icons/notepad-icon/NotepadIcon.stories.tsx +108 -1137
- package/dist/icons/notes-icon/NotesIcon.stories.tsx +116 -1138
- package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +106 -1146
- package/dist/icons/page-text-icon/PageTextIcon.stories.tsx +119 -719
- package/dist/icons/paint-roll-icon/PaintRollIcon.stories.tsx +110 -999
- package/dist/icons/paper-plane-icon/PaperPlaneIcon.stories.tsx +109 -912
- package/dist/icons/pause-icon/PauseIcon.stories.tsx +110 -1041
- package/dist/icons/pencil-icon/PencilIcon.stories.tsx +112 -1109
- package/dist/icons/phone-icon/PhoneIcon.stories.tsx +112 -1023
- package/dist/icons/plus-icon/PlusIcon.stories.tsx +103 -1132
- package/dist/icons/pocket-studio-icon/PocketStudioIcon.stories.tsx +104 -870
- package/dist/icons/scroll-down-icon/ScrollDownIcon.stories.tsx +99 -476
- package/dist/icons/search-icon/SearchIcon.stories.tsx +108 -1161
- package/dist/icons/setting-icon/SettingIcon.stories.tsx +104 -1009
- package/dist/icons/share-icon/ShareIcon.stories.tsx +117 -1064
- package/dist/icons/shield-icon/ShieldIcon.stories.tsx +114 -974
- package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +134 -1160
- package/dist/icons/skip-backward-icon/SkipBackwardIcon.stories.tsx +169 -1017
- package/dist/icons/skip-forward-icon/SkipForwardIcon.stories.tsx +161 -1016
- package/dist/icons/sparkles-soft-icon/SparklesSoftIcon.stories.tsx +102 -1001
- package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +155 -593
- package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +155 -608
- package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +142 -712
- package/dist/icons/star-icon/StarIcon.stories.tsx +120 -946
- package/dist/icons/store-coin-icon/StoreCoinIcon.stories.tsx +109 -1013
- package/dist/icons/suggestion-icon/SuggestionIcon.stories.tsx +113 -891
- package/dist/icons/sun-icon/SunIcon.stories.tsx +117 -864
- package/dist/icons/text-color-icon/TextColorIcon.stories.tsx +113 -989
- package/dist/icons/text-indicator-icon/TextIndicatorIcon.stories.tsx +120 -1027
- package/dist/icons/threads-icon/ThreadsIcon.stories.tsx +153 -1476
- package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +143 -1187
- package/dist/icons/tick-icon/TickIcon.stories.tsx +142 -1322
- package/dist/icons/trash-icon/TrashIcon.stories.tsx +105 -970
- package/dist/icons/twitter-x-icon/TwitterXIcon.stories.tsx +154 -1457
- package/dist/icons/upload-icon/UploadIcon.stories.tsx +112 -930
- package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +115 -1019
- package/dist/icons/video-play-list-icon/VideoPlaylistIcon.stories.tsx +122 -1092
- package/dist/icons/voice-playing-icon/VoicePlayingIcon.stories.tsx +120 -1401
- package/dist/icons/volume-full-icon/VolumeFullIcon.stories.tsx +107 -1212
- package/dist/icons/volume-half-icon/VolumeHalfIcon.stories.tsx +109 -1122
- package/dist/icons/volume-off-icon/VolumeOffIcon.stories.tsx +112 -1124
- package/dist/icons/warning-icon/WarningIcon.stories.tsx +119 -1083
- package/dist/icons/youtube-icon/YoutubeIcon.stories.tsx +158 -983
- package/dist/index.cjs +90 -90
- package/dist/index.js +90 -90
- package/package.json +8 -3
|
@@ -4,18 +4,16 @@ import { Button } from "@components/button"
|
|
|
4
4
|
import { Checkbox } from "@components/checkbox"
|
|
5
5
|
import Input from "@components/input"
|
|
6
6
|
import { Label } from "@components/label"
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from "@components/select"
|
|
14
|
-
import Textarea from "@components/textarea"
|
|
15
|
-
import { CrossIcon } from "@icons/cross-icon"
|
|
16
|
-
import { EditBigIcon } from "@icons/edit-big-icon"
|
|
7
|
+
import { ChevronRightIcon } from "@icons/chevron-right-icon"
|
|
8
|
+
import { MaintenanceIcon } from "@icons/maintenance-icon"
|
|
9
|
+
import { MusicalNoteIcon } from "@icons/musical-note-icon"
|
|
10
|
+
import { SearchIcon } from "@icons/search-icon"
|
|
11
|
+
import { SiteLogoIcon } from "@icons/site-logo-icon"
|
|
12
|
+
import { TickCircleIcon } from "@icons/tick-circle-icon"
|
|
17
13
|
import type { Meta, StoryObj } from "@storybook/react-vite"
|
|
18
14
|
|
|
15
|
+
import { AuralComponentDocsPage } from "src/ui/story-spec/components/component-story-docs-page"
|
|
16
|
+
|
|
19
17
|
import {
|
|
20
18
|
Drawer,
|
|
21
19
|
DrawerClose,
|
|
@@ -27,194 +25,50 @@ import {
|
|
|
27
25
|
DrawerTrigger,
|
|
28
26
|
} from "."
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
+
const meta: Meta<any> = {
|
|
31
30
|
title: "Components/UI/Drawer",
|
|
32
31
|
component: Drawer,
|
|
33
32
|
parameters: {
|
|
34
33
|
layout: "centered",
|
|
35
|
-
backgrounds: {
|
|
36
|
-
default: "dark",
|
|
37
|
-
values: [
|
|
38
|
-
{ name: "dark", value: "#0a0a0a" },
|
|
39
|
-
{ name: "light", value: "#ffffff" },
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
34
|
docs: {
|
|
43
35
|
description: {
|
|
44
|
-
component:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
A slide-out drawer component built on Vaul primitives with support for multiple directions, smooth animations, customizable content sections, and enhanced accessibility features.
|
|
48
|
-
|
|
49
|
-
## Features
|
|
50
|
-
|
|
51
|
-
- **Multiple Directions**: Top, bottom, left, and right slide directions
|
|
52
|
-
- **Multiple Variants**: Neutral and gradient styles with custom styling
|
|
53
|
-
- **Custom Overlays**: Configurable opacity, glass effect, and noise texture
|
|
54
|
-
- **Smooth Animations**: Fade in/out animations for overlay and content with customizable duration
|
|
55
|
-
- **Accessible**: Full keyboard navigation, screen reader support, and focus management
|
|
56
|
-
- **Flexible Content**: Header, footer, and body sections with custom styling
|
|
57
|
-
- **Portal Rendering**: Renders outside normal DOM hierarchy for proper layering
|
|
58
|
-
- **Focus Management**: Automatic focus trapping and restoration
|
|
59
|
-
- **Responsive Design**: Adapts to different screen sizes with mobile-first approach
|
|
60
|
-
- **Drag Support**: Built-in drag gestures for intuitive interaction
|
|
61
|
-
- **Nested Support**: Support for nested drawers with proper z-index management
|
|
62
|
-
|
|
63
|
-
## Directions
|
|
64
|
-
|
|
65
|
-
The drawer can slide from different directions using the \`direction\` prop:
|
|
66
|
-
|
|
67
|
-
- **Bottom** (default): Slides up from the bottom - ideal for mobile navigation
|
|
68
|
-
- **Top**: Slides down from the top - useful for notifications or quick actions
|
|
69
|
-
- **Left**: Slides in from the left - perfect for navigation menus
|
|
70
|
-
- **Right**: Slides in from the right - great for settings or detail panels
|
|
71
|
-
|
|
72
|
-
## Usage Examples
|
|
73
|
-
|
|
74
|
-
### Basic Drawer with Direction Configuration
|
|
75
|
-
\`\`\`tsx
|
|
76
|
-
import { Drawer, DrawerContent, DrawerTrigger } from '@/components/drawer'
|
|
77
|
-
|
|
78
|
-
// Bottom drawer (default)
|
|
79
|
-
<Drawer>
|
|
80
|
-
<DrawerTrigger asChild>
|
|
81
|
-
<Button>Open Bottom Drawer</Button>
|
|
82
|
-
</DrawerTrigger>
|
|
83
|
-
<DrawerContent>
|
|
84
|
-
Content slides up from bottom
|
|
85
|
-
</DrawerContent>
|
|
86
|
-
</Drawer>
|
|
87
|
-
|
|
88
|
-
// Top drawer
|
|
89
|
-
<Drawer>
|
|
90
|
-
<DrawerTrigger asChild>
|
|
91
|
-
<Button>Open Top Drawer</Button>
|
|
92
|
-
</DrawerTrigger>
|
|
93
|
-
<DrawerContent>
|
|
94
|
-
Content slides down from top
|
|
95
|
-
</DrawerContent>
|
|
96
|
-
</Drawer>
|
|
97
|
-
|
|
98
|
-
// Left drawer
|
|
99
|
-
<Drawer>
|
|
100
|
-
<DrawerTrigger asChild>
|
|
101
|
-
<Button>Open Left Drawer</Button>
|
|
102
|
-
</DrawerTrigger>
|
|
103
|
-
<DrawerContent>
|
|
104
|
-
Content slides in from left
|
|
105
|
-
</DrawerContent>
|
|
106
|
-
</Drawer>
|
|
107
|
-
|
|
108
|
-
// Right drawer
|
|
109
|
-
<Drawer>
|
|
110
|
-
<DrawerTrigger asChild>
|
|
111
|
-
<Button>Open Right Drawer</Button>
|
|
112
|
-
</DrawerTrigger>
|
|
113
|
-
<DrawerContent>
|
|
114
|
-
Content slides in from right
|
|
115
|
-
</DrawerContent>
|
|
116
|
-
</Drawer>
|
|
117
|
-
|
|
118
|
-
### Drawer with Custom Overlay Effects
|
|
119
|
-
\`\`\`tsx
|
|
120
|
-
<Drawer>
|
|
121
|
-
<DrawerTrigger asChild>
|
|
122
|
-
<Button>Open Drawer with Custom Overlay</Button>
|
|
123
|
-
</DrawerTrigger>
|
|
124
|
-
<DrawerContent
|
|
125
|
-
noise="high"
|
|
126
|
-
opacity="medium"
|
|
127
|
-
glass="low"
|
|
128
|
-
>
|
|
129
|
-
Content with custom overlay effects
|
|
130
|
-
</DrawerContent>
|
|
131
|
-
</Drawer>
|
|
132
|
-
\`\`\`
|
|
133
|
-
|
|
134
|
-
### Overlay Configuration
|
|
135
|
-
|
|
136
|
-
The drawer supports configurable overlay effects through the \`opacity\`, \`glass\`, and \`noise\` props:
|
|
137
|
-
|
|
138
|
-
- **opacity**: Controls background dimming level
|
|
139
|
-
- \`"high"\` - Strong dimming (80%)
|
|
140
|
-
- \`"medium"\` - Balanced dimming (60%) - default
|
|
141
|
-
- \`"low"\` - Subtle dimming (40%)
|
|
142
|
-
- \`"none"\` - No dimming (100% coverage)
|
|
143
|
-
|
|
144
|
-
- **glass**: Controls backdrop blur effect
|
|
145
|
-
- \`"high"\` - Strong blur effect
|
|
146
|
-
- \`"medium"\` - Balanced blur effect
|
|
147
|
-
- \`"low"\` - Subtle blur effect - default
|
|
148
|
-
- \`"none"\` - No blur effect
|
|
149
|
-
|
|
150
|
-
- **noise**: Controls texture overlay
|
|
151
|
-
- \`"high"\` - Strong texture pattern
|
|
152
|
-
- \`"medium"\` - Balanced texture pattern
|
|
153
|
-
- \`"low"\` - Subtle texture pattern - default
|
|
154
|
-
- \`"none"\` - No texture pattern
|
|
155
|
-
|
|
156
|
-
### Usage Examples
|
|
157
|
-
|
|
158
|
-
\`\`\`tsx
|
|
159
|
-
// High opacity with glass effect
|
|
160
|
-
<DrawerContent opacity="high" glass="medium" noise="low">
|
|
161
|
-
Content with strong background dimming
|
|
162
|
-
</DrawerContent>
|
|
163
|
-
|
|
164
|
-
// Subtle overlay with texture
|
|
165
|
-
<DrawerContent opacity="low" glass="none" noise="high">
|
|
166
|
-
Content with subtle dimming and strong texture
|
|
167
|
-
</DrawerContent>
|
|
168
|
-
|
|
169
|
-
// No overlay effects
|
|
170
|
-
<DrawerContent opacity="none" glass="none" noise="none">
|
|
171
|
-
Content without any overlay effects
|
|
172
|
-
</DrawerContent>
|
|
173
|
-
\`\`\`
|
|
174
|
-
\`\`\`
|
|
175
|
-
|
|
176
|
-
### Drawer with Form Elements
|
|
177
|
-
\`\`\`tsx
|
|
178
|
-
<Drawer>
|
|
179
|
-
<DrawerTrigger asChild>
|
|
180
|
-
<Button>Open Form Drawer</Button>
|
|
181
|
-
</DrawerTrigger>
|
|
182
|
-
<DrawerContent>
|
|
183
|
-
<DrawerHeader>
|
|
184
|
-
<DrawerTitle>Contact Form</DrawerTitle>
|
|
185
|
-
<DrawerDescription>Fill out the form below to get in touch.</DrawerDescription>
|
|
186
|
-
</DrawerHeader>
|
|
187
|
-
<div className="space-y-4 p-4">
|
|
188
|
-
<Input placeholder="Name" />
|
|
189
|
-
<Input placeholder="Email" type="email" />
|
|
190
|
-
<Textarea placeholder="Message" rows={4} />
|
|
191
|
-
</div>
|
|
192
|
-
<DrawerFooter>
|
|
193
|
-
<Button>Submit</Button>
|
|
194
|
-
<DrawerClose asChild>
|
|
195
|
-
<Button variant="outline">Cancel</Button>
|
|
196
|
-
</DrawerClose>
|
|
197
|
-
</DrawerFooter>
|
|
198
|
-
</DrawerContent>
|
|
199
|
-
</Drawer>
|
|
200
|
-
\`\`\`
|
|
201
|
-
`,
|
|
36
|
+
component:
|
|
37
|
+
"A slide-out drawer built on Vaul primitives. Supports four slide directions, neutral and gradient variants, configurable glass/noise overlays, an optional swipe handle, and an optional backdrop overlay — ideal for mobile navigation, settings panels, and contextual actions.",
|
|
202
38
|
},
|
|
39
|
+
page: () => (
|
|
40
|
+
<AuralComponentDocsPage
|
|
41
|
+
features={[
|
|
42
|
+
{
|
|
43
|
+
title: "4 Slide Directions",
|
|
44
|
+
description: "Top, bottom, left, right",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
title: "Glass & Noise Overlay",
|
|
48
|
+
description: "Blur and grain levels",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
title: "Swipe Handle",
|
|
52
|
+
description: "Optional pill indicator",
|
|
53
|
+
},
|
|
54
|
+
]}
|
|
55
|
+
/>
|
|
56
|
+
),
|
|
203
57
|
},
|
|
204
58
|
},
|
|
205
59
|
argTypes: {
|
|
206
60
|
variant: {
|
|
207
61
|
control: { type: "select" },
|
|
208
62
|
options: ["neutral", "gradient"],
|
|
209
|
-
description: "
|
|
63
|
+
description: "Visual style variant",
|
|
210
64
|
},
|
|
211
65
|
showOverlay: {
|
|
212
66
|
control: { type: "boolean" },
|
|
213
|
-
description: "Whether to
|
|
67
|
+
description: "Whether to render the backdrop overlay",
|
|
214
68
|
},
|
|
215
69
|
showSwipeButton: {
|
|
216
70
|
control: { type: "boolean" },
|
|
217
|
-
description: "
|
|
71
|
+
description: "Show swipe indicator handle (bottom drawers only)",
|
|
218
72
|
},
|
|
219
73
|
opacity: {
|
|
220
74
|
control: { type: "select" },
|
|
@@ -224,12 +78,12 @@ The drawer supports configurable overlay effects through the \`opacity\`, \`glas
|
|
|
224
78
|
glass: {
|
|
225
79
|
control: { type: "select" },
|
|
226
80
|
options: ["high", "medium", "low", "none"],
|
|
227
|
-
description: "Overlay glass
|
|
81
|
+
description: "Overlay glass blur intensity",
|
|
228
82
|
},
|
|
229
83
|
noise: {
|
|
230
84
|
control: { type: "select" },
|
|
231
85
|
options: ["high", "medium", "low", "none"],
|
|
232
|
-
description: "Overlay noise texture
|
|
86
|
+
description: "Overlay noise texture intensity",
|
|
233
87
|
},
|
|
234
88
|
},
|
|
235
89
|
tags: ["autodocs"],
|
|
@@ -238,36 +92,28 @@ The drawer supports configurable overlay effects through the \`opacity\`, \`glas
|
|
|
238
92
|
export default meta
|
|
239
93
|
type Story = StoryObj<typeof Drawer>
|
|
240
94
|
|
|
241
|
-
//
|
|
242
|
-
|
|
95
|
+
// ─── Configurations ────────────────────────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
export const Configurations: Story = {
|
|
243
98
|
render: () => {
|
|
244
|
-
const
|
|
245
|
-
|
|
99
|
+
const DirDrawer = ({ direction, label, description }: any) => (
|
|
100
|
+
<div className="space-y-2 text-center">
|
|
246
101
|
<Drawer direction={direction}>
|
|
247
102
|
<DrawerTrigger asChild>
|
|
248
103
|
<Button variant="outline" size="sm">
|
|
249
|
-
{
|
|
104
|
+
{label}
|
|
250
105
|
</Button>
|
|
251
106
|
</DrawerTrigger>
|
|
252
107
|
<DrawerContent>
|
|
253
108
|
<DrawerHeader>
|
|
254
|
-
<DrawerTitle>{
|
|
109
|
+
<DrawerTitle>{label} Drawer</DrawerTitle>
|
|
255
110
|
<DrawerDescription>{description}</DrawerDescription>
|
|
256
111
|
</DrawerHeader>
|
|
257
|
-
<div className="p-
|
|
258
|
-
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border
|
|
259
|
-
<
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
<span className="text-fm-primary">{direction}</span>
|
|
263
|
-
</div>
|
|
264
|
-
<div>
|
|
265
|
-
Content:{" "}
|
|
266
|
-
<span className="text-fm-primary">
|
|
267
|
-
Slides from {direction}
|
|
268
|
-
</span>
|
|
269
|
-
</div>
|
|
270
|
-
</div>
|
|
112
|
+
<div className="p-4">
|
|
113
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-4 py-3">
|
|
114
|
+
<code className="text-fm-secondary text-fm-sm leading-fm-sm font-(--font-fm-mono)">
|
|
115
|
+
direction="{direction}"
|
|
116
|
+
</code>
|
|
271
117
|
</div>
|
|
272
118
|
</div>
|
|
273
119
|
<DrawerFooter>
|
|
@@ -277,77 +123,202 @@ export const DirectionExamples: Story = {
|
|
|
277
123
|
</DrawerFooter>
|
|
278
124
|
</DrawerContent>
|
|
279
125
|
</Drawer>
|
|
280
|
-
|
|
281
|
-
|
|
126
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
127
|
+
{label}
|
|
128
|
+
</p>
|
|
129
|
+
</div>
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
const OverlayDrawer = ({ label, opacity, glass, noise }: any) => (
|
|
133
|
+
<div className="space-y-2 text-center">
|
|
134
|
+
<Drawer direction="bottom">
|
|
135
|
+
<DrawerTrigger asChild>
|
|
136
|
+
<Button variant="outline" size="sm">
|
|
137
|
+
{label}
|
|
138
|
+
</Button>
|
|
139
|
+
</DrawerTrigger>
|
|
140
|
+
<DrawerContent opacity={opacity} glass={glass} noise={noise}>
|
|
141
|
+
<DrawerHeader>
|
|
142
|
+
<DrawerTitle>{label}</DrawerTitle>
|
|
143
|
+
<DrawerDescription>Overlay configuration demo.</DrawerDescription>
|
|
144
|
+
</DrawerHeader>
|
|
145
|
+
<div className="p-4">
|
|
146
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-4 py-3">
|
|
147
|
+
<code className="text-fm-secondary text-fm-sm leading-fm-sm font-(--font-fm-mono)">
|
|
148
|
+
{opacity ? `opacity="${opacity}"` : ""}
|
|
149
|
+
{glass ? ` glass="${glass}"` : ""}
|
|
150
|
+
{noise ? ` noise="${noise}"` : ""}
|
|
151
|
+
</code>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
<DrawerFooter>
|
|
155
|
+
<DrawerClose asChild>
|
|
156
|
+
<Button>Close</Button>
|
|
157
|
+
</DrawerClose>
|
|
158
|
+
</DrawerFooter>
|
|
159
|
+
</DrawerContent>
|
|
160
|
+
</Drawer>
|
|
161
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
162
|
+
{label}
|
|
163
|
+
</p>
|
|
164
|
+
</div>
|
|
165
|
+
)
|
|
282
166
|
|
|
283
167
|
return (
|
|
284
168
|
<div className="space-y-8">
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
169
|
+
{/* All four directions */}
|
|
170
|
+
<div className="space-y-3">
|
|
171
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
172
|
+
Slide Directions
|
|
173
|
+
</h4>
|
|
174
|
+
<div className="flex flex-wrap gap-6">
|
|
175
|
+
<DirDrawer
|
|
176
|
+
direction="bottom"
|
|
177
|
+
label="Bottom"
|
|
178
|
+
description="Slides up from the bottom — default for mobile."
|
|
179
|
+
/>
|
|
180
|
+
<DirDrawer
|
|
181
|
+
direction="top"
|
|
182
|
+
label="Top"
|
|
183
|
+
description="Slides down from the top — ideal for notifications."
|
|
184
|
+
/>
|
|
185
|
+
<DirDrawer
|
|
186
|
+
direction="left"
|
|
187
|
+
label="Left"
|
|
188
|
+
description="Slides in from the left — navigation menus."
|
|
189
|
+
/>
|
|
190
|
+
<DirDrawer
|
|
191
|
+
direction="right"
|
|
192
|
+
label="Right"
|
|
193
|
+
description="Slides in from the right — settings panels."
|
|
194
|
+
/>
|
|
195
|
+
</div>
|
|
292
196
|
</div>
|
|
293
197
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
<
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
<div className="
|
|
301
|
-
<
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
198
|
+
{/* Variant styles */}
|
|
199
|
+
<div className="space-y-3">
|
|
200
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
201
|
+
Variant Styles
|
|
202
|
+
</h4>
|
|
203
|
+
<div className="flex flex-wrap gap-6">
|
|
204
|
+
<div className="space-y-2 text-center">
|
|
205
|
+
<Drawer direction="bottom">
|
|
206
|
+
<DrawerTrigger asChild>
|
|
207
|
+
<Button variant="outline" size="sm">
|
|
208
|
+
Neutral
|
|
209
|
+
</Button>
|
|
210
|
+
</DrawerTrigger>
|
|
211
|
+
<DrawerContent variant="neutral">
|
|
212
|
+
<DrawerHeader>
|
|
213
|
+
<DrawerTitle>Neutral Variant</DrawerTitle>
|
|
214
|
+
<DrawerDescription>
|
|
215
|
+
Frosted glass surface with backdrop blur.
|
|
216
|
+
</DrawerDescription>
|
|
217
|
+
</DrawerHeader>
|
|
218
|
+
<DrawerFooter>
|
|
219
|
+
<DrawerClose asChild>
|
|
220
|
+
<Button>Close</Button>
|
|
221
|
+
</DrawerClose>
|
|
222
|
+
</DrawerFooter>
|
|
223
|
+
</DrawerContent>
|
|
224
|
+
</Drawer>
|
|
225
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
226
|
+
Neutral
|
|
227
|
+
</p>
|
|
306
228
|
</div>
|
|
307
|
-
</div>
|
|
308
229
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
230
|
+
<div className="space-y-2 text-center">
|
|
231
|
+
<Drawer direction="bottom">
|
|
232
|
+
<DrawerTrigger asChild>
|
|
233
|
+
<Button variant="outline" size="sm">
|
|
234
|
+
Gradient
|
|
235
|
+
</Button>
|
|
236
|
+
</DrawerTrigger>
|
|
237
|
+
<DrawerContent variant="gradient">
|
|
238
|
+
<DrawerHeader>
|
|
239
|
+
<DrawerTitle>Gradient Variant</DrawerTitle>
|
|
240
|
+
<DrawerDescription>
|
|
241
|
+
Surface primary with a white gradient overlay.
|
|
242
|
+
</DrawerDescription>
|
|
243
|
+
</DrawerHeader>
|
|
244
|
+
<DrawerFooter>
|
|
245
|
+
<DrawerClose asChild>
|
|
246
|
+
<Button>Close</Button>
|
|
247
|
+
</DrawerClose>
|
|
248
|
+
</DrawerFooter>
|
|
249
|
+
</DrawerContent>
|
|
250
|
+
</Drawer>
|
|
251
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
252
|
+
Gradient
|
|
253
|
+
</p>
|
|
320
254
|
</div>
|
|
321
|
-
</div>
|
|
322
255
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
256
|
+
<div className="space-y-2 text-center">
|
|
257
|
+
<Drawer direction="bottom">
|
|
258
|
+
<DrawerTrigger asChild>
|
|
259
|
+
<Button variant="outline" size="sm">
|
|
260
|
+
Swipe handle
|
|
261
|
+
</Button>
|
|
262
|
+
</DrawerTrigger>
|
|
263
|
+
<DrawerContent showSwipeButton>
|
|
264
|
+
<DrawerHeader>
|
|
265
|
+
<DrawerTitle>Swipe Handle</DrawerTitle>
|
|
266
|
+
<DrawerDescription>
|
|
267
|
+
Pill handle appears at the top of bottom drawers.
|
|
268
|
+
</DrawerDescription>
|
|
269
|
+
</DrawerHeader>
|
|
270
|
+
<DrawerFooter>
|
|
271
|
+
<DrawerClose asChild>
|
|
272
|
+
<Button>Close</Button>
|
|
273
|
+
</DrawerClose>
|
|
274
|
+
</DrawerFooter>
|
|
275
|
+
</DrawerContent>
|
|
276
|
+
</Drawer>
|
|
277
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
278
|
+
Swipe button
|
|
279
|
+
</p>
|
|
334
280
|
</div>
|
|
335
|
-
</div>
|
|
336
281
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
282
|
+
<div className="space-y-2 text-center">
|
|
283
|
+
<Drawer direction="bottom">
|
|
284
|
+
<DrawerTrigger asChild>
|
|
285
|
+
<Button variant="outline" size="sm">
|
|
286
|
+
No overlay
|
|
287
|
+
</Button>
|
|
288
|
+
</DrawerTrigger>
|
|
289
|
+
<DrawerContent showOverlay={false}>
|
|
290
|
+
<DrawerHeader>
|
|
291
|
+
<DrawerTitle>No Overlay</DrawerTitle>
|
|
292
|
+
<DrawerDescription>
|
|
293
|
+
Drawer without the backdrop overlay.
|
|
294
|
+
</DrawerDescription>
|
|
295
|
+
</DrawerHeader>
|
|
296
|
+
<DrawerFooter>
|
|
297
|
+
<DrawerClose asChild>
|
|
298
|
+
<Button>Close</Button>
|
|
299
|
+
</DrawerClose>
|
|
300
|
+
</DrawerFooter>
|
|
301
|
+
</DrawerContent>
|
|
302
|
+
</Drawer>
|
|
303
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
304
|
+
No overlay
|
|
305
|
+
</p>
|
|
348
306
|
</div>
|
|
349
307
|
</div>
|
|
350
308
|
</div>
|
|
309
|
+
|
|
310
|
+
{/* Glass / noise options */}
|
|
311
|
+
<div className="space-y-3">
|
|
312
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
313
|
+
Glass & Noise Overlay Options
|
|
314
|
+
</h4>
|
|
315
|
+
<div className="flex flex-wrap gap-6">
|
|
316
|
+
<OverlayDrawer label="Low opacity" opacity="low" />
|
|
317
|
+
<OverlayDrawer label="High opacity" opacity="high" />
|
|
318
|
+
<OverlayDrawer label="High glass" glass="high" />
|
|
319
|
+
<OverlayDrawer label="Noise texture" noise="medium" />
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
351
322
|
</div>
|
|
352
323
|
)
|
|
353
324
|
},
|
|
@@ -355,614 +326,456 @@ export const DirectionExamples: Story = {
|
|
|
355
326
|
docs: {
|
|
356
327
|
description: {
|
|
357
328
|
story:
|
|
358
|
-
"
|
|
329
|
+
"Comparison of all four slide directions, both visual variants, swipe handle, overlay toggle, and glass/noise overlay options.",
|
|
359
330
|
},
|
|
360
331
|
},
|
|
361
332
|
},
|
|
362
333
|
}
|
|
363
334
|
|
|
364
|
-
//
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
<Drawer>
|
|
368
|
-
<DrawerTrigger asChild>
|
|
369
|
-
<Button>Open Drawer</Button>
|
|
370
|
-
</DrawerTrigger>
|
|
371
|
-
<DrawerContent>
|
|
372
|
-
<DrawerHeader>
|
|
373
|
-
<DrawerTitle>Basic Drawer</DrawerTitle>
|
|
374
|
-
<DrawerDescription>
|
|
375
|
-
This is a basic drawer example with header, content, and footer.
|
|
376
|
-
</DrawerDescription>
|
|
377
|
-
</DrawerHeader>
|
|
378
|
-
<p className="p-4 text-sm">
|
|
379
|
-
This is the main content area of the drawer. You can put any content
|
|
380
|
-
here.
|
|
381
|
-
</p>
|
|
382
|
-
<DrawerFooter>
|
|
383
|
-
<Button>Save Changes</Button>
|
|
384
|
-
<DrawerClose asChild>
|
|
385
|
-
<Button variant="outline">Cancel</Button>
|
|
386
|
-
</DrawerClose>
|
|
387
|
-
</DrawerFooter>
|
|
388
|
-
</DrawerContent>
|
|
389
|
-
</Drawer>
|
|
390
|
-
),
|
|
391
|
-
parameters: {
|
|
392
|
-
docs: {
|
|
393
|
-
description: {
|
|
394
|
-
story:
|
|
395
|
-
"Basic drawer example demonstrating the fundamental structure with header, content, and footer sections.",
|
|
396
|
-
},
|
|
397
|
-
},
|
|
398
|
-
},
|
|
399
|
-
}
|
|
400
|
-
// 2. Form Drawer with Select Components
|
|
401
|
-
export const FormDrawer: Story = {
|
|
335
|
+
// ─── Interactive ───────────────────────────────────────────────────────────────
|
|
336
|
+
|
|
337
|
+
export const Interactive: Story = {
|
|
402
338
|
render: () => {
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
339
|
+
const InteractiveDemo = () => {
|
|
340
|
+
const [direction, setDirection] = useState<
|
|
341
|
+
"top" | "bottom" | "left" | "right"
|
|
342
|
+
>("bottom")
|
|
343
|
+
const [variant, setVariant] = useState<"neutral" | "gradient">("neutral")
|
|
344
|
+
const [opacity, setOpacity] = useState<
|
|
345
|
+
"high" | "medium" | "low" | "none"
|
|
346
|
+
>("medium")
|
|
347
|
+
const [glass, setGlass] = useState<"high" | "medium" | "low" | "none">(
|
|
348
|
+
"none"
|
|
349
|
+
)
|
|
350
|
+
const [noise, setNoise] = useState<"high" | "medium" | "low" | "none">(
|
|
351
|
+
"none"
|
|
352
|
+
)
|
|
353
|
+
const [showSwipeButton, setShowSwipeButton] = useState(false)
|
|
354
|
+
const [name, setName] = useState("")
|
|
355
|
+
const [email, setEmail] = useState("")
|
|
356
|
+
const [submitted, setSubmitted] = useState(false)
|
|
357
|
+
|
|
358
|
+
const directions = ["bottom", "top", "left", "right"] as const
|
|
359
|
+
const variants = ["neutral", "gradient"] as const
|
|
360
|
+
const levels = ["none", "low", "medium", "high"] as const
|
|
361
|
+
|
|
362
|
+
const btnCls = (active: boolean) =>
|
|
363
|
+
`font-fm-text text-fm-sm leading-fm-sm rounded px-2 py-1 outline-none transition-colors ${
|
|
364
|
+
active
|
|
365
|
+
? "bg-fm-surface-contrast text-fm-contrast"
|
|
366
|
+
: "bg-fm-surface-secondary text-fm-secondary hover:text-fm-primary"
|
|
367
|
+
}`
|
|
411
368
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
369
|
+
return (
|
|
370
|
+
<div className="w-full p-8">
|
|
371
|
+
<div className="mx-auto max-w-3xl space-y-6">
|
|
372
|
+
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
|
373
|
+
{/* Controls panel */}
|
|
374
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-5 rounded-xl border p-5">
|
|
375
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold tracking-widest uppercase">
|
|
376
|
+
Configuration
|
|
377
|
+
</p>
|
|
378
|
+
|
|
379
|
+
<div className="space-y-2">
|
|
380
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
381
|
+
Direction
|
|
382
|
+
</p>
|
|
383
|
+
<div className="flex flex-wrap gap-1">
|
|
384
|
+
{directions.map((d) => (
|
|
385
|
+
<button
|
|
386
|
+
key={d}
|
|
387
|
+
onClick={() => setDirection(d)}
|
|
388
|
+
className={btnCls(direction === d)}
|
|
389
|
+
>
|
|
390
|
+
{d}
|
|
391
|
+
</button>
|
|
392
|
+
))}
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
416
395
|
|
|
417
|
-
|
|
418
|
-
<Drawer>
|
|
419
|
-
<DrawerTrigger asChild>
|
|
420
|
-
<Button className="gap-2">
|
|
421
|
-
<EditBigIcon className="h-4 w-4" />
|
|
422
|
-
Contact Form
|
|
423
|
-
</Button>
|
|
424
|
-
</DrawerTrigger>
|
|
425
|
-
<DrawerContent>
|
|
426
|
-
<DrawerHeader>
|
|
427
|
-
<DrawerTitle>Contact Form</DrawerTitle>
|
|
428
|
-
<DrawerDescription>
|
|
429
|
-
Fill out the form below to get in touch with us.
|
|
430
|
-
</DrawerDescription>
|
|
431
|
-
</DrawerHeader>
|
|
432
|
-
<form onSubmit={handleSubmit} className="space-y-4 overflow-auto p-4">
|
|
433
|
-
<div className="space-y-2">
|
|
434
|
-
<Label htmlFor="name">Name</Label>
|
|
435
|
-
<Input
|
|
436
|
-
id="name"
|
|
437
|
-
value={formData.name}
|
|
438
|
-
onChange={(e) =>
|
|
439
|
-
setFormData({ ...formData, name: e.target.value })
|
|
440
|
-
}
|
|
441
|
-
placeholder="Enter your name"
|
|
442
|
-
/>
|
|
443
|
-
</div>
|
|
444
|
-
<div className="space-y-2">
|
|
445
|
-
<Label htmlFor="email">Email</Label>
|
|
446
|
-
<Input
|
|
447
|
-
id="email"
|
|
448
|
-
type="email"
|
|
449
|
-
value={formData.email}
|
|
450
|
-
onChange={(e) =>
|
|
451
|
-
setFormData({ ...formData, email: e.target.value })
|
|
452
|
-
}
|
|
453
|
-
placeholder="Enter your email"
|
|
454
|
-
/>
|
|
455
|
-
</div>
|
|
456
|
-
<div className="space-y-2">
|
|
457
|
-
<Label htmlFor="category">Category</Label>
|
|
458
|
-
<Select
|
|
459
|
-
value={formData.category}
|
|
460
|
-
onValueChange={(value) =>
|
|
461
|
-
setFormData({ ...formData, category: value })
|
|
462
|
-
}
|
|
463
|
-
>
|
|
464
|
-
<SelectTrigger>
|
|
465
|
-
<SelectValue placeholder="Select a category" />
|
|
466
|
-
</SelectTrigger>
|
|
467
|
-
<SelectContent>
|
|
468
|
-
<SelectItem value="general">General Inquiry</SelectItem>
|
|
469
|
-
<SelectItem value="support">Technical Support</SelectItem>
|
|
470
|
-
<SelectItem value="sales">Sales Question</SelectItem>
|
|
471
|
-
<SelectItem value="feedback">Feedback</SelectItem>
|
|
472
|
-
</SelectContent>
|
|
473
|
-
</Select>
|
|
474
|
-
</div>
|
|
475
|
-
<div className="space-y-2">
|
|
476
|
-
<Label htmlFor="priority">Priority</Label>
|
|
477
|
-
<Select
|
|
478
|
-
value={formData.priority}
|
|
479
|
-
onValueChange={(value) =>
|
|
480
|
-
setFormData({ ...formData, priority: value })
|
|
481
|
-
}
|
|
482
|
-
>
|
|
483
|
-
<SelectTrigger>
|
|
484
|
-
<SelectValue placeholder="Select priority level" />
|
|
485
|
-
</SelectTrigger>
|
|
486
|
-
<SelectContent>
|
|
487
|
-
<SelectItem value="low">Low</SelectItem>
|
|
488
|
-
<SelectItem value="medium">Medium</SelectItem>
|
|
489
|
-
<SelectItem value="high">High</SelectItem>
|
|
490
|
-
<SelectItem value="urgent">Urgent</SelectItem>
|
|
491
|
-
</SelectContent>
|
|
492
|
-
</Select>
|
|
493
|
-
</div>
|
|
494
|
-
<div className="space-y-2">
|
|
495
|
-
<Label htmlFor="message">Message</Label>
|
|
496
|
-
<Textarea
|
|
497
|
-
id="message"
|
|
498
|
-
value={formData.message}
|
|
499
|
-
onChange={(e) =>
|
|
500
|
-
setFormData({ ...formData, message: e.target.value })
|
|
501
|
-
}
|
|
502
|
-
placeholder="Enter your message"
|
|
503
|
-
rows={4}
|
|
504
|
-
/>
|
|
505
|
-
</div>
|
|
506
|
-
<div className="flex items-center space-x-2">
|
|
507
|
-
<Checkbox
|
|
508
|
-
id="newsletter"
|
|
509
|
-
checked={formData.newsletter}
|
|
510
|
-
onCheckedChange={(checked) =>
|
|
511
|
-
setFormData({ ...formData, newsletter: !!checked })
|
|
512
|
-
}
|
|
513
|
-
/>
|
|
514
|
-
<Label htmlFor="newsletter" className="text-sm">
|
|
515
|
-
Subscribe to newsletter
|
|
516
|
-
</Label>
|
|
517
|
-
</div>
|
|
518
|
-
</form>
|
|
519
|
-
<DrawerFooter>
|
|
520
|
-
<Button
|
|
521
|
-
disabled={!formData.name || !formData.email || !formData.message}
|
|
522
|
-
onClick={handleSubmit}
|
|
523
|
-
>
|
|
524
|
-
Submit
|
|
525
|
-
</Button>
|
|
526
|
-
<DrawerClose asChild>
|
|
527
|
-
<Button variant="outline">Cancel</Button>
|
|
528
|
-
</DrawerClose>
|
|
529
|
-
</DrawerFooter>
|
|
530
|
-
</DrawerContent>
|
|
531
|
-
</Drawer>
|
|
532
|
-
)
|
|
533
|
-
},
|
|
534
|
-
parameters: {
|
|
535
|
-
docs: {
|
|
536
|
-
description: {
|
|
537
|
-
story:
|
|
538
|
-
"Form drawer with select components instead of native select tags, demonstrating proper form handling and validation.",
|
|
539
|
-
},
|
|
540
|
-
},
|
|
541
|
-
},
|
|
542
|
-
}
|
|
396
|
+
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
543
397
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
398
|
+
<div className="space-y-2">
|
|
399
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
400
|
+
Variant
|
|
401
|
+
</p>
|
|
402
|
+
<div className="flex flex-wrap gap-1">
|
|
403
|
+
{variants.map((v) => (
|
|
404
|
+
<button
|
|
405
|
+
key={v}
|
|
406
|
+
onClick={() => setVariant(v)}
|
|
407
|
+
className={btnCls(variant === v)}
|
|
408
|
+
>
|
|
409
|
+
{v}
|
|
410
|
+
</button>
|
|
411
|
+
))}
|
|
412
|
+
</div>
|
|
413
|
+
</div>
|
|
553
414
|
|
|
554
|
-
|
|
555
|
-
<Drawer>
|
|
556
|
-
<DrawerTrigger asChild>
|
|
557
|
-
<Button>Open Settings</Button>
|
|
558
|
-
</DrawerTrigger>
|
|
559
|
-
<DrawerContent>
|
|
560
|
-
<DrawerHeader>
|
|
561
|
-
<DrawerTitle>Settings</DrawerTitle>
|
|
562
|
-
<DrawerDescription>
|
|
563
|
-
Configure your application preferences.
|
|
564
|
-
</DrawerDescription>
|
|
565
|
-
</DrawerHeader>
|
|
566
|
-
<div className="space-y-6 overflow-auto p-4">
|
|
567
|
-
<div className="space-y-4">
|
|
568
|
-
<h3 className="text-sm font-medium">Appearance</h3>
|
|
569
|
-
<div className="space-y-2">
|
|
570
|
-
<Label htmlFor="theme">Theme</Label>
|
|
571
|
-
<Select
|
|
572
|
-
value={settings.theme}
|
|
573
|
-
onValueChange={(value) =>
|
|
574
|
-
setSettings({ ...settings, theme: value })
|
|
575
|
-
}
|
|
576
|
-
>
|
|
577
|
-
<SelectTrigger>
|
|
578
|
-
<SelectValue />
|
|
579
|
-
</SelectTrigger>
|
|
580
|
-
<SelectContent>
|
|
581
|
-
<SelectItem value="light">Light</SelectItem>
|
|
582
|
-
<SelectItem value="dark">Dark</SelectItem>
|
|
583
|
-
<SelectItem value="system">System</SelectItem>
|
|
584
|
-
</SelectContent>
|
|
585
|
-
</Select>
|
|
586
|
-
</div>
|
|
587
|
-
</div>
|
|
588
|
-
<div className="space-y-4">
|
|
589
|
-
<h3 className="text-sm font-medium">Notifications</h3>
|
|
590
|
-
<div className="space-y-2">
|
|
591
|
-
<Label htmlFor="notifications">Email Notifications</Label>
|
|
592
|
-
<Select
|
|
593
|
-
value={settings.notifications}
|
|
594
|
-
onValueChange={(value) =>
|
|
595
|
-
setSettings({ ...settings, notifications: value })
|
|
596
|
-
}
|
|
597
|
-
>
|
|
598
|
-
<SelectTrigger>
|
|
599
|
-
<SelectValue />
|
|
600
|
-
</SelectTrigger>
|
|
601
|
-
<SelectContent>
|
|
602
|
-
<SelectItem value="all">All notifications</SelectItem>
|
|
603
|
-
<SelectItem value="important">Important only</SelectItem>
|
|
604
|
-
<SelectItem value="none">None</SelectItem>
|
|
605
|
-
</SelectContent>
|
|
606
|
-
</Select>
|
|
607
|
-
</div>
|
|
608
|
-
</div>
|
|
609
|
-
<div className="space-y-4">
|
|
610
|
-
<h3 className="text-sm font-medium">Regional</h3>
|
|
611
|
-
<div className="space-y-2">
|
|
612
|
-
<Label htmlFor="language">Language</Label>
|
|
613
|
-
<Select
|
|
614
|
-
value={settings.language}
|
|
615
|
-
onValueChange={(value) =>
|
|
616
|
-
setSettings({ ...settings, language: value })
|
|
617
|
-
}
|
|
618
|
-
>
|
|
619
|
-
<SelectTrigger>
|
|
620
|
-
<SelectValue />
|
|
621
|
-
</SelectTrigger>
|
|
622
|
-
<SelectContent>
|
|
623
|
-
<SelectItem value="en">English</SelectItem>
|
|
624
|
-
<SelectItem value="es">Spanish</SelectItem>
|
|
625
|
-
<SelectItem value="fr">French</SelectItem>
|
|
626
|
-
<SelectItem value="de">German</SelectItem>
|
|
627
|
-
</SelectContent>
|
|
628
|
-
</Select>
|
|
629
|
-
</div>
|
|
630
|
-
<div className="space-y-2">
|
|
631
|
-
<Label htmlFor="timezone">Timezone</Label>
|
|
632
|
-
<Select
|
|
633
|
-
value={settings.timezone}
|
|
634
|
-
onValueChange={(value) =>
|
|
635
|
-
setSettings({ ...settings, timezone: value })
|
|
636
|
-
}
|
|
637
|
-
>
|
|
638
|
-
<SelectTrigger>
|
|
639
|
-
<SelectValue />
|
|
640
|
-
</SelectTrigger>
|
|
641
|
-
<SelectContent>
|
|
642
|
-
<SelectItem value="utc">UTC</SelectItem>
|
|
643
|
-
<SelectItem value="est">Eastern Time</SelectItem>
|
|
644
|
-
<SelectItem value="pst">Pacific Time</SelectItem>
|
|
645
|
-
<SelectItem value="gmt">GMT</SelectItem>
|
|
646
|
-
</SelectContent>
|
|
647
|
-
</Select>
|
|
648
|
-
</div>
|
|
649
|
-
</div>
|
|
650
|
-
</div>
|
|
651
|
-
<DrawerFooter>
|
|
652
|
-
<Button onClick={() => console.log("Settings saved:", settings)}>
|
|
653
|
-
Save Settings
|
|
654
|
-
</Button>
|
|
655
|
-
<DrawerClose asChild>
|
|
656
|
-
<Button variant="outline">Cancel</Button>
|
|
657
|
-
</DrawerClose>
|
|
658
|
-
</DrawerFooter>
|
|
659
|
-
</DrawerContent>
|
|
660
|
-
</Drawer>
|
|
661
|
-
)
|
|
662
|
-
},
|
|
663
|
-
parameters: {
|
|
664
|
-
docs: {
|
|
665
|
-
description: {
|
|
666
|
-
story:
|
|
667
|
-
"Settings drawer showcasing select components for configuration options with proper state management.",
|
|
668
|
-
},
|
|
669
|
-
},
|
|
670
|
-
},
|
|
671
|
-
}
|
|
415
|
+
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
672
416
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
417
|
+
<div className="space-y-2">
|
|
418
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
419
|
+
Opacity
|
|
420
|
+
</p>
|
|
421
|
+
<div className="flex flex-wrap gap-1">
|
|
422
|
+
{levels.map((l) => (
|
|
423
|
+
<button
|
|
424
|
+
key={l}
|
|
425
|
+
onClick={() => setOpacity(l)}
|
|
426
|
+
className={btnCls(opacity === l)}
|
|
427
|
+
>
|
|
428
|
+
{l}
|
|
429
|
+
</button>
|
|
430
|
+
))}
|
|
431
|
+
</div>
|
|
432
|
+
</div>
|
|
677
433
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
<Button>Open Parent Drawer</Button>
|
|
682
|
-
</DrawerTrigger>
|
|
683
|
-
<DrawerContent>
|
|
684
|
-
<DrawerHeader>
|
|
685
|
-
<DrawerTitle>Parent Drawer</DrawerTitle>
|
|
686
|
-
<DrawerDescription>
|
|
687
|
-
This drawer contains a nested drawer example.
|
|
688
|
-
</DrawerDescription>
|
|
689
|
-
</DrawerHeader>
|
|
690
|
-
<div className="space-y-4 p-4">
|
|
691
|
-
<p className="text-muted-foreground text-sm">
|
|
692
|
-
This is the parent drawer content.
|
|
693
|
-
</p>
|
|
694
|
-
<Drawer open={isNestedOpen} onOpenChange={setIsNestedOpen}>
|
|
695
|
-
<DrawerTrigger asChild>
|
|
696
|
-
<Button variant="outline">Open Nested Drawer</Button>
|
|
697
|
-
</DrawerTrigger>
|
|
698
|
-
<DrawerContent>
|
|
699
|
-
<DrawerHeader>
|
|
700
|
-
<DrawerTitle>Nested Drawer</DrawerTitle>
|
|
701
|
-
<DrawerDescription>
|
|
702
|
-
This is a nested drawer within the parent drawer.
|
|
703
|
-
</DrawerDescription>
|
|
704
|
-
</DrawerHeader>
|
|
705
|
-
<div className="p-4">
|
|
706
|
-
<p className="text-muted-foreground text-sm">
|
|
707
|
-
Nested drawer content goes here.
|
|
434
|
+
<div className="space-y-2">
|
|
435
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
436
|
+
Glass
|
|
708
437
|
</p>
|
|
438
|
+
<div className="flex flex-wrap gap-1">
|
|
439
|
+
{levels.map((l) => (
|
|
440
|
+
<button
|
|
441
|
+
key={l}
|
|
442
|
+
onClick={() => setGlass(l)}
|
|
443
|
+
className={btnCls(glass === l)}
|
|
444
|
+
>
|
|
445
|
+
{l}
|
|
446
|
+
</button>
|
|
447
|
+
))}
|
|
448
|
+
</div>
|
|
709
449
|
</div>
|
|
710
|
-
<DrawerFooter>
|
|
711
|
-
<Button onClick={() => setIsNestedOpen(false)}>
|
|
712
|
-
Close Nested
|
|
713
|
-
</Button>
|
|
714
|
-
<DrawerClose asChild>
|
|
715
|
-
<Button variant="outline">Cancel</Button>
|
|
716
|
-
</DrawerClose>
|
|
717
|
-
</DrawerFooter>
|
|
718
|
-
</DrawerContent>
|
|
719
|
-
</Drawer>
|
|
720
|
-
</div>
|
|
721
|
-
<DrawerFooter>
|
|
722
|
-
<Button>Save</Button>
|
|
723
|
-
<DrawerClose asChild>
|
|
724
|
-
<Button variant="outline">Close Parent</Button>
|
|
725
|
-
</DrawerClose>
|
|
726
|
-
</DrawerFooter>
|
|
727
|
-
</DrawerContent>
|
|
728
|
-
</Drawer>
|
|
729
|
-
)
|
|
730
|
-
},
|
|
731
|
-
parameters: {
|
|
732
|
-
docs: {
|
|
733
|
-
description: {
|
|
734
|
-
story:
|
|
735
|
-
"Nested drawer example demonstrating proper modal stacking and z-index management.",
|
|
736
|
-
},
|
|
737
|
-
},
|
|
738
|
-
},
|
|
739
|
-
}
|
|
740
450
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
451
|
+
<div className="space-y-2">
|
|
452
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
453
|
+
Noise
|
|
454
|
+
</p>
|
|
455
|
+
<div className="flex flex-wrap gap-1">
|
|
456
|
+
{levels.map((l) => (
|
|
457
|
+
<button
|
|
458
|
+
key={l}
|
|
459
|
+
onClick={() => setNoise(l)}
|
|
460
|
+
className={btnCls(noise === l)}
|
|
461
|
+
>
|
|
462
|
+
{l}
|
|
463
|
+
</button>
|
|
464
|
+
))}
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
|
|
468
|
+
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
469
|
+
|
|
470
|
+
<div className="flex items-center gap-2">
|
|
471
|
+
<Checkbox
|
|
472
|
+
id="swipe-btn"
|
|
473
|
+
checked={showSwipeButton}
|
|
474
|
+
onCheckedChange={(c) => setShowSwipeButton(!!c)}
|
|
475
|
+
/>
|
|
476
|
+
<Label
|
|
477
|
+
htmlFor="swipe-btn"
|
|
478
|
+
className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm"
|
|
479
|
+
>
|
|
480
|
+
Swipe handle
|
|
481
|
+
</Label>
|
|
482
|
+
</div>
|
|
483
|
+
</div>
|
|
484
|
+
|
|
485
|
+
{/* Preview stage */}
|
|
486
|
+
<div className="flex flex-col gap-3 lg:col-span-2">
|
|
487
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary flex min-h-48 flex-col items-center justify-center gap-4 rounded-xl border p-8">
|
|
488
|
+
{submitted && (
|
|
489
|
+
<div className="border-fm-divider-positive bg-fm-surface-positive-sec rounded-lg border px-4 py-2">
|
|
490
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
491
|
+
Form submitted for{" "}
|
|
492
|
+
<span className="text-fm-primary font-medium">
|
|
493
|
+
{name}
|
|
494
|
+
</span>
|
|
495
|
+
</p>
|
|
496
|
+
</div>
|
|
497
|
+
)}
|
|
498
|
+
|
|
499
|
+
<Drawer direction={direction}>
|
|
500
|
+
<DrawerTrigger asChild>
|
|
501
|
+
<Button onClick={() => setSubmitted(false)}>
|
|
502
|
+
Open Drawer
|
|
503
|
+
</Button>
|
|
504
|
+
</DrawerTrigger>
|
|
505
|
+
<DrawerContent
|
|
506
|
+
variant={variant}
|
|
507
|
+
opacity={opacity}
|
|
508
|
+
glass={glass}
|
|
509
|
+
noise={noise}
|
|
510
|
+
showSwipeButton={showSwipeButton}
|
|
511
|
+
>
|
|
512
|
+
<DrawerHeader>
|
|
513
|
+
<DrawerTitle>Quick Contact</DrawerTitle>
|
|
514
|
+
<DrawerDescription>
|
|
515
|
+
Fill out the form to send a message.
|
|
516
|
+
</DrawerDescription>
|
|
517
|
+
</DrawerHeader>
|
|
518
|
+
|
|
519
|
+
<div className="space-y-4 p-4">
|
|
520
|
+
<div className="space-y-2">
|
|
521
|
+
<Label htmlFor="drawer-name">Name</Label>
|
|
522
|
+
<Input
|
|
523
|
+
id="drawer-name"
|
|
524
|
+
placeholder="Your name"
|
|
525
|
+
value={name}
|
|
526
|
+
onChange={(e) => setName(e.target.value)}
|
|
527
|
+
/>
|
|
528
|
+
</div>
|
|
529
|
+
<div className="space-y-2">
|
|
530
|
+
<Label htmlFor="drawer-email">Email</Label>
|
|
531
|
+
<Input
|
|
532
|
+
id="drawer-email"
|
|
533
|
+
type="email"
|
|
534
|
+
placeholder="your@email.com"
|
|
535
|
+
value={email}
|
|
536
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
537
|
+
/>
|
|
538
|
+
</div>
|
|
539
|
+
</div>
|
|
540
|
+
|
|
541
|
+
<DrawerFooter>
|
|
542
|
+
<DrawerClose asChild>
|
|
543
|
+
<Button
|
|
544
|
+
disabled={!name || !email}
|
|
545
|
+
onClick={() => setSubmitted(true)}
|
|
546
|
+
>
|
|
547
|
+
Submit
|
|
548
|
+
</Button>
|
|
549
|
+
</DrawerClose>
|
|
550
|
+
<DrawerClose asChild>
|
|
551
|
+
<Button variant="outline">Cancel</Button>
|
|
552
|
+
</DrawerClose>
|
|
553
|
+
</DrawerFooter>
|
|
554
|
+
</DrawerContent>
|
|
555
|
+
</Drawer>
|
|
556
|
+
</div>
|
|
557
|
+
|
|
558
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-4 py-3">
|
|
559
|
+
<code className="text-fm-secondary text-fm-sm leading-fm-sm font-(--font-fm-mono)">
|
|
560
|
+
{`<Drawer direction="${direction}"><DrawerContent variant="${variant}" opacity="${opacity}" glass="${glass}" noise="${noise}" showSwipeButton={${showSwipeButton}} />`}
|
|
561
|
+
</code>
|
|
562
|
+
</div>
|
|
563
|
+
</div>
|
|
756
564
|
</div>
|
|
757
|
-
<DrawerClose asChild>
|
|
758
|
-
<Button variant="text" size="sm" className="ml-4">
|
|
759
|
-
<CrossIcon className="h-4 w-4" />
|
|
760
|
-
</Button>
|
|
761
|
-
</DrawerClose>
|
|
762
565
|
</div>
|
|
763
|
-
</
|
|
566
|
+
</div>
|
|
567
|
+
)
|
|
568
|
+
}
|
|
764
569
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
<DrawerClose asChild>
|
|
768
|
-
<Button variant="outline">Cancel</Button>
|
|
769
|
-
</DrawerClose>
|
|
770
|
-
</DrawerFooter>
|
|
771
|
-
</DrawerContent>
|
|
772
|
-
</Drawer>
|
|
773
|
-
),
|
|
570
|
+
return <InteractiveDemo />
|
|
571
|
+
},
|
|
774
572
|
parameters: {
|
|
775
573
|
docs: {
|
|
776
574
|
description: {
|
|
777
575
|
story:
|
|
778
|
-
"
|
|
576
|
+
"Live configurator — select direction, variant, overlay settings, and swipe handle, then open the drawer and submit the form inside to see state feedback.",
|
|
779
577
|
},
|
|
780
578
|
},
|
|
781
579
|
},
|
|
782
580
|
}
|
|
783
581
|
|
|
784
|
-
//
|
|
785
|
-
export const AccessibilityExample: Story = {
|
|
786
|
-
render: () => {
|
|
787
|
-
return (
|
|
788
|
-
<Drawer>
|
|
789
|
-
<DrawerTrigger asChild>
|
|
790
|
-
<Button>Accessible Drawer Demo</Button>
|
|
791
|
-
</DrawerTrigger>
|
|
792
|
-
<DrawerContent>
|
|
793
|
-
<DrawerHeader>
|
|
794
|
-
<DrawerTitle>Accessibility Features</DrawerTitle>
|
|
795
|
-
<DrawerDescription>
|
|
796
|
-
This drawer demonstrates proper accessibility implementation.
|
|
797
|
-
</DrawerDescription>
|
|
798
|
-
</DrawerHeader>
|
|
582
|
+
// ─── UseCases ─────────────────────────────────────────────────────────────────
|
|
799
583
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
<li>
|
|
807
|
-
•{" "}
|
|
808
|
-
<kbd className="bg-fm-surface-secondary rounded px-1">
|
|
809
|
-
Tab
|
|
810
|
-
</kbd>{" "}
|
|
811
|
-
- Navigate between elements
|
|
812
|
-
</li>
|
|
813
|
-
<li>
|
|
814
|
-
•{" "}
|
|
815
|
-
<kbd className="bg-fm-surface-secondary rounded px-1">
|
|
816
|
-
Escape
|
|
817
|
-
</kbd>{" "}
|
|
818
|
-
- Close drawer
|
|
819
|
-
</li>
|
|
820
|
-
<li>
|
|
821
|
-
•{" "}
|
|
822
|
-
<kbd className="bg-fm-surface-secondary rounded px-1">
|
|
823
|
-
Enter
|
|
824
|
-
</kbd>{" "}
|
|
825
|
-
- Activate buttons
|
|
826
|
-
</li>
|
|
827
|
-
<li>
|
|
828
|
-
•{" "}
|
|
829
|
-
<kbd className="bg-fm-surface-secondary rounded px-1">
|
|
830
|
-
Space
|
|
831
|
-
</kbd>{" "}
|
|
832
|
-
- Activate buttons
|
|
833
|
-
</li>
|
|
834
|
-
</ul>
|
|
835
|
-
</div>
|
|
584
|
+
export const UseCases: Story = {
|
|
585
|
+
render: () => {
|
|
586
|
+
// Track actions bottom drawer
|
|
587
|
+
const TrackActionsDrawer = () => {
|
|
588
|
+
const [liked, setLiked] = useState(false)
|
|
589
|
+
const [queued, setQueued] = useState(false)
|
|
836
590
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
</
|
|
847
|
-
|
|
591
|
+
return (
|
|
592
|
+
<Drawer direction="bottom">
|
|
593
|
+
<DrawerTrigger asChild>
|
|
594
|
+
<Button variant="outline" size="sm">
|
|
595
|
+
Track actions
|
|
596
|
+
</Button>
|
|
597
|
+
</DrawerTrigger>
|
|
598
|
+
<DrawerContent showSwipeButton>
|
|
599
|
+
<DrawerHeader>
|
|
600
|
+
<DrawerTitle>Midnight Drive</DrawerTitle>
|
|
601
|
+
<DrawerDescription>Lo-fi Chill · 3:42</DrawerDescription>
|
|
602
|
+
</DrawerHeader>
|
|
848
603
|
|
|
849
|
-
<div className="
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
604
|
+
<div className="space-y-1 p-4">
|
|
605
|
+
{[
|
|
606
|
+
{
|
|
607
|
+
label: liked ? "Remove from Liked" : "Like this track",
|
|
608
|
+
icon: TickCircleIcon,
|
|
609
|
+
action: () => setLiked((v) => !v),
|
|
610
|
+
active: liked,
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
label: queued ? "Remove from queue" : "Add to queue",
|
|
614
|
+
icon: MusicalNoteIcon,
|
|
615
|
+
action: () => setQueued((v) => !v),
|
|
616
|
+
active: queued,
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
label: "Go to artist",
|
|
620
|
+
icon: ChevronRightIcon,
|
|
621
|
+
action: () => {},
|
|
622
|
+
active: false,
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
label: "Share",
|
|
626
|
+
icon: SearchIcon,
|
|
627
|
+
action: () => {},
|
|
628
|
+
active: false,
|
|
629
|
+
},
|
|
630
|
+
].map((item) => (
|
|
631
|
+
<button
|
|
632
|
+
key={item.label}
|
|
633
|
+
onClick={item.action}
|
|
634
|
+
className={`flex w-full items-center gap-3 rounded-lg px-3 py-3 text-left transition-colors ${
|
|
635
|
+
item.active
|
|
636
|
+
? "bg-fm-surface-positive-sec text-fm-primary"
|
|
637
|
+
: "text-fm-primary hover:bg-fm-surface-secondary"
|
|
638
|
+
}`}
|
|
639
|
+
>
|
|
640
|
+
<item.icon className="text-fm-secondary h-5 w-5 shrink-0" />
|
|
641
|
+
<span className="font-fm-text text-fm-md leading-fm-md">
|
|
642
|
+
{item.label}
|
|
643
|
+
</span>
|
|
644
|
+
</button>
|
|
645
|
+
))}
|
|
857
646
|
</div>
|
|
858
|
-
</div>
|
|
859
647
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
parameters: {
|
|
870
|
-
docs: {
|
|
871
|
-
description: {
|
|
872
|
-
story:
|
|
873
|
-
"Comprehensive accessibility example showcasing keyboard navigation, focus management, and drag support features.",
|
|
874
|
-
},
|
|
875
|
-
},
|
|
876
|
-
},
|
|
877
|
-
}
|
|
648
|
+
<DrawerFooter>
|
|
649
|
+
<DrawerClose asChild>
|
|
650
|
+
<Button variant="outline">Close</Button>
|
|
651
|
+
</DrawerClose>
|
|
652
|
+
</DrawerFooter>
|
|
653
|
+
</DrawerContent>
|
|
654
|
+
</Drawer>
|
|
655
|
+
)
|
|
656
|
+
}
|
|
878
657
|
|
|
879
|
-
//
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
<DrawerHeader>
|
|
889
|
-
<DrawerTitle>Drawer Without Overlay</DrawerTitle>
|
|
890
|
-
<DrawerDescription>
|
|
891
|
-
This drawer opens without a backdrop overlay, allowing background
|
|
892
|
-
content to remain visible.
|
|
893
|
-
</DrawerDescription>
|
|
894
|
-
</DrawerHeader>
|
|
895
|
-
<DrawerFooter>
|
|
896
|
-
<Button>Apply Changes</Button>
|
|
897
|
-
<DrawerClose asChild>
|
|
898
|
-
<Button variant="outline">Cancel</Button>
|
|
899
|
-
</DrawerClose>
|
|
900
|
-
</DrawerFooter>
|
|
901
|
-
</DrawerContent>
|
|
902
|
-
</Drawer>
|
|
903
|
-
</div>
|
|
904
|
-
),
|
|
905
|
-
parameters: {
|
|
906
|
-
docs: {
|
|
907
|
-
description: {
|
|
908
|
-
story:
|
|
909
|
-
"Drawer example with `showOverlay={false}` demonstrating how to create non-modal drawer interactions that don't obscure background content.",
|
|
910
|
-
},
|
|
911
|
-
},
|
|
912
|
-
},
|
|
913
|
-
}
|
|
658
|
+
// Side navigation drawer
|
|
659
|
+
const NavDrawer = () => {
|
|
660
|
+
const [active, setActive] = useState("Home")
|
|
661
|
+
const items = [
|
|
662
|
+
{ label: "Home", icon: SiteLogoIcon },
|
|
663
|
+
{ label: "Search", icon: SearchIcon },
|
|
664
|
+
{ label: "Library", icon: MusicalNoteIcon },
|
|
665
|
+
{ label: "Settings", icon: MaintenanceIcon },
|
|
666
|
+
]
|
|
914
667
|
|
|
915
|
-
// 8. Overlay Variations
|
|
916
|
-
export const OverlayVariations: Story = {
|
|
917
|
-
render: () => {
|
|
918
|
-
const OverlayDrawer = ({
|
|
919
|
-
opacity,
|
|
920
|
-
glass,
|
|
921
|
-
noise,
|
|
922
|
-
title,
|
|
923
|
-
description,
|
|
924
|
-
}: any) => {
|
|
925
668
|
return (
|
|
926
|
-
<Drawer>
|
|
669
|
+
<Drawer direction="left">
|
|
927
670
|
<DrawerTrigger asChild>
|
|
928
671
|
<Button variant="outline" size="sm">
|
|
929
|
-
|
|
672
|
+
Side navigation
|
|
930
673
|
</Button>
|
|
931
674
|
</DrawerTrigger>
|
|
932
|
-
<DrawerContent
|
|
933
|
-
opacity={opacity}
|
|
934
|
-
glass={glass}
|
|
935
|
-
noise={noise}
|
|
936
|
-
variant="neutral"
|
|
937
|
-
>
|
|
675
|
+
<DrawerContent>
|
|
938
676
|
<DrawerHeader>
|
|
939
|
-
<DrawerTitle>
|
|
940
|
-
<DrawerDescription>
|
|
677
|
+
<DrawerTitle>Navigation</DrawerTitle>
|
|
678
|
+
<DrawerDescription>Main app navigation</DrawerDescription>
|
|
941
679
|
</DrawerHeader>
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
680
|
+
|
|
681
|
+
<nav className="space-y-1 p-4">
|
|
682
|
+
{items.map((item) => (
|
|
683
|
+
<button
|
|
684
|
+
key={item.label}
|
|
685
|
+
onClick={() => setActive(item.label)}
|
|
686
|
+
className={`flex w-full items-center gap-3 rounded-lg px-3 py-3 text-left transition-colors ${
|
|
687
|
+
active === item.label
|
|
688
|
+
? "bg-fm-surface-info-sec text-fm-primary"
|
|
689
|
+
: "text-fm-primary hover:bg-fm-surface-secondary"
|
|
690
|
+
}`}
|
|
691
|
+
>
|
|
692
|
+
<item.icon className="text-fm-secondary h-5 w-5 shrink-0" />
|
|
693
|
+
<span className="font-fm-text text-fm-md leading-fm-md">
|
|
694
|
+
{item.label}
|
|
948
695
|
</span>
|
|
696
|
+
</button>
|
|
697
|
+
))}
|
|
698
|
+
</nav>
|
|
699
|
+
|
|
700
|
+
<DrawerFooter>
|
|
701
|
+
<DrawerClose asChild>
|
|
702
|
+
<Button variant="outline">Close</Button>
|
|
703
|
+
</DrawerClose>
|
|
704
|
+
</DrawerFooter>
|
|
705
|
+
</DrawerContent>
|
|
706
|
+
</Drawer>
|
|
707
|
+
)
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// Settings panel drawer
|
|
711
|
+
const SettingsDrawer = () => {
|
|
712
|
+
const [autoplay, setAutoplay] = useState(true)
|
|
713
|
+
const [notifications, setNotifications] = useState(false)
|
|
714
|
+
const [hq, setHq] = useState(true)
|
|
715
|
+
|
|
716
|
+
return (
|
|
717
|
+
<Drawer direction="right">
|
|
718
|
+
<DrawerTrigger asChild>
|
|
719
|
+
<Button variant="outline" size="sm">
|
|
720
|
+
Settings panel
|
|
721
|
+
</Button>
|
|
722
|
+
</DrawerTrigger>
|
|
723
|
+
<DrawerContent>
|
|
724
|
+
<DrawerHeader>
|
|
725
|
+
<DrawerTitle>Playback Settings</DrawerTitle>
|
|
726
|
+
<DrawerDescription>
|
|
727
|
+
Configure your listening experience
|
|
728
|
+
</DrawerDescription>
|
|
729
|
+
</DrawerHeader>
|
|
730
|
+
|
|
731
|
+
<div className="space-y-5 p-4">
|
|
732
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
733
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm mb-3 font-semibold tracking-widest uppercase">
|
|
734
|
+
Playback
|
|
735
|
+
</p>
|
|
736
|
+
<div className="space-y-3">
|
|
737
|
+
{[
|
|
738
|
+
{ label: "Autoplay", value: autoplay, set: setAutoplay },
|
|
739
|
+
{ label: "High quality audio", value: hq, set: setHq },
|
|
740
|
+
].map((s) => (
|
|
741
|
+
<div
|
|
742
|
+
key={s.label}
|
|
743
|
+
className="flex items-center justify-between"
|
|
744
|
+
>
|
|
745
|
+
<span className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
|
|
746
|
+
{s.label}
|
|
747
|
+
</span>
|
|
748
|
+
<Checkbox
|
|
749
|
+
checked={s.value}
|
|
750
|
+
onCheckedChange={(c) => s.set(!!c)}
|
|
751
|
+
/>
|
|
752
|
+
</div>
|
|
753
|
+
))}
|
|
949
754
|
</div>
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
755
|
+
</div>
|
|
756
|
+
|
|
757
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
758
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm mb-3 font-semibold tracking-widest uppercase">
|
|
759
|
+
Notifications
|
|
760
|
+
</p>
|
|
761
|
+
<div className="flex items-center justify-between">
|
|
762
|
+
<span className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
|
|
763
|
+
Push notifications
|
|
764
|
+
</span>
|
|
765
|
+
<Checkbox
|
|
766
|
+
checked={notifications}
|
|
767
|
+
onCheckedChange={(c) => setNotifications(!!c)}
|
|
768
|
+
/>
|
|
960
769
|
</div>
|
|
961
770
|
</div>
|
|
962
771
|
</div>
|
|
772
|
+
|
|
963
773
|
<DrawerFooter>
|
|
964
774
|
<DrawerClose asChild>
|
|
965
|
-
<Button>
|
|
775
|
+
<Button>Save</Button>
|
|
776
|
+
</DrawerClose>
|
|
777
|
+
<DrawerClose asChild>
|
|
778
|
+
<Button variant="outline">Cancel</Button>
|
|
966
779
|
</DrawerClose>
|
|
967
780
|
</DrawerFooter>
|
|
968
781
|
</DrawerContent>
|
|
@@ -971,180 +784,39 @@ export const OverlayVariations: Story = {
|
|
|
971
784
|
}
|
|
972
785
|
|
|
973
786
|
return (
|
|
974
|
-
<div className="space-y-8">
|
|
975
|
-
<div className="
|
|
976
|
-
<
|
|
977
|
-
|
|
978
|
-
</
|
|
979
|
-
<p className="text-fm-
|
|
980
|
-
|
|
787
|
+
<div className="mx-auto max-w-3xl space-y-8 p-8">
|
|
788
|
+
<div className="space-y-3">
|
|
789
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
790
|
+
Mobile Bottom Drawer — Track Actions
|
|
791
|
+
</h4>
|
|
792
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-xl">
|
|
793
|
+
A bottom sheet presenting contextual actions for the currently
|
|
794
|
+
playing track. Includes a swipe handle and stateful like/queue
|
|
795
|
+
toggles.
|
|
981
796
|
</p>
|
|
797
|
+
<TrackActionsDrawer />
|
|
982
798
|
</div>
|
|
983
799
|
|
|
984
|
-
<div className="
|
|
985
|
-
<
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
opacity="medium"
|
|
992
|
-
title="Medium Opacity"
|
|
993
|
-
description="Balanced background dimming (60%)"
|
|
994
|
-
/>
|
|
995
|
-
<OverlayDrawer
|
|
996
|
-
opacity="high"
|
|
997
|
-
title="High Opacity"
|
|
998
|
-
description="Strong background dimming (80%)"
|
|
999
|
-
/>
|
|
1000
|
-
<OverlayDrawer
|
|
1001
|
-
opacity="none"
|
|
1002
|
-
title="Full Opacity"
|
|
1003
|
-
description="Complete background coverage (100%)"
|
|
1004
|
-
/>
|
|
1005
|
-
<OverlayDrawer
|
|
1006
|
-
glass="low"
|
|
1007
|
-
title="Low Glass"
|
|
1008
|
-
description="Subtle backdrop blur effect"
|
|
1009
|
-
/>
|
|
1010
|
-
<OverlayDrawer
|
|
1011
|
-
glass="medium"
|
|
1012
|
-
title="Medium Glass"
|
|
1013
|
-
description="Balanced backdrop blur effect"
|
|
1014
|
-
/>
|
|
1015
|
-
<OverlayDrawer
|
|
1016
|
-
glass="high"
|
|
1017
|
-
title="High Glass"
|
|
1018
|
-
description="Strong backdrop blur effect"
|
|
1019
|
-
/>
|
|
1020
|
-
<OverlayDrawer
|
|
1021
|
-
noise="low"
|
|
1022
|
-
title="Low Noise"
|
|
1023
|
-
description="Subtle texture pattern"
|
|
1024
|
-
/>
|
|
1025
|
-
<OverlayDrawer
|
|
1026
|
-
noise="medium"
|
|
1027
|
-
title="Medium Noise"
|
|
1028
|
-
description="Balanced texture pattern"
|
|
1029
|
-
/>
|
|
1030
|
-
<OverlayDrawer
|
|
1031
|
-
noise="high"
|
|
1032
|
-
title="High Noise"
|
|
1033
|
-
description="Strong texture pattern"
|
|
1034
|
-
/>
|
|
1035
|
-
<OverlayDrawer
|
|
1036
|
-
opacity="medium"
|
|
1037
|
-
glass="medium"
|
|
1038
|
-
noise="medium"
|
|
1039
|
-
title="Balanced"
|
|
1040
|
-
description="All effects at medium level"
|
|
1041
|
-
/>
|
|
1042
|
-
</div>
|
|
1043
|
-
</div>
|
|
1044
|
-
)
|
|
1045
|
-
},
|
|
1046
|
-
parameters: {
|
|
1047
|
-
docs: {
|
|
1048
|
-
description: {
|
|
1049
|
-
story:
|
|
1050
|
-
"Showcase of different overlay configurations demonstrating various opacity, glass, and noise effects.",
|
|
1051
|
-
},
|
|
1052
|
-
},
|
|
1053
|
-
},
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
// 9. Variant Examples
|
|
1057
|
-
export const VariantExamples: Story = {
|
|
1058
|
-
render: () => {
|
|
1059
|
-
return (
|
|
1060
|
-
<div className="space-y-8">
|
|
1061
|
-
<div className="text-center">
|
|
1062
|
-
<h3 className="text-fm-primary mb-2 font-medium">Drawer Variants</h3>
|
|
1063
|
-
<p className="text-fm-primary/60 text-sm">
|
|
1064
|
-
Compare the neutral (default) and gradient variants
|
|
800
|
+
<div className="space-y-3">
|
|
801
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
802
|
+
Side Navigation Drawer
|
|
803
|
+
</h4>
|
|
804
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-xl">
|
|
805
|
+
A left-side navigation drawer for switching between primary app
|
|
806
|
+
sections. Active item is highlighted.
|
|
1065
807
|
</p>
|
|
808
|
+
<NavDrawer />
|
|
1066
809
|
</div>
|
|
1067
810
|
|
|
1068
|
-
<div className="
|
|
1069
|
-
<
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
</Button>
|
|
1078
|
-
</DrawerTrigger>
|
|
1079
|
-
<DrawerContent variant="neutral">
|
|
1080
|
-
<DrawerHeader>
|
|
1081
|
-
<DrawerTitle>Neutral Variant</DrawerTitle>
|
|
1082
|
-
<DrawerDescription>
|
|
1083
|
-
This is the default neutral variant with frosted glass
|
|
1084
|
-
background and border.
|
|
1085
|
-
</DrawerDescription>
|
|
1086
|
-
</DrawerHeader>
|
|
1087
|
-
<div className="py-4">
|
|
1088
|
-
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
1089
|
-
<h5 className="text-fm-primary mb-2 font-medium">
|
|
1090
|
-
Features:
|
|
1091
|
-
</h5>
|
|
1092
|
-
<ul className="text-fm-primary/70 space-y-1 text-sm">
|
|
1093
|
-
<li>• Frosted glass background</li>
|
|
1094
|
-
<li>• Subtle border</li>
|
|
1095
|
-
<li>• Backdrop blur effect</li>
|
|
1096
|
-
<li>• Semi-transparent appearance</li>
|
|
1097
|
-
</ul>
|
|
1098
|
-
</div>
|
|
1099
|
-
</div>
|
|
1100
|
-
<DrawerFooter>
|
|
1101
|
-
<DrawerClose asChild>
|
|
1102
|
-
<Button>Close</Button>
|
|
1103
|
-
</DrawerClose>
|
|
1104
|
-
</DrawerFooter>
|
|
1105
|
-
</DrawerContent>
|
|
1106
|
-
</Drawer>
|
|
1107
|
-
</div>
|
|
1108
|
-
|
|
1109
|
-
<div className="space-y-4">
|
|
1110
|
-
<h4 className="text-fm-primary text-center font-medium">
|
|
1111
|
-
Gradient Variant
|
|
1112
|
-
</h4>
|
|
1113
|
-
<Drawer>
|
|
1114
|
-
<DrawerTrigger asChild>
|
|
1115
|
-
<Button variant="outline" className="w-full">
|
|
1116
|
-
Open Gradient Drawer
|
|
1117
|
-
</Button>
|
|
1118
|
-
</DrawerTrigger>
|
|
1119
|
-
<DrawerContent variant="gradient">
|
|
1120
|
-
<DrawerHeader>
|
|
1121
|
-
<DrawerTitle>Gradient Variant</DrawerTitle>
|
|
1122
|
-
<DrawerDescription>
|
|
1123
|
-
This is the gradient variant with white gradient background
|
|
1124
|
-
and no border.
|
|
1125
|
-
</DrawerDescription>
|
|
1126
|
-
</DrawerHeader>
|
|
1127
|
-
<div className="py-4">
|
|
1128
|
-
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
1129
|
-
<h5 className="text-fm-primary mb-2 font-medium">
|
|
1130
|
-
Features:
|
|
1131
|
-
</h5>
|
|
1132
|
-
<ul className="text-fm-primary/70 space-y-1 text-sm">
|
|
1133
|
-
<li>• White gradient background</li>
|
|
1134
|
-
<li>• No border</li>
|
|
1135
|
-
<li>• Clean, modern appearance</li>
|
|
1136
|
-
<li>• Solid background effect</li>
|
|
1137
|
-
</ul>
|
|
1138
|
-
</div>
|
|
1139
|
-
</div>
|
|
1140
|
-
<DrawerFooter>
|
|
1141
|
-
<DrawerClose asChild>
|
|
1142
|
-
<Button>Close</Button>
|
|
1143
|
-
</DrawerClose>
|
|
1144
|
-
</DrawerFooter>
|
|
1145
|
-
</DrawerContent>
|
|
1146
|
-
</Drawer>
|
|
1147
|
-
</div>
|
|
811
|
+
<div className="space-y-3">
|
|
812
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
813
|
+
Settings Panel Drawer
|
|
814
|
+
</h4>
|
|
815
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-xl">
|
|
816
|
+
A right-side settings panel that groups playback and notification
|
|
817
|
+
preferences with interactive checkboxes.
|
|
818
|
+
</p>
|
|
819
|
+
<SettingsDrawer />
|
|
1148
820
|
</div>
|
|
1149
821
|
</div>
|
|
1150
822
|
)
|
|
@@ -1153,43 +825,7 @@ export const VariantExamples: Story = {
|
|
|
1153
825
|
docs: {
|
|
1154
826
|
description: {
|
|
1155
827
|
story:
|
|
1156
|
-
"
|
|
1157
|
-
},
|
|
1158
|
-
},
|
|
1159
|
-
},
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
export const DrawerWithSwipeButton: Story = {
|
|
1163
|
-
render: () => (
|
|
1164
|
-
<div>
|
|
1165
|
-
<Drawer>
|
|
1166
|
-
<DrawerTrigger asChild>
|
|
1167
|
-
<Button className="relative z-10">
|
|
1168
|
-
Open Drawer (With Swipe button)
|
|
1169
|
-
</Button>
|
|
1170
|
-
</DrawerTrigger>
|
|
1171
|
-
<DrawerContent showSwipeButton={true}>
|
|
1172
|
-
<DrawerHeader>
|
|
1173
|
-
<DrawerTitle>Drawer with Swipe button</DrawerTitle>
|
|
1174
|
-
<DrawerDescription>
|
|
1175
|
-
This drawer opens with a swipe button.
|
|
1176
|
-
</DrawerDescription>
|
|
1177
|
-
</DrawerHeader>
|
|
1178
|
-
<DrawerFooter>
|
|
1179
|
-
<Button>Apply Changes</Button>
|
|
1180
|
-
<DrawerClose asChild>
|
|
1181
|
-
<Button variant="outline">Cancel</Button>
|
|
1182
|
-
</DrawerClose>
|
|
1183
|
-
</DrawerFooter>
|
|
1184
|
-
</DrawerContent>
|
|
1185
|
-
</Drawer>
|
|
1186
|
-
</div>
|
|
1187
|
-
),
|
|
1188
|
-
parameters: {
|
|
1189
|
-
docs: {
|
|
1190
|
-
description: {
|
|
1191
|
-
story:
|
|
1192
|
-
"Drawer example with `showSwipeButton={true}` showing a swipe indicator button",
|
|
828
|
+
"Three realistic product scenarios: a mobile bottom track-actions sheet, a left-side app navigation drawer, and a right-side settings panel.",
|
|
1193
829
|
},
|
|
1194
830
|
},
|
|
1195
831
|
},
|