@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
@@ -1,121 +0,0 @@
1
- /*
2
- * Local addition (not part of Fluid Functionalism): the field ladder FF
3
- * repeats across InputGroup, Combobox and Sidebar's input, as one recipe,
4
- * and `useFieldBox`, the box every text field (Input, Textarea, Combobox,
5
- * the date and time pickers) builds on.
6
- */
7
-
8
- import { createContext, type MouseEvent, type RefObject, useContext } from 'react'
9
- import { FIELD_PX, type FieldVariant, fieldVariants } from './field-variants'
10
- import { useShape } from './shape-context'
11
- import { type SizeVariant, useSize } from './size-context'
12
- import { cn } from './utils'
13
-
14
- // The pure tables live in `field-variants.ts` (callable from a server
15
- // component); every name stays importable from here.
16
- export {
17
- FIELD_ACTION,
18
- FIELD_ACTION_BOX,
19
- FIELD_ACTION_END,
20
- FIELD_ACTION_RADIUS,
21
- FIELD_ADORNMENT_ICON,
22
- FIELD_PX,
23
- FIELD_TEXT_INSET,
24
- type FieldVariant,
25
- fieldActionClasses,
26
- fieldAdornmentClasses,
27
- fieldIconClasses,
28
- fieldVariants,
29
- } from './field-variants'
30
-
31
- /**
32
- * What every text field's box takes. Items re-declare these members in their
33
- * own props interface (the docs read only same-file members), with this prose.
34
- */
35
- export interface FieldBoxOptions {
36
- /** Framed at rest, or invisible until hovered or focused. */
37
- variant: FieldVariant
38
- /** Turns the field destructive. */
39
- invalid?: boolean
40
- /** Frames and dims the field. */
41
- disabled?: boolean
42
- /** Lit from outside, e.g. a group's fluid hover. */
43
- active?: boolean
44
- /** Shows the value without letting it change: the ring answers, the fill never lifts. */
45
- readOnly?: boolean
46
- /** Marks the control required (`required` on the control). */
47
- required?: boolean
48
- /** Pins the field to one step of the size ladder. Defaults to the surrounding SizeProvider. */
49
- size?: SizeVariant
50
- }
51
-
52
- /** What a field wrapper hands to the control it holds. */
53
- export interface FieldState {
54
- /** Lit by a group's fluid hover. */
55
- active: boolean
56
- invalid: boolean
57
- disabled: boolean
58
- readOnly?: boolean
59
- required?: boolean
60
- }
61
-
62
- /**
63
- * State a field wrapper (Field, InputGroup.Field) hands to whatever control
64
- * it holds: lit by the group's fluid hover, its error, its disabled,
65
- * read-only and required state. `useFieldBox` reads it, so any field built on
66
- * the box joins in; the control's own props win.
67
- */
68
- export const FieldStateContext = createContext<FieldState | null>(null)
69
-
70
- /** The surrounding field's state, or `null` outside one. */
71
- export function useFieldState() {
72
- return useContext(FieldStateContext)
73
- }
74
-
75
- /**
76
- * The box around a text field's control: the field ladder in the chosen
77
- * variant, the state attributes it reads, the shape's input radius and the
78
- * horizontal inset. Spread `props` on the element around the control (or the
79
- * control itself, for a button field); the height stays with the item, from
80
- * the returned `size`. Inside a Field or InputGroup.Field, unset `active` / `invalid` /
81
- * `disabled` / `readOnly` / `required` come from the field (`FieldStateContext`).
82
- */
83
- export function useFieldBox({ variant, invalid, disabled, active, readOnly, required, size }: FieldBoxOptions) {
84
- const field = useContext(FieldStateContext)
85
- const shape = useShape()
86
- const sizeClasses = useSize(size)
87
- const isInvalid = invalid ?? field?.invalid ?? false
88
- const isDisabled = disabled ?? field?.disabled ?? false
89
- const isReadOnly = readOnly ?? field?.readOnly ?? false
90
-
91
- return {
92
- size: sizeClasses,
93
- /** Resolved with the field's state, for the control's `aria-invalid` / `disabled` / `readOnly` / `required`. */
94
- invalid: isInvalid,
95
- disabled: isDisabled,
96
- readOnly: isReadOnly,
97
- required: required ?? field?.required,
98
- props: {
99
- 'data-active': (active ?? field?.active) || undefined,
100
- 'data-invalid': isInvalid || undefined,
101
- 'data-disabled': isDisabled || undefined,
102
- 'data-readonly': isReadOnly || undefined,
103
- className: cn(fieldVariants({ variant }), shape.input, FIELD_PX[sizeClasses.variant]),
104
- },
105
- }
106
- }
107
-
108
- /**
109
- * A press anywhere in the box (icon, padding) focuses the control, without
110
- * disturbing the control's own caret placement. A press that only reaches the
111
- * box through the React tree (a popup portalled out of an adornment, e.g. a
112
- * searchable Dropdown) is left alone, so that popup can take focus itself.
113
- */
114
- export function focusControlOnPress(control: RefObject<HTMLElement | null>) {
115
- return (e: MouseEvent) => {
116
- if (e.target === control.current) return
117
- if (!e.currentTarget.contains(e.target as Node)) return
118
- e.preventDefault()
119
- control.current?.focus()
120
- }
121
- }
@@ -1,117 +0,0 @@
1
- /*
2
- * Local addition (not part of Fluid Functionalism): the field ladder's pure
3
- * class tables, split from `field-classes.ts` so they carry no hooks, JSX or
4
- * contexts. A React Server Component can call them; `field-classes.ts`
5
- * re-exports every name, so its imports keep working.
6
- */
7
-
8
- import { cva } from 'class-variance-authority'
9
- import type { ShapeVariant } from './shape-context'
10
- import type { SizeVariant } from './size-context'
11
-
12
- /**
13
- * The ringed box of a text field. It steps from rest to a muted fill when lit
14
- * (hovered, or `data-active` from a group's fluid hover) to the card fill
15
- * when focused. `data-invalid` keeps a destructive ring in every state and
16
- * tints the lit fill; `data-disabled` frames and dims it; `data-readonly`
17
- * shows the ring when lit or focused but never lifts the fill. Put it on the
18
- * element around the control and stamp the data attributes; Base UI parts
19
- * stamp `data-invalid` / `data-disabled` themselves.
20
- */
21
- export const fieldVariants = cva(
22
- [
23
- 'group/field ring-1 cursor-text transition-[background-color,box-shadow,opacity] duration-fast',
24
- 'hover:bg-muted/50 hover:ring-border data-[active]:bg-muted/50 data-[active]:ring-border',
25
- // `!`: Uno doesn't emit the state variants in a fixed order, so the
26
- // states that must win (focus fill, invalid ring) win on importance.
27
- 'focus-within:!bg-card focus-within:ring-border',
28
- 'data-[invalid]:!ring-destructive/50 data-[invalid]:hover:bg-destructive-light/60 data-[invalid]:data-[active]:bg-destructive-light/60',
29
- 'data-[disabled]:ring-border data-[disabled]:opacity-50 data-[disabled]:pointer-events-none',
30
- // A read-only value can be selected and copied but not changed: the ring
31
- // still answers the pointer and the keyboard, the fill never lifts. The
32
- // attribute selector outranks the focus fill's at equal importance.
33
- 'data-[readonly]:cursor-default data-[readonly]:hover:!bg-transparent data-[readonly]:data-[active]:!bg-transparent data-[readonly]:focus-within:!bg-transparent',
34
- ],
35
- {
36
- variants: {
37
- variant: {
38
- // Invisible until lit or focused.
39
- borderless: 'bg-transparent ring-transparent',
40
- // Framed at rest.
41
- bordered: 'bg-transparent ring-border',
42
- },
43
- },
44
- defaultVariants: {
45
- variant: 'borderless',
46
- },
47
- },
48
- )
49
-
50
- /** A leading icon inside a `fieldVariants` box: muted at rest, it darkens and thickens with the field. Pass `strokeWidth={1.5}`. */
51
- export const fieldIconClasses =
52
- 'shrink-0 text-muted-foreground transition-[color,stroke-width] duration-fast group-hover/field:text-foreground group-hover/field:stroke-[2] group-data-[active]/field:text-foreground group-data-[active]/field:stroke-[2] group-focus-within/field:text-foreground group-focus-within/field:stroke-[2]'
53
-
54
- /**
55
- * Content beside a field's text (an adornment): muted, held to the ladder's
56
- * glyph size, and lit with the field like a leading icon. Strings read as a
57
- * prefix or a unit.
58
- */
59
- export const fieldAdornmentClasses =
60
- 'flex shrink-0 items-center whitespace-nowrap text-muted-foreground transition-[color] duration-fast group-hover/field:text-foreground group-data-[active]/field:text-foreground group-focus-within/field:text-foreground'
61
-
62
- /** Glyph size for an adornment's icons, per ladder step (16px default, 14px compact). */
63
- export const FIELD_ADORNMENT_ICON: Record<SizeVariant, string> = {
64
- default: '[&_svg]:size-4',
65
- compact: '[&_svg]:size-3.5',
66
- }
67
-
68
- /**
69
- * A small icon button inside a field box (a password reveal, a clear, a
70
- * stepper): 4px inside the ring on every side (28px in a 36px field, 20px in
71
- * a 28px one), its negative margin taking back the box's inset so the gap to
72
- * the edge matches the gap above and below.
73
- */
74
- export const FIELD_ACTION: Record<SizeVariant, string> = {
75
- default: 'size-7 -mx-1.5 [&_svg]:size-4',
76
- compact: 'size-5 -mx-1 [&_svg]:size-3.5',
77
- }
78
-
79
- /** A field action's box alone, without `FIELD_ACTION`'s margins, for actions set side by side (a stepper pair). */
80
- export const FIELD_ACTION_BOX: Record<SizeVariant, string> = {
81
- default: 'size-7 [&_svg]:size-4',
82
- compact: 'size-5 [&_svg]:size-3.5',
83
- }
84
-
85
- /** The margin that pulls the last of several side-by-side actions to 4px inside the ring. */
86
- export const FIELD_ACTION_END: Record<SizeVariant, string> = {
87
- default: '-mr-1.5',
88
- compact: '-mr-1',
89
- }
90
-
91
- /** A field action's corners, concentric with the box's (8px box, 4px gap) or round in pill mode. */
92
- export const FIELD_ACTION_RADIUS: Record<ShapeVariant, string> = {
93
- rounded: 'rounded-sm',
94
- pill: 'rounded-full',
95
- }
96
-
97
- /** The classes every field action shares, beside its `FIELD_ACTION` size and radius. */
98
- export const fieldActionClasses =
99
- 'relative inline-flex shrink-0 cursor-pointer items-center justify-center text-muted-foreground outline-none transition-[color,background-color,opacity] duration-fast hover:bg-hover hover:text-foreground active:bg-active focus-visible:ring-1 focus-visible:ring-focus-ring disabled:pointer-events-none disabled:opacity-50 data-[disabled]:pointer-events-none data-[disabled]:opacity-50'
100
-
101
- // Literal tables: one notch tighter than the ladder's `px`, since the ring is
102
- // invisible at rest and the roomier inset would read as a gap.
103
-
104
- /** Horizontal inset of a field box. */
105
- export const FIELD_PX: Record<SizeVariant, string> = {
106
- default: 'px-2.5',
107
- compact: 'px-2',
108
- }
109
-
110
- /** Left inset of the text around a field (label, description, error), so it lines up with the text inside the box. */
111
- export const FIELD_TEXT_INSET: Record<SizeVariant, string> = {
112
- default: 'pl-2.5',
113
- compact: 'pl-2',
114
- }
115
-
116
- /** Framed at rest (`bordered`), or invisible until hovered or focused (`borderless`). */
117
- export type FieldVariant = 'bordered' | 'borderless'
@@ -1,139 +0,0 @@
1
- /*
2
- * Vendored from Fluid Functionalism — `registry/default/fluid-hover-highlight.tsx` at
3
- * github.com/mickadesign/fluid-functionalism@b3587bdbd83fc66c2a6aae3817ffb856cb09260b
4
- * (fluidfunctionalism.com). MIT License © 2026 Micka Touillaud — see
5
- * LICENSE.fluid-functionalism in this package.
6
- *
7
- * Local modifications:
8
- * - `"use client"` directive dropped (no RSC here).
9
- * - `framer-motion` → `motion/react` (the package's current name).
10
- * - `@/lib/*` and `@/hooks/*` imports rewritten to sibling `./*` paths.
11
- * - The fill is a `GooIndicator` (`./goo-indicator`, local): it melts from row
12
- * to row with a liquid neck instead of sliding as one box. The keyed fade,
13
- * `from`, `hidden` and `transition` behave as before; a square highlight
14
- * (no radius) has nothing to melt and slides as before.
15
- */
16
-
17
- import { AnimatePresence, motion, type Transition, useReducedMotion } from 'motion/react'
18
- import { GooIndicator } from './goo-indicator'
19
- import { spring } from './springs'
20
- import type { ItemRect, UseFluidHoverReturn } from './use-fluid-hover'
21
- import { cn } from './utils'
22
-
23
- // ---------------------------------------------------------------------------
24
- // The one hover highlight every fluid hover list renders: an absolutely
25
- // positioned fill that springs between the rects `useFluidHover` measures.
26
- // Consumers used to hand-roll this motion.div; this is that block, once.
27
- //
28
- // const hover = useFluidHover(ref);
29
- // <FluidHoverHighlight hover={hover} className={shape.bg} />
30
- //
31
- // It owns no layout opinion beyond `absolute`: radius, z-index, and the
32
- // offsetParent (the container must be `relative`) are the consumer's.
33
- // ---------------------------------------------------------------------------
34
-
35
- /** What the highlight reads off the hook: the highlighted index, the
36
- * measured rects, whether they are current, and the pointer session. */
37
- export type FluidHoverSource = Pick<UseFluidHoverReturn, 'activeIndex' | 'itemRects' | 'isMeasured' | 'sessionRef'>
38
-
39
- interface HighlightFromHook {
40
- /** The hook's return value. The highlight sits on
41
- * `itemRects[activeIndex]` once `isMeasured`, and re-keys on the session. */
42
- hover: FluidHoverSource
43
- /** Keep the list's state but show nothing (a closed popup, hover switched
44
- * off). Runs the exit fade. */
45
- hidden?: boolean
46
- rect?: never
47
- session?: never
48
- }
49
-
50
- interface HighlightFromRect {
51
- /** For lists that resolve their own rect (the sidebar's unified scope):
52
- * the rect to sit on, in the container's coordinate space. `null` hides
53
- * the highlight (it fades out on `spring.fast.exit`). */
54
- rect: ItemRect | null
55
- /** `sessionRef.current` from `useFluidHover`. It increments when the
56
- * cursor enters the container, which re-keys the highlight so it fades in
57
- * at `from ?? rect` instead of sliding over from wherever it was last. */
58
- session: number
59
- hover?: never
60
- hidden?: never
61
- }
62
-
63
- export type FluidHoverHighlightProps = (HighlightFromHook | HighlightFromRect) & {
64
- /** Where a fresh session fades in from. A dropdown passes its checked row,
65
- * a nav menu its active route. Defaults to the rect itself. */
66
- from?: ItemRect | null
67
- /** Radius, z-index, anything else. Merged onto
68
- * `absolute bg-hover pointer-events-none`. */
69
- className?: string
70
- /** The positional spring. Defaults to `spring.fast`. Pass `false` to snap
71
- * to the new rect with no travel (a layout reflow that moved the rows
72
- * underneath, not a hover change). The opacity fade is always 0.08s. */
73
- transition?: Transition | false
74
- }
75
-
76
- const fade: Transition = { duration: 0.08 }
77
- const snap: Transition = { duration: 0 }
78
-
79
- /** A measured rect as animation targets: position as a transform, size as
80
- * layout. Exported for the unit test. */
81
- export function toTarget(rect: ItemRect) {
82
- return { x: rect.left, y: rect.top, width: rect.width, height: rect.height }
83
- }
84
-
85
- /**
86
- * Resolves the positional transition. Reduced motion keeps the opacity fade
87
- * and drops the travel, per the motion guidelines: fewer and gentler, not
88
- * none. Exported for the unit test.
89
- */
90
- export function resolveHighlightTransition(
91
- transition: Transition | false | undefined,
92
- reduceMotion: boolean,
93
- ): Transition {
94
- const positional = transition === false || reduceMotion ? snap : (transition ?? spring.fast)
95
- return { ...positional, opacity: fade }
96
- }
97
-
98
- /** The rect and session a set of props resolves to. Exported for the test. */
99
- export function resolveHighlightSource(props: FluidHoverHighlightProps): {
100
- rect: ItemRect | null
101
- session: number
102
- } {
103
- if (props.hover) {
104
- const { activeIndex, itemRects, isMeasured, sessionRef } = props.hover
105
- const rect = !props.hidden && isMeasured && activeIndex !== null ? (itemRects[activeIndex] ?? null) : null
106
- return { rect, session: sessionRef.current }
107
- }
108
- return { rect: props.rect, session: props.session }
109
- }
110
-
111
- export function FluidHoverHighlight(props: FluidHoverHighlightProps) {
112
- const { from, className, transition } = props
113
- const { rect, session } = resolveHighlightSource(props)
114
- // Reads the OS media query directly, so an installed copy honours reduced
115
- // motion without the app wrapping its tree in MotionConfig.
116
- const reduceMotion = useReducedMotion() ?? false
117
- return (
118
- <AnimatePresence>
119
- {rect && (
120
- <motion.div
121
- key={session}
122
- data-slot="fluid-hover-highlight"
123
- className="pointer-events-none absolute top-0 left-0"
124
- initial={{ opacity: 0 }}
125
- animate={{ opacity: 1 }}
126
- exit={{ opacity: 0, transition: spring.fast.exit }}
127
- transition={fade}
128
- >
129
- <GooIndicator
130
- rect={rect}
131
- from={from}
132
- className={cn('bg-hover', className)}
133
- transition={transition === false || reduceMotion ? false : (transition ?? spring.fast)}
134
- />
135
- </motion.div>
136
- )}
137
- </AnimatePresence>
138
- )
139
- }
@@ -1,46 +0,0 @@
1
- /*
2
- * Local addition (not part of Fluid Functionalism): the one keyboard ring a
3
- * list panel draws (Dropdown and its submenus, NavigationMenu's panels,
4
- * Select): 2px outside the focused row, springing between rows on
5
- * `spring.fast` (a snap under reduced motion) and fading out on its exit.
6
- * Its corners follow the surrounding shape's `focusRing` radius, concentric
7
- * with the row; a popup that pins its own shape passes it.
8
- */
9
-
10
- import { AnimatePresence, motion } from 'motion/react'
11
- import { useReduceMotion } from './reduced-motion'
12
- import { type ShapeVariant, shapeMap, useShape } from './shape-context'
13
- import { spring } from './springs'
14
- import type { ItemRect } from './use-fluid-hover'
15
- import { cn } from './utils'
16
-
17
- interface FocusRingProps {
18
- /** The focused row's rect in the panel's coordinates; nothing while none has keyboard focus. */
19
- rect: ItemRect | null | undefined
20
- /** Pins the radius to one shape (popups stay `rounded`); defaults to the surrounding ShapeProvider. */
21
- shape?: ShapeVariant
22
- }
23
-
24
- /** The keyboard ring: 2px outside the focused row, springing between rows. */
25
- function FocusRing({ rect, shape }: FocusRingProps) {
26
- const surrounding = useShape()
27
- const radius = (shape ? shapeMap[shape] : surrounding).focusRing
28
- const reduced = useReduceMotion()
29
- return (
30
- <AnimatePresence>
31
- {rect && (
32
- <motion.div
33
- aria-hidden="true"
34
- className={cn('pointer-events-none absolute z-20 border border-focus-ring', radius)}
35
- initial={false}
36
- animate={{ left: rect.left - 2, top: rect.top - 2, width: rect.width + 4, height: rect.height + 4 }}
37
- exit={{ opacity: 0, transition: spring.fast.exit }}
38
- transition={reduced ? { duration: 0 } : { ...spring.fast, opacity: { duration: spring.fast.duration } }}
39
- />
40
- )}
41
- </AnimatePresence>
42
- )
43
- }
44
-
45
- export type { FocusRingProps }
46
- export { FocusRing }
@@ -1,261 +0,0 @@
1
- /*
2
- * Local addition (not part of Fluid Functionalism): the liquid indicator, the
3
- * morph style for everything that travels between items: a tab's active pill,
4
- * a switch thumb, the fluid hover highlight and merged selection backgrounds.
5
- * When the indicator leaves a rect it leaves a blob behind. The blob lingers
6
- * for a third of the spring, then follows to the back of the new rect,
7
- * shrinking, while the indicator springs on: the goo melts the two into one
8
- * stretched drop that lets go, or, on a long move, a drop and a droplet that
9
- * catches up. The filter runs only while a blob is alive; at rest nothing is
10
- * filtered.
11
- *
12
- * The goo is the morph engine's (`GOO_MATRIX` and `GOO_BLUR_RATIO` in
13
- * `lib/use-morph.ts`, after beUI's gooey popover and Sileo, notices
14
- * LICENSE.beui and LICENSE.sileo). `GooFilter` lays the source over the
15
- * thresholded blur, which only works for opaque fills: `bg-hover` and
16
- * `bg-active` are a few percent alpha, under the threshold. `GooLayer`
17
- * thresholds the shapes' coverage instead and fills the result with their own
18
- * token, read from their fill class, so translucent and opaque fills melt
19
- * alike.
20
- */
21
-
22
- import { animate, motion, type Transition, useMotionValue, type ValueAnimationTransition } from 'motion/react'
23
- import { type ReactNode, useId, useLayoutEffect, useRef, useState } from 'react'
24
- import { useReduceMotion } from './reduced-motion'
25
- import { spring } from './springs'
26
- import type { ItemRect } from './use-fluid-hover'
27
- import { GOO_BLUR_RATIO, GOO_MATRIX } from './use-morph'
28
- import { cn } from './utils'
29
-
30
- // Any coverage counts as solid before the blur, so a 4%-alpha fill melts like an opaque one.
31
- const COVERAGE = '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0'
32
- // The share of its cross size a retracting blob keeps: it thins into a neck instead of a point.
33
- const NECK = 0.5
34
-
35
- function union(a: ItemRect | null, b: ItemRect): ItemRect {
36
- if (!a) return b
37
- const left = Math.min(a.left, b.left)
38
- const top = Math.min(a.top, b.top)
39
- return {
40
- left,
41
- top,
42
- width: Math.max(a.left + a.width, b.left + b.width) - left,
43
- height: Math.max(a.top + a.height, b.top + b.height) - top,
44
- }
45
- }
46
-
47
- function pad(rect: ItemRect, by: number): ItemRect {
48
- return { left: rect.left - by, top: rect.top - by, width: rect.width + by * 2, height: rect.height + by * 2 }
49
- }
50
-
51
- function center(rect: ItemRect) {
52
- return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 }
53
- }
54
-
55
- /** A move worth a blob: the center travels more than half the indicator's size, not a resize in place. */
56
- function travels(from: ItemRect, to: ItemRect) {
57
- const a = center(from)
58
- const b = center(to)
59
- return (
60
- Math.abs(b.x - a.x) > Math.min(from.width, to.width) / 2 ||
61
- Math.abs(b.y - a.y) > Math.min(from.height, to.height) / 2
62
- )
63
- }
64
-
65
- /**
66
- * Where the blob left at `from` goes: the back edge of `to` on each axis that
67
- * moved, so it follows the indicator and is absorbed, and a neck on the other.
68
- */
69
- function retract(from: ItemRect, to: ItemRect): ItemRect {
70
- const axis = (start: number, size: number, toStart: number, toSize: number) => {
71
- const delta = toStart + toSize / 2 - (start + size / 2)
72
- if (Math.abs(delta) < 1) return [start + (size * (1 - NECK)) / 2, size * NECK] as const
73
- return [delta > 0 ? toStart : toStart + toSize, 0] as const
74
- }
75
- const [left, width] = axis(from.left, from.width, to.left, to.width)
76
- const [top, height] = axis(from.top, from.height, to.top, to.height)
77
- return { left, top, width, height }
78
- }
79
-
80
- function toTarget(rect: ItemRect) {
81
- return { x: rect.left, y: rect.top, width: rect.width, height: rect.height }
82
- }
83
-
84
- function blurOf(el: Element, rect: ItemRect) {
85
- const r = Number.parseFloat(getComputedStyle(el).borderTopLeftRadius) || 0
86
- return Math.min(r, rect.width / 2, rect.height / 2) * GOO_BLUR_RATIO
87
- }
88
-
89
- interface GooLayerProps {
90
- /** Filter on: the shapes melt into one. Off at rest. */
91
- active: boolean
92
- /** Blur in px: the shapes' radius times `GOO_BLUR_RATIO`. */
93
- blur: number
94
- /** The layer's box in the container's coordinates, covering every shape; padded for the blur here. */
95
- box: ItemRect | null
96
- /** The shapes' classes (a bg token, a radius): the melted result is filled with their background. */
97
- fill: string
98
- /** The shapes, positioned in the container's coordinates. */
99
- children?: ReactNode
100
- }
101
-
102
- /** A box of shapes that melt into one while `active`. The filter's region follows the box, so keep it tight. */
103
- export function GooLayer({ active, blur, box, fill, children }: GooLayerProps) {
104
- const id = `goo-${useId().replace(/:/g, '')}`
105
- const flood = useRef<SVGFEFloodElement>(null)
106
- const probe = useRef<HTMLDivElement>(null)
107
- const layer = box ? pad(box, blur * 3) : { left: 0, top: 0, width: 0, height: 0 }
108
-
109
- // Resolved each time the goo starts, so it follows the scheme.
110
- useLayoutEffect(() => {
111
- if (!active || !probe.current) return
112
- flood.current?.setAttribute('flood-color', getComputedStyle(probe.current).backgroundColor)
113
- }, [active])
114
-
115
- return (
116
- <>
117
- <svg aria-hidden className="absolute size-0">
118
- <filter id={id} x="-50%" y="-50%" width="200%" height="200%" colorInterpolationFilters="sRGB">
119
- <feColorMatrix in="SourceGraphic" values={COVERAGE} result="coverage" />
120
- <feGaussianBlur in="coverage" stdDeviation={blur} result="blur" />
121
- <feColorMatrix in="blur" values={GOO_MATRIX} result="goo" />
122
- <feFlood ref={flood} />
123
- <feComposite in2="goo" operator="in" />
124
- </filter>
125
- </svg>
126
- <div
127
- aria-hidden
128
- className="pointer-events-none absolute"
129
- // Geometry is the shapes' own; the filter is the effect itself, melting their token fill.
130
- style={{ ...layer, filter: active ? `url(#${id})` : undefined }}
131
- >
132
- {/* Zero-sized, so it paints nothing: it carries the fill token for the flood and maps the shapes back to the container's coordinates. */}
133
- <div ref={probe} className={cn(fill, 'absolute')} style={{ left: -layer.left, top: -layer.top }}>
134
- {children}
135
- </div>
136
- </div>
137
- </>
138
- )
139
- }
140
-
141
- interface Trail {
142
- id: number
143
- from: ItemRect
144
- to: ItemRect
145
- }
146
-
147
- interface GooIndicatorProps {
148
- /** The rect to sit on, in the container's coordinates (as `useFluidHover` measures them). */
149
- rect: ItemRect
150
- /** Where it first appears; it then travels to `rect`. Defaults to `rect`. */
151
- from?: ItemRect | null
152
- /** Fill and radius classes: a bg token and the shape's radius. */
153
- className?: string
154
- /** Shadow class. While it melts, the shapes are drawn again beneath the goo with it, since the filter flattens shadows. */
155
- shadow?: string
156
- /** The travel: a spring tier. `false` snaps (a reflow, reduced motion). Defaults to `spring.moderate`. */
157
- transition?: Transition | false
158
- /** Opacity of the whole indicator, faded on `spring.fast`. Defaults to `1`. */
159
- opacity?: number
160
- }
161
-
162
- /**
163
- * An indicator that travels between items with a liquid neck. Render it in the
164
- * items' `relative` container, beneath them: the items' text stays above it,
165
- * unfiltered.
166
- */
167
- export function GooIndicator({
168
- rect,
169
- from,
170
- className,
171
- shadow,
172
- transition = spring.moderate,
173
- opacity = 1,
174
- }: GooIndicatorProps) {
175
- const reduced = useReduceMotion()
176
- const start = from ?? rect
177
- const x = useMotionValue(start.left)
178
- const y = useMotionValue(start.top)
179
- const width = useMotionValue(start.width)
180
- const height = useMotionValue(start.height)
181
- const lead = useRef<HTMLDivElement>(null)
182
- const [trails, setTrails] = useState<Trail[]>([])
183
- const [blur, setBlur] = useState(0)
184
- const ids = useRef(0)
185
- const travel = transition === false || reduced ? false : transition
186
- const travelRef = useRef(travel)
187
- travelRef.current = travel
188
- const read = () => ({ left: x.get(), top: y.get(), width: width.get(), height: height.get() })
189
-
190
- // Only a new rect moves it: the transition is often an inline object.
191
- useLayoutEffect(() => {
192
- const move = travelRef.current as ValueAnimationTransition<number> | false
193
- const current = read()
194
- if (!move) {
195
- x.jump(rect.left)
196
- y.jump(rect.top)
197
- width.jump(rect.width)
198
- height.jump(rect.height)
199
- return
200
- }
201
- const goo = lead.current && travels(current, rect) ? blurOf(lead.current, current) : 0
202
- // Square shapes have no radius to melt with.
203
- if (goo >= 1) {
204
- setBlur(goo)
205
- setTrails(list => [...list, { id: ++ids.current, from: current, to: retract(current, rect) }])
206
- }
207
- animate(x, rect.left, move)
208
- animate(y, rect.top, move)
209
- animate(width, rect.width, move)
210
- animate(height, rect.height, move)
211
- }, [rect.left, rect.top, rect.width, rect.height])
212
-
213
- const melting = trails.length > 0
214
- const linger = travel ? { ...travel, delay: (travel.duration ?? 0) / 3 } : undefined
215
- const shape = cn('pointer-events-none absolute top-0 left-0', className)
216
- const box = trails.reduce<ItemRect>((all, trail) => union(all, trail.from), union(read(), rect))
217
- const drop = (trail: Trail) => setTrails(list => list.filter(t => t.id !== trail.id))
218
-
219
- return (
220
- <motion.div
221
- aria-hidden
222
- className="pointer-events-none absolute top-0 left-0"
223
- initial={false}
224
- animate={{ opacity }}
225
- transition={{ duration: spring.fast.duration }}
226
- >
227
- {shadow && (
228
- <>
229
- {/* Fading as it shrinks: the goo lets a sliver vanish, a crisp shadow would not. */}
230
- {trails.map(trail => (
231
- <motion.div
232
- key={trail.id}
233
- className={cn(shape, shadow)}
234
- initial={{ ...toTarget(trail.from), opacity: 1 }}
235
- animate={{ ...toTarget(trail.to), opacity: 0 }}
236
- transition={linger}
237
- />
238
- ))}
239
- <motion.div className={cn(shape, shadow, !melting && 'invisible')} style={{ x, y, width, height }} />
240
- </>
241
- )}
242
- <GooLayer active={melting} blur={blur} box={box} fill={className ?? ''}>
243
- {trails.map(trail => (
244
- <motion.div
245
- key={trail.id}
246
- className={shape}
247
- initial={toTarget(trail.from)}
248
- animate={toTarget(trail.to)}
249
- transition={linger}
250
- onAnimationComplete={() => drop(trail)}
251
- />
252
- ))}
253
- {/* At rest it wears its own shadow; melting, a shadow would count as coverage and swell the goo. */}
254
- <motion.div ref={lead} className={cn(shape, !melting && shadow)} style={{ x, y, width, height }} />
255
- </GooLayer>
256
- </motion.div>
257
- )
258
- }
259
-
260
- export type { GooIndicatorProps, GooLayerProps }
261
- export { union }