@justanarthur/modo-ui 0.6.0-canary.8 → 0.6.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 (490) hide show
  1. package/README.md +66 -164
  2. package/dist/base.css +4 -141
  3. package/dist/blocks/sidebar-app/index.js +26 -40
  4. package/dist/components/AI/input-message/index.js +16 -23
  5. package/dist/components/AI/thinking-indicator/index.js +6 -9
  6. package/dist/components/accordion/index.d.ts +11 -39
  7. package/dist/components/accordion/index.js +13 -18
  8. package/dist/components/badge/index.d.ts +11 -18
  9. package/dist/components/badge/index.js +7 -12
  10. package/dist/components/button/index.d.ts +17 -53
  11. package/dist/components/button/index.js +6 -11
  12. package/dist/components/card/index.d.ts +9 -32
  13. package/dist/components/card/index.js +11 -17
  14. package/dist/components/copy/index.d.ts +8 -41
  15. package/dist/components/copy/index.js +9 -15
  16. package/dist/components/inputs/checkbox/index.d.ts +9 -28
  17. package/dist/components/inputs/checkbox/index.js +13 -18
  18. package/dist/components/inputs/color-picker/index.d.ts +14 -22
  19. package/dist/components/inputs/color-picker/index.js +18 -26
  20. package/dist/components/inputs/combobox/index.d.ts +20 -85
  21. package/dist/components/inputs/combobox/index.js +18 -27
  22. package/dist/components/inputs/date-time/calendar/index.d.ts +18 -24
  23. package/dist/components/inputs/date-time/calendar/index.js +11 -15
  24. package/dist/components/inputs/date-time/date-picker/index.d.ts +16 -105
  25. package/dist/components/inputs/date-time/date-picker/index.js +25 -35
  26. package/dist/components/inputs/date-time/date-range-picker/index.d.ts +12 -106
  27. package/dist/components/inputs/date-time/date-range-picker/index.js +24 -35
  28. package/dist/components/inputs/date-time/duration-picker/index.d.ts +13 -66
  29. package/dist/components/inputs/date-time/duration-picker/index.js +24 -33
  30. package/dist/components/inputs/date-time/month-picker/index.d.ts +10 -60
  31. package/dist/components/inputs/date-time/month-picker/index.js +23 -32
  32. package/dist/components/inputs/date-time/time-picker/index.d.ts +10 -58
  33. package/dist/components/inputs/date-time/time-picker/index.js +24 -33
  34. package/dist/components/inputs/input/index.d.ts +13 -95
  35. package/dist/components/inputs/input/index.js +9 -18
  36. package/dist/components/inputs/radio/index.d.ts +5 -20
  37. package/dist/components/inputs/radio/index.js +12 -16
  38. package/dist/components/inputs/search/index.d.ts +3 -3
  39. package/dist/components/inputs/search/index.js +18 -26
  40. package/dist/components/inputs/select/index.d.ts +23 -99
  41. package/dist/components/inputs/select/index.js +14 -29
  42. package/dist/components/inputs/slider/index.d.ts +0 -9
  43. package/dist/components/inputs/slider/index.js +5 -8
  44. package/dist/components/inputs/switch/index.d.ts +2 -8
  45. package/dist/components/inputs/switch/index.js +12 -15
  46. package/dist/components/inputs/textarea/index.d.ts +1 -20
  47. package/dist/components/inputs/textarea/index.js +6 -9
  48. package/dist/components/navigation/sidebar/index.d.ts +21 -44
  49. package/dist/components/navigation/sidebar/index.js +31 -42
  50. package/dist/components/navigation/tabs/index.d.ts +2 -8
  51. package/dist/components/navigation/tabs/index.js +10 -15
  52. package/dist/components/navigation/tabs-subtle/index.js +10 -13
  53. package/dist/components/overlays/alert-dialog/index.d.ts +16 -135
  54. package/dist/components/overlays/alert-dialog/index.js +13 -23
  55. package/dist/components/overlays/command/index.d.ts +20 -25
  56. package/dist/components/overlays/command/index.js +17 -25
  57. package/dist/components/overlays/context-menu/index.d.ts +17 -39
  58. package/dist/components/overlays/context-menu/index.js +18 -29
  59. package/dist/components/overlays/dialog/index.d.ts +16 -42
  60. package/dist/components/overlays/dialog/index.js +12 -20
  61. package/dist/components/overlays/dropdown/index.d.ts +34 -304
  62. package/dist/components/overlays/dropdown/index.js +17 -44
  63. package/dist/components/overlays/popover/index.d.ts +12 -38
  64. package/dist/components/overlays/popover/index.js +9 -13
  65. package/dist/components/overlays/preview-card/index.js +8 -12
  66. package/dist/components/overlays/sheet/index.d.ts +8 -25
  67. package/dist/components/overlays/sheet/index.js +13 -19
  68. package/dist/components/overlays/toast/index.d.ts +50 -209
  69. package/dist/components/overlays/toast/index.js +10 -23
  70. package/dist/components/overlays/tooltip/index.d.ts +21 -123
  71. package/dist/components/overlays/tooltip/index.js +6 -16
  72. package/dist/components/table/index.d.ts +8 -63
  73. package/dist/components/table/index.js +9 -20
  74. package/dist/index.d.ts +1048 -2999
  75. package/dist/index.js +82 -231
  76. package/dist/preset.d.ts +0 -22
  77. package/dist/preset.js +2 -24
  78. package/dist/primitives/code/index.js +5 -8
  79. package/dist/primitives/craft/index.js +6 -10
  80. package/dist/primitives/fluid-hover/index.js +8 -10
  81. package/dist/primitives/morph/index.js +10 -16
  82. package/dist/primitives/motion/index.js +8 -11
  83. package/dist/primitives/scroll-area/index.js +3 -5
  84. package/dist/primitives/sizes/index.js +4 -6
  85. package/dist/primitives/surface/index.js +4 -6
  86. package/dist/shared/{components-4y816hwp.js → components-0q0sqfh4.js} +49 -27
  87. package/dist/shared/components-0sn7ypjw.js +61 -0
  88. package/dist/shared/{components-vc864c51.js → components-11da9ajg.js} +5 -8
  89. package/dist/shared/components-1434p1mh.js +123 -0
  90. package/dist/shared/{components-t2a3qmy9.js → components-1z6tdadk.js} +24 -40
  91. package/dist/shared/{components-qs4rkqsj.js → components-27nnvrwe.js} +14 -15
  92. package/dist/shared/{components-av5t26rc.js → components-2dxkv6zm.js} +7 -8
  93. package/dist/shared/{components-wqrvqq5p.js → components-2ecg8svx.js} +152 -234
  94. package/dist/shared/{components-3ydr2fqe.js → components-2ph6t61s.js} +34 -37
  95. package/dist/shared/{components-6gk118w3.js → components-39jq9va1.js} +24 -29
  96. package/dist/shared/components-3ky44908.js +9 -0
  97. package/dist/shared/{components-y1qvbawa.js → components-3mkepka5.js} +25 -28
  98. package/dist/shared/{components-xqszvkj4.js → components-4700p9kz.js} +22 -24
  99. package/dist/shared/{components-yhgq0qxx.js → components-59efxjd9.js} +12 -13
  100. package/dist/shared/{components-9j9abkct.js → components-5vgpnxgy.js} +27 -51
  101. package/dist/shared/{components-8tt3xbb5.js → components-5xc2j8jz.js} +18 -19
  102. package/dist/shared/{components-jymmaevv.js → components-6p8tfcd6.js} +29 -57
  103. package/dist/shared/{components-4nck8acq.js → components-7r3etddy.js} +54 -19
  104. package/dist/shared/{components-skfd7kff.js → components-8snj490h.js} +32 -78
  105. package/dist/shared/{components-ctqmge8t.js → components-b0eac83j.js} +30 -9
  106. package/dist/shared/{components-9sttq78t.js → components-b2wyq2cq.js} +59 -41
  107. package/dist/shared/{components-vkwq2k96.js → components-b3c5et5b.js} +38 -49
  108. package/dist/shared/{components-rrbpmfx4.js → components-c6s6b43g.js} +2 -3
  109. package/dist/shared/{components-pw06rbxq.js → components-chacnk61.js} +19 -19
  110. package/dist/shared/{components-71nbt03m.js → components-cv16mryv.js} +7 -26
  111. package/dist/shared/{components-eqze3y30.js → components-d6xtjht3.js} +30 -35
  112. package/dist/shared/{components-5y5shqfd.js → components-dk0gjr5a.js} +18 -19
  113. package/dist/shared/{components-khspp26b.js → components-fzrq6tr3.js} +34 -37
  114. package/dist/shared/{components-km7fhgbk.js → components-gc5vtq2f.js} +30 -66
  115. package/dist/shared/components-gf5s6ap9.js +42 -0
  116. package/dist/shared/{components-qqcmtrbv.js → components-gz8zf3ec.js} +55 -56
  117. package/dist/shared/{components-mattt5jp.js → components-h2ajmhwn.js} +35 -107
  118. package/dist/shared/{components-awra5sff.js → components-hqeq3w9q.js} +16 -24
  119. package/dist/shared/{components-5tzhqbcw.js → components-hw9yk32z.js} +24 -36
  120. package/dist/shared/components-hyq23phv.js +310 -0
  121. package/dist/shared/{components-8mt5bsv6.js → components-jbbmdr74.js} +22 -41
  122. package/dist/shared/{components-dcc02hs2.js → components-jjw69c4c.js} +4 -7
  123. package/dist/shared/{components-2syq4mwc.js → components-jthe1pwb.js} +420 -139
  124. package/dist/shared/{components-r7q1zm7r.js → components-jwst3vtj.js} +76 -224
  125. package/dist/shared/{components-qdm3yh26.js → components-kvr7f9hy.js} +10 -19
  126. package/dist/shared/{components-s8yqk2dc.js → components-kwa6mrf9.js} +11 -46
  127. package/dist/shared/{components-de99ykt7.js → components-men63rwj.js} +2 -3
  128. package/dist/shared/{components-6b0zb8z3.js → components-mjthm1kf.js} +9 -13
  129. package/dist/shared/{components-2c64r8c9.js → components-n42c79bz.js} +22 -23
  130. package/dist/shared/{components-tz1fv35x.js → components-n7mjr357.js} +2 -3
  131. package/dist/shared/components-ng72k97e.js +128 -0
  132. package/dist/shared/{components-dyae0y7h.js → components-pbmqctfa.js} +65 -169
  133. package/dist/shared/{components-px2zm7dc.js → components-q5xj5c16.js} +8 -9
  134. package/dist/shared/components-raknhppb.js +64 -0
  135. package/dist/shared/{components-8rb25gbe.js → components-rr7a6ja9.js} +27 -59
  136. package/dist/shared/{components-5012r6gr.js → components-s083f38z.js} +34 -164
  137. package/dist/shared/components-s5ngg32c.js +267 -0
  138. package/dist/shared/components-sn1rxx1d.js +143 -0
  139. package/dist/shared/{components-r8eqs7gz.js → components-ta7shw28.js} +4 -4
  140. package/dist/shared/{components-9as3rf68.js → components-vc7vq5nz.js} +3 -6
  141. package/dist/shared/{components-ft3zdc79.js → components-vfbhxf5r.js} +5 -6
  142. package/dist/shared/components-vynjtrk6.js +19 -0
  143. package/dist/shared/{components-w0xq6q9k.js → components-w1r67ag9.js} +149 -294
  144. package/dist/shared/{components-z0bqtvcp.js → components-w90endve.js} +72 -71
  145. package/dist/shared/{components-t5pk5nmc.js → components-wvp1m52g.js} +102 -149
  146. package/dist/shared/components-wy9jpqny.js +146 -0
  147. package/dist/shared/{components-5sxjeh6h.js → components-y9y0g8er.js} +28 -52
  148. package/dist/shared/components-ypp01w3p.js +986 -0
  149. package/dist/shared/{components-t50hrswb.js → components-zfnmn5d4.js} +36 -82
  150. package/dist/shared/{components-jqpefjsn.js → components-zrkzcayz.js} +6 -54
  151. package/dist/shared/{components-vf45j12c.js → components-zx6b6yby.js} +18 -4
  152. package/dist/styles.css +32 -320
  153. package/dist/tailwind.css +0 -16
  154. package/dist/tokens.css +0 -67
  155. package/package.json +4 -227
  156. package/DESIGN.md +0 -623
  157. package/blocks/sidebar-app/examples.mdx +0 -33
  158. package/blocks/sidebar-app/index.tsx +0 -218
  159. package/blocks/sidebar-app/inset-topbar.tsx +0 -25
  160. package/blocks/sidebar-app/menu-grid.ts +0 -26
  161. package/blocks/sidebar-app/nav-data.ts +0 -36
  162. package/blocks/sidebar-app/search-field.tsx +0 -48
  163. package/blocks/sidebar-app/user-footer.tsx +0 -67
  164. package/blocks/sidebar-app/workspace-header.tsx +0 -129
  165. package/components/AI/input-message/examples.mdx +0 -130
  166. package/components/AI/input-message/file-thumbnail.tsx +0 -173
  167. package/components/AI/input-message/index.tsx +0 -1385
  168. package/components/AI/thinking-indicator/examples.mdx +0 -27
  169. package/components/AI/thinking-indicator/index.tsx +0 -210
  170. package/components/accordion/examples.mdx +0 -233
  171. package/components/accordion/index.tsx +0 -1071
  172. package/components/avatar/examples.mdx +0 -95
  173. package/components/avatar/index.tsx +0 -129
  174. package/components/badge/change-demo.tsx +0 -29
  175. package/components/badge/examples.mdx +0 -124
  176. package/components/badge/index.tsx +0 -225
  177. package/components/badge/variants.ts +0 -73
  178. package/components/button/examples.mdx +0 -168
  179. package/components/button/index.tsx +0 -424
  180. package/components/button/loading-demo.tsx +0 -25
  181. package/components/button/variants.ts +0 -168
  182. package/components/card/examples.mdx +0 -251
  183. package/components/card/index.tsx +0 -1070
  184. package/components/copy/examples.mdx +0 -125
  185. package/components/copy/index.tsx +0 -662
  186. package/components/inputs/checkbox/examples.mdx +0 -87
  187. package/components/inputs/checkbox/index.tsx +0 -611
  188. package/components/inputs/checkbox/select-all-demo.tsx +0 -48
  189. package/components/inputs/color-picker/examples.mdx +0 -111
  190. package/components/inputs/color-picker/index.tsx +0 -1981
  191. package/components/inputs/color-picker/variants.ts +0 -401
  192. package/components/inputs/combobox/examples.mdx +0 -366
  193. package/components/inputs/combobox/index.tsx +0 -1527
  194. package/components/inputs/combobox/remote-demo.tsx +0 -105
  195. package/components/inputs/date-time/calendar/examples.mdx +0 -45
  196. package/components/inputs/date-time/calendar/index.tsx +0 -370
  197. package/components/inputs/date-time/calendar/use-month-window.ts +0 -173
  198. package/components/inputs/date-time/date-picker/examples.mdx +0 -243
  199. package/components/inputs/date-time/date-picker/index.tsx +0 -476
  200. package/components/inputs/date-time/date-picker/masked-date-input.tsx +0 -348
  201. package/components/inputs/date-time/date-range-picker/examples.mdx +0 -93
  202. package/components/inputs/date-time/date-range-picker/index.tsx +0 -525
  203. package/components/inputs/date-time/duration-picker/examples.mdx +0 -40
  204. package/components/inputs/date-time/duration-picker/index.tsx +0 -253
  205. package/components/inputs/date-time/month-picker/examples.mdx +0 -45
  206. package/components/inputs/date-time/month-picker/index.tsx +0 -254
  207. package/components/inputs/date-time/picker-shell.tsx +0 -581
  208. package/components/inputs/date-time/time-columns.tsx +0 -94
  209. package/components/inputs/date-time/time-picker/examples.mdx +0 -57
  210. package/components/inputs/date-time/time-picker/index.tsx +0 -227
  211. package/components/inputs/field/examples.mdx +0 -117
  212. package/components/inputs/field/index.tsx +0 -268
  213. package/components/inputs/file-dropzone/examples.mdx +0 -83
  214. package/components/inputs/file-dropzone/file-row.tsx +0 -201
  215. package/components/inputs/file-dropzone/index.tsx +0 -316
  216. package/components/inputs/file-dropzone/upload-demo.tsx +0 -67
  217. package/components/inputs/file-dropzone/variants.ts +0 -94
  218. package/components/inputs/input/examples.mdx +0 -166
  219. package/components/inputs/input/index.tsx +0 -494
  220. package/components/inputs/input/password-demo.tsx +0 -30
  221. package/components/inputs/label/examples.mdx +0 -67
  222. package/components/inputs/label/index.tsx +0 -85
  223. package/components/inputs/number-input/examples.mdx +0 -69
  224. package/components/inputs/number-input/index.tsx +0 -221
  225. package/components/inputs/radio/examples.mdx +0 -77
  226. package/components/inputs/radio/index.tsx +0 -636
  227. package/components/inputs/search/examples.mdx +0 -74
  228. package/components/inputs/search/index.tsx +0 -333
  229. package/components/inputs/select/examples.mdx +0 -296
  230. package/components/inputs/select/index.tsx +0 -1044
  231. package/components/inputs/select/variants.ts +0 -32
  232. package/components/inputs/slider/examples.mdx +0 -153
  233. package/components/inputs/slider/index.tsx +0 -1867
  234. package/components/inputs/switch/examples.mdx +0 -96
  235. package/components/inputs/switch/index.tsx +0 -504
  236. package/components/inputs/textarea/examples.mdx +0 -126
  237. package/components/inputs/textarea/index.tsx +0 -207
  238. package/components/navigation/navigation-menu/examples.mdx +0 -136
  239. package/components/navigation/navigation-menu/index.tsx +0 -704
  240. package/components/navigation/pagination/examples.mdx +0 -74
  241. package/components/navigation/pagination/index.tsx +0 -401
  242. package/components/navigation/sidebar/examples.mdx +0 -325
  243. package/components/navigation/sidebar/index.tsx +0 -453
  244. package/components/navigation/sidebar/sidebar-core.tsx +0 -1408
  245. package/components/navigation/sidebar/sidebar-menu.tsx +0 -1495
  246. package/components/navigation/sidebar/sidebar.css +0 -74
  247. package/components/navigation/sidebar/variants.ts +0 -55
  248. package/components/navigation/tabs/examples.mdx +0 -89
  249. package/components/navigation/tabs/index.tsx +0 -494
  250. package/components/navigation/tabs-subtle/examples.mdx +0 -49
  251. package/components/navigation/tabs-subtle/index.tsx +0 -512
  252. package/components/overlays/alert-dialog/examples.mdx +0 -123
  253. package/components/overlays/alert-dialog/index.tsx +0 -276
  254. package/components/overlays/alert-dialog/pending-demo.tsx +0 -36
  255. package/components/overlays/command/examples.mdx +0 -113
  256. package/components/overlays/command/index.tsx +0 -425
  257. package/components/overlays/context-menu/examples.mdx +0 -56
  258. package/components/overlays/context-menu/index.tsx +0 -279
  259. package/components/overlays/dialog/examples.mdx +0 -165
  260. package/components/overlays/dialog/index.tsx +0 -451
  261. package/components/overlays/dropdown/dropdown-search.tsx +0 -395
  262. package/components/overlays/dropdown/examples.mdx +0 -444
  263. package/components/overlays/dropdown/index.tsx +0 -1241
  264. package/components/overlays/dropdown/menu-item.tsx +0 -510
  265. package/components/overlays/dropdown/menu-parts.tsx +0 -725
  266. package/components/overlays/popover/anchored-demo.tsx +0 -59
  267. package/components/overlays/popover/examples.mdx +0 -203
  268. package/components/overlays/popover/index.tsx +0 -317
  269. package/components/overlays/preview-card/examples.mdx +0 -61
  270. package/components/overlays/preview-card/index.tsx +0 -204
  271. package/components/overlays/sheet/examples.mdx +0 -101
  272. package/components/overlays/sheet/index.tsx +0 -307
  273. package/components/overlays/toast/examples.mdx +0 -85
  274. package/components/overlays/toast/global-demo.tsx +0 -72
  275. package/components/overlays/toast/index.tsx +0 -544
  276. package/components/overlays/toast/manager.ts +0 -193
  277. package/components/overlays/tooltip/examples.mdx +0 -106
  278. package/components/overlays/tooltip/index.tsx +0 -539
  279. package/components/progress/examples.mdx +0 -59
  280. package/components/progress/index.tsx +0 -174
  281. package/components/progress/progress.css +0 -49
  282. package/components/progress/step-demo.tsx +0 -27
  283. package/components/table/examples.mdx +0 -188
  284. package/components/table/index.tsx +0 -535
  285. package/components/table/sort-demo.tsx +0 -61
  286. package/dist/components/avatar/index.d.ts +0 -46
  287. package/dist/components/avatar/index.js +0 -19
  288. package/dist/components/badge/variants.d.ts +0 -33
  289. package/dist/components/badge/variants.js +0 -10
  290. package/dist/components/button/variants.d.ts +0 -39
  291. package/dist/components/button/variants.js +0 -8
  292. package/dist/components/inputs/color-picker/variants.d.ts +0 -61
  293. package/dist/components/inputs/color-picker/variants.js +0 -28
  294. package/dist/components/inputs/field/index.d.ts +0 -116
  295. package/dist/components/inputs/field/index.js +0 -29
  296. package/dist/components/inputs/file-dropzone/index.d.ts +0 -167
  297. package/dist/components/inputs/file-dropzone/index.js +0 -33
  298. package/dist/components/inputs/file-dropzone/variants.d.ts +0 -35
  299. package/dist/components/inputs/file-dropzone/variants.js +0 -12
  300. package/dist/components/inputs/label/index.d.ts +0 -32
  301. package/dist/components/inputs/label/index.js +0 -11
  302. package/dist/components/inputs/number-input/index.d.ts +0 -87
  303. package/dist/components/inputs/number-input/index.js +0 -21
  304. package/dist/components/inputs/select/variants.d.ts +0 -5
  305. package/dist/components/inputs/select/variants.js +0 -6
  306. package/dist/components/navigation/navigation-menu/index.d.ts +0 -126
  307. package/dist/components/navigation/navigation-menu/index.js +0 -41
  308. package/dist/components/navigation/pagination/index.d.ts +0 -75
  309. package/dist/components/navigation/pagination/index.js +0 -41
  310. package/dist/components/navigation/sidebar/variants.d.ts +0 -25
  311. package/dist/components/navigation/sidebar/variants.js +0 -28
  312. package/dist/components/progress/index.d.ts +0 -56
  313. package/dist/components/progress/index.js +0 -15
  314. package/dist/docs/index.d.ts +0 -83
  315. package/dist/docs/index.js +0 -288
  316. package/dist/docs/vite.d.ts +0 -31
  317. package/dist/docs/vite.js +0 -45
  318. package/dist/lib/date-locale.d.ts +0 -26
  319. package/dist/lib/date-locale.js +0 -24
  320. package/dist/lib/field-classes.d.ts +0 -149
  321. package/dist/lib/field-classes.js +0 -41
  322. package/dist/lib/field-variants.d.ts +0 -47
  323. package/dist/lib/field-variants.js +0 -26
  324. package/dist/lib/fluid-hover-highlight.d.ts +0 -112
  325. package/dist/lib/fluid-hover-highlight.js +0 -17
  326. package/dist/lib/focus-ring.d.ts +0 -18
  327. package/dist/lib/focus-ring.js +0 -11
  328. package/dist/lib/goo-indicator.d.ts +0 -46
  329. package/dist/lib/goo-indicator.js +0 -14
  330. package/dist/lib/icon-context.d.ts +0 -30
  331. package/dist/lib/icon-context.js +0 -12
  332. package/dist/lib/inert.d.ts +0 -9
  333. package/dist/lib/inert.js +0 -8
  334. package/dist/lib/morph-layers.d.ts +0 -93
  335. package/dist/lib/morph-layers.js +0 -13
  336. package/dist/lib/morph-part.d.ts +0 -21
  337. package/dist/lib/morph-part.js +0 -12
  338. package/dist/lib/popup.d.ts +0 -20
  339. package/dist/lib/popup.js +0 -12
  340. package/dist/lib/reduced-motion.d.ts +0 -9
  341. package/dist/lib/reduced-motion.js +0 -6
  342. package/dist/lib/row-index.d.ts +0 -10
  343. package/dist/lib/row-index.js +0 -8
  344. package/dist/lib/row-order.d.ts +0 -28
  345. package/dist/lib/row-order.js +0 -10
  346. package/dist/lib/scroll-column.d.ts +0 -31
  347. package/dist/lib/scroll-column.js +0 -19
  348. package/dist/lib/shape-context.d.ts +0 -30
  349. package/dist/lib/shape-context.js +0 -13
  350. package/dist/lib/shape-radius.d.ts +0 -19
  351. package/dist/lib/shape-radius.js +0 -6
  352. package/dist/lib/size-context.d.ts +0 -94
  353. package/dist/lib/size-context.js +0 -20
  354. package/dist/lib/size-scale.d.ts +0 -79
  355. package/dist/lib/size-scale.js +0 -8
  356. package/dist/lib/slot.d.ts +0 -39
  357. package/dist/lib/slot.js +0 -14
  358. package/dist/lib/springs.d.ts +0 -44
  359. package/dist/lib/springs.js +0 -8
  360. package/dist/lib/surface-classes.d.ts +0 -19
  361. package/dist/lib/surface-classes.js +0 -10
  362. package/dist/lib/surface-context.d.ts +0 -9
  363. package/dist/lib/surface-context.js +0 -8
  364. package/dist/lib/use-controllable-state.d.ts +0 -2
  365. package/dist/lib/use-controllable-state.js +0 -6
  366. package/dist/lib/use-fluid-hover.d.ts +0 -138
  367. package/dist/lib/use-fluid-hover.js +0 -14
  368. package/dist/lib/use-is-mobile.d.ts +0 -2
  369. package/dist/lib/use-is-mobile.js +0 -6
  370. package/dist/lib/use-keyboard-nav-gate.d.ts +0 -20
  371. package/dist/lib/use-keyboard-nav-gate.js +0 -7
  372. package/dist/lib/use-merge-split.d.ts +0 -47
  373. package/dist/lib/use-merge-split.js +0 -15
  374. package/dist/lib/use-morph.d.ts +0 -101
  375. package/dist/lib/use-morph.js +0 -20
  376. package/dist/lib/use-touch-primary.d.ts +0 -2
  377. package/dist/lib/use-touch-primary.js +0 -6
  378. package/dist/lib/utils.d.ts +0 -3
  379. package/dist/lib/utils.js +0 -6
  380. package/dist/primitives/separator/index.d.ts +0 -25
  381. package/dist/primitives/separator/index.js +0 -9
  382. package/dist/primitives/skeleton/index.d.ts +0 -35
  383. package/dist/primitives/skeleton/index.js +0 -13
  384. package/dist/shared/components-124epb7f.js +0 -53
  385. package/dist/shared/components-1kab3j44.js +0 -337
  386. package/dist/shared/components-26snnbs9.js +0 -322
  387. package/dist/shared/components-34txk9rj.js +0 -35
  388. package/dist/shared/components-3h92d94m.js +0 -23
  389. package/dist/shared/components-4vfm04wq.js +0 -82
  390. package/dist/shared/components-54nq988h.js +0 -123
  391. package/dist/shared/components-7s7pykk5.js +0 -281
  392. package/dist/shared/components-7zkhz3r8.js +0 -399
  393. package/dist/shared/components-8v644a0s.js +0 -298
  394. package/dist/shared/components-a4evvq8h.js +0 -271
  395. package/dist/shared/components-adkarj8n.js +0 -35
  396. package/dist/shared/components-b1e239g3.js +0 -28
  397. package/dist/shared/components-b94t6qtj.js +0 -143
  398. package/dist/shared/components-c9yr4ed1.js +0 -44
  399. package/dist/shared/components-cwg1d0w6.js +0 -254
  400. package/dist/shared/components-d3shbwqq.js +0 -95
  401. package/dist/shared/components-dhgk6mbt.js +0 -16
  402. package/dist/shared/components-drxrtnp2.js +0 -25
  403. package/dist/shared/components-ej4r7wmj.js +0 -482
  404. package/dist/shared/components-f7h57m6t.js +0 -59
  405. package/dist/shared/components-fejdzvqc.js +0 -448
  406. package/dist/shared/components-gx4h5rbb.js +0 -40
  407. package/dist/shared/components-gyt7my41.js +0 -328
  408. package/dist/shared/components-h6p86be3.js +0 -19
  409. package/dist/shared/components-h83az0bz.js +0 -33
  410. package/dist/shared/components-hdzrqqpx.js +0 -55
  411. package/dist/shared/components-krtx3m5b.js +0 -84
  412. package/dist/shared/components-kswxnm3h.js +0 -24
  413. package/dist/shared/components-mpa2y6x8.js +0 -277
  414. package/dist/shared/components-mrbaxt8q.js +0 -62
  415. package/dist/shared/components-pt5ftm4p.js +0 -38
  416. package/dist/shared/components-rpw4md2b.js +0 -179
  417. package/dist/shared/components-rtadhd9j.js +0 -64
  418. package/dist/shared/components-tz4gaf1v.js +0 -23
  419. package/dist/shared/components-wbbckbw8.js +0 -34
  420. package/dist/shared/components-xdqmt6ed.js +0 -20
  421. package/dist/shared/components-xjkdvnbg.js +0 -107
  422. package/dist/shared/components-z3v0n0de.js +0 -11
  423. package/dist/shared/components-z6dfqtyt.js +0 -1545
  424. package/dist/tokens/colors.css +0 -230
  425. package/dist/tokens/motion.css +0 -40
  426. package/dist/tokens/radius.css +0 -10
  427. package/dist/tokens/spacing.css +0 -9
  428. package/dist/tokens/typography.css +0 -119
  429. package/docs/chrome.css +0 -120
  430. package/docs/chrome.tsx +0 -283
  431. package/docs/index.ts +0 -9
  432. package/docs/vite.ts +0 -85
  433. package/index.ts +0 -60
  434. package/lib/date-locale.ts +0 -195
  435. package/lib/field-classes.ts +0 -121
  436. package/lib/field-variants.ts +0 -117
  437. package/lib/fluid-hover-highlight.tsx +0 -139
  438. package/lib/focus-ring.tsx +0 -46
  439. package/lib/goo-indicator.tsx +0 -261
  440. package/lib/icon-context.tsx +0 -310
  441. package/lib/inert.ts +0 -22
  442. package/lib/morph-layers.tsx +0 -102
  443. package/lib/morph-part.tsx +0 -49
  444. package/lib/popup.ts +0 -52
  445. package/lib/reduced-motion.ts +0 -19
  446. package/lib/row-index.tsx +0 -29
  447. package/lib/row-order.tsx +0 -126
  448. package/lib/scroll-column.tsx +0 -273
  449. package/lib/shape-context.tsx +0 -138
  450. package/lib/shape-radius.ts +0 -67
  451. package/lib/size-context.tsx +0 -66
  452. package/lib/size-scale.ts +0 -115
  453. package/lib/slot.ts +0 -115
  454. package/lib/springs.ts +0 -62
  455. package/lib/surface-classes.ts +0 -58
  456. package/lib/surface-context.tsx +0 -21
  457. package/lib/use-controllable-state.ts +0 -44
  458. package/lib/use-fluid-hover.ts +0 -541
  459. package/lib/use-is-mobile.ts +0 -25
  460. package/lib/use-keyboard-nav-gate.ts +0 -45
  461. package/lib/use-merge-split.tsx +0 -209
  462. package/lib/use-morph.ts +0 -557
  463. package/lib/use-touch-primary.tsx +0 -43
  464. package/lib/utils.ts +0 -37
  465. package/preset.ts +0 -199
  466. package/primitives/code/examples.mdx +0 -27
  467. package/primitives/code/index.tsx +0 -80
  468. package/primitives/craft/demos.tsx +0 -173
  469. package/primitives/craft/examples.mdx +0 -142
  470. package/primitives/craft/index.tsx +0 -76
  471. package/primitives/fluid-hover/examples.mdx +0 -84
  472. package/primitives/fluid-hover/index.tsx +0 -316
  473. package/primitives/morph/examples.mdx +0 -139
  474. package/primitives/morph/index.tsx +0 -192
  475. package/primitives/motion/examples.mdx +0 -100
  476. package/primitives/motion/index.tsx +0 -160
  477. package/primitives/scroll-area/examples.mdx +0 -58
  478. package/primitives/scroll-area/index.tsx +0 -204
  479. package/primitives/separator/examples.mdx +0 -30
  480. package/primitives/separator/index.tsx +0 -53
  481. package/primitives/sizes/examples.mdx +0 -167
  482. package/primitives/sizes/index.tsx +0 -89
  483. package/primitives/skeleton/examples.mdx +0 -51
  484. package/primitives/skeleton/index.tsx +0 -72
  485. package/primitives/skeleton/skeleton.css +0 -15
  486. package/primitives/surface/examples.mdx +0 -173
  487. package/primitives/surface/index.tsx +0 -109
  488. package/primitives/surface/surface.css +0 -176
  489. /package/dist/shared/{components-3ey0hzpb.js → components-1v7rxytx.js} +0 -0
  490. /package/dist/shared/{components-jcnjay5g.js → components-ezxhrmer.js} +0 -0
