aural-ui 4.0.1 → 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 (174) hide show
  1. package/dist/components/aspect-ratio/AspectRatio.stories.tsx +290 -1228
  2. package/dist/components/avatar/Avatar.stories.tsx +219 -235
  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/card/Card.stories.tsx +619 -301
  8. package/dist/components/char-count/CharCount.stories.tsx +350 -248
  9. package/dist/components/checkbox/Checkbox.stories.tsx +309 -167
  10. package/dist/components/chip/Chip.stories.tsx +362 -168
  11. package/dist/components/circular-loader/CircularLoader.stories.tsx +221 -636
  12. package/dist/components/clamp-lines/ClampLines.stories.tsx +246 -117
  13. package/dist/components/collapsible/Collapsible.stories.tsx +391 -252
  14. package/dist/components/command/Command.stories.tsx +530 -867
  15. package/dist/components/dialog/Dialog.stories.tsx +501 -950
  16. package/dist/components/divider/Divider.stories.tsx +264 -527
  17. package/dist/components/dot-loader/DotLoader.stories.tsx +256 -257
  18. package/dist/components/drawer/Drawer.stories.tsx +659 -1023
  19. package/dist/components/dropdown/Dropdown.stories.tsx +643 -1028
  20. package/dist/components/form/Form.stories.tsx +560 -274
  21. package/dist/components/helper-text/HelperText.stories.tsx +199 -200
  22. package/dist/components/hover-card/HoverCard.stories.tsx +318 -1254
  23. package/dist/components/icon-button/IconButton.stories.tsx +837 -194
  24. package/dist/components/if-else/if-else.stories.tsx +370 -83
  25. package/dist/components/input/Input.stories.tsx +436 -368
  26. package/dist/components/label/Label.stories.tsx +156 -154
  27. package/dist/components/list/List.stories.tsx +484 -835
  28. package/dist/components/marquee/Marquee.stories.tsx +356 -712
  29. package/dist/components/otp-inputs/OtpInputs.stories.tsx +352 -422
  30. package/dist/components/overlay/Overlay.stories.tsx +452 -824
  31. package/dist/components/pagination/Pagination.stories.tsx +721 -210
  32. package/dist/components/popover/Popover.stories.tsx +481 -896
  33. package/dist/components/radio/Radio.stories.tsx +432 -124
  34. package/dist/components/resizable/Resizable.stories.tsx +495 -799
  35. package/dist/components/scroll-area/ScrollArea.stories.tsx +383 -1059
  36. package/dist/components/search/Search.stories.tsx +312 -595
  37. package/dist/components/select/Select.stories.tsx +684 -789
  38. package/dist/components/sheet/Sheet.stories.tsx +671 -950
  39. package/dist/components/skelton/Skelton.stories.tsx +230 -764
  40. package/dist/components/slider/Slider.stories.tsx +383 -760
  41. package/dist/components/stepper/Stepper.stories.tsx +371 -514
  42. package/dist/components/switch/Switch.stories.tsx +461 -208
  43. package/dist/components/switch-case/SwitchCase.stories.tsx +367 -188
  44. package/dist/components/table/Table.stories.tsx +770 -916
  45. package/dist/components/tabs/Tabs.stories.tsx +458 -1455
  46. package/dist/components/tag/Tag.stories.tsx +714 -542
  47. package/dist/components/textarea/TextArea.stories.tsx +621 -562
  48. package/dist/components/thumbnail-tags/ThumbnailTags.stories.tsx +228 -154
  49. package/dist/components/toast/Toast.stories.tsx +452 -1339
  50. package/dist/components/toggle/Toggle.stories.tsx +488 -931
  51. package/dist/components/tooltip/Tooltip.stories.tsx +344 -1388
  52. package/dist/components/typography/Typography.stories.tsx +406 -89
  53. package/dist/hooks/use-change-state/UseChangeState.stories.tsx +309 -606
  54. package/dist/hooks/use-previous/UsePrevious.stories.tsx +367 -917
  55. package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +639 -867
  56. package/dist/icons/Icons.stories.tsx +0 -12
  57. package/dist/icons/ai-avatar-icon/AiAvatarIcon.stories.tsx +223 -1060
  58. package/dist/icons/alert-icon/AlertIcon.stories.tsx +106 -968
  59. package/dist/icons/all-icons.tsx +37 -16
  60. package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +137 -1010
  61. package/dist/icons/apple-logo-icon/AppleLogoIcon.stories.tsx +145 -935
  62. package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +132 -1046
  63. package/dist/icons/arrow-corner-up-left-icon/ArrowCornerUpLeftIcon.stories.tsx +134 -986
  64. package/dist/icons/arrow-corner-up-right-icon/ArrowCornerUpRightIcon.stories.tsx +135 -1028
  65. package/dist/icons/arrow-left-icon/ArrowLeftIcon.stories.tsx +133 -971
  66. package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +145 -1123
  67. package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +143 -1252
  68. package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +123 -632
  69. package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +141 -1223
  70. package/dist/icons/backward-ten-seconds-icon/BackwardTenSecondsIcon.stories.tsx +164 -1018
  71. package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +121 -1236
  72. package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +121 -1213
  73. package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +116 -893
  74. package/dist/icons/camera-icon/CameraIcon.stories.tsx +109 -1254
  75. package/dist/icons/capital-a-letter-icon/CapitalALetterIcon.stories.tsx +114 -975
  76. package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +157 -994
  77. package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +160 -992
  78. package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +140 -970
  79. package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +126 -993
  80. package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +144 -987
  81. package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +141 -1007
  82. package/dist/icons/circle-tick-icon/CircleTickIcon.stories.tsx +147 -1187
  83. package/dist/icons/circular-play-icon/CircularPlayIcon.stories.tsx +110 -476
  84. package/dist/icons/coin-icon/CoinIcon.stories.tsx +120 -1364
  85. package/dist/icons/coin-toons-icon/CoinToonsIcon.stories.tsx +113 -1360
  86. package/dist/icons/column-wide-add-icon/ColumnWideAddIcon.stories.tsx +111 -942
  87. package/dist/icons/command-icon/CommandIcon.stories.tsx +124 -1087
  88. package/dist/icons/copy-icon/CopyIcon.stories.tsx +119 -996
  89. package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +144 -1046
  90. package/dist/icons/cross-icon/CrossIcon.stories.tsx +136 -999
  91. package/dist/icons/download-icon/DownloadIcon.stories.tsx +123 -857
  92. package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +121 -1080
  93. package/dist/icons/email-icon/EmailIcon.stories.tsx +112 -979
  94. package/dist/icons/expand-icon/ExpandIcon.stories.tsx +109 -1146
  95. package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +141 -1068
  96. package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +140 -1081
  97. package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +124 -1050
  98. package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +123 -1091
  99. package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +122 -633
  100. package/dist/icons/filter-bar-row-icon/FilterBarRowIcon.stories.tsx +116 -1087
  101. package/dist/icons/forward-ten-seconds-icon/ForwardTenSecondsIcon.stories.tsx +166 -1020
  102. package/dist/icons/git-branch-icon/GitBranchIcon.stories.tsx +112 -1182
  103. package/dist/icons/git-fork-icon/GitForkIcon.stories.tsx +112 -1155
  104. package/dist/icons/globe-icon/GlobeIcon.stories.tsx +127 -325
  105. package/dist/icons/google-logo-icon/GoogleLogoIcon.stories.tsx +142 -985
  106. package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +116 -1217
  107. package/dist/icons/head-icon/HeadIcon.stories.tsx +108 -953
  108. package/dist/icons/heart-icon/HeartIcon.stories.tsx +117 -1060
  109. package/dist/icons/image-avatar-sparkle-icon/ImageAvatarSparkleIcon.stories.tsx +116 -716
  110. package/dist/icons/image-icon/ImageIcon.stories.tsx +102 -1164
  111. package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +108 -1233
  112. package/dist/icons/import-left-arrow-folder-icon/ImportLeftArrowFolderIcon.stories.tsx +133 -1289
  113. package/dist/icons/indian-flag-icon/IndianFlagIcon.stories.tsx +155 -1012
  114. package/dist/icons/instagram-icon/InstagramIcon.stories.tsx +158 -1438
  115. package/dist/icons/layout-column-icon/LayoutColumnIcon.stories.tsx +121 -1011
  116. package/dist/icons/layout-left-icon/LayoutLeftIcon.stories.tsx +116 -981
  117. package/dist/icons/layout-right-icon/LayoutRightIcon.stories.tsx +116 -979
  118. package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +105 -1252
  119. package/dist/icons/linked-in-icon/LinkedInIcon.stories.tsx +151 -1554
  120. package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +107 -1227
  121. package/dist/icons/magic-edit-icon/MagicEditIcon.stories.tsx +116 -707
  122. package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +119 -1226
  123. package/dist/icons/message-icon/MessageIcon.stories.tsx +111 -557
  124. package/dist/icons/minimize-icon/MinimizeIcon.stories.tsx +112 -1198
  125. package/dist/icons/moon-icon/MoonIcon.stories.tsx +117 -557
  126. package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +106 -1235
  127. package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +112 -1185
  128. package/dist/icons/musical-note-icon/MusicalNoteIcon.stories.tsx +116 -1012
  129. package/dist/icons/notepad-icon/NotepadIcon.stories.tsx +108 -1137
  130. package/dist/icons/notes-icon/NotesIcon.stories.tsx +116 -1138
  131. package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +106 -1146
  132. package/dist/icons/page-text-icon/PageTextIcon.stories.tsx +119 -719
  133. package/dist/icons/paint-roll-icon/PaintRollIcon.stories.tsx +110 -999
  134. package/dist/icons/paper-plane-icon/PaperPlaneIcon.stories.tsx +109 -912
  135. package/dist/icons/pause-icon/PauseIcon.stories.tsx +110 -1041
  136. package/dist/icons/pencil-icon/PencilIcon.stories.tsx +112 -1109
  137. package/dist/icons/phone-icon/PhoneIcon.stories.tsx +112 -1023
  138. package/dist/icons/plus-icon/PlusIcon.stories.tsx +103 -1132
  139. package/dist/icons/pocket-studio-icon/PocketStudioIcon.stories.tsx +104 -870
  140. package/dist/icons/scroll-down-icon/ScrollDownIcon.stories.tsx +99 -476
  141. package/dist/icons/search-icon/SearchIcon.stories.tsx +108 -1161
  142. package/dist/icons/setting-icon/SettingIcon.stories.tsx +104 -1009
  143. package/dist/icons/share-icon/ShareIcon.stories.tsx +117 -1064
  144. package/dist/icons/shield-icon/ShieldIcon.stories.tsx +114 -974
  145. package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +134 -1160
  146. package/dist/icons/skip-backward-icon/SkipBackwardIcon.stories.tsx +169 -1017
  147. package/dist/icons/skip-forward-icon/SkipForwardIcon.stories.tsx +161 -1016
  148. package/dist/icons/sparkles-soft-icon/SparklesSoftIcon.stories.tsx +102 -1001
  149. package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +155 -593
  150. package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +155 -608
  151. package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +142 -712
  152. package/dist/icons/star-icon/StarIcon.stories.tsx +120 -946
  153. package/dist/icons/store-coin-icon/StoreCoinIcon.stories.tsx +109 -1013
  154. package/dist/icons/suggestion-icon/SuggestionIcon.stories.tsx +113 -891
  155. package/dist/icons/sun-icon/SunIcon.stories.tsx +117 -864
  156. package/dist/icons/text-color-icon/TextColorIcon.stories.tsx +113 -989
  157. package/dist/icons/text-indicator-icon/TextIndicatorIcon.stories.tsx +120 -1027
  158. package/dist/icons/threads-icon/ThreadsIcon.stories.tsx +153 -1476
  159. package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +143 -1187
  160. package/dist/icons/tick-icon/TickIcon.stories.tsx +142 -1322
  161. package/dist/icons/trash-icon/TrashIcon.stories.tsx +105 -970
  162. package/dist/icons/twitter-x-icon/TwitterXIcon.stories.tsx +154 -1457
  163. package/dist/icons/upload-icon/UploadIcon.stories.tsx +112 -930
  164. package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +115 -1019
  165. package/dist/icons/video-play-list-icon/VideoPlaylistIcon.stories.tsx +122 -1092
  166. package/dist/icons/voice-playing-icon/VoicePlayingIcon.stories.tsx +120 -1401
  167. package/dist/icons/volume-full-icon/VolumeFullIcon.stories.tsx +107 -1212
  168. package/dist/icons/volume-half-icon/VolumeHalfIcon.stories.tsx +109 -1122
  169. package/dist/icons/volume-off-icon/VolumeOffIcon.stories.tsx +112 -1124
  170. package/dist/icons/warning-icon/WarningIcon.stories.tsx +119 -1083
  171. package/dist/icons/youtube-icon/YoutubeIcon.stories.tsx +158 -983
  172. package/dist/index.cjs +1 -1
  173. package/dist/index.js +1 -1
  174. package/package.json +1 -1
