aural-ui 2.0.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 (308) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +456 -0
  3. package/dist/components/aspect-ratio/AspectRatio.stories.tsx +1327 -0
  4. package/dist/components/aspect-ratio/index.tsx +10 -0
  5. package/dist/components/aspect-ratio/meta.ts +8 -0
  6. package/dist/components/avatar/Avatar.stories.tsx +645 -0
  7. package/dist/components/avatar/index.tsx +50 -0
  8. package/dist/components/avatar/meta.ts +8 -0
  9. package/dist/components/badge/Badge.stories.tsx +169 -0
  10. package/dist/components/badge/index.tsx +28 -0
  11. package/dist/components/badge/meta.ts +6 -0
  12. package/dist/components/banner/Banner.stories.tsx +475 -0
  13. package/dist/components/banner/index.tsx +256 -0
  14. package/dist/components/banner/meta.ts +36 -0
  15. package/dist/components/button/Button.stories.tsx +74 -0
  16. package/dist/components/button/index.tsx +158 -0
  17. package/dist/components/button/meta.ts +33 -0
  18. package/dist/components/card/Card.stories.tsx +377 -0
  19. package/dist/components/card/index.tsx +85 -0
  20. package/dist/components/card/meta.ts +14 -0
  21. package/dist/components/char-count/CharCount.stories.tsx +334 -0
  22. package/dist/components/char-count/index.tsx +51 -0
  23. package/dist/components/char-count/meta.ts +13 -0
  24. package/dist/components/checkbox/Checkbox.stories.tsx +209 -0
  25. package/dist/components/checkbox/index.tsx +34 -0
  26. package/dist/components/checkbox/meta.ts +19 -0
  27. package/dist/components/chip/Chip.stories.tsx +207 -0
  28. package/dist/components/chip/index.tsx +92 -0
  29. package/dist/components/chip/meta.ts +17 -0
  30. package/dist/components/circular-loader/CircularLoader.stories.tsx +741 -0
  31. package/dist/components/circular-loader/index.tsx +138 -0
  32. package/dist/components/circular-loader/meta.ts +11 -0
  33. package/dist/components/collapsible/Collapsible.stories.tsx +319 -0
  34. package/dist/components/collapsible/index.tsx +158 -0
  35. package/dist/components/collapsible/meta.ts +22 -0
  36. package/dist/components/command/Command.stories.tsx +996 -0
  37. package/dist/components/command/index.tsx +324 -0
  38. package/dist/components/command/meta.ts +18 -0
  39. package/dist/components/dialog/Dialog.stories.tsx +963 -0
  40. package/dist/components/dialog/index.tsx +250 -0
  41. package/dist/components/dialog/meta.ts +28 -0
  42. package/dist/components/divider/Divider.stories.tsx +633 -0
  43. package/dist/components/divider/index.tsx +181 -0
  44. package/dist/components/divider/meta.ts +12 -0
  45. package/dist/components/dot-loader/DotLoader.stories.tsx +352 -0
  46. package/dist/components/dot-loader/index.tsx +78 -0
  47. package/dist/components/dot-loader/meta.ts +14 -0
  48. package/dist/components/dropdown/Dropdown.stories.tsx +1210 -0
  49. package/dist/components/dropdown/index.tsx +479 -0
  50. package/dist/components/dropdown/meta.ts +21 -0
  51. package/dist/components/form/Form.stories.tsx +320 -0
  52. package/dist/components/form/index.tsx +183 -0
  53. package/dist/components/form/meta.ts +11 -0
  54. package/dist/components/helper-text/HelperText.stories.tsx +254 -0
  55. package/dist/components/helper-text/index.tsx +102 -0
  56. package/dist/components/helper-text/meta.ts +18 -0
  57. package/dist/components/hover-card/HoverCard.stories.tsx +1328 -0
  58. package/dist/components/hover-card/index.tsx +42 -0
  59. package/dist/components/hover-card/meta.ts +12 -0
  60. package/dist/components/icon-button/IconButton.stories.tsx +252 -0
  61. package/dist/components/icon-button/index.tsx +130 -0
  62. package/dist/components/icon-button/meta.ts +20 -0
  63. package/dist/components/if-else/if-else.stories.tsx +100 -0
  64. package/dist/components/if-else/index.tsx +56 -0
  65. package/dist/components/if-else/meta.ts +6 -0
  66. package/dist/components/index.ts +70 -0
  67. package/dist/components/input/Input.stories.tsx +431 -0
  68. package/dist/components/input/index.tsx +487 -0
  69. package/dist/components/input/meta.ts +28 -0
  70. package/dist/components/label/Label.stories.tsx +200 -0
  71. package/dist/components/label/index.tsx +43 -0
  72. package/dist/components/label/meta.ts +14 -0
  73. package/dist/components/list/List.stories.tsx +963 -0
  74. package/dist/components/list/index.tsx +567 -0
  75. package/dist/components/list/meta.ts +24 -0
  76. package/dist/components/marquee/Marquee.stories.tsx +819 -0
  77. package/dist/components/marquee/index.tsx +107 -0
  78. package/dist/components/marquee/meta.ts +6 -0
  79. package/dist/components/overlay/Overlay.stories.tsx +954 -0
  80. package/dist/components/overlay/index.tsx +58 -0
  81. package/dist/components/overlay/meta.ts +10 -0
  82. package/dist/components/pagination/Pagination.stories.tsx +354 -0
  83. package/dist/components/pagination/index.tsx +455 -0
  84. package/dist/components/pagination/meta.ts +29 -0
  85. package/dist/components/popover/Popover.stories.tsx +1037 -0
  86. package/dist/components/popover/index.tsx +67 -0
  87. package/dist/components/popover/meta.ts +12 -0
  88. package/dist/components/radio/Radio.stories.tsx +146 -0
  89. package/dist/components/radio/index.tsx +41 -0
  90. package/dist/components/radio/meta.ts +19 -0
  91. package/dist/components/resizable/Resizable.stories.tsx +866 -0
  92. package/dist/components/resizable/index.tsx +55 -0
  93. package/dist/components/resizable/meta.ts +12 -0
  94. package/dist/components/scroll-area/ScrollArea.stories.tsx +1104 -0
  95. package/dist/components/scroll-area/index.tsx +55 -0
  96. package/dist/components/scroll-area/meta.ts +8 -0
  97. package/dist/components/search/Search.stories.tsx +678 -0
  98. package/dist/components/search/index.tsx +141 -0
  99. package/dist/components/search/meta.ts +6 -0
  100. package/dist/components/select/Select.stories.tsx +962 -0
  101. package/dist/components/select/index.tsx +512 -0
  102. package/dist/components/select/meta.ts +40 -0
  103. package/dist/components/sheet/Sheet.stories.tsx +1060 -0
  104. package/dist/components/sheet/index.tsx +440 -0
  105. package/dist/components/sheet/meta.ts +38 -0
  106. package/dist/components/skelton/Skelton.stories.tsx +859 -0
  107. package/dist/components/skelton/index.tsx +17 -0
  108. package/dist/components/skelton/meta.ts +6 -0
  109. package/dist/components/slider/Slider.stories.tsx +876 -0
  110. package/dist/components/slider/index.tsx +156 -0
  111. package/dist/components/slider/meta.ts +29 -0
  112. package/dist/components/stepper/Stepper.stories.tsx +639 -0
  113. package/dist/components/stepper/index.tsx +650 -0
  114. package/dist/components/stepper/meta.ts +19 -0
  115. package/dist/components/switch/Switch.stories.tsx +85 -0
  116. package/dist/components/switch/index.tsx +37 -0
  117. package/dist/components/switch/meta.ts +24 -0
  118. package/dist/components/switch-case/SwitchCase.stories.tsx +209 -0
  119. package/dist/components/switch-case/index.tsx +89 -0
  120. package/dist/components/switch-case/meta.ts +6 -0
  121. package/dist/components/table/Table.stories.tsx +1095 -0
  122. package/dist/components/table/index.tsx +113 -0
  123. package/dist/components/table/meta.ts +20 -0
  124. package/dist/components/tabs/Tabs.stories.tsx +1379 -0
  125. package/dist/components/tabs/index.tsx +186 -0
  126. package/dist/components/tabs/meta.ts +25 -0
  127. package/dist/components/tag/Tag.stories.tsx +625 -0
  128. package/dist/components/tag/index.tsx +320 -0
  129. package/dist/components/tag/meta.ts +52 -0
  130. package/dist/components/textarea/TextArea.stories.tsx +723 -0
  131. package/dist/components/textarea/index.tsx +480 -0
  132. package/dist/components/textarea/meta.ts +23 -0
  133. package/dist/components/toast/Toast.stories.tsx +1427 -0
  134. package/dist/components/toast/index.tsx +26 -0
  135. package/dist/components/toast/meta.ts +19 -0
  136. package/dist/components/toggle/Toggle.stories.tsx +1093 -0
  137. package/dist/components/toggle/index.tsx +44 -0
  138. package/dist/components/toggle/meta.ts +19 -0
  139. package/dist/components/tooltip/Tooltip.stories.tsx +1548 -0
  140. package/dist/components/tooltip/index.tsx +304 -0
  141. package/dist/components/tooltip/meta.ts +21 -0
  142. package/dist/components/typography/Typography.stories.tsx +197 -0
  143. package/dist/components/typography/index.tsx +184 -0
  144. package/dist/components/typography/meta.ts +38 -0
  145. package/dist/fonts/LabGrotesque-Regular.ttf +0 -0
  146. package/dist/fonts/LabGrotesqueTRIAL-Bold.otf +0 -0
  147. package/dist/fonts/LabGrotesqueTRIAL-Light.otf +0 -0
  148. package/dist/fonts/LabGrotesqueTRIAL-Medium.otf +0 -0
  149. package/dist/fonts/LabGrotesqueTRIAL-Regular.otf +0 -0
  150. package/dist/fonts/PPSupplySans-Regular (1).otf +0 -0
  151. package/dist/fonts/PPSupplySans-Regular.otf +0 -0
  152. package/dist/fonts/PPSupplySans-Ultralight.otf +0 -0
  153. package/dist/hooks/index.ts +3 -0
  154. package/dist/hooks/use-previous/UsePrevious.stories.tsx +997 -0
  155. package/dist/hooks/use-previous/index.ts +15 -0
  156. package/dist/hooks/use-previous/meta.ts +6 -0
  157. package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +983 -0
  158. package/dist/hooks/use-standalone-pagination/index.ts +146 -0
  159. package/dist/hooks/use-standalone-pagination/meta.ts +6 -0
  160. package/dist/icons/Icons.stories.tsx +29 -0
  161. package/dist/icons/alert-icon/AlertIcon.stories.tsx +991 -0
  162. package/dist/icons/alert-icon/index.tsx +48 -0
  163. package/dist/icons/alert-icon/meta.ts +8 -0
  164. package/dist/icons/all-icons.tsx +738 -0
  165. package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +1031 -0
  166. package/dist/icons/angle-down-icon/index.tsx +25 -0
  167. package/dist/icons/angle-down-icon/meta.ts +8 -0
  168. package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +1080 -0
  169. package/dist/icons/arrow-box-left-icon/index.tsx +24 -0
  170. package/dist/icons/arrow-box-left-icon/meta.ts +8 -0
  171. package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +1151 -0
  172. package/dist/icons/arrow-right-icon/index.tsx +26 -0
  173. package/dist/icons/arrow-right-icon/meta.ts +8 -0
  174. package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +1273 -0
  175. package/dist/icons/arrow-right-up-icon/index.tsx +24 -0
  176. package/dist/icons/arrow-right-up-icon/meta.ts +8 -0
  177. package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +670 -0
  178. package/dist/icons/art-board-icon/index.tsx +24 -0
  179. package/dist/icons/art-board-icon/meta.ts +7 -0
  180. package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +1244 -0
  181. package/dist/icons/audio-bar-icon/index.tsx +19 -0
  182. package/dist/icons/audio-bar-icon/meta.ts +8 -0
  183. package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +1239 -0
  184. package/dist/icons/bubble-check-icon/index.tsx +24 -0
  185. package/dist/icons/bubble-check-icon/meta.ts +8 -0
  186. package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +1228 -0
  187. package/dist/icons/bubble-crossed-icon/index.tsx +24 -0
  188. package/dist/icons/bubble-crossed-icon/meta.ts +8 -0
  189. package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +912 -0
  190. package/dist/icons/bubble-sparkle-icon/index.tsx +26 -0
  191. package/dist/icons/bubble-sparkle-icon/meta.ts +8 -0
  192. package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +1021 -0
  193. package/dist/icons/chevron-double-left-icon/index.tsx +34 -0
  194. package/dist/icons/chevron-double-left-icon/meta.ts +8 -0
  195. package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +1021 -0
  196. package/dist/icons/chevron-double-right-icon/index.tsx +34 -0
  197. package/dist/icons/chevron-double-right-icon/meta.ts +8 -0
  198. package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +1001 -0
  199. package/dist/icons/chevron-down-icon/index.tsx +27 -0
  200. package/dist/icons/chevron-down-icon/meta.ts +8 -0
  201. package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +1029 -0
  202. package/dist/icons/chevron-left-icon/index.tsx +27 -0
  203. package/dist/icons/chevron-left-icon/meta.ts +8 -0
  204. package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +1021 -0
  205. package/dist/icons/chevron-right-icon/index.tsx +27 -0
  206. package/dist/icons/chevron-right-icon/meta.ts +8 -0
  207. package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +1036 -0
  208. package/dist/icons/chevron-up-icon/index.tsx +27 -0
  209. package/dist/icons/chevron-up-icon/meta.ts +8 -0
  210. package/dist/icons/command-icon/CommandIcon.stories.tsx +1098 -0
  211. package/dist/icons/command-icon/index.tsx +24 -0
  212. package/dist/icons/command-icon/meta.ts +8 -0
  213. package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +1061 -0
  214. package/dist/icons/cross-circle-icon/index.tsx +23 -0
  215. package/dist/icons/cross-circle-icon/meta.ts +8 -0
  216. package/dist/icons/cross-icon/CrossIcon.stories.tsx +1027 -0
  217. package/dist/icons/cross-icon/index.tsx +24 -0
  218. package/dist/icons/cross-icon/meta.ts +8 -0
  219. package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +1092 -0
  220. package/dist/icons/edit-big-icon/index.tsx +22 -0
  221. package/dist/icons/edit-big-icon/meta.ts +8 -0
  222. package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +1090 -0
  223. package/dist/icons/eye-close-icon/index.tsx +26 -0
  224. package/dist/icons/eye-close-icon/meta.ts +8 -0
  225. package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +1098 -0
  226. package/dist/icons/eye-open-icon/index.tsx +24 -0
  227. package/dist/icons/eye-open-icon/meta.ts +8 -0
  228. package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +1071 -0
  229. package/dist/icons/feature-shine-icon/index.tsx +29 -0
  230. package/dist/icons/feature-shine-icon/meta.ts +8 -0
  231. package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +1115 -0
  232. package/dist/icons/file-chart-icon/index.tsx +24 -0
  233. package/dist/icons/file-chart-icon/meta.ts +8 -0
  234. package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +668 -0
  235. package/dist/icons/file-text-icon/index.tsx +24 -0
  236. package/dist/icons/file-text-icon/meta.ts +8 -0
  237. package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +1239 -0
  238. package/dist/icons/grip-vertical-icon/index.tsx +28 -0
  239. package/dist/icons/grip-vertical-icon/meta.ts +8 -0
  240. package/dist/icons/image-icon/ImageIcon.stories.tsx +1181 -0
  241. package/dist/icons/image-icon/index.tsx +24 -0
  242. package/dist/icons/image-icon/meta.ts +8 -0
  243. package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +1248 -0
  244. package/dist/icons/import-folder-icon/index.tsx +22 -0
  245. package/dist/icons/import-folder-icon/meta.ts +8 -0
  246. package/dist/icons/index.ts +46 -0
  247. package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +1272 -0
  248. package/dist/icons/light-bulb-simple-icon/index.tsx +24 -0
  249. package/dist/icons/light-bulb-simple-icon/meta.ts +8 -0
  250. package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +1245 -0
  251. package/dist/icons/magic-book-icon/index.tsx +32 -0
  252. package/dist/icons/magic-book-icon/meta.ts +8 -0
  253. package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +1251 -0
  254. package/dist/icons/maintenance-icon/index.tsx +23 -0
  255. package/dist/icons/maintenance-icon/meta.ts +8 -0
  256. package/dist/icons/message-icon/MessageIcon.stories.tsx +595 -0
  257. package/dist/icons/message-icon/index.tsx +30 -0
  258. package/dist/icons/message-icon/meta.ts +8 -0
  259. package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +1245 -0
  260. package/dist/icons/move-horizontal-icon/index.tsx +23 -0
  261. package/dist/icons/move-horizontal-icon/meta.ts +8 -0
  262. package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +1196 -0
  263. package/dist/icons/move-vertical-icon/index.tsx +23 -0
  264. package/dist/icons/move-vertical-icon/meta.ts +8 -0
  265. package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +1167 -0
  266. package/dist/icons/page-search-icon/index.tsx +21 -0
  267. package/dist/icons/page-search-icon/meta.ts +8 -0
  268. package/dist/icons/pencil-icon/PencilIcon.stories.tsx +1131 -0
  269. package/dist/icons/pencil-icon/index.tsx +21 -0
  270. package/dist/icons/pencil-icon/meta.ts +8 -0
  271. package/dist/icons/plus-icon/PlusIcon.stories.tsx +1151 -0
  272. package/dist/icons/plus-icon/index.tsx +24 -0
  273. package/dist/icons/plus-icon/meta.ts +8 -0
  274. package/dist/icons/search-icon/SearchIcon.stories.tsx +1181 -0
  275. package/dist/icons/search-icon/index.tsx +24 -0
  276. package/dist/icons/search-icon/meta.ts +8 -0
  277. package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +1167 -0
  278. package/dist/icons/site-logo-icon/index.tsx +79 -0
  279. package/dist/icons/site-logo-icon/meta.ts +8 -0
  280. package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +637 -0
  281. package/dist/icons/spinner-gradient-icon/index.tsx +53 -0
  282. package/dist/icons/spinner-gradient-icon/meta.ts +8 -0
  283. package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +644 -0
  284. package/dist/icons/spinner-solid-icon/index.tsx +59 -0
  285. package/dist/icons/spinner-solid-icon/meta.ts +8 -0
  286. package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +736 -0
  287. package/dist/icons/spinner-solid-neutral-icon/index.tsx +53 -0
  288. package/dist/icons/spinner-solid-neutral-icon/meta.ts +8 -0
  289. package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +1204 -0
  290. package/dist/icons/tick-circle-icon/index.tsx +23 -0
  291. package/dist/icons/tick-circle-icon/meta.ts +8 -0
  292. package/dist/icons/tick-icon/TickIcon.stories.tsx +1340 -0
  293. package/dist/icons/tick-icon/index.tsx +24 -0
  294. package/dist/icons/tick-icon/meta.ts +8 -0
  295. package/dist/icons/trash-icon/TrashIcon.stories.tsx +996 -0
  296. package/dist/icons/trash-icon/index.tsx +24 -0
  297. package/dist/icons/trash-icon/meta.ts +8 -0
  298. package/dist/icons/upload-icon/UploadIcon.stories.tsx +947 -0
  299. package/dist/icons/upload-icon/index.tsx +24 -0
  300. package/dist/icons/upload-icon/meta.ts +8 -0
  301. package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +1045 -0
  302. package/dist/icons/vertical-menu-icon/index.tsx +27 -0
  303. package/dist/icons/vertical-menu-icon/meta.ts +8 -0
  304. package/dist/index.d.ts +6 -0
  305. package/dist/index.js +206 -0
  306. package/dist/lib/utils.ts +6 -0
  307. package/dist/styles/aural-theme.css +1008 -0
  308. package/package.json +142 -0