package/README.md CHANGED
@@ -75,9 +75,7 @@ import 'virtual:uno.css'
75
75
  import '@justanarthur/modo-ui/base.css'
76
76
  ```
77
77
 
78
- `tokens.css` holds the CSS variables alone. Each token file also ships on its
79
- own, unchanged, as `@justanarthur/modo-ui/tokens/<group>.css` (`colors`, `motion`,
80
- `radius`, `spacing`, `typography`), for a host whose modo viewer reads `tokens/*.css`.
78
+ `tokens.css` holds the CSS variables alone.
81
79
 
82
80
  ### Theme
83
81
 
@@ -106,7 +104,7 @@ Every vendored file opens with a plain `/* */` header. The header names the
106
104
  upstream path and commit, carries the MIT notice, and lists every local
107
105
  modification. The vendored code below the header keeps upstream's formatting.
108
106
  Files written for this port (`preset.ts`, `uno.config.ts`, `vite.ts`, `index.ts`,
109
- `scripts/build-css.ts`, `docs/*`,
107
+ `scripts/build-css.ts`, `modo.components.tsx`,
110
108
  `lib/use-controllable-state.ts`, `primitives/code/index.tsx`, `primitives/craft/*`, the morph files
111
109
  in `lib/` (`use-morph.ts`, `reduced-motion.ts`, `morph-layers.tsx`, `morph-part.tsx`, `goo-indicator.tsx`,
112
110
  `slot.ts`) and `primitives/morph/index.tsx`, `blocks/sidebar-app/index.tsx`,
@@ -135,15 +133,14 @@ positioning) are ported.
135
133
  |---|---|
136
134
  | `AGENTS.md` | The ui-specific guide for coding agents (where things live, the rules that matter most, the checks); `CLAUDE.md` imports it. |
137
135
  | `DESIGN.md` | The design language in Google's [DESIGN.md](https://github.com/google-labs-code/design.md) format: the tokens as front matter, the rules as prose. Agents building here follow the `modo-ui` skill (`.claude/skills/modo-ui` at the repo root). |
138
- | `tokens/*.css` | Colors, typography (`--font-sans`, `--text-*`), motion (`--duration-*`), radius and spacing. Shipped per group as `dist/tokens/*.css` (`./tokens/*`). |
139
- | `base.css` | Theme switching, base styles, focus fallback, scrollbars, shimmer/spinner keyframes and `.scroll-fade`. Shipped in the package. The inline `code` chip applies only inside the docs shell, `data-modo="prose"` and `.modo-prose`. |
140
- | `global.css` | The docs site's stylesheet (`modo.config.ts` `css`): imports `base.css`, then `docs/chrome.css`. |
136
+ | `tokens/*.css` | Colors, typography (`--font-sans`, `--text-*`), motion (`--duration-*`), radius and spacing. |
137
+ | `base.css` | Theme switching, base styles, focus fallback, scrollbars, shimmer/spinner keyframes and `.scroll-fade`. Shipped in the package. |
138
+ | `global.css` | The docs site's stylesheet (`modo.config.ts` `css`): imports `base.css`, then the modo-only focus revert and the docs chrome. |
141
139
  | `preset.ts` | The UnoCSS preset (theme and token utilities), shipped as `@justanarthur/modo-ui/unocss`. |
142
- | `uno.config.ts`, `vite.ts` | The UnoCSS setup of the docs site and the prebuilt CSS (see below); `vite.ts` also applies the docs chrome's `docsTheme` plugin. |
140
+ | `uno.config.ts`, `vite.ts` | The UnoCSS setup of the docs site and the prebuilt CSS (see below). |
143
141
  | `index.ts`, `bunup.config.ts`, `scripts/build-css.ts` | The package build: `bun run build` writes the components, their types and the stylesheets to `dist/`. The docs site builds with `bun run build:docs` into `docs-dist/`. |
144
- | `scripts/exports.ts`, `scripts/use-client.ts`, `scripts/check-singletons.ts` | Packaging around that build. `exports.ts` (first step of `bun run build`) writes one `./lib/<name>` export per `lib/` module into `package.json`, plus `./components/*/variants` and `./blocks/*/variants` for the items' server-callable `variants.ts` entries; commit the `package.json` it leaves. `use-client.ts` (after bunup) puts `"use client"` on the emitted modules that render, call a hook or create a context, or use a binding from one; pure helpers (`cn`, class tables, springs, `variants.ts`) and re-export entries stay directive-free so a React Server Component can call them (`--list` prints the split). `check-singletons.ts` (`bun run check:dist`) checks that every React context and the `toast()` manager exist once in `dist/`, and that every entry has its `.d.ts`. `typesVersions` in `package.json` maps every public subpath to `dist/**/*.d.ts`, so `moduleResolution: node` consumers do not type-check the shipped source. |
145
142
  | `lib/` | FF's shared system files (upstream `lib/`, `hooks/` and the fluid-hover highlight, flat, upstream names), imported relatively by items. modo only scans the tier folders, so it never mistakes them for items. |
146
- | `docs/` | The docs chrome, shipped: `chrome.tsx` (the `Button`, `Link`, `Icon`, `Select` and `DocsNav` shell-slot adapters and the `ThemeSwitcher` panel item, re-exported by `index.ts` as `@justanarthur/modo-ui/docs`), `chrome.css` (the inset layout and the look of the chrome, `@justanarthur/modo-ui/docs/chrome.css`) and `vite.ts` (`docsTheme`, the pre-paint theme controller, `@justanarthur/modo-ui/docs/vite`). `modo.config.ts` picks the slots by export name (`./docs#DocsNav`); another design system documented with modo points at the same module by package specifier (see **The docs chrome, for another design system**). The barrel (`index.ts`) never imports it, `bun run check:dist` fails if it does. |
143
+ | `modo.components.tsx` | Components only the docs site uses: the `Icon`, `Select` and `DocsNav` shell-slot adapters and the `ThemeSwitcher` panel item, picked in `modo.config.ts` by export name (`./modo.components.tsx#Select`). |
147
144
  | `primitives/<id>/` | FF's "System" pages: `index.tsx` (component + TSDoc prose) and `examples.mdx`, pulled in by `@example {@include ./examples.mdx}`. |
