aural-ui 3.0.7 → 4.1.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.
Files changed (183) hide show
  1. package/dist/components/aspect-ratio/AspectRatio.stories.tsx +290 -1199
  2. package/dist/components/avatar/Avatar.stories.tsx +235 -237
  3. package/dist/components/badge/Badge.stories.tsx +379 -116
  4. package/dist/components/banner/Banner.stories.tsx +445 -391
  5. package/dist/components/breadcrumb/Breadcrumb.stories.tsx +453 -199
  6. package/dist/components/button/Button.stories.tsx +585 -230
  7. package/dist/components/button/index.tsx +7 -7
  8. package/dist/components/card/Card.stories.tsx +619 -301
  9. package/dist/components/char-count/CharCount.stories.tsx +350 -248
  10. package/dist/components/checkbox/Checkbox.stories.tsx +309 -167
  11. package/dist/components/chip/Chip.stories.tsx +362 -168
  12. package/dist/components/circular-loader/CircularLoader.stories.tsx +221 -620
  13. package/dist/components/clamp-lines/ClampLines.stories.tsx +246 -117
  14. package/dist/components/collapsible/Collapsible.stories.tsx +391 -252
  15. package/dist/components/command/Command.stories.tsx +533 -856
  16. package/dist/components/dialog/Dialog.stories.tsx +505 -949
  17. package/dist/components/divider/Divider.stories.tsx +265 -502
  18. package/dist/components/dot-loader/DotLoader.stories.tsx +256 -257
  19. package/dist/components/drawer/Drawer.stories.tsx +659 -993
  20. package/dist/components/drawer/index.tsx +3 -3
  21. package/dist/components/dropdown/Dropdown.stories.tsx +643 -1018
  22. package/dist/components/form/Form.stories.tsx +560 -274
  23. package/dist/components/helper-text/HelperText.stories.tsx +199 -200
  24. package/dist/components/hover-card/HoverCard.stories.tsx +318 -1221
  25. package/dist/components/icon-button/IconButton.stories.tsx +837 -194
  26. package/dist/components/if-else/if-else.stories.tsx +370 -83
  27. package/dist/components/input/Input.stories.tsx +436 -368
  28. package/dist/components/label/Label.stories.tsx +156 -154
  29. package/dist/components/list/List.stories.tsx +485 -822
  30. package/dist/components/marquee/Marquee.stories.tsx +356 -694
  31. package/dist/components/otp-inputs/OtpInputs.stories.tsx +352 -410
  32. package/dist/components/overlay/Overlay.stories.tsx +452 -818
  33. package/dist/components/overlay/index.tsx +4 -4
  34. package/dist/components/pagination/Pagination.stories.tsx +721 -210
  35. package/dist/components/popover/Popover.stories.tsx +484 -873
  36. package/dist/components/radio/Radio.stories.tsx +432 -124
  37. package/dist/components/resizable/Resizable.stories.tsx +496 -752
  38. package/dist/components/scroll-area/ScrollArea.stories.tsx +384 -1006
  39. package/dist/components/search/Search.stories.tsx +314 -575
  40. package/dist/components/select/Select.stories.tsx +684 -787
  41. package/dist/components/sheet/Sheet.stories.tsx +671 -936
  42. package/dist/components/skelton/Skelton.stories.tsx +230 -764
  43. package/dist/components/slider/Slider.stories.tsx +384 -737
  44. package/dist/components/stepper/Stepper.stories.tsx +371 -514
  45. package/dist/components/switch/Switch.stories.tsx +461 -208
  46. package/dist/components/switch-case/SwitchCase.stories.tsx +367 -188
  47. package/dist/components/table/Table.stories.tsx +770 -914
  48. package/dist/components/tabs/Tabs.stories.tsx +459 -1400
  49. package/dist/components/tag/Tag.stories.tsx +714 -542
  50. package/dist/components/textarea/TextArea.stories.tsx +621 -562
  51. package/dist/components/thumbnail-tags/ThumbnailTags.stories.tsx +228 -148
  52. package/dist/components/toast/Toast.stories.tsx +452 -1333
  53. package/dist/components/toggle/Toggle.stories.tsx +488 -909
  54. package/dist/components/tooltip/Tooltip.stories.tsx +344 -1372
  55. package/dist/components/typography/Typography.stories.tsx +406 -89
  56. package/dist/hooks/use-change-state/UseChangeState.stories.tsx +309 -606
  57. package/dist/hooks/use-previous/UsePrevious.stories.tsx +367 -917
  58. package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +639 -867
  59. package/dist/icons/Icons.stories.tsx +0 -12
  60. package/dist/icons/ai-avatar-icon/AiAvatarIcon.stories.tsx +226 -1013
  61. package/dist/icons/alert-icon/AlertIcon.stories.tsx +109 -929
  62. package/dist/icons/all-icons.tsx +124 -87
  63. package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +140 -971
  64. package/dist/icons/apple-logo-icon/AppleLogoIcon.stories.tsx +148 -888
  65. package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +135 -1019
  66. package/dist/icons/arrow-corner-up-left-icon/ArrowCornerUpLeftIcon.stories.tsx +137 -953
  67. package/dist/icons/arrow-corner-up-right-icon/ArrowCornerUpRightIcon.stories.tsx +138 -997
  68. package/dist/icons/arrow-left-icon/ArrowLeftIcon.stories.tsx +136 -942
  69. package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +148 -1092
  70. package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +146 -1211
  71. package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +126 -615
  72. package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +144 -1164
  73. package/dist/icons/backward-ten-seconds-icon/BackwardTenSecondsIcon.stories.tsx +167 -985
  74. package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +122 -1179
  75. package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +124 -1168
  76. package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +119 -850
  77. package/dist/icons/camera-icon/CameraIcon.stories.tsx +112 -1213
  78. package/dist/icons/capital-a-letter-icon/CapitalALetterIcon.stories.tsx +117 -934
  79. package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +160 -961
  80. package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +163 -961
  81. package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +144 -942
  82. package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +129 -966
  83. package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +147 -964
  84. package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +145 -975
  85. package/dist/icons/circle-tick-icon/CircleTickIcon.stories.tsx +150 -1142
  86. package/dist/icons/circular-play-icon/CircularPlayIcon.stories.tsx +114 -461
  87. package/dist/icons/coin-icon/CoinIcon.stories.tsx +124 -1322
  88. package/dist/icons/coin-toons-icon/CoinToonsIcon.stories.tsx +117 -1318
  89. package/dist/icons/column-wide-add-icon/ColumnWideAddIcon.stories.tsx +114 -903
  90. package/dist/icons/command-icon/CommandIcon.stories.tsx +127 -1042
  91. package/dist/icons/copy-icon/CopyIcon.stories.tsx +123 -962
  92. package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +147 -999
  93. package/dist/icons/cross-icon/CrossIcon.stories.tsx +139 -960
  94. package/dist/icons/download-icon/DownloadIcon.stories.tsx +126 -820
  95. package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +124 -1031
  96. package/dist/icons/email-icon/EmailIcon.stories.tsx +115 -936
  97. package/dist/icons/expand-icon/ExpandIcon.stories.tsx +112 -1111
  98. package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +144 -1025
  99. package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +143 -1036
  100. package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +127 -1011
  101. package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +126 -1056
  102. package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +125 -614
  103. package/dist/icons/filter-bar-row-icon/FilterBarRowIcon.stories.tsx +119 -1050
  104. package/dist/icons/forward-ten-seconds-icon/ForwardTenSecondsIcon.stories.tsx +169 -989
  105. package/dist/icons/git-branch-icon/GitBranchIcon.stories.tsx +115 -1145
  106. package/dist/icons/git-fork-icon/GitForkIcon.stories.tsx +115 -1122
  107. package/dist/icons/globe-icon/GlobeIcon.stories.tsx +130 -313
  108. package/dist/icons/google-logo-icon/GoogleLogoIcon.stories.tsx +145 -940
  109. package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +119 -1174
  110. package/dist/icons/head-icon/HeadIcon.stories.tsx +111 -916
  111. package/dist/icons/heart-icon/HeartIcon.stories.tsx +120 -1019
  112. package/dist/icons/image-avatar-sparkle-icon/ImageAvatarSparkleIcon.stories.tsx +119 -683
  113. package/dist/icons/image-icon/ImageIcon.stories.tsx +105 -1121
  114. package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +111 -1192
  115. package/dist/icons/import-left-arrow-folder-icon/ImportLeftArrowFolderIcon.stories.tsx +136 -1256
  116. package/dist/icons/indian-flag-icon/IndianFlagIcon.stories.tsx +159 -962
  117. package/dist/icons/instagram-icon/InstagramIcon.stories.tsx +161 -1385
  118. package/dist/icons/layout-column-icon/LayoutColumnIcon.stories.tsx +124 -972
  119. package/dist/icons/layout-left-icon/LayoutLeftIcon.stories.tsx +119 -948
  120. package/dist/icons/layout-right-icon/LayoutRightIcon.stories.tsx +119 -942
  121. package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +108 -1215
  122. package/dist/icons/linked-in-icon/LinkedInIcon.stories.tsx +154 -1517
  123. package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +110 -1188
  124. package/dist/icons/magic-edit-icon/MagicEditIcon.stories.tsx +119 -678
  125. package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +123 -1184
  126. package/dist/icons/message-icon/MessageIcon.stories.tsx +114 -538
  127. package/dist/icons/minimize-icon/MinimizeIcon.stories.tsx +116 -1158
  128. package/dist/icons/moon-icon/MoonIcon.stories.tsx +120 -536
  129. package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +109 -1184
  130. package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +115 -1134
  131. package/dist/icons/musical-note-icon/MusicalNoteIcon.stories.tsx +119 -971
  132. package/dist/icons/notepad-icon/NotepadIcon.stories.tsx +111 -1100
  133. package/dist/icons/notes-icon/NotesIcon.stories.tsx +119 -1101
  134. package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +109 -1111
  135. package/dist/icons/page-text-icon/PageTextIcon.stories.tsx +122 -684
  136. package/dist/icons/paint-roll-icon/PaintRollIcon.stories.tsx +113 -954
  137. package/dist/icons/paper-plane-icon/PaperPlaneIcon.stories.tsx +112 -877
  138. package/dist/icons/pause-icon/PauseIcon.stories.tsx +113 -1000
  139. package/dist/icons/pencil-icon/PencilIcon.stories.tsx +115 -1070
  140. package/dist/icons/phone-icon/PhoneIcon.stories.tsx +115 -978
  141. package/dist/icons/plus-icon/PlusIcon.stories.tsx +106 -1093
  142. package/dist/icons/pocket-studio-icon/PocketStudioIcon.stories.tsx +107 -829
  143. package/dist/icons/scroll-down-icon/ScrollDownIcon.stories.tsx +102 -469
  144. package/dist/icons/search-icon/SearchIcon.stories.tsx +111 -1124
  145. package/dist/icons/setting-icon/SettingIcon.stories.tsx +107 -970
  146. package/dist/icons/share-icon/ShareIcon.stories.tsx +120 -1025
  147. package/dist/icons/shield-icon/ShieldIcon.stories.tsx +117 -931
  148. package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +137 -1104
  149. package/dist/icons/skip-backward-icon/SkipBackwardIcon.stories.tsx +172 -982
  150. package/dist/icons/skip-forward-icon/SkipForwardIcon.stories.tsx +164 -983
  151. package/dist/icons/sparkles-soft-icon/SparklesSoftIcon.stories.tsx +105 -958
  152. package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +158 -580
  153. package/dist/icons/spinner-gradient-icon/index.tsx +6 -1
  154. package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +158 -587
  155. package/dist/icons/spinner-solid-icon/index.tsx +6 -1
  156. package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +146 -682
  157. package/dist/icons/spinner-solid-neutral-icon/index.tsx +1 -1
  158. package/dist/icons/star-icon/StarIcon.stories.tsx +124 -904
  159. package/dist/icons/store-coin-icon/StoreCoinIcon.stories.tsx +112 -964
  160. package/dist/icons/suggestion-icon/SuggestionIcon.stories.tsx +116 -852
  161. package/dist/icons/sun-icon/SunIcon.stories.tsx +120 -831
  162. package/dist/icons/text-color-icon/TextColorIcon.stories.tsx +116 -950
  163. package/dist/icons/text-indicator-icon/TextIndicatorIcon.stories.tsx +123 -980
  164. package/dist/icons/threads-icon/ThreadsIcon.stories.tsx +156 -1427
  165. package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +146 -1142
  166. package/dist/icons/tick-icon/TickIcon.stories.tsx +145 -1276
  167. package/dist/icons/trash-icon/TrashIcon.stories.tsx +108 -933
  168. package/dist/icons/twitter-x-icon/TwitterXIcon.stories.tsx +157 -1402
  169. package/dist/icons/upload-icon/UploadIcon.stories.tsx +115 -889
  170. package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +118 -984
  171. package/dist/icons/video-play-list-icon/VideoPlaylistIcon.stories.tsx +125 -1049
  172. package/dist/icons/voice-playing-icon/VoicePlayingIcon.stories.tsx +123 -1356
  173. package/dist/icons/volume-full-icon/VolumeFullIcon.stories.tsx +110 -1171
  174. package/dist/icons/volume-half-icon/VolumeHalfIcon.stories.tsx +112 -1093
  175. package/dist/icons/volume-off-icon/VolumeOffIcon.stories.tsx +115 -1087
  176. package/dist/icons/warning-icon/WarningIcon.stories.tsx +122 -1046
  177. package/dist/icons/youtube-icon/YoutubeIcon.stories.tsx +161 -936
  178. package/dist/index.cjs +84 -84
  179. package/dist/index.js +84 -84
  180. package/dist/styles/aural-all-theme.css +1222 -0
  181. package/dist/styles/{aural-theme.css → aural-dark-theme.css} +15 -3
  182. package/dist/styles/aural-light-theme.css +1047 -0
  183. package/package.json +1 -1
