@neynar/ui 0.1.1

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 (364) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -0
  3. package/dist/components/ui/accordion.d.ts +229 -0
  4. package/dist/components/ui/accordion.d.ts.map +1 -0
  5. package/dist/components/ui/alert-dialog.d.ts +247 -0
  6. package/dist/components/ui/alert-dialog.d.ts.map +1 -0
  7. package/dist/components/ui/alert.d.ts +187 -0
  8. package/dist/components/ui/alert.d.ts.map +1 -0
  9. package/dist/components/ui/aspect-ratio.d.ts +94 -0
  10. package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
  11. package/dist/components/ui/avatar.d.ts +244 -0
  12. package/dist/components/ui/avatar.d.ts.map +1 -0
  13. package/dist/components/ui/badge.d.ts +163 -0
  14. package/dist/components/ui/badge.d.ts.map +1 -0
  15. package/dist/components/ui/breadcrumb.d.ts +281 -0
  16. package/dist/components/ui/breadcrumb.d.ts.map +1 -0
  17. package/dist/components/ui/button.d.ts +129 -0
  18. package/dist/components/ui/button.d.ts.map +1 -0
  19. package/dist/components/ui/calendar.d.ts +169 -0
  20. package/dist/components/ui/calendar.d.ts.map +1 -0
  21. package/dist/components/ui/card.d.ts +365 -0
  22. package/dist/components/ui/card.d.ts.map +1 -0
  23. package/dist/components/ui/carousel.d.ts +369 -0
  24. package/dist/components/ui/carousel.d.ts.map +1 -0
  25. package/dist/components/ui/chart.d.ts +442 -0
  26. package/dist/components/ui/chart.d.ts.map +1 -0
  27. package/dist/components/ui/checkbox.d.ts +88 -0
  28. package/dist/components/ui/checkbox.d.ts.map +1 -0
  29. package/dist/components/ui/collapsible.d.ts +182 -0
  30. package/dist/components/ui/collapsible.d.ts.map +1 -0
  31. package/dist/components/ui/combobox.d.ts +270 -0
  32. package/dist/components/ui/combobox.d.ts.map +1 -0
  33. package/dist/components/ui/command.d.ts +355 -0
  34. package/dist/components/ui/command.d.ts.map +1 -0
  35. package/dist/components/ui/container.d.ts +102 -0
  36. package/dist/components/ui/container.d.ts.map +1 -0
  37. package/dist/components/ui/context-menu.d.ts +339 -0
  38. package/dist/components/ui/context-menu.d.ts.map +1 -0
  39. package/dist/components/ui/date-picker.d.ts +145 -0
  40. package/dist/components/ui/date-picker.d.ts.map +1 -0
  41. package/dist/components/ui/dialog.d.ts +322 -0
  42. package/dist/components/ui/dialog.d.ts.map +1 -0
  43. package/dist/components/ui/drawer.d.ts +154 -0
  44. package/dist/components/ui/drawer.d.ts.map +1 -0
  45. package/dist/components/ui/dropdown-menu.d.ts +349 -0
  46. package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
  47. package/dist/components/ui/empty-state.d.ts +133 -0
  48. package/dist/components/ui/empty-state.d.ts.map +1 -0
  49. package/dist/components/ui/hover-card.d.ts +109 -0
  50. package/dist/components/ui/hover-card.d.ts.map +1 -0
  51. package/dist/components/ui/input.d.ts +89 -0
  52. package/dist/components/ui/input.d.ts.map +1 -0
  53. package/dist/components/ui/label.d.ts +93 -0
  54. package/dist/components/ui/label.d.ts.map +1 -0
  55. package/dist/components/ui/menubar.d.ts +306 -0
  56. package/dist/components/ui/menubar.d.ts.map +1 -0
  57. package/dist/components/ui/navigation-menu.d.ts +318 -0
  58. package/dist/components/ui/navigation-menu.d.ts.map +1 -0
  59. package/dist/components/ui/pagination.d.ts +343 -0
  60. package/dist/components/ui/pagination.d.ts.map +1 -0
  61. package/dist/components/ui/popover.d.ts +178 -0
  62. package/dist/components/ui/popover.d.ts.map +1 -0
  63. package/dist/components/ui/progress.d.ts +64 -0
  64. package/dist/components/ui/progress.d.ts.map +1 -0
  65. package/dist/components/ui/radio-group.d.ts +144 -0
  66. package/dist/components/ui/radio-group.d.ts.map +1 -0
  67. package/dist/components/ui/resizable.d.ts +164 -0
  68. package/dist/components/ui/resizable.d.ts.map +1 -0
  69. package/dist/components/ui/scroll-area.d.ts +82 -0
  70. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  71. package/dist/components/ui/select.d.ts +316 -0
  72. package/dist/components/ui/select.d.ts.map +1 -0
  73. package/dist/components/ui/separator.d.ts +80 -0
  74. package/dist/components/ui/separator.d.ts.map +1 -0
  75. package/dist/components/ui/sheet.d.ts +346 -0
  76. package/dist/components/ui/sheet.d.ts.map +1 -0
  77. package/dist/components/ui/sidebar.d.ts +1561 -0
  78. package/dist/components/ui/sidebar.d.ts.map +1 -0
  79. package/dist/components/ui/skeleton.d.ts +66 -0
  80. package/dist/components/ui/skeleton.d.ts.map +1 -0
  81. package/dist/components/ui/slider.d.ts +95 -0
  82. package/dist/components/ui/slider.d.ts.map +1 -0
  83. package/dist/components/ui/sonner.d.ts +101 -0
  84. package/dist/components/ui/sonner.d.ts.map +1 -0
  85. package/dist/components/ui/stack.d.ts +192 -0
  86. package/dist/components/ui/stack.d.ts.map +1 -0
  87. package/dist/components/ui/stories/accordion.stories.d.ts +71 -0
  88. package/dist/components/ui/stories/accordion.stories.d.ts.map +1 -0
  89. package/dist/components/ui/stories/alert-dialog.stories.d.ts +39 -0
  90. package/dist/components/ui/stories/alert-dialog.stories.d.ts.map +1 -0
  91. package/dist/components/ui/stories/alert.stories.d.ts +48 -0
  92. package/dist/components/ui/stories/alert.stories.d.ts.map +1 -0
  93. package/dist/components/ui/stories/aspect-ratio.stories.d.ts +53 -0
  94. package/dist/components/ui/stories/aspect-ratio.stories.d.ts.map +1 -0
  95. package/dist/components/ui/stories/avatar.stories.d.ts +49 -0
  96. package/dist/components/ui/stories/avatar.stories.d.ts.map +1 -0
  97. package/dist/components/ui/stories/badge.stories.d.ts +64 -0
  98. package/dist/components/ui/stories/badge.stories.d.ts.map +1 -0
  99. package/dist/components/ui/stories/breadcrumb.stories.d.ts +27 -0
  100. package/dist/components/ui/stories/breadcrumb.stories.d.ts.map +1 -0
  101. package/dist/components/ui/stories/button.stories.d.ts +92 -0
  102. package/dist/components/ui/stories/button.stories.d.ts.map +1 -0
  103. package/dist/components/ui/stories/calendar.stories.d.ts +94 -0
  104. package/dist/components/ui/stories/calendar.stories.d.ts.map +1 -0
  105. package/dist/components/ui/stories/card.stories.d.ts +29 -0
  106. package/dist/components/ui/stories/card.stories.d.ts.map +1 -0
  107. package/dist/components/ui/stories/carousel.stories.d.ts +42 -0
  108. package/dist/components/ui/stories/carousel.stories.d.ts.map +1 -0
  109. package/dist/components/ui/stories/chart.stories.d.ts +51 -0
  110. package/dist/components/ui/stories/chart.stories.d.ts.map +1 -0
  111. package/dist/components/ui/stories/checkbox.stories.d.ts +72 -0
  112. package/dist/components/ui/stories/checkbox.stories.d.ts.map +1 -0
  113. package/dist/components/ui/stories/cn.stories.d.ts +19 -0
  114. package/dist/components/ui/stories/cn.stories.d.ts.map +1 -0
  115. package/dist/components/ui/stories/collapsible.stories.d.ts +51 -0
  116. package/dist/components/ui/stories/collapsible.stories.d.ts.map +1 -0
  117. package/dist/components/ui/stories/colors.stories.d.ts +31 -0
  118. package/dist/components/ui/stories/colors.stories.d.ts.map +1 -0
  119. package/dist/components/ui/stories/combobox.stories.d.ts +89 -0
  120. package/dist/components/ui/stories/combobox.stories.d.ts.map +1 -0
  121. package/dist/components/ui/stories/command.stories.d.ts +69 -0
  122. package/dist/components/ui/stories/command.stories.d.ts.map +1 -0
  123. package/dist/components/ui/stories/container.stories.d.ts +42 -0
  124. package/dist/components/ui/stories/container.stories.d.ts.map +1 -0
  125. package/dist/components/ui/stories/context-menu.stories.d.ts +32 -0
  126. package/dist/components/ui/stories/context-menu.stories.d.ts.map +1 -0
  127. package/dist/components/ui/stories/date-picker.stories.d.ts +67 -0
  128. package/dist/components/ui/stories/date-picker.stories.d.ts.map +1 -0
  129. package/dist/components/ui/stories/dialog.stories.d.ts +48 -0
  130. package/dist/components/ui/stories/dialog.stories.d.ts.map +1 -0
  131. package/dist/components/ui/stories/drawer.stories.d.ts +33 -0
  132. package/dist/components/ui/stories/drawer.stories.d.ts.map +1 -0
  133. package/dist/components/ui/stories/dropdown-menu.stories.d.ts +31 -0
  134. package/dist/components/ui/stories/dropdown-menu.stories.d.ts.map +1 -0
  135. package/dist/components/ui/stories/empty-state.stories.d.ts +74 -0
  136. package/dist/components/ui/stories/empty-state.stories.d.ts.map +1 -0
  137. package/dist/components/ui/stories/hover-card.stories.d.ts +35 -0
  138. package/dist/components/ui/stories/hover-card.stories.d.ts.map +1 -0
  139. package/dist/components/ui/stories/input.stories.d.ts +69 -0
  140. package/dist/components/ui/stories/input.stories.d.ts.map +1 -0
  141. package/dist/components/ui/stories/label.stories.d.ts +47 -0
  142. package/dist/components/ui/stories/label.stories.d.ts.map +1 -0
  143. package/dist/components/ui/stories/menubar.stories.d.ts +39 -0
  144. package/dist/components/ui/stories/menubar.stories.d.ts.map +1 -0
  145. package/dist/components/ui/stories/navigation-menu.stories.d.ts +44 -0
  146. package/dist/components/ui/stories/navigation-menu.stories.d.ts.map +1 -0
  147. package/dist/components/ui/stories/pagination.stories.d.ts +33 -0
  148. package/dist/components/ui/stories/pagination.stories.d.ts.map +1 -0
  149. package/dist/components/ui/stories/popover.stories.d.ts +36 -0
  150. package/dist/components/ui/stories/popover.stories.d.ts.map +1 -0
  151. package/dist/components/ui/stories/progress.stories.d.ts +38 -0
  152. package/dist/components/ui/stories/progress.stories.d.ts.map +1 -0
  153. package/dist/components/ui/stories/radio-group.stories.d.ts +76 -0
  154. package/dist/components/ui/stories/radio-group.stories.d.ts.map +1 -0
  155. package/dist/components/ui/stories/resizable.stories.d.ts +49 -0
  156. package/dist/components/ui/stories/resizable.stories.d.ts.map +1 -0
  157. package/dist/components/ui/stories/scroll-area.stories.d.ts +35 -0
  158. package/dist/components/ui/stories/scroll-area.stories.d.ts.map +1 -0
  159. package/dist/components/ui/stories/select.stories.d.ts +51 -0
  160. package/dist/components/ui/stories/select.stories.d.ts.map +1 -0
  161. package/dist/components/ui/stories/separator.stories.d.ts +58 -0
  162. package/dist/components/ui/stories/separator.stories.d.ts.map +1 -0
  163. package/dist/components/ui/stories/sheet.stories.d.ts +43 -0
  164. package/dist/components/ui/stories/sheet.stories.d.ts.map +1 -0
  165. package/dist/components/ui/stories/sidebar.stories.d.ts +60 -0
  166. package/dist/components/ui/stories/sidebar.stories.d.ts.map +1 -0
  167. package/dist/components/ui/stories/skeleton.stories.d.ts +42 -0
  168. package/dist/components/ui/stories/skeleton.stories.d.ts.map +1 -0
  169. package/dist/components/ui/stories/slider.stories.d.ts +99 -0
  170. package/dist/components/ui/stories/slider.stories.d.ts.map +1 -0
  171. package/dist/components/ui/stories/sonner.stories.d.ts +9 -0
  172. package/dist/components/ui/stories/sonner.stories.d.ts.map +1 -0
  173. package/dist/components/ui/stories/stack.stories.d.ts +39 -0
  174. package/dist/components/ui/stories/stack.stories.d.ts.map +1 -0
  175. package/dist/components/ui/stories/switch.stories.d.ts +71 -0
  176. package/dist/components/ui/stories/switch.stories.d.ts.map +1 -0
  177. package/dist/components/ui/stories/table.stories.d.ts +40 -0
  178. package/dist/components/ui/stories/table.stories.d.ts.map +1 -0
  179. package/dist/components/ui/stories/tabs.stories.d.ts +62 -0
  180. package/dist/components/ui/stories/tabs.stories.d.ts.map +1 -0
  181. package/dist/components/ui/stories/text-field.stories.d.ts +78 -0
  182. package/dist/components/ui/stories/text-field.stories.d.ts.map +1 -0
  183. package/dist/components/ui/stories/textarea.stories.d.ts +57 -0
  184. package/dist/components/ui/stories/textarea.stories.d.ts.map +1 -0
  185. package/dist/components/ui/stories/theme-toggle.stories.d.ts +71 -0
  186. package/dist/components/ui/stories/theme-toggle.stories.d.ts.map +1 -0
  187. package/dist/components/ui/stories/theme.stories.d.ts +51 -0
  188. package/dist/components/ui/stories/theme.stories.d.ts.map +1 -0
  189. package/dist/components/ui/stories/toggle-group.stories.d.ts +71 -0
  190. package/dist/components/ui/stories/toggle-group.stories.d.ts.map +1 -0
  191. package/dist/components/ui/stories/toggle.stories.d.ts +78 -0
  192. package/dist/components/ui/stories/toggle.stories.d.ts.map +1 -0
  193. package/dist/components/ui/stories/tooltip.stories.d.ts +37 -0
  194. package/dist/components/ui/stories/tooltip.stories.d.ts.map +1 -0
  195. package/dist/components/ui/stories/typography.stories.d.ts +137 -0
  196. package/dist/components/ui/stories/typography.stories.d.ts.map +1 -0
  197. package/dist/components/ui/stories/use-mobile.stories.d.ts +20 -0
  198. package/dist/components/ui/stories/use-mobile.stories.d.ts.map +1 -0
  199. package/dist/components/ui/stories/use-theme.stories.d.ts +23 -0
  200. package/dist/components/ui/stories/use-theme.stories.d.ts.map +1 -0
  201. package/dist/components/ui/switch.d.ts +84 -0
  202. package/dist/components/ui/switch.d.ts.map +1 -0
  203. package/dist/components/ui/table.d.ts +321 -0
  204. package/dist/components/ui/table.d.ts.map +1 -0
  205. package/dist/components/ui/tabs.d.ts +260 -0
  206. package/dist/components/ui/tabs.d.ts.map +1 -0
  207. package/dist/components/ui/text-field.d.ts +157 -0
  208. package/dist/components/ui/text-field.d.ts.map +1 -0
  209. package/dist/components/ui/textarea.d.ts +84 -0
  210. package/dist/components/ui/textarea.d.ts.map +1 -0
  211. package/dist/components/ui/theme-toggle.d.ts +105 -0
  212. package/dist/components/ui/theme-toggle.d.ts.map +1 -0
  213. package/dist/components/ui/theme.d.ts +110 -0
  214. package/dist/components/ui/theme.d.ts.map +1 -0
  215. package/dist/components/ui/toggle-group.d.ts +133 -0
  216. package/dist/components/ui/toggle-group.d.ts.map +1 -0
  217. package/dist/components/ui/toggle.d.ts +84 -0
  218. package/dist/components/ui/toggle.d.ts.map +1 -0
  219. package/dist/components/ui/tooltip.d.ts +202 -0
  220. package/dist/components/ui/tooltip.d.ts.map +1 -0
  221. package/dist/components/ui/typography.d.ts +287 -0
  222. package/dist/components/ui/typography.d.ts.map +1 -0
  223. package/dist/hooks/use-mobile.d.ts +74 -0
  224. package/dist/hooks/use-mobile.d.ts.map +1 -0
  225. package/dist/hooks/use-theme.d.ts +142 -0
  226. package/dist/hooks/use-theme.d.ts.map +1 -0
  227. package/dist/index.d.ts +57 -0
  228. package/dist/index.d.ts.map +1 -0
  229. package/dist/index.js +27498 -0
  230. package/dist/index.js.map +1 -0
  231. package/dist/lib/utils.d.ts +43 -0
  232. package/dist/lib/utils.d.ts.map +1 -0
  233. package/dist/tsconfig.tsbuildinfo +1 -0
  234. package/docs/llm/colors.md +273 -0
  235. package/docs/llm/components/buttons.md +68 -0
  236. package/docs/llm/components/cards.md +53 -0
  237. package/docs/llm/components/display.md +134 -0
  238. package/docs/llm/components/feedback.md +96 -0
  239. package/docs/llm/components/forms.md +90 -0
  240. package/docs/llm/components/layout.md +59 -0
  241. package/docs/llm/components/menus.md +70 -0
  242. package/docs/llm/components/navigation.md +80 -0
  243. package/docs/llm/components/overlays.md +83 -0
  244. package/docs/llm/components/tables.md +73 -0
  245. package/docs/llm/components/typography.md +199 -0
  246. package/docs/llm/components/utilities.md +114 -0
  247. package/docs/llm/guide.md +165 -0
  248. package/llms.txt +122 -0
  249. package/package.json +104 -0
  250. package/src/components/ui/accordion.tsx +285 -0
  251. package/src/components/ui/alert-dialog.tsx +387 -0
  252. package/src/components/ui/alert.tsx +243 -0
  253. package/src/components/ui/aspect-ratio.tsx +99 -0
  254. package/src/components/ui/avatar.tsx +288 -0
  255. package/src/components/ui/badge.tsx +205 -0
  256. package/src/components/ui/breadcrumb.tsx +378 -0
  257. package/src/components/ui/button.tsx +195 -0
  258. package/src/components/ui/calendar.tsx +371 -0
  259. package/src/components/ui/card.tsx +447 -0
  260. package/src/components/ui/carousel.tsx +624 -0
  261. package/src/components/ui/chart.tsx +802 -0
  262. package/src/components/ui/checkbox.tsx +113 -0
  263. package/src/components/ui/collapsible.tsx +207 -0
  264. package/src/components/ui/combobox.tsx +373 -0
  265. package/src/components/ui/command.tsx +518 -0
  266. package/src/components/ui/container.tsx +114 -0
  267. package/src/components/ui/context-menu.tsx +563 -0
  268. package/src/components/ui/date-picker.tsx +213 -0
  269. package/src/components/ui/dialog.tsx +447 -0
  270. package/src/components/ui/drawer.tsx +273 -0
  271. package/src/components/ui/dropdown-menu.tsx +578 -0
  272. package/src/components/ui/empty-state.tsx +145 -0
  273. package/src/components/ui/hover-card.tsx +144 -0
  274. package/src/components/ui/input.tsx +106 -0
  275. package/src/components/ui/label.tsx +110 -0
  276. package/src/components/ui/menubar.tsx +553 -0
  277. package/src/components/ui/navigation-menu.tsx +471 -0
  278. package/src/components/ui/pagination.tsx +456 -0
  279. package/src/components/ui/popover.tsx +216 -0
  280. package/src/components/ui/progress.tsx +88 -0
  281. package/src/components/ui/radio-group.tsx +183 -0
  282. package/src/components/ui/resizable.tsx +209 -0
  283. package/src/components/ui/scroll-area.tsx +132 -0
  284. package/src/components/ui/select.tsx +485 -0
  285. package/src/components/ui/separator.tsx +101 -0
  286. package/src/components/ui/sheet.tsx +495 -0
  287. package/src/components/ui/sidebar.tsx +2211 -0
  288. package/src/components/ui/skeleton.tsx +76 -0
  289. package/src/components/ui/slider.tsx +147 -0
  290. package/src/components/ui/sonner.tsx +120 -0
  291. package/src/components/ui/stack.tsx +180 -0
  292. package/src/components/ui/stories/accordion.stories.tsx +429 -0
  293. package/src/components/ui/stories/alert-dialog.stories.tsx +519 -0
  294. package/src/components/ui/stories/alert.stories.tsx +228 -0
  295. package/src/components/ui/stories/aspect-ratio.stories.tsx +200 -0
  296. package/src/components/ui/stories/avatar.stories.tsx +317 -0
  297. package/src/components/ui/stories/badge.stories.tsx +260 -0
  298. package/src/components/ui/stories/breadcrumb.stories.tsx +482 -0
  299. package/src/components/ui/stories/button.stories.tsx +266 -0
  300. package/src/components/ui/stories/calendar.stories.tsx +375 -0
  301. package/src/components/ui/stories/card.stories.tsx +308 -0
  302. package/src/components/ui/stories/carousel.stories.tsx +328 -0
  303. package/src/components/ui/stories/chart.stories.tsx +430 -0
  304. package/src/components/ui/stories/checkbox.stories.tsx +297 -0
  305. package/src/components/ui/stories/cn.stories.tsx +433 -0
  306. package/src/components/ui/stories/collapsible.stories.tsx +256 -0
  307. package/src/components/ui/stories/colors.stories.tsx +502 -0
  308. package/src/components/ui/stories/combobox.stories.tsx +301 -0
  309. package/src/components/ui/stories/command.stories.tsx +632 -0
  310. package/src/components/ui/stories/container.stories.tsx +250 -0
  311. package/src/components/ui/stories/context-menu.stories.tsx +446 -0
  312. package/src/components/ui/stories/date-picker.stories.tsx +378 -0
  313. package/src/components/ui/stories/dialog.stories.tsx +535 -0
  314. package/src/components/ui/stories/drawer.stories.tsx +364 -0
  315. package/src/components/ui/stories/dropdown-menu.stories.tsx +374 -0
  316. package/src/components/ui/stories/empty-state.stories.tsx +244 -0
  317. package/src/components/ui/stories/hover-card.stories.tsx +355 -0
  318. package/src/components/ui/stories/input.stories.tsx +289 -0
  319. package/src/components/ui/stories/label.stories.tsx +294 -0
  320. package/src/components/ui/stories/menubar.stories.tsx +764 -0
  321. package/src/components/ui/stories/navigation-menu.stories.tsx +539 -0
  322. package/src/components/ui/stories/pagination.stories.tsx +604 -0
  323. package/src/components/ui/stories/popover.stories.tsx +392 -0
  324. package/src/components/ui/stories/progress.stories.tsx +218 -0
  325. package/src/components/ui/stories/radio-group.stories.tsx +400 -0
  326. package/src/components/ui/stories/resizable.stories.tsx +417 -0
  327. package/src/components/ui/stories/scroll-area.stories.tsx +180 -0
  328. package/src/components/ui/stories/select.stories.tsx +389 -0
  329. package/src/components/ui/stories/separator.stories.tsx +192 -0
  330. package/src/components/ui/stories/sheet.stories.tsx +468 -0
  331. package/src/components/ui/stories/sidebar.stories.tsx +731 -0
  332. package/src/components/ui/stories/skeleton.stories.tsx +216 -0
  333. package/src/components/ui/stories/slider.stories.tsx +321 -0
  334. package/src/components/ui/stories/sonner.stories.tsx +373 -0
  335. package/src/components/ui/stories/stack.stories.tsx +222 -0
  336. package/src/components/ui/stories/switch.stories.tsx +202 -0
  337. package/src/components/ui/stories/table.stories.tsx +541 -0
  338. package/src/components/ui/stories/tabs.stories.tsx +544 -0
  339. package/src/components/ui/stories/text-field.stories.tsx +280 -0
  340. package/src/components/ui/stories/textarea.stories.tsx +245 -0
  341. package/src/components/ui/stories/theme-toggle.stories.tsx +275 -0
  342. package/src/components/ui/stories/theme.stories.tsx +412 -0
  343. package/src/components/ui/stories/toggle-group.stories.tsx +337 -0
  344. package/src/components/ui/stories/toggle.stories.tsx +325 -0
  345. package/src/components/ui/stories/tooltip.stories.tsx +444 -0
  346. package/src/components/ui/stories/typography.stories.tsx +1586 -0
  347. package/src/components/ui/stories/use-mobile.stories.tsx +420 -0
  348. package/src/components/ui/stories/use-theme.stories.tsx +531 -0
  349. package/src/components/ui/switch.tsx +106 -0
  350. package/src/components/ui/table.tsx +424 -0
  351. package/src/components/ui/tabs.tsx +316 -0
  352. package/src/components/ui/text-field.tsx +206 -0
  353. package/src/components/ui/textarea.tsx +98 -0
  354. package/src/components/ui/theme-toggle.tsx +185 -0
  355. package/src/components/ui/theme.tsx +148 -0
  356. package/src/components/ui/toggle-group.tsx +196 -0
  357. package/src/components/ui/toggle.tsx +115 -0
  358. package/src/components/ui/tooltip.tsx +253 -0
  359. package/src/components/ui/typography.tsx +468 -0
  360. package/src/hooks/use-mobile.ts +91 -0
  361. package/src/hooks/use-theme.ts +319 -0
  362. package/src/index.ts +77 -0
  363. package/src/lib/utils.ts +57 -0
  364. package/src/styles/globals.css +160 -0
