@justanarthur/modo-ui 0.5.0 → 0.6.0-canary.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 (461) hide show
  1. package/DESIGN.md +608 -0
  2. package/README.md +61 -39
  3. package/blocks/sidebar-app/examples.mdx +33 -0
  4. package/blocks/sidebar-app/index.tsx +218 -0
  5. package/blocks/sidebar-app/inset-topbar.tsx +25 -0
  6. package/blocks/sidebar-app/menu-grid.ts +26 -0
  7. package/blocks/sidebar-app/nav-data.ts +36 -0
  8. package/blocks/sidebar-app/search-field.tsx +48 -0
  9. package/blocks/sidebar-app/user-footer.tsx +67 -0
  10. package/blocks/sidebar-app/workspace-header.tsx +129 -0
  11. package/components/AI/input-message/examples.mdx +124 -0
  12. package/components/AI/input-message/file-thumbnail.tsx +173 -0
  13. package/components/AI/input-message/index.tsx +1383 -0
  14. package/components/AI/thinking-indicator/examples.mdx +27 -0
  15. package/components/AI/thinking-indicator/index.tsx +210 -0
  16. package/components/accordion/examples.mdx +148 -0
  17. package/components/accordion/index.tsx +1034 -0
  18. package/components/avatar/examples.mdx +95 -0
  19. package/components/avatar/index.tsx +129 -0
  20. package/components/badge/change-demo.tsx +29 -0
  21. package/components/badge/examples.mdx +120 -0
  22. package/components/badge/index.tsx +225 -0
  23. package/components/badge/variants.ts +73 -0
  24. package/components/button/examples.mdx +164 -0
  25. package/components/button/index.tsx +416 -0
  26. package/components/button/loading-demo.tsx +25 -0
  27. package/components/button/variants.ts +166 -0
  28. package/components/card/examples.mdx +212 -0
  29. package/components/card/index.tsx +1037 -0
  30. package/components/copy/examples.mdx +87 -0
  31. package/components/copy/index.tsx +482 -0
  32. package/components/inputs/checkbox/examples.mdx +83 -0
  33. package/components/inputs/checkbox/index.tsx +611 -0
  34. package/components/inputs/checkbox/select-all-demo.tsx +48 -0
  35. package/components/inputs/color-picker/examples.mdx +72 -0
  36. package/components/inputs/color-picker/index.tsx +1955 -0
  37. package/components/inputs/color-picker/variants.ts +401 -0
  38. package/components/inputs/combobox/examples.mdx +273 -0
  39. package/components/inputs/combobox/index.tsx +1436 -0
  40. package/components/inputs/combobox/remote-demo.tsx +101 -0
  41. package/components/inputs/date-time/calendar/examples.mdx +34 -0
  42. package/components/inputs/date-time/calendar/index.tsx +351 -0
  43. package/components/inputs/date-time/calendar/use-month-window.ts +163 -0
  44. package/components/inputs/date-time/date-picker/examples.mdx +166 -0
  45. package/components/inputs/date-time/date-picker/index.tsx +385 -0
  46. package/components/inputs/date-time/date-picker/masked-date-input.tsx +336 -0
  47. package/components/inputs/date-time/date-range-picker/examples.mdx +29 -0
  48. package/components/inputs/date-time/date-range-picker/index.tsx +217 -0
  49. package/components/inputs/date-time/duration-picker/examples.mdx +16 -0
  50. package/components/inputs/date-time/duration-picker/index.tsx +189 -0
  51. package/components/inputs/date-time/month-picker/examples.mdx +16 -0
  52. package/components/inputs/date-time/month-picker/index.tsx +190 -0
  53. package/components/inputs/date-time/picker-shell.tsx +395 -0
  54. package/components/inputs/date-time/time-columns.tsx +91 -0
  55. package/components/inputs/date-time/time-picker/examples.mdx +26 -0
  56. package/components/inputs/date-time/time-picker/index.tsx +166 -0
  57. package/components/inputs/field/examples.mdx +113 -0
  58. package/components/inputs/field/index.tsx +267 -0
  59. package/components/inputs/file-dropzone/examples.mdx +73 -0
  60. package/components/inputs/file-dropzone/file-row.tsx +201 -0
  61. package/components/inputs/file-dropzone/index.tsx +296 -0
  62. package/components/inputs/file-dropzone/upload-demo.tsx +67 -0
  63. package/components/inputs/file-dropzone/variants.ts +94 -0
  64. package/components/inputs/input/examples.mdx +135 -0
  65. package/components/inputs/input/index.tsx +494 -0
  66. package/components/inputs/input/password-demo.tsx +30 -0
  67. package/components/inputs/label/examples.mdx +67 -0
  68. package/components/inputs/label/index.tsx +85 -0
  69. package/components/inputs/number-input/examples.mdx +56 -0
  70. package/components/inputs/number-input/index.tsx +214 -0
  71. package/components/inputs/radio/examples.mdx +77 -0
  72. package/components/inputs/radio/index.tsx +636 -0
  73. package/components/inputs/search/examples.mdx +74 -0
  74. package/components/inputs/search/index.tsx +333 -0
  75. package/components/inputs/select/examples.mdx +218 -0
  76. package/components/inputs/select/index.tsx +862 -0
  77. package/components/inputs/select/variants.ts +32 -0
  78. package/components/inputs/slider/examples.mdx +127 -0
  79. package/components/inputs/slider/index.tsx +1725 -0
  80. package/components/inputs/switch/examples.mdx +94 -0
  81. package/components/inputs/switch/index.tsx +504 -0
  82. package/components/inputs/textarea/examples.mdx +88 -0
  83. package/components/inputs/textarea/index.tsx +161 -0
  84. package/components/navigation/navigation-menu/examples.mdx +109 -0
  85. package/components/navigation/navigation-menu/index.tsx +613 -0
  86. package/components/navigation/pagination/examples.mdx +64 -0
  87. package/components/navigation/pagination/index.tsx +395 -0
  88. package/components/navigation/sidebar/examples.mdx +319 -0
  89. package/components/navigation/sidebar/index.tsx +453 -0
  90. package/components/navigation/sidebar/sidebar-core.tsx +1408 -0
  91. package/components/navigation/sidebar/sidebar-menu.tsx +1495 -0
  92. package/components/navigation/sidebar/sidebar.css +74 -0
  93. package/components/navigation/sidebar/variants.ts +55 -0
  94. package/components/navigation/tabs/examples.mdx +89 -0
  95. package/components/navigation/tabs/index.tsx +494 -0
  96. package/components/navigation/tabs-subtle/examples.mdx +49 -0
  97. package/components/navigation/tabs-subtle/index.tsx +512 -0
  98. package/components/overlays/alert-dialog/examples.mdx +123 -0
  99. package/components/overlays/alert-dialog/index.tsx +258 -0
  100. package/components/overlays/alert-dialog/pending-demo.tsx +36 -0
  101. package/components/overlays/command/examples.mdx +113 -0
  102. package/components/overlays/command/index.tsx +416 -0
  103. package/components/overlays/context-menu/examples.mdx +56 -0
  104. package/components/overlays/context-menu/index.tsx +279 -0
  105. package/components/overlays/dialog/examples.mdx +144 -0
  106. package/components/overlays/dialog/index.tsx +366 -0
  107. package/components/overlays/dropdown/dropdown-search.tsx +395 -0
  108. package/components/overlays/dropdown/examples.mdx +294 -0
  109. package/components/overlays/dropdown/index.tsx +1168 -0
  110. package/components/overlays/dropdown/menu-item.tsx +464 -0
  111. package/components/overlays/dropdown/menu-parts.tsx +660 -0
  112. package/components/overlays/popover/anchored-demo.tsx +59 -0
  113. package/components/overlays/popover/examples.mdx +180 -0
  114. package/components/overlays/popover/index.tsx +315 -0
  115. package/components/overlays/preview-card/examples.mdx +61 -0
  116. package/components/overlays/preview-card/index.tsx +204 -0
  117. package/components/overlays/sheet/examples.mdx +89 -0
  118. package/components/overlays/sheet/index.tsx +247 -0
  119. package/components/overlays/toast/examples.mdx +68 -0
  120. package/components/overlays/toast/global-demo.tsx +72 -0
  121. package/components/overlays/toast/index.tsx +474 -0
  122. package/components/overlays/toast/manager.ts +193 -0
  123. package/components/overlays/tooltip/examples.mdx +106 -0
  124. package/components/overlays/tooltip/index.tsx +519 -0
  125. package/components/progress/examples.mdx +59 -0
  126. package/components/progress/index.tsx +174 -0
  127. package/components/progress/progress.css +49 -0
  128. package/components/progress/step-demo.tsx +27 -0
  129. package/components/table/examples.mdx +184 -0
  130. package/components/table/index.tsx +510 -0
  131. package/components/table/sort-demo.tsx +61 -0
  132. package/dist/base.css +100 -0
  133. package/dist/blocks/sidebar-app/index.js +39 -26
  134. package/dist/components/AI/input-message/index.js +22 -16
  135. package/dist/components/AI/thinking-indicator/index.js +9 -6
  136. package/dist/components/accordion/index.js +16 -13
  137. package/dist/components/avatar/index.d.ts +46 -0
  138. package/dist/components/avatar/index.js +18 -0
  139. package/dist/components/badge/index.d.ts +18 -11
  140. package/dist/components/badge/index.js +11 -7
  141. package/dist/components/badge/variants.d.ts +33 -0
  142. package/dist/components/badge/variants.js +10 -0
  143. package/dist/components/button/index.d.ts +53 -17
  144. package/dist/components/button/index.js +10 -6
  145. package/dist/components/button/variants.d.ts +39 -0
  146. package/dist/components/button/variants.js +8 -0
  147. package/dist/components/card/index.d.ts +16 -3
  148. package/dist/components/card/index.js +16 -11
  149. package/dist/components/copy/index.js +13 -9
  150. package/dist/components/inputs/checkbox/index.d.ts +28 -9
  151. package/dist/components/inputs/checkbox/index.js +17 -13
  152. package/dist/components/inputs/color-picker/index.d.ts +13 -13
  153. package/dist/components/inputs/color-picker/index.js +25 -18
  154. package/dist/components/inputs/color-picker/variants.d.ts +61 -0
  155. package/dist/components/inputs/color-picker/variants.js +28 -0
  156. package/dist/components/inputs/combobox/index.d.ts +60 -17
  157. package/dist/components/inputs/combobox/index.js +26 -18
  158. package/dist/components/inputs/date-time/calendar/index.js +14 -11
  159. package/dist/components/inputs/date-time/date-picker/index.d.ts +53 -11
  160. package/dist/components/inputs/date-time/date-picker/index.js +33 -25
  161. package/dist/components/inputs/date-time/date-range-picker/index.d.ts +3 -3
  162. package/dist/components/inputs/date-time/date-range-picker/index.js +32 -24
  163. package/dist/components/inputs/date-time/duration-picker/index.d.ts +3 -3
  164. package/dist/components/inputs/date-time/duration-picker/index.js +32 -24
  165. package/dist/components/inputs/date-time/month-picker/index.d.ts +3 -3
  166. package/dist/components/inputs/date-time/month-picker/index.js +31 -23
  167. package/dist/components/inputs/date-time/time-picker/index.d.ts +3 -3
  168. package/dist/components/inputs/date-time/time-picker/index.js +32 -24
  169. package/dist/components/inputs/field/index.d.ts +116 -0
  170. package/dist/components/inputs/field/index.js +28 -0
  171. package/dist/components/inputs/file-dropzone/index.d.ts +165 -0
  172. package/dist/components/inputs/file-dropzone/index.js +32 -0
  173. package/dist/components/inputs/file-dropzone/variants.d.ts +35 -0
  174. package/dist/components/inputs/file-dropzone/variants.js +12 -0
  175. package/dist/components/inputs/input/index.d.ts +95 -13
  176. package/dist/components/inputs/input/index.js +17 -9
  177. package/dist/components/inputs/label/index.d.ts +32 -0
  178. package/dist/components/inputs/label/index.js +11 -0
  179. package/dist/components/inputs/number-input/index.d.ts +84 -0
  180. package/dist/components/inputs/number-input/index.js +20 -0
  181. package/dist/components/inputs/radio/index.d.ts +20 -5
  182. package/dist/components/inputs/radio/index.js +15 -12
  183. package/dist/components/inputs/search/index.js +25 -18
  184. package/dist/components/inputs/select/index.d.ts +41 -11
  185. package/dist/components/inputs/select/index.js +27 -14
  186. package/dist/components/inputs/select/variants.d.ts +5 -0
  187. package/dist/components/inputs/select/variants.js +6 -0
  188. package/dist/components/inputs/slider/index.js +7 -5
  189. package/dist/components/inputs/switch/index.d.ts +8 -2
  190. package/dist/components/inputs/switch/index.js +14 -12
  191. package/dist/components/inputs/textarea/index.d.ts +4 -0
  192. package/dist/components/inputs/textarea/index.js +8 -6
  193. package/dist/components/navigation/navigation-menu/index.d.ts +114 -0
  194. package/dist/components/navigation/navigation-menu/index.js +40 -0
  195. package/dist/components/navigation/pagination/index.d.ts +73 -0
  196. package/dist/components/navigation/pagination/index.js +39 -0
  197. package/dist/components/navigation/sidebar/index.d.ts +44 -21
  198. package/dist/components/navigation/sidebar/index.js +41 -31
  199. package/dist/components/navigation/sidebar/variants.d.ts +25 -0
  200. package/dist/components/navigation/sidebar/variants.js +28 -0
  201. package/dist/components/navigation/tabs/index.d.ts +8 -2
  202. package/dist/components/navigation/tabs/index.js +14 -10
  203. package/dist/components/navigation/tabs-subtle/index.js +12 -10
  204. package/dist/components/overlays/alert-dialog/index.d.ts +121 -15
  205. package/dist/components/overlays/alert-dialog/index.js +22 -13
  206. package/dist/components/overlays/command/index.js +24 -17
  207. package/dist/components/overlays/context-menu/index.d.ts +33 -17
  208. package/dist/components/overlays/context-menu/index.js +27 -18
  209. package/dist/components/overlays/dialog/index.js +17 -12
  210. package/dist/components/overlays/dropdown/index.d.ts +257 -31
  211. package/dist/components/overlays/dropdown/index.js +42 -17
  212. package/dist/components/overlays/popover/index.d.ts +31 -9
  213. package/dist/components/overlays/popover/index.js +12 -9
  214. package/dist/components/overlays/preview-card/index.js +11 -8
  215. package/dist/components/overlays/sheet/index.js +18 -13
  216. package/dist/components/overlays/toast/index.d.ts +123 -47
  217. package/dist/components/overlays/toast/index.js +18 -10
  218. package/dist/components/overlays/tooltip/index.d.ts +113 -21
  219. package/dist/components/overlays/tooltip/index.js +15 -6
  220. package/dist/components/progress/index.d.ts +56 -0
  221. package/dist/components/progress/index.js +15 -0
  222. package/dist/components/table/index.d.ts +63 -8
  223. package/dist/components/table/index.js +19 -9
  224. package/dist/index.d.ts +2201 -736
  225. package/dist/index.js +223 -82
  226. package/dist/lib/date-locale.d.ts +14 -0
  227. package/dist/lib/date-locale.js +16 -0
  228. package/dist/lib/field-classes.d.ts +144 -0
  229. package/dist/lib/field-classes.js +40 -0
  230. package/dist/lib/field-variants.d.ts +47 -0
  231. package/dist/lib/field-variants.js +26 -0
  232. package/dist/lib/fluid-hover-highlight.d.ts +112 -0
  233. package/dist/lib/fluid-hover-highlight.js +17 -0
  234. package/dist/lib/focus-ring.d.ts +18 -0
  235. package/dist/lib/focus-ring.js +10 -0
  236. package/dist/lib/goo-indicator.d.ts +46 -0
  237. package/dist/lib/goo-indicator.js +14 -0
  238. package/dist/lib/icon-context.d.ts +30 -0
  239. package/dist/lib/icon-context.js +12 -0
  240. package/dist/lib/inert.d.ts +9 -0
  241. package/dist/lib/inert.js +8 -0
  242. package/dist/lib/morph-layers.d.ts +93 -0
  243. package/dist/lib/morph-layers.js +13 -0
  244. package/dist/lib/morph-part.d.ts +21 -0
  245. package/dist/lib/morph-part.js +12 -0
  246. package/dist/lib/popup.d.ts +20 -0
  247. package/dist/lib/popup.js +12 -0
  248. package/dist/lib/reduced-motion.d.ts +9 -0
  249. package/dist/lib/reduced-motion.js +6 -0
  250. package/dist/lib/row-index.d.ts +10 -0
  251. package/dist/lib/row-index.js +8 -0
  252. package/dist/lib/row-order.d.ts +28 -0
  253. package/dist/lib/row-order.js +10 -0
  254. package/dist/lib/scroll-column.d.ts +27 -0
  255. package/dist/lib/scroll-column.js +18 -0
  256. package/dist/lib/shape-context.d.ts +30 -0
  257. package/dist/lib/shape-context.js +12 -0
  258. package/dist/lib/size-context.d.ts +94 -0
  259. package/dist/lib/size-context.js +20 -0
  260. package/dist/lib/size-scale.d.ts +79 -0
  261. package/dist/lib/size-scale.js +8 -0
  262. package/dist/lib/slot.d.ts +12 -0
  263. package/dist/lib/slot.js +6 -0
  264. package/dist/lib/springs.d.ts +44 -0
  265. package/dist/lib/springs.js +8 -0
  266. package/dist/lib/surface-classes.d.ts +19 -0
  267. package/dist/lib/surface-classes.js +10 -0
  268. package/dist/lib/surface-context.d.ts +9 -0
  269. package/dist/lib/surface-context.js +8 -0
  270. package/dist/lib/use-controllable-state.d.ts +2 -0
  271. package/dist/lib/use-controllable-state.js +6 -0
  272. package/dist/lib/use-fluid-hover.d.ts +138 -0
  273. package/dist/lib/use-fluid-hover.js +14 -0
  274. package/dist/lib/use-is-mobile.d.ts +2 -0
  275. package/dist/lib/use-is-mobile.js +6 -0
  276. package/dist/lib/use-keyboard-nav-gate.d.ts +20 -0
  277. package/dist/lib/use-keyboard-nav-gate.js +7 -0
  278. package/dist/lib/use-merge-split.d.ts +47 -0
  279. package/dist/lib/use-merge-split.js +15 -0
  280. package/dist/lib/use-morph.d.ts +101 -0
  281. package/dist/lib/use-morph.js +20 -0
  282. package/dist/lib/use-touch-primary.d.ts +2 -0
  283. package/dist/lib/use-touch-primary.js +6 -0
  284. package/dist/lib/utils.d.ts +3 -0
  285. package/dist/lib/utils.js +6 -0
  286. package/dist/preset.d.ts +17 -0
  287. package/dist/preset.js +22 -2
  288. package/dist/primitives/code/index.js +7 -5
  289. package/dist/primitives/craft/index.js +9 -6
  290. package/dist/primitives/fluid-hover/index.js +9 -8
  291. package/dist/primitives/morph/index.js +15 -10
  292. package/dist/primitives/motion/index.js +10 -8
  293. package/dist/primitives/scroll-area/index.js +4 -3
  294. package/dist/primitives/separator/index.d.ts +25 -0
  295. package/dist/primitives/separator/index.js +9 -0
  296. package/dist/primitives/sizes/index.js +6 -4
  297. package/dist/primitives/skeleton/index.d.ts +35 -0
  298. package/dist/primitives/skeleton/index.js +12 -0
  299. package/dist/primitives/surface/index.js +6 -4
  300. package/dist/shared/{components-3mkepka5.js → components-0jmqhx2k.js} +28 -25
  301. package/dist/shared/components-124epb7f.js +53 -0
  302. package/dist/shared/{components-gz8zf3ec.js → components-1k0wv53d.js} +15 -43
  303. package/dist/shared/components-26snnbs9.js +322 -0
  304. package/dist/shared/{components-2dxkv6zm.js → components-2c0qcfx4.js} +8 -7
  305. package/dist/shared/{components-473g814w.js → components-2mt9te6d.js} +243 -137
  306. package/dist/shared/{components-hawvy2qz.js → components-2z48g4fp.js} +9 -30
  307. package/dist/shared/components-34txk9rj.js +35 -0
  308. package/dist/shared/components-3h92d94m.js +23 -0
  309. package/dist/shared/{components-zfnmn5d4.js → components-3sp623ae.js} +36 -31
  310. package/dist/shared/{components-jwst3vtj.js → components-3wxkjgqn.js} +186 -76
  311. package/dist/shared/{components-s2bz1xpk.js → components-49bsynbw.js} +8 -5
  312. package/dist/shared/components-4bwsd46w.js +71 -0
  313. package/dist/shared/components-4n4f5m3e.js +297 -0
  314. package/dist/shared/{components-0q0sqfh4.js → components-4y816hwp.js} +27 -49
  315. package/dist/shared/components-52ngsgca.js +399 -0
  316. package/dist/shared/{components-y9y0g8er.js → components-52r5763g.js} +22 -19
  317. package/dist/shared/components-559tf7yb.js +28 -0
  318. package/dist/shared/components-5mkga9hj.js +440 -0
  319. package/dist/shared/{components-kwa6mrf9.js → components-5s0nfqvw.js} +14 -9
  320. package/dist/shared/{components-dk0gjr5a.js → components-60atskhp.js} +19 -18
  321. package/dist/shared/{components-rr7a6ja9.js → components-658b26nb.js} +21 -18
  322. package/dist/shared/{components-xxvdw7k1.js → components-65vwfjs6.js} +37 -34
  323. package/dist/shared/{components-frw34b65.js → components-6j2fh74k.js} +114 -123
  324. package/dist/shared/components-6zg1yft7.js +167 -0
  325. package/dist/shared/components-6zng858q.js +53 -0
  326. package/dist/shared/components-72w4ge68.js +64 -0
  327. package/dist/shared/{components-cv16mryv.js → components-78x40gee.js} +13 -7
  328. package/dist/shared/{components-b2wyq2cq.js → components-7d4r7hh1.js} +39 -57
  329. package/dist/shared/components-7ntvvegr.js +316 -0
  330. package/dist/shared/components-8nwsqjn8.js +34 -0
  331. package/dist/shared/{components-5xc2j8jz.js → components-8tt3xbb5.js} +19 -18
  332. package/dist/shared/{components-vc7vq5nz.js → components-9as3rf68.js} +6 -3
  333. package/dist/shared/components-9mys9jna.js +255 -0
  334. package/dist/shared/components-adkarj8n.js +35 -0
  335. package/dist/shared/{components-b3c5et5b.js → components-ae9fncz4.js} +32 -31
  336. package/dist/shared/{components-hqeq3w9q.js → components-awra5sff.js} +24 -16
  337. package/dist/shared/components-b1e239g3.js +28 -0
  338. package/dist/shared/{components-q5xj5c16.js → components-b1f2bjf1.js} +9 -8
  339. package/dist/shared/{components-qmmjx1qw.js → components-bn42vq6d.js} +71 -72
  340. package/dist/shared/components-c96g82th.js +1444 -0
  341. package/dist/shared/components-c9yr4ed1.js +44 -0
  342. package/dist/shared/components-d3shbwqq.js +95 -0
  343. package/dist/shared/{components-jjw69c4c.js → components-dcc02hs2.js} +7 -4
  344. package/dist/shared/{components-men63rwj.js → components-de99ykt7.js} +3 -2
  345. package/dist/shared/components-dhgk6mbt.js +16 -0
  346. package/dist/shared/components-drxrtnp2.js +25 -0
  347. package/dist/shared/{components-6p8tfcd6.js → components-ds9fqat9.js} +21 -18
  348. package/dist/shared/{components-mjthm1kf.js → components-egy4tyjt.js} +11 -8
  349. package/dist/shared/components-f0xfpkhh.js +82 -0
  350. package/dist/shared/components-f7h57m6t.js +59 -0
  351. package/dist/shared/{components-d6xtjht3.js → components-fjkpbg6n.js} +33 -30
  352. package/dist/shared/{components-gc5vtq2f.js → components-gh0qeey3.js} +63 -29
  353. package/dist/shared/{components-39jq9va1.js → components-gvbapfen.js} +29 -24
  354. package/dist/shared/{components-5vgpnxgy.js → components-gzesg7hy.js} +19 -16
  355. package/dist/shared/components-h6p86be3.js +19 -0
  356. package/dist/shared/components-h83az0bz.js +33 -0
  357. package/dist/shared/components-jjrj6ymn.js +104 -0
  358. package/dist/shared/{components-wvp1m52g.js → components-jp5v0m0f.js} +15 -14
  359. package/dist/shared/{components-zrkzcayz.js → components-jqpefjsn.js} +54 -6
  360. package/dist/shared/{components-1z6tdadk.js → components-k74j4hwh.js} +20 -17
  361. package/dist/shared/components-kswxnm3h.js +24 -0
  362. package/dist/shared/{components-jbbmdr74.js → components-mkkbbgb7.js} +36 -17
  363. package/dist/shared/{components-pbmqctfa.js → components-mpw667rb.js} +169 -65
  364. package/dist/shared/{components-s5ngg32c.js → components-paa08427.js} +121 -47
  365. package/dist/shared/{components-vfbhxf5r.js → components-pd42emw3.js} +6 -5
  366. package/dist/shared/{components-hw9yk32z.js → components-pmfszv7a.js} +35 -23
  367. package/dist/shared/{components-chacnk61.js → components-pw06rbxq.js} +19 -19
  368. package/dist/shared/components-q03cktx8.js +246 -0
  369. package/dist/shared/{components-kvr7f9hy.js → components-qdm3yh26.js} +19 -10
  370. package/dist/shared/{components-27nnvrwe.js → components-qs4rkqsj.js} +15 -14
  371. package/dist/shared/{components-s083f38z.js → components-r6gbmkew.js} +22 -21
  372. package/dist/shared/{components-ta7shw28.js → components-r8eqs7gz.js} +4 -4
  373. package/dist/shared/{components-sn1rxx1d.js → components-rm02h9nt.js} +12 -11
  374. package/dist/shared/{components-c6s6b43g.js → components-rrbpmfx4.js} +3 -2
  375. package/dist/shared/{components-n7mjr357.js → components-tz1fv35x.js} +3 -2
  376. package/dist/shared/components-tz4gaf1v.js +23 -0
  377. package/dist/shared/{components-zx6b6yby.js → components-vf45j12c.js} +4 -18
  378. package/dist/shared/{components-3ky44908.js → components-vfjc9jzz.js} +2 -3
  379. package/dist/shared/{components-39vmfq9s.js → components-vsa625vk.js} +21 -20
  380. package/dist/shared/components-wawnmkph.js +500 -0
  381. package/dist/shared/components-wktrrb4m.js +38 -0
  382. package/dist/shared/{components-8snj490h.js → components-wwd363me.js} +78 -32
  383. package/dist/shared/{components-5pnw8183.js → components-xcwvgcrd.js} +23 -22
  384. package/dist/shared/components-xdqmt6ed.js +20 -0
  385. package/dist/shared/{components-h2ajmhwn.js → components-y1w3a6wx.js} +107 -35
  386. package/dist/shared/{components-ar66gnt0.js → components-y6578b8h.js} +37 -34
  387. package/dist/shared/{components-59efxjd9.js → components-yhgq0qxx.js} +13 -12
  388. package/dist/shared/{components-jthe1pwb.js → components-yz84gpkq.js} +101 -404
  389. package/dist/shared/components-z3v0n0de.js +11 -0
  390. package/dist/shared/{components-7r3etddy.js → components-z9n19fyk.js} +19 -54
  391. package/dist/shared/components-zbvjzh1p.js +141 -0
  392. package/dist/styles.css +241 -16
  393. package/dist/tailwind.css +13 -0
  394. package/dist/tokens.css +34 -0
  395. package/index.ts +60 -0
  396. package/lib/date-locale.ts +50 -0
  397. package/lib/field-classes.ts +115 -0
  398. package/lib/field-variants.ts +117 -0
  399. package/lib/fluid-hover-highlight.tsx +139 -0
  400. package/lib/focus-ring.tsx +46 -0
  401. package/lib/goo-indicator.tsx +261 -0
  402. package/lib/icon-context.tsx +310 -0
  403. package/lib/inert.ts +22 -0
  404. package/lib/morph-layers.tsx +102 -0
  405. package/lib/morph-part.tsx +49 -0
  406. package/lib/popup.ts +52 -0
  407. package/lib/reduced-motion.ts +19 -0
  408. package/lib/row-index.tsx +29 -0
  409. package/lib/row-order.tsx +115 -0
  410. package/lib/scroll-column.tsx +244 -0
  411. package/lib/shape-context.tsx +124 -0
  412. package/lib/size-context.tsx +66 -0
  413. package/lib/size-scale.ts +115 -0
  414. package/lib/slot.ts +25 -0
  415. package/lib/springs.ts +62 -0
  416. package/lib/surface-classes.ts +58 -0
  417. package/lib/surface-context.tsx +21 -0
  418. package/lib/use-controllable-state.ts +44 -0
  419. package/lib/use-fluid-hover.ts +541 -0
  420. package/lib/use-is-mobile.ts +25 -0
  421. package/lib/use-keyboard-nav-gate.ts +45 -0
  422. package/lib/use-merge-split.tsx +209 -0
  423. package/lib/use-morph.ts +557 -0
  424. package/lib/use-touch-primary.tsx +43 -0
  425. package/lib/utils.ts +37 -0
  426. package/package.json +177 -4
  427. package/preset.ts +196 -0
  428. package/primitives/code/examples.mdx +27 -0
  429. package/primitives/code/index.tsx +80 -0
  430. package/primitives/craft/demos.tsx +173 -0
  431. package/primitives/craft/examples.mdx +138 -0
  432. package/primitives/craft/index.tsx +76 -0
  433. package/primitives/fluid-hover/examples.mdx +84 -0
  434. package/primitives/fluid-hover/index.tsx +316 -0
  435. package/primitives/morph/examples.mdx +135 -0
  436. package/primitives/morph/index.tsx +192 -0
  437. package/primitives/motion/examples.mdx +100 -0
  438. package/primitives/motion/index.tsx +160 -0
  439. package/primitives/scroll-area/examples.mdx +58 -0
  440. package/primitives/scroll-area/index.tsx +200 -0
  441. package/primitives/separator/examples.mdx +30 -0
  442. package/primitives/separator/index.tsx +53 -0
  443. package/primitives/sizes/examples.mdx +167 -0
  444. package/primitives/sizes/index.tsx +89 -0
  445. package/primitives/skeleton/examples.mdx +51 -0
  446. package/primitives/skeleton/index.tsx +72 -0
  447. package/primitives/skeleton/skeleton.css +15 -0
  448. package/primitives/surface/examples.mdx +173 -0
  449. package/primitives/surface/index.tsx +109 -0
  450. package/primitives/surface/surface.css +176 -0
  451. package/dist/shared/components-0sn7ypjw.js +0 -61
  452. package/dist/shared/components-1434p1mh.js +0 -123
  453. package/dist/shared/components-a86dytt0.js +0 -986
  454. package/dist/shared/components-gf5s6ap9.js +0 -42
  455. package/dist/shared/components-hyq23phv.js +0 -310
  456. package/dist/shared/components-ng72k97e.js +0 -128
  457. package/dist/shared/components-raknhppb.js +0 -64
  458. package/dist/shared/components-vynjtrk6.js +0 -19
  459. package/dist/shared/components-wy9jpqny.js +0 -146
  460. /package/dist/shared/{components-1v7rxytx.js → components-3ey0hzpb.js} +0 -0
  461. /package/dist/shared/{components-ezxhrmer.js → components-jcnjay5g.js} +0 -0