@@ -1,8 +1,9 @@
1
- import React from "react"
1
+ import React, { useState } from "react"
2
2
  import { AngleDownIcon } from "@icons/angle-down-icon"
3
3
  import type { Meta, StoryObj } from "@storybook/react-vite"
4
4
 
5
- import { IconButton } from "../icon-button"
5
+ import { AuralComponentDocsPage } from "src/ui/story-spec/components/component-story-docs-page"
6
+
6
7
  import {
7
8
  Collapsible,
8
9
  CollapsibleContent,
@@ -16,18 +17,29 @@ const meta: Meta<typeof Collapsible> = {
16
17
  component: Collapsible,
17
18
  parameters: {
18
19
  layout: "centered",
19
- backgrounds: {
20
- default: "dark",
21
- values: [
22
- { name: "dark", value: "#0a0a0a" },
23
- { name: "light", value: "#ffffff" },
24
- ],
25
- },
26
20
  docs: {
27
21
  description: {
28
22
  component:
29
- "A collapsible component built on Radix UI that can expand and collapse content.",
23
+ "A compound collapsible component built on Radix UI. Composed of CollapsibleHeader, CollapsibleTrigger, CollapsibleTitle, and CollapsibleContent for building expandable sections with defaultOpen and disabled states.",
30
24
  },
25
+ page: () => (
26
+ <AuralComponentDocsPage
27
+ features={[
28
+ {
29
+ title: "Compound Structure",
30
+ description: "Header, trigger, content",
31
+ },
32
+ {
33
+ title: "Stateful by Design",
34
+ description: "Open, closed, disabled",
35
+ },
36
+ {
37
+ title: "Expandable Content",
38
+ description: "Smooth reveal pattern",
39
+ },
40
+ ]}
41
+ />
42
+ ),
31
43
  },
32
44
  },
33
45
  tags: ["autodocs"],
@@ -46,281 +58,408 @@ const meta: Meta<typeof Collapsible> = {
46
58
  export default meta
47
59
  type Story = StoryObj<typeof Collapsible>
48
60
 
49
- export const Default: Story = {
50
- render: (args) => (
51
- <div className="w-[800px]">
52
- <Collapsible {...args}>
53
- <CollapsibleHeader title="Frequently Asked Questions" />
54
- <CollapsibleContent>
55
- <div className="pt-4">
56
- <p>
57
- This is the collapsible content area. You can put any content here
58
- including text, images, forms, or other components. The content
59
- will smoothly animate when the collapsible is opened or closed.
60
- </p>
61
- </div>
62
- </CollapsibleContent>
63
- </Collapsible>
61
+ function InfoBox({ children }: { children: React.ReactNode }) {
62
+ return (
63
+ <div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
64
+ <p className="text-fm-secondary font-fm-text text-fm-md leading-fm-xl">
65
+ {children}
66
+ </p>
64
67
  </div>
65
- ),
66
- args: {
67
- defaultOpen: false,
68
- },
68
+ )
69
69
  }
70
70
 
71
- export const DefaultOpen: Story = {
72
- render: () => (
73
- <div className="w-[800px]">
74
- <Collapsible defaultOpen>
75
- <CollapsibleHeader title="Settings Panel" />
76
- <CollapsibleContent>
77
- <div className="space-y-3 pt-4">
78
- <div className="flex items-center justify-between">
79
- <span>Enable notifications</span>
80
- <input type="checkbox" defaultChecked />
81
- </div>
82
- <div className="flex items-center justify-between">
83
- <span>Dark mode</span>
84
- <input type="checkbox" />
85
- </div>
86
- <div className="flex items-center justify-between">
87
- <span>Auto-save</span>
88
- <input type="checkbox" defaultChecked />
89
- </div>
90
- </div>
91
- </CollapsibleContent>
92
- </Collapsible>
71
+ function PartCard({
72
+ title,
73
+ example,
74
+ description,
75
+ }: {
76
+ title: string
77
+ example: React.ReactNode
78
+ description: React.ReactNode
79
+ }) {
80
+ return (
81
+ <div className="space-y-3">
82
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
83
+ {title}
84
+ </h4>
85
+ <div className="border-fm-divider-secondary bg-fm-surface-primary rounded-xl border p-4">
86
+ {example}
87
+ </div>
88
+ <InfoBox>{description}</InfoBox>
93
89
  </div>
94
- ),
90
+ )
95
91
  }
96
92
 
97
- export const Disabled: Story = {
98
- render: () => (
99
- <div className="w-[800px]">
100
- <Collapsible disabled>
101
- <CollapsibleHeader title="Disabled Section" />
102
- <CollapsibleContent>
103
- <div className="pt-4">
104
- <p>
105
- This content cannot be accessed because the collapsible is
106
- disabled.
107
- </p>
108
- </div>
109
- </CollapsibleContent>
110
- </Collapsible>
93
+ function TrackMeta() {
94
+ return (
95
+ <div className="space-y-1 pt-4">
96
+ <p className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
97
+ Midnight Rain
98
+ </p>
99
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
100
+ Taylor Swift · Midnights · 2:53
101
+ </p>
111
102
  </div>
112
- ),
103
+ )
113
104
  }
114
105
 
115
- export const CustomTrigger: Story = {
116
- render: () => (
117
- <div className="w-[800px]">
118
- <Collapsible>
119
- <div className="flex items-center justify-between gap-2">
120
- <CollapsibleTitle>Advanced Settings</CollapsibleTitle>
121
- <CollapsibleTrigger asChild>
122
- <IconButton
123
- variant="ghost"
124
- size="small"
125
- icon={
126
- <AngleDownIcon className="toggle-icon" height={32} width={32} />
127
- }
128
- label="Toggle Settings"
129
- className="text-fm-icon-active disabled:text-fm-icon-inactive flex [&>.toggle-icon]:transition-transform [&>.toggle-icon]:duration-50 data-[state=open]:[&>.toggle-icon]:-rotate-180"
130
- />
131
- </CollapsibleTrigger>
132
- </div>
133
- <CollapsibleContent>
134
- <div className="pt-4">
135
- <p>
136
- Custom trigger button with settings icon that rotates 45 degrees
137
- when opened.
138
- </p>
139
- </div>
140
- </CollapsibleContent>
141
- </Collapsible>
142
- </div>
143
- ),
144
- }
106
+ // ─── Parts ───────────────────────────────────────────────────────────────────
145
107
 
146
- export const MultipleCollapsibles: Story = {
108
+ export const Parts: Story = {
109
+ parameters: {
110
+ docs: {
111
+ description: {
112
+ story:
113
+ "The compound parts demonstrated in valid compositions so each piece is visible and interactive in context.",
114
+ },
115
+ },
116
+ },
147
117
  render: () => (
148
- <div className="w-[800px] space-y-4">
149
- <Collapsible>
150
- <CollapsibleHeader title="Section 1: Getting Started" />
151
- <CollapsibleContent>
152
- <div className="pt-4">
153
- <p>
154
- Learn the basics of using our platform. This section covers
155
- initial setup, account creation, and basic navigation.
118
+ <div className="space-y-10">
119
+ <PartCard
120
+ title="CollapsibleTitle"
121
+ example={
122
+ <div className="space-y-3">
123
+ <CollapsibleTitle>Track Information</CollapsibleTitle>
124
+ <p className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm">
125
+ Standalone title styling for section headings.
156
126
  </p>
157
127
  </div>
158
- </CollapsibleContent>
159
- </Collapsible>
128
+ }
129
+ description={
130
+ <>
131
+ Renders the heading text for a collapsible section. By default it
132
+ maps to <code>&lt;h2&gt;</code> and provides the large title
133
+ treatment used in the header row.
134
+ </>
135
+ }
136
+ />
160
137
 
161
- <Collapsible>
162
- <CollapsibleHeader title="Section 2: Advanced Features" />
163
- <CollapsibleContent>
164
- <div className="pt-4">
165
- <p>
166
- Explore advanced functionality including custom integrations, API
167
- usage, and automation tools.
168
- </p>
169
- </div>
170
- </CollapsibleContent>
171
- </Collapsible>
138
+ <PartCard
139
+ title="CollapsibleTrigger"
140
+ example={
141
+ <Collapsible className="border-0 pb-0" defaultOpen>
142
+ <div className="space-y-3">
143
+ <div className="flex items-center gap-3">
144
+ <CollapsibleTrigger asChild>
145
+ <button className="text-fm-primary border-fm-divider-secondary bg-fm-surface-secondary flex items-center gap-2 rounded-lg border px-3 py-2 [&>.toggle-icon]:transition-transform [&>.toggle-icon]:duration-150 data-[state=open]:[&>.toggle-icon]:-rotate-180">
146
+ <span className="font-fm-text text-fm-sm leading-fm-sm">
147
+ Toggle Details
148
+ </span>
149
+ <AngleDownIcon
150
+ className="toggle-icon text-fm-icon-active"
151
+ height={20}
152
+ width={20}
153
+ />
154
+ </button>
155
+ </CollapsibleTrigger>
156
+ <p className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm">
157
+ Custom trigger using <code>asChild</code>
158
+ </p>
159
+ </div>
160
+ <CollapsibleContent>
161
+ <div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-3">
162
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
163
+ Clicking the trigger collapses and reveals this panel.
164
+ </p>
165
+ </div>
166
+ </CollapsibleContent>
167
+ </div>
168
+ </Collapsible>
169
+ }
170
+ description={
171
+ <>
172
+ The trigger controls the open state. Here it is rendered with{" "}
173
+ <code>asChild</code> so the toggle state is visible on a custom
174
+ button while still using the same collapsible trigger primitive.
175
+ </>
176
+ }
177
+ />
172
178
 
173
- <Collapsible>
174
- <CollapsibleHeader title="Section 3: Troubleshooting" />
175
- <CollapsibleContent>
176
- <div className="pt-4">
177
- <p>
178
- Common issues and their solutions. Find answers to frequently
179
- encountered problems.
180
- </p>
181
- </div>
182
- </CollapsibleContent>
183
- </Collapsible>
184
- </div>
185
- ),
186
- }
179
+ <PartCard
180
+ title="CollapsibleHeader"
181
+ example={
182
+ <Collapsible className="border-0 pb-0">
183
+ <CollapsibleHeader title="EQ Settings" />
184
+ <CollapsibleContent>
185
+ <div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-3">
186
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
187
+ The full header row acts as the trigger.
188
+ </p>
189
+ </div>
190
+ </CollapsibleContent>
191
+ </Collapsible>
192
+ }
193
+ description={
194
+ <>
195
+ A convenience wrapper that combines <code>CollapsibleTitle</code>{" "}
196
+ and <code>CollapsibleTrigger</code> into one clickable header row.
197
+ </>
198
+ }
199
+ />
187
200
 
188
- export const RichContent: Story = {
189
- render: () => (
190
- <div className="w-[800px]">
191
- <Collapsible>
192
- <CollapsibleHeader title="Product Features" />
193
- <CollapsibleContent>
194
- <div className="space-y-4 pt-4">
195
- <div>
196
- <h4 className="mb-2 font-semibold">Key Benefits:</h4>
197
- <ul className="list-inside list-disc space-y-1">
198
- <li>Easy to use interface</li>
199
- <li>Powerful automation tools</li>
200
- <li>24/7 customer support</li>
201
- <li>Enterprise-grade security</li>
202
- </ul>
203
- </div>
204
- <div>
205
- <h4 className="mb-2 font-semibold">Pricing:</h4>
206
- <div className="rounded bg-gray-50 p-3">
207
- <p className="text-sm">Starting at $29/month for basic plan</p>
201
+ <PartCard
202
+ title="CollapsibleContent"
203
+ example={
204
+ <Collapsible defaultOpen className="border-0 pb-0">
205
+ <CollapsibleHeader title="Current EQ Preset" />
206
+ <CollapsibleContent>
207
+ <div className="space-y-2 pt-4">
208
+ <p className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
209
+ Warm Vocal Boost
210
+ </p>
211
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
212
+ Bass 80 Hz · +3 dB
213
+ </p>
214
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
215
+ Mid 1 kHz · 0 dB
216
+ </p>
217
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
218
+ Treble 10 kHz · −2 dB
219
+ </p>
208
220
  </div>
209
- </div>
210
- </div>
211
- </CollapsibleContent>
212
- </Collapsible>
221
+ </CollapsibleContent>
222
+ </Collapsible>
223
+ }
224
+ description={
225
+ <>
226
+ The content region is the expandable body. It stays mounted within
227
+ the collapsible and becomes visible when the section is opened.
228
+ </>
229
+ }
230
+ />
213
231
  </div>
214
232
  ),
215
233
  }
216
234
 
217
- export const WithCustomStyling: Story = {
218
- render: () => (
219
- <div className="w-[800px]">
220
- <Collapsible className="rounded-lg border-2 border-blue-200 bg-blue-50 p-4">
221
- <div className="flex items-center justify-between gap-2">
222
- <CollapsibleTitle className="font-bold text-blue-800">
223
- Important Notice
224
- </CollapsibleTitle>
225
- <CollapsibleTrigger asChild>
226
- <IconButton
227
- variant="ghost"
228
- size="small"
229
- className="text-blue-600 hover:bg-blue-100"
230
- icon={
231
- <AngleDownIcon className="transition-transform duration-200 data-[state=open]:rotate-180" />
232
- }
233
- label="Toggle Notice"
234
- />
235
- </CollapsibleTrigger>
236
- </div>
237
- <CollapsibleContent className="text-blue-700">
238
- <div className="pt-4">
239
- <p>
240
- This is an important system notification with custom styling. The
241
- entire collapsible has a blue theme to draw attention to critical
242
- information.
243
- </p>
244
- </div>
245
- </CollapsibleContent>
246
- </Collapsible>
247
- </div>
248
- ),
249
- }
235
+ // ─── States ──────────────────────────────────────────────────────────────────
250
236
 
251
- export const LongContent: Story = {
237
+ export const States: Story = {
238
+ parameters: {
239
+ docs: {
240
+ description: {
241
+ story:
242
+ "Open, closed, and disabled states side by side, using realistic content so each state reads clearly.",
243
+ },
244
+ },
245
+ },
252
246
  render: () => (
253
- <div className="w-[800px]">
254
- <Collapsible>
255
- <CollapsibleHeader title="Terms and Conditions" />
256
- <CollapsibleContent>
257
- <div className="max-h-60 overflow-y-auto pt-4">
258
- <div className="space-y-4 text-sm">
259
- <p>
260
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
261
- eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
262
- enim ad minim veniam, quis nostrud exercitation ullamco laboris.
263
- </p>
264
- <p>
265
- Duis aute irure dolor in reprehenderit in voluptate velit esse
266
- cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
267
- cupidatat non proident, sunt in culpa qui officia deserunt
268
- mollit anim id est laborum.
269
- </p>
270
- <p>
271
- Sed ut perspiciatis unde omnis iste natus error sit voluptatem
272
- accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
273
- quae ab illo inventore veritatis et quasi architecto beatae
274
- vitae dicta sunt explicabo.
275
- </p>
276
- <p>
277
- Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit
278
- aut fugit, sed quia consequuntur magni dolores eos qui ratione
279
- voluptatem sequi nesciunt.
247
+ <div className="space-y-8">
248
+ <div className="space-y-3">
249
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
250
+ Open
251
+ </h4>
252
+ <Collapsible defaultOpen>
253
+ <CollapsibleHeader title="Now Playing" />
254
+ <CollapsibleContent>
255
+ <TrackMeta />
256
+ </CollapsibleContent>
257
+ </Collapsible>
258
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm text-center">
259
+ Default Open
260
+ </p>
261
+ </div>
262
+
263
+ <div className="space-y-3">
264
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
265
+ Closed
266
+ </h4>
267
+ <Collapsible>
268
+ <CollapsibleHeader title="Playlist Details" />
269
+ <CollapsibleContent>
270
+ <div className="pt-4">
271
+ <p className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
272
+ Hidden until expanded
280
273
  </p>
281
- <p>
282
- At vero eos et accusamus et iusto odio dignissimos ducimus qui
283
- blanditiis praesentium voluptatum deleniti atque corrupti quos
284
- dolores et quas molestias excepturi sint occaecati cupiditate
285
- non provident.
274
+ </div>
275
+ </CollapsibleContent>
276
+ </Collapsible>
277
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm text-center">
278
+ Default closed
279
+ </p>
280
+ </div>
281
+
282
+ <div className="space-y-3">
283
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
284
+ Disabled
285
+ </h4>
286
+ <Collapsible disabled>
287
+ <CollapsibleHeader title="Locked Section" />
288
+ <CollapsibleContent>
289
+ <div className="pt-4">
290
+ <p className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
291
+ This content cannot be expanded while disabled.
286
292
  </p>
287
293
  </div>
288
- </div>
289
- </CollapsibleContent>
290
- </Collapsible>
294
+ </CollapsibleContent>
295
+ </Collapsible>
296
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm text-center">
297
+ Disabled trigger and title
298
+ </p>
299
+ </div>
291
300
  </div>
292
301
  ),
293
302
  }
294
303
 
295
- export const NestedCollapsibles: Story = {
296
- render: () => (
297
- <div className="w-[800px]">
298
- <Collapsible>
299
- <CollapsibleHeader title="Main Category" />
300
- <CollapsibleContent>
304
+ // ─── Interactive ─────────────────────────────────────────────────────────────
305
+
306
+ export const Interactive: Story = {
307
+ parameters: {
308
+ docs: {
309
+ description: {
310
+ story:
311
+ "A multi-panel audio settings surface with local state controls for opening individual panels or expanding everything at once.",
312
+ },
313
+ },
314
+ },
315
+ render: () => {
316
+ const sections = [
317
+ {
318
+ id: "track",
319
+ title: "Track Info",
320
+ content: (
321
+ <div className="space-y-3 pt-4">
322
+ {[
323
+ ["Title", "Midnight Rain"],
324
+ ["Artist", "Taylor Swift"],
325
+ ["Album", "Midnights"],
326
+ ["Duration", "2:53"],
327
+ ].map(([label, value]) => (
328
+ <div key={label} className="flex items-center justify-between">
329
+ <span className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
330
+ {label}
331
+ </span>
332
+ <span className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
333
+ {value}
334
+ </span>
335
+ </div>
336
+ ))}
337
+ </div>
338
+ ),
339
+ },
340
+ {
341
+ id: "eq",
342
+ title: "EQ Settings",
343
+ content: (
344
+ <div className="space-y-3 pt-4">
345
+ {[
346
+ ["Sub-Bass", "60 Hz · +2 dB"],
347
+ ["Bass", "250 Hz · +4 dB"],
348
+ ["Mid", "1 kHz · 0 dB"],
349
+ ["Presence", "4 kHz · −1 dB"],
350
+ ["Treble", "10 kHz · −3 dB"],
351
+ ].map(([label, value]) => (
352
+ <div key={label} className="flex items-center justify-between">
353
+ <span className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
354
+ {label}
355
+ </span>
356
+ <span className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
357
+ {value}
358
+ </span>
359
+ </div>
360
+ ))}
361
+ </div>
362
+ ),
363
+ },
364
+ {
365
+ id: "playlist",
366
+ title: "Playlist Details",
367
+ content: (
301
368
  <div className="space-y-2 pt-4">
302
- <p className="mb-4">This section contains nested collapsibles:</p>
369
+ {[
370
+ "Anti-Hero",
371
+ "Lavender Haze",
372
+ "Midnight Rain",
373
+ "Question...?",
374
+ "Vigilante Shit",
375
+ ].map((track, index) => (
376
+ <div key={track} className="flex items-center gap-3">
377
+ <span className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm w-5 text-right">
378
+ {index + 1}
379
+ </span>
380
+ <span className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
381
+ {track}
382
+ </span>
383
+ </div>
384
+ ))}
385
+ </div>
386
+ ),
387
+ },
388
+ ]
303
389
 
304
- <Collapsible className="ml-4">
305
- <CollapsibleHeader title="Subcategory A" />
306
- <CollapsibleContent>
307
- <div className="pt-4">
308
- <p>Content for subcategory A with detailed information.</p>
309
- </div>
310
- </CollapsibleContent>
311
- </Collapsible>
390
+ const Demo = () => {
391
+ const [openMap, setOpenMap] = useState<Record<string, boolean>>({
392
+ track: true,
393
+ eq: false,
394
+ playlist: false,
395
+ })
312
396
 
313
- <Collapsible className="ml-4">
314
- <CollapsibleHeader title="Subcategory B" />
315
- <CollapsibleContent>
316
- <div className="pt-4">
317
- <p>Content for subcategory B with additional details.</p>
397
+ const allOpen = Object.values(openMap).every(Boolean)
398
+
399
+ const togglePanel = (id: string) => {
400
+ setOpenMap((current) => ({ ...current, [id]: !current[id] }))
401
+ }
402
+
403
+ const toggleAll = () => {
404
+ const nextValue = !allOpen
405
+ setOpenMap(
406
+ Object.fromEntries(sections.map(({ id }) => [id, nextValue]))
407
+ )
408
+ }
409
+
410
+ return (
411
+ <div className="w-full p-8">
412
+ <div className="mx-auto max-w-3xl space-y-6">
413
+ <div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
414
+ <div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-5 rounded-xl border p-5">
415
+ <p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold tracking-widest uppercase">
416
+ Panels
417
+ </p>
418
+ {sections.map(({ id, title }) => (
419
+ <button
420
+ key={id}
421
+ onClick={() => togglePanel(id)}
422
+ className="border-fm-divider-secondary bg-fm-surface-primary text-fm-primary font-fm-text text-fm-sm leading-fm-sm hover:border-fm-divider-primary w-full rounded-lg border px-4 py-2 text-left transition-colors"
423
+ >
424
+ {openMap[id] ? "Close" : "Open"} {title}
425
+ </button>
426
+ ))}
427
+ <div className="border-fm-divider-secondary border-t pt-4" />
428
+ <button
429
+ onClick={toggleAll}
430
+ className="border-fm-divider-primary text-fm-primary font-fm-text text-fm-sm leading-fm-sm hover:bg-fm-surface-primary w-full rounded-lg border px-4 py-2 transition-colors"
431
+ >
432
+ {allOpen ? "Collapse All" : "Expand All"}
433
+ </button>
434
+ </div>
435
+
436
+ <div className="flex flex-col gap-3 lg:col-span-2">
437
+ <div className="space-y-0">
438
+ {sections.map(({ id, title, content }) => (
439
+ <Collapsible
440
+ key={id}
441
+ open={openMap[id]}
442
+ onOpenChange={(open) =>
443
+ setOpenMap((current) => ({ ...current, [id]: open }))
444
+ }
445
+ >
446
+ <CollapsibleHeader title={title} />
447
+ <CollapsibleContent>{content}</CollapsibleContent>
448
+ </Collapsible>
449
+ ))}
318
450
  </div>
319
- </CollapsibleContent>
320
- </Collapsible>
451
+ <div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-4 py-3">
452
+ <code className="text-fm-secondary text-fm-md leading-fm-md font-[var(--font-fm-mono)]">
453
+ {`openMap = ${JSON.stringify(openMap)}`}
454
+ </code>
455
+ </div>
456
+ </div>
457
+ </div>
321
458
  </div>
322
- </CollapsibleContent>
323
- </Collapsible>
324
- </div>
325
- ),
459
+ </div>
460
+ )
461
+ }
462
+
463
+ return <Demo />
464
+ },
326
465
  }