@@ -0,0 +1,275 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { ThemeToggle } from "../theme-toggle";
3
+
4
+ /**
5
+ * ThemeToggle component stories for design system documentation
6
+ *
7
+ * This story file demonstrates the ThemeToggle component's capabilities through three focused stories:
8
+ * - Interactive: Playground for testing all props and custom theme configurations
9
+ * - Variants: Systematic showcase of all available styles, sizes, and theme combinations
10
+ * - InContext: Real-world usage examples for business and design teams
11
+ */
12
+ const meta = {
13
+ title: "Theme/ThemeToggle",
14
+ component: ThemeToggle,
15
+ parameters: {
16
+ layout: "centered",
17
+ docs: {
18
+ description: {
19
+ component:
20
+ "An advanced theme toggle component that supports custom themes, visual styling, and color-coded indicators. Built on top of the framework-agnostic useTheme hook for maximum compatibility across different React environments.",
21
+ },
22
+ },
23
+ },
24
+ tags: ["autodocs"],
25
+ argTypes: {
26
+ variant: {
27
+ control: { type: "select" },
28
+ options: [
29
+ "default",
30
+ "destructive",
31
+ "outline",
32
+ "secondary",
33
+ "ghost",
34
+ "link",
35
+ ],
36
+ description: "Visual style variant for the toggle button",
37
+ },
38
+ size: {
39
+ control: { type: "select" },
40
+ options: ["default", "sm", "lg", "icon"],
41
+ description:
42
+ "Size of the toggle button - icon shows only icon, others include text",
43
+ },
44
+ className: {
45
+ control: "text",
46
+ description: "Additional CSS classes to apply to the button",
47
+ },
48
+ },
49
+ args: {
50
+ variant: "outline",
51
+ size: "icon",
52
+ },
53
+ } satisfies Meta<typeof ThemeToggle>;
54
+
55
+ export default meta;
56
+ type Story = StoryObj<typeof meta>;
57
+
58
+ /**
59
+ * Interactive Playground Story
60
+ *
61
+ * Use this story to test all ThemeToggle props and configurations through Storybook controls.
62
+ * Perfect for designers and developers to experiment with custom themes and styling options.
63
+ */
64
+ export const Interactive: Story = {
65
+ args: {
66
+ variant: "outline",
67
+ size: "icon",
68
+ showLabel: false,
69
+ align: "end",
70
+ },
71
+ parameters: {
72
+ docs: {
73
+ description: {
74
+ story:
75
+ "Interactive playground for testing all ThemeToggle properties. Use the controls panel to experiment with custom themes, colors, variants, and visual options. The component will persist theme changes using cookies.",
76
+ },
77
+ },
78
+ },
79
+ };
80
+
81
+ /**
82
+ * Variants Showcase Story
83
+ *
84
+ * Systematic display of all available ThemeToggle variants, sizes, and custom theme configurations.
85
+ * Helps design teams understand the full range of available options and styling capabilities.
86
+ */
87
+ export const Variants: Story = {
88
+ render: () => (
89
+ <div className="space-y-8">
90
+ {/* Size Variants */}
91
+ <div className="space-y-4">
92
+ <h3 className="text-lg font-semibold">Size Variants</h3>
93
+ <div className="flex items-center gap-4">
94
+ <div className="space-y-2">
95
+ <div className="text-sm text-muted-foreground">Icon</div>
96
+ <ThemeToggle size="icon" />
97
+ </div>
98
+ <div className="space-y-2">
99
+ <div className="text-sm text-muted-foreground">Small</div>
100
+ <ThemeToggle size="sm" />
101
+ </div>
102
+ <div className="space-y-2">
103
+ <div className="text-sm text-muted-foreground">Default</div>
104
+ <ThemeToggle size="default" />
105
+ </div>
106
+ <div className="space-y-2">
107
+ <div className="text-sm text-muted-foreground">Large</div>
108
+ <ThemeToggle size="lg" />
109
+ </div>
110
+ </div>
111
+ </div>
112
+
113
+ {/* Visual Variants */}
114
+ <div className="space-y-4">
115
+ <h3 className="text-lg font-semibold">Visual Variants</h3>
116
+ <div className="flex flex-wrap gap-3">
117
+ <ThemeToggle variant="default" size="sm" />
118
+ <ThemeToggle variant="outline" size="sm" />
119
+ <ThemeToggle variant="secondary" size="sm" />
120
+ <ThemeToggle variant="ghost" size="sm" />
121
+ <ThemeToggle variant="link" size="sm" />
122
+ </div>
123
+ </div>
124
+
125
+ {/* Custom Themes */}
126
+ <div className="space-y-4">
127
+ <h3 className="text-lg font-semibold">Custom Themes</h3>
128
+ <div className="space-y-3">
129
+ <div className="space-y-2">
130
+ <div className="text-sm text-muted-foreground">
131
+ Basic Custom Themes
132
+ </div>
133
+ <ThemeToggle size="default" />
134
+ </div>
135
+
136
+ <div className="space-y-2">
137
+ <div className="text-sm text-muted-foreground">
138
+ With Color Indicators
139
+ </div>
140
+ <ThemeToggle size="default" />
141
+ </div>
142
+
143
+ <div className="space-y-2">
144
+ <div className="text-sm text-muted-foreground">
145
+ System-Respecting Theme
146
+ </div>
147
+ <ThemeToggle size="default" />
148
+ </div>
149
+ </div>
150
+ </div>
151
+
152
+ {/* Advanced Styling */}
153
+ <div className="space-y-4">
154
+ <h3 className="text-lg font-semibold">Advanced Styling</h3>
155
+ <div className="flex flex-wrap gap-3">
156
+ <ThemeToggle variant="outline" size="default" className="border-2" />
157
+
158
+ <ThemeToggle variant="secondary" size="lg" className="border-2" />
159
+ </div>
160
+ </div>
161
+ </div>
162
+ ),
163
+ parameters: {
164
+ layout: "padded",
165
+ docs: {
166
+ description: {
167
+ story:
168
+ "Complete showcase of all ThemeToggle variants, sizes, custom theme configurations, and styling options. Use this as a reference for what's available in the design system and how custom themes work.",
169
+ },
170
+ },
171
+ },
172
+ };
173
+
174
+ /**
175
+ * Real-world Context Story
176
+ *
177
+ * Demonstrates the ThemeToggle component in realistic UI scenarios.
178
+ * Helps business teams and designers understand practical usage patterns and integration approaches.
179
+ */
180
+ export const InContext: Story = {
181
+ render: () => (
182
+ <div className="space-y-8 max-w-2xl">
183
+ {/* Application Header */}
184
+ <div className="space-y-4">
185
+ <h3 className="text-lg font-semibold">Application Header</h3>
186
+ <div className="flex items-center justify-between p-4 border rounded-lg bg-card">
187
+ <div className="flex items-center gap-3">
188
+ <div className="h-8 w-8 rounded-full bg-primary" />
189
+ <h2 className="font-semibold">My Application</h2>
190
+ </div>
191
+ <div className="flex items-center gap-2">
192
+ <button className="px-3 py-1.5 text-sm rounded-md hover:bg-muted">
193
+ Profile
194
+ </button>
195
+ <ThemeToggle variant="ghost" size="icon" />
196
+ </div>
197
+ </div>
198
+ </div>
199
+
200
+ {/* Settings Panel */}
201
+ <div className="space-y-4">
202
+ <h3 className="text-lg font-semibold">Settings Panel</h3>
203
+ <div className="p-6 border rounded-lg bg-card space-y-4">
204
+ <h4 className="font-medium">Appearance</h4>
205
+ <div className="space-y-3">
206
+ <div className="flex items-center justify-between">
207
+ <div>
208
+ <div className="font-medium">Theme</div>
209
+ <div className="text-sm text-muted-foreground">
210
+ Choose your preferred color scheme
211
+ </div>
212
+ </div>
213
+ <ThemeToggle size="default" variant="outline" />
214
+ </div>
215
+ </div>
216
+ </div>
217
+ </div>
218
+
219
+ {/* Design System Demo */}
220
+ <div className="space-y-4">
221
+ <h3 className="text-lg font-semibold">Design System Customization</h3>
222
+ <div className="p-6 border rounded-lg bg-card space-y-4">
223
+ <h4 className="font-medium">Brand Themes</h4>
224
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
225
+ <div className="space-y-2">
226
+ <div className="text-sm font-medium">Marketing Site</div>
227
+ <ThemeToggle size="sm" variant="secondary" />
228
+ </div>
229
+
230
+ <div className="space-y-2">
231
+ <div className="text-sm font-medium">Creative Tools</div>
232
+ <ThemeToggle size="sm" variant="outline" />
233
+ </div>
234
+ </div>
235
+ </div>
236
+ </div>
237
+
238
+ {/* Mobile Layout */}
239
+ <div className="space-y-4">
240
+ <h3 className="text-lg font-semibold">Mobile Navigation</h3>
241
+ <div className="max-w-sm mx-auto border rounded-lg bg-card">
242
+ <div className="p-4 border-b">
243
+ <div className="flex items-center justify-between">
244
+ <h4 className="font-medium">Settings</h4>
245
+ <ThemeToggle size="icon" variant="ghost" />
246
+ </div>
247
+ </div>
248
+ <div className="p-4 space-y-3">
249
+ <div className="flex items-center justify-between py-2">
250
+ <span>Notifications</span>
251
+ <div className="w-10 h-6 bg-primary rounded-full" />
252
+ </div>
253
+ <div className="flex items-center justify-between py-2">
254
+ <span>Theme</span>
255
+ <ThemeToggle size="sm" variant="outline" />
256
+ </div>
257
+ <div className="flex items-center justify-between py-2">
258
+ <span>Language</span>
259
+ <span className="text-sm text-muted-foreground">English</span>
260
+ </div>
261
+ </div>
262
+ </div>
263
+ </div>
264
+ </div>
265
+ ),
266
+ parameters: {
267
+ layout: "padded",
268
+ docs: {
269
+ description: {
270
+ story:
271
+ "Real-world usage examples showing how ThemeToggle integrates into common UI patterns like application headers, settings panels, and mobile layouts. These patterns demonstrate practical implementation approaches for different use cases.",
272
+ },
273
+ },
274
+ },
275
+ };
@@ -0,0 +1,412 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { Theme } from "../theme";
3
+ import { ThemeToggle } from "../theme-toggle";
4
+ import { Card, CardHeader, CardTitle, CardContent } from "../card";
5
+ import { Button } from "../button";
6
+
7
+ /**
8
+ * Theme stories demonstrate FOUC prevention and theming system setup
9
+ *
10
+ * The Theme component prevents flash of unstyled content (FOUC) by applying
11
+ * the user's preferred theme before the page renders. It should be placed once
12
+ * at the root of your application for optimal theming experience.
13
+ *
14
+ * These stories showcase:
15
+ * - Basic Theme component setup
16
+ * - Integration with ThemeToggle for user controls
17
+ * - Multiple synchronized theme toggles
18
+ * - Framework-agnostic theming patterns
19
+ */
20
+ const meta = {
21
+ title: "Theme/Theme",
22
+ component: Theme,
23
+ parameters: {
24
+ layout: "fullscreen",
25
+ docs: {
26
+ description: {
27
+ component: `
28
+ The Theme component prevents flash of unstyled content (FOUC) by injecting a small script that applies the correct theme before the page renders.
29
+
30
+ **Key Features:**
31
+ - ⚡ Prevents FOUC (flash of unstyled content)
32
+ - 🌐 Framework agnostic (Next.js, Vite, Remix, etc.)
33
+ - 🔄 Perfect synchronization across multiple theme toggles
34
+ - 🍪 Persistent theme storage via cookies
35
+ - 🎨 System theme detection and following
36
+ - ⚙️ Zero configuration required
37
+
38
+ **Usage:**
39
+ Place the Theme component once at the root of your application, ideally in the document head or at the very top of your app component.
40
+ `,
41
+ },
42
+ },
43
+ },
44
+ tags: ["autodocs"],
45
+ } satisfies Meta<typeof Theme>;
46
+
47
+ export default meta;
48
+ type Story = StoryObj<typeof meta>;
49
+
50
+ /**
51
+ * Basic usage showing the Theme component with a simple themed interface.
52
+ * The Theme component should be placed at the top of your application to prevent FOUC.
53
+ */
54
+ export const Basic: Story = {
55
+ render: () => (
56
+ <div className="min-h-screen bg-background text-foreground p-8">
57
+ <Theme />
58
+
59
+ <div className="max-w-2xl mx-auto space-y-6">
60
+ <div className="text-center space-y-2">
61
+ <h1 className="text-3xl font-bold">Theme Setup Demo</h1>
62
+ <p className="text-muted-foreground">
63
+ The Theme component prevents FOUC and enables theming system
64
+ </p>
65
+ </div>
66
+
67
+ <Card>
68
+ <CardHeader>
69
+ <CardTitle>Themed Content</CardTitle>
70
+ </CardHeader>
71
+ <CardContent className="space-y-4">
72
+ <p className="text-sm text-muted-foreground">
73
+ This content is themed correctly without any flash of unstyled
74
+ content. The Theme component loads the user&apos;s preferred theme
75
+ before first paint.
76
+ </p>
77
+
78
+ <div className="flex items-center justify-center">
79
+ <ThemeToggle />
80
+ </div>
81
+ </CardContent>
82
+ </Card>
83
+ </div>
84
+ </div>
85
+ ),
86
+ };
87
+
88
+ /**
89
+ * Demonstrates multiple synchronized theme toggles working together.
90
+ * All toggles stay perfectly in sync through the custom event system.
91
+ */
92
+ export const MultipleSynchronizedToggles: Story = {
93
+ render: () => (
94
+ <div className="min-h-screen bg-background text-foreground">
95
+ <Theme />
96
+
97
+ {/* Header with theme toggle */}
98
+ <header className="border-b p-4">
99
+ <div className="max-w-4xl mx-auto flex items-center justify-between">
100
+ <h1 className="text-xl font-semibold">My App</h1>
101
+ <ThemeToggle />
102
+ </div>
103
+ </header>
104
+
105
+ {/* Main content */}
106
+ <main className="p-8">
107
+ <div className="max-w-4xl mx-auto grid gap-6 md:grid-cols-2">
108
+ <Card>
109
+ <CardHeader>
110
+ <div className="flex items-center justify-between">
111
+ <CardTitle>Settings Panel</CardTitle>
112
+ <ThemeToggle variant="ghost" size="sm" />
113
+ </div>
114
+ </CardHeader>
115
+ <CardContent className="space-y-4">
116
+ <p className="text-sm text-muted-foreground">
117
+ This toggle is synchronized with all other theme toggles on the
118
+ page. Try switching themes and watch how they all update
119
+ together.
120
+ </p>
121
+ <Button variant="outline">Configure Settings</Button>
122
+ </CardContent>
123
+ </Card>
124
+
125
+ <Card>
126
+ <CardHeader>
127
+ <div className="flex items-center justify-between">
128
+ <CardTitle>User Profile</CardTitle>
129
+ <ThemeToggle variant="secondary" showLabel />
130
+ </div>
131
+ </CardHeader>
132
+ <CardContent className="space-y-4">
133
+ <p className="text-sm text-muted-foreground">
134
+ All theme toggles use the same underlying state via cookies and
135
+ custom events. This ensures perfect synchronization without any
136
+ providers or context.
137
+ </p>
138
+ <Button>Update Profile</Button>
139
+ </CardContent>
140
+ </Card>
141
+ </div>
142
+ </main>
143
+
144
+ {/* Footer with another toggle */}
145
+ <footer className="border-t mt-8 p-4">
146
+ <div className="max-w-4xl mx-auto flex items-center justify-between">
147
+ <p className="text-sm text-muted-foreground">
148
+ Footer content with synchronized theme
149
+ </p>
150
+ <ThemeToggle variant="outline" size="sm" />
151
+ </div>
152
+ </footer>
153
+ </div>
154
+ ),
155
+ };
156
+
157
+ /**
158
+ * Framework integration examples showing how to use Theme with different React frameworks.
159
+ * This story demonstrates the setup patterns for Next.js, Vite, and other frameworks.
160
+ */
161
+ export const FrameworkIntegration: Story = {
162
+ render: () => (
163
+ <div className="min-h-screen bg-background text-foreground p-8">
164
+ <Theme />
165
+
166
+ <div className="max-w-4xl mx-auto space-y-8">
167
+ <div className="text-center space-y-2">
168
+ <h1 className="text-3xl font-bold">Framework Integration</h1>
169
+ <p className="text-muted-foreground">
170
+ Theme component works with any React framework
171
+ </p>
172
+ </div>
173
+
174
+ <div className="grid gap-6 md:grid-cols-2">
175
+ <Card>
176
+ <CardHeader>
177
+ <CardTitle>Next.js App Router</CardTitle>
178
+ </CardHeader>
179
+ <CardContent>
180
+ <pre className="text-xs bg-muted p-3 rounded overflow-x-auto">
181
+ {`// app/layout.tsx
182
+ import { Theme } from "@neynar/ui";
183
+
184
+ export default function RootLayout({ children }) {
185
+ return (
186
+ <html suppressHydrationWarning>
187
+ <head>
188
+ <Theme /> {/* Prevents FOUC */}
189
+ </head>
190
+ <body>{children}</body>
191
+ </html>
192
+ );
193
+ }`}
194
+ </pre>
195
+ </CardContent>
196
+ </Card>
197
+
198
+ <Card>
199
+ <CardHeader>
200
+ <CardTitle>Vite + React</CardTitle>
201
+ </CardHeader>
202
+ <CardContent>
203
+ <pre className="text-xs bg-muted p-3 rounded overflow-x-auto">
204
+ {`// App.tsx
205
+ import { Theme } from "@neynar/ui";
206
+
207
+ function App() {
208
+ return (
209
+ <>
210
+ <Theme /> {/* Place at the top */}
211
+ <div className="app">
212
+ {/* Your content */}
213
+ </div>
214
+ </>
215
+ );
216
+ }`}
217
+ </pre>
218
+ </CardContent>
219
+ </Card>
220
+
221
+ <Card>
222
+ <CardHeader>
223
+ <CardTitle>Next.js Pages Router</CardTitle>
224
+ </CardHeader>
225
+ <CardContent>
226
+ <pre className="text-xs bg-muted p-3 rounded overflow-x-auto">
227
+ {`// pages/_document.tsx
228
+ import { Theme } from "@neynar/ui";
229
+
230
+ export default function Document() {
231
+ return (
232
+ <Html>
233
+ <Head>
234
+ <Theme /> {/* In document head */}
235
+ </Head>
236
+ <body>
237
+ <Main />
238
+ <NextScript />
239
+ </body>
240
+ </Html>
241
+ );
242
+ }`}
243
+ </pre>
244
+ </CardContent>
245
+ </Card>
246
+
247
+ <Card>
248
+ <CardHeader>
249
+ <CardTitle>Remix</CardTitle>
250
+ </CardHeader>
251
+ <CardContent>
252
+ <pre className="text-xs bg-muted p-3 rounded overflow-x-auto">
253
+ {`// app/root.tsx
254
+ import { Theme } from "@neynar/ui";
255
+
256
+ export default function Root() {
257
+ return (
258
+ <html>
259
+ <head>
260
+ <Theme /> {/* Before other head content */}
261
+ <Meta />
262
+ <Links />
263
+ </head>
264
+ <body>
265
+ <Outlet />
266
+ <ScrollRestoration />
267
+ <Scripts />
268
+ </body>
269
+ </html>
270
+ );
271
+ }`}
272
+ </pre>
273
+ </CardContent>
274
+ </Card>
275
+ </div>
276
+
277
+ <Card>
278
+ <CardHeader>
279
+ <CardTitle>Live Demo</CardTitle>
280
+ </CardHeader>
281
+ <CardContent className="space-y-4">
282
+ <p className="text-sm text-muted-foreground">
283
+ The Theme component is already active on this page, preventing
284
+ FOUC and enabling the theme system to work correctly. Use the
285
+ toggle below to test theme switching.
286
+ </p>
287
+
288
+ <div className="flex items-center justify-center">
289
+ <ThemeToggle showLabel />
290
+ </div>
291
+ </CardContent>
292
+ </Card>
293
+ </div>
294
+ </div>
295
+ ),
296
+ };
297
+
298
+ /**
299
+ * Technical implementation details showing how the Theme component works internally.
300
+ * This story provides insight into the script content and architecture.
301
+ */
302
+ export const TechnicalDetails: Story = {
303
+ render: () => (
304
+ <div className="min-h-screen bg-background text-foreground p-8">
305
+ <Theme />
306
+
307
+ <div className="max-w-4xl mx-auto space-y-6">
308
+ <div className="text-center space-y-2">
309
+ <h1 className="text-3xl font-bold">How Theme Works</h1>
310
+ <p className="text-muted-foreground">
311
+ Under the hood technical details
312
+ </p>
313
+ </div>
314
+
315
+ <div className="grid gap-6">
316
+ <Card>
317
+ <CardHeader>
318
+ <CardTitle>Script Content</CardTitle>
319
+ </CardHeader>
320
+ <CardContent>
321
+ <p className="text-sm text-muted-foreground mb-4">
322
+ The Theme component injects a small inline script that executes
323
+ before React hydration:
324
+ </p>
325
+ <pre className="text-xs bg-muted p-3 rounded overflow-x-auto max-h-60">
326
+ {`// Injected script content (minified in production)
327
+ (function() {
328
+ try {
329
+ // Read theme preference from cookie
330
+ var cookie = document.cookie.match(/theme=([^;]*)/);
331
+ var stored = cookie ? JSON.parse(decodeURIComponent(cookie[1])) : null;
332
+ var preference = stored ? stored.preference : 'system';
333
+ var mode;
334
+
335
+ // Determine active theme mode
336
+ if (preference === 'system') {
337
+ mode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
338
+ } else {
339
+ mode = preference;
340
+ }
341
+
342
+ // Apply theme to document root
343
+ if (mode === 'dark') {
344
+ document.documentElement.classList.add('dark');
345
+ } else {
346
+ document.documentElement.classList.remove('dark');
347
+ }
348
+
349
+ // Set color-scheme for native elements
350
+ document.documentElement.style.colorScheme = mode;
351
+ } catch (e) {
352
+ // Graceful fallback - default to light theme
353
+ document.documentElement.classList.remove('dark');
354
+ document.documentElement.style.colorScheme = 'light';
355
+ }
356
+ })();`}
357
+ </pre>
358
+ </CardContent>
359
+ </Card>
360
+
361
+ <Card>
362
+ <CardHeader>
363
+ <CardTitle>Synchronization Architecture</CardTitle>
364
+ </CardHeader>
365
+ <CardContent className="space-y-4">
366
+ <p className="text-sm text-muted-foreground">
367
+ Multiple theme toggles stay perfectly synchronized through
368
+ custom events:
369
+ </p>
370
+
371
+ <div className="space-y-3">
372
+ <div className="flex items-center gap-3">
373
+ <div className="w-2 h-2 bg-blue-500 rounded-full" />
374
+ <span className="text-sm">
375
+ Cookie stores theme preference (single source of truth)
376
+ </span>
377
+ </div>
378
+ <div className="flex items-center gap-3">
379
+ <div className="w-2 h-2 bg-green-500 rounded-full" />
380
+ <span className="text-sm">
381
+ Custom &apos;theme-change&apos; events broadcast changes
382
+ </span>
383
+ </div>
384
+ <div className="flex items-center gap-3">
385
+ <div className="w-2 h-2 bg-purple-500 rounded-full" />
386
+ <span className="text-sm">
387
+ All useTheme hooks listen and update in sync
388
+ </span>
389
+ </div>
390
+ <div className="flex items-center gap-3">
391
+ <div className="w-2 h-2 bg-orange-500 rounded-full" />
392
+ <span className="text-sm">
393
+ DOM updates happen immediately (no React re-render delay)
394
+ </span>
395
+ </div>
396
+ </div>
397
+
398
+ <div className="flex items-center justify-center pt-4">
399
+ <div className="flex gap-2">
400
+ <ThemeToggle variant="default" size="sm" />
401
+ <ThemeToggle variant="outline" size="sm" />
402
+ <ThemeToggle variant="ghost" size="sm" />
403
+ <ThemeToggle variant="secondary" size="sm" />
404
+ </div>
405
+ </div>
406
+ </CardContent>
407
+ </Card>
408
+ </div>
409
+ </div>
410
+ </div>
411
+ ),
412
+ };