148
145
  | `components/[<group>/]<id>/` | FF's "Components" pages, same shape. The `AI/`, `inputs/` (with `inputs/date-time/`), `navigation/` and `overlays/` group folders become sidebar sub-groups and overview sections; the core display items stay ungrouped. |
149
146
  | `blocks/<id>/` | Compositions of several items, same shape: `sidebar-app`, FF's sidebar preset `sa1FQfCxH6` as an app shell, with the header and footer blocks it is built from beside it. |
@@ -158,10 +155,8 @@ positioning) are ported.
158
155
  | `lib/springs.ts` | `lib/springs.ts` | `goo` tier added (the morph engine's goo: 250ms to land, bounce 0.15, a 200ms spring back); `exitFallbackMs` also reads a spring exit's `visualDuration` |
159
156
  | `lib/font-weight.ts` | — | not ported: its `fontWeights` became the `--weight-*` tokens in `tokens/typography.css` (the `weight-*` utilities) |
160
157
  | `lib/popup.ts` | `lib/popup.ts` | `popupMotionClass` dropped (unused since the popups morph) |
161
- | `lib/shape-context.tsx` | `lib/shape-context.tsx` | `"use client"` dropped; `--shape-input-radius` is published through `claimShapeRadius` and given back on unmount |
162
- | — (new) | `lib/shape-radius.ts` | Local addition: the stack of `ShapeProvider` claims on `--shape-input-radius` (`<html>`), so an unmounting provider restores the one below it or the page's own value; plain data, tested without a DOM |
163
- | `lib/size-context.tsx` | `lib/size-context.tsx` | `"use client"` dropped; `SizeProvider` moved to `primitives/sizes` (the documented item), with `SizeContext` exported for it; `sizeMap`, `typeScale` and their types moved to `size-scale.ts` and re-exported |
164
- | `lib/size-context.tsx` (`sizeMap`, `typeScale`) | `lib/size-scale.ts` | The ladder's plain data, split out so server code can read it (no JSX, hooks or contexts); `sizeMap` text classes → `text-body` / `text-body-compact` |
158
+ | `lib/shape-context.tsx` | `lib/shape-context.tsx` | `"use client"` dropped |
159
+ | `lib/size-context.tsx` | `lib/size-context.tsx` | `"use client"` dropped; `SizeProvider` moved to `primitives/sizes` (the documented item), with `SizeContext` exported for it; `sizeMap` text classes → `text-body` / `text-body-compact` |
165
160
  | `lib/icon-context.tsx` | `lib/icon-context.tsx` | `"use client"` dropped; `size`/`strokeWidth` widened to `number \| string` for lucide v1 + React 18 types |
166
161
  | `lib/surface-context.tsx` | `lib/surface-context.tsx` | `"use client"` dropped |
167
162
  | `lib/surface-classes.ts` | `lib/surface-classes.ts` | `SURFACE_HOVER_*` and `surfaceHoverClasses` dropped (only Sidebar used them) |
@@ -174,14 +169,10 @@ positioning) are ported.
174
169
  | — (new) | `lib/use-controllable-state.ts` | Local addition: controlled + uncontrolled state, Base UI style |
