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
|
@@ -1,142 +1,66 @@
|
|
|
1
|
-
import React from "react"
|
|
1
|
+
import React, { useState } from "react"
|
|
2
2
|
import {
|
|
3
3
|
AlertIcon,
|
|
4
4
|
EditBigIcon,
|
|
5
5
|
EyeCloseIcon,
|
|
6
6
|
EyeOpenIcon,
|
|
7
7
|
FileChartIcon,
|
|
8
|
-
|
|
8
|
+
MoonIcon,
|
|
9
|
+
PauseIcon,
|
|
9
10
|
SearchIcon,
|
|
11
|
+
SkipBackwardIcon,
|
|
12
|
+
SkipForwardIcon,
|
|
10
13
|
TickCircleIcon,
|
|
11
14
|
TrashIcon,
|
|
15
|
+
VolumeFullIcon,
|
|
12
16
|
} from "@icons/index"
|
|
13
17
|
import type { Meta, StoryObj } from "@storybook/react-vite"
|
|
14
18
|
|
|
19
|
+
import { AuralComponentDocsPage } from "src/ui/story-spec/components/component-story-docs-page"
|
|
20
|
+
|
|
15
21
|
import { Toggle } from "."
|
|
16
22
|
|
|
17
23
|
const meta: Meta<typeof Toggle> = {
|
|
18
24
|
title: "Components/UI/Toggle",
|
|
19
25
|
component: Toggle,
|
|
26
|
+
tags: ["autodocs"],
|
|
20
27
|
parameters: {
|
|
21
28
|
layout: "centered",
|
|
22
|
-
backgrounds: {
|
|
23
|
-
default: "dark",
|
|
24
|
-
values: [
|
|
25
|
-
{ name: "dark", value: "#0a0a0a" },
|
|
26
|
-
{ name: "light", value: "#ffffff" },
|
|
27
|
-
],
|
|
28
|
-
},
|
|
29
29
|
docs: {
|
|
30
30
|
description: {
|
|
31
|
-
component:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
A flexible toggle button component built on top of Radix UI's Toggle primitive, providing on/off state management with visual feedback.
|
|
35
|
-
|
|
36
|
-
## Features
|
|
37
|
-
|
|
38
|
-
- **State Management**: Built-in pressed/unpressed state handling
|
|
39
|
-
- **Keyboard Accessible**: Full keyboard navigation support
|
|
40
|
-
- **Multiple Variants**: Default and outline styles
|
|
41
|
-
- **Size Options**: Small, default, and large sizes
|
|
42
|
-
- **Icon Support**: Automatic icon sizing and styling
|
|
43
|
-
- **Disabled State**: Proper disabled state handling
|
|
44
|
-
- **Focus Management**: Clear focus indicators
|
|
45
|
-
- **ARIA Support**: Proper accessibility attributes
|
|
46
|
-
|
|
47
|
-
## Variants
|
|
48
|
-
|
|
49
|
-
### Default
|
|
50
|
-
- **default**: Transparent background with accent highlighting
|
|
51
|
-
- **outline**: Border style with shadow and hover effects
|
|
52
|
-
|
|
53
|
-
### Sizes
|
|
54
|
-
- **sm**: Small (32px height, compact padding)
|
|
55
|
-
- **default**: Standard (36px height, balanced padding)
|
|
56
|
-
- **lg**: Large (40px height, generous padding)
|
|
57
|
-
|
|
58
|
-
## Usage Examples
|
|
59
|
-
|
|
60
|
-
### Basic Toggle
|
|
61
|
-
\`\`\`tsx
|
|
62
|
-
<Toggle aria-label="Toggle bold">
|
|
63
|
-
Bold
|
|
64
|
-
</Toggle>
|
|
65
|
-
\`\`\`
|
|
66
|
-
|
|
67
|
-
### With Icon
|
|
68
|
-
\`\`\`tsx
|
|
69
|
-
<Toggle aria-label="Toggle notifications">
|
|
70
|
-
<AlertIcon />
|
|
71
|
-
Notifications
|
|
72
|
-
</Toggle>
|
|
73
|
-
\`\`\`
|
|
74
|
-
|
|
75
|
-
### Icon Only
|
|
76
|
-
\`\`\`tsx
|
|
77
|
-
<Toggle aria-label="Toggle visibility">
|
|
78
|
-
<EyeOpenIcon />
|
|
79
|
-
</Toggle>
|
|
80
|
-
\`\`\`
|
|
81
|
-
|
|
82
|
-
### Controlled State
|
|
83
|
-
\`\`\`tsx
|
|
84
|
-
const [pressed, setPressed] = useState(false)
|
|
85
|
-
|
|
86
|
-
<Toggle
|
|
87
|
-
pressed={pressed}
|
|
88
|
-
onPressedChange={setPressed}
|
|
89
|
-
aria-label="Toggle feature"
|
|
90
|
-
>
|
|
91
|
-
Feature
|
|
92
|
-
</Toggle>
|
|
93
|
-
\`\`\`
|
|
94
|
-
|
|
95
|
-
### Different Variants
|
|
96
|
-
\`\`\`tsx
|
|
97
|
-
<Toggle variant="outline" size="sm">
|
|
98
|
-
Small Outline
|
|
99
|
-
</Toggle>
|
|
100
|
-
\`\`\`
|
|
101
|
-
|
|
102
|
-
## Accessibility
|
|
103
|
-
|
|
104
|
-
- **ARIA Label**: Always provide \`aria-label\` for screen readers
|
|
105
|
-
- **Keyboard Navigation**: Spacebar and Enter toggle state
|
|
106
|
-
- **Focus Indicators**: Clear visual focus ring
|
|
107
|
-
- **State Announcement**: Screen readers announce pressed state
|
|
108
|
-
- **Semantic HTML**: Uses proper button semantics
|
|
109
|
-
|
|
110
|
-
## States
|
|
111
|
-
|
|
112
|
-
- **Default**: Unpressed/off state
|
|
113
|
-
- **Pressed**: Pressed/on state with accent styling
|
|
114
|
-
- **Hover**: Subtle background change on hover
|
|
115
|
-
- **Focus**: Clear focus ring for keyboard navigation
|
|
116
|
-
- **Disabled**: Reduced opacity and no interaction
|
|
117
|
-
|
|
118
|
-
## Best Practices
|
|
119
|
-
|
|
120
|
-
- Always provide descriptive \`aria-label\` attributes
|
|
121
|
-
- Use consistent toggle patterns throughout your app
|
|
122
|
-
- Consider using icons to enhance visual clarity
|
|
123
|
-
- Test with keyboard navigation and screen readers
|
|
124
|
-
- Provide visual feedback for state changes
|
|
125
|
-
`,
|
|
31
|
+
component:
|
|
32
|
+
"A stateful toggle button built on Radix UI's Toggle primitive. Supports three visual variants (default, outline, filled), three sizes (sm, default, lg), pressed/unpressed states, disabled state, and icon or text content.",
|
|
126
33
|
},
|
|
34
|
+
page: () => (
|
|
35
|
+
<AuralComponentDocsPage
|
|
36
|
+
features={[
|
|
37
|
+
{
|
|
38
|
+
title: "3 Variants",
|
|
39
|
+
description: "Default, outline, filled",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
title: "Pressed State",
|
|
43
|
+
description: "Controlled or uncontrolled",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
title: "Icon or Text",
|
|
47
|
+
description: "Flexible content slot",
|
|
48
|
+
},
|
|
49
|
+
]}
|
|
50
|
+
/>
|
|
51
|
+
),
|
|
127
52
|
},
|
|
128
53
|
},
|
|
129
|
-
tags: ["autodocs"],
|
|
130
54
|
argTypes: {
|
|
131
55
|
variant: {
|
|
132
56
|
control: "select",
|
|
133
|
-
options: ["default", "outline"],
|
|
57
|
+
options: ["default", "outline", "filled"],
|
|
134
58
|
description: "Visual style variant",
|
|
135
59
|
},
|
|
136
60
|
size: {
|
|
137
61
|
control: "select",
|
|
138
62
|
options: ["sm", "default", "lg"],
|
|
139
|
-
description: "Size of the toggle
|
|
63
|
+
description: "Size of the toggle",
|
|
140
64
|
},
|
|
141
65
|
pressed: {
|
|
142
66
|
control: "boolean",
|
|
@@ -146,180 +70,178 @@ const [pressed, setPressed] = useState(false)
|
|
|
146
70
|
control: "boolean",
|
|
147
71
|
description: "Disabled state",
|
|
148
72
|
},
|
|
149
|
-
className: {
|
|
150
|
-
control: "text",
|
|
151
|
-
description: "Additional CSS classes",
|
|
152
|
-
},
|
|
153
73
|
},
|
|
154
74
|
}
|
|
155
75
|
|
|
156
76
|
export default meta
|
|
157
77
|
type Story = StoryObj<typeof Toggle>
|
|
158
78
|
|
|
159
|
-
// 1.
|
|
160
|
-
|
|
79
|
+
// ─── 1. Playground ────────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
export const Playground: Story = {
|
|
161
82
|
args: {
|
|
162
|
-
children: "Toggle
|
|
163
|
-
|
|
83
|
+
children: "Toggle",
|
|
84
|
+
variant: "default",
|
|
85
|
+
size: "default",
|
|
86
|
+
"aria-label": "Playground toggle",
|
|
164
87
|
},
|
|
88
|
+
render: (args) => (
|
|
89
|
+
<div className="w-full max-w-sm space-y-4">
|
|
90
|
+
<div className="flex justify-center">
|
|
91
|
+
<Toggle {...args} />
|
|
92
|
+
</div>
|
|
93
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-4 py-3">
|
|
94
|
+
<code className="text-fm-secondary text-fm-md leading-fm-md font-(--font-fm-mono)">{`<Toggle variant="${args.variant}" size="${args.size}">${args.children}</Toggle>`}</code>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
),
|
|
165
98
|
parameters: {
|
|
166
99
|
docs: {
|
|
167
100
|
description: {
|
|
168
|
-
story:
|
|
101
|
+
story:
|
|
102
|
+
"Adjust variant, size, pressed, and disabled using the controls panel in the sidebar.",
|
|
169
103
|
},
|
|
170
104
|
},
|
|
171
105
|
},
|
|
172
106
|
}
|
|
173
107
|
|
|
174
|
-
// 2. Variants
|
|
175
|
-
export const Variants: Story = {
|
|
176
|
-
render: () => (
|
|
177
|
-
<div className="flex flex-col gap-8 p-8">
|
|
178
|
-
<h3 className="text-fm-primary text-center text-lg font-medium">
|
|
179
|
-
Toggle Variants
|
|
180
|
-
</h3>
|
|
108
|
+
// ─── 2. All Variants ──────────────────────────────────────────────────────────
|
|
181
109
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
110
|
+
export const AllVariants: Story = {
|
|
111
|
+
render: () => (
|
|
112
|
+
<div className="space-y-8">
|
|
113
|
+
{/* Default variant × sizes */}
|
|
114
|
+
<div className="space-y-4">
|
|
115
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
116
|
+
Default variant — all sizes
|
|
117
|
+
</h4>
|
|
118
|
+
<div className="flex flex-wrap items-end gap-4">
|
|
119
|
+
<div className="space-y-2 text-center">
|
|
120
|
+
<Toggle size="sm" aria-label="Default small">
|
|
121
|
+
Small
|
|
192
122
|
</Toggle>
|
|
193
|
-
<
|
|
194
|
-
|
|
123
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
124
|
+
sm
|
|
125
|
+
</p>
|
|
126
|
+
</div>
|
|
127
|
+
<div className="space-y-2 text-center">
|
|
128
|
+
<Toggle size="default" aria-label="Default default">
|
|
129
|
+
Default
|
|
195
130
|
</Toggle>
|
|
131
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
132
|
+
default
|
|
133
|
+
</p>
|
|
134
|
+
</div>
|
|
135
|
+
<div className="space-y-2 text-center">
|
|
136
|
+
<Toggle size="lg" aria-label="Default large">
|
|
137
|
+
Large
|
|
138
|
+
</Toggle>
|
|
139
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
140
|
+
lg
|
|
141
|
+
</p>
|
|
196
142
|
</div>
|
|
197
143
|
</div>
|
|
144
|
+
</div>
|
|
198
145
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
146
|
+
{/* Outline variant × sizes */}
|
|
147
|
+
<div className="space-y-4">
|
|
148
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
149
|
+
Outline variant — all sizes
|
|
150
|
+
</h4>
|
|
151
|
+
<div className="flex flex-wrap items-end gap-4">
|
|
152
|
+
<div className="space-y-2 text-center">
|
|
153
|
+
<Toggle variant="outline" size="sm" aria-label="Outline small">
|
|
154
|
+
Small
|
|
207
155
|
</Toggle>
|
|
156
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
157
|
+
sm
|
|
158
|
+
</p>
|
|
159
|
+
</div>
|
|
160
|
+
<div className="space-y-2 text-center">
|
|
208
161
|
<Toggle
|
|
209
162
|
variant="outline"
|
|
210
|
-
|
|
211
|
-
aria-label="Outline
|
|
163
|
+
size="default"
|
|
164
|
+
aria-label="Outline default"
|
|
212
165
|
>
|
|
213
|
-
|
|
214
|
-
</Toggle>
|
|
215
|
-
<Toggle variant="outline" disabled aria-label="Outline disabled">
|
|
216
|
-
Disabled
|
|
166
|
+
Default
|
|
217
167
|
</Toggle>
|
|
168
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
169
|
+
default
|
|
170
|
+
</p>
|
|
218
171
|
</div>
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
<div className="space-y-4">
|
|
223
|
-
<h4 className="text-fm-secondary text-sm font-medium">
|
|
224
|
-
Filled Variant
|
|
225
|
-
</h4>
|
|
226
|
-
<div className="flex flex-wrap gap-4">
|
|
227
|
-
<Toggle variant="filled" aria-label="Filled unpressed">
|
|
228
|
-
Filled
|
|
229
|
-
</Toggle>
|
|
230
|
-
<Toggle variant="filled" defaultPressed aria-label="Filled pressed">
|
|
231
|
-
Pressed
|
|
232
|
-
</Toggle>
|
|
233
|
-
<Toggle variant="filled" disabled aria-label="Filled disabled">
|
|
234
|
-
Disabled
|
|
172
|
+
<div className="space-y-2 text-center">
|
|
173
|
+
<Toggle variant="outline" size="lg" aria-label="Outline large">
|
|
174
|
+
Large
|
|
235
175
|
</Toggle>
|
|
176
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
177
|
+
lg
|
|
178
|
+
</p>
|
|
236
179
|
</div>
|
|
237
180
|
</div>
|
|
238
181
|
</div>
|
|
239
|
-
</div>
|
|
240
|
-
),
|
|
241
|
-
parameters: {
|
|
242
|
-
docs: {
|
|
243
|
-
description: {
|
|
244
|
-
story:
|
|
245
|
-
"Different visual variants showing default and outline styles in various states.",
|
|
246
|
-
},
|
|
247
|
-
},
|
|
248
|
-
},
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// 3. Sizes
|
|
252
|
-
export const Sizes: Story = {
|
|
253
|
-
render: () => (
|
|
254
|
-
<div className="space-y-8 p-8">
|
|
255
|
-
<h3 className="text-fm-primary text-center text-lg font-medium">
|
|
256
|
-
Toggle Sizes
|
|
257
|
-
</h3>
|
|
258
|
-
|
|
259
|
-
<div className="space-y-6">
|
|
260
|
-
{/* Size Comparison */}
|
|
261
|
-
<div className="space-y-4">
|
|
262
|
-
<h4 className="text-fm-secondary text-center text-sm font-medium">
|
|
263
|
-
Size Comparison
|
|
264
|
-
</h4>
|
|
265
|
-
<div className="flex items-center justify-center gap-4">
|
|
266
|
-
<div className="flex flex-col items-center gap-2">
|
|
267
|
-
<Toggle size="sm" aria-label="Small toggle">
|
|
268
|
-
Small
|
|
269
|
-
</Toggle>
|
|
270
|
-
<span className="text-fm-secondary text-xs">Small (32px)</span>
|
|
271
|
-
</div>
|
|
272
|
-
<div className="flex flex-col items-center gap-2">
|
|
273
|
-
<Toggle size="default" aria-label="Default toggle">
|
|
274
|
-
Default
|
|
275
|
-
</Toggle>
|
|
276
|
-
<span className="text-fm-secondary text-xs">Default (36px)</span>
|
|
277
|
-
</div>
|
|
278
|
-
<div className="flex flex-col items-center gap-2">
|
|
279
|
-
<Toggle size="lg" aria-label="Large toggle">
|
|
280
|
-
Large
|
|
281
|
-
</Toggle>
|
|
282
|
-
<span className="text-fm-secondary text-xs">Large (40px)</span>
|
|
283
|
-
</div>
|
|
284
|
-
</div>
|
|
285
|
-
</div>
|
|
286
182
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
183
|
+
{/* Filled variant × sizes */}
|
|
184
|
+
<div className="space-y-4">
|
|
185
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
186
|
+
Filled variant — all sizes
|
|
187
|
+
</h4>
|
|
188
|
+
<div className="flex flex-wrap items-end gap-4">
|
|
189
|
+
<div className="space-y-2 text-center">
|
|
190
|
+
<Toggle variant="filled" size="sm" aria-label="Filled small">
|
|
295
191
|
Small
|
|
296
192
|
</Toggle>
|
|
297
|
-
<
|
|
298
|
-
|
|
193
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
194
|
+
sm
|
|
195
|
+
</p>
|
|
196
|
+
</div>
|
|
197
|
+
<div className="space-y-2 text-center">
|
|
198
|
+
<Toggle variant="filled" size="default" aria-label="Filled default">
|
|
299
199
|
Default
|
|
300
200
|
</Toggle>
|
|
301
|
-
<
|
|
302
|
-
|
|
201
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
202
|
+
default
|
|
203
|
+
</p>
|
|
204
|
+
</div>
|
|
205
|
+
<div className="space-y-2 text-center">
|
|
206
|
+
<Toggle variant="filled" size="lg" aria-label="Filled large">
|
|
303
207
|
Large
|
|
304
208
|
</Toggle>
|
|
209
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
210
|
+
lg
|
|
211
|
+
</p>
|
|
305
212
|
</div>
|
|
306
213
|
</div>
|
|
214
|
+
</div>
|
|
307
215
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
216
|
+
{/* Icon-only × all variants */}
|
|
217
|
+
<div className="space-y-4">
|
|
218
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
219
|
+
Icon-only — all variants
|
|
220
|
+
</h4>
|
|
221
|
+
<div className="flex flex-wrap items-center gap-4">
|
|
222
|
+
<div className="space-y-2 text-center">
|
|
223
|
+
<Toggle aria-label="Default icon only">
|
|
224
|
+
<SearchIcon />
|
|
316
225
|
</Toggle>
|
|
317
|
-
<
|
|
226
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
227
|
+
default
|
|
228
|
+
</p>
|
|
229
|
+
</div>
|
|
230
|
+
<div className="space-y-2 text-center">
|
|
231
|
+
<Toggle variant="outline" aria-label="Outline icon only">
|
|
318
232
|
<SearchIcon />
|
|
319
233
|
</Toggle>
|
|
320
|
-
<
|
|
321
|
-
|
|
234
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
235
|
+
outline
|
|
236
|
+
</p>
|
|
237
|
+
</div>
|
|
238
|
+
<div className="space-y-2 text-center">
|
|
239
|
+
<Toggle variant="filled" aria-label="Filled icon only">
|
|
240
|
+
<SearchIcon />
|
|
322
241
|
</Toggle>
|
|
242
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
243
|
+
filled
|
|
244
|
+
</p>
|
|
323
245
|
</div>
|
|
324
246
|
</div>
|
|
325
247
|
</div>
|
|
@@ -329,405 +251,173 @@ export const Sizes: Story = {
|
|
|
329
251
|
docs: {
|
|
330
252
|
description: {
|
|
331
253
|
story:
|
|
332
|
-
"
|
|
254
|
+
"Full variant × size matrix for all three visual styles (default, outline, filled), plus icon-only instances across each variant.",
|
|
333
255
|
},
|
|
334
256
|
},
|
|
335
257
|
},
|
|
336
258
|
}
|
|
337
259
|
|
|
338
|
-
//
|
|
339
|
-
export const IconToggles: Story = {
|
|
340
|
-
render: () => {
|
|
341
|
-
const [notifications, setNotifications] = React.useState(false)
|
|
342
|
-
const [visibility, setVisibility] = React.useState(false)
|
|
343
|
-
const [completed, setCompleted] = React.useState(false)
|
|
344
|
-
|
|
345
|
-
return (
|
|
346
|
-
<div className="space-y-8 p-8">
|
|
347
|
-
<h3 className="text-fm-primary text-center text-lg font-medium">
|
|
348
|
-
Icon Toggles
|
|
349
|
-
</h3>
|
|
260
|
+
// ─── 3. States ────────────────────────────────────────────────────────────────
|
|
350
261
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
</Toggle>
|
|
366
|
-
|
|
367
|
-
<Toggle
|
|
368
|
-
pressed={visibility}
|
|
369
|
-
onPressedChange={setVisibility}
|
|
370
|
-
aria-label="Toggle visibility"
|
|
371
|
-
>
|
|
372
|
-
{visibility ? <EyeOpenIcon /> : <EyeCloseIcon />}
|
|
373
|
-
{visibility ? "Visible" : "Hidden"}
|
|
374
|
-
</Toggle>
|
|
375
|
-
|
|
376
|
-
<Toggle
|
|
377
|
-
pressed={completed}
|
|
378
|
-
onPressedChange={setCompleted}
|
|
379
|
-
aria-label="Toggle completion"
|
|
380
|
-
>
|
|
381
|
-
<TickCircleIcon />
|
|
382
|
-
Complete
|
|
383
|
-
</Toggle>
|
|
384
|
-
</div>
|
|
262
|
+
export const States: Story = {
|
|
263
|
+
render: () => (
|
|
264
|
+
<div className="space-y-8">
|
|
265
|
+
{/* Default variant states */}
|
|
266
|
+
<div className="space-y-4">
|
|
267
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
268
|
+
Default variant
|
|
269
|
+
</h4>
|
|
270
|
+
<div className="flex flex-wrap gap-4">
|
|
271
|
+
<div className="space-y-2 text-center">
|
|
272
|
+
<Toggle aria-label="Unpressed default">Unpressed</Toggle>
|
|
273
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
274
|
+
Unpressed
|
|
275
|
+
</p>
|
|
385
276
|
</div>
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
<Toggle aria-label="Toggle search">
|
|
394
|
-
<SearchIcon />
|
|
395
|
-
</Toggle>
|
|
396
|
-
|
|
397
|
-
<Toggle aria-label="Toggle edit mode">
|
|
398
|
-
<EditBigIcon />
|
|
399
|
-
</Toggle>
|
|
400
|
-
|
|
401
|
-
<Toggle aria-label="Toggle charts">
|
|
402
|
-
<FileChartIcon />
|
|
403
|
-
</Toggle>
|
|
404
|
-
|
|
405
|
-
<Toggle aria-label="Add to favorites" defaultPressed>
|
|
406
|
-
<PlusIcon />
|
|
407
|
-
</Toggle>
|
|
408
|
-
|
|
409
|
-
<Toggle aria-label="Delete mode" variant="outline">
|
|
410
|
-
<TrashIcon />
|
|
411
|
-
</Toggle>
|
|
412
|
-
</div>
|
|
277
|
+
<div className="space-y-2 text-center">
|
|
278
|
+
<Toggle defaultPressed aria-label="Pressed default">
|
|
279
|
+
Pressed
|
|
280
|
+
</Toggle>
|
|
281
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
282
|
+
Pressed
|
|
283
|
+
</p>
|
|
413
284
|
</div>
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
<div className="space-y-2">
|
|
422
|
-
<span className="text-fm-secondary text-xs">
|
|
423
|
-
Default Variant
|
|
424
|
-
</span>
|
|
425
|
-
<div className="flex flex-wrap gap-2">
|
|
426
|
-
<Toggle aria-label="Default alert">
|
|
427
|
-
<AlertIcon />
|
|
428
|
-
</Toggle>
|
|
429
|
-
<Toggle defaultPressed aria-label="Default search">
|
|
430
|
-
<SearchIcon />
|
|
431
|
-
</Toggle>
|
|
432
|
-
<Toggle aria-label="Default edit">
|
|
433
|
-
<EditBigIcon />
|
|
434
|
-
</Toggle>
|
|
435
|
-
</div>
|
|
436
|
-
</div>
|
|
437
|
-
|
|
438
|
-
<div className="space-y-2">
|
|
439
|
-
<span className="text-fm-secondary text-xs">
|
|
440
|
-
Outline Variant
|
|
441
|
-
</span>
|
|
442
|
-
<div className="flex flex-wrap gap-2">
|
|
443
|
-
<Toggle variant="outline" aria-label="Outline alert">
|
|
444
|
-
<AlertIcon />
|
|
445
|
-
</Toggle>
|
|
446
|
-
<Toggle
|
|
447
|
-
variant="outline"
|
|
448
|
-
defaultPressed
|
|
449
|
-
aria-label="Outline search"
|
|
450
|
-
>
|
|
451
|
-
<SearchIcon />
|
|
452
|
-
</Toggle>
|
|
453
|
-
<Toggle variant="outline" aria-label="Outline edit">
|
|
454
|
-
<EditBigIcon />
|
|
455
|
-
</Toggle>
|
|
456
|
-
</div>
|
|
457
|
-
</div>
|
|
458
|
-
</div>
|
|
285
|
+
<div className="space-y-2 text-center">
|
|
286
|
+
<Toggle disabled aria-label="Disabled default">
|
|
287
|
+
Disabled
|
|
288
|
+
</Toggle>
|
|
289
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
290
|
+
Disabled
|
|
291
|
+
</p>
|
|
459
292
|
</div>
|
|
460
293
|
</div>
|
|
461
294
|
</div>
|
|
462
|
-
)
|
|
463
|
-
},
|
|
464
|
-
parameters: {
|
|
465
|
-
docs: {
|
|
466
|
-
description: {
|
|
467
|
-
story:
|
|
468
|
-
"Icon-based toggles showing different configurations including dynamic icons and various states.",
|
|
469
|
-
},
|
|
470
|
-
},
|
|
471
|
-
},
|
|
472
|
-
}
|
|
473
295
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
setStates((prev) => ({ ...prev, [key]: !prev[key] }))
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
return (
|
|
491
|
-
<div className="space-y-8 p-8">
|
|
492
|
-
<h3 className="text-fm-primary text-center text-lg font-medium">
|
|
493
|
-
Interactive States
|
|
494
|
-
</h3>
|
|
495
|
-
|
|
496
|
-
<div className="space-y-6">
|
|
497
|
-
{/* Text Formatting Toolbar */}
|
|
498
|
-
<div className="space-y-4">
|
|
499
|
-
<h4 className="text-fm-secondary text-center text-sm font-medium">
|
|
500
|
-
Text Formatting Toolbar
|
|
501
|
-
</h4>
|
|
502
|
-
<div className="flex justify-center">
|
|
503
|
-
<div className="border-fm-divider-secondary bg-fm-surface-secondary flex items-center gap-1 rounded-lg border p-2">
|
|
504
|
-
<Toggle
|
|
505
|
-
size="sm"
|
|
506
|
-
pressed={states.bold}
|
|
507
|
-
onPressedChange={() => updateState("bold")}
|
|
508
|
-
aria-label="Toggle bold"
|
|
509
|
-
>
|
|
510
|
-
<span className="font-bold">B</span>
|
|
511
|
-
</Toggle>
|
|
512
|
-
<Toggle
|
|
513
|
-
size="sm"
|
|
514
|
-
pressed={states.italic}
|
|
515
|
-
onPressedChange={() => updateState("italic")}
|
|
516
|
-
aria-label="Toggle italic"
|
|
517
|
-
>
|
|
518
|
-
<span className="italic">I</span>
|
|
519
|
-
</Toggle>
|
|
520
|
-
<Toggle
|
|
521
|
-
size="sm"
|
|
522
|
-
pressed={states.underline}
|
|
523
|
-
onPressedChange={() => updateState("underline")}
|
|
524
|
-
aria-label="Toggle underline"
|
|
525
|
-
>
|
|
526
|
-
<span className="underline">U</span>
|
|
527
|
-
</Toggle>
|
|
528
|
-
<div className="bg-fm-surface-tertiary mx-2 h-6 w-px"></div>
|
|
529
|
-
<Toggle size="sm" aria-label="Add item">
|
|
530
|
-
<PlusIcon />
|
|
531
|
-
</Toggle>
|
|
532
|
-
<Toggle size="sm" aria-label="Search">
|
|
533
|
-
<SearchIcon />
|
|
534
|
-
</Toggle>
|
|
535
|
-
</div>
|
|
536
|
-
</div>
|
|
296
|
+
{/* Outline variant states */}
|
|
297
|
+
<div className="space-y-4">
|
|
298
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
299
|
+
Outline variant
|
|
300
|
+
</h4>
|
|
301
|
+
<div className="flex flex-wrap gap-4">
|
|
302
|
+
<div className="space-y-2 text-center">
|
|
303
|
+
<Toggle variant="outline" aria-label="Unpressed outline">
|
|
304
|
+
Unpressed
|
|
305
|
+
</Toggle>
|
|
306
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
307
|
+
Unpressed
|
|
308
|
+
</p>
|
|
537
309
|
</div>
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
</div>
|
|
550
|
-
<Toggle
|
|
551
|
-
size="sm"
|
|
552
|
-
pressed={states.notifications}
|
|
553
|
-
onPressedChange={() => updateState("notifications")}
|
|
554
|
-
aria-label="Toggle notifications"
|
|
555
|
-
/>
|
|
556
|
-
</div>
|
|
557
|
-
|
|
558
|
-
<div className="border-fm-divider-secondary bg-fm-surface-secondary flex items-center justify-between rounded-lg border p-3">
|
|
559
|
-
<div className="flex items-center gap-3">
|
|
560
|
-
<TickCircleIcon className="text-fm-icon-positive h-4 w-4" />
|
|
561
|
-
<span className="text-fm-primary text-sm">Auto Save</span>
|
|
562
|
-
</div>
|
|
563
|
-
<Toggle
|
|
564
|
-
size="sm"
|
|
565
|
-
pressed={states.autoSave}
|
|
566
|
-
onPressedChange={() => updateState("autoSave")}
|
|
567
|
-
aria-label="Toggle auto save"
|
|
568
|
-
/>
|
|
569
|
-
</div>
|
|
570
|
-
|
|
571
|
-
<div className="border-fm-divider-secondary bg-fm-surface-secondary flex items-center justify-between rounded-lg border p-3">
|
|
572
|
-
<div className="flex items-center gap-3">
|
|
573
|
-
<EyeOpenIcon className="text-fm-icon-brand-secondary h-4 w-4" />
|
|
574
|
-
<span className="text-fm-primary text-sm">Dark Mode</span>
|
|
575
|
-
</div>
|
|
576
|
-
<Toggle
|
|
577
|
-
size="sm"
|
|
578
|
-
pressed={states.darkMode}
|
|
579
|
-
onPressedChange={() => updateState("darkMode")}
|
|
580
|
-
aria-label="Toggle dark mode"
|
|
581
|
-
/>
|
|
582
|
-
</div>
|
|
583
|
-
</div>
|
|
310
|
+
<div className="space-y-2 text-center">
|
|
311
|
+
<Toggle
|
|
312
|
+
variant="outline"
|
|
313
|
+
defaultPressed
|
|
314
|
+
aria-label="Pressed outline"
|
|
315
|
+
>
|
|
316
|
+
Pressed
|
|
317
|
+
</Toggle>
|
|
318
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
319
|
+
Pressed
|
|
320
|
+
</p>
|
|
584
321
|
</div>
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
<div className="grid grid-cols-2 gap-2 text-xs">
|
|
593
|
-
{Object.entries(states).map(([key, value]) => (
|
|
594
|
-
<div key={key} className="flex justify-between">
|
|
595
|
-
<span className="text-fm-secondary capitalize">{key}:</span>
|
|
596
|
-
<span
|
|
597
|
-
className={
|
|
598
|
-
value
|
|
599
|
-
? "text-fm-icon-positive"
|
|
600
|
-
: "text-fm-icon-negative"
|
|
601
|
-
}
|
|
602
|
-
>
|
|
603
|
-
{value ? "ON" : "OFF"}
|
|
604
|
-
</span>
|
|
605
|
-
</div>
|
|
606
|
-
))}
|
|
607
|
-
</div>
|
|
608
|
-
</div>
|
|
322
|
+
<div className="space-y-2 text-center">
|
|
323
|
+
<Toggle variant="outline" disabled aria-label="Disabled outline">
|
|
324
|
+
Disabled
|
|
325
|
+
</Toggle>
|
|
326
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
327
|
+
Disabled
|
|
328
|
+
</p>
|
|
609
329
|
</div>
|
|
610
330
|
</div>
|
|
611
331
|
</div>
|
|
612
|
-
)
|
|
613
|
-
},
|
|
614
|
-
parameters: {
|
|
615
|
-
docs: {
|
|
616
|
-
description: {
|
|
617
|
-
story:
|
|
618
|
-
"Interactive examples showing toggles in real-world scenarios like toolbars and settings panels.",
|
|
619
|
-
},
|
|
620
|
-
},
|
|
621
|
-
},
|
|
622
|
-
}
|
|
623
332
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
</
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
</ul>
|
|
333
|
+
{/* Filled variant states */}
|
|
334
|
+
<div className="space-y-4">
|
|
335
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
336
|
+
Filled variant
|
|
337
|
+
</h4>
|
|
338
|
+
<div className="flex flex-wrap gap-4">
|
|
339
|
+
<div className="space-y-2 text-center">
|
|
340
|
+
<Toggle variant="filled" aria-label="Unpressed filled">
|
|
341
|
+
Unpressed
|
|
342
|
+
</Toggle>
|
|
343
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
344
|
+
Unpressed
|
|
345
|
+
</p>
|
|
346
|
+
</div>
|
|
347
|
+
<div className="space-y-2 text-center">
|
|
348
|
+
<Toggle variant="filled" defaultPressed aria-label="Pressed filled">
|
|
349
|
+
Pressed
|
|
350
|
+
</Toggle>
|
|
351
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
352
|
+
Pressed
|
|
353
|
+
</p>
|
|
354
|
+
</div>
|
|
355
|
+
<div className="space-y-2 text-center">
|
|
356
|
+
<Toggle variant="filled" disabled aria-label="Disabled filled">
|
|
357
|
+
Disabled
|
|
358
|
+
</Toggle>
|
|
359
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
360
|
+
Disabled
|
|
361
|
+
</p>
|
|
362
|
+
</div>
|
|
655
363
|
</div>
|
|
364
|
+
</div>
|
|
656
365
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
366
|
+
{/* Icon states */}
|
|
367
|
+
<div className="space-y-4">
|
|
368
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
369
|
+
Icon-only states
|
|
370
|
+
</h4>
|
|
371
|
+
<div className="flex flex-wrap gap-4">
|
|
372
|
+
<div className="space-y-2 text-center">
|
|
373
|
+
<Toggle aria-label="Alert unpressed">
|
|
664
374
|
<AlertIcon />
|
|
665
|
-
Feature A
|
|
666
375
|
</Toggle>
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
376
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
377
|
+
Unpressed
|
|
378
|
+
</p>
|
|
379
|
+
</div>
|
|
380
|
+
<div className="space-y-2 text-center">
|
|
381
|
+
<Toggle defaultPressed aria-label="Alert pressed">
|
|
382
|
+
<AlertIcon />
|
|
671
383
|
</Toggle>
|
|
672
|
-
|
|
384
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
385
|
+
Pressed
|
|
386
|
+
</p>
|
|
387
|
+
</div>
|
|
388
|
+
<div className="space-y-2 text-center">
|
|
389
|
+
<Toggle disabled aria-label="Alert disabled">
|
|
390
|
+
<AlertIcon />
|
|
391
|
+
</Toggle>
|
|
392
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
393
|
+
Disabled
|
|
394
|
+
</p>
|
|
395
|
+
</div>
|
|
396
|
+
<div className="space-y-2 text-center">
|
|
673
397
|
<Toggle
|
|
674
398
|
variant="outline"
|
|
675
|
-
|
|
399
|
+
defaultPressed
|
|
400
|
+
aria-label="Trash pressed outline"
|
|
676
401
|
>
|
|
677
|
-
<
|
|
678
|
-
Visibility
|
|
679
|
-
</Toggle>
|
|
680
|
-
|
|
681
|
-
<Toggle size="sm" aria-label="Toggle search mode">
|
|
682
|
-
<SearchIcon />
|
|
402
|
+
<TrashIcon />
|
|
683
403
|
</Toggle>
|
|
404
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
405
|
+
Pressed outline
|
|
406
|
+
</p>
|
|
684
407
|
</div>
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
<
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
<Toggle aria-label="Toggle notifications - receive alerts when new messages arrive">
|
|
697
|
-
<AlertIcon />
|
|
698
|
-
Notifications
|
|
699
|
-
</Toggle>
|
|
700
|
-
<Toggle aria-label="Toggle edit mode - switch between viewing and editing">
|
|
701
|
-
<EditBigIcon />
|
|
702
|
-
Edit Mode
|
|
703
|
-
</Toggle>
|
|
704
|
-
</div>
|
|
705
|
-
</div>
|
|
706
|
-
|
|
707
|
-
<div className="space-y-3">
|
|
708
|
-
<span className="text-fm-secondary text-xs">Code Examples</span>
|
|
709
|
-
<div className="border-fm-divider-secondary bg-fm-surface-secondary text-fm-tertiary rounded border p-3 font-mono text-xs">
|
|
710
|
-
<div>aria-label="Toggle notifications"</div>
|
|
711
|
-
<div>aria-label="Show/hide password"</div>
|
|
712
|
-
<div>aria-label="Enable dark mode"</div>
|
|
713
|
-
</div>
|
|
714
|
-
</div>
|
|
408
|
+
<div className="space-y-2 text-center">
|
|
409
|
+
<Toggle
|
|
410
|
+
variant="outline"
|
|
411
|
+
disabled
|
|
412
|
+
aria-label="Trash disabled outline"
|
|
413
|
+
>
|
|
414
|
+
<TrashIcon />
|
|
415
|
+
</Toggle>
|
|
416
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
417
|
+
Disabled outline
|
|
418
|
+
</p>
|
|
715
419
|
</div>
|
|
716
420
|
</div>
|
|
717
|
-
|
|
718
|
-
<div className="border-fm-divider-warning bg-fm-surface-warning-sec rounded-lg border p-4">
|
|
719
|
-
<h4 className="text-fm-warning mb-2 text-sm font-medium">
|
|
720
|
-
Best Practices
|
|
721
|
-
</h4>
|
|
722
|
-
<ul className="text-fm-warning-sec space-y-1 text-xs">
|
|
723
|
-
<li>• Always provide descriptive aria-label attributes</li>
|
|
724
|
-
<li>• Include current state in label when helpful</li>
|
|
725
|
-
<li>• Use consistent toggle patterns across your app</li>
|
|
726
|
-
<li>• Test with screen readers and keyboard navigation</li>
|
|
727
|
-
<li>• Ensure sufficient color contrast for all states</li>
|
|
728
|
-
<li>• Provide visual feedback for state changes</li>
|
|
729
|
-
</ul>
|
|
730
|
-
</div>
|
|
731
421
|
</div>
|
|
732
422
|
</div>
|
|
733
423
|
),
|
|
@@ -735,369 +425,236 @@ export const AccessibilityDemo: Story = {
|
|
|
735
425
|
docs: {
|
|
736
426
|
description: {
|
|
737
427
|
story:
|
|
738
|
-
"
|
|
428
|
+
"Pressed, unpressed, and disabled states rendered for each variant. Disabled toggles suppress pointer events and render at reduced opacity.",
|
|
739
429
|
},
|
|
740
430
|
},
|
|
741
431
|
},
|
|
742
432
|
}
|
|
743
433
|
|
|
744
|
-
//
|
|
745
|
-
export const UseCases: Story = {
|
|
746
|
-
render: () => {
|
|
747
|
-
const [preferences, setPreferences] = React.useState({
|
|
748
|
-
notifications: true,
|
|
749
|
-
autoSave: false,
|
|
750
|
-
showPreview: true,
|
|
751
|
-
darkMode: true,
|
|
752
|
-
})
|
|
434
|
+
// ─── 4. Interactive ───────────────────────────────────────────────────────────
|
|
753
435
|
|
|
754
|
-
|
|
436
|
+
export const Interactive: Story = {
|
|
437
|
+
render: () => {
|
|
438
|
+
const [formatting, setFormatting] = useState({
|
|
755
439
|
bold: false,
|
|
756
440
|
italic: false,
|
|
757
|
-
|
|
441
|
+
underline: false,
|
|
758
442
|
code: false,
|
|
759
443
|
})
|
|
760
444
|
|
|
761
|
-
const
|
|
762
|
-
|
|
763
|
-
|
|
445
|
+
const [playback, setPlayback] = useState({
|
|
446
|
+
shuffle: false,
|
|
447
|
+
repeat: false,
|
|
448
|
+
mute: false,
|
|
449
|
+
})
|
|
450
|
+
|
|
451
|
+
const [visibility, setVisibility] = useState(false)
|
|
452
|
+
const [done, setDone] = useState(false)
|
|
453
|
+
|
|
454
|
+
const toggleFormat = (key: keyof typeof formatting) =>
|
|
455
|
+
setFormatting((prev) => ({ ...prev, [key]: !prev[key] }))
|
|
764
456
|
|
|
765
|
-
const
|
|
766
|
-
|
|
767
|
-
|
|
457
|
+
const togglePlayback = (key: keyof typeof playback) =>
|
|
458
|
+
setPlayback((prev) => ({ ...prev, [key]: !prev[key] }))
|
|
459
|
+
|
|
460
|
+
const activeFormats = Object.entries(formatting)
|
|
461
|
+
.filter(([, v]) => v)
|
|
462
|
+
.map(([k]) => k)
|
|
768
463
|
|
|
769
464
|
return (
|
|
770
|
-
<div className="
|
|
771
|
-
<
|
|
772
|
-
|
|
773
|
-
|
|
465
|
+
<div className="w-full p-8">
|
|
466
|
+
<div className="mx-auto max-w-3xl space-y-6">
|
|
467
|
+
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
|
468
|
+
{/* Controls panel */}
|
|
469
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-5 rounded-xl border p-5">
|
|
470
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold tracking-widest uppercase">
|
|
471
|
+
Current State
|
|
472
|
+
</p>
|
|
473
|
+
|
|
474
|
+
<div className="space-y-2">
|
|
475
|
+
<p className="text-fm-secondary font-fm-text text-fm-xs leading-fm-xs tracking-wider uppercase">
|
|
476
|
+
Active formats
|
|
477
|
+
</p>
|
|
478
|
+
<p className="text-fm-primary font-fm-brand text-fm-md leading-fm-md font-semibold">
|
|
479
|
+
{activeFormats.length === 0
|
|
480
|
+
? "None"
|
|
481
|
+
: activeFormats.join(", ")}
|
|
482
|
+
</p>
|
|
483
|
+
</div>
|
|
484
|
+
|
|
485
|
+
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
486
|
+
|
|
487
|
+
<div className="space-y-2">
|
|
488
|
+
<p className="text-fm-secondary font-fm-text text-fm-xs leading-fm-xs tracking-wider uppercase">
|
|
489
|
+
Playback
|
|
490
|
+
</p>
|
|
491
|
+
<div className="flex flex-col gap-1">
|
|
492
|
+
<p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
493
|
+
Shuffle:{" "}
|
|
494
|
+
<span className="font-semibold">
|
|
495
|
+
{playback.shuffle ? "ON" : "OFF"}
|
|
496
|
+
</span>
|
|
497
|
+
</p>
|
|
498
|
+
<p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
499
|
+
Repeat:{" "}
|
|
500
|
+
<span className="font-semibold">
|
|
501
|
+
{playback.repeat ? "ON" : "OFF"}
|
|
502
|
+
</span>
|
|
503
|
+
</p>
|
|
504
|
+
<p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
505
|
+
Mute:{" "}
|
|
506
|
+
<span className="font-semibold">
|
|
507
|
+
{playback.mute ? "ON" : "OFF"}
|
|
508
|
+
</span>
|
|
509
|
+
</p>
|
|
510
|
+
</div>
|
|
511
|
+
</div>
|
|
774
512
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
size="sm"
|
|
785
|
-
pressed={toolbar.bold}
|
|
786
|
-
onPressedChange={() => updateToolbar("bold")}
|
|
787
|
-
aria-label="Toggle bold formatting"
|
|
788
|
-
>
|
|
789
|
-
<span className="text-sm font-bold">B</span>
|
|
790
|
-
</Toggle>
|
|
791
|
-
<Toggle
|
|
792
|
-
size="sm"
|
|
793
|
-
pressed={toolbar.italic}
|
|
794
|
-
onPressedChange={() => updateToolbar("italic")}
|
|
795
|
-
aria-label="Toggle italic formatting"
|
|
796
|
-
>
|
|
797
|
-
<span className="text-sm italic">I</span>
|
|
798
|
-
</Toggle>
|
|
799
|
-
<div className="bg-fm-surface-tertiary mx-2 h-4 w-px"></div>
|
|
800
|
-
<Toggle
|
|
801
|
-
size="sm"
|
|
802
|
-
pressed={toolbar.list}
|
|
803
|
-
onPressedChange={() => updateToolbar("list")}
|
|
804
|
-
aria-label="Toggle bullet list"
|
|
805
|
-
>
|
|
806
|
-
• List
|
|
807
|
-
</Toggle>
|
|
808
|
-
<Toggle
|
|
809
|
-
size="sm"
|
|
810
|
-
pressed={toolbar.code}
|
|
811
|
-
onPressedChange={() => updateToolbar("code")}
|
|
812
|
-
aria-label="Toggle code formatting"
|
|
813
|
-
>
|
|
814
|
-
<span className="font-mono text-sm"></></span>
|
|
815
|
-
</Toggle>
|
|
816
|
-
<div className="bg-fm-surface-tertiary mx-2 h-4 w-px"></div>
|
|
817
|
-
<Toggle size="sm" aria-label="Insert image">
|
|
818
|
-
<FileChartIcon />
|
|
819
|
-
</Toggle>
|
|
820
|
-
<Toggle size="sm" aria-label="Add link">
|
|
821
|
-
<PlusIcon />
|
|
822
|
-
</Toggle>
|
|
513
|
+
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
514
|
+
|
|
515
|
+
<div className="space-y-2">
|
|
516
|
+
<p className="text-fm-secondary font-fm-text text-fm-xs leading-fm-xs tracking-wider uppercase">
|
|
517
|
+
Visibility
|
|
518
|
+
</p>
|
|
519
|
+
<p className="text-fm-primary font-fm-brand text-fm-md leading-fm-md font-semibold">
|
|
520
|
+
{visibility ? "Visible" : "Hidden"}
|
|
521
|
+
</p>
|
|
823
522
|
</div>
|
|
824
523
|
</div>
|
|
825
|
-
</div>
|
|
826
524
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
User Preferences
|
|
831
|
-
</h4>
|
|
832
|
-
<div className="grid grid-cols-1 gap-3 lg:grid-cols-2">
|
|
525
|
+
{/* Preview stage */}
|
|
526
|
+
<div className="flex flex-col gap-6 lg:col-span-2">
|
|
527
|
+
{/* Text formatting toolbar */}
|
|
833
528
|
<div className="space-y-3">
|
|
834
|
-
<
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
<div className="text-fm-primary text-sm">
|
|
839
|
-
Push Notifications
|
|
840
|
-
</div>
|
|
841
|
-
<div className="text-fm-secondary text-xs">
|
|
842
|
-
Get notified of updates
|
|
843
|
-
</div>
|
|
844
|
-
</div>
|
|
845
|
-
</div>
|
|
529
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
530
|
+
Text formatting toolbar
|
|
531
|
+
</h4>
|
|
532
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary inline-flex items-center gap-1 rounded-lg border p-2">
|
|
846
533
|
<Toggle
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
<
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
534
|
+
size="sm"
|
|
535
|
+
pressed={formatting.bold}
|
|
536
|
+
onPressedChange={() => toggleFormat("bold")}
|
|
537
|
+
aria-label="Toggle bold"
|
|
538
|
+
>
|
|
539
|
+
<span className="font-bold">B</span>
|
|
540
|
+
</Toggle>
|
|
541
|
+
<Toggle
|
|
542
|
+
size="sm"
|
|
543
|
+
pressed={formatting.italic}
|
|
544
|
+
onPressedChange={() => toggleFormat("italic")}
|
|
545
|
+
aria-label="Toggle italic"
|
|
546
|
+
>
|
|
547
|
+
<span className="italic">I</span>
|
|
548
|
+
</Toggle>
|
|
549
|
+
<Toggle
|
|
550
|
+
size="sm"
|
|
551
|
+
pressed={formatting.underline}
|
|
552
|
+
onPressedChange={() => toggleFormat("underline")}
|
|
553
|
+
aria-label="Toggle underline"
|
|
554
|
+
>
|
|
555
|
+
<span className="underline">U</span>
|
|
556
|
+
</Toggle>
|
|
557
|
+
<div className="bg-fm-divider-secondary mx-1 h-5 w-px" />
|
|
863
558
|
<Toggle
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
559
|
+
size="sm"
|
|
560
|
+
pressed={formatting.code}
|
|
561
|
+
onPressedChange={() => toggleFormat("code")}
|
|
562
|
+
aria-label="Toggle code"
|
|
563
|
+
>
|
|
564
|
+
<span className="text-fm-xs font-(--font-fm-mono)">{`</>`}</span>
|
|
565
|
+
</Toggle>
|
|
566
|
+
<div className="bg-fm-divider-secondary mx-1 h-5 w-px" />
|
|
567
|
+
<Toggle size="sm" aria-label="Search">
|
|
568
|
+
<SearchIcon />
|
|
569
|
+
</Toggle>
|
|
570
|
+
<Toggle size="sm" aria-label="Edit">
|
|
571
|
+
<EditBigIcon />
|
|
572
|
+
</Toggle>
|
|
868
573
|
</div>
|
|
869
574
|
</div>
|
|
870
575
|
|
|
576
|
+
{/* Playback controls */}
|
|
871
577
|
<div className="space-y-3">
|
|
872
|
-
<
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
<div className="text-fm-primary text-sm">
|
|
877
|
-
Preview Mode
|
|
878
|
-
</div>
|
|
879
|
-
<div className="text-fm-secondary text-xs">
|
|
880
|
-
Show live preview
|
|
881
|
-
</div>
|
|
882
|
-
</div>
|
|
883
|
-
</div>
|
|
578
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
579
|
+
Playback controls
|
|
580
|
+
</h4>
|
|
581
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary flex items-center justify-center gap-2 rounded-xl border p-4">
|
|
884
582
|
<Toggle
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
583
|
+
variant="outline"
|
|
584
|
+
size="sm"
|
|
585
|
+
pressed={playback.shuffle}
|
|
586
|
+
onPressedChange={() => togglePlayback("shuffle")}
|
|
587
|
+
aria-label="Toggle shuffle"
|
|
588
|
+
>
|
|
589
|
+
<FileChartIcon />
|
|
590
|
+
Shuffle
|
|
591
|
+
</Toggle>
|
|
592
|
+
<Toggle size="default" aria-label="Skip backward">
|
|
593
|
+
<SkipBackwardIcon />
|
|
594
|
+
</Toggle>
|
|
595
|
+
<Toggle size="lg" defaultPressed aria-label="Pause">
|
|
596
|
+
<PauseIcon />
|
|
597
|
+
</Toggle>
|
|
598
|
+
<Toggle size="default" aria-label="Skip forward">
|
|
599
|
+
<SkipForwardIcon />
|
|
600
|
+
</Toggle>
|
|
901
601
|
<Toggle
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
602
|
+
variant="outline"
|
|
603
|
+
size="sm"
|
|
604
|
+
pressed={playback.repeat}
|
|
605
|
+
onPressedChange={() => togglePlayback("repeat")}
|
|
606
|
+
aria-label="Toggle repeat"
|
|
607
|
+
>
|
|
608
|
+
<TickCircleIcon />
|
|
609
|
+
Repeat
|
|
610
|
+
</Toggle>
|
|
906
611
|
</div>
|
|
907
612
|
</div>
|
|
908
|
-
</div>
|
|
909
|
-
</div>
|
|
910
|
-
|
|
911
|
-
{/* Filter Toolbar */}
|
|
912
|
-
<div className="space-y-4">
|
|
913
|
-
<h4 className="text-fm-secondary text-sm font-medium">
|
|
914
|
-
Filter Toolbar
|
|
915
|
-
</h4>
|
|
916
|
-
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
917
|
-
<div className="flex flex-wrap gap-2">
|
|
918
|
-
<Toggle
|
|
919
|
-
variant="outline"
|
|
920
|
-
size="sm"
|
|
921
|
-
aria-label="Show completed items"
|
|
922
|
-
>
|
|
923
|
-
<TickCircleIcon />
|
|
924
|
-
Completed
|
|
925
|
-
</Toggle>
|
|
926
|
-
<Toggle
|
|
927
|
-
variant="outline"
|
|
928
|
-
size="sm"
|
|
929
|
-
aria-label="Show pending items"
|
|
930
|
-
>
|
|
931
|
-
<AlertIcon />
|
|
932
|
-
Pending
|
|
933
|
-
</Toggle>
|
|
934
|
-
<Toggle
|
|
935
|
-
variant="outline"
|
|
936
|
-
size="sm"
|
|
937
|
-
aria-label="Show archived items"
|
|
938
|
-
>
|
|
939
|
-
<FileChartIcon />
|
|
940
|
-
Archived
|
|
941
|
-
</Toggle>
|
|
942
|
-
<Toggle
|
|
943
|
-
variant="outline"
|
|
944
|
-
size="sm"
|
|
945
|
-
defaultPressed
|
|
946
|
-
aria-label="Show active items"
|
|
947
|
-
>
|
|
948
|
-
<EyeOpenIcon />
|
|
949
|
-
Active
|
|
950
|
-
</Toggle>
|
|
951
|
-
</div>
|
|
952
|
-
</div>
|
|
953
|
-
</div>
|
|
954
613
|
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
</Toggle>
|
|
970
|
-
</div>
|
|
971
|
-
</div>
|
|
972
|
-
</div>
|
|
973
|
-
</div>
|
|
974
|
-
)
|
|
975
|
-
},
|
|
976
|
-
parameters: {
|
|
977
|
-
docs: {
|
|
978
|
-
description: {
|
|
979
|
-
story:
|
|
980
|
-
"Real-world examples showing toggles in editor toolbars, user preferences, filters, and view options.",
|
|
981
|
-
},
|
|
982
|
-
},
|
|
983
|
-
},
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
// 8. Controlled vs Uncontrolled
|
|
987
|
-
export const ControlledVsUncontrolled: Story = {
|
|
988
|
-
render: () => {
|
|
989
|
-
const [controlledState, setControlledState] = React.useState(false)
|
|
990
|
-
const [multipleStates, setMultipleStates] = React.useState({
|
|
991
|
-
option1: true,
|
|
992
|
-
option2: false,
|
|
993
|
-
option3: true,
|
|
994
|
-
})
|
|
995
|
-
|
|
996
|
-
return (
|
|
997
|
-
<div className="space-y-8 p-8">
|
|
998
|
-
<h3 className="text-fm-primary text-center text-lg font-medium">
|
|
999
|
-
Controlled vs Uncontrolled
|
|
1000
|
-
</h3>
|
|
1001
|
-
|
|
1002
|
-
<div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
|
|
1003
|
-
{/* Uncontrolled */}
|
|
1004
|
-
<div className="space-y-4">
|
|
1005
|
-
<h4 className="text-fm-secondary text-sm font-medium">
|
|
1006
|
-
Uncontrolled (Internal State)
|
|
1007
|
-
</h4>
|
|
1008
|
-
<div className="space-y-3">
|
|
1009
|
-
<Toggle aria-label="Uncontrolled toggle 1">Default State</Toggle>
|
|
1010
|
-
<Toggle defaultPressed aria-label="Uncontrolled toggle 2">
|
|
1011
|
-
Default Pressed
|
|
1012
|
-
</Toggle>
|
|
1013
|
-
<Toggle variant="outline" aria-label="Uncontrolled toggle 3">
|
|
1014
|
-
<AlertIcon />
|
|
1015
|
-
With Icon
|
|
1016
|
-
</Toggle>
|
|
1017
|
-
</div>
|
|
1018
|
-
<div className="border-fm-divider-secondary bg-fm-surface-secondary text-fm-tertiary rounded border p-3 font-mono text-xs">
|
|
1019
|
-
<div>{"<Toggle>"}</div>
|
|
1020
|
-
<div>{" Default State"}</div>
|
|
1021
|
-
<div>{"</Toggle>"}</div>
|
|
1022
|
-
<br />
|
|
1023
|
-
<div>{"<Toggle defaultPressed>"}</div>
|
|
1024
|
-
<div>{" Default Pressed"}</div>
|
|
1025
|
-
<div>{"</Toggle>"}</div>
|
|
1026
|
-
</div>
|
|
1027
|
-
</div>
|
|
1028
|
-
|
|
1029
|
-
{/* Controlled */}
|
|
1030
|
-
<div className="space-y-4">
|
|
1031
|
-
<h4 className="text-fm-secondary text-sm font-medium">
|
|
1032
|
-
Controlled (External State)
|
|
1033
|
-
</h4>
|
|
1034
|
-
<div className="space-y-3">
|
|
1035
|
-
<Toggle
|
|
1036
|
-
pressed={controlledState}
|
|
1037
|
-
onPressedChange={setControlledState}
|
|
1038
|
-
aria-label="Controlled toggle"
|
|
1039
|
-
>
|
|
1040
|
-
Controlled: {controlledState ? "ON" : "OFF"}
|
|
1041
|
-
</Toggle>
|
|
1042
|
-
|
|
1043
|
-
<div className="space-y-2">
|
|
1044
|
-
{Object.entries(multipleStates).map(([key, value]) => (
|
|
614
|
+
{/* Stateful icon swap */}
|
|
615
|
+
<div className="space-y-3">
|
|
616
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
617
|
+
Stateful icon swap
|
|
618
|
+
</h4>
|
|
619
|
+
<div className="flex flex-wrap gap-3">
|
|
620
|
+
<Toggle
|
|
621
|
+
pressed={visibility}
|
|
622
|
+
onPressedChange={setVisibility}
|
|
623
|
+
aria-label="Toggle visibility"
|
|
624
|
+
>
|
|
625
|
+
{visibility ? <EyeOpenIcon /> : <EyeCloseIcon />}
|
|
626
|
+
{visibility ? "Visible" : "Hidden"}
|
|
627
|
+
</Toggle>
|
|
1045
628
|
<Toggle
|
|
1046
|
-
key={key}
|
|
1047
629
|
variant="outline"
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
setMultipleStates((prev) => ({ ...prev, [key]: pressed }))
|
|
1052
|
-
}
|
|
1053
|
-
aria-label={`Toggle ${key}`}
|
|
630
|
+
pressed={done}
|
|
631
|
+
onPressedChange={setDone}
|
|
632
|
+
aria-label="Toggle complete"
|
|
1054
633
|
>
|
|
1055
634
|
<TickCircleIcon />
|
|
1056
|
-
{
|
|
635
|
+
{done ? "Done" : "Mark done"}
|
|
636
|
+
</Toggle>
|
|
637
|
+
<Toggle
|
|
638
|
+
variant="filled"
|
|
639
|
+
pressed={playback.mute}
|
|
640
|
+
onPressedChange={() => togglePlayback("mute")}
|
|
641
|
+
aria-label="Toggle mute"
|
|
642
|
+
>
|
|
643
|
+
{playback.mute ? <VolumeFullIcon /> : <VolumeFullIcon />}
|
|
644
|
+
{playback.mute ? "Unmute" : "Mute"}
|
|
645
|
+
</Toggle>
|
|
646
|
+
<Toggle disabled aria-label="Sleep — unavailable">
|
|
647
|
+
<MoonIcon />
|
|
648
|
+
Sleep
|
|
1057
649
|
</Toggle>
|
|
1058
|
-
|
|
650
|
+
</div>
|
|
1059
651
|
</div>
|
|
1060
|
-
</div>
|
|
1061
|
-
|
|
1062
|
-
<div className="border-fm-divider-secondary bg-fm-surface-secondary text-fm-tertiary rounded border p-3 font-mono text-xs">
|
|
1063
|
-
<div>{"const [state, setState] = useState(false)"}</div>
|
|
1064
|
-
<br />
|
|
1065
|
-
<div>{"<Toggle"}</div>
|
|
1066
|
-
<div>{" pressed={state}"}</div>
|
|
1067
|
-
<div>{" onPressedChange={setState}"}</div>
|
|
1068
|
-
<div>{">"}</div>
|
|
1069
|
-
<div>{" Controlled"}</div>
|
|
1070
|
-
<div>{"</Toggle>"}</div>
|
|
1071
|
-
</div>
|
|
1072
|
-
</div>
|
|
1073
|
-
</div>
|
|
1074
652
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
<div>
|
|
1081
|
-
<h5 className="text-fm-info mb-1 text-xs font-medium">
|
|
1082
|
-
Uncontrolled
|
|
1083
|
-
</h5>
|
|
1084
|
-
<ul className="text-fm-info-sec space-y-1 text-xs">
|
|
1085
|
-
<li>• Simple on/off toggles</li>
|
|
1086
|
-
<li>• No external state dependency</li>
|
|
1087
|
-
<li>• Form elements</li>
|
|
1088
|
-
<li>• Less code complexity</li>
|
|
1089
|
-
</ul>
|
|
1090
|
-
</div>
|
|
1091
|
-
<div>
|
|
1092
|
-
<h5 className="text-fm-info mb-1 text-xs font-medium">
|
|
1093
|
-
Controlled
|
|
1094
|
-
</h5>
|
|
1095
|
-
<ul className="text-fm-info-sec space-y-1 text-xs">
|
|
1096
|
-
<li>• Complex state management</li>
|
|
1097
|
-
<li>• Multiple dependent toggles</li>
|
|
1098
|
-
<li>• Form validation</li>
|
|
1099
|
-
<li>• External state updates</li>
|
|
1100
|
-
</ul>
|
|
653
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-4 py-3">
|
|
654
|
+
<code className="text-fm-secondary text-fm-md leading-fm-md font-(--font-fm-mono)">
|
|
655
|
+
{`<Toggle pressed={bold} onPressedChange={setBold}>B</Toggle>`}
|
|
656
|
+
</code>
|
|
657
|
+
</div>
|
|
1101
658
|
</div>
|
|
1102
659
|
</div>
|
|
1103
660
|
</div>
|
|
@@ -1108,7 +665,7 @@ export const ControlledVsUncontrolled: Story = {
|
|
|
1108
665
|
docs: {
|
|
1109
666
|
description: {
|
|
1110
667
|
story:
|
|
1111
|
-
"
|
|
668
|
+
"Live stateful toggles showing two real-world patterns: a text-formatting toolbar (multi-active) and playback controls. Click any button to toggle its pressed state.",
|
|
1112
669
|
},
|
|
1113
670
|
},
|
|
1114
671
|
},
|