@@ -0,0 +1,1427 @@
1
+ import React from "react"
2
+ import { Button } from "@components/button"
3
+ import type { Meta, StoryObj } from "@storybook/react"
4
+ import { toast } from "sonner"
5
+
6
+ import { Toaster } from "."
7
+
8
+ const meta: Meta<typeof Toaster> = {
9
+ title: "Components/UI/Toast",
10
+ component: Toaster,
11
+ parameters: {
12
+ layout: "fullscreen",
13
+ docs: {
14
+ description: {
15
+ component: `
16
+ A toast notification system built on top of Sonner for displaying temporary messages to users.
17
+ Provides a clean, accessible way to show success messages, errors, loading states, and other notifications.
18
+
19
+ ## Features
20
+ - Built on Sonner for excellent performance and accessibility
21
+ - Multiple toast types (success, error, warning, info, loading)
22
+ - Customizable styling with design tokens
23
+ - Action buttons and dismiss functionality
24
+ - Promise-based toasts for async operations
25
+ - Rich content support (icons, descriptions, custom content)
26
+ - Keyboard navigation and screen reader support
27
+ - Automatic dismiss with customizable duration
28
+ - Positioning options (top, bottom, left, right)
29
+ - Swipe to dismiss on mobile
30
+ - Queue management for multiple toasts
31
+
32
+ ## Installation
33
+ \`\`\`bash
34
+ npm install sonner
35
+ \`\`\`
36
+
37
+ ## Usage
38
+
39
+ ### Basic Setup
40
+ First, add the Toaster component to your app root:
41
+
42
+ \`\`\`tsx
43
+ import { Toaster } from '@/ui/components/toast'
44
+
45
+ export default function App() {
46
+ return (
47
+ <>
48
+ {/* Your app content */}
49
+ <Toaster />
50
+ </>
51
+ )
52
+ }
53
+ \`\`\`
54
+
55
+ ### Triggering Toasts
56
+ \`\`\`tsx
57
+ import { toast } from 'sonner'
58
+
59
+ // Basic toast
60
+ toast('Hello World!')
61
+
62
+ // Success toast
63
+ toast.success('Profile updated successfully!')
64
+
65
+ // Error toast
66
+ toast.error('Something went wrong')
67
+
68
+ // Warning toast
69
+ toast.warning('Please save your changes')
70
+
71
+ // Info toast
72
+ toast.info('New version available')
73
+
74
+ // Loading toast
75
+ toast.loading('Uploading file...')
76
+
77
+ // Toast with description
78
+ toast('Event Created', {
79
+ description: 'Your event has been created successfully'
80
+ })
81
+
82
+ // Toast with action
83
+ toast('Event Created', {
84
+ action: {
85
+ label: 'View',
86
+ onClick: () => console.log('View clicked')
87
+ }
88
+ })
89
+
90
+ // Promise-based toast
91
+ const promise = fetch('/api/data')
92
+ toast.promise(promise, {
93
+ loading: 'Loading data...',
94
+ success: 'Data loaded successfully!',
95
+ error: 'Failed to load data'
96
+ })
97
+ \`\`\`
98
+
99
+ ### Custom Styling
100
+ The component uses your design system tokens and can be customized through the \`toastOptions\` prop:
101
+
102
+ \`\`\`tsx
103
+ <Toaster
104
+ position="top-right"
105
+ toastOptions={{
106
+ duration: 4000,
107
+ style: {
108
+ background: 'var(--color-fm-surface-primary)',
109
+ color: 'var(--color-fm-text-primary)',
110
+ }
111
+ }}
112
+ />
113
+ \`\`\`
114
+ `,
115
+ },
116
+ },
117
+ },
118
+ tags: ["autodocs"],
119
+ argTypes: {
120
+ position: {
121
+ control: { type: "select" },
122
+ options: [
123
+ "top-left",
124
+ "top-center",
125
+ "top-right",
126
+ "bottom-left",
127
+ "bottom-center",
128
+ "bottom-right",
129
+ ],
130
+ description: "Position where toasts appear on screen",
131
+ table: {
132
+ type: {
133
+ summary:
134
+ '"top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right"',
135
+ },
136
+ defaultValue: { summary: '"bottom-right"' },
137
+ },
138
+ },
139
+ expand: {
140
+ control: { type: "boolean" },
141
+ description: "Whether toasts should expand when hovered",
142
+ table: {
143
+ type: { summary: "boolean" },
144
+ defaultValue: { summary: "false" },
145
+ },
146
+ },
147
+ richColors: {
148
+ control: { type: "boolean" },
149
+ description: "Whether to use rich colors for different toast types",
150
+ table: {
151
+ type: { summary: "boolean" },
152
+ defaultValue: { summary: "false" },
153
+ },
154
+ },
155
+ closeButton: {
156
+ control: { type: "boolean" },
157
+ description: "Whether to show close button on toasts",
158
+ table: {
159
+ type: { summary: "boolean" },
160
+ defaultValue: { summary: "false" },
161
+ },
162
+ },
163
+ theme: {
164
+ control: { type: "select" },
165
+ options: ["light", "dark", "system"],
166
+ description: "Color theme for toasts",
167
+ table: {
168
+ type: { summary: '"light" | "dark" | "system"' },
169
+ defaultValue: { summary: '"system"' },
170
+ },
171
+ },
172
+ toastOptions: {
173
+ control: { type: "object" },
174
+ description: "Default options for all toasts",
175
+ table: {
176
+ type: { summary: "ToastOptions" },
177
+ defaultValue: { summary: "{}" },
178
+ },
179
+ },
180
+ offset: {
181
+ control: { type: "text" },
182
+ description: "Offset from screen edge (CSS value)",
183
+ table: {
184
+ type: { summary: "string | number" },
185
+ defaultValue: { summary: '"32px"' },
186
+ },
187
+ },
188
+ dir: {
189
+ control: { type: "select" },
190
+ options: ["ltr", "rtl"],
191
+ description: "Text direction for RTL support",
192
+ table: {
193
+ type: { summary: '"ltr" | "rtl"' },
194
+ defaultValue: { summary: '"ltr"' },
195
+ },
196
+ },
197
+ },
198
+ decorators: [
199
+ (Story) => (
200
+ <div style={{ height: "80vh", padding: "2rem" }}>
201
+ <Story />
202
+ <Toaster />
203
+ </div>
204
+ ),
205
+ ],
206
+ }
207
+
208
+ export default meta
209
+ type Story = StoryObj<typeof meta>
210
+
211
+ export const Default: Story = {
212
+ args: {
213
+ position: "bottom-right",
214
+ expand: false,
215
+ richColors: false,
216
+ closeButton: false,
217
+ },
218
+ render: (args) => (
219
+ <div className="text-fm-primary space-y-4">
220
+ <h2 className="text-xl font-semibold">Toast Examples</h2>
221
+ <p>
222
+ Click the buttons below to see different types of toast notifications.
223
+ </p>
224
+
225
+ <div className="flex flex-wrap gap-2">
226
+ <Button onClick={() => toast("Hello World!")}>Basic Toast</Button>
227
+
228
+ <Button
229
+ onClick={() => toast.success("Operation completed successfully!")}
230
+ >
231
+ Success Toast
232
+ </Button>
233
+
234
+ <Button onClick={() => toast.error("Something went wrong")}>
235
+ Error Toast
236
+ </Button>
237
+ </div>
238
+
239
+ <Toaster {...args} />
240
+ </div>
241
+ ),
242
+ }
243
+
244
+ export const ToastTypes: Story = {
245
+ render: () => (
246
+ <div className="text-fm-primary space-y-4">
247
+ <h2 className="text-xl font-semibold">Toast Types</h2>
248
+ <p>Different types of toast notifications for various use cases.</p>
249
+
250
+ <div className="grid max-w-lg grid-cols-2 gap-3">
251
+ <Button onClick={() => toast("Default message")} variant="outline">
252
+ Default
253
+ </Button>
254
+
255
+ <Button onClick={() => toast.success("Success message")}>
256
+ Success
257
+ </Button>
258
+
259
+ <Button onClick={() => toast.error("Error message")}>Error</Button>
260
+
261
+ <Button onClick={() => toast.warning("Warning message")}>
262
+ Warning
263
+ </Button>
264
+
265
+ <Button onClick={() => toast.info("Info message")}>Info</Button>
266
+
267
+ <Button onClick={() => toast.loading("Loading...")}>Loading</Button>
268
+ </div>
269
+ </div>
270
+ ),
271
+ parameters: {
272
+ docs: {
273
+ description: {
274
+ story:
275
+ "Different toast types available: default, success, error, warning, info, and loading.",
276
+ },
277
+ },
278
+ },
279
+ }
280
+
281
+ export const WithDescription: Story = {
282
+ render: () => (
283
+ <div className="text-fm-primary space-y-4">
284
+ <h2 className="text-xl font-semibold">Toasts with Descriptions</h2>
285
+ <p>Add additional context with description text.</p>
286
+
287
+ <div className="flex flex-wrap gap-2">
288
+ <Button
289
+ onClick={() =>
290
+ toast("Profile Updated", {
291
+ description:
292
+ "Your profile information has been saved successfully.",
293
+ })
294
+ }
295
+ >
296
+ With Description
297
+ </Button>
298
+
299
+ <Button
300
+ onClick={() =>
301
+ toast.success("File Uploaded", {
302
+ description: "document.pdf has been uploaded to the cloud.",
303
+ })
304
+ }
305
+ >
306
+ Success with Description
307
+ </Button>
308
+
309
+ <Button
310
+ onClick={() =>
311
+ toast.error("Upload Failed", {
312
+ description: "The file could not be uploaded. Please try again.",
313
+ })
314
+ }
315
+ >
316
+ Error with Description
317
+ </Button>
318
+ </div>
319
+ </div>
320
+ ),
321
+ parameters: {
322
+ docs: {
323
+ description: {
324
+ story:
325
+ "Toasts can include additional description text for more context.",
326
+ },
327
+ },
328
+ },
329
+ }
330
+
331
+ export const WithActions: Story = {
332
+ render: () => (
333
+ <div className="text-fm-primary space-y-4">
334
+ <h2 className="text-xl font-semibold">Toasts with Actions</h2>
335
+ <p>Include action buttons for user interaction.</p>
336
+
337
+ <div className="flex flex-wrap gap-2">
338
+ <Button
339
+ onClick={() =>
340
+ toast("Event Created", {
341
+ description: "Your event has been scheduled for tomorrow.",
342
+ action: {
343
+ label: "View",
344
+ onClick: () => toast("Viewing event..."),
345
+ },
346
+ })
347
+ }
348
+ >
349
+ With Action
350
+ </Button>
351
+
352
+ <Button
353
+ onClick={() =>
354
+ toast("Changes Saved", {
355
+ description: "Your document has been saved to the cloud.",
356
+ action: {
357
+ label: "Undo",
358
+ onClick: () => toast.info("Changes undone"),
359
+ },
360
+ })
361
+ }
362
+ >
363
+ With Undo Action
364
+ </Button>
365
+
366
+ <Button
367
+ onClick={() =>
368
+ toast("New Message", {
369
+ description: "You have received a new message from John.",
370
+ action: {
371
+ label: "Reply",
372
+ onClick: () => toast("Opening reply..."),
373
+ },
374
+ })
375
+ }
376
+ >
377
+ With Reply Action
378
+ </Button>
379
+ </div>
380
+ </div>
381
+ ),
382
+ parameters: {
383
+ docs: {
384
+ description: {
385
+ story:
386
+ "Toasts can include action buttons for immediate user interaction.",
387
+ },
388
+ },
389
+ },
390
+ }
391
+
392
+ export const PromiseToasts: Story = {
393
+ render: () => {
394
+ const simulateApiCall = (shouldFail = false, delay = 2000) => {
395
+ return new Promise((resolve, reject) => {
396
+ setTimeout(() => {
397
+ if (shouldFail) {
398
+ reject(new Error("API call failed"))
399
+ } else {
400
+ resolve("Data loaded successfully")
401
+ }
402
+ }, delay)
403
+ })
404
+ }
405
+
406
+ return (
407
+ <div className="text-fm-primary space-y-4">
408
+ <h2 className="text-xl font-semibold">Promise-based Toasts</h2>
409
+ <p>Automatically update toasts based on promise resolution.</p>
410
+
411
+ <div className="flex flex-wrap gap-2">
412
+ <Button
413
+ onClick={() => {
414
+ const promise = simulateApiCall(false, 2000)
415
+ toast.promise(promise, {
416
+ loading: "Loading data...",
417
+ success: "Data loaded successfully!",
418
+ error: "Failed to load data",
419
+ })
420
+ }}
421
+ >
422
+ Successful Promise
423
+ </Button>
424
+
425
+ <Button
426
+ variant="outline"
427
+ onClick={() => {
428
+ const promise = simulateApiCall(true, 1500)
429
+ toast.promise(promise, {
430
+ loading: "Uploading file...",
431
+ success: "File uploaded successfully!",
432
+ error: "Upload failed",
433
+ })
434
+ }}
435
+ >
436
+ Failed Promise
437
+ </Button>
438
+
439
+ <Button
440
+ onClick={() => {
441
+ const promise = simulateApiCall(false, 3000)
442
+ toast.promise(promise, {
443
+ loading: "Processing payment...",
444
+ success: (data) => `Payment processed: ${data}`,
445
+ error: (error) => `Payment failed: ${error.message}`,
446
+ })
447
+ }}
448
+ >
449
+ Custom Messages
450
+ </Button>
451
+ </div>
452
+ </div>
453
+ )
454
+ },
455
+ parameters: {
456
+ docs: {
457
+ description: {
458
+ story:
459
+ "Use promise-based toasts for async operations. The toast automatically updates based on promise state.",
460
+ },
461
+ },
462
+ },
463
+ }
464
+
465
+ export const CustomDuration: Story = {
466
+ render: () => (
467
+ <div className="text-fm-primary space-y-4">
468
+ <h2 className="text-xl font-semibold">Custom Duration</h2>
469
+ <p>Control how long toasts stay visible.</p>
470
+
471
+ <div className="flex flex-wrap gap-2">
472
+ <Button onClick={() => toast("Quick message", { duration: 1000 })}>
473
+ 1 Second
474
+ </Button>
475
+
476
+ <Button onClick={() => toast("Normal message", { duration: 4000 })}>
477
+ 4 Seconds (Default)
478
+ </Button>
479
+
480
+ <Button onClick={() => toast("Long message", { duration: 10000 })}>
481
+ 10 Seconds
482
+ </Button>
483
+
484
+ <Button
485
+ onClick={() =>
486
+ toast("Persistent message", {
487
+ description: "Your event has been scheduled for tomorrow.",
488
+ action: {
489
+ label: "View",
490
+ onClick: () => toast("Viewing event..."),
491
+ },
492
+ cancel: {
493
+ label: "Cancel",
494
+ onClick: () => console.log("Cancel!"),
495
+ },
496
+ duration: Infinity,
497
+ })
498
+ }
499
+ >
500
+ Persistent (Manual dismiss)
501
+ </Button>
502
+ </div>
503
+ </div>
504
+ ),
505
+ parameters: {
506
+ docs: {
507
+ description: {
508
+ story:
509
+ "Customize how long toasts remain visible. Use Infinity for persistent toasts.",
510
+ },
511
+ },
512
+ },
513
+ }
514
+
515
+ export const Positioning: Story = {
516
+ render: () => (
517
+ <div className="text-fm-primary space-y-4">
518
+ <h2 className="text-xl font-semibold">Toast Positioning</h2>
519
+ <p>Try different positions for the toast container.</p>
520
+
521
+ <div className="grid max-w-md grid-cols-3 gap-2">
522
+ <Button
523
+ size="sm"
524
+ onClick={() => {
525
+ toast.dismiss()
526
+ toast("Top Left", { duration: 3000 })
527
+ }}
528
+ >
529
+ Top Left
530
+ </Button>
531
+
532
+ <Button
533
+ size="sm"
534
+ onClick={() => {
535
+ toast.dismiss()
536
+ toast("Top Center", { duration: 3000 })
537
+ }}
538
+ >
539
+ Top Center
540
+ </Button>
541
+
542
+ <Button
543
+ size="sm"
544
+ onClick={() => {
545
+ toast.dismiss()
546
+ toast("Top Right", { duration: 3000 })
547
+ }}
548
+ >
549
+ Top Right
550
+ </Button>
551
+
552
+ <Button
553
+ size="sm"
554
+ onClick={() => {
555
+ toast.dismiss()
556
+ toast("Bottom Left", { duration: 3000 })
557
+ }}
558
+ >
559
+ Bottom Left
560
+ </Button>
561
+
562
+ <Button
563
+ size="sm"
564
+ onClick={() => {
565
+ toast.dismiss()
566
+ toast("Bottom Center", { duration: 3000 })
567
+ }}
568
+ >
569
+ Bottom Center
570
+ </Button>
571
+
572
+ <Button
573
+ size="sm"
574
+ onClick={() => {
575
+ toast.dismiss()
576
+ toast("Bottom Right", { duration: 3000 })
577
+ }}
578
+ >
579
+ Bottom Right
580
+ </Button>
581
+ </div>
582
+
583
+ <p className="text-sm">
584
+ Note: Change the position prop on the Toaster component to see different
585
+ positions.
586
+ </p>
587
+ </div>
588
+ ),
589
+ parameters: {
590
+ docs: {
591
+ description: {
592
+ story:
593
+ "Toasts can be positioned in different areas of the screen. Configure via the position prop on Toaster.",
594
+ },
595
+ },
596
+ },
597
+ }
598
+
599
+ export const RichColors: Story = {
600
+ args: {
601
+ richColors: true,
602
+ },
603
+ render: (args) => (
604
+ <div className="text-fm-primary space-y-4">
605
+ <h2 className="text-xl font-semibold">Rich Colors</h2>
606
+ <p>Enable rich colors for more vibrant toast notifications.</p>
607
+
608
+ <div className="flex flex-wrap gap-2">
609
+ <Button onClick={() => toast.success("Success with rich colors!")}>
610
+ Success
611
+ </Button>
612
+
613
+ <Button onClick={() => toast.error("Error with rich colors!")}>
614
+ Error
615
+ </Button>
616
+
617
+ <Button onClick={() => toast.warning("Warning with rich colors!")}>
618
+ Warning
619
+ </Button>
620
+
621
+ <Button onClick={() => toast.info("Info with rich colors!")}>
622
+ Info
623
+ </Button>
624
+ </div>
625
+
626
+ <Toaster {...args} />
627
+ </div>
628
+ ),
629
+ parameters: {
630
+ docs: {
631
+ description: {
632
+ story:
633
+ "Enable richColors prop for more vibrant, colorful toast notifications.",
634
+ },
635
+ },
636
+ },
637
+ }
638
+
639
+ export const WithCloseButton: Story = {
640
+ args: {
641
+ closeButton: true,
642
+ },
643
+ render: (args) => (
644
+ <div className="text-fm-primary space-y-4">
645
+ <h2 className="text-xl font-semibold">With Close Button</h2>
646
+ <p>Show close buttons on all toasts for manual dismissal.</p>
647
+
648
+ <div className="flex flex-wrap gap-2">
649
+ <Button onClick={() => toast("Message with close button")}>
650
+ Show Toast
651
+ </Button>
652
+
653
+ <Button onClick={() => toast.success("Success with close button")}>
654
+ Show Success
655
+ </Button>
656
+
657
+ <Button
658
+ onClick={() => toast("Persistent with close", { duration: Infinity })}
659
+ >
660
+ Persistent Toast
661
+ </Button>
662
+ </div>
663
+
664
+ <Toaster {...args} />
665
+ </div>
666
+ ),
667
+ parameters: {
668
+ docs: {
669
+ description: {
670
+ story: "Enable closeButton prop to show close buttons on all toasts.",
671
+ },
672
+ },
673
+ },
674
+ }
675
+
676
+ export const CustomStyling: Story = {
677
+ render: () => (
678
+ <div className="text-fm-primary space-y-4">
679
+ <h2 className="text-xl font-semibold">Custom Styling</h2>
680
+ <p>Customize toast appearance with inline styles and class names.</p>
681
+
682
+ <div className="flex flex-wrap gap-2">
683
+ <Button
684
+ onClick={() =>
685
+ toast("Custom styled toast", {
686
+ style: {
687
+ background: "#1f2937",
688
+ color: "#f9fafb",
689
+ border: "1px solid #374151",
690
+ },
691
+ })
692
+ }
693
+ >
694
+ Dark Style
695
+ </Button>
696
+
697
+ <Button
698
+ onClick={() =>
699
+ toast.success("Gradient success", {
700
+ style: {
701
+ background: "linear-gradient(to right, #10b981, #059669)",
702
+ color: "white",
703
+ },
704
+ })
705
+ }
706
+ >
707
+ Gradient Style
708
+ </Button>
709
+
710
+ <Button
711
+ onClick={() =>
712
+ toast("Large toast", {
713
+ className: "text-lg p-6",
714
+ style: {
715
+ minHeight: "80px",
716
+ },
717
+ })
718
+ }
719
+ >
720
+ Large Size
721
+ </Button>
722
+ </div>
723
+ </div>
724
+ ),
725
+ parameters: {
726
+ docs: {
727
+ description: {
728
+ story:
729
+ "Customize individual toasts with inline styles and CSS classes.",
730
+ },
731
+ },
732
+ },
733
+ }
734
+
735
+ export const ToastManagement: Story = {
736
+ render: () => {
737
+ const [toastCount, setToastCount] = React.useState(0)
738
+
739
+ return (
740
+ <div className="text-fm-primary space-y-4">
741
+ <h2 className="text-xl font-semibold">Toast Management</h2>
742
+ <p>Programmatically control toast behavior.</p>
743
+
744
+ <div className="flex flex-wrap gap-2">
745
+ <Button
746
+ onClick={() => {
747
+ setToastCount((count) => count + 1)
748
+ toast(`Toast #${toastCount + 1}`)
749
+ }}
750
+ >
751
+ Add Toast
752
+ </Button>
753
+
754
+ <Button variant="outline" onClick={() => toast.dismiss()}>
755
+ Dismiss All
756
+ </Button>
757
+
758
+ <Button
759
+ variant="outline"
760
+ onClick={() => {
761
+ // Store toast ID for later dismissal
762
+ const toastId = toast("Dismissible toast", {
763
+ duration: Infinity,
764
+ action: {
765
+ label: "Dismiss",
766
+ onClick: () => toast.dismiss(toastId),
767
+ },
768
+ })
769
+ }}
770
+ >
771
+ Dismissible Toast
772
+ </Button>
773
+
774
+ <Button
775
+ onClick={() => {
776
+ // Queue multiple toasts
777
+ toast("First toast")
778
+ setTimeout(() => toast("Second toast"), 500)
779
+ setTimeout(() => toast("Third toast"), 1000)
780
+ }}
781
+ >
782
+ Queue Multiple
783
+ </Button>
784
+ </div>
785
+
786
+ <div className="text-fm-primary text-sm">
787
+ <p>Toast count: {toastCount}</p>
788
+ </div>
789
+ </div>
790
+ )
791
+ },
792
+ parameters: {
793
+ docs: {
794
+ description: {
795
+ story:
796
+ "Manage toasts programmatically with dismiss, queuing, and ID-based control.",
797
+ },
798
+ },
799
+ },
800
+ }
801
+
802
+ export const AccessibilityFeatures: Story = {
803
+ render: () => (
804
+ <div className="text-fm-primary space-y-4">
805
+ <h2 className="text-xl font-semibold">Accessibility Features</h2>
806
+ <p>Toast notifications are built with accessibility in mind.</p>
807
+
808
+ <div className="space-y-3">
809
+ <div className="rounded-lg bg-blue-50 p-4">
810
+ <h3 className="font-medium text-blue-900">Keyboard Navigation</h3>
811
+ <p className="text-sm text-blue-700">
812
+ Use Tab to focus toasts, Enter/Space to activate actions, Escape to
813
+ dismiss.
814
+ </p>
815
+ </div>
816
+
817
+ <div className="rounded-lg bg-green-50 p-4">
818
+ <h3 className="font-medium text-green-900">Screen Reader Support</h3>
819
+ <p className="text-sm text-green-700">
820
+ Toasts are announced to screen readers with proper ARIA labels.
821
+ </p>
822
+ </div>
823
+
824
+ <div className="rounded-lg bg-purple-50 p-4">
825
+ <h3 className="font-medium text-purple-900">Reduced Motion</h3>
826
+ <p className="text-sm text-purple-700">
827
+ Respects user's motion preferences for animations.
828
+ </p>
829
+ </div>
830
+ </div>
831
+
832
+ <div className="flex gap-2">
833
+ <Button
834
+ onClick={() =>
835
+ toast.success("Accessible success message", {
836
+ description: "This toast is fully accessible to screen readers",
837
+ })
838
+ }
839
+ >
840
+ Try Accessible Toast
841
+ </Button>
842
+ </div>
843
+ </div>
844
+ ),
845
+ parameters: {
846
+ docs: {
847
+ description: {
848
+ story:
849
+ "Toast component includes comprehensive accessibility features including keyboard navigation, screen reader support, and reduced motion respect.",
850
+ },
851
+ },
852
+ },
853
+ }
854
+
855
+ export const RealWorldExamples: Story = {
856
+ render: () => {
857
+ const handleSave = () => {
858
+ toast.loading("Saving changes...")
859
+
860
+ // Simulate API call
861
+ setTimeout(() => {
862
+ toast.dismiss()
863
+ toast.success("Changes saved successfully!", {
864
+ description: "Your document has been updated.",
865
+ action: {
866
+ label: "View",
867
+ onClick: () => toast("Opening document..."),
868
+ },
869
+ })
870
+ }, 2000)
871
+ }
872
+
873
+ const handleDelete = () => {
874
+ toast("Are you sure?", {
875
+ description: "This action cannot be undone.",
876
+ action: {
877
+ label: "Delete",
878
+ onClick: () => {
879
+ toast.dismiss()
880
+ toast.error("Item deleted", {
881
+ description: "The item has been permanently removed.",
882
+ })
883
+ },
884
+ },
885
+ })
886
+ }
887
+
888
+ const handleUpload = () => {
889
+ const files = ["document.pdf", "image.jpg", "data.csv"]
890
+ let completed = 0
891
+
892
+ files.forEach((file, index) => {
893
+ setTimeout(
894
+ () => {
895
+ completed++
896
+ if (completed === files.length) {
897
+ toast.success("All files uploaded!", {
898
+ description: `Successfully uploaded ${files.length} files.`,
899
+ })
900
+ } else {
901
+ toast.info(`Uploaded ${file}`, {
902
+ description: `${completed}/${files.length} files complete.`,
903
+ })
904
+ }
905
+ },
906
+ (index + 1) * 1000
907
+ )
908
+ })
909
+
910
+ toast.loading("Uploading files...", {
911
+ description: "Please wait while we upload your files.",
912
+ })
913
+ }
914
+
915
+ return (
916
+ <div className="text-fm-primary space-y-4">
917
+ <h2 className="text-xl font-semibold">Real World Examples</h2>
918
+ <p>Common patterns and use cases for toast notifications.</p>
919
+
920
+ <div className="space-y-3">
921
+ <div className="rounded-lg border p-4">
922
+ <h3 className="mb-2 font-medium">Document Editor</h3>
923
+ <div className="flex gap-2">
924
+ <Button onClick={handleSave}>Save Document</Button>
925
+ <Button onClick={handleDelete}>Delete Document</Button>
926
+ </div>
927
+ </div>
928
+
929
+ <div className="rounded-lg border p-4">
930
+ <h3 className="mb-2 font-medium">File Upload</h3>
931
+ <Button onClick={handleUpload}>Upload Multiple Files</Button>
932
+ </div>
933
+
934
+ <div className="rounded-lg border p-4">
935
+ <h3 className="mb-2 font-medium">Network Status</h3>
936
+ <div className="flex gap-2">
937
+ <Button
938
+ onClick={() =>
939
+ toast.info("Connection restored", {
940
+ description: "You're back online!",
941
+ })
942
+ }
943
+ >
944
+ Simulate Online
945
+ </Button>
946
+ <Button
947
+ variant="outline"
948
+ onClick={() =>
949
+ toast.warning("Connection lost", {
950
+ description: "Check your internet connection.",
951
+ duration: Infinity,
952
+ })
953
+ }
954
+ >
955
+ Simulate Offline
956
+ </Button>
957
+ </div>
958
+ </div>
959
+ </div>
960
+ </div>
961
+ )
962
+ },
963
+ parameters: {
964
+ docs: {
965
+ description: {
966
+ story:
967
+ "Real-world examples showing how to use toasts for common application scenarios like saving, uploading, and network status.",
968
+ },
969
+ },
970
+ },
971
+ }
972
+
973
+ export const HeadlessCustomDesign: Story = {
974
+ render: () => {
975
+ const customToast = (
976
+ message: string,
977
+ type: "success" | "error" | "warning" | "info" = "info"
978
+ ) => {
979
+ toast.custom((t) => (
980
+ <div
981
+ className={`flex items-center gap-3 rounded-xl border p-4 shadow-lg backdrop-blur-sm ${type === "success" ? "border-green-200 bg-green-50/90 text-green-800" : ""} ${type === "error" ? "border-red-200 bg-red-50/90 text-red-800" : ""} ${type === "warning" ? "border-orange-200 bg-orange-50/90 text-orange-800" : ""} ${type === "info" ? "border-blue-200 bg-blue-50/90 text-blue-800" : ""} transform transition-all duration-300 ease-in-out ${t ? "translate-x-0 opacity-100" : "translate-x-full opacity-0"} `}
982
+ >
983
+ {/* Custom Icons */}
984
+ <div className="flex-shrink-0">
985
+ {type === "success" && (
986
+ <div className="flex h-8 w-8 items-center justify-center rounded-full bg-green-100">
987
+ <svg
988
+ className="h-5 w-5 text-green-600"
989
+ fill="none"
990
+ stroke="currentColor"
991
+ viewBox="0 0 24 24"
992
+ >
993
+ <path
994
+ strokeLinecap="round"
995
+ strokeLinejoin="round"
996
+ strokeWidth={2}
997
+ d="M5 13l4 4L19 7"
998
+ />
999
+ </svg>
1000
+ </div>
1001
+ )}
1002
+ {type === "error" && (
1003
+ <div className="flex h-8 w-8 items-center justify-center rounded-full bg-red-100">
1004
+ <svg
1005
+ className="h-5 w-5 text-red-600"
1006
+ fill="none"
1007
+ stroke="currentColor"
1008
+ viewBox="0 0 24 24"
1009
+ >
1010
+ <path
1011
+ strokeLinecap="round"
1012
+ strokeLinejoin="round"
1013
+ strokeWidth={2}
1014
+ d="M6 18L18 6M6 6l12 12"
1015
+ />
1016
+ </svg>
1017
+ </div>
1018
+ )}
1019
+ {type === "warning" && (
1020
+ <div className="flex h-8 w-8 items-center justify-center rounded-full bg-orange-100">
1021
+ <svg
1022
+ className="h-5 w-5 text-orange-600"
1023
+ fill="none"
1024
+ stroke="currentColor"
1025
+ viewBox="0 0 24 24"
1026
+ >
1027
+ <path
1028
+ strokeLinecap="round"
1029
+ strokeLinejoin="round"
1030
+ strokeWidth={2}
1031
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
1032
+ />
1033
+ </svg>
1034
+ </div>
1035
+ )}
1036
+ {type === "info" && (
1037
+ <div className="flex h-8 w-8 items-center justify-center rounded-full bg-blue-100">
1038
+ <svg
1039
+ className="h-5 w-5 text-blue-600"
1040
+ fill="none"
1041
+ stroke="currentColor"
1042
+ viewBox="0 0 24 24"
1043
+ >
1044
+ <path
1045
+ strokeLinecap="round"
1046
+ strokeLinejoin="round"
1047
+ strokeWidth={2}
1048
+ d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
1049
+ />
1050
+ </svg>
1051
+ </div>
1052
+ )}
1053
+ </div>
1054
+
1055
+ {/* Message */}
1056
+ <div className="flex-1 font-medium">{message}</div>
1057
+
1058
+ {/* Close Button */}
1059
+ <button
1060
+ onClick={() => toast.dismiss(t)}
1061
+ className="flex-shrink-0 rounded-full p-1 transition-colors hover:bg-black/10"
1062
+ >
1063
+ <svg
1064
+ className="h-4 w-4"
1065
+ fill="none"
1066
+ stroke="currentColor"
1067
+ viewBox="0 0 24 24"
1068
+ >
1069
+ <path
1070
+ strokeLinecap="round"
1071
+ strokeLinejoin="round"
1072
+ strokeWidth={2}
1073
+ d="M6 18L18 6M6 6l12 12"
1074
+ />
1075
+ </svg>
1076
+ </button>
1077
+ </div>
1078
+ ))
1079
+ }
1080
+
1081
+ const cardToast = (title: string, description: string, avatar?: string) => {
1082
+ toast.custom((t) => (
1083
+ <div
1084
+ className={`max-w-sm transform rounded-2xl border border-gray-200 bg-white p-4 shadow-xl transition-all duration-300 ease-in-out ${t ? "translate-y-0 scale-100 opacity-100" : "translate-y-2 scale-95 opacity-0"} `}
1085
+ >
1086
+ <div className="flex items-start gap-3">
1087
+ {avatar && (
1088
+ <img
1089
+ src={avatar}
1090
+ alt=""
1091
+ className="h-10 w-10 flex-shrink-0 rounded-full object-cover"
1092
+ />
1093
+ )}
1094
+ <div className="min-w-0 flex-1">
1095
+ <div className="flex items-start justify-between">
1096
+ <div>
1097
+ <p className="text-sm font-semibold text-gray-900">{title}</p>
1098
+ <p className="mt-1 text-sm text-gray-600">{description}</p>
1099
+ </div>
1100
+ <button
1101
+ onClick={() => toast.dismiss(t)}
1102
+ className="ml-2 flex-shrink-0 rounded-full p-1 transition-colors hover:bg-gray-100"
1103
+ >
1104
+ <svg
1105
+ className="h-4 w-4 text-gray-400"
1106
+ fill="none"
1107
+ stroke="currentColor"
1108
+ viewBox="0 0 24 24"
1109
+ >
1110
+ <path
1111
+ strokeLinecap="round"
1112
+ strokeLinejoin="round"
1113
+ strokeWidth={2}
1114
+ d="M6 18L18 6M6 6l12 12"
1115
+ />
1116
+ </svg>
1117
+ </button>
1118
+ </div>
1119
+ <div className="mt-3 flex gap-2">
1120
+ <button className="rounded-full bg-blue-600 px-3 py-1 text-xs text-white transition-colors hover:bg-blue-700">
1121
+ View
1122
+ </button>
1123
+ <button
1124
+ onClick={() => toast.dismiss(t)}
1125
+ className="rounded-full bg-gray-100 px-3 py-1 text-xs text-gray-700 transition-colors hover:bg-gray-200"
1126
+ >
1127
+ Dismiss
1128
+ </button>
1129
+ </div>
1130
+ </div>
1131
+ </div>
1132
+ </div>
1133
+ ))
1134
+ }
1135
+
1136
+ const progressToast = (message: string) => {
1137
+ const toastId = toast.custom((t) => (
1138
+ <div
1139
+ className={`min-w-[300px] transform rounded-xl border border-gray-200 bg-white p-4 shadow-lg transition-all duration-300 ease-in-out ${t ? "translate-x-0 opacity-100" : "translate-x-full opacity-0"} `}
1140
+ >
1141
+ <div className="flex items-center gap-3">
1142
+ <div className="flex h-8 w-8 items-center justify-center rounded-full bg-blue-100">
1143
+ <div className="h-4 w-4 animate-spin rounded-full border-2 border-blue-600 border-t-transparent"></div>
1144
+ </div>
1145
+ <div className="flex-1">
1146
+ <p className="font-medium text-gray-900">{message}</p>
1147
+ <div className="mt-2 h-2 w-full rounded-full bg-gray-200">
1148
+ <div
1149
+ className="progress-bar h-2 rounded-full bg-blue-600"
1150
+ style={{ width: "0%" }}
1151
+ ></div>
1152
+ </div>
1153
+ </div>
1154
+ <button
1155
+ onClick={() => toast.dismiss(t)}
1156
+ className="flex-shrink-0 rounded-full p-1 transition-colors hover:bg-gray-100"
1157
+ >
1158
+ <svg
1159
+ className="h-4 w-4 text-gray-400"
1160
+ fill="none"
1161
+ stroke="currentColor"
1162
+ viewBox="0 0 24 24"
1163
+ >
1164
+ <path
1165
+ strokeLinecap="round"
1166
+ strokeLinejoin="round"
1167
+ strokeWidth={2}
1168
+ d="M6 18L18 6M6 6l12 12"
1169
+ />
1170
+ </svg>
1171
+ </button>
1172
+ </div>
1173
+ </div>
1174
+ ))
1175
+
1176
+ // Simulate progress
1177
+ let progress = 0
1178
+ const interval = setInterval(() => {
1179
+ progress += 10
1180
+ const progressBar = document.querySelector(
1181
+ ".progress-bar"
1182
+ ) as HTMLElement
1183
+ if (progressBar) {
1184
+ progressBar.style.width = `${progress}%`
1185
+ }
1186
+
1187
+ if (progress >= 100) {
1188
+ clearInterval(interval)
1189
+ setTimeout(() => {
1190
+ toast.dismiss(toastId)
1191
+ toast.custom(() => (
1192
+ <div className="flex items-center gap-3 rounded-xl border border-green-200 bg-green-50 p-4">
1193
+ <div className="flex h-8 w-8 items-center justify-center rounded-full bg-green-100">
1194
+ <svg
1195
+ className="h-5 w-5 text-green-600"
1196
+ fill="none"
1197
+ stroke="currentColor"
1198
+ viewBox="0 0 24 24"
1199
+ >
1200
+ <path
1201
+ strokeLinecap="round"
1202
+ strokeLinejoin="round"
1203
+ strokeWidth={2}
1204
+ d="M5 13l4 4L19 7"
1205
+ />
1206
+ </svg>
1207
+ </div>
1208
+ <span className="font-medium text-green-800">
1209
+ Upload completed!
1210
+ </span>
1211
+ </div>
1212
+ ))
1213
+ }, 500)
1214
+ }
1215
+ }, 300)
1216
+ }
1217
+
1218
+ const glassmorphismToast = (message: string, emoji: string) => {
1219
+ toast.custom((t) => (
1220
+ <div
1221
+ className={`transform rounded-2xl border border-white/30 bg-white/20 p-4 shadow-xl backdrop-blur-md transition-all duration-500 ease-out ${t ? "translate-y-0 scale-100 opacity-100" : "translate-y-4 scale-95 opacity-0"} `}
1222
+ >
1223
+ <div className="flex items-center gap-3">
1224
+ <span className="text-2xl">{emoji}</span>
1225
+ <span className="font-medium text-gray-800">{message}</span>
1226
+ <button
1227
+ onClick={() => toast.dismiss(t)}
1228
+ className="ml-auto rounded-full p-1 transition-colors hover:bg-white/20"
1229
+ >
1230
+ <svg
1231
+ className="h-4 w-4 text-gray-600"
1232
+ fill="none"
1233
+ stroke="currentColor"
1234
+ viewBox="0 0 24 24"
1235
+ >
1236
+ <path
1237
+ strokeLinecap="round"
1238
+ strokeLinejoin="round"
1239
+ strokeWidth={2}
1240
+ d="M6 18L18 6M6 6l12 12"
1241
+ />
1242
+ </svg>
1243
+ </button>
1244
+ </div>
1245
+ </div>
1246
+ ))
1247
+ }
1248
+
1249
+ return (
1250
+ <div className="text-fm-primary space-y-6">
1251
+ <div className="space-y-4">
1252
+ <h2 className="text-xl font-semibold">Headless Custom Design</h2>
1253
+ <p>
1254
+ Create completely custom toast designs using toast.custom() with
1255
+ your own components and styling.
1256
+ </p>
1257
+ </div>
1258
+
1259
+ <div className="space-y-6">
1260
+ {/* Icon-based Toasts */}
1261
+ <div className="space-y-3">
1262
+ <h3 className="text-lg font-medium">Icon-based Custom Toasts</h3>
1263
+ <p className="text-sm">
1264
+ Custom designed toasts with icons and tailored styling for each
1265
+ type.
1266
+ </p>
1267
+ <div className="flex flex-wrap gap-2">
1268
+ <Button
1269
+ onClick={() =>
1270
+ customToast("Profile updated successfully!", "success")
1271
+ }
1272
+ >
1273
+ Custom Success
1274
+ </Button>
1275
+ <Button
1276
+ onClick={() => customToast("Failed to save changes", "error")}
1277
+ >
1278
+ Custom Error
1279
+ </Button>
1280
+ <Button
1281
+ onClick={() =>
1282
+ customToast("Please review your settings", "warning")
1283
+ }
1284
+ >
1285
+ Custom Warning
1286
+ </Button>
1287
+ <Button
1288
+ onClick={() => customToast("New feature available", "info")}
1289
+ >
1290
+ Custom Info
1291
+ </Button>
1292
+ </div>
1293
+ </div>
1294
+
1295
+ {/* Card-style Toasts */}
1296
+ <div className="space-y-3">
1297
+ <h3 className="text-lg font-medium">Card-style Notifications</h3>
1298
+ <p className="text-sm">
1299
+ Rich card-style toasts with avatars and action buttons.
1300
+ </p>
1301
+ <div className="flex flex-wrap gap-2">
1302
+ <Button
1303
+ onClick={() =>
1304
+ cardToast(
1305
+ "New Message",
1306
+ "John sent you a new message about the project timeline.",
1307
+ "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=40&h=40&fit=crop&crop=face"
1308
+ )
1309
+ }
1310
+ >
1311
+ Message Notification
1312
+ </Button>
1313
+ <Button
1314
+ onClick={() =>
1315
+ cardToast(
1316
+ "System Update",
1317
+ "A new system update is available. Update now to get the latest features."
1318
+ )
1319
+ }
1320
+ >
1321
+ System Notification
1322
+ </Button>
1323
+ </div>
1324
+ </div>
1325
+
1326
+ {/* Progress Toasts */}
1327
+ <div className="space-y-3">
1328
+ <h3 className="text-lg font-medium">Progress Notifications</h3>
1329
+ <p className="text-sm">
1330
+ Custom toasts with progress bars for long-running operations.
1331
+ </p>
1332
+ <div className="flex flex-wrap gap-2">
1333
+ <Button onClick={() => progressToast("Uploading files...")}>
1334
+ Upload Progress
1335
+ </Button>
1336
+ </div>
1337
+ </div>
1338
+
1339
+ {/* Glassmorphism Toasts */}
1340
+ <div className="space-y-3">
1341
+ <h3 className="text-lg font-medium">Glassmorphism Style</h3>
1342
+ <p className="text-sm">
1343
+ Modern glassmorphism design with backdrop blur effects.
1344
+ </p>
1345
+ <div className="flex flex-wrap gap-2">
1346
+ <Button
1347
+ onClick={() =>
1348
+ glassmorphismToast("Welcome to the future!", "🚀")
1349
+ }
1350
+ >
1351
+ Glassmorphism Toast
1352
+ </Button>
1353
+ <Button
1354
+ onClick={() =>
1355
+ glassmorphismToast("Achievement unlocked!", "🏆")
1356
+ }
1357
+ >
1358
+ Achievement Toast
1359
+ </Button>
1360
+ <Button
1361
+ onClick={() =>
1362
+ glassmorphismToast("You have a new follower", "👋")
1363
+ }
1364
+ >
1365
+ Social Toast
1366
+ </Button>
1367
+ </div>
1368
+ </div>
1369
+
1370
+ {/* Code Example */}
1371
+ <div className="space-y-3">
1372
+ <h3 className="text-lg font-medium">Implementation Example</h3>
1373
+ <div className="rounded-lg bg-gray-50 p-4 text-sm">
1374
+ <pre className="overflow-x-auto text-gray-800">
1375
+ {`// Custom toast with full control
1376
+ toast.custom((t) => (
1377
+ <div className={\`
1378
+ bg-white border rounded-xl p-4 shadow-lg
1379
+ transform transition-all duration-300
1380
+ \${t ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0'}
1381
+ \`}>
1382
+ <div className="flex items-center gap-3">
1383
+ <div className="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center">
1384
+ <CheckIcon className="w-5 h-5 text-blue-600" />
1385
+ </div>
1386
+ <span className="font-medium">Custom message</span>
1387
+ <button onClick={() => toast.dismiss(t)}>
1388
+ <XIcon className="w-4 h-4" />
1389
+ </button>
1390
+ </div>
1391
+ </div>
1392
+ ))`}
1393
+ </pre>
1394
+ </div>
1395
+ </div>
1396
+ </div>
1397
+ </div>
1398
+ )
1399
+ },
1400
+ parameters: {
1401
+ docs: {
1402
+ description: {
1403
+ story: `
1404
+ Create completely custom toast designs using \`toast.custom()\`. This gives you full control over the toast appearance and behavior.
1405
+
1406
+ **Key Features:**
1407
+ - Full design control with custom React components
1408
+ - Access to toast state (\`t\` parameter) for animations
1409
+ - Custom dismiss logic and interactions
1410
+ - Integration with your design system
1411
+ - Advanced layouts like cards, progress bars, and glassmorphism
1412
+ - Custom icons, avatars, and action buttons
1413
+
1414
+ **Use Cases:**
1415
+ - Branded notifications matching your design system
1416
+ - Rich notifications with images and multiple actions
1417
+ - Progress indicators for uploads/downloads
1418
+ - Social media style notifications
1419
+ - Achievement and gamification toasts
1420
+ - Complex form validation feedback
1421
+
1422
+ The \`t\` parameter in the render function represents the toast's visibility state, allowing you to create smooth enter/exit animations.
1423
+ `,
1424
+ },
1425
+ },
1426
+ },
1427
+ }