aural-ui 4.0.1 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +8 -1
  2. package/dist/components/aspect-ratio/AspectRatio.stories.tsx +290 -1228
  3. package/dist/components/avatar/Avatar.stories.tsx +219 -235
  4. package/dist/components/badge/Badge.stories.tsx +379 -116
  5. package/dist/components/banner/Banner.stories.tsx +445 -391
  6. package/dist/components/breadcrumb/Breadcrumb.stories.tsx +453 -199
  7. package/dist/components/button/Button.stories.tsx +585 -230
  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 -636
  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 +530 -867
  16. package/dist/components/dialog/Dialog.stories.tsx +501 -950
  17. package/dist/components/divider/Divider.stories.tsx +264 -527
  18. package/dist/components/dot-loader/DotLoader.stories.tsx +256 -257
  19. package/dist/components/drawer/Drawer.stories.tsx +659 -1023
  20. package/dist/components/dropdown/Dropdown.stories.tsx +643 -1028
  21. package/dist/components/form/Form.stories.tsx +560 -274
  22. package/dist/components/helper-text/HelperText.stories.tsx +199 -200
  23. package/dist/components/hover-card/HoverCard.stories.tsx +318 -1254
  24. package/dist/components/icon-button/IconButton.stories.tsx +837 -194
  25. package/dist/components/if-else/if-else.stories.tsx +370 -83
  26. package/dist/components/input/Input.stories.tsx +436 -368
  27. package/dist/components/label/Label.stories.tsx +156 -154
  28. package/dist/components/list/List.stories.tsx +484 -835
  29. package/dist/components/marquee/Marquee.stories.tsx +356 -712
  30. package/dist/components/otp-inputs/OtpInputs.stories.tsx +352 -422
  31. package/dist/components/overlay/Overlay.stories.tsx +452 -824
  32. package/dist/components/pagination/Pagination.stories.tsx +721 -210
  33. package/dist/components/popover/Popover.stories.tsx +481 -896
  34. package/dist/components/radio/Radio.stories.tsx +432 -124
  35. package/dist/components/resizable/Resizable.stories.tsx +495 -799
  36. package/dist/components/scroll-area/ScrollArea.stories.tsx +383 -1059
  37. package/dist/components/search/Search.stories.tsx +312 -595
  38. package/dist/components/select/Select.stories.tsx +684 -789
  39. package/dist/components/sheet/Sheet.stories.tsx +671 -950
  40. package/dist/components/skelton/Skelton.stories.tsx +230 -764
  41. package/dist/components/slider/Slider.stories.tsx +383 -760
  42. package/dist/components/stepper/Stepper.stories.tsx +371 -514
  43. package/dist/components/switch/Switch.stories.tsx +461 -208
  44. package/dist/components/switch-case/SwitchCase.stories.tsx +367 -188
  45. package/dist/components/table/Table.stories.tsx +770 -916
  46. package/dist/components/tabs/Tabs.stories.tsx +458 -1455
  47. package/dist/components/tag/Tag.stories.tsx +714 -542
  48. package/dist/components/textarea/TextArea.stories.tsx +621 -562
  49. package/dist/components/thumbnail-tags/ThumbnailTags.stories.tsx +228 -154
  50. package/dist/components/toast/Toast.stories.tsx +452 -1339
  51. package/dist/components/toggle/Toggle.stories.tsx +488 -931
  52. package/dist/components/tooltip/Tooltip.stories.tsx +344 -1388
  53. package/dist/components/typography/Typography.stories.tsx +406 -89
  54. package/dist/hooks/use-change-state/UseChangeState.stories.tsx +309 -606
  55. package/dist/hooks/use-previous/UsePrevious.stories.tsx +367 -917
  56. package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +639 -867
  57. package/dist/icons/Icons.stories.tsx +0 -12
  58. package/dist/icons/ai-avatar-icon/AiAvatarIcon.stories.tsx +223 -1060
  59. package/dist/icons/alert-icon/AlertIcon.stories.tsx +106 -968
  60. package/dist/icons/all-icons.tsx +37 -16
  61. package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +137 -1010
  62. package/dist/icons/apple-logo-icon/AppleLogoIcon.stories.tsx +145 -935
  63. package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +132 -1046
  64. package/dist/icons/arrow-corner-up-left-icon/ArrowCornerUpLeftIcon.stories.tsx +134 -986
  65. package/dist/icons/arrow-corner-up-right-icon/ArrowCornerUpRightIcon.stories.tsx +135 -1028
  66. package/dist/icons/arrow-left-icon/ArrowLeftIcon.stories.tsx +133 -971
  67. package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +145 -1123
  68. package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +143 -1252
  69. package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +123 -632
  70. package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +141 -1223
  71. package/dist/icons/backward-ten-seconds-icon/BackwardTenSecondsIcon.stories.tsx +164 -1018
  72. package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +121 -1236
  73. package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +121 -1213
  74. package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +116 -893
  75. package/dist/icons/camera-icon/CameraIcon.stories.tsx +109 -1254
  76. package/dist/icons/capital-a-letter-icon/CapitalALetterIcon.stories.tsx +114 -975
  77. package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +157 -994
  78. package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +160 -992
  79. package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +140 -970
  80. package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +126 -993
  81. package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +144 -987
  82. package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +141 -1007
  83. package/dist/icons/circle-tick-icon/CircleTickIcon.stories.tsx +147 -1187
  84. package/dist/icons/circular-play-icon/CircularPlayIcon.stories.tsx +110 -476
  85. package/dist/icons/coin-icon/CoinIcon.stories.tsx +120 -1364
  86. package/dist/icons/coin-toons-icon/CoinToonsIcon.stories.tsx +113 -1360
  87. package/dist/icons/column-wide-add-icon/ColumnWideAddIcon.stories.tsx +111 -942
  88. package/dist/icons/command-icon/CommandIcon.stories.tsx +124 -1087
  89. package/dist/icons/copy-icon/CopyIcon.stories.tsx +119 -996
  90. package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +144 -1046
  91. package/dist/icons/cross-icon/CrossIcon.stories.tsx +136 -999
  92. package/dist/icons/download-icon/DownloadIcon.stories.tsx +123 -857
  93. package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +121 -1080
  94. package/dist/icons/email-icon/EmailIcon.stories.tsx +112 -979
  95. package/dist/icons/expand-icon/ExpandIcon.stories.tsx +109 -1146
  96. package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +141 -1068
  97. package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +140 -1081
  98. package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +124 -1050
  99. package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +123 -1091
  100. package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +122 -633
  101. package/dist/icons/filter-bar-row-icon/FilterBarRowIcon.stories.tsx +116 -1087
  102. package/dist/icons/forward-ten-seconds-icon/ForwardTenSecondsIcon.stories.tsx +166 -1020
  103. package/dist/icons/git-branch-icon/GitBranchIcon.stories.tsx +112 -1182
  104. package/dist/icons/git-fork-icon/GitForkIcon.stories.tsx +112 -1155
  105. package/dist/icons/globe-icon/GlobeIcon.stories.tsx +127 -325
  106. package/dist/icons/google-logo-icon/GoogleLogoIcon.stories.tsx +142 -985
  107. package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +116 -1217
  108. package/dist/icons/head-icon/HeadIcon.stories.tsx +108 -953
  109. package/dist/icons/heart-icon/HeartIcon.stories.tsx +117 -1060
  110. package/dist/icons/image-avatar-sparkle-icon/ImageAvatarSparkleIcon.stories.tsx +116 -716
  111. package/dist/icons/image-icon/ImageIcon.stories.tsx +102 -1164
  112. package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +108 -1233
  113. package/dist/icons/import-left-arrow-folder-icon/ImportLeftArrowFolderIcon.stories.tsx +133 -1289
  114. package/dist/icons/indian-flag-icon/IndianFlagIcon.stories.tsx +155 -1012
  115. package/dist/icons/instagram-icon/InstagramIcon.stories.tsx +158 -1438
  116. package/dist/icons/layout-column-icon/LayoutColumnIcon.stories.tsx +121 -1011
  117. package/dist/icons/layout-left-icon/LayoutLeftIcon.stories.tsx +116 -981
  118. package/dist/icons/layout-right-icon/LayoutRightIcon.stories.tsx +116 -979
  119. package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +105 -1252
  120. package/dist/icons/linked-in-icon/LinkedInIcon.stories.tsx +151 -1554
  121. package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +107 -1227
  122. package/dist/icons/magic-edit-icon/MagicEditIcon.stories.tsx +116 -707
  123. package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +119 -1226
  124. package/dist/icons/message-icon/MessageIcon.stories.tsx +111 -557
  125. package/dist/icons/minimize-icon/MinimizeIcon.stories.tsx +112 -1198
  126. package/dist/icons/moon-icon/MoonIcon.stories.tsx +117 -557
  127. package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +106 -1235
  128. package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +112 -1185
  129. package/dist/icons/musical-note-icon/MusicalNoteIcon.stories.tsx +116 -1012
  130. package/dist/icons/notepad-icon/NotepadIcon.stories.tsx +108 -1137
  131. package/dist/icons/notes-icon/NotesIcon.stories.tsx +116 -1138
  132. package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +106 -1146
  133. package/dist/icons/page-text-icon/PageTextIcon.stories.tsx +119 -719
  134. package/dist/icons/paint-roll-icon/PaintRollIcon.stories.tsx +110 -999
  135. package/dist/icons/paper-plane-icon/PaperPlaneIcon.stories.tsx +109 -912
  136. package/dist/icons/pause-icon/PauseIcon.stories.tsx +110 -1041
  137. package/dist/icons/pencil-icon/PencilIcon.stories.tsx +112 -1109
  138. package/dist/icons/phone-icon/PhoneIcon.stories.tsx +112 -1023
  139. package/dist/icons/plus-icon/PlusIcon.stories.tsx +103 -1132
  140. package/dist/icons/pocket-studio-icon/PocketStudioIcon.stories.tsx +104 -870
  141. package/dist/icons/scroll-down-icon/ScrollDownIcon.stories.tsx +99 -476
  142. package/dist/icons/search-icon/SearchIcon.stories.tsx +108 -1161
  143. package/dist/icons/setting-icon/SettingIcon.stories.tsx +104 -1009
  144. package/dist/icons/share-icon/ShareIcon.stories.tsx +117 -1064
  145. package/dist/icons/shield-icon/ShieldIcon.stories.tsx +114 -974
  146. package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +134 -1160
  147. package/dist/icons/skip-backward-icon/SkipBackwardIcon.stories.tsx +169 -1017
  148. package/dist/icons/skip-forward-icon/SkipForwardIcon.stories.tsx +161 -1016
  149. package/dist/icons/sparkles-soft-icon/SparklesSoftIcon.stories.tsx +102 -1001
  150. package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +155 -593
  151. package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +155 -608
  152. package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +142 -712
  153. package/dist/icons/star-icon/StarIcon.stories.tsx +120 -946
  154. package/dist/icons/store-coin-icon/StoreCoinIcon.stories.tsx +109 -1013
  155. package/dist/icons/suggestion-icon/SuggestionIcon.stories.tsx +113 -891
  156. package/dist/icons/sun-icon/SunIcon.stories.tsx +117 -864
  157. package/dist/icons/text-color-icon/TextColorIcon.stories.tsx +113 -989
  158. package/dist/icons/text-indicator-icon/TextIndicatorIcon.stories.tsx +120 -1027
  159. package/dist/icons/threads-icon/ThreadsIcon.stories.tsx +153 -1476
  160. package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +143 -1187
  161. package/dist/icons/tick-icon/TickIcon.stories.tsx +142 -1322
  162. package/dist/icons/trash-icon/TrashIcon.stories.tsx +105 -970
  163. package/dist/icons/twitter-x-icon/TwitterXIcon.stories.tsx +154 -1457
  164. package/dist/icons/upload-icon/UploadIcon.stories.tsx +112 -930
  165. package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +115 -1019
  166. package/dist/icons/video-play-list-icon/VideoPlaylistIcon.stories.tsx +122 -1092
  167. package/dist/icons/voice-playing-icon/VoicePlayingIcon.stories.tsx +120 -1401
  168. package/dist/icons/volume-full-icon/VolumeFullIcon.stories.tsx +107 -1212
  169. package/dist/icons/volume-half-icon/VolumeHalfIcon.stories.tsx +109 -1122
  170. package/dist/icons/volume-off-icon/VolumeOffIcon.stories.tsx +112 -1124
  171. package/dist/icons/warning-icon/WarningIcon.stories.tsx +119 -1083
  172. package/dist/icons/youtube-icon/YoutubeIcon.stories.tsx +158 -983
  173. package/dist/index.cjs +90 -90
  174. package/dist/index.js +90 -90
  175. package/package.json +8 -3