@@ -1,6 +1,8 @@
1
1
  import React from "react"
2
2
  import type { Meta, StoryObj } from "@storybook/react-vite"
3
3
 
4
+ import { AuralComponentDocsPage } from "src/ui/story-spec/components/component-story-docs-page"
5
+
4
6
  import { ScrollArea, ScrollBar } from "."
5
7
 
6
8
  const meta: Meta<typeof ScrollArea> = {
@@ -8,69 +10,29 @@ const meta: Meta<typeof ScrollArea> = {
8
10
  component: ScrollArea,
9
11
  parameters: {
10
12
  layout: "centered",
11
- backgrounds: {
12
- default: "dark",
13
- values: [
14
- { name: "dark", value: "#0a0a0a" },
15
- { name: "light", value: "#ffffff" },
16
- ],
17
- },
18
13
  docs: {
19
14
  description: {
20
- component: `
21
- # ScrollArea Component
22
-
23
- A custom scrollable area component built on Radix UI primitives with styled scrollbars and smooth scrolling behavior.
24
-
25
- ## Features
26
-
27
- - **Custom Scrollbars**: Styled scrollbars that match your design system
28
- - **Smooth Scrolling**: Optimized scrolling performance with native feel
29
- - **Keyboard Navigation**: Full keyboard support for accessibility
30
- - **Focus Management**: Proper focus ring and outline handling
31
- - **Cross-browser**: Consistent appearance across different browsers
32
- - **Touch Support**: Touch-friendly scrolling on mobile devices
33
- - **Orientation Support**: Both vertical and horizontal scrolling
34
-
35
- ## Component Structure
36
-
37
- - **ScrollArea**: Root container that manages the scrollable region
38
- - **ScrollBar**: Custom scrollbar component with thumb indicator
39
- - **Viewport**: The actual scrollable content area
40
- - **Corner**: Corner element for when both scrollbars are present
41
-
42
- ## Usage Examples
43
-
44
- ### Basic Vertical Scroll
45
- \`\`\`tsx
46
- <ScrollArea className="h-72 w-48">
47
- <div className="p-4">
48
- {/* Long content that needs scrolling */}
49
- </div>
50
- </ScrollArea>
51
- \`\`\`
52
-
53
- ### Horizontal Scroll
54
- \`\`\`tsx
55
- <ScrollArea className="w-72 whitespace-nowrap">
56
- <div className="flex w-max gap-4 p-4">
57
- {/* Wide content that needs horizontal scrolling */}
58
- </div>
59
- <ScrollBar orientation="horizontal" />
60
- </ScrollArea>
61
- \`\`\`
62
-
63
- ### Both Directions
64
- \`\`\`tsx
65
- <ScrollArea className="h-72 w-72">
66
- <div className="w-[800px] h-[600px] p-4">
67
- {/* Content that overflows both directions */}
68
- </div>
69
- <ScrollBar orientation="horizontal" />
70
- </ScrollArea>
71
- \`\`\`
72
- `,
15
+ component:
16
+ "A custom scrollable container built on Radix UI primitives. Provides styled scrollbars and smooth scrolling in vertical, horizontal, or both directions. Ideal for constraining long lists, message threads, track queues, and other overflow content within a fixed viewport.",
73
17
  },
18
+ page: () => (
19
+ <AuralComponentDocsPage
20
+ features={[
21
+ {
22
+ title: "Styled Scrollbars",
23
+ description: "Custom Radix scrollbar",
24
+ },
25
+ {
26
+ title: "Both Directions",
27
+ description: "Vertical and horizontal",
28
+ },
29
+ {
30
+ title: "Fixed Viewport",
31
+ description: "Overflow content area",
32
+ },
33
+ ]}
34
+ />
35
+ ),
74
36
  },
75
37
  },
76
38
  tags: ["autodocs"],
@@ -79,459 +41,146 @@ A custom scrollable area component built on Radix UI primitives with styled scro
79
41
  export default meta
80
42
  type Story = StoryObj<typeof ScrollArea>
81
43
 
82
- // 1. Basic Vertical Scroll
83
- export const BasicVerticalScroll: Story = {
44
+ // ─── 1. Configurations ────────────────────────────────────────────────────────
45
+
46
+ export const Configurations: Story = {
84
47
  render: () => (
85
48
  <div className="space-y-8">
86
- <div className="text-center">
87
- <h3 className="text-fm-primary mb-2 font-medium">
88
- Basic Vertical Scroll
89
- </h3>
90
- <p className="text-fm-secondary text-sm">
91
- Standard vertical scrolling with custom styled scrollbar
92
- </p>
93
- </div>
94
-
95
- <div className="flex flex-wrap justify-center gap-8">
96
- {/* Text Content */}
97
- <div className="space-y-2">
98
- <h4 className="text-fm-secondary text-sm font-medium">
99
- Text Content
100
- </h4>
101
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-72 w-80 rounded-lg border">
102
- <div className="p-4">
103
- <h4 className="text-fm-primary mb-4 text-sm leading-none font-medium">
104
- The Art of Web Development
105
- </h4>
106
- <div className="text-fm-secondary space-y-4 text-sm">
107
- <p>
108
- Web development is an ever-evolving field that combines
109
- creativity with technical expertise. Modern developers must
110
- master a wide array of technologies, from frontend frameworks
111
- like React and Vue to backend systems built with Node.js,
112
- Python, or Go.
113
- </p>
114
- <p>
115
- The importance of user experience cannot be overstated. Every
116
- line of code we write should be with the end user in mind.
117
- Performance, accessibility, and intuitive design are not just
118
- buzzwords—they are fundamental requirements for successful web
119
- applications.
120
- </p>
121
- <p>
122
- Component-driven development has revolutionized how we build
123
- user interfaces. By creating reusable, modular components, we
124
- can maintain consistency across large applications while
125
- reducing development time and improving code quality.
126
- </p>
127
- <p>
128
- CSS has grown tremendously powerful with features like Grid,
129
- Flexbox, and custom properties. Combined with modern tools
130
- like Tailwind CSS, we can create beautiful, responsive designs
131
- with unprecedented efficiency.
132
- </p>
133
- <p>
134
- The future of web development looks bright with emerging
135
- technologies like WebAssembly, Web Components, and progressive
136
- enhancement techniques that make the web more capable and
137
- accessible to everyone.
138
- </p>
139
- <p>
140
- Testing and quality assurance remain critical aspects of
141
- professional development. Unit tests, integration tests, and
142
- end-to-end testing help ensure our applications work reliably
143
- across different environments and use cases.
144
- </p>
145
- </div>
146
- </div>
147
- </ScrollArea>
148
- </div>
149
-
150
- {/* List Content */}
151
- <div className="space-y-2">
152
- <h4 className="text-fm-secondary text-sm font-medium">
153
- List Content
154
- </h4>
155
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-72 w-80 rounded-lg border">
156
- <div className="p-4">
157
- <h4 className="text-fm-primary mb-4 text-sm leading-none font-medium">
158
- Popular Programming Languages
159
- </h4>
160
- <div className="space-y-2">
161
- {[
162
- {
163
- name: "JavaScript",
164
- desc: "Dynamic web programming language",
165
- },
166
- { name: "TypeScript", desc: "Typed superset of JavaScript" },
167
- { name: "Python", desc: "Versatile and beginner-friendly" },
168
- { name: "Java", desc: "Object-oriented enterprise language" },
169
- {
170
- name: "C#",
171
- desc: "Microsoft's modern programming language",
172
- },
173
- { name: "Go", desc: "Fast and efficient systems language" },
174
- { name: "Rust", desc: "Memory-safe systems programming" },
175
- {
176
- name: "Swift",
177
- desc: "Apple's modern programming language",
178
- },
179
- { name: "Kotlin", desc: "Modern alternative to Java" },
180
- { name: "PHP", desc: "Server-side web development" },
181
- { name: "Ruby", desc: "Elegant and expressive language" },
182
- {
183
- name: "C++",
184
- desc: "Powerful systems programming language",
185
- },
186
- { name: "Dart", desc: "Language for Flutter development" },
187
- { name: "Scala", desc: "Functional programming on JVM" },
188
- { name: "Elixir", desc: "Concurrent and fault-tolerant" },
189
- ].map((lang, index) => (
49
+ {/* Vertical scroll */}
50
+ <div>
51
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md mb-4 font-medium">
52
+ Vertical Scroll
53
+ </h4>
54
+ <div className="flex flex-wrap gap-6">
55
+ <div className="space-y-2 text-center">
56
+ <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-56 w-64 rounded-lg border">
57
+ <div className="space-y-2 p-4">
58
+ {Array.from({ length: 12 }, (_, i) => (
190
59
  <div
191
- key={index}
192
- className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-3"
60
+ key={i}
61
+ className="border-fm-divider-secondary bg-fm-surface-primary rounded-md border px-3 py-2"
193
62
  >
194
- <div className="text-fm-primary font-medium">
195
- {lang.name}
196
- </div>
197
- <div className="text-fm-secondary text-xs">{lang.desc}</div>
63
+ <p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
64
+ Track {i + 1}
65
+ </p>
198
66
  </div>
199
67
  ))}
200
68
  </div>
201
- </div>
202
- </ScrollArea>
203
- </div>
204
- </div>
205
- </div>
206
- ),
207
- parameters: {
208
- docs: {
209
- description: {
210
- story:
211
- "Basic vertical scrolling examples with text content and list items showing custom scrollbar styling.",
212
- },
213
- },
214
- },
215
- }
216
-
217
- // 2. Horizontal Scroll
218
- export const HorizontalScroll: Story = {
219
- render: () => (
220
- <div className="space-y-8">
221
- <div className="text-center">
222
- <h3 className="text-fm-primary mb-2 font-medium">Horizontal Scroll</h3>
223
- <p className="text-fm-secondary text-sm">
224
- Horizontal scrolling with custom scrollbar orientation
225
- </p>
226
- </div>
69
+ </ScrollArea>
70
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
71
+ Fixed height (224px)
72
+ </p>
73
+ </div>
227
74
 
228
- <div className="space-y-6">
229
- {/* Image Gallery */}
230
- <div className="space-y-2">
231
- <h4 className="text-fm-secondary text-sm font-medium">
232
- Image Gallery
233
- </h4>
234
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary w-full max-w-4xl rounded-lg border whitespace-nowrap">
235
- <div className="flex w-max gap-4 p-4">
236
- {[
237
- {
238
- id: 1,
239
- color: "from-blue-500 to-purple-600",
240
- name: "Mountain Vista",
241
- },
242
- {
243
- id: 2,
244
- color: "from-green-500 to-teal-600",
245
- name: "Forest Path",
246
- },
247
- {
248
- id: 3,
249
- color: "from-orange-500 to-red-600",
250
- name: "Desert Sunset",
251
- },
252
- {
253
- id: 4,
254
- color: "from-purple-500 to-pink-600",
255
- name: "Ocean Waves",
256
- },
257
- {
258
- id: 5,
259
- color: "from-teal-500 to-cyan-600",
260
- name: "City Lights",
261
- },
262
- {
263
- id: 6,
264
- color: "from-yellow-500 to-orange-600",
265
- name: "Golden Hour",
266
- },
267
- {
268
- id: 7,
269
- color: "from-indigo-500 to-blue-600",
270
- name: "Starry Night",
271
- },
272
- {
273
- id: 8,
274
- color: "from-pink-500 to-rose-600",
275
- name: "Cherry Blossoms",
276
- },
277
- ].map((item) => (
278
- <div key={item.id} className="flex-none space-y-2">
75
+ <div className="space-y-2 text-center">
76
+ <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-40 w-64 rounded-lg border">
77
+ <div className="space-y-2 p-4">
78
+ {Array.from({ length: 10 }, (_, i) => (
279
79
  <div
280
- className={`h-32 w-48 rounded-lg bg-gradient-to-br ${item.color} flex items-center justify-center font-medium text-white`}
80
+ key={i}
81
+ className="border-fm-divider-secondary bg-fm-surface-primary rounded-md border px-3 py-2"
281
82
  >
282
- {item.name}
83
+ <p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
84
+ Playlist item {i + 1}
85
+ </p>
283
86
  </div>
284
- <p className="text-fm-secondary text-center text-xs">
285
- {item.name}
286
- </p>
287
- </div>
288
- ))}
289
- </div>
290
- <ScrollBar orientation="horizontal" />
291
- </ScrollArea>
87
+ ))}
88
+ </div>
89
+ </ScrollArea>
90
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
91
+ Compact height (160px)
92
+ </p>
93
+ </div>
292
94
  </div>
95
+ </div>
293
96
 
294
- {/* Tag List */}
295
- <div className="space-y-2">
296
- <h4 className="text-fm-secondary text-sm font-medium">
297
- Technology Tags
298
- </h4>
299
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary w-full max-w-2xl rounded-lg border whitespace-nowrap">
300
- <div className="flex w-max gap-2 p-4">
97
+ {/* Horizontal scroll */}
98
+ <div>
99
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md mb-4 font-medium">
100
+ Horizontal Scroll
101
+ </h4>
102
+ <div className="space-y-2 text-center">
103
+ <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary w-80 rounded-lg border whitespace-nowrap">
104
+ <div className="flex w-max gap-3 p-4">
301
105
  {[
302
- "React",
303
- "Vue.js",
304
- "Angular",
305
- "Svelte",
306
- "Next.js",
307
- "Nuxt.js",
308
- "Gatsby",
309
- "TypeScript",
310
- "JavaScript",
311
- "Node.js",
312
- "Express",
313
- "Fastify",
314
- "Koa",
315
- "MongoDB",
316
- "PostgreSQL",
317
- "MySQL",
318
- "Redis",
319
- "GraphQL",
320
- "REST API",
321
- "Docker",
322
- "Kubernetes",
323
- "AWS",
324
- "Vercel",
325
- "Netlify",
326
- "Firebase",
327
- ].map((tag, index) => (
106
+ "Hip-Hop",
107
+ "R&B",
108
+ "Electronic",
109
+ "Jazz",
110
+ "Classical",
111
+ "Indie",
112
+ "Pop",
113
+ "Metal",
114
+ "Soul",
115
+ "Funk",
116
+ "Reggae",
117
+ ].map((genre) => (
328
118
  <div
329
- key={index}
330
- className="border-fm-divider-secondary bg-fm-surface-info-sec text-fm-info flex-none rounded-full border px-3 py-1 text-xs"
119
+ key={genre}
120
+ className="border-fm-divider-secondary bg-fm-surface-primary flex-none rounded-full border px-4 py-1.5"
331
121
  >
332
- {tag}
333
- </div>
334
- ))}
335
- </div>
336
- <ScrollBar orientation="horizontal" />
337
- </ScrollArea>
338
- </div>
339
-
340
- {/* Timeline */}
341
- <div className="space-y-2">
342
- <h4 className="text-fm-secondary text-sm font-medium">
343
- Project Timeline
344
- </h4>
345
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary w-full max-w-3xl rounded-lg border whitespace-nowrap">
346
- <div className="flex w-max gap-6 p-4">
347
- {[
348
- { phase: "Planning", duration: "2 weeks", status: "completed" },
349
- { phase: "Design", duration: "3 weeks", status: "completed" },
350
- {
351
- phase: "Development",
352
- duration: "8 weeks",
353
- status: "in-progress",
354
- },
355
- { phase: "Testing", duration: "2 weeks", status: "pending" },
356
- { phase: "Deployment", duration: "1 week", status: "pending" },
357
- { phase: "Launch", duration: "1 week", status: "pending" },
358
- ].map((item, index) => (
359
- <div key={index} className="flex-none space-y-2">
360
- <div className="border-fm-divider-secondary bg-fm-surface-secondary w-32 rounded-lg border p-3">
361
- <div
362
- className={`mb-2 h-2 w-2 rounded-full ${
363
- item.status === "completed"
364
- ? "bg-fm-surface-positive"
365
- : item.status === "in-progress"
366
- ? "bg-fm-surface-warning"
367
- : "bg-fm-surface-tertiary"
368
- }`}
369
- ></div>
370
- <div className="text-fm-primary text-sm font-medium">
371
- {item.phase}
372
- </div>
373
- <div className="text-fm-secondary text-xs">
374
- {item.duration}
375
- </div>
376
- </div>
122
+ <p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
123
+ {genre}
124
+ </p>
377
125
  </div>
378
126
  ))}
379
127
  </div>
380
128
  <ScrollBar orientation="horizontal" />
381
129
  </ScrollArea>
130
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
131
+ Genre tag strip (fixed width 320px)
132
+ </p>
382
133
  </div>
383
134
  </div>
384
- </div>
385
- ),
386
- parameters: {
387
- docs: {
388
- description: {
389
- story:
390
- "Horizontal scrolling examples including image galleries, tag lists, and timeline components with horizontal scrollbars.",
391
- },
392
- },
393
- },
394
- }
395
-
396
- // 3. Both Directions
397
- export const BothDirectionsScroll: Story = {
398
- render: () => (
399
- <div className="space-y-8">
400
- <div className="text-center">
401
- <h3 className="text-fm-primary mb-2 font-medium">
402
- Two-Dimensional Scroll
403
- </h3>
404
- <p className="text-fm-secondary text-sm">
405
- Content that scrolls both horizontally and vertically
406
- </p>
407
- </div>
408
135
 
409
- <div className="space-y-6">
410
- {/* Data Table */}
411
- <div className="space-y-2">
412
- <h4 className="text-fm-secondary text-sm font-medium">Data Table</h4>
413
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-80 w-full max-w-4xl rounded-lg border">
414
- <div className="w-[1200px] p-4">
415
- <table className="w-full text-sm">
416
- <thead>
417
- <tr className="border-fm-divider-secondary border-b">
418
- <th className="text-fm-primary p-2 text-left">ID</th>
419
- <th className="text-fm-primary p-2 text-left">Name</th>
420
- <th className="text-fm-primary p-2 text-left">Email</th>
421
- <th className="text-fm-primary p-2 text-left">Role</th>
422
- <th className="text-fm-primary p-2 text-left">
423
- Department
424
- </th>
425
- <th className="text-fm-primary p-2 text-left">Location</th>
426
- <th className="text-fm-primary p-2 text-left">
427
- Start Date
428
- </th>
429
- <th className="text-fm-primary p-2 text-left">Salary</th>
430
- <th className="text-fm-primary p-2 text-left">Status</th>
431
- </tr>
432
- </thead>
433
- <tbody>
434
- {Array.from({ length: 50 }, (_, i) => (
435
- <tr
436
- key={i}
437
- className="border-fm-divider-secondary border-b"
136
+ {/* Both directions */}
137
+ <div>
138
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md mb-4 font-medium">
139
+ Both Directions
140
+ </h4>
141
+ <div className="space-y-2 text-center">
142
+ <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-48 w-80 rounded-lg border">
143
+ <div className="w-140 p-4">
144
+ <div className="mb-3 grid grid-cols-5 gap-3">
145
+ {["Title", "Artist", "Album", "Duration", "Plays"].map(
146
+ (col) => (
147
+ <p
148
+ key={col}
149
+ className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm font-medium"
438
150
  >
439
- <td className="text-fm-secondary p-2">{1000 + i}</td>
440
- <td className="text-fm-secondary p-2">
441
- Employee {i + 1}
442
- </td>
443
- <td className="text-fm-secondary p-2">
444
- employee{i + 1}@company.com
445
- </td>
446
- <td className="text-fm-secondary p-2">
447
- {["Developer", "Designer", "Manager", "Analyst"][i % 4]}
448
- </td>
449
- <td className="text-fm-secondary p-2">
450
- {["Engineering", "Design", "Marketing", "Sales"][i % 4]}
451
- </td>
452
- <td className="text-fm-secondary p-2">
453
- {
454
- ["San Francisco", "New York", "London", "Tokyo"][
455
- i % 4
456
- ]
457
- }
458
- </td>
459
- <td className="text-fm-secondary p-2">
460
- {new Date(
461
- 2020 + (i % 4),
462
- i % 12,
463
- (i % 28) + 1
464
- ).toLocaleDateString()}
465
- </td>
466
- <td className="text-fm-secondary p-2">
467
- ${(50000 + i * 1000).toLocaleString()}
468
- </td>
469
- <td className="p-2">
470
- <span
471
- className={`rounded-full px-2 py-1 text-xs ${
472
- i % 3 === 0
473
- ? "bg-fm-surface-positive-sec text-fm-positive"
474
- : i % 3 === 1
475
- ? "bg-fm-surface-warning-sec text-fm-warning"
476
- : "bg-fm-surface-secondary text-fm-icon-negative"
477
- }`}
478
- >
479
- {i % 3 === 0
480
- ? "Active"
481
- : i % 3 === 1
482
- ? "Away"
483
- : "Inactive"}
484
- </span>
485
- </td>
486
- </tr>
487
- ))}
488
- </tbody>
489
- </table>
490
- </div>
491
- <ScrollBar orientation="horizontal" />
492
- </ScrollArea>
493
- </div>
494
-
495
- {/* Large Canvas */}
496
- <div className="space-y-2">
497
- <h4 className="text-fm-secondary text-sm font-medium">
498
- Design Canvas
499
- </h4>
500
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-96 w-full max-w-2xl rounded-lg border">
501
- <div className="h-[1200px] w-[1500px] bg-gradient-to-br from-blue-900/20 to-purple-900/20 p-4">
502
- <div className="relative h-full w-full">
503
- {/* Grid Pattern */}
151
+ {col}
152
+ </p>
153
+ )
154
+ )}
155
+ </div>
156
+ {Array.from({ length: 10 }, (_, i) => (
504
157
  <div
505
- className="absolute inset-0 opacity-20"
506
- style={{
507
- backgroundImage: `
508
- linear-gradient(rgba(255,255,255,0.1) 1px, transparent 1px),
509
- linear-gradient(90deg, rgba(255,255,255,0.1) 1px, transparent 1px)
510
- `,
511
- backgroundSize: "50px 50px",
512
- }}
513
- />
514
-
515
- {/* Design Elements */}
516
- <div className="text-fm-primary absolute top-20 left-20 flex h-32 w-48 items-center justify-center rounded-lg border border-blue-400/50 bg-blue-500/30">
517
- Header Component
518
- </div>
519
- <div className="text-fm-primary absolute top-60 left-20 flex h-40 w-64 items-center justify-center rounded-lg border border-green-400/50 bg-green-500/30">
520
- Navigation Menu
521
- </div>
522
- <div className="text-fm-primary absolute top-20 left-80 flex h-96 w-80 items-center justify-center rounded-lg border border-purple-400/50 bg-purple-500/30">
523
- Main Content Area
524
- </div>
525
- <div className="text-fm-primary absolute top-20 right-20 flex h-64 w-56 items-center justify-center rounded-lg border border-orange-400/50 bg-orange-500/30">
526
- Sidebar Widget
527
- </div>
528
- <div className="border-fm-divider-secondary bg-fm-surface-secondary text-fm-primary absolute bottom-20 left-20 flex h-24 w-[calc(100%-160px)] items-center justify-center rounded-lg border">
529
- Footer Component
158
+ key={i}
159
+ className="border-fm-divider-secondary grid grid-cols-5 gap-3 border-t py-2"
160
+ >
161
+ <p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm truncate">
162
+ Song {i + 1}
163
+ </p>
164
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm truncate">
165
+ Artist
166
+ </p>
167
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm truncate">
168
+ Album Name
169
+ </p>
170
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
171
+ 3:45
172
+ </p>
173
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
174
+ 1.2M
175
+ </p>
530
176
  </div>
531
- </div>
177
+ ))}
532
178
  </div>
533
179
  <ScrollBar orientation="horizontal" />
534
180
  </ScrollArea>
181
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
182
+ Wide table (560px content, 320px viewport)
183
+ </p>
535
184
  </div>
536
185
  </div>
537
186
  </div>
@@ -540,608 +189,283 @@ export const BothDirectionsScroll: Story = {
540
189
  docs: {
541
190
  description: {
542
191
  story:
543
- "Two-dimensional scrolling examples including data tables and design canvases that require both horizontal and vertical scrolling.",
192
+ "Comparison of all three scroll orientations: vertical with different height constraints, horizontal with a tag strip, and bidirectional with a wide data table.",
544
193
  },
545
194
  },
546
195
  },
547
196
  }
548
197
 
549
- // 4. Different Sizes
550
- export const DifferentSizes: Story = {
551
- render: () => (
552
- <div className="space-y-8">
553
- <div className="text-center">
554
- <h3 className="text-fm-primary mb-2 font-medium">Different Sizes</h3>
555
- <p className="text-fm-secondary text-sm">
556
- ScrollArea components in various sizes and configurations
557
- </p>
558
- </div>
559
-
560
- <div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
561
- {/* Small */}
562
- <div className="space-y-2">
563
- <h4 className="text-fm-secondary text-sm font-medium">
564
- Small (h-40)
565
- </h4>
566
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-40 w-full rounded-lg border">
567
- <div className="p-3">
568
- <h5 className="text-fm-primary mb-2 text-sm font-medium">
569
- Quick Notes
570
- </h5>
571
- <div className="text-fm-secondary space-y-2 text-xs">
572
- {Array.from({ length: 15 }, (_, i) => (
573
- <div key={i} className="bg-fm-surface-secondary rounded p-2">
574
- Note item {i + 1}: This is a quick note or reminder item.
575
- </div>
576
- ))}
577
- </div>
578
- </div>
579
- </ScrollArea>
580
- </div>
198
+ // ─── 2. UseCases ──────────────────────────────────────────────────────────────
581
199
 
582
- {/* Medium */}
583
- <div className="space-y-2">
584
- <h4 className="text-fm-secondary text-sm font-medium">
585
- Medium (h-64)
586
- </h4>
587
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-64 w-full rounded-lg border">
588
- <div className="p-4">
589
- <h5 className="text-fm-primary mb-3 text-sm font-medium">
590
- Task List
591
- </h5>
592
- <div className="space-y-3">
593
- {Array.from({ length: 12 }, (_, i) => (
594
- <div
595
- key={i}
596
- className="bg-fm-surface-secondary flex items-center gap-3 rounded-lg p-3"
597
- >
598
- <div
599
- className={`h-3 w-3 rounded-full ${
600
- i % 3 === 0
601
- ? "bg-fm-surface-positive"
602
- : "bg-fm-surface-tertiary"
603
- }`}
604
- ></div>
605
- <div>
606
- <div className="text-fm-primary text-sm">
607
- Task {i + 1}
608
- </div>
609
- <div className="text-fm-secondary text-xs">
610
- {i % 3 === 0 ? "Completed" : "Pending"}
611
- </div>
612
- </div>
613
- </div>
614
- ))}
615
- </div>
616
- </div>
617
- </ScrollArea>
618
- </div>
619
-
620
- {/* Large */}
621
- <div className="space-y-2">
622
- <h4 className="text-fm-secondary text-sm font-medium">
623
- Large (h-96)
624
- </h4>
625
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-96 w-full rounded-lg border">
626
- <div className="p-4">
627
- <h5 className="text-fm-primary mb-4 text-sm font-medium">
628
- Activity Feed
629
- </h5>
630
- <div className="space-y-4">
631
- {Array.from({ length: 20 }, (_, i) => (
632
- <div
633
- key={i}
634
- className="bg-fm-surface-secondary flex gap-3 rounded-lg p-3"
635
- >
636
- <div className="text-fm-primary flex h-8 w-8 items-center justify-center rounded-full bg-gradient-to-br from-blue-500 to-purple-600 text-xs font-medium">
637
- {String.fromCharCode(65 + (i % 26))}
638
- </div>
639
- <div className="flex-1">
640
- <div className="text-fm-primary text-sm">
641
- User {i + 1} performed an action
642
- </div>
643
- <div className="text-fm-secondary text-xs">
644
- {Math.floor(Math.random() * 60)} minutes ago
645
- </div>
646
- </div>
647
- </div>
648
- ))}
649
- </div>
650
- </div>
651
- </ScrollArea>
652
- </div>
653
- </div>
654
- </div>
655
- ),
656
- parameters: {
657
- docs: {
658
- description: {
659
- story:
660
- "ScrollArea components in different sizes from small notification lists to large activity feeds.",
661
- },
662
- },
200
+ const tracks = [
201
+ {
202
+ title: "Neon Pulse",
203
+ artist: "Synthwave Collective",
204
+ duration: "3:42",
205
+ plays: "4.1M",
663
206
  },
664
- }
207
+ {
208
+ title: "Midnight Rain",
209
+ artist: "Luna Beats",
210
+ duration: "4:10",
211
+ plays: "2.8M",
212
+ },
213
+ { title: "Golden Hour", artist: "Solstice", duration: "3:55", plays: "6.3M" },
214
+ {
215
+ title: "City Echoes",
216
+ artist: "Urban Drift",
217
+ duration: "2:58",
218
+ plays: "1.4M",
219
+ },
220
+ {
221
+ title: "Deep Waters",
222
+ artist: "Ocean State",
223
+ duration: "5:12",
224
+ plays: "892K",
225
+ },
226
+ {
227
+ title: "Electric Sky",
228
+ artist: "Volt Lab",
229
+ duration: "3:30",
230
+ plays: "3.7M",
231
+ },
232
+ {
233
+ title: "Static Dreams",
234
+ artist: "Cassette Ghost",
235
+ duration: "4:05",
236
+ plays: "2.1M",
237
+ },
238
+ {
239
+ title: "Sunrise Protocol",
240
+ artist: "Dawn Circuit",
241
+ duration: "3:18",
242
+ plays: "5.0M",
243
+ },
244
+ {
245
+ title: "Phantom Groove",
246
+ artist: "The Frequency",
247
+ duration: "4:48",
248
+ plays: "1.6M",
249
+ },
250
+ {
251
+ title: "Quiet Storm",
252
+ artist: "Ember Tone",
253
+ duration: "3:22",
254
+ plays: "3.2M",
255
+ },
256
+ ]
257
+
258
+ const messages = [
259
+ {
260
+ user: "Mia",
261
+ avatar: "M",
262
+ text: "Just dropped a new EP — check it out!",
263
+ time: "2m ago",
264
+ self: false,
265
+ },
266
+ {
267
+ user: "You",
268
+ avatar: "Y",
269
+ text: "Sounds amazing, already on repeat.",
270
+ time: "1m ago",
271
+ self: true,
272
+ },
273
+ {
274
+ user: "Mia",
275
+ avatar: "M",
276
+ text: "Thanks! Recorded it all in one weekend.",
277
+ time: "1m ago",
278
+ self: false,
279
+ },
280
+ {
281
+ user: "Kai",
282
+ avatar: "K",
283
+ text: "The production on track 3 is incredible.",
284
+ time: "45s ago",
285
+ self: false,
286
+ },
287
+ {
288
+ user: "You",
289
+ avatar: "Y",
290
+ text: "Agreed. The bass line hits hard.",
291
+ time: "30s ago",
292
+ self: true,
293
+ },
294
+ {
295
+ user: "Mia",
296
+ avatar: "M",
297
+ text: "I'll share the stems if you want to remix.",
298
+ time: "20s ago",
299
+ self: false,
300
+ },
301
+ {
302
+ user: "Kai",
303
+ avatar: "K",
304
+ text: "Yes please! Would love to flip it.",
305
+ time: "10s ago",
306
+ self: false,
307
+ },
308
+ {
309
+ user: "You",
310
+ avatar: "Y",
311
+ text: "Count me in too.",
312
+ time: "just now",
313
+ self: true,
314
+ },
315
+ ]
316
+
317
+ const settingsSections = [
318
+ {
319
+ section: "Playback",
320
+ items: [
321
+ "Audio quality",
322
+ "Crossfade duration",
323
+ "Equalizer presets",
324
+ "Volume normalisation",
325
+ ],
326
+ },
327
+ {
328
+ section: "Downloads",
329
+ items: [
330
+ "Download quality",
331
+ "Storage location",
332
+ "Auto-download new releases",
333
+ "Cache size limit",
334
+ ],
335
+ },
336
+ {
337
+ section: "Notifications",
338
+ items: [
339
+ "New release alerts",
340
+ "Friend activity",
341
+ "Podcast updates",
342
+ "Weekly digest",
343
+ ],
344
+ },
345
+ {
346
+ section: "Privacy",
347
+ items: [
348
+ "Listening history",
349
+ "Public profile",
350
+ "Activity status",
351
+ "Data sharing",
352
+ ],
353
+ },
354
+ ]
665
355
 
666
- // 5. Real World Examples
667
- export const RealWorldExamples: Story = {
356
+ export const UseCases: Story = {
668
357
  render: () => (
669
- <div className="space-y-8">
670
- <div className="text-center">
671
- <h3 className="text-fm-primary mb-2 font-medium">
672
- Real World Examples
673
- </h3>
674
- <p className="text-fm-secondary text-sm">
675
- Common use cases for scrollable areas in applications
676
- </p>
358
+ <div className="mx-auto max-w-3xl space-y-8 p-8">
359
+ {/* Track list */}
360
+ <div>
361
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md mb-4 font-medium">
362
+ Scrollable Track List
363
+ </h4>
364
+ <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-72 rounded-xl border">
365
+ <div className="p-2">
366
+ {tracks.map((track, i) => (
367
+ <div
368
+ key={i}
369
+ className="hover:bg-fm-surface-primary flex items-center gap-4 rounded-lg px-3 py-2.5 transition-colors"
370
+ >
371
+ <span className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm w-5 text-right">
372
+ {i + 1}
373
+ </span>
374
+ <div className="bg-fm-surface-tertiary flex h-9 w-9 flex-none items-center justify-center rounded-md">
375
+ <span className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold">
376
+
377
+ </span>
378
+ </div>
379
+ <div className="min-w-0 flex-1">
380
+ <p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm truncate font-medium">
381
+ {track.title}
382
+ </p>
383
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm truncate">
384
+ {track.artist}
385
+ </p>
386
+ </div>
387
+ <span className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm hidden sm:block">
388
+ {track.plays}
389
+ </span>
390
+ <span className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm">
391
+ {track.duration}
392
+ </span>
393
+ </div>
394
+ ))}
395
+ </div>
396
+ </ScrollArea>
677
397
  </div>
678
398
 
679
- <div className="grid grid-cols-1 gap-6 lg:grid-cols-2">
680
- {/* Chat Messages */}
681
- <div className="space-y-2">
682
- <h4 className="text-fm-secondary text-sm font-medium">
683
- Chat Messages
684
- </h4>
685
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-80 w-full rounded-lg border">
686
- <div className="space-y-4 p-4">
687
- {[
688
- {
689
- user: "Alice",
690
- message: "Hey everyone! How's the project going?",
691
- time: "10:30",
692
- self: false,
693
- },
694
- {
695
- user: "You",
696
- message:
697
- "Going well! Just finished the new component library.",
698
- time: "10:32",
699
- self: true,
700
- },
701
- {
702
- user: "Bob",
703
- message: "That's awesome! Can't wait to try it out.",
704
- time: "10:33",
705
- self: false,
706
- },
707
- {
708
- user: "Alice",
709
- message: "Same here! Are there any examples we can look at?",
710
- time: "10:35",
711
- self: false,
712
- },
713
- {
714
- user: "You",
715
- message:
716
- "Yes! I've created a Storybook with all the components and examples.",
717
- time: "10:36",
718
- self: true,
719
- },
720
- {
721
- user: "Carol",
722
- message:
723
- "Perfect timing! I was just about to ask about documentation.",
724
- time: "10:38",
725
- self: false,
726
- },
727
- {
728
- user: "Bob",
729
- message: "The dark theme looks really good btw 👍",
730
- time: "10:40",
731
- self: false,
732
- },
733
- {
734
- user: "You",
735
- message:
736
- "Thanks! We spent a lot of time getting the frosted glass effects right.",
737
- time: "10:41",
738
- self: true,
739
- },
740
- {
741
- user: "Alice",
742
- message:
743
- "It really shows! The attention to detail is impressive.",
744
- time: "10:43",
745
- self: false,
746
- },
747
- {
748
- user: "Carol",
749
- message: "Should we schedule a demo session for the team?",
750
- time: "10:45",
751
- self: false,
752
- },
753
- {
754
- user: "You",
755
- message: "Great idea! How about tomorrow at 2 PM?",
756
- time: "10:46",
757
- self: true,
758
- },
759
- {
760
- user: "Bob",
761
- message: "Works for me! I'll send out calendar invites.",
762
- time: "10:47",
763
- self: false,
764
- },
765
- ].map((msg, i) => (
399
+ {/* Message thread */}
400
+ <div>
401
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md mb-4 font-medium">
402
+ Message Thread
403
+ </h4>
404
+ <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-64 rounded-xl border">
405
+ <div className="flex flex-col gap-3 p-4">
406
+ {messages.map((msg, i) => (
407
+ <div
408
+ key={i}
409
+ className={`flex items-end gap-2 ${msg.self ? "flex-row-reverse" : "flex-row"}`}
410
+ >
411
+ <div className="bg-fm-surface-tertiary flex h-7 w-7 flex-none items-center justify-center rounded-full">
412
+ <span className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold">
413
+ {msg.avatar}
414
+ </span>
415
+ </div>
766
416
  <div
767
- key={i}
768
- className={`flex ${msg.self ? "justify-end" : "justify-start"}`}
417
+ className={`max-w-[72%] space-y-1 ${msg.self ? "items-end" : "items-start"} flex flex-col`}
769
418
  >
770
419
  <div
771
- className={`max-w-xs rounded-lg p-3 ${
420
+ className={`rounded-2xl px-3 py-2 ${
772
421
  msg.self
773
- ? "bg-fm-surface-info text-fm-surface-primary"
774
- : "bg-fm-surface-secondary text-fm-primary"
422
+ ? "bg-fm-surface-info-sec"
423
+ : "bg-fm-surface-primary border-fm-divider-secondary border"
775
424
  }`}
776
425
  >
777
- {!msg.self && (
778
- <div className="text-fm-secondary mb-1 text-xs font-medium">
779
- {msg.user}
780
- </div>
781
- )}
782
- <div className="text-sm">{msg.message}</div>
783
- <div
784
- className={`mt-1 text-xs ${
785
- msg.self ? "text-fm-info-sec" : "text-fm-secondary"
786
- }`}
787
- >
788
- {msg.time}
789
- </div>
426
+ <p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
427
+ {msg.text}
428
+ </p>
790
429
  </div>
430
+ <p className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm px-1">
431
+ {msg.time}
432
+ </p>
791
433
  </div>
792
- ))}
793
- </div>
794
- </ScrollArea>
795
- </div>
796
-
797
- {/* File Explorer */}
798
- <div className="space-y-2">
799
- <h4 className="text-fm-secondary text-sm font-medium">
800
- File Explorer
801
- </h4>
802
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-80 w-full rounded-lg border">
803
- <div className="text-fm-primary p-2">
804
- {[
805
- {
806
- name: "📁 Documents",
807
- type: "folder",
808
- size: "",
809
- modified: "Today",
810
- },
811
- {
812
- name: "📁 Images",
813
- type: "folder",
814
- size: "",
815
- modified: "Yesterday",
816
- },
817
- {
818
- name: "📁 Projects",
819
- type: "folder",
820
- size: "",
821
- modified: "2 days ago",
822
- },
823
- {
824
- name: "📄 README.md",
825
- type: "file",
826
- size: "2.1 KB",
827
- modified: "Today",
828
- },
829
- {
830
- name: "📄 package.json",
831
- type: "file",
832
- size: "1.8 KB",
833
- modified: "Today",
834
- },
835
- {
836
- name: "🖼️ hero-image.jpg",
837
- type: "file",
838
- size: "245 KB",
839
- modified: "Yesterday",
840
- },
841
- {
842
- name: "📄 index.html",
843
- type: "file",
844
- size: "3.2 KB",
845
- modified: "2 days ago",
846
- },
847
- {
848
- name: "🎨 styles.css",
849
- type: "file",
850
- size: "12.5 KB",
851
- modified: "Today",
852
- },
853
- {
854
- name: "⚡ app.js",
855
- type: "file",
856
- size: "8.7 KB",
857
- modified: "Today",
858
- },
859
- {
860
- name: "📄 config.json",
861
- type: "file",
862
- size: "892 B",
863
- modified: "3 days ago",
864
- },
865
- {
866
- name: "🖼️ logo.svg",
867
- type: "file",
868
- size: "3.4 KB",
869
- modified: "Yesterday",
870
- },
871
- {
872
- name: "📄 .gitignore",
873
- type: "file",
874
- size: "156 B",
875
- modified: "5 days ago",
876
- },
877
- {
878
- name: "📁 node_modules",
879
- type: "folder",
880
- size: "",
881
- modified: "Today",
882
- },
883
- {
884
- name: "📄 tsconfig.json",
885
- type: "file",
886
- size: "654 B",
887
- modified: "Yesterday",
888
- },
889
- {
890
- name: "🔧 webpack.config.js",
891
- type: "file",
892
- size: "2.9 KB",
893
- modified: "3 days ago",
894
- },
895
- ].map((item, i) => (
896
- <div
897
- key={i}
898
- className="hover:bg-fm-surface-secondary flex cursor-pointer items-center justify-between rounded p-2"
899
- >
900
- <div className="flex min-w-0 flex-1 items-center gap-2">
901
- <span className="text-sm">{item.name}</span>
902
- </div>
903
- <div className="text-fm-secondary flex items-center gap-4 text-xs">
904
- <span className="w-12 text-right">{item.size}</span>
905
- <span className="w-20 text-right">{item.modified}</span>
906
- </div>
907
- </div>
908
- ))}
909
- </div>
910
- </ScrollArea>
911
- </div>
912
-
913
- {/* Code Editor Sidebar */}
914
- <div className="space-y-2">
915
- <h4 className="text-fm-secondary text-sm font-medium">
916
- Code Editor Sidebar
917
- </h4>
918
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-80 w-full rounded-lg border">
919
- <div className="p-2">
920
- <div className="space-y-1">
921
- <div className="text-fm-primary p-2 text-xs font-medium tracking-wide uppercase">
922
- Explorer
923
- </div>
924
- {[
925
- { name: "src", level: 0, type: "folder", expanded: true },
926
- {
927
- name: "components",
928
- level: 1,
929
- type: "folder",
930
- expanded: true,
931
- },
932
- { name: "Button.tsx", level: 2, type: "file" },
933
- { name: "Button.stories.tsx", level: 2, type: "file" },
934
- { name: "Avatar.tsx", level: 2, type: "file" },
935
- { name: "Avatar.stories.tsx", level: 2, type: "file" },
936
- { name: "ScrollArea.tsx", level: 2, type: "file" },
937
- { name: "hooks", level: 1, type: "folder", expanded: false },
938
- { name: "utils", level: 1, type: "folder", expanded: true },
939
- { name: "cn.ts", level: 2, type: "file" },
940
- { name: "types.ts", level: 2, type: "file" },
941
- { name: "index.ts", level: 1, type: "file" },
942
- { name: "App.tsx", level: 1, type: "file" },
943
- { name: "public", level: 0, type: "folder", expanded: false },
944
- { name: "package.json", level: 0, type: "file" },
945
- { name: "tsconfig.json", level: 0, type: "file" },
946
- { name: "tailwind.config.js", level: 0, type: "file" },
947
- { name: "vite.config.ts", level: 0, type: "file" },
948
- ].map((item, i) => (
949
- <div
950
- key={i}
951
- className="hover:bg-fm-surface-secondary flex cursor-pointer items-center gap-1 rounded p-1 text-sm"
952
- style={{ paddingLeft: `${8 + item.level * 16}px` }}
953
- >
954
- {item.type === "folder" && (
955
- <span className="text-fm-secondary">
956
- {item.expanded ? "📂" : "📁"}
957
- </span>
958
- )}
959
- {item.type === "file" && (
960
- <span className="text-fm-secondary">📄</span>
961
- )}
962
- <span className="text-fm-primary">{item.name}</span>
963
- </div>
964
- ))}
965
434
  </div>
966
- </div>
967
- </ScrollArea>
968
- </div>
969
-
970
- {/* Settings Panel */}
971
- <div className="space-y-2">
972
- <h4 className="text-fm-secondary text-sm font-medium">
973
- Settings Panel
974
- </h4>
975
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-80 w-full rounded-lg border">
976
- <div className="space-y-6 p-4">
977
- {[
978
- {
979
- section: "Appearance",
980
- settings: [
981
- { label: "Theme", value: "Dark", type: "select" },
982
- { label: "Font Size", value: "Medium", type: "select" },
983
- { label: "Animations", value: true, type: "toggle" },
984
- ],
985
- },
986
- {
987
- section: "Behavior",
988
- settings: [
989
- { label: "Auto Save", value: true, type: "toggle" },
990
- {
991
- label: "Smart Suggestions",
992
- value: false,
993
- type: "toggle",
994
- },
995
- {
996
- label: "Keyboard Shortcuts",
997
- value: true,
998
- type: "toggle",
999
- },
1000
- ],
1001
- },
1002
- {
1003
- section: "Privacy",
1004
- settings: [
1005
- { label: "Analytics", value: false, type: "toggle" },
1006
- { label: "Crash Reports", value: true, type: "toggle" },
1007
- { label: "Usage Data", value: false, type: "toggle" },
1008
- ],
1009
- },
1010
- {
1011
- section: "Advanced",
1012
- settings: [
1013
- { label: "Developer Mode", value: false, type: "toggle" },
1014
- {
1015
- label: "Experimental Features",
1016
- value: false,
1017
- type: "toggle",
1018
- },
1019
- { label: "Debug Logging", value: false, type: "toggle" },
1020
- ],
1021
- },
1022
- ].map((group, i) => (
1023
- <div key={i}>
1024
- <h5 className="text-fm-primary mb-3 text-sm font-medium">
1025
- {group.section}
1026
- </h5>
1027
- <div className="space-y-3">
1028
- {group.settings.map((setting, j) => (
1029
- <div
1030
- key={j}
1031
- className="flex items-center justify-between"
1032
- >
1033
- <span className="text-fm-secondary text-sm">
1034
- {setting.label}
1035
- </span>
1036
- {setting.type === "toggle" ? (
1037
- <div
1038
- className={`h-5 w-10 rounded-full p-1 ${
1039
- setting.value
1040
- ? "bg-fm-surface-info"
1041
- : "bg-fm-surface-tertiary"
1042
- }`}
1043
- >
1044
- <div
1045
- className={`bg-fm-surface-primary h-3 w-3 rounded-full transition-transform ${
1046
- setting.value
1047
- ? "translate-x-5"
1048
- : "translate-x-0"
1049
- }`}
1050
- ></div>
1051
- </div>
1052
- ) : (
1053
- <span className="text-fm-secondary text-sm">
1054
- {setting.value}
1055
- </span>
1056
- )}
1057
- </div>
1058
- ))}
1059
- </div>
1060
- </div>
1061
- ))}
1062
- </div>
1063
- </ScrollArea>
1064
- </div>
1065
- </div>
1066
- </div>
1067
- ),
1068
- parameters: {
1069
- docs: {
1070
- description: {
1071
- story:
1072
- "Real-world examples including chat interfaces, file explorers, code editor sidebars, and settings panels demonstrating practical ScrollArea usage.",
1073
- },
1074
- },
1075
- },
1076
- }
1077
-
1078
- // 6. Performance Example
1079
- export const PerformanceExample: Story = {
1080
- render: () => (
1081
- <div className="space-y-8">
1082
- <div className="text-center">
1083
- <h3 className="text-fm-primary mb-2 font-medium">
1084
- Performance Example
1085
- </h3>
1086
- <p className="text-fm-secondary text-sm">
1087
- Large datasets handled efficiently with virtual scrolling simulation
1088
- </p>
1089
- </div>
1090
-
1091
- <div className="space-y-4">
1092
- <div className="text-center">
1093
- <div className="border-fm-divider-secondary bg-fm-surface-secondary inline-block rounded-lg border p-4">
1094
- <h4 className="text-fm-primary mb-2 text-sm font-medium">
1095
- Large Dataset
1096
- </h4>
1097
- <p className="text-fm-secondary text-xs leading-relaxed">
1098
- This example shows 1000+ items in a scrollable area. The
1099
- ScrollArea component handles smooth scrolling even with large
1100
- amounts of content.
1101
- </p>
435
+ ))}
1102
436
  </div>
1103
- </div>
437
+ </ScrollArea>
438
+ </div>
1104
439
 
1105
- <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary mx-auto h-96 w-full max-w-2xl rounded-lg border">
440
+ {/* Settings panel */}
441
+ <div>
442
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md mb-4 font-medium">
443
+ Settings Panel
444
+ </h4>
445
+ <ScrollArea className="border-fm-divider-secondary bg-fm-surface-secondary h-64 w-72 rounded-xl border">
1106
446
  <div className="p-4">
1107
- <h4 className="text-fm-primary mb-4 text-sm leading-none font-medium">
1108
- Large Item List (1000 items)
1109
- </h4>
1110
- <div className="space-y-1">
1111
- {Array.from({ length: 1000 }, (_, i) => (
1112
- <div
1113
- key={i}
1114
- className="bg-fm-surface-secondary hover:bg-fm-surface-tertiary flex items-center justify-between rounded-lg p-3 transition-colors"
1115
- >
1116
- <div className="flex items-center gap-3">
447
+ {settingsSections.map((group) => (
448
+ <div key={group.section} className="mb-5 last:mb-0">
449
+ <p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm mb-2 font-semibold tracking-widest uppercase">
450
+ {group.section}
451
+ </p>
452
+ <div className="space-y-px">
453
+ {group.items.map((item) => (
1117
454
  <div
1118
- className={`text-fm-primary flex h-8 w-8 items-center justify-center rounded-full text-xs font-medium ${
1119
- [
1120
- "bg-blue-500",
1121
- "bg-green-500",
1122
- "bg-purple-500",
1123
- "bg-orange-500",
1124
- ][i % 4]
1125
- }`}
455
+ key={item}
456
+ className="hover:bg-fm-surface-primary flex items-center justify-between rounded-md px-3 py-2 transition-colors"
1126
457
  >
1127
- {i + 1}
1128
- </div>
1129
- <div>
1130
- <div className="text-fm-primary text-sm font-medium">
1131
- Item {i + 1}
1132
- </div>
1133
- <div className="text-fm-secondary text-xs">
1134
- Category:{" "}
1135
- {["Development", "Design", "Marketing", "Sales"][i % 4]}
1136
- </div>
458
+ <p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
459
+ {item}
460
+ </p>
461
+ <span className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm">
462
+
463
+ </span>
1137
464
  </div>
1138
- </div>
1139
- <div className="text-fm-secondary text-xs">
1140
- {new Date(Date.now() - i * 60000).toLocaleTimeString()}
1141
- </div>
465
+ ))}
1142
466
  </div>
1143
- ))}
1144
- </div>
467
+ </div>
468
+ ))}
1145
469
  </div>
1146
470
  </ScrollArea>
1147
471
  </div>
@@ -1151,7 +475,7 @@ export const PerformanceExample: Story = {
1151
475
  docs: {
1152
476
  description: {
1153
477
  story:
1154
- "Performance demonstration with 1000+ items showing how ScrollArea maintains smooth scrolling with large datasets.",
478
+ "Real product-shaped scenarios: a numbered track list with play counts, a chat message thread between collaborators, and a settings panel with categorised preferences — all inside fixed-height scroll regions.",
1155
479
  },
1156
480
  },
1157
481
  },