175
170
  | — (new) | `lib/use-morph.ts` | Local addition: the morph engine (source rect → popup box on a spring tier, exit hold for Base UI's unmount), geometry after beUI's popover; goo runs on its own `spring.goo` with a blur of at least 8px that eases to nothing as the surface lands, so the neck pinches off; a close-only `exit` override, an `instant` predicate that ends a run at once, press points from clicks, context menus and long presses (a droplet source for `from="pointer"`), cleanup when the popup unmounts mid-run; focus goes back to the trigger when a closed popup that held it is gone and Base UI skipped the return (the exit hold makes a menu read the pointer leaving the inert popup as a hover close) |
176
171
  | — (new) | `lib/reduced-motion.ts` | Local addition: `useReduceMotion`, the one reduced-motion read for the morph layer and the liquid indicators — the OS setting, or a `MotionConfig` asking for it (motion's `useReducedMotionConfig` alone ignores the OS without `<MotionConfig reducedMotion="user">`) |
177
- | — (new) | `lib/field-classes.ts` | Local addition: the field ladder FF repeats per text field (rest → muted fill on hover or a group's `data-active` → card fill on focus; `data-invalid` keeps a destructive ring), as `fieldVariants` + `fieldIconClasses`, shared by Input, Textarea, Combobox and Sidebar's input; `useFieldBox` (variant, state attributes incl. `readOnly` / `required`, radius, inset) + `focusControlOnPress`, the box Input, Textarea, NumberInput, Combobox's fields and the date/time pickers' field build on, so each takes `variant`; `FieldStateContext`, which hands a `Field`'s state to its control; the pure class tables live in `field-variants.ts` and are re-exported here |
178
- | — (new) | `lib/field-variants.ts` | Local addition: the field ladder's pure class tables (box, icon, adornment, action, label/description insets), split from `field-classes.ts` so a React Server Component can call them |
179
- | — (new) | `lib/date-locale.ts` | Local addition: what the date and time pickers read off a react-day-picker (date-fns) locale — the hour cycle (Intl), typed dates, times and months in the locale's formats (date-fns `parse` with `P`…`PPPP`), field names for column labels (`Intl.DisplayNames`); `resolveLocale` (a BCP 47 tag → an Intl-backed date-fns Locale, after utegsk/ui's `localeFromTag`), `formatTime` on an explicit hour cycle, `parseDateTimeText` / `parseMonthNameText` |
180
- | — (new) | `lib/row-order.tsx` | Local addition: document-order row numbering for menus and lists (`useRowOrder`, `useRowSlot`, `RowOrderContext`), so a row's `index` is optional; unlike `row-index.tsx` (direct children) it reaches rows anywhere below the panel; labels, separators and groups are numbered without a rect, so a selection run never melts across them. Lifted out of Dropdown; an explicit `index` on every row skips the DOM sort |
181
- | — (new) | `lib/inert.ts` | Local addition: `inert` that holds on React 18 and 19 (18 passes it through as an unknown attribute and needs `''`, 19 reads a boolean and drops `''`): `inertProps(on)` to spread, `markInert` as a ref for an element that is always inert; Sidebar's folded and collapsed parts, Tabs' ghost label |
182
- | — (new) | `lib/focus-ring.tsx` | Local addition: `FocusRing`, the one keyboard ring a list panel draws, 2px outside the focused row and springing between rows (a snap under reduced motion); radius from the surrounding shape, or pinned with `shape` (popups pin `rounded`); Dropdown and its submenus, NavigationMenu, Select |
183
- | — (new) | `lib/scroll-column.tsx` | Local addition: `ScrollColumn`, the scrolling option list beside a calendar (months, years, hours, minutes) or a strip above it: the pick gets a dot, a run of `inView` options one band, the followed option stays centred; fluid hover, listbox semantics, arrow keys; `dividedColumns` puts a hairline between neighbours; `layout="grid"` (`columns` 2–6, 2-D fluid hover, row-wise arrow keys) after utegsk/ui's 0.14 grid picker |
184
- | — (new) | `lib/slot.ts` | Local addition: Dialog's `render` / `asChild` slot shape (`SlotProps`, `slotRender`), shared by every overlay part that wraps a control; `children` fill a `render` element that has none of its own (Base UI semantics), and `nativeButton` reaches the Base UI triggers and closes (`false` for a `<div>` or link); `cloneSlot` / `mergeSlotProps` / `composeRefs` are Radix Slot's merge (child props win, `on*` handlers chain child-first, `className` joins, `style` merges, refs compose; React 18 `forwardRef` and React 19 `props.ref`); `slotId(el, id)` hands a slot element's own `id` to the Base UI part, so triggers and Field.Control register the id the DOM carries |
172
+ | — (new) | `lib/field-classes.ts` | Local addition: the field ladder FF repeats per text field (rest → muted fill on hover or a group's `data-active` → card fill on focus; `data-invalid` keeps a destructive ring), as `fieldVariants` + `fieldIconClasses`, shared by Input, Textarea, Combobox and Sidebar's input; `useFieldBox` (variant, state attributes, radius, inset) + `focusControlOnPress`, the box Input, Textarea, Combobox's fields and the date/time pickers' field build on, so each takes `variant` |
173
+ | — (new) | `lib/date-locale.ts` | Local addition: what the date and time pickers read off a react-day-picker (date-fns) locale — the hour cycle (Intl), typed dates, times and months in the locale's formats (date-fns `parse` with `P`…`PPPP`), field names for column labels (`Intl.DisplayNames`) |
174
+ | — (new) | `lib/scroll-column.tsx` | Local addition: `ScrollColumn`, the scrolling option list beside a calendar (months, years, hours, minutes) or a strip above it: the pick gets a dot, a run of `inView` options one band, the followed option stays centred; fluid hover, listbox semantics, arrow keys; `dividedColumns` puts a hairline between neighbours |
175
+ | — (new) | `lib/slot.ts` | Local addition: Dialog's `render` / `asChild` slot shape (`SlotProps`, `slotRender`), shared by every overlay part that wraps a control |
185
176
  | — (new) | `lib/morph-part.tsx` | Local addition: `MorphPart` (shared parts over a motion `layoutId`, after motion-primitives' morphing dialog) and the scope contexts overlays provide |
186
177
  | — (new) | `lib/goo-indicator.tsx` | Local addition: `GooIndicator` (melts between items, a lingering blob follows it) and `GooLayer` (goo over the shapes' coverage, filled with their own token, on only while moving), on the engine's `GOO_MATRIX` / `GOO_BLUR_RATIO` |
187
178
  | — (new) | `lib/morph-layers.tsx` | Local addition: `MorphSurface`, the renderer (shapes layer with beUI's goo filter plus a `--shadow-color` hairline around the melted shape, surface background and shadow, clipped content) |
@@ -190,7 +181,7 @@ positioning) are ported.
190
181
 
191
182
  | Upstream | Local |
192
183
  |---|---|
193
- | `app/globals.css` §1 tokens | `tokens/colors.css`, with HEX converted to oklch. The surface ladder and shadows live in `primitives/surface/surface.css`. Local addition: the `--status-*` roles (toast states), by reference to the badge palette, `--destructive` and `--brand`; and the primary-action hooks `--primary`, `--primary-hover`, `--primary-active`, `--primary-foreground`, `--shadow-button-primary` (defaults: the ink, its 90% / 80% mixes toward the background, the background, a no-op shadow), read by Button's `primary` variant and by `bg-primary` / `text-primary-foreground`. |
184
+ | `app/globals.css` §1 tokens | `tokens/colors.css`, with HEX converted to oklch. The surface ladder and shadows live in `primitives/surface/surface.css`. Local addition: the `--status-*` roles (toast states), by reference to the badge palette, `--destructive` and `--brand`. |
194
185
  | `app/globals.css` §2 theme switching | `base.css` (`color-scheme`, `--overlay`) and `surface.css` (`--shadow-N` per scheme) |
195
186
  | `app/globals.css` §3 `@theme inline` | `preset.ts` `theme` |
196
187
  | `app/globals.css` `--fs-*` + `@utility text-*` | `tokens/typography.css` `--text-*` and `preset.ts` `utilities` |
@@ -210,11 +201,10 @@ only what is specific to it:
210
201
  `@/components/ui/fluid-hover-highlight` → `../../lib/fluid-hover-highlight`,
211
202
  `@/registry/radix/*` → the Base-flavor sibling, `framer-motion` →
212
203
  `motion/react`, `next/link` → a plain anchor.
213
- - A local `interface <Item>Props` whose members carry the FF docs API-table
214
- text, modo TSDoc written from the FF docs page, and `export default <Item>`.
215
- Upstream's named exports are kept. (Many members are re-declared in the
216
- interface body from when modo listed only those; it now reads props through
217
- the TypeScript compiler, inherited members included.)
204
+ - A local `interface <Item>Props` whose members are each declared on one line
205
+ with the FF docs API-table text (modo's parser lists only members declared
206
+ in the interface body), modo TSDoc written from the FF docs page, and
207
+ `export default <Item>`. Upstream's named exports are kept.
218
208
 
219
209
  #### primitives
220
210
 
@@ -228,59 +218,47 @@ only what is specific to it:
228
218
  | `Morph` | — (local; see [Morph sources](#morph-sources)) | `primitives/morph/index.tsx` | a docs stage like `Motion`: a trigger and a panel playing one `from` × `effect` pair over `lib/use-morph.ts`; static `.Part` (= `MorphPart`); also documents the liquid indicators (`lib/goo-indicator.tsx`) |
229
219
  | `Code` | — (local; FF has no code item) | `primitives/code/index.tsx` | sugar-high tokens colored by the `--syntax-*` tokens, one surface step above its substrate; also the docs chrome's Code slot |
230
220
  | `Craft` | — (local; after the before/after pairs on fluidfunctionalism.com/docs/skill) | `primitives/craft/index.tsx` (+ `demos.tsx`) | a docs stage: a bad and a good version side by side with a one-line verdict each; the bad sides live in `demos.tsx` and break one rule each on purpose, the good sides are this package's items |
231
- | `Separator` | — (local) | `primitives/separator/index.tsx` | Base UI Separator (role and orientation for assistive tech) on the `border` token; `orientation` |
232
- | `Skeleton` | — (local) | `primitives/skeleton/index.tsx` (+ `skeleton.css`) | a `--skeleton` fill pulsing in opacity on `--duration-loop` (also under reduced motion); one block sized by its caller, or `rows` on the size ladder (`bordered` frames them); hidden from assistive tech |
233
221
 
234
222
  #### components
235
223
 
236
224
  | Item | Upstream | Local | Specific modifications |
237
225
  |---|---|---|---|
238
- | `Accordion` | `registry/base/accordion.tsx` | `components/accordion/index.tsx` | open state runs through `useControllableState` (see [Behavior additions](#behavior-additions)); standalone `Accordion` accepts `highlight` and passes it to its items as their default; the panel morphs out of its row (a shape grows from the press point into the item, content clipped by it, layout height on its bottom edge; the `"item"` tint is that shape melted into the row through `GooFilter`), `effect` / `tier` on `Accordion.Content`; the group's hover highlight and focus ring snap with reflowed rows; statics `.Group/.Item/.Trigger/.Content`; local Trigger `icon` / `weightShift`, Content `contentClassName`; `Accordion.Trigger` takes `render` / `asChild` (`lib/slot.ts`) |
239
- | `AlertDialog` | — (local) | `components/overlays/alert-dialog/index.tsx` (+ `pending-demo.tsx`) | Base UI AlertDialog root (always modal, no outside-press dismissal) over Dialog's own parts and `DialogState`, so it morphs like Dialog; `AlertDialog.Content` drops the ✕ by default; statics as Dialog's; `AlertDialog.Action` (promise-aware confirm: Button `loading`, every close blocked via `details.cancel()` while pending, closes on resolve, `onError` on reject; a controlled `pending` makes a plain `onClick` close once `pending` goes true and back to false) and `AlertDialog.Cancel` (Close as a ghost Button, disabled while pending); `pending-demo.tsx` is the docs stage; `onOpenChange(open, details)` with Base UI's change details (an action's own close reports `'imperative-action'`) |
240
- | `Avatar` | — (local) | `components/avatar/index.tsx` | Base UI Avatar (image loading status, the fallback's `delay`); one control tall (36 / 28px compact), `shape` circle or square; a 1px inset image edge after FF's media outline (`outline-image-edge`); the image fades in on the fast tier; statics `.Image/.Fallback` |
241
- | `Badge` | `registry/default/badge.tsx` | `components/badge/index.tsx` | `variant` re-declared (it came from cva's `VariantProps` upstream); changes animate: a new label or variant springs the width (inner content span, `spring.moderate`) while the label blur-crossfades, a new color fades, the dot scales in and out; "Changes" example over a local `change-demo.tsx` stage; `badgeColors`, `badgeVariants` and the size aliases moved to `variants.ts` (server-callable) and re-exported; local variant `outline` (the dot badge's neutral hairline without the dot; `color` has no effect) |
242
- | `Button` | `registry/base/button.tsx` | `components/button/index.tsx` | `variant`/`disabled`/`children` re-declared; extra Sizes / Active / As-child / Loading morph examples; `loading` folds the surface into a circle around the spinner and back (`spring.moderate`, box unchanged), label and spinner crossfade, `aria-busy`, the disabled dim fades; "Loading morph" example over a local `loading-demo.tsx` stage; also serves modo's chrome Button (`shell.Button`); `buttonVariants` and the size aliases moved to `variants.ts` (server-callable) and re-exported; local variants for shadcn-style hosts: `outline` (renders as `tertiary`), `destructive` / `success` (their `-strong` hue as text on a translucent wash that deepens on hover and press, never a solid fill), `link` (underlined foreground text on the control height); size `xs` → `compact`; the `primary` variant reads the `--primary*` / `--shadow-button-primary` hooks (the same ink look by default); `buttonVariants` resolves the size aliases and takes `surface` (fill/ring/wash/hover/press/`aria-disabled` as root classes, for an anchor host); `loading` keeps focus (`focusableWhenDisabled`; `asChild` sets `aria-disabled` and blocks clicks) |
243
- | `Calendar` | — (local, on react-day-picker) | `components/inputs/date-time/calendar/index.tsx` (+ `use-month-window.ts`) | DayPicker props pass through (as shadcn's Calendar); styled through `classNames` and custom `Month` / `Day` / `DayButton` (no react-day-picker stylesheet); one scrolling list of months rendered as a 25-month window that moves as you scroll; a pinned weekday row, muted weekends, today's dot; FF's fills (the pick `bg-foreground text-background` like the primary button, a range `bg-active`, its preview `bg-hover`); month and year columns that mark the month being read and jump on click, before or after the days (`columnsSide`), turning into strips when narrow; `extraColumns` / `extraColumnsSide` for the date picker's time; `columnLabels`; a named `CalendarProps` and a `ReactElement` return; the month window's edge margin is capped, so a list with no height of its own no longer loops |
244
- | `Card` | `registry/default/card.tsx` | `components/card/index.tsx` | `next/link` → plain anchors (stretched card link, `CardButton`'s `href` form); statics `.Group/.Header/.Title/.Description/.Action/.Content/.Footer/.Media/.Image/.Eyebrow/.Feature/.Button/.Divider`; local `border="outlined"` on a standalone card (the outlined group's hairline frame; inside a group the group decides); local `Card.Divider` (a full-bleed hairline between the card's parts, vertical in an inline card; the Separator primitive); local Title `as`, Content `bodyText` |
245
- | `Checkbox` (upstream `CheckboxItem`), `Checkbox.Group` (upstream `CheckboxGroup`) | `registry/base/checkbox-group.tsx` | `components/inputs/checkbox/index.tsx` | renamed; the row stands alone too (own state from `defaultChecked`, `onCheckedChange`, own hover and focus ring, `size`); rows numbered by the group (`lib/row-index.tsx`), so `index` is optional; uncontrolled mode + group-level callback; item `checked`/`onToggle` optional, falling back to group context; arrow-key focus guarded for `noUncheckedIndexedAccess`; shared `useSelectionRuns`, picks melt and split through the goo; `label` optional, any node (named via `aria-labelledby`); without a label and outside a group the checkbox is a bare box, Base UI's Checkbox.Root itself (`id` / `<label htmlFor>`, `aria-label`, `name` / `value` / `required` for forms), keeping its border when checked; `indeterminate` / `checked="indeterminate"` shows the icon set's `minus`, swapped with the self-drawing check in one cell; `disabled` dims a row and takes it out of the group's hover and arrow keys |
246
- | `ColorPicker` | `registry/default/color-picker.tsx` | `components/inputs/color-picker/index.tsx` | `@/registry/radix/{slider,tooltip}` → the Base siblings `../slider` / `../../overlays/tooltip`; `noUncheckedIndexedAccess` guards on regex captures, `rgb()`/`hsl()`/`oklch()` parts, `itemRects[i]` and the Slider's array value; static `.Popover`; uncontrolled support was already upstream (verified, kept); `ColorPicker.Popover` (goo on `spring.goo`; `from` / `effect` / `hideSource` / `tier`) and the format menu morph out of their triggers, replacing the motion wrappers and the ignored `actionsRef`; the color types and math (`parseColor`, `buildParsed`, conversions, formatting) in `variants.ts` (server-callable) and re-exported; `ColorPicker.Popover` takes `disabled`, `readOnly`, `rootClassName` and `removeLabel`; swatches and tiles keep a hairline above the color |
247
- | `Combobox` | `registry/base/combobox.tsx` | `components/inputs/combobox/index.tsx` | root de-generified (the parser needs a plain function plus a same-file `interface ComboboxProps`): items gained an index signature, `value`/`defaultValue` are `string \| string[]` and `onValueChange` is a union of the two handler shapes; `ComboboxValue<Multiple>` still exported; `creatable` added; `React.*` type refs replaced by named type imports; statics `.Input/.Chips/.Content/.List/.Item/.Empty`; the popup morphs out of the field (morph layer, goo on `spring.goo`; `from` / `effect` / `hideSource` / `tier` on `Combobox.Content`), replacing the `scaleY` wrapper and the `actionsRef` deferred unmount; `loading` (the chevron blurs into a `loader-circle` spinner, a status row under the list, the empty message held back) and `loadingLabel`; controlled query (`inputValue` / `defaultInputValue` / `onInputValueChange`); `filter={null}` shows the items as given; `readOnly` (Base UI's, plus the field box's read-only state; no clear or chip ✕); controlled popup (`open` / `defaultOpen` / `onOpenChange`); `footer` on `Combobox.Content` (a node or `({ close, query }) => node`); object items' `label` may be any node (unclipped in rows and chips) with `textValue` to filter, fill the field and name the chip; fields read the surrounding Field's invalid state (`invalid` prop, `error` forces it), `hideTrigger`, a root `labels` object (`open` / `clear` / `remove(label)` / `placeholder`), and `onInputValueChange(value, details)` forwarding Base UI's change details |
248
- | `Command` | — (local) | `components/overlays/command/index.tsx` | Base UI Autocomplete rendered inline in Dialog's panel (`position="top"`, no ✕), morphing from its trigger with goo; grouped/flat command data filtered by label + keywords; one fluid highlight follows Base UI's highlight; ⌘K/Ctrl+K `hotkey` (one palette answers a press); fresh palette per open; statics `.Trigger/.Content/.Palette/.Shortcut`; `CommandList`/`CommandListRoot` exported for Search; `onOpenChange(open, details)` with Base UI's change details (`reason`, `event`, `cancel()`) |
226
+ | `Accordion` | `registry/base/accordion.tsx` | `components/accordion/index.tsx` | open state runs through `useControllableState` (see [Behavior additions](#behavior-additions)); standalone `Accordion` accepts `highlight` and passes it to its items as their default; the panel morphs out of its row (a shape grows from the press point into the item, content clipped by it, layout height on its bottom edge; the `"item"` tint is that shape melted into the row through `GooFilter`), `effect` / `tier` on `Accordion.Content`; the group's hover highlight and focus ring snap with reflowed rows; statics `.Group/.Item/.Trigger/.Content` |
227
+ | `AlertDialog` | — (local) | `components/overlays/alert-dialog/index.tsx` | Base UI AlertDialog root (always modal, no outside-press dismissal) over Dialog's own parts and `DialogState`, so it morphs like Dialog; `AlertDialog.Content` drops the ✕ by default; statics as Dialog's |
228
+ | `Badge` | `registry/default/badge.tsx` | `components/badge/index.tsx` | `variant` re-declared (it came from cva's `VariantProps` upstream); changes animate: a new label or variant springs the width (inner content span, `spring.moderate`) while the label blur-crossfades, a new color fades, the dot scales in and out; "Changes" example over a local `change-demo.tsx` stage |
229
+ | `Button` | `registry/base/button.tsx` | `components/button/index.tsx` | `variant`/`disabled`/`children` re-declared; extra Sizes / Active / As-child / Loading morph examples; `loading` folds the surface into a circle around the spinner and back (`spring.moderate`, box unchanged), label and spinner crossfade, `aria-busy`, the disabled dim fades; "Loading morph" example over a local `loading-demo.tsx` stage; also serves modo's chrome Button (`shell.Button`) |
230
+ | `Calendar` | — (local, on react-day-picker) | `components/inputs/date-time/calendar/index.tsx` (+ `use-month-window.ts`) | DayPicker props pass through (as shadcn's Calendar); styled through `classNames` and custom `Month` / `Day` / `DayButton` (no react-day-picker stylesheet); one scrolling list of months rendered as a 25-month window that moves as you scroll; a pinned weekday row, muted weekends, today's dot; FF's fills (the pick `bg-foreground text-background` like the primary button, a range `bg-active`, its preview `bg-hover`); month and year columns that mark the month being read and jump on click, before or after the days (`columnsSide`), turning into strips when narrow; `extraColumns` / `extraColumnsSide` for the date picker's time |
231
+ | `Card` | `registry/default/card.tsx` | `components/card/index.tsx` | `next/link` → plain anchors (stretched card link, `CardButton`'s `href` form); statics `.Group/.Header/.Title/.Description/.Action/.Content/.Footer/.Media/.Image/.Eyebrow/.Feature/.Button` |
232
+ | `Checkbox` (upstream `CheckboxItem`), `Checkbox.Group` (upstream `CheckboxGroup`) | `registry/base/checkbox-group.tsx` | `components/inputs/checkbox/index.tsx` | renamed; the row stands alone too (own state from `defaultChecked`, `onCheckedChange`, own hover and focus ring, `size`); rows numbered by the group (`lib/row-index.tsx`), so `index` is optional; uncontrolled mode + group-level callback; item `checked`/`onToggle` optional, falling back to group context; arrow-key focus guarded for `noUncheckedIndexedAccess`; shared `useSelectionRuns`, picks melt and split through the goo |
233
+ | `ColorPicker` | `registry/default/color-picker.tsx` | `components/inputs/color-picker/index.tsx` | `@/registry/radix/{slider,tooltip}` → the Base siblings `../slider` / `../../overlays/tooltip`; `noUncheckedIndexedAccess` guards on regex captures, `rgb()`/`hsl()`/`oklch()` parts, `itemRects[i]` and the Slider's array value; static `.Popover`; uncontrolled support was already upstream (verified, kept); `ColorPicker.Popover` (goo on `spring.goo`; `from` / `effect` / `hideSource` / `tier`) and the format menu morph out of their triggers, replacing the motion wrappers and the ignored `actionsRef` |
234
+ | `Combobox` | `registry/base/combobox.tsx` | `components/inputs/combobox/index.tsx` | root de-generified (the parser needs a plain function plus a same-file `interface ComboboxProps`): items gained an index signature, `value`/`defaultValue` are `string \| string[]` and `onValueChange` is a union of the two handler shapes; `ComboboxValue<Multiple>` still exported; `creatable` added; `React.*` type refs replaced by named type imports; statics `.Input/.Chips/.Content/.List/.Item/.Empty`; the popup morphs out of the field (morph layer, goo on `spring.goo`; `from` / `effect` / `hideSource` / `tier` on `Combobox.Content`), replacing the `scaleY` wrapper and the `actionsRef` deferred unmount |
235
+ | `Command` | — (local) | `components/overlays/command/index.tsx` | Base UI Autocomplete rendered inline in Dialog's panel (`position="top"`, no ✕), morphing from its trigger with goo; grouped/flat command data filtered by label + keywords; one fluid highlight follows Base UI's highlight; ⌘K/Ctrl+K `hotkey` (one palette answers a press); fresh palette per open; statics `.Trigger/.Content/.Palette/.Shortcut`; `CommandList`/`CommandListRoot` exported for Search |
249
236
  | `ContextMenu` | — (local; see [Morph sources](#morph-sources)) | `components/overlays/context-menu/index.tsx` | Base UI ContextMenu (right click, long press) with the morph layer growing from the press point (`from="pointer"` default, goo on `spring.goo`); rows are Dropdown's `MenuItem`, `Dropdown.Label`, `Dropdown.Separator` with fluid hover; `ContextMenu.Item` adds `shortcut`; `size` on the root; statics `.Trigger/.Content/.Item/.Label/.Separator` |
250
- | `Dialog` | `registry/base/dialog.tsx` | `components/overlays/dialog/index.tsx` | `DialogProps` and `DialogContentProps` fully re-declared (the slot props now come from `lib/slot.ts`); statics attached as expando properties (`Dialog.Trigger = …`), so `<Dialog.Content>` types without a cast; FF's "With a sidebar" example replaced by "Surfaces inside a dialog" (written before the Sidebar was ported); the panel morphs out of its trigger (morph layer, goo on `spring.goo`; `from` / `effect` / `hideSource` / `tier` on `Dialog.Content`), the backdrop fades with the morph's progress, the root holds the open state and scopes `Morph.Part` pairs; `onOpenChange(open, details)` hears Base UI's change details and can `cancel()` (one-argument handlers still work), and `createDialogChangeDetails` builds them for the library's own changes; `disablePointerDismissal` on the root; `Dialog.Content` types and forwards `initialFocus` / `finalFocus` and takes `popupClassName` (merged after the popup's width) |
251
- | `Dropdown` | `registry/base/dropdown.tsx` | `components/overlays/dropdown/index.tsx` | uncontrolled selection and uncontrolled search filtering (below); `items[next].focus()` guarded; statics `.Menu/.Trigger/.Content/.Item/.Label/.Separator/.Search/.Empty`; FF's "Create from the query" section skipped — adding a row to the list is real consumer state; the popup menu morphs out of its trigger (morph layer, goo on `spring.goo`; `from` / `effect` / `hideSource` / `tier` on `Dropdown.Content`), replacing the `scaleY` wrapper and the ignored `actionsRef`; popup rows hand activation to the Menu item's `onClick` so Enter / Space pick; shadcn DropdownMenu parity: children rows with an optional index (`lib/row-order.tsx`), `inset` / `shortcut` rows, a cancelable `onSelect(event)`, `asChild` on the trigger, a keyboard focus ring, `keepMounted`, and the parts in `menu-parts.tsx` (see the headers); `render`/`asChild` and `textValue` on rows; Menu `onOpenChange(open, details)` and `modal`; Content/SubContent `finalFocus`, modo-side `initialFocus`, `collisionPadding`, `container`, `positionerClassName`, popup HTML attributes; Content `alignOffset`, `collisionBoundary` |
252
- | `DatePicker`, `DateRangePicker`, `TimePicker`, `DurationPicker`, `MonthPicker` | — (local; props after shadcn's date picker and utegsk/ui's pickers) | `components/inputs/date-time/<id>/index.tsx` (+ the group's `picker-shell.tsx`, `time-columns.tsx`) | a field on the field ladder whose panel morphs out of it with Combobox's options (goo by default; `from` / `effect` / `hideSource` / `tier`, in place with `effect="morph"` + `hideSource`), or a bottom `Sheet` under 640px; one hour column with AM/PM on a 12-hour clock; `columnsSide` / `timeColumnsSide`; the panel header types the value in the locale's formats; `value` / `defaultValue` / `onValueChange` with `null` for empty — a `Date`, react-day-picker's `DateRange`, `"HH:mm"`, a date-fns `Duration`, a month's first day; `locale` is a react-day-picker locale throughout; `picker-shell.tsx` takes an `editor`, `triggerLabel` and `readOnly`; `picker-shell.tsx` also takes `controlRef` / `controlProps` / `formValues` / `required` (visually hidden inputs for native forms) and exports `PickerControlProps` (form + aria props every picker forwards); every picker is a `forwardRef` with `readOnly`, `labels`, string `locale`; `DateRangePicker` adds `editable`, `withTime`, `hourCycle`, `hidden`, `startName` / `endName`, `startInputProps` / `endInputProps`; `controlProps` reaches an editable field's input after its defaults (`autoComplete`, `inputMode`); the range panel header wraps with `withTime` |
253
- | `DatePicker` | — (local; the masked input after utegsk/ui's `MaskedDateInput`) | `components/inputs/date-time/date-picker/index.tsx` (+ `masked-date-input.tsx`) | `editable` masked input in the field (Escape restores the last real date), `labels`, `formatDate`, `actions`, `readOnly`, string values (date-only strings read as local days) with an invalid state; `hidden`, `required` (no deselect), `unselectable` (`masked-date-input.tsx` takes `clearable`) |
254
- | — | `registry/default/menu-item.tsx` | `components/overlays/dropdown/menu-item.tsx` | a row with no `checked` derives it from a self-managed panel and toggles the panel's state; `sourceIndex` carries the authored index so selection survives filter re-indexing; `label` and `index` optional (`children` rows numbered in document order), `inset`, `shortcut`, cancelable `onSelect(event)`; checkbox and radio rows report to the panel for the merged selection background; `render`/`asChild` and `textValue` on rows |
255
- | — | — (local) | `components/overlays/dropdown/menu-parts.tsx` | `Dropdown.Group`, the `Dropdown.Shortcut` re-export, value-keyed `Dropdown.CheckboxItem`, `Dropdown.RadioGroup` / `Dropdown.RadioItem`, `Dropdown.Sub` / `.SubTrigger` / `.SubContent` (a submenu morphs out of its row), and `useMenuPanel`, the state both popups share (keyboard focus ring, the submenu trigger's pinned highlight, value-checked backgrounds); `Sub` / `SubContent` take `finalFocus`, modo-side `initialFocus`, `collisionPadding`, `container`, `positionerClassName` and popup HTML attributes |
237
+ | `Dialog` | `registry/base/dialog.tsx` | `components/overlays/dialog/index.tsx` | `DialogProps` and `DialogContentProps` fully re-declared (the slot props now come from `lib/slot.ts`); statics attached as expando properties (`Dialog.Trigger = …`), so `<Dialog.Content>` types without a cast; FF's "With a sidebar" example replaced by "Surfaces inside a dialog" (written before the Sidebar was ported); the panel morphs out of its trigger (morph layer, goo on `spring.goo`; `from` / `effect` / `hideSource` / `tier` on `Dialog.Content`), the backdrop fades with the morph's progress, the root holds the open state and scopes `Morph.Part` pairs |
238
+ | `Dropdown` | `registry/base/dropdown.tsx` | `components/overlays/dropdown/index.tsx` | uncontrolled selection and uncontrolled search filtering (below); `items[next].focus()` guarded; statics `.Menu/.Trigger/.Content/.Item/.Label/.Separator/.Search/.Empty`; FF's "Create from the query" section skipped — adding a row to the list is real consumer state; the popup menu morphs out of its trigger (morph layer, goo on `spring.goo`; `from` / `effect` / `hideSource` / `tier` on `Dropdown.Content`), replacing the `scaleY` wrapper and the ignored `actionsRef`; popup rows hand activation to the Menu item's `onClick` so Enter / Space pick |
239
+ | `DatePicker`, `DateRangePicker`, `TimePicker`, `DurationPicker`, `MonthPicker` | — (local; props after shadcn's date picker and utegsk/ui's pickers) | `components/inputs/date-time/<id>/index.tsx` (+ the group's `picker-shell.tsx`, `time-columns.tsx`) | a field on the field ladder whose panel morphs out of it with Combobox's options (goo by default; `from` / `effect` / `hideSource` / `tier`, in place with `effect="morph"` + `hideSource`), or a bottom `Sheet` under 640px; one hour column with AM/PM on a 12-hour clock; `columnsSide` / `timeColumnsSide`; the panel header types the value in the locale's formats; `value` / `defaultValue` / `onValueChange` with `null` for empty — a `Date`, react-day-picker's `DateRange`, `"HH:mm"`, a date-fns `Duration`, a month's first day; `locale` is a react-day-picker locale throughout |
240
+ | — | `registry/default/menu-item.tsx` | `components/overlays/dropdown/menu-item.tsx` | a row with no `checked` derives it from a self-managed panel and toggles the panel's state; `sourceIndex` carries the authored index so selection survives filter re-indexing |
256
241
  | — | `registry/default/dropdown-search.tsx` | `components/overlays/dropdown/dropdown-search.tsx` | `filter` mode: `value`/`onValueChange` optional, the field reads and writes the query held by the panel (`DropdownFilterContext`) |
257
- | `Copy` (upstream `InputCopy`) | `registry/default/input-copy.tsx` | `components/copy/index.tsx` | renamed, out of the inputs group; `@/registry/radix/tooltip` → `../overlays/tooltip`; `useRef<ReturnType<typeof setTimeout> \| null>(null)` (React 18 overloads); defaults spelled into the prop prose; the tooltip comment's "Radix" reads "Base UI"; the copied state morphs: the glyph's two sheets melt through the goo filter into a status-tinted disc behind the check (✕ on failure) and split back; local `chip` and `glyph` variants, `labels`, live-region announcement; ref typed `HTMLElement` |
258
- | `Field` | — (local) | `components/inputs/field/index.tsx` | Base UI Field with no form library: `.Label` / `.Description` / `.Error` / `.Control`, inset to the text in the field box (`lib/field-variants.ts`); the field's state (invalid, also from native validity; disabled, read-only, required) reaches any control on `useFieldBox` through `FieldStateContext` |
259
- | `FileDropzone` | — (local) | `components/inputs/file-dropzone/index.tsx` (+ `file-row.tsx`, `variants.ts`, `upload-demo.tsx`) | a label around a visually hidden file input, joined to Base UI's Field; hands picked files over and keeps none (no upload logic); drag verdicts accept / partial (some will be skipped) / reject, refusing only drags where nothing can pass; `required` announced, not native; `.Row` (`FileRow`: status and progress); the pure accept / size / count helpers (`acceptsFile`, `dragVerdict`, `sortFiles`, `formatFileSize`) in `variants.ts`; `upload-demo.tsx` is the docs stage; rest `<label>` props and `style` on the root |
260
- | `Input`, `Label`, `InputGroup` | `registry/default/input-group.tsx` | `components/inputs/input/index.tsx` | `InputField` split into `Input` (the ringed box, standalone: own hover outside a group, `invalid`, `size`) and `Label` (now its own item `components/inputs/label/index.tsx`, re-exported from `inputs/input`; rendered through `Field.Label` in a field), composed back by `InputGroup.Field`; item renamed `input`, `Input` the default export; uncontrolled mode (`InputHTMLAttributes`' own `defaultValue` omitted in favour of the local one); static `.Field`; `startAdornment` / `endAdornment`, `readOnly`, `required` (both also from a surrounding `Field`), `InputAction` (an icon button inside the box) and `InputAdornment`; a `type` swap keeps the caret and selection |
261
- | `Label` | `registry/default/input-group.tsx` | `components/inputs/label/index.tsx` | split out of InputField; invalid, size; data-disabled dims it; re-exported from inputs/input |
242
+ | `Copy` (upstream `InputCopy`) | `registry/default/input-copy.tsx` | `components/copy/index.tsx` | renamed, out of the inputs group; `@/registry/radix/tooltip` → `../overlays/tooltip`; `useRef<ReturnType<typeof setTimeout> \| null>(null)` (React 18 overloads); defaults spelled into the prop prose; the tooltip comment's "Radix" reads "Base UI"; the copied state morphs: the glyph's two sheets melt through the goo filter into a status-tinted disc behind the check (✕ on failure) and split back |
243
+ | `Input`, `Label`, `InputGroup` | `registry/default/input-group.tsx` | `components/inputs/input/index.tsx` | `InputField` split into `Input` (the ringed box, standalone: own hover outside a group, `invalid`, `size`) and `Label` (a plain `<label>`, rendered through `Field.Label` in a field), composed back by `InputGroup.Field`; item renamed `input`, `Input` the default export; uncontrolled mode (`InputHTMLAttributes`' own `defaultValue` omitted in favour of the local one); static `.Field` |
262
244
  | `InputMessage` | `registry/default/input-message.tsx` | `components/AI/input-message/index.tsx` | uncontrolled twins for value, files, queue and status (below); `FilePreviewTile` turned into a `forwardRef` (it exits inside `<AnimatePresence mode="popLayout">`, which measures through a ref); guards on `queue[0]`, `history[i]`, `suggestions[i]` and the `moveQueued` swap; FF's Playground section skipped and the surrounding transcript dropped (`ChatMessage` is not ported) |
263
- | `NavigationMenu` | — (local) | `components/navigation/navigation-menu/index.tsx` | Base UI NavigationMenu; one shared flyout morphing from its trigger (anchored to the List, frame springs to each content's size, content crossfades by activation direction); fluid hover on strip and panels; one keyboard ring per panel; `Indicator` is a GooIndicator under the open/current item; Root takes ref and nav attributes; Trigger and Content `asChild` keep the child's element and ref |
264
- | `NumberInput` | — (local) | `components/inputs/number-input/index.tsx` | Base UI NumberField on the field box (`useFieldBox`), steppers as field actions inside the ring, Intl `format`, scrub; `inputProps` spread last on the `<input>`; `onValueChange(value, details)` |
265
- | `Pagination` | — (local, from the skill's authoring.md template) | `components/navigation/pagination/index.tsx` | pages strip (GooIndicator + fluid hover) or jump-to-page field; edges; page-size Select; labels as props |
266
245
  | — | `registry/default/file-thumbnail.tsx` | `components/AI/input-message/file-thumbnail.tsx` | the lazy `import("pdfjs-dist")` is kept as-is — verified against modo's esbuild settings, it lands in a ~790 kB chunk fetched only when a PDF is attached; the worker still comes from jsDelivr, so no bundler-side worker config is needed; the `@next/next/no-img-element` eslint-disable dropped |
267
- | `Popover` | — (local; after beUI's gooey popover and motion-primitives' morphing popover, see [Morph sources](#morph-sources)) | `components/overlays/popover/index.tsx` | Base UI Popover with the morph layer (goo by default); `openOnHover` on the trigger; statics `.Trigger/.Content/.Title/.Description/.Close`; `Popover.Content` forwards `anchor` (the morph's source when it is an element), `alignOffset`, `collisionPadding`, `collisionBoundary`, `initialFocus`, `finalFocus`; `onOpenChange(open, details)` with Base UI's change details (`cancel()`) |
246
+ | `Popover` | — (local; after beUI's gooey popover and motion-primitives' morphing popover, see [Morph sources](#morph-sources)) | `components/overlays/popover/index.tsx` | Base UI Popover with the morph layer (goo by default); `openOnHover` on the trigger; statics `.Trigger/.Content/.Title/.Description/.Close` |
268
247
  | `PreviewCard` | — (local; after beUI's gooey popover, see [Morph sources](#morph-sources)) | `components/overlays/preview-card/index.tsx` | Base UI PreviewCard with the morph layer (goo from the link on `spring.goo`); `delay` / `closeDelay` / `render` on the trigger, a token-styled link by default; `from` without `'pointer'`; statics `.Trigger/.Content` |
269
- | `Progress` | — (local) | `components/progress/index.tsx` (+ `progress.css`, `step-demo.tsx`) | Base UI Progress; the determinate fill is a full-width bar slid with `translateX` on `spring.moderate` (after FF's CarouselDots fill, never scaled); with no `value` a segment sweeps the track; `.Spinner` draws Button's figure-eight loading glyph; both loops on `--duration-loop` (`progress.css`); `step-demo.tsx` is the docs stage |
270
- | `Radio` (upstream `RadioItem`), `Radio.Group` (upstream `RadioGroup`) | `registry/base/radio-group.tsx` | `components/inputs/radio/index.tsx` | renamed; rows numbered by the group (`lib/row-index.tsx`), so `index` is optional; uncontrolled index and value modes; group context carries a `selectIndex` setter every item calls, so items need no `selected`/`onSelect`; arrow-key focus guarded; selected background is a `GooIndicator`; `label` optional, any node; a `Radio` without one is a bare circle, Base UI's Radio.Root (picked by `value`, `id` / `<label htmlFor>`, keeping its border when picked) laid out freely inside a value-mode group, which then draws no rows and leaves the arrow keys to Base UI; `disabled` on a row, or on the group (which dims as a whole); the group's `name` / `required` reach Base UI's RadioGroup for forms |
248
+ | `Radio` (upstream `RadioItem`), `Radio.Group` (upstream `RadioGroup`) | `registry/base/radio-group.tsx` | `components/inputs/radio/index.tsx` | renamed; rows numbered by the group (`lib/row-index.tsx`), so `index` is optional; uncontrolled index and value modes; group context carries a `selectIndex` setter every item calls, so items need no `selected`/`onSelect`; arrow-key focus guarded; selected background is a `GooIndicator` |
271
249
  | `Search` | — (local; after beUI's morphing search, see [Morph sources](#morph-sources)) | `components/inputs/search/index.tsx` | pill or icon button springing its own width in place (`spring.slow`), growing over its neighbors (`align`); with `items`, Autocomplete suggestions ooze out of the field via the morph layer (goo on `spring.goo`, `effect`/`tier`) with Command's rows; Escape closes → clears → collapses; blur collapses when empty; `shortcut`; `<search>` landmark + form, `onSubmit` |
272
- | `Select` | `registry/base/select.tsx` | `components/inputs/select/index.tsx` | members re-declared one per line (the parser drops members whose type spans lines); upstream's uncontrolled `defaultValue` verified and kept rather than rerouted through `useControllableState`; expando statics `.Trigger/.Content/.Item/.Group/.Label/.Separator`; the popup morphs out of its trigger (morph layer, goo on `spring.goo`; `from` / `effect` / `hideSource` / `tier` on `Select.Content`), replacing the `scaleY` wrapper and the `actionsRef` deferred unmount; `Select.Item`'s `index` is optional: rows take their place in document order (`lib/row-order.tsx`), inside groups, conditionals and maps, and the checked row is found by its own index; `textValue` for typeahead; a node label is shown as is (unclipped) in the rows and, through Base UI's `items`, in the trigger; `Select.Value` part, with `Select.Trigger` children replacing its value slot; `side` / `align` / `sideOffset` on `Select.Content`; `triggerVariants` in `variants.ts` (server-callable) and re-exported; the keyboard ring is the shared `lib/focus-ring.tsx`; `open` / `defaultOpen` / `onOpenChange(open, details)` (the 300ms pick ack runs only while uncontrolled); `Select.Content` `alignOffset` / `collisionPadding` / `finalFocus` / rest HTML attributes; `Select.Trigger` / `Select.Item` `render` / `asChild`; `Select.Trigger` `wrapperClassName`; `Select.Value` and `Select.Group` forward ref |
273
- | `Sheet` | — (local; replaces beUI's bottom sheet and drawer, see [Morph sources](#morph-sources)) | `components/overlays/sheet/index.tsx` | Base UI Drawer (swipe to dismiss, snap points, `Drawer.Viewport` for the swipe) with the morph growing from the sheet's own edge; a swipe-dismissed sheet slides on off its edge from the release point (the morph's `exit`); `side`, `snapPoints`, `defaultSnapPoint`; Dialog's parts and `DialogState` (Base UI's Drawer parts are Dialog's); statics as Dialog's plus `.Provider` / `.Indent`; `onOpenChange(open, details)` with Base UI's change details (`reason`, `event`, `cancel()`); `disablePointerDismissal` on the root; `Sheet.Content` takes `side` (overrides the root's, the swipe follows), `initialFocus` / `finalFocus` and `popupClassName` (merged after `PLACEMENT`) |
274
- | `Sidebar` | `registry/base/sidebar.tsx` (+ `registry/default/sidebar-core.tsx`, `sidebar-menu.tsx`; `app/globals.css` `.scroll-divider`) | `components/navigation/sidebar/index.tsx` (+ `sidebar-core.tsx`, `sidebar-menu.tsx`, `sidebar.css`) | the mobile sheet is the DS's `Sheet` (goo from its edge, swipe to dismiss) instead of a Dialog with a framer slide; no collapsed peek: `openOnHover` on the provider opens the sidebar in flow while the pointer is between its edge and the far side of a trigger beside it, the trigger switching between open and on hover (`panel-*-dashed` glyphs added to the icon context); the active row backgrounds are `GooIndicator`s and the hover highlight the liquid `FluidHoverHighlight`; uncontrolled selection (`value` on the buttons, `value` / `defaultValue` / `onValueChange` on `Sidebar`) and collapsible rows (`Sidebar.MenuItem collapsible`, below); statics `.Provider/.Trigger/.Rail/.Inset/.Input/.Header/.Content/.Footer/.Separator/.Group/.GroupLabel/.GroupAction/.GroupActions/.GroupContent/.Menu/.MenuItem/.MenuButton/.MenuAction/.MenuActions/.MenuBadge/.MenuSkeleton/.MenuSub/.MenuSubItem/.MenuSubButton` through a `SidebarComponent` cast; `fontVariationSettings` → `weight-*`, `text-[Npx]` → type roles, hex focus ring → `ring-focus-ring`, `duration-80\|160\|240` → tiers; `sidebarMenuButtonVariants` and the `SIDEBAR_*` constants in `variants.ts` (server-callable; `variants.ts` files are bunup entries); `inert` through `lib/inert.ts` |
275
- | `Slider` | `registry/base/slider.tsx` | `components/inputs/slider/index.tsx` | `var(--color-accent)` → `var(--accent)` (no `--color-*` aliases here); uncontrolled support on the public wrapper, with both engines still fully controlled; `SliderProps extends Omit<SliderEngineProps, "value" \| "onChange">`; React 18 ref types (`MutableRefObject`); indexed reads of the value/step/pip arrays asserted; `aria-label` names the thumbs ahead of the visible `label`; `orientation="vertical"` (compact engine, min at bottom) and `onValueCommit` (both engines; drag end, keyboard step, value edit) |
276
- | `Switch` | `registry/base/switch.tsx` | `components/inputs/switch/index.tsx` | uncontrolled support; every in-body read goes through the resolved `isChecked` and a `toggle()` that also calls `onToggle`; the thumb is a `GooIndicator` in Base UI's Thumb (stretches as it travels), dragged x held in state; local `description` (muted line, `aria-describedby`) and `trackSide`; local `Switch.Group`: switches as settings rows (track at the end) in one outlined fieldset, after an outlined `Card.Group` (shared hairlines dropped around the fluid hover highlight), rows numbered by the group; `label` optional, any node; without one (outside a group) the switch is the bare track, Base UI's Switch.Root, which toggles itself (click, keyboard, a `<label htmlFor>`) through `onCheckedChange`, with the thumb drag on the track and the toggle that follows a drag swallowed; `name` / `value` / `required` reach Base UI's hidden input in both modes |
277
- | `Table` | `registry/default/table.tsx` | `components/table/index.tsx` (+ `sort-demo.tsx`) | statics `.Header/.Body/.Row/.Head/.Cell`; `TableProps` / `TableRowProps` exported; local additions: Footer, Caption, Empty, sortable Head (`sortDirection`/`defaultSortDirection`/`onSort`), `stacked` + Cell `label` (stacked cells `items-start`), `containerClassName`; unindexed body rows numbered in document order (`lib/row-order`); weight by section; header-only border melt; stacked values in foreground |
278
- | `Tabs` | `registry/base/tabs.tsx` | `components/navigation/tabs/index.tsx` | `defaultSelectedIndex` added as the index-mode twin of the existing `defaultValue`; indicator and hover pill are `GooIndicator`s (the hover pill returns to the active tab as it fades); statics `.List/.Item/.Panel`; `Tabs.Item` node `label` (inert ghost copy), `href` link tabs |
250
+ | `Select` | `registry/base/select.tsx` | `components/inputs/select/index.tsx` | members re-declared one per line (the parser drops members whose type spans lines); upstream's uncontrolled `defaultValue` verified and kept rather than rerouted through `useControllableState`; expando statics `.Trigger/.Content/.Item/.Group/.Label/.Separator`; the popup morphs out of its trigger (morph layer, goo on `spring.goo`; `from` / `effect` / `hideSource` / `tier` on `Select.Content`), replacing the `scaleY` wrapper and the `actionsRef` deferred unmount |
251
+ | `Sheet` | — (local; replaces beUI's bottom sheet and drawer, see [Morph sources](#morph-sources)) | `components/overlays/sheet/index.tsx` | Base UI Drawer (swipe to dismiss, snap points, `Drawer.Viewport` for the swipe) with the morph growing from the sheet's own edge; a swipe-dismissed sheet slides on off its edge from the release point (the morph's `exit`); `side`, `snapPoints`, `defaultSnapPoint`; Dialog's parts and `DialogState` (Base UI's Drawer parts are Dialog's); statics as Dialog's plus `.Provider` / `.Indent` |
252
+ | `Sidebar` | `registry/base/sidebar.tsx` (+ `registry/default/sidebar-core.tsx`, `sidebar-menu.tsx`; `app/globals.css` `.scroll-divider`) | `components/navigation/sidebar/index.tsx` (+ `sidebar-core.tsx`, `sidebar-menu.tsx`, `sidebar.css`) | the mobile sheet is the DS's `Sheet` (goo from its edge, swipe to dismiss) instead of a Dialog with a framer slide; no collapsed peek: `openOnHover` on the provider opens the sidebar in flow while the pointer is between its edge and the far side of a trigger beside it, the trigger switching between open and on hover (`panel-*-dashed` glyphs added to the icon context); the active row backgrounds are `GooIndicator`s and the hover highlight the liquid `FluidHoverHighlight`; uncontrolled selection (`value` on the buttons, `value` / `defaultValue` / `onValueChange` on `Sidebar`) and collapsible rows (`Sidebar.MenuItem collapsible`, below); statics `.Provider/.Trigger/.Rail/.Inset/.Input/.Header/.Content/.Footer/.Separator/.Group/.GroupLabel/.GroupAction/.GroupActions/.GroupContent/.Menu/.MenuItem/.MenuButton/.MenuAction/.MenuActions/.MenuBadge/.MenuSkeleton/.MenuSub/.MenuSubItem/.MenuSubButton` through a `SidebarComponent` cast; `fontVariationSettings` → `weight-*`, `text-[Npx]` → type roles, hex focus ring → `ring-focus-ring`, `duration-80\|160\|240` → tiers |
253
+ | `Slider` | `registry/base/slider.tsx` | `components/inputs/slider/index.tsx` | `var(--color-accent)` → `var(--accent)` (no `--color-*` aliases here); uncontrolled support on the public wrapper, with both engines still fully controlled; `SliderProps extends Omit<SliderEngineProps, "value" \| "onChange">`; React 18 ref types (`MutableRefObject`); indexed reads of the value/step/pip arrays asserted |
254
+ | `Switch` | `registry/base/switch.tsx` | `components/inputs/switch/index.tsx` | uncontrolled support; every in-body read goes through the resolved `isChecked` and a `toggle()` that also calls `onToggle`; the thumb is a `GooIndicator` in Base UI's Thumb (stretches as it travels), dragged x held in state; local `description` (muted line, `aria-describedby`) and `trackSide`; local `Switch.Group`: switches as settings rows (track at the end) in one outlined fieldset, after an outlined `Card.Group` (shared hairlines dropped around the fluid hover highlight), rows numbered by the group |
255
+ | `Table` | `registry/default/table.tsx` | `components/table/index.tsx` | statics `.Header/.Body/.Row/.Head/.Cell`; `TableProps` / `TableRowProps` exported |
256
+ | `Tabs` | `registry/base/tabs.tsx` | `components/navigation/tabs/index.tsx` | `defaultSelectedIndex` added as the index-mode twin of the existing `defaultValue`; indicator and hover pill are `GooIndicator`s (the hover pill returns to the active tab as it fades); statics `.List/.Item/.Panel` |
279
257
  | `TabsSubtle` | `registry/base/tabs-subtle.tsx` | `components/navigation/tabs-subtle/index.tsx` | uncontrolled mode; panels may be authored inside the root (below); the tab list's ref write goes through `MutableRefObject`; selected and hover pills are `GooIndicator`s; statics `.Item/.Panel` |
280
- | `Textarea` | — (local; Input's multi-line twin) | `components/inputs/textarea/index.tsx` | Base UI `Field.Control` rendered as a `<textarea>`; the field ladder from `lib/field-classes.ts`; padding sized so one row matches the control height; grows from `minRows` to `maxRows` (InputMessage's measure), then scrolls; `value` / `defaultValue` / `onChange`; `readOnly` / `required` (also from a surrounding `Field`); neither `value` nor `onChange` means a DOM-held uncontrolled `<textarea>` (ref-readable, form-reset aware) |
258
+ | `Textarea` | — (local; Input's multi-line twin) | `components/inputs/textarea/index.tsx` | Base UI `Field.Control` rendered as a `<textarea>`; the field ladder from `lib/field-classes.ts`; padding sized so one row matches the control height; grows from `minRows` to `maxRows` (InputMessage's measure), then scrolls; `value` / `defaultValue` / `onChange` |
281
259
  | `ThinkingIndicator` | `registry/default/thinking-indicator.tsx` | `components/AI/thinking-indicator/index.tsx` | upstream prop JSDoc kept (it already matches the FF API table); the `.shimmer-text` rule it rides lives in `base.css`; local `variant="goo"` (three dots merging and splitting through `GooFilter`, plain label; default stays `shimmer`); reduced motion also follows MotionConfig |
282
- | `Toast` | — (local; after Sileo, see [Morph sources](#morph-sources)) | `components/overlays/toast/index.tsx` (+ `manager.ts`, `global-demo.tsx`) | Base UI Toast (queue, timers, swipe, announcements) with Sileo's pill melting into a body through the shared `GooFilter`; autopilot expand/collapse, six states on the `--status-*` tokens, promise toasts; `Toast` is the provider + viewport, `Toast.Trigger` shows one, `useToast()` the in-tree API (plus `toasts`, `update`, `dismiss`); `manager.ts` holds one module-level Base UI `createToastManager()` exported as the global `toast()` (`.success/.error/.warning/.info/.loading/.promise/.update/.dismiss`, each returning `{ id, update, dismiss }`), queuing calls made before a provider subscribes (dropped on the server); `<Toast manager={toast}>` renders them (`manager` takes any source with a `subscribe`); ReactNode title/description, `icon` as a component or node, `action` as `{ label, onClick }` or a node, `duration` as an alias of `timeout`; a loading toast stays until its type changes, then leaves on the timeout; status glyphs via `useIcons()` instead of direct lucide imports; `global-demo.tsx` is the docs stage; `Toast.Action` / `Toast.Close` (Base UI's parts as compact Buttons, `render` / `asChild`) for custom action nodes |
283
- | `Tooltip` | `registry/base/tooltip.tsx` | `components/overlays/tooltip/index.tsx` | `className`/`children` docs filled in; statics `.Provider` / `.PortalContainer`; the slide + fade replaced by the morph layer (goo from the trigger on `spring.goo`, `from` / `effect` / `tier` props; `followCursor` tooltips fade); a hand-off between grouped tooltips skips the morph (Base UI's `data-instant`); local compound parts `TooltipRoot` (`open` / `defaultOpen` / `onOpenChange`, `delay` or `delayDuration`, `closeDelay`, `followCursor`), `TooltipTrigger` (`render` or Radix-style `asChild`; drops the slot's `nativeButton`) and `TooltipContent` (`side`, `align`, `sideOffset`, `alignOffset`, `collisionPadding`, `positionerClassName`, morph options, `render` / `asChild` for the label, rest props on the popup), also as statics `.Root .Trigger .Content`; `Tooltip` without `content` is the root, and the flat form gains `open` / `defaultOpen` / `align` / `alignOffset` / `collisionPadding` / `delay` / `closeDelay`; `TooltipProvider` takes `delay` / `closeDelay` / `timeout` and Radix's `delayDuration` / `skipDelayDuration` (Base UI name wins; a negative skip clamps to 0) |
260
+ | `Toast` | — (local; after Sileo, see [Morph sources](#morph-sources)) | `components/overlays/toast/index.tsx` | Base UI Toast (queue, timers, swipe, announcements) with Sileo's pill melting into a body through the shared `GooFilter`; autopilot expand/collapse, six states on the `--status-*` tokens, promise toasts; `Toast` is the provider + viewport, `Toast.Trigger` shows one, `useToast()` the imperative API |
261
+ | `Tooltip` | `registry/base/tooltip.tsx` | `components/overlays/tooltip/index.tsx` | `className`/`children` docs filled in; statics `.Provider` / `.PortalContainer`; the slide + fade replaced by the morph layer (goo from the trigger on `spring.goo`, `from` / `effect` / `tier` props; `followCursor` tooltips fade); a hand-off between grouped tooltips skips the morph (Base UI's `data-instant`) |
284
262
 
285
263
  #### blocks
286
264
 
@@ -293,17 +271,17 @@ only what is specific to it:
293
271
  | — | `registry/blocks/sidebar-app/inset-topbar.tsx` | `blocks/sidebar-app/inset-topbar.tsx` | the trigger's peek-time fade dropped (the sidebar opens on hover in flow, so the trigger stays) |
294
272
  | — | `registry/default/lib/sidebar-menu-grid.ts` | `blocks/sidebar-app/menu-grid.ts` | the width reads `--anchor-width` only; the `-ml-1` shift dropped (it would move the morph surface's content off its background) |
295
273
 
296
- `Select` in `docs/chrome.tsx` is not an item: modo's docs chrome renders its Select slot
274
+ `Select` in `modo.components.tsx` is not an item: modo's docs chrome renders its Select slot
297
275
  with a flat `value` / `onChange` / `options` contract
298
276
  (`lib/src/lib/slots.tsx`), and this adapter maps it onto
299
277
  `Select.Trigger` / `Select.Content` / `Select.Item` so the chrome runs on the
300
278
  design system's own Select. The
301
279
  `components/inputs/select` item keeps the upstream API untouched.
302
280
 
303
- `DocsNav` in `docs/chrome.tsx` is the chrome's Sidebar slot, pinned as
281
+ `DocsNav` in `modo.components.tsx` is the chrome's Sidebar slot, pinned as
304
282
  `shell.Sidebar` (by name alone modo would adopt the documented `Sidebar`, an
305
283
  app shell that needs its provider). Each aside is an inset `Sidebar` with its
306
- own provider, and `docs/chrome.css` turns the content between them into the inset
284
+ own provider, and `global.css` turns the content between them into the inset
307
285
  card (the lib's grid columns become `auto`, so they follow the sidebars' width
308
286
  springs). Each provider has `openOnHover`, and its `Sidebar.Trigger` sits in
309
287
  the card's corner: the trigger, `[` for the nav and `]` for the panel, switch
@@ -316,7 +294,7 @@ below xl. A section of links is a collapsible `Sidebar.Group` with one
316
294
  highlight melt from link to link; a panel section (Theme) keeps its control
317
295
  under the group label.
318
296
 
319
- `ThemeSwitcher` in `docs/chrome.tsx` is not an item either: it is the `Theme` entry in
297
+ `ThemeSwitcher` in `modo.components.tsx` is not an item either: it is the `Theme` entry in
320
298
  `modo.config.ts` `panel.items`, a `Select` of Light / Dark / System (each row
321
299
  with its icon, the trigger showing the active one) that reads and sets
322
300
  `window.__uiTheme` and re-reads it on `ui:themechange`. All switching logic lives in the pre-paint controller
@@ -324,75 +302,6 @@ described under **Tailwind → UnoCSS**, so the control holds no theme state of
324
302
  its own. `demo/scripts/run-design-systems.ts` appends its own `Switcher` panel
325
303
  item to whatever a design system declares, so both show up under the runner.
326
304
 
327
- The chrome's own elements (the corner triggers, the panel section's gutter) are
328
- styled in `docs/chrome.css` through `data-modo-ui` attributes, not utility
329
- classes: nothing in `docs/` needs a UnoCSS or Tailwind scan, so a host with
330
- either generator loads the same file. `Button` and `Link` are pinned too, so a
331
- design system with items of those names but another prop shape is not matched
332
- by name (modo would warn on every start).
333
-
334
- ### The docs chrome, for another design system
335
-
336
- A design system documented with modo (an `@utegsk/ui`-style package that
337
- depends on `@justanarthur/modo-ui`) gets the same sidebars, inset card layout,
338
- panel and Theme switcher as this site by pointing its `modo.config.ts` at the
339
- shipped module. A `shell` / `panel` value may be a package specifier (the
340
- viewer resolves it from the project root through the package's `exports`, the
341
- `source` file first), which needs an `@justanarthur/modo` release after
342
- 0.9.0-canary.0; with an older viewer keep a one-line local re-export instead
343
- (`export * from '@justanarthur/modo-ui/docs'` in a `docs/shell.tsx`, and point
344
- the slots at `./docs/shell.tsx#DocsNav`).
345
-
346
- ```ts
347
- // modo.config.ts
348
- import { defineConfig } from '@justanarthur/modo/config'
349
-
350
- export default defineConfig({
351
- name: 'My DS',
352
- css: './docs.css',
353
- vite: './vite.mjs',
354
- shell: {
355
- Button: '@justanarthur/modo-ui/docs#Button',
356
- Link: '@justanarthur/modo-ui/docs#Link',
357
- Select: '@justanarthur/modo-ui/docs#Select',
358
- Icon: '@justanarthur/modo-ui/docs#Icon',
359
- Sidebar: '@justanarthur/modo-ui/docs#DocsNav',
360
- },
361
- panel: { items: [{ label: 'Theme', component: '@justanarthur/modo-ui/docs#ThemeSwitcher' }] },
362
- })
363
- ```
364
-
365
- ```css
366
- /* docs.css: the package stylesheet (or base.css with your own utilities), then the chrome */
367
- @import "@justanarthur/modo-ui/styles.css";
368
- @import "@justanarthur/modo-ui/docs/chrome.css";
369
- ```
370
-
371
- ```js
372
- // vite.mjs: plain JS, Node loads it as is. Add your own plugins (Tailwind, UnoCSS) beside docsTheme.
373
- import { docsTheme } from '@justanarthur/modo-ui/docs/vite'
374
-
375
- export default config => {
376
- config.plugins = [...(config.plugins ?? []), docsTheme({ storageKey: 'my-ds-theme' })]
377
- return config
378
- }
379
- ```
380
-
381
- - `chrome.css` also loads by itself, as the stylesheet beside the slot module,
382
- when modo bundles `@justanarthur/modo-ui/docs` from its source; the explicit
383
- `@import` fixes where it sits in your cascade and is the one to rely on.
384
- - `docsTheme` puts `.light` / `.dark` on `<html>` before first paint and
385
- exposes `window.__uiTheme` for `ThemeSwitcher`; `storageKey` (default
386
- `modo-ui-theme`) keeps two sites on one origin apart.
387
- - The panel's narrow-screen behavior (below xl the panel is a drawer, opened on
388
- hover or with `]`, never a strip above the content) comes with `chrome.css`.
389
- A stylesheet that re-implements the layout instead of importing it can
390
- recreate the lib's `grid-template-rows: auto` strip: a viewport-tall blank
391
- row with the Theme select behind it.
392
- - `lucide-react` (the `Icon` slot) is already a dependency of the package;
393
- the docs entry adds no other. `@justanarthur/modo-ui` itself must be a
394
- dependency of the host: modo resolves the specifier from the project root.
395
-
396
305
  ## Tier mapping
397
306
 
398
307
  The tiers mirror the FF docs navigation. FF's "System" pages become
@@ -409,7 +318,6 @@ becomes the one block.
409
318
  | primitives | `code` (Code) | — (local, sugar-high) | — |
410
319
  | primitives | `morph` (Morph) | — (local, `lib/use-morph.ts`) | — |
411
320
  | primitives | `craft` (Craft) | — (local, bad/good pairs) | skill (before/after) |
412
- | primitives | `separator` (Separator), `skeleton` (Skeleton) | — (local) | — |
413
321
  | components | accordion, button, combobox, dialog, dropdown, select, slider, switch, tabs, tabs-subtle, tooltip | `registry/base/<id>.tsx` | same slug |
414
322
  | components | `checkbox` (Checkbox, `.Group`), `radio` (Radio, `.Group`) | `registry/base/checkbox-group.tsx`, `radio-group.tsx` | checkbox-group, radio-group |
415
323
  | components | badge, card, color-picker, input-message, table, thinking-indicator | `registry/default/<id>.tsx` | same slug |
@@ -417,7 +325,6 @@ becomes the one block.
417
325
  | components | `input` (Input, Label, InputGroup) | `registry/default/input-group.tsx` | input-group |
418
326
  | components | alert-dialog, command, context-menu, popover, preview-card, search, sheet, toast | — (local, see [Morph sources](#morph-sources)) | — |
419
327
  | components | calendar, date-picker, date-range-picker, time-picker, duration-picker, month-picker (group `inputs/date-time`) | — (local, on react-day-picker) | — |
420
- | components | avatar, progress, field, number-input, file-dropzone, navigation-menu, pagination | — (local) | — |
421
328
  | components | sidebar | `base/sidebar.tsx` + `default/sidebar-core.tsx` + `default/sidebar-menu.tsx` | sidebar |
422
329
  | blocks | `sidebar-app` (SidebarApp) | the preset generator's output + `blocks/sidebar-*` | sidebar, preset `sa1FQfCxH6` |
423
330
 
@@ -441,7 +348,7 @@ No ported file imports any of them.
441
348
 
442
349
  The files only they, or the FF docs site's nav, use are left out too:
443
350
  `mobile-drawer`, `nav-item`, `nav-menu`, `lib/theme-context.tsx` (the
444
- `ThemeSwitcher` panel item and docs/vite.ts's pre-paint controller take its
351
+ `ThemeSwitcher` panel item and vite.ts's pre-paint controller take its
445
352
  place) and the blocks other than the sidebar's (`queued-stack`,
446
353
  `dialog-sidebar`). Inside kept files, the same rule removed
447
354
  `SURFACE_HOVER_BG`, `SURFACE_HOVER_SHADOW` and `surfaceHoverClasses` from
@@ -468,8 +375,7 @@ prebuilt `styles.css`, and turns `preset.ts` into `tailwind.css`.
468
375
 
469
376
  - **Dark mode.** `dark: 'class'` produces `.dark .dark\:x`, the same "inside a
470
377
  `.dark` ancestor" contract as FF's `@custom-variant dark (&:is(.dark *))`.
471
- modo ships no theme of its own, so `docsTheme` (`docs/vite.ts`, applied by
472
- `vite.ts`) injects a small controller into
378
+ modo ships no theme of its own, so `vite.ts` injects a small controller into
473
379
  `index.html` (`transformIndexHtml`, `head-prepend`). Before first paint it
474
380
  puts `light` or `dark` on `<html>` — the stored preference, or the OS one
475
381
  under `system` — which is also what flips every `light-dark()` token through
@@ -482,10 +388,7 @@ prebuilt `styles.css`, and turns `preset.ts` into `tailwind.css`.
482
388
  `global.css` (and the `base.css` it imports) and fixes the order of the
483
389
  layer its `@layer base` rules join.
484
390
  `vite.ts` is loaded by Node with type stripping, so it may only use erasable
485
- TypeScript, names the `.ts` extension of the one relative module it imports
486
- (`./docs/vite.ts`) and hands `uno.config.ts` to UnoCSS by absolute path.
487
- `docs/vite.ts` ships built (`dist/docs/vite.js`): Node never strips types
488
- from a file under `node_modules`.
391
+ TypeScript and hands `uno.config.ts` to UnoCSS by absolute path.
489
392
  - **Colors.** Theme colors point at the CSS variables directly (for example
490
393
  `accent: 'var(--accent)'`, `surface.1..8`). wind4 applies opacity modifiers
491
394
  to `var()` colors with `color-mix(in srgb, …)`, so `bg-accent/12` works on
@@ -509,7 +412,7 @@ prebuilt `styles.css`, and turns `preset.ts` into `tailwind.css`.
509
412
  after the reset, so utilities (in `default`) still win. This is the same
510
413
  arrangement as Tailwind's base/utilities split.
511
414
  - **Content.** UnoCSS scans `{lib,primitives,components,blocks}/**/*.{ts,tsx,mdx}`
512
- from disk (`content.filesystem`, and the same
415
+ and `modo.components.tsx` from disk (`content.filesystem`, and the same
513
416
  globs in `content.pipeline.include`, since the default pipeline skips
514
417
  `.ts`). Two reasons:
515
418
  - modo serves items pre-bundled, so the sources never pass through Vite's
@@ -619,20 +522,19 @@ declared packages.
619
522
 
620
523
  ## Docs and examples
621
524
 
622
- What modo's item reader (`lib/src/lib/docs.ts`, `tsdoc.ts`) and example compiler
525
+ What modo's parser (`lib/src/lib/tsdoc.ts`) and example compiler
623
526
  (`lib/src/lib/example.ts`) need, and how this package answers it:
624
527
 
625
- - **The item is the file's `export default`**, followed through re-exports
626
- to its declaration — `function X(…)`, a `forwardRef<El, XProps>(…)`, or any
627
- component-typed value. (The workarounds for the old text parser stay: ScrollArea's
628
- spelled-out `HTMLDivElement`, Combobox's de-generified root.)
629
- - **Props are read with the TypeScript compiler** from the render function's
630
- parameter, the `forwardRef` props type or the component's type, inherited
631
- members included (`extends`, `Omit`, `Pick`, intersections, across files).
632
- React's DOM attributes and other libraries' typings (Base UI,
633
- react-day-picker) stay out unless re-declared, so a prop meant for the table
634
- is declared with a description. The Default column takes the destructured
635
- default, else `@default`, else a closing ``Defaults to `x`.`` sentence.
528
+ - **The item is the file's `export default`** — either `function X(…)` or a
529
+ `const X = forwardRef<HTMLXElement, XProps>(…)`. The forwardRef form's first
530
+ type argument must contain no `<` or `,`, which is why ScrollArea spells out
531
+ `HTMLDivElement` instead of `ComponentRef<typeof …>`, and why Combobox's
532
+ root lost its generics.
533
+ - **Props come from a same-file `interface XProps`**, and only from members
534
+ declared in its body — inherited members are invisible, and a member whose
535
+ type spans several lines is dropped. Every member needs a description, and
536
+ defaults are read from that prose (`Defaults to \`false\`.`), not from the
537
+ destructuring. Hence the FF API-table text re-declared on every prop.
636
538
  - **Examples live in `examples.mdx`** next to the item, included by the
637
539
  TSDoc's `@example {@include ./examples.mdx}`: a `# <FF section title>`,
638
540
  an optional caption, then one JSX block (or a fenced code block for code to
@@ -698,7 +600,7 @@ The runner kills stray `modo dev` processes, splices a temporary
698
600
  upward. To run the package on its own, without the switcher:
699
601
 
700
602
  ```sh
701
- cd ui && MODO_PORT=5180 bun ../lib/dist/cli.js dev # after a lib build; ui has no modo bin
603
+ cd ui && MODO_PORT=5180 bunx modo dev
702
604
  ```
703
605
 
704
606
  ## How to verify