@@ -1,15 +1,9 @@
1
1
  import React from "react"
2
2
  import { Button } from "@components/button"
3
- import {
4
- AlertIcon,
5
- EditBigIcon,
6
- FileChartIcon,
7
- PlusIcon,
8
- SearchIcon,
9
- TickCircleIcon,
10
- } from "@icons/index"
11
3
  import type { Meta, StoryObj } from "@storybook/react-vite"
12
4
 
5
+ import { AuralComponentDocsPage } from "src/ui/story-spec/components/component-story-docs-page"
6
+
13
7
  import { HoverCard, HoverCardContent, HoverCardTrigger } from "."
14
8
 
15
9
  const meta: Meta<typeof HoverCard> = {
@@ -17,151 +11,40 @@ const meta: Meta<typeof HoverCard> = {
17
11
  component: HoverCard,
18
12
  parameters: {
19
13
  layout: "centered",
20
- backgrounds: {
21
- default: "dark",
22
- values: [
23
- { name: "dark", value: "#0a0a0a" },
24
- { name: "light", value: "#ffffff" },
25
- ],
26
- },
27
14
  docs: {
28
15
  description: {
29
- component: `
30
- # HoverCard Component
31
-
32
- A rich contextual preview component built on top of Radix UI's HoverCard primitive, providing detailed information that appears on hover with a slight delay.
33
-
34
- ## Components
35
-
36
- ### Core Components
37
- - **HoverCard**: Root component that manages the hover state and timing
38
- - **HoverCardTrigger**: The element that triggers the hover card display
39
- - **HoverCardContent**: The content container with positioning and styling
40
-
41
- ## Features
42
-
43
- - **Smart Positioning**: Automatically positions to stay within viewport
44
- - **Hover Delay**: Configurable delay before showing content
45
- - **Rich Content**: Supports complex layouts with images, text, and actions
46
- - **Keyboard Accessible**: Full keyboard navigation support
47
- - **Portal Rendering**: Renders in a portal to avoid z-index issues
48
- - **Responsive**: Adapts to different screen sizes
49
- - **Design System**: Integrated with design tokens and themes
50
- - **Animation**: Smooth enter/exit animations
51
-
52
- ## Usage Examples
53
-
54
- ### Basic HoverCard
55
- \`\`\`tsx
56
- <HoverCard>
57
- <HoverCardTrigger>
58
- <Button variant="link">Hover me</Button>
59
- </HoverCardTrigger>
60
- <HoverCardContent>
61
- <div className="space-y-2">
62
- <h4 className="text-sm font-semibold">Quick Info</h4>
63
- <p className="text-sm text-muted-foreground">
64
- This is a hover card with basic information.
65
- </p>
66
- </div>
67
- </HoverCardContent>
68
- </HoverCard>
69
- \`\`\`
70
-
71
- ### User Profile Card
72
- \`\`\`tsx
73
- <HoverCard>
74
- <HoverCardTrigger>
75
- <Button variant="link">@username</Button>
76
- </HoverCardTrigger>
77
- <HoverCardContent className="w-80">
78
- <div className="flex justify-between space-x-4">
79
- <div className="space-y-1">
80
- <h4 className="text-sm font-semibold">@username</h4>
81
- <p className="text-sm">
82
- Full Name - Software Developer
83
- </p>
84
- <div className="flex items-center pt-2">
85
- <CalendarIcon className="mr-2 h-4 w-4" />
86
- <span className="text-xs text-muted-foreground">
87
- Joined December 2021
88
- </span>
89
- </div>
90
- </div>
91
- </div>
92
- </HoverCardContent>
93
- </HoverCard>
94
- \`\`\`
95
-
96
- ### Product Preview
97
- \`\`\`tsx
98
- <HoverCard>
99
- <HoverCardTrigger>
100
- <img src="product.jpg" alt="Product" />
101
- </HoverCardTrigger>
102
- <HoverCardContent>
103
- <div className="space-y-3">
104
- <div>
105
- <h4 className="font-semibold">Product Name</h4>
106
- <p className="text-sm text-muted-foreground">
107
- Product description with key features
108
- </p>
109
- </div>
110
- <div className="flex items-center justify-between">
111
- <span className="text-lg font-bold">$99.99</span>
112
- <Button size="sm">Add to Cart</Button>
113
- </div>
114
- </div>
115
- </HoverCardContent>
116
- </HoverCard>
117
- \`\`\`
118
-
119
- ## Positioning
120
-
121
- The hover card automatically positions itself:
122
- - **side**: "top" | "right" | "bottom" | "left"
123
- - **align**: "start" | "center" | "end"
124
- - **sideOffset**: Distance from the trigger (default: 4px)
125
- - **alignOffset**: Offset along the alignment axis
126
-
127
- ## Accessibility
128
-
129
- - **ARIA Support**: Proper ARIA attributes for screen readers
130
- - **Keyboard Navigation**: Accessible via keyboard focus
131
- - **Focus Management**: Proper focus handling
132
- - **Delayed Appearance**: Prevents accidental triggers
133
- - **Screen Reader**: Content is announced when card appears
134
-
135
- ## Design Tokens
136
-
137
- - \`bg-fm-surface-frosted/20\`: Translucent background
138
- - \`text-fm-primary\`: Primary text color
139
- - \`rounded-md\`: Border radius
140
- - \`border\`: Border styling
141
- - \`shadow-md\`: Drop shadow
142
- - \`p-4\`: Default padding
143
-
144
- ## Best Practices
145
-
146
- - Use for supplementary information, not critical content
147
- - Keep content concise and scannable
148
- - Provide clear visual hierarchy
149
- - Test with keyboard navigation
150
- - Consider mobile users (hover cards don't work on touch)
151
- - Don't nest interactive elements unnecessarily
152
- `,
16
+ component:
17
+ "A rich contextual preview that appears on hover after a configurable delay. Composed of HoverCard (root state manager), HoverCardTrigger (the hovered element), and HoverCardContent (the floating panel). Supports align, sideOffset, openDelay, and closeDelay props.",
153
18
  },
19
+ page: () => (
20
+ <AuralComponentDocsPage
21
+ features={[
22
+ {
23
+ title: "Hover Preview",
24
+ description: "Configurable open delay",
25
+ },
26
+ {
27
+ title: "Compound Parts",
28
+ description: "Trigger and content",
29
+ },
30
+ {
31
+ title: "Alignment Control",
32
+ description: "align and sideOffset",
33
+ },
34
+ ]}
35
+ />
36
+ ),
154
37
  },
155
38
  },
156
39
  tags: ["autodocs"],
157
40
  argTypes: {
158
41
  openDelay: {
159
42
  control: { type: "number", min: 0, max: 2000, step: 100 },
160
- description: "Delay before hover card opens (ms)",
43
+ description: "Delay in ms before the card opens",
161
44
  },
162
45
  closeDelay: {
163
46
  control: { type: "number", min: 0, max: 2000, step: 100 },
164
- description: "Delay before hover card closes (ms)",
47
+ description: "Delay in ms before the card closes",
165
48
  },
166
49
  },
167
50
  }
@@ -169,1193 +52,374 @@ The hover card automatically positions itself:
169
52
  export default meta
170
53
  type Story = StoryObj<typeof HoverCard>
171
54
 
172
- // 1. Basic HoverCard
173
- export const Basic: Story = {
174
- render: () => (
175
- <div className="p-8">
176
- <HoverCard>
177
- <HoverCardTrigger asChild>
178
- <Button variant="text">Hover for more info</Button>
179
- </HoverCardTrigger>
180
- <HoverCardContent>
181
- <div className="space-y-2">
182
- <h4 className="text-fm-primary text-sm font-semibold">
183
- Quick Information
184
- </h4>
185
- <p className="text-fm-secondary text-sm">
186
- This is a basic hover card that provides additional context when
187
- you hover over the trigger element.
188
- </p>
189
- </div>
190
- </HoverCardContent>
191
- </HoverCard>
192
- </div>
193
- ),
194
- parameters: {
195
- docs: {
196
- description: {
197
- story:
198
- "A simple hover card that appears when hovering over a trigger element.",
199
- },
200
- },
201
- },
202
- }
203
-
204
- // 2. User Profile Cards
205
- export const UserProfiles: Story = {
206
- render: () => (
207
- <div className="space-y-8 p-8">
208
- <h3 className="text-fm-primary text-center text-lg font-medium">
209
- User Profile Cards
210
- </h3>
211
-
212
- <div className="grid grid-cols-1 gap-6 lg:grid-cols-2">
213
- {/* Basic Profile */}
214
- <div className="space-y-4">
215
- <h4 className="text-fm-secondary text-sm font-medium">
216
- Basic Profile
217
- </h4>
218
- <div className="text-center">
219
- <HoverCard>
220
- <HoverCardTrigger asChild>
221
- <Button variant="text" className="text-fm-info">
222
- @johndoe
223
- </Button>
224
- </HoverCardTrigger>
225
- <HoverCardContent className="w-80">
226
- <div className="flex space-x-4">
227
- <div className="flex h-12 w-12 items-center justify-center rounded-full bg-gradient-to-br from-blue-500 to-purple-600">
228
- <span className="text-fm-primary font-semibold">JD</span>
229
- </div>
230
- <div className="flex-1 space-y-1">
231
- <h4 className="text-fm-primary text-sm font-semibold">
232
- John Doe
233
- </h4>
234
- <p className="text-fm-secondary text-sm">
235
- Senior Software Engineer
236
- </p>
237
- <p className="text-fm-tertiary text-xs">
238
- Building amazing user experiences with React and
239
- TypeScript
240
- </p>
241
- <div className="text-fm-secondary flex items-center gap-4 pt-2 text-xs">
242
- <span>👥 1.2k followers</span>
243
- <span>📍 San Francisco</span>
244
- </div>
245
- </div>
246
- </div>
247
- </HoverCardContent>
248
- </HoverCard>
249
- </div>
250
- </div>
251
-
252
- {/* Detailed Profile */}
253
- <div className="space-y-4">
254
- <h4 className="text-fm-secondary text-sm font-medium">
255
- Detailed Profile
256
- </h4>
257
- <div className="text-center">
258
- <HoverCard>
259
- <HoverCardTrigger asChild>
260
- <Button variant="text" className="text-fm-positive">
261
- @sarahsmith
262
- </Button>
263
- </HoverCardTrigger>
264
- <HoverCardContent className="w-96">
265
- <div className="space-y-3">
266
- <div className="flex space-x-4">
267
- <div className="flex h-16 w-16 items-center justify-center rounded-full bg-gradient-to-br from-green-500 to-teal-600">
268
- <span className="text-fm-primary text-lg font-semibold">
269
- SS
270
- </span>
271
- </div>
272
- <div className="flex-1 space-y-1">
273
- <h4 className="text-fm-primary text-base font-semibold">
274
- Sarah Smith
275
- </h4>
276
- <p className="text-fm-secondary text-sm">
277
- UX Designer & Product Manager
278
- </p>
279
- <div className="text-fm-secondary flex items-center gap-2 text-xs">
280
- <TickCircleIcon className="h-3 w-3" />
281
- <span>Verified Account</span>
282
- </div>
283
- </div>
284
- </div>
285
-
286
- <p className="text-fm-secondary text-sm">
287
- Passionate about creating intuitive digital experiences.
288
- Currently working on design systems and user research.
289
- </p>
290
-
291
- <div className="grid grid-cols-3 gap-4 pt-2 text-center">
292
- <div>
293
- <div className="text-fm-primary text-lg font-semibold">
294
- 248
295
- </div>
296
- <div className="text-fm-secondary text-xs">Posts</div>
297
- </div>
298
- <div>
299
- <div className="text-fm-primary text-lg font-semibold">
300
- 2.8k
301
- </div>
302
- <div className="text-fm-secondary text-xs">Followers</div>
303
- </div>
304
- <div>
305
- <div className="text-fm-primary text-lg font-semibold">
306
- 892
307
- </div>
308
- <div className="text-fm-secondary text-xs">Following</div>
309
- </div>
310
- </div>
55
+ // ─── Parts ───────────────────────────────────────────────────────────────────
311
56
 
312
- <div className="flex gap-2 pt-2">
313
- <Button size="sm" className="flex-1">
314
- Follow
315
- </Button>
316
- <Button size="sm" variant="outline">
317
- Message
318
- </Button>
319
- </div>
320
- </div>
321
- </HoverCardContent>
322
- </HoverCard>
323
- </div>
324
- </div>
325
- </div>
326
- </div>
327
- ),
57
+ export const Parts: Story = {
328
58
  parameters: {
329
59
  docs: {
330
60
  description: {
331
61
  story:
332
- "User profile cards showing basic and detailed user information with actions.",
62
+ "Each sub-component shown with its role. HoverCardTrigger wraps the hovered element; HoverCardContent hosts the floating preview panel.",
333
63
  },
334
64
  },
335
65
  },
336
- }
337
-
338
- // 3. Product Previews
339
- export const ProductPreviews: Story = {
340
66
  render: () => (
341
- <div className="space-y-8 p-8">
342
- <h3 className="text-fm-primary text-center text-lg font-medium">
343
- Product Previews
344
- </h3>
345
-
346
- <div className="grid grid-cols-1 gap-8 lg:grid-cols-3">
347
- {/* Simple Product */}
348
- <div className="space-y-4">
349
- <h4 className="text-fm-secondary text-sm font-medium">
350
- Simple Product
351
- </h4>
352
- <div className="text-center">
353
- <HoverCard>
354
- <HoverCardTrigger asChild>
355
- <div className="border-fm-divider-secondary bg-fm-surface-secondary hover:bg-fm-surface-frosted/15 hover:border-fm-divider-contrast cursor-pointer rounded-lg border p-4 transition-colors">
356
- <div className="mx-auto mb-2 flex h-20 w-20 items-center justify-center rounded-lg bg-gradient-to-br from-purple-500 to-pink-600">
357
- <FileChartIcon className="text-fm-primary h-8 w-8" />
358
- </div>
359
- <p className="text-fm-primary text-sm">Analytics Pro</p>
360
- </div>
361
- </HoverCardTrigger>
362
- <HoverCardContent>
363
- <div className="space-y-3">
364
- <div>
365
- <h4 className="text-fm-primary font-semibold">
366
- Analytics Pro
367
- </h4>
368
- <p className="text-fm-secondary text-sm">
369
- Advanced analytics dashboard with real-time insights
370
- </p>
371
- </div>
372
- <div className="flex items-center justify-between">
373
- <span className="text-fm-primary text-lg font-bold">
374
- $29/mo
375
- </span>
376
- <Button size="sm">
377
- <PlusIcon className="mr-1 h-3 w-3" />
378
- Add
379
- </Button>
380
- </div>
381
- </div>
382
- </HoverCardContent>
383
- </HoverCard>
384
- </div>
385
- </div>
386
-
387
- {/* Detailed Product */}
388
- <div className="space-y-4">
389
- <h4 className="text-fm-secondary text-sm font-medium">
390
- Detailed Product
391
- </h4>
392
- <div className="text-center">
393
- <HoverCard>
394
- <HoverCardTrigger asChild>
395
- <div className="border-fm-divider-secondary bg-fm-surface-secondary hover:bg-fm-surface-frosted/15 hover:border-fm-divider-contrast cursor-pointer rounded-lg border p-4 transition-colors">
396
- <div className="mx-auto mb-2 flex h-20 w-20 items-center justify-center rounded-lg bg-gradient-to-br from-blue-500 to-cyan-600">
397
- <SearchIcon className="text-fm-primary h-8 w-8" />
398
- </div>
399
- <p className="text-fm-primary text-sm">Search Engine</p>
400
- </div>
401
- </HoverCardTrigger>
402
- <HoverCardContent className="w-80">
403
- <div className="space-y-4">
404
- <div className="flex space-x-3">
405
- <div className="flex h-16 w-16 flex-shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-blue-500 to-cyan-600">
406
- <SearchIcon className="text-fm-primary h-8 w-8" />
407
- </div>
408
- <div className="space-y-1">
409
- <h4 className="text-fm-primary font-semibold">
410
- Advanced Search Engine
411
- </h4>
412
- <p className="text-fm-secondary text-sm">
413
- AI-powered search with natural language processing
414
- </p>
415
- <div className="flex items-center gap-2">
416
- <div className="flex">
417
- {[1, 2, 3, 4, 5].map((star) => (
418
- <span
419
- key={star}
420
- className="text-fm-warning text-xs"
421
- >
422
-
423
- </span>
424
- ))}
425
- </div>
426
- <span className="text-fm-secondary text-xs">
427
- (124 reviews)
428
- </span>
429
- </div>
430
- </div>
431
- </div>
432
-
433
- <div className="space-y-2">
434
- <div className="flex justify-between text-sm">
435
- <span className="text-fm-secondary">Features:</span>
436
- </div>
437
- <ul className="text-fm-secondary space-y-1 text-xs">
438
- <li>• Real-time search suggestions</li>
439
- <li>• Advanced filtering options</li>
440
- <li>• Analytics and insights</li>
441
- <li>• API access included</li>
442
- </ul>
443
- </div>
444
-
445
- <div className="border-fm-divider-secondary flex items-center justify-between border-t pt-2">
446
- <div>
447
- <span className="text-fm-secondary text-xs line-through">
448
- $99/mo
449
- </span>
450
- <span className="text-fm-primary ml-2 text-lg font-bold">
451
- $79/mo
452
- </span>
453
- </div>
454
- <Button size="sm">Start Trial</Button>
455
- </div>
456
- </div>
457
- </HoverCardContent>
458
- </HoverCard>
459
- </div>
460
- </div>
461
-
462
- {/* Feature Product */}
463
- <div className="space-y-4">
464
- <h4 className="text-fm-secondary text-sm font-medium">
465
- Feature Product
466
- </h4>
467
- <div className="text-center">
468
- <HoverCard>
469
- <HoverCardTrigger asChild>
470
- <div className="border-fm-divider-secondary bg-fm-surface-secondary hover:bg-fm-surface-frosted/15 hover:border-fm-divider-contrast cursor-pointer rounded-lg border p-4 transition-colors">
471
- <div className="mx-auto mb-2 flex h-20 w-20 items-center justify-center rounded-lg bg-gradient-to-br from-orange-500 to-red-600">
472
- <EditBigIcon className="text-fm-primary h-8 w-8" />
473
- </div>
474
- <p className="text-fm-primary text-sm">Editor Pro</p>
475
- </div>
476
- </HoverCardTrigger>
477
- <HoverCardContent className="w-72">
478
- <div className="space-y-3">
479
- <div className="flex items-start space-x-3">
480
- <div className="flex h-12 w-12 items-center justify-center rounded-lg bg-gradient-to-br from-orange-500 to-red-600">
481
- <EditBigIcon className="text-fm-primary h-6 w-6" />
482
- </div>
483
- <div>
484
- <h4 className="text-fm-primary font-semibold">
485
- Editor Pro
486
- </h4>
487
- <p className="text-fm-secondary text-sm">
488
- Professional code editor
489
- </p>
490
- <div className="mt-1 flex items-center gap-1">
491
- <span className="rounded bg-orange-500/20 px-2 py-0.5 text-xs text-orange-300">
492
- Popular
493
- </span>
494
- <span className="bg-fm-surface-positive/20 text-fm-positive rounded px-2 py-0.5 text-xs">
495
- New
496
- </span>
497
- </div>
498
- </div>
499
- </div>
500
-
501
- <div className="grid grid-cols-2 gap-3 text-xs">
502
- <div className="space-y-1">
503
- <div className="text-fm-secondary">Languages:</div>
504
- <div className="text-fm-secondary">20+ supported</div>
505
- </div>
506
- <div className="space-y-1">
507
- <div className="text-fm-secondary">Themes:</div>
508
- <div className="text-fm-secondary">50+ themes</div>
509
- </div>
510
- </div>
511
-
512
- <div className="flex items-center justify-between">
513
- <span className="text-fm-primary text-lg font-bold">
514
- Free
515
- </span>
516
- <Button size="sm" variant="outline">
517
- Download
518
- </Button>
519
- </div>
520
- </div>
521
- </HoverCardContent>
522
- </HoverCard>
523
- </div>
67
+ <div className="w-full max-w-2xl space-y-10">
68
+ {/* HoverCardTrigger */}
69
+ <div className="space-y-3">
70
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
71
+ HoverCardTrigger
72
+ </h4>
73
+ <HoverCard>
74
+ <HoverCardTrigger asChild>
75
+ <Button variant="text">@aural_artist</Button>
76
+ </HoverCardTrigger>
77
+ <HoverCardContent>
78
+ <div className="space-y-1">
79
+ <p className="text-fm-primary font-fm-text text-fm-md leading-fm-md font-semibold">
80
+ Aural Artist
81
+ </p>
82
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
83
+ Hover the trigger above to see this card.
84
+ </p>
85
+ </div>
86
+ </HoverCardContent>
87
+ </HoverCard>
88
+ <div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
89
+ <p className="text-fm-secondary font-fm-text text-fm-md leading-fm-xl">
90
+ Wraps any element and attaches hover event listeners. Pass{" "}
91
+ <code>asChild</code> to render the child element directly rather
92
+ than adding an extra DOM node. Must be a direct child of the{" "}
93
+ <code>HoverCard</code> root.
94
+ </p>
524
95
  </div>
525
96
  </div>
526
- </div>
527
- ),
528
- parameters: {
529
- docs: {
530
- description: {
531
- story:
532
- "Product preview cards showing different levels of detail and information architecture.",
533
- },
534
- },
535
- },
536
- }
537
-
538
- // 4. Documentation Links
539
- export const DocumentationLinks: Story = {
540
- render: () => (
541
- <div className="space-y-8 p-8">
542
- <h3 className="text-fm-primary text-center text-lg font-medium">
543
- Documentation Links
544
- </h3>
545
-
546
- <div className="space-y-6">
547
- {/* API Documentation */}
548
- <div className="space-y-4">
549
- <h4 className="text-fm-secondary text-sm font-medium">
550
- API Documentation
551
- </h4>
552
- <div className="space-y-2">
553
- <p className="text-fm-secondary text-sm">
554
- Learn more about our{" "}
555
- <HoverCard>
556
- <HoverCardTrigger asChild>
557
- <Button
558
- variant="text"
559
- className="text-fm-info h-auto p-0 font-normal"
560
- >
561
- REST API
562
- </Button>
563
- </HoverCardTrigger>
564
- <HoverCardContent>
565
- <div className="space-y-2">
566
- <h4 className="text-fm-primary text-sm font-semibold">
567
- REST API
568
- </h4>
569
- <p className="text-fm-secondary text-sm">
570
- Our REST API provides programmatic access to all platform
571
- features.
572
- </p>
573
- <div className="text-fm-secondary space-y-1 text-xs">
574
- <div>• Rate limit: 1000 requests/hour</div>
575
- <div>• Authentication: API Key required</div>
576
- <div>• Response format: JSON</div>
577
- </div>
578
- <Button size="sm" className="mt-2 w-full">
579
- View Documentation
580
- </Button>
581
- </div>
582
- </HoverCardContent>
583
- </HoverCard>{" "}
584
- and{" "}
585
- <HoverCard>
586
- <HoverCardTrigger asChild>
587
- <Button
588
- variant="text"
589
- className="text-fm-info h-auto p-0 font-normal"
590
- >
591
- GraphQL endpoint
592
- </Button>
593
- </HoverCardTrigger>
594
- <HoverCardContent>
595
- <div className="space-y-2">
596
- <h4 className="text-fm-primary text-sm font-semibold">
597
- GraphQL API
598
- </h4>
599
- <p className="text-fm-secondary text-sm">
600
- Query exactly the data you need with our GraphQL API.
601
- </p>
602
- <div className="text-fm-secondary space-y-1 text-xs">
603
- <div>• Single endpoint for all queries</div>
604
- <div>• Type-safe schema</div>
605
- <div>• Real-time subscriptions</div>
606
- </div>
607
- <div className="mt-2 flex gap-2">
608
- <Button size="sm" className="flex-1">
609
- Playground
610
- </Button>
611
- <Button size="sm" variant="outline" className="flex-1">
612
- Schema
613
- </Button>
614
- </div>
615
- </div>
616
- </HoverCardContent>
617
- </HoverCard>
618
- .
619
- </p>
620
- </div>
621
- </div>
622
97
 
623
- {/* Configuration Options */}
624
- <div className="space-y-4">
625
- <h4 className="text-fm-secondary text-sm font-medium">
626
- Configuration Options
627
- </h4>
628
- <div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
629
- <div className="space-y-3 text-sm">
630
- <div className="flex items-center justify-between">
631
- <span className="text-fm-primary">Enable notifications</span>
632
- <HoverCard>
633
- <HoverCardTrigger asChild>
634
- <Button variant="outline" size="sm" className="h-6 w-6 p-0">
635
- <AlertIcon className="h-4 w-4" />
636
- </Button>
637
- </HoverCardTrigger>
638
- <HoverCardContent className="w-72">
639
- <div className="space-y-2">
640
- <h4 className="text-fm-primary text-sm font-semibold">
641
- Notification Settings
642
- </h4>
643
- <p className="text-fm-secondary text-sm">
644
- Control when and how you receive notifications from the
645
- platform.
646
- </p>
647
- <div className="space-y-2">
648
- <div className="text-fm-secondary text-xs">
649
- Available notification types:
650
- </div>
651
- <ul className="text-fm-secondary ml-2 space-y-1 text-xs">
652
- <li>• Email notifications</li>
653
- <li>• Push notifications</li>
654
- <li>• In-app notifications</li>
655
- <li>• SMS alerts (premium)</li>
656
- </ul>
657
- </div>
658
- </div>
659
- </HoverCardContent>
660
- </HoverCard>
661
- </div>
662
-
663
- <div className="flex items-center justify-between">
664
- <span className="text-fm-primary">Auto-save frequency</span>
665
- <HoverCard>
666
- <HoverCardTrigger asChild>
667
- <Button variant="outline" size="sm" className="h-6 w-6 p-0">
668
- <TickCircleIcon className="h-4 w-4" />
669
- </Button>
670
- </HoverCardTrigger>
671
- <HoverCardContent>
672
- <div className="space-y-2">
673
- <h4 className="text-fm-primary text-sm font-semibold">
674
- Auto-save Settings
675
- </h4>
676
- <p className="text-fm-secondary text-sm">
677
- Automatically save your work at regular intervals.
678
- </p>
679
- <div className="text-fm-secondary space-y-1 text-xs">
680
- <div>• Every 30 seconds (recommended)</div>
681
- <div>• Every 1 minute</div>
682
- <div>• Every 5 minutes</div>
683
- <div>• Disabled</div>
684
- </div>
685
- </div>
686
- </HoverCardContent>
687
- </HoverCard>
688
- </div>
98
+ {/* HoverCardContent */}
99
+ <div className="space-y-3">
100
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
101
+ HoverCardContent
102
+ </h4>
103
+ <HoverCard defaultOpen>
104
+ <HoverCardTrigger asChild>
105
+ <Button variant="text">Hover card open</Button>
106
+ </HoverCardTrigger>
107
+ <HoverCardContent>
108
+ <div className="space-y-2">
109
+ <p className="text-fm-primary font-fm-text text-fm-md leading-fm-md font-semibold">
110
+ Frosted glass panel
111
+ </p>
112
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
113
+ Backdrop-blurred container with{" "}
114
+ <code>bg-fm-surface-frosted/20</code>. Accepts{" "}
115
+ <code>align</code>, <code>sideOffset</code>, and all Radix
116
+ Content props.
117
+ </p>
689
118
  </div>
690
- </div>
119
+ </HoverCardContent>
120
+ </HoverCard>
121
+ <div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
122
+ <p className="text-fm-secondary font-fm-text text-fm-md leading-fm-xl">
123
+ The floating panel rendered in a portal. Uses a frosted-glass
124
+ backdrop with <code>text-fm-primary</code> text and{" "}
125
+ <code>w-64</code> default width. Positioning is controlled by{" "}
126
+ <code>align</code> and <code>sideOffset</code>.
127
+ </p>
691
128
  </div>
692
129
  </div>
693
130
  </div>
694
131
  ),
695
- parameters: {
696
- docs: {
697
- description: {
698
- story:
699
- "Documentation and help text hover cards for providing contextual information about features and settings.",
700
- },
701
- },
702
- },
703
132
  }
704
133
 
705
- // 5. Interactive Elements
706
- export const InteractiveElements: Story = {
707
- render: () => {
708
- const [selectedUser, setSelectedUser] = React.useState<string | null>(null)
709
- const [hoveredProduct, setHoveredProduct] = React.useState<string | null>(
710
- null
711
- )
712
-
713
- const users = [
714
- { id: "1", name: "Alice Johnson", role: "Designer", status: "online" },
715
- { id: "2", name: "Bob Smith", role: "Developer", status: "away" },
716
- { id: "3", name: "Carol Davis", role: "Manager", status: "offline" },
717
- ]
718
-
719
- const products = [
720
- { id: "1", name: "Dashboard Pro", price: "$49", sales: 1234 },
721
- { id: "2", name: "Analytics Suite", price: "$79", sales: 856 },
722
- { id: "3", name: "Report Builder", price: "$29", sales: 2341 },
723
- ]
724
-
725
- return (
726
- <div className="space-y-8 p-8">
727
- <h3 className="text-fm-primary text-center text-lg font-medium">
728
- Interactive Elements
729
- </h3>
730
-
731
- <div className="grid grid-cols-1 gap-8 lg:grid-cols-2">
732
- {/* Team Members */}
733
- <div className="space-y-4">
734
- <h4 className="text-fm-secondary text-sm font-medium">
735
- Team Members
736
- </h4>
737
- <div className="space-y-2">
738
- {users.map((user) => (
739
- <HoverCard key={user.id}>
740
- <HoverCardTrigger asChild>
741
- <div
742
- className={`flex cursor-pointer items-center space-x-3 rounded-lg border p-3 transition-colors ${
743
- selectedUser === user.id
744
- ? "border-fm-divider-secondary bg-fm-surface-info-sec"
745
- : "border-fm-divider-secondary bg-fm-surface-secondary hover:bg-fm-surface-frosted/15 hover:border-fm-divider-contrast"
746
- }`}
747
- onClick={() =>
748
- setSelectedUser(
749
- selectedUser === user.id ? null : user.id
750
- )
751
- }
752
- >
753
- <div
754
- className={`flex h-8 w-8 items-center justify-center rounded-full ${
755
- user.status === "online"
756
- ? "bg-fm-surface-positive"
757
- : user.status === "away"
758
- ? "bg-fm-surface-warning"
759
- : "bg-fm-surface-secondary"
760
- }`}
761
- >
762
- <span className="text-fm-primary text-xs font-semibold">
763
- {user.name
764
- .split(" ")
765
- .map((n) => n[0])
766
- .join("")}
767
- </span>
768
- </div>
769
- <div className="flex-1">
770
- <div className="text-fm-primary text-sm font-medium">
771
- {user.name}
772
- </div>
773
- <div className="text-fm-secondary text-xs">
774
- {user.role}
775
- </div>
776
- </div>
777
- <div
778
- className={`h-2 w-2 rounded-full ${
779
- user.status === "online"
780
- ? "bg-fm-surface-positive"
781
- : user.status === "away"
782
- ? "bg-fm-surface-warning"
783
- : "bg-fm-surface-secondary"
784
- }`}
785
- />
786
- </div>
787
- </HoverCardTrigger>
788
- <HoverCardContent className="w-80">
789
- <div className="space-y-3">
790
- <div className="flex space-x-4">
791
- <div
792
- className={`flex h-16 w-16 items-center justify-center rounded-full ${
793
- user.status === "online"
794
- ? "bg-fm-surface-positive"
795
- : user.status === "away"
796
- ? "bg-fm-surface-warning"
797
- : "bg-fm-surface-secondary"
798
- }`}
799
- >
800
- <span className="text-fm-primary font-semibold">
801
- {user.name
802
- .split(" ")
803
- .map((n) => n[0])
804
- .join("")}
805
- </span>
806
- </div>
807
- <div className="space-y-1">
808
- <h4 className="text-fm-primary text-sm font-semibold">
809
- {user.name}
810
- </h4>
811
- <p className="text-fm-secondary text-sm">
812
- {user.role}
813
- </p>
814
- <div className="flex items-center gap-2 text-xs">
815
- <div
816
- className={`h-2 w-2 rounded-full ${
817
- user.status === "online"
818
- ? "bg-fm-surface-positive"
819
- : user.status === "away"
820
- ? "bg-fm-surface-warning"
821
- : "bg-fm-surface-secondary"
822
- }`}
823
- />
824
- <span className="text-fm-secondary capitalize">
825
- {user.status}
826
- </span>
827
- </div>
828
- </div>
829
- </div>
830
-
831
- <div className="text-fm-secondary text-sm">
832
- {user.status === "online"
833
- ? "Available for collaboration"
834
- : user.status === "away"
835
- ? "Away - will respond later"
836
- : "Last seen 2 hours ago"}
837
- </div>
838
-
839
- <div className="flex gap-2">
840
- <Button size="sm" className="flex-1">
841
- Message
842
- </Button>
843
- <Button size="sm" variant="outline" className="flex-1">
844
- Profile
845
- </Button>
846
- </div>
847
- </div>
848
- </HoverCardContent>
849
- </HoverCard>
850
- ))}
851
- </div>
852
- </div>
853
-
854
- {/* Product Analytics */}
855
- <div className="space-y-4">
856
- <h4 className="text-fm-secondary text-sm font-medium">
857
- Product Analytics
858
- </h4>
859
- <div className="space-y-2">
860
- {products.map((product) => (
861
- <HoverCard key={product.id}>
862
- <HoverCardTrigger asChild>
863
- <div
864
- className={`cursor-pointer rounded-lg border p-3 transition-colors ${
865
- hoveredProduct === product.id
866
- ? "border-purple-500 bg-purple-500/10"
867
- : "border-fm-divider-secondary bg-fm-surface-secondary hover:bg-fm-surface-frosted/15 hover:border-fm-divider-contrast"
868
- }`}
869
- onMouseEnter={() => setHoveredProduct(product.id)}
870
- onMouseLeave={() => setHoveredProduct(null)}
871
- >
872
- <div className="flex items-center justify-between">
873
- <div>
874
- <div className="text-fm-primary text-sm font-medium">
875
- {product.name}
876
- </div>
877
- <div className="text-fm-secondary text-xs">
878
- {product.sales} sales
879
- </div>
880
- </div>
881
- <div className="text-right">
882
- <div className="text-fm-primary text-sm font-semibold">
883
- {product.price}
884
- </div>
885
- <div className="text-fm-positive text-xs">↗ +12%</div>
886
- </div>
887
- </div>
888
- </div>
889
- </HoverCardTrigger>
890
- <HoverCardContent className="w-96">
891
- <div className="space-y-4">
892
- <div className="flex items-start justify-between">
893
- <div>
894
- <h4 className="text-fm-primary font-semibold">
895
- {product.name}
896
- </h4>
897
- <p className="text-fm-secondary text-sm">
898
- Detailed product analytics
899
- </p>
900
- </div>
901
- <span className="text-fm-primary text-lg font-bold">
902
- {product.price}
903
- </span>
904
- </div>
905
-
906
- <div className="grid grid-cols-2 gap-4">
907
- <div className="space-y-1">
908
- <div className="text-fm-secondary text-xs">
909
- Total Sales
910
- </div>
911
- <div className="text-fm-primary text-lg font-semibold">
912
- {product.sales}
913
- </div>
914
- <div className="text-fm-positive text-xs">
915
- +12% vs last month
916
- </div>
917
- </div>
918
- <div className="space-y-1">
919
- <div className="text-fm-secondary text-xs">
920
- Revenue
921
- </div>
922
- <div className="text-fm-primary text-lg font-semibold">
923
- $
924
- {(
925
- parseInt(product.price.slice(1)) * product.sales
926
- ).toLocaleString()}
927
- </div>
928
- <div className="text-fm-positive text-xs">
929
- +8% vs last month
930
- </div>
931
- </div>
932
- </div>
134
+ // ─── Configurations ──────────────────────────────────────────────────────────
933
135
 
934
- <div className="space-y-2">
935
- <div className="text-fm-secondary text-xs">
936
- Top Markets
937
- </div>
938
- <div className="space-y-1">
939
- <div className="flex justify-between text-xs">
940
- <span className="text-fm-secondary">
941
- North America
942
- </span>
943
- <span className="text-fm-primary">45%</span>
944
- </div>
945
- <div className="flex justify-between text-xs">
946
- <span className="text-fm-secondary">Europe</span>
947
- <span className="text-fm-primary">32%</span>
948
- </div>
949
- <div className="flex justify-between text-xs">
950
- <span className="text-fm-secondary">
951
- Asia Pacific
952
- </span>
953
- <span className="text-fm-primary">23%</span>
954
- </div>
955
- </div>
956
- </div>
957
-
958
- <Button size="sm" className="w-full">
959
- <FileChartIcon className="mr-2 h-3 w-3" />
960
- View Full Report
961
- </Button>
962
- </div>
963
- </HoverCardContent>
964
- </HoverCard>
965
- ))}
966
- </div>
967
- </div>
968
- </div>
969
- </div>
970
- )
971
- },
136
+ export const Configurations: Story = {
972
137
  parameters: {
973
138
  docs: {
974
139
  description: {
975
140
  story:
976
- "Interactive hover cards that respond to user interactions and display dynamic content.",
141
+ "Demonstrates align (start / center / end), sideOffset variations, and delay timing. Hover each trigger to see the positioning difference.",
977
142
  },
978
143
  },
979
144
  },
980
- }
981
-
982
- // 6. Positioning & Timing
983
- export const PositioningAndTiming: Story = {
984
145
  render: () => (
985
- <div className="space-y-8 p-8">
986
- <h3 className="text-fm-primary text-center text-lg font-medium">
987
- Positioning & Timing
988
- </h3>
989
-
990
- <div className="space-y-8">
991
- {/* Positioning */}
992
- <div className="space-y-4">
993
- <h4 className="text-fm-secondary text-center text-sm font-medium">
994
- Different Positions
995
- </h4>
996
- <div className="grid grid-cols-2 place-items-center gap-8 lg:grid-cols-4">
997
- {/* Top */}
998
- <div className="flex flex-col items-center gap-4">
999
- <span className="text-fm-secondary text-sm">Top</span>
1000
- <HoverCard>
1001
- <HoverCardTrigger asChild>
1002
- <Button variant="outline" size="sm">
1003
- Top
1004
- </Button>
1005
- </HoverCardTrigger>
1006
- <HoverCardContent side="top">
1007
- <div className="space-y-2">
1008
- <h4 className="text-fm-primary text-sm font-semibold">
1009
- Top Position
1010
- </h4>
1011
- <p className="text-fm-secondary text-sm">
1012
- Card positioned above the trigger
1013
- </p>
1014
- </div>
1015
- </HoverCardContent>
1016
- </HoverCard>
1017
- </div>
1018
-
1019
- {/* Right */}
1020
- <div className="flex flex-col items-center gap-4">
1021
- <span className="text-fm-secondary text-sm">Right</span>
146
+ <div className="w-full max-w-3xl space-y-8">
147
+ {/* Alignment */}
148
+ <div className="space-y-4">
149
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
150
+ Alignment — align prop
151
+ </h4>
152
+ <div className="flex flex-wrap justify-center gap-6">
153
+ {(["start", "center", "end"] as const).map((align) => (
154
+ <div key={align} className="space-y-2 text-center">
1022
155
  <HoverCard>
1023
156
  <HoverCardTrigger asChild>
1024
- <Button variant="outline" size="sm">
1025
- Right
1026
- </Button>
157
+ <Button variant="outline">align="{align}"</Button>
1027
158
  </HoverCardTrigger>
1028
- <HoverCardContent side="right">
1029
- <div className="space-y-2">
1030
- <h4 className="text-fm-primary text-sm font-semibold">
1031
- Right Position
1032
- </h4>
1033
- <p className="text-fm-secondary text-sm">
1034
- Card positioned to the right
1035
- </p>
1036
- </div>
159
+ <HoverCardContent align={align}>
160
+ <p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
161
+ Content aligned to <strong>{align}</strong> of trigger.
162
+ </p>
1037
163
  </HoverCardContent>
1038
164
  </HoverCard>
165
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
166
+ {align}
167
+ </p>
1039
168
  </div>
169
+ ))}
170
+ </div>
171
+ </div>
1040
172
 
1041
- {/* Bottom */}
1042
- <div className="flex flex-col items-center gap-4">
1043
- <span className="text-fm-secondary text-sm">Bottom</span>
173
+ {/* sideOffset */}
174
+ <div className="space-y-4">
175
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
176
+ Side Offset — sideOffset prop
177
+ </h4>
178
+ <div className="flex flex-wrap justify-center gap-6">
179
+ {[0, 8, 16, 24].map((offset) => (
180
+ <div key={offset} className="space-y-2 text-center">
1044
181
  <HoverCard>
1045
182
  <HoverCardTrigger asChild>
1046
- <Button variant="outline" size="sm">
1047
- Bottom
1048
- </Button>
183
+ <Button variant="outline">offset {offset}px</Button>
1049
184
  </HoverCardTrigger>
1050
- <HoverCardContent side="bottom">
1051
- <div className="space-y-2">
1052
- <h4 className="text-fm-primary text-sm font-semibold">
1053
- Bottom Position
1054
- </h4>
1055
- <p className="text-fm-secondary text-sm">
1056
- Card positioned below the trigger
1057
- </p>
1058
- </div>
185
+ <HoverCardContent sideOffset={offset}>
186
+ <p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
187
+ sideOffset={offset}
188
+ </p>
1059
189
  </HoverCardContent>
1060
190
  </HoverCard>
191
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
192
+ {offset}px gap
193
+ </p>
1061
194
  </div>
195
+ ))}
196
+ </div>
197
+ </div>
1062
198
 
1063
- {/* Left */}
1064
- <div className="flex flex-col items-center gap-4">
1065
- <span className="text-fm-secondary text-sm">Left</span>
1066
- <HoverCard>
199
+ {/* Delay timing */}
200
+ <div className="space-y-4">
201
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
202
+ Delay Timing — openDelay / closeDelay
203
+ </h4>
204
+ <div className="flex flex-wrap justify-center gap-6">
205
+ {[
206
+ { label: "Instant", openDelay: 0, closeDelay: 0 },
207
+ { label: "Default (700ms)", openDelay: 700, closeDelay: 300 },
208
+ { label: "Slow (1200ms)", openDelay: 1200, closeDelay: 600 },
209
+ ].map(({ label, openDelay, closeDelay }) => (
210
+ <div key={label} className="space-y-2 text-center">
211
+ <HoverCard openDelay={openDelay} closeDelay={closeDelay}>
1067
212
  <HoverCardTrigger asChild>
1068
- <Button variant="outline" size="sm">
1069
- Left
1070
- </Button>
213
+ <Button variant="outline">{label}</Button>
1071
214
  </HoverCardTrigger>
1072
- <HoverCardContent side="left">
1073
- <div className="space-y-2">
1074
- <h4 className="text-fm-primary text-sm font-semibold">
1075
- Left Position
1076
- </h4>
1077
- <p className="text-fm-secondary text-sm">
1078
- Card positioned to the left
1079
- </p>
1080
- </div>
215
+ <HoverCardContent>
216
+ <p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
217
+ Open: {openDelay}ms · Close: {closeDelay}ms
218
+ </p>
1081
219
  </HoverCardContent>
1082
220
  </HoverCard>
221
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
222
+ open {openDelay}ms
223
+ </p>
1083
224
  </div>
1084
- </div>
1085
- </div>
1086
-
1087
- {/* Timing */}
1088
- <div className="space-y-4">
1089
- <h4 className="text-fm-secondary text-center text-sm font-medium">
1090
- Different Delays
1091
- </h4>
1092
- <div className="flex justify-center gap-4">
1093
- <HoverCard openDelay={0}>
1094
- <HoverCardTrigger asChild>
1095
- <Button variant="outline" size="sm">
1096
- Instant
1097
- </Button>
1098
- </HoverCardTrigger>
1099
- <HoverCardContent>
1100
- <div className="space-y-2">
1101
- <h4 className="text-fm-primary text-sm font-semibold">
1102
- No Delay
1103
- </h4>
1104
- <p className="text-fm-secondary text-sm">
1105
- Appears immediately on hover
1106
- </p>
1107
- </div>
1108
- </HoverCardContent>
1109
- </HoverCard>
1110
-
1111
- <HoverCard openDelay={500}>
1112
- <HoverCardTrigger asChild>
1113
- <Button variant="outline" size="sm">
1114
- Medium
1115
- </Button>
1116
- </HoverCardTrigger>
1117
- <HoverCardContent>
1118
- <div className="space-y-2">
1119
- <h4 className="text-fm-primary text-sm font-semibold">
1120
- Medium Delay
1121
- </h4>
1122
- <p className="text-fm-secondary text-sm">
1123
- 500ms delay before appearing
1124
- </p>
1125
- </div>
1126
- </HoverCardContent>
1127
- </HoverCard>
1128
-
1129
- <HoverCard openDelay={1000}>
1130
- <HoverCardTrigger asChild>
1131
- <Button variant="outline" size="sm">
1132
- Slow
1133
- </Button>
1134
- </HoverCardTrigger>
1135
- <HoverCardContent>
1136
- <div className="space-y-2">
1137
- <h4 className="text-fm-primary text-sm font-semibold">
1138
- Long Delay
1139
- </h4>
1140
- <p className="text-fm-secondary text-sm">
1141
- 1000ms delay before appearing
1142
- </p>
1143
- </div>
1144
- </HoverCardContent>
1145
- </HoverCard>
1146
- </div>
1147
- </div>
1148
-
1149
- {/* Size Variations */}
1150
- <div className="space-y-4">
1151
- <h4 className="text-fm-secondary text-center text-sm font-medium">
1152
- Different Sizes
1153
- </h4>
1154
- <div className="flex justify-center gap-4">
1155
- <HoverCard>
1156
- <HoverCardTrigger asChild>
1157
- <Button variant="outline" size="sm">
1158
- Small
1159
- </Button>
1160
- </HoverCardTrigger>
1161
- <HoverCardContent className="w-48">
1162
- <div className="space-y-2">
1163
- <h4 className="text-fm-primary text-sm font-semibold">
1164
- Small Card
1165
- </h4>
1166
- <p className="text-fm-secondary text-sm">
1167
- Compact information
1168
- </p>
1169
- </div>
1170
- </HoverCardContent>
1171
- </HoverCard>
1172
-
1173
- <HoverCard>
1174
- <HoverCardTrigger asChild>
1175
- <Button variant="outline" size="sm">
1176
- Medium
1177
- </Button>
1178
- </HoverCardTrigger>
1179
- <HoverCardContent className="w-80">
1180
- <div className="space-y-2">
1181
- <h4 className="text-fm-primary text-sm font-semibold">
1182
- Medium Card
1183
- </h4>
1184
- <p className="text-fm-secondary text-sm">
1185
- Medium-sized card with more detailed information and
1186
- multiple lines of text.
1187
- </p>
1188
- </div>
1189
- </HoverCardContent>
1190
- </HoverCard>
1191
-
1192
- <HoverCard>
1193
- <HoverCardTrigger asChild>
1194
- <Button variant="outline" size="sm">
1195
- Large
1196
- </Button>
1197
- </HoverCardTrigger>
1198
- <HoverCardContent className="w-96">
1199
- <div className="space-y-3">
1200
- <h4 className="text-fm-primary text-sm font-semibold">
1201
- Large Card
1202
- </h4>
1203
- <p className="text-fm-secondary text-sm">
1204
- Large card with extensive information, multiple sections,
1205
- and complex layouts. Perfect for detailed previews and
1206
- comprehensive information displays.
1207
- </p>
1208
- <div className="border-fm-divider-secondary border-t pt-2">
1209
- <Button size="sm" className="w-full">
1210
- Learn More
1211
- </Button>
1212
- </div>
1213
- </div>
1214
- </HoverCardContent>
1215
- </HoverCard>
1216
- </div>
225
+ ))}
1217
226
  </div>
1218
227
  </div>
1219
228
  </div>
1220
229
  ),
230
+ }
231
+
232
+ // ─── UseCases ────────────────────────────────────────────────────────────────
233
+
234
+ export const UseCases: Story = {
1221
235
  parameters: {
1222
236
  docs: {
1223
237
  description: {
1224
238
  story:
1225
- "Different positioning options, timing delays, and size variations for hover cards.",
239
+ "Real product-shaped examples: artist profile preview on hover, album info card, and user mention preview all in an audio streaming context.",
1226
240
  },
1227
241
  },
1228
242
  },
1229
- }
1230
-
1231
- // 7. Accessibility Demo
1232
- export const AccessibilityDemo: Story = {
1233
243
  render: () => (
1234
- <div className="space-y-8 p-8">
1235
- <h3 className="text-fm-primary text-center text-lg font-medium">
1236
- Accessibility Features
1237
- </h3>
1238
-
1239
- <div className="space-y-6">
1240
- <div className="border-fm-divider-secondary bg-fm-surface-info-sec rounded-lg border p-4">
1241
- <h4 className="text-fm-info mb-2 text-sm font-medium">
1242
- Keyboard Navigation
1243
- </h4>
1244
- <p className="text-fm-info-sec mb-2 text-xs">
1245
- Try these keyboard interactions:
244
+ <div className="mx-auto max-w-3xl space-y-8 p-8">
245
+ {/* Artist profile preview */}
246
+ <div className="space-y-4">
247
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
248
+ Artist Profile Preview
249
+ </h4>
250
+ <div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-2 rounded-xl border p-5">
251
+ <p className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm">
252
+ Now playing from
1246
253
  </p>
1247
- <ul className="text-fm-info-sec space-y-1 text-xs">
1248
- <li>
1249
- <kbd className="bg-fm-surface-secondary rounded px-1">Tab</kbd>{" "}
1250
- to focus hover card triggers
1251
- </li>
1252
- <li>• Hover card appears automatically on focus</li>
1253
- <li>
1254
- •{" "}
1255
- <kbd className="bg-fm-surface-secondary rounded px-1">Escape</kbd>{" "}
1256
- to dismiss hover card
1257
- </li>
1258
- <li>• Content is announced by screen readers</li>
1259
- </ul>
1260
- </div>
1261
-
1262
- {/* Keyboard Accessible Examples */}
1263
- <div className="space-y-4">
1264
- <h4 className="text-fm-secondary text-sm font-medium">
1265
- Keyboard Accessible Hover Cards
1266
- </h4>
1267
- <div className="flex flex-wrap gap-4">
1268
- <HoverCard>
1269
- <HoverCardTrigger asChild>
1270
- <Button>Focusable Button</Button>
1271
- </HoverCardTrigger>
1272
- <HoverCardContent>
1273
- <div className="space-y-2">
1274
- <h4 className="text-fm-primary text-sm font-semibold">
1275
- Keyboard Accessible
1276
- </h4>
1277
- <p className="text-fm-secondary text-sm">
1278
- This hover card appears on both hover and keyboard focus.
1279
- </p>
1280
- </div>
1281
- </HoverCardContent>
1282
- </HoverCard>
1283
-
1284
- <HoverCard>
1285
- <HoverCardTrigger asChild>
1286
- <a
1287
- href="#"
1288
- className="text-fm-info inline-flex items-center gap-2 rounded px-3 py-2 text-sm hover:text-blue-300 focus:ring-2 focus:ring-blue-500 focus:outline-none"
1289
- onClick={(e) => e.preventDefault()}
1290
- >
1291
- <AlertIcon className="h-4 w-4" />
1292
- Documentation Link
1293
- </a>
1294
- </HoverCardTrigger>
1295
- <HoverCardContent>
1296
- <div className="space-y-2">
1297
- <h4 className="text-fm-primary text-sm font-semibold">
1298
- Documentation
1299
- </h4>
1300
- <p className="text-fm-secondary text-sm">
1301
- Comprehensive guides and API reference for developers.
1302
- </p>
1303
- <Button size="sm" className="w-full">
1304
- View Docs
1305
- </Button>
1306
- </div>
1307
- </HoverCardContent>
1308
- </HoverCard>
1309
-
1310
- <HoverCard>
254
+ <p className="text-fm-primary font-fm-text text-fm-md leading-fm-md">
255
+ Midnights ·{" "}
256
+ <HoverCard openDelay={300} closeDelay={150}>
1311
257
  <HoverCardTrigger asChild>
1312
- <button className="border-fm-divider-secondary bg-fm-surface-secondary text-fm-primary hover:bg-fm-surface-frosted/15 hover:border-fm-divider-contrast inline-flex items-center gap-2 rounded border px-3 py-2 text-sm focus:ring-2 focus:ring-purple-500 focus:outline-none">
1313
- <TickCircleIcon className="h-4 w-4" />
1314
- Status Check
258
+ <button className="text-fm-primary cursor-pointer font-semibold underline underline-offset-2 outline-none">
259
+ Taylor Swift
1315
260
  </button>
1316
261
  </HoverCardTrigger>
1317
- <HoverCardContent>
1318
- <div className="space-y-2">
1319
- <h4 className="text-fm-primary text-sm font-semibold">
1320
- System Status
1321
- </h4>
1322
- <div className="text-fm-secondary space-y-1 text-sm">
1323
- <div className="flex items-center gap-2">
1324
- <div className="bg-fm-surface-positive h-2 w-2 rounded-full"></div>
1325
- <span>All systems operational</span>
262
+ <HoverCardContent className="w-72">
263
+ <div className="space-y-3">
264
+ <div className="flex items-center gap-3">
265
+ <div className="bg-fm-surface-primary border-fm-divider-secondary flex h-12 w-12 shrink-0 items-center justify-center rounded-full border">
266
+ <span className="text-fm-primary font-fm-brand text-fm-md leading-fm-md font-semibold">
267
+ TS
268
+ </span>
1326
269
  </div>
1327
- <div className="text-fm-secondary text-xs">
1328
- Last updated: 2 minutes ago
270
+ <div className="space-y-0.5">
271
+ <p className="text-fm-primary font-fm-text text-fm-md leading-fm-md font-semibold">
272
+ Taylor Swift
273
+ </p>
274
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
275
+ Pop · Country
276
+ </p>
1329
277
  </div>
1330
278
  </div>
279
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
280
+ 11 studio albums · 85M+ monthly listeners
281
+ </p>
282
+ <div className="text-fm-tertiary font-fm-text text-fm-xs leading-fm-xs flex gap-2">
283
+ <span className="border-fm-divider-secondary rounded border px-2 py-0.5">
284
+ Pop
285
+ </span>
286
+ <span className="border-fm-divider-secondary rounded border px-2 py-0.5">
287
+ Country
288
+ </span>
289
+ <span className="border-fm-divider-secondary rounded border px-2 py-0.5">
290
+ Indie
291
+ </span>
292
+ </div>
1331
293
  </div>
1332
294
  </HoverCardContent>
1333
295
  </HoverCard>
296
+ </p>
297
+ </div>
298
+ </div>
299
+
300
+ {/* Album info card */}
301
+ <div className="space-y-4">
302
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
303
+ Album Info Card
304
+ </h4>
305
+ <div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-xl border p-5">
306
+ <p className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm mb-3">
307
+ Recently played albums
308
+ </p>
309
+ <div className="flex flex-wrap gap-3">
310
+ {[
311
+ {
312
+ name: "Midnights",
313
+ artist: "Taylor Swift",
314
+ year: "2022",
315
+ tracks: 13,
316
+ },
317
+ {
318
+ name: "Renaissance",
319
+ artist: "Beyoncé",
320
+ year: "2022",
321
+ tracks: 16,
322
+ },
323
+ {
324
+ name: "Harry's House",
325
+ artist: "Harry Styles",
326
+ year: "2022",
327
+ tracks: 13,
328
+ },
329
+ ].map((album) => (
330
+ <HoverCard key={album.name} openDelay={400}>
331
+ <HoverCardTrigger asChild>
332
+ <div className="bg-fm-surface-primary border-fm-divider-secondary hover:border-fm-divider-primary flex h-16 w-16 cursor-pointer items-center justify-center rounded-lg border transition-colors">
333
+ <span className="text-fm-tertiary font-fm-text text-fm-xs leading-fm-xs px-1 text-center">
334
+ {album.name.slice(0, 3)}
335
+ </span>
336
+ </div>
337
+ </HoverCardTrigger>
338
+ <HoverCardContent className="w-64">
339
+ <div className="space-y-2">
340
+ <p className="text-fm-primary font-fm-text text-fm-md leading-fm-md font-semibold">
341
+ {album.name}
342
+ </p>
343
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
344
+ {album.artist}
345
+ </p>
346
+ <div className="text-fm-tertiary font-fm-text text-fm-xs leading-fm-xs flex gap-4 pt-1">
347
+ <span>{album.year}</span>
348
+ <span>{album.tracks} tracks</span>
349
+ </div>
350
+ </div>
351
+ </HoverCardContent>
352
+ </HoverCard>
353
+ ))}
1334
354
  </div>
1335
355
  </div>
356
+ </div>
1336
357
 
1337
- <div className="border-fm-divider-warning bg-fm-surface-warning-sec rounded-lg border p-4">
1338
- <h4 className="text-fm-warning mb-2 text-sm font-medium">
1339
- Best Practices
1340
- </h4>
1341
- <ul className="text-fm-warning space-y-1 text-xs">
1342
- <li>• Ensure hover cards work with keyboard navigation</li>
1343
- <li>• Don't put critical information only in hover cards</li>
1344
- <li>• Keep content concise and scannable</li>
1345
- <li>• Test with screen readers and keyboard users</li>
1346
- <li>• Consider mobile users (hover doesn't work on touch)</li>
1347
- <li>• Provide alternative access methods for important content</li>
1348
- </ul>
358
+ {/* User mention preview */}
359
+ <div className="space-y-4">
360
+ <h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
361
+ User Mention Preview
362
+ </h4>
363
+ <div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-3 rounded-xl border p-5">
364
+ <p className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm">
365
+ Activity feed
366
+ </p>
367
+ {[
368
+ {
369
+ handle: "@mikejameson",
370
+ action: "shared a playlist with you",
371
+ initials: "MJ",
372
+ name: "Mike Jameson",
373
+ role: "Music Producer",
374
+ followers: "4.1k",
375
+ },
376
+ {
377
+ handle: "@luna_beats",
378
+ action: "liked your track",
379
+ initials: "LB",
380
+ name: "Luna Beats",
381
+ role: "DJ · Electronic",
382
+ followers: "12k",
383
+ },
384
+ ].map(({ handle, action, initials, name, role, followers }) => (
385
+ <div
386
+ key={handle}
387
+ className="text-fm-primary font-fm-text text-fm-md leading-fm-md flex items-center gap-2"
388
+ >
389
+ <HoverCard openDelay={300} closeDelay={200}>
390
+ <HoverCardTrigger asChild>
391
+ <button className="text-fm-primary cursor-pointer font-semibold underline underline-offset-2 outline-none">
392
+ {handle}
393
+ </button>
394
+ </HoverCardTrigger>
395
+ <HoverCardContent className="w-64">
396
+ <div className="space-y-3">
397
+ <div className="flex items-center gap-3">
398
+ <div className="bg-fm-surface-primary border-fm-divider-secondary flex h-10 w-10 shrink-0 items-center justify-center rounded-full border">
399
+ <span className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold">
400
+ {initials}
401
+ </span>
402
+ </div>
403
+ <div>
404
+ <p className="text-fm-primary font-fm-text text-fm-md leading-fm-md font-semibold">
405
+ {name}
406
+ </p>
407
+ <p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
408
+ {role}
409
+ </p>
410
+ </div>
411
+ </div>
412
+ <p className="text-fm-tertiary font-fm-text text-fm-xs leading-fm-xs">
413
+ {followers} followers
414
+ </p>
415
+ </div>
416
+ </HoverCardContent>
417
+ </HoverCard>
418
+ <span className="text-fm-secondary">{action}</span>
419
+ </div>
420
+ ))}
1349
421
  </div>
1350
422
  </div>
1351
423
  </div>
1352
424
  ),
1353
- parameters: {
1354
- docs: {
1355
- description: {
1356
- story:
1357
- "Accessibility features including keyboard navigation, focus management, and best practices for inclusive design.",
1358
- },
1359
- },
1360
- },
1361
425
  }