@@ -0,0 +1,261 @@
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 }
@@ -0,0 +1,310 @@
1
+ /*
2
+ * Vendored from Fluid Functionalism — `registry/default/lib/icon-context.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
+ * - lucide-react v1 + React 18 types: `IconComponentProps.size` /
10
+ * `strokeWidth` widened to `number | string` (lucide icons' propTypes
11
+ * accept both, and @types/react 18 compares propTypes).
12
+ * - `panel-left-dashed` / `panel-right-dashed`: the sidebar trigger's glyph
13
+ * while the sidebar opens on hover.
14
+ * - Names for the @utegsk/ui layer (pagination, sorting, status, password
15
+ * reveal, file dropzone, indeterminate): `chevron-left`, `chevron-up`, `chevrons-left`, `chevrons-right`, `arrow-up-down`, `circle-alert`, `triangle-alert`, `circle-check`, `info`, `circle-question-mark`, `trash`, `eye`, `eye-off`, `timer`, `arrow-right-from-line`, `arrow-right-to-line`, `funnel-x`, `flag`, `loader-circle`, `minus`, `upload`, `file`.
16
+ */
17
+
18
+ import {
19
+ ArrowDown,
20
+ ArrowLeft,
21
+ ArrowRight,
22
+ ArrowRightFromLine,
23
+ ArrowRightToLine,
24
+ ArrowUp,
25
+ ArrowUpDown,
26
+ Bell,
27
+ Brain,
28
+ Calendar,
29
+ Check,
30
+ ChevronDown,
31
+ ChevronLeft,
32
+ ChevronRight,
33
+ ChevronsLeft,
34
+ ChevronsRight,
35
+ ChevronsUpDown,
36
+ ChevronUp,
37
+ Circle,
38
+ CircleAlert,
39
+ CircleCheck,
40
+ CircleQuestionMark,
41
+ Clock,
42
+ Copy,
43
+ CornerDownLeft,
44
+ CornerDownRight,
45
+ Dot,
46
+ Ellipsis,
47
+ EllipsisVertical,
48
+ Eye,
49
+ EyeOff,
50
+ File,
51
+ Flag,
52
+ Folder,
53
+ FunnelX,
54
+ Globe,
55
+ Heart,
56
+ Home,
57
+ ImageIcon,
58
+ Inbox,
59
+ Info,
60
+ Lightbulb,
61
+ Link,
62
+ Loader,
63
+ LoaderCircle,
64
+ Lock,
65
+ Mail,
66
+ Menu,
67
+ MessageCircle,
68
+ Minus,
69
+ Monitor,
70
+ Moon,
71
+ Paintbrush,
72
+ Palette,
73
+ PanelLeft,
74
+ PanelLeftDashed,
75
+ PanelRight,
76
+ PanelRightDashed,
77
+ Pause,
78
+ Pencil,
79
+ Pipette,
80
+ Play,
81
+ Plus,
82
+ RectangleHorizontal,
83
+ Rocket,
84
+ RotateCcw,
85
+ Scaling,
86
+ Search,
87
+ Settings,
88
+ Shield,
89
+ SkipForward,
90
+ SlidersHorizontal,
91
+ SquareLibrary,
92
+ Star,
93
+ Sun,
94
+ Timer,
95
+ Trash2,
96
+ TriangleAlert,
97
+ Upload,
98
+ User,
99
+ Users,
100
+ X,
101
+ } from 'lucide-react'
102
+ import { type ComponentType, createContext, type ReactNode, useContext, useMemo } from 'react'
103
+
104
+ export interface IconComponentProps {
105
+ size?: number | string
106
+ strokeWidth?: number | string
107
+ className?: string
108
+ }
109
+
110
+ export type IconComponent = ComponentType<IconComponentProps>
111
+
112
+ export type IconName =
113
+ | 'chevron-right'
114
+ | 'chevron-down'
115
+ | 'x'
116
+ | 'copy'
117
+ | 'menu'
118
+ | 'dot'
119
+ | 'monitor'
120
+ | 'sun'
121
+ | 'moon'
122
+ | 'rectangle-horizontal'
123
+ | 'circle'
124
+ | 'square-library'
125
+ | 'clock'
126
+ | 'star'
127
+ | 'settings'
128
+ | 'plus'
129
+ | 'arrow-left'
130
+ | 'arrow-right'
131
+ | 'arrow-up'
132
+ | 'arrow-down'
133
+ | 'search'
134
+ | 'loader'
135
+ | 'users'
136
+ | 'lock'
137
+ | 'mail'
138
+ | 'bell'
139
+ | 'shield'
140
+ | 'palette'
141
+ | 'lightbulb'
142
+ | 'rocket'
143
+ | 'heart'
144
+ | 'paintbrush'
145
+ | 'brain'
146
+ | 'globe'
147
+ | 'user'
148
+ | 'image'
149
+ | 'link'
150
+ | 'check'
151
+ | 'rotate-ccw'
152
+ | 'play'
153
+ | 'pause'
154
+ | 'pipette'
155
+ | 'home'
156
+ | 'message-circle'
157
+ | 'inbox'
158
+ | 'pencil'
159
+ | 'scaling'
160
+ | 'skip-forward'
161
+ | 'corner-down-right'
162
+ | 'corner-down-left'
163
+ | 'panel-left'
164
+ | 'panel-left-dashed'
165
+ | 'panel-right'
166
+ | 'panel-right-dashed'
167
+ | 'chevrons-up-down'
168
+ | 'more-horizontal'
169
+ | 'more-vertical'
170
+ | 'calendar'
171
+ | 'folder'
172
+ | 'sliders-horizontal'
173
+ | 'chevron-left'
174
+ | 'chevron-up'
175
+ | 'chevrons-left'
176
+ | 'chevrons-right'
177
+ | 'arrow-up-down'
178
+ | 'circle-alert'
179
+ | 'triangle-alert'
180
+ | 'circle-check'
181
+ | 'info'
182
+ | 'circle-question-mark'
183
+ | 'trash'
184
+ | 'eye'
185
+ | 'eye-off'
186
+ | 'timer'
187
+ | 'arrow-right-from-line'
188
+ | 'arrow-right-to-line'
189
+ | 'funnel-x'
190
+ | 'flag'
191
+ | 'loader-circle'
192
+ | 'minus'
193
+ | 'upload'
194
+ | 'file'
195
+
196
+ export const defaultIcons: Record<IconName, IconComponent> = {
197
+ 'chevron-left': ChevronLeft,
198
+ 'chevron-up': ChevronUp,
199
+ 'chevrons-left': ChevronsLeft,
200
+ 'chevrons-right': ChevronsRight,
201
+ 'arrow-up-down': ArrowUpDown,
202
+ 'circle-alert': CircleAlert,
203
+ 'triangle-alert': TriangleAlert,
204
+ 'circle-check': CircleCheck,
205
+ info: Info,
206
+ 'circle-question-mark': CircleQuestionMark,
207
+ trash: Trash2,
208
+ eye: Eye,
209
+ 'eye-off': EyeOff,
210
+ timer: Timer,
211
+ 'arrow-right-from-line': ArrowRightFromLine,
212
+ 'arrow-right-to-line': ArrowRightToLine,
213
+ 'funnel-x': FunnelX,
214
+ flag: Flag,
215
+ 'loader-circle': LoaderCircle,
216
+ minus: Minus,
217
+ upload: Upload,
218
+ file: File,
219
+ 'chevron-right': ChevronRight,
220
+ 'chevron-down': ChevronDown,
221
+ pipette: Pipette,
222
+ x: X,
223
+ copy: Copy,
224
+ menu: Menu,
225
+ dot: Dot,
226
+ monitor: Monitor,
227
+ sun: Sun,
228
+ moon: Moon,
229
+ 'rectangle-horizontal': RectangleHorizontal,
230
+ circle: Circle,
231
+ 'square-library': SquareLibrary,
232
+ clock: Clock,
233
+ star: Star,
234
+ settings: Settings,
235
+ plus: Plus,
236
+ 'arrow-left': ArrowLeft,
237
+ 'arrow-right': ArrowRight,
238
+ 'arrow-up': ArrowUp,
239
+ 'arrow-down': ArrowDown,
240
+ search: Search,
241
+ loader: Loader,
242
+ users: Users,
243
+ lock: Lock,
244
+ mail: Mail,
245
+ bell: Bell,
246
+ shield: Shield,
247
+ palette: Palette,
248
+ lightbulb: Lightbulb,
249
+ rocket: Rocket,
250
+ heart: Heart,
251
+ paintbrush: Paintbrush,
252
+ brain: Brain,
253
+ globe: Globe,
254
+ user: User,
255
+ image: ImageIcon,
256
+ link: Link,
257
+ check: Check,
258
+ 'rotate-ccw': RotateCcw,
259
+ play: Play,
260
+ pause: Pause,
261
+ home: Home,
262
+ 'message-circle': MessageCircle,
263
+ inbox: Inbox,
264
+ pencil: Pencil,
265
+ scaling: Scaling,
266
+ 'skip-forward': SkipForward,
267
+ 'corner-down-right': CornerDownRight,
268
+ 'corner-down-left': CornerDownLeft,
269
+ 'panel-left': PanelLeft,
270
+ 'panel-left-dashed': PanelLeftDashed,
271
+ 'panel-right': PanelRight,
272
+ 'panel-right-dashed': PanelRightDashed,
273
+ 'chevrons-up-down': ChevronsUpDown,
274
+ 'more-horizontal': Ellipsis,
275
+ 'more-vertical': EllipsisVertical,
276
+ calendar: Calendar,
277
+ folder: Folder,
278
+ 'sliders-horizontal': SlidersHorizontal,
279
+ }
280
+
281
+ const IconContext = createContext<Record<IconName, IconComponent> | null>(null)
282
+
283
+ /**
284
+ * Returns a single icon component for the given name.
285
+ * Falls back to the default (Lucide) set if no provider is present.
286
+ */
287
+ function useIcon(name: IconName): IconComponent {
288
+ const icons = useContext(IconContext)
289
+ return (icons ?? defaultIcons)[name]
290
+ }
291
+
292
+ /**
293
+ * Returns the full icon map.
294
+ * Falls back to the default (Lucide) set if no provider is present.
295
+ */
296
+ function useIcons(): Record<IconName, IconComponent> {
297
+ const icons = useContext(IconContext)
298
+ return icons ?? defaultIcons
299
+ }
300
+
301
+ /**
302
+ * Swap some or all icons for components from another library.
303
+ * Names left out of `icons` keep their default (Lucide) component.
304
+ */
305
+ function IconProvider({ children, icons }: { children: ReactNode; icons?: Partial<Record<IconName, IconComponent>> }) {
306
+ const value = useMemo(() => ({ ...defaultIcons, ...icons }), [icons])
307
+ return <IconContext.Provider value={value}>{children}</IconContext.Provider>
308
+ }
309
+
310
+ export { IconProvider, useIcon, useIcons }
package/lib/inert.ts ADDED
@@ -0,0 +1,22 @@
1
+ /*
2
+ * Local addition (not part of Fluid Functionalism): `inert` that holds on
3
+ * React 18 and 19. React 18 has no `inert` prop and passes it through as an
4
+ * unknown attribute, so it needs a string (`''`); React 19 reads it as a
5
+ * boolean prop and drops `''`. `inertProps` picks the value per React major;
6
+ * `markInert` sets the attribute from a ref, outside React, for an element
7
+ * that is always inert.
8
+ */
9
+
10
+ import { version } from 'react'
11
+
12
+ const INERT = (Number.parseInt(version, 10) >= 19 ? true : '') as unknown as boolean
13
+
14
+ /** Spread onto an element to make it inert while `on`. */
15
+ export function inertProps(on: boolean) {
16
+ return on ? { inert: INERT } : {}
17
+ }
18
+
19
+ /** A ref callback that makes its element inert for good. */
20
+ export function markInert(el: HTMLElement | null) {
21
+ el?.setAttribute('inert', '')
22
+ }
@@ -0,0 +1,102 @@
1
+ /*
2
+ * Local addition (not part of Fluid Functionalism): the one renderer behind
3
+ * every morphing overlay, driven by `lib/use-morph.ts`. It goes inside the
4
+ * Base UI popup, which stays transparent and at its final size:
5
+ *
6
+ * - shapes: while goo or morph runs, the growing surface, cut around the
7
+ * source so the source stays visible. For goo, an SVG goo filter melts it
8
+ * with a copy of the source into one shape with a liquid neck. The filter
9
+ * (blur, alpha threshold, composite on top) is beUI's gooey popover
10
+ * (github.com/starc007/ui-components `components/motion/popover.tsx` @
11
+ * de52f337e520e7ee37749b36eb1c32df86137bcb — MIT © 2026 Saurabh Chauhan,
12
+ * notice: LICENSE.beui), the same one Sileo's toast uses
13
+ * (github.com/hiaaryan/sileo `src/sileo.tsx` @
14
+ * 9793f844349983e140cf33cebbb8f51626d41407 — MIT, notice: LICENSE.sileo).
15
+ * - surface: the background and, above it, the shadow (so a dark scheme's
16
+ * inset highlight lands on top, as on one `Elevated` element). Two layers
17
+ * so the shadow can fade in while the goo neck is still attached.
18
+ * - content: in normal flow at its final place, revealed by a clip from the
19
+ * same rect.
20
+ */
21
+
22
+ import type { ReactNode, Ref } from 'react'
23
+ import { MorphPartInOverlay } from './morph-part'
24
+ import { GOO_MATRIX, type Morph } from './use-morph'
25
+ import { cn } from './utils'
26
+
27
+ interface MorphSurfaceProps {
28
+ /** The engine, from `useMorph`. */
29
+ morph: Morph
30
+ /** Background class of the surface: `SURFACE_BG[level]`, or `bg-foreground` for an inverted tooltip. */
31
+ bg?: string
32
+ /** Shadow class (`SURFACE_SHADOW[level]`); leave out for a flat surface. */
33
+ shadow?: string
34
+ /** Radius class the surface rests at (the shape context's `container`, `bg`, …). */
35
+ radius: string
36
+ /** Classes for the content wrapper: padding, width. */
37
+ className?: string
38
+ /** The overlay's content. */
39
+ children?: ReactNode
40
+ }
41
+
42
+ interface GooFilterProps {
43
+ id: string
44
+ /** Blur radius; leave out when `blurRef` sets it per morph. */
45
+ blur?: number
46
+ blurRef?: Ref<SVGFEGaussianBlurElement>
47
+ /** Outlines the melted shape with the surface shadow's 1px ring (`--shadow-color`), so a surface the color of the page still shows its neck; the ref's `flood-opacity` fades it. */
48
+ outlineRef?: Ref<SVGFEFloodElement>
49
+ }
50
+
51
+ /** The goo filter: blur, threshold the alpha back into solid shapes, then lay the crisp original on top. */
52
+ export function GooFilter({ id, blur, blurRef, outlineRef }: GooFilterProps) {
53
+ return (
54
+ <svg aria-hidden className="absolute size-0">
55
+ <filter id={id} x="-50%" y="-50%" width="200%" height="200%" colorInterpolationFilters="sRGB">
56
+ <feGaussianBlur ref={blurRef} in="SourceGraphic" stdDeviation={blur} result="blur" />
57
+ <feColorMatrix in="blur" mode="matrix" values={GOO_MATRIX} result="goo" />
58
+ <feComposite in="SourceGraphic" in2="goo" operator="atop" result="body" />
59
+ {outlineRef && (
60
+ <>
61
+ <feMorphology in="goo" operator="dilate" radius={1} result="grown" />
62
+ <feFlood ref={outlineRef} className="[flood-color:var(--shadow-color)]" />
63
+ <feComposite in2="grown" operator="in" result="outline" />
64
+ <feMerge>
65
+ <feMergeNode in="outline" />
66
+ <feMergeNode in="body" />
67
+ </feMerge>
68
+ </>
69
+ )}
70
+ </filter>
71
+ </svg>
72
+ )
73
+ }
74
+
75
+ export function MorphSurface({ morph, bg, shadow, radius, className, children }: MorphSurfaceProps) {
76
+ const { refs, gooId, effect } = morph
77
+
78
+ return (
79
+ <>
80
+ {effect === 'goo' && <GooFilter id={gooId} blurRef={refs.blur} outlineRef={refs.outline} />}
81
+ {(effect === 'goo' || effect === 'morph') && (
82
+ // The filter is the effect itself, not a visual value: it melts the shapes' own token background.
83
+ <div
84
+ ref={refs.shapes}
85
+ aria-hidden
86
+ className="pointer-events-none absolute hidden"
87
+ style={effect === 'goo' ? { filter: `url(#${gooId})` } : undefined}
88
+ >
89
+ {effect === 'goo' && <div ref={refs.copy} className={cn('absolute', bg)} />}
90
+ <div ref={refs.shape} className={cn('absolute', bg)} />
91
+ </div>
92
+ )}
93
+ <div ref={refs.bg} aria-hidden className={cn('pointer-events-none absolute inset-0', bg, radius)} />
94
+ {shadow && (
95
+ <div ref={refs.shadow} aria-hidden className={cn('pointer-events-none absolute inset-0', shadow, radius)} />
96
+ )}
97
+ <div ref={refs.content} className={cn('relative', className)}>
98
+ <MorphPartInOverlay.Provider value={true}>{children}</MorphPartInOverlay.Provider>
99
+ </div>
100
+ </>
101
+ )
102
+ }