@justanarthur/modo-ui 0.6.0-canary.9 → 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-c7rwx0ap.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-c74gf16d.js → components-1z6tdadk.js} +24 -40
  91. package/dist/shared/{components-bae8sbjx.js → components-27nnvrwe.js} +14 -15
  92. package/dist/shared/{components-qh1cvj6p.js → components-2dxkv6zm.js} +7 -8
  93. package/dist/shared/{components-y0kfy2g4.js → components-2ecg8svx.js} +152 -234
  94. package/dist/shared/{components-c5w5zk0s.js → components-2ph6t61s.js} +34 -37
  95. package/dist/shared/{components-4j3t39dd.js → components-39jq9va1.js} +24 -29
  96. package/dist/shared/components-3ky44908.js +9 -0
  97. package/dist/shared/{components-syynwm1r.js → components-3mkepka5.js} +25 -28
  98. package/dist/shared/{components-wgtjt2af.js → components-4700p9kz.js} +22 -24
  99. package/dist/shared/{components-yhgq0qxx.js → components-59efxjd9.js} +12 -13
  100. package/dist/shared/{components-91zw3d9f.js → components-5vgpnxgy.js} +27 -51
  101. package/dist/shared/{components-kz5q11pp.js → components-5xc2j8jz.js} +18 -19
  102. package/dist/shared/{components-zkk3fmw8.js → components-6p8tfcd6.js} +29 -57
  103. package/dist/shared/{components-4nck8acq.js → components-7r3etddy.js} +54 -19
  104. package/dist/shared/{components-svkt577j.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-pv1dyrtn.js → components-b3c5et5b.js} +38 -49
  108. package/dist/shared/{components-rrbpmfx4.js → components-c6s6b43g.js} +2 -3
  109. package/dist/shared/{components-pwayrkw9.js → components-chacnk61.js} +19 -19
  110. package/dist/shared/{components-71nbt03m.js → components-cv16mryv.js} +7 -26
  111. package/dist/shared/{components-hgv6tygd.js → components-d6xtjht3.js} +30 -35
  112. package/dist/shared/{components-z8fedth5.js → components-dk0gjr5a.js} +18 -19
  113. package/dist/shared/{components-cet3jpa0.js → components-fzrq6tr3.js} +34 -37
  114. package/dist/shared/{components-cnead5qm.js → components-gc5vtq2f.js} +30 -66
  115. package/dist/shared/components-gf5s6ap9.js +42 -0
  116. package/dist/shared/{components-0h78g3b5.js → components-gz8zf3ec.js} +55 -56
  117. package/dist/shared/{components-mattt5jp.js → components-h2ajmhwn.js} +35 -107
  118. package/dist/shared/{components-m06yq8wk.js → components-hqeq3w9q.js} +23 -38
  119. package/dist/shared/{components-7qx17na9.js → components-hw9yk32z.js} +24 -36
  120. package/dist/shared/components-hyq23phv.js +310 -0
  121. package/dist/shared/{components-9jmjnkqd.js → components-jbbmdr74.js} +22 -41
  122. package/dist/shared/{components-dcc02hs2.js → components-jjw69c4c.js} +4 -7
  123. package/dist/shared/{components-303jf96s.js → components-jthe1pwb.js} +420 -139
  124. package/dist/shared/{components-dtca4s6b.js → components-jwst3vtj.js} +76 -224
  125. package/dist/shared/{components-dc5q749x.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-qx27excf.js → components-mjthm1kf.js} +9 -13
  129. package/dist/shared/{components-1e64t8aj.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-w2jqa6hx.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-2a7hcand.js → components-rr7a6ja9.js} +27 -59
  136. package/dist/shared/{components-005jt2nz.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-p0fm0bab.js → components-w1r67ag9.js} +149 -294
  144. package/dist/shared/{components-xd3emmy4.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-yxmxn2jp.js → components-y9y0g8er.js} +28 -52
  148. package/dist/shared/components-ypp01w3p.js +986 -0
  149. package/dist/shared/{components-czdvj1a8.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-01w9qcfa.js +0 -277
  385. package/dist/shared/components-124epb7f.js +0 -53
  386. package/dist/shared/components-26snnbs9.js +0 -322
  387. package/dist/shared/components-2krsc300.js +0 -254
  388. package/dist/shared/components-2qbqqpgq.js +0 -1545
  389. package/dist/shared/components-34txk9rj.js +0 -35
  390. package/dist/shared/components-3h92d94m.js +0 -23
  391. package/dist/shared/components-4vfm04wq.js +0 -82
  392. package/dist/shared/components-54nq988h.js +0 -123
  393. package/dist/shared/components-7s7pykk5.js +0 -281
  394. package/dist/shared/components-868v7scv.js +0 -399
  395. package/dist/shared/components-8jrk5eye.js +0 -448
  396. package/dist/shared/components-adkarj8n.js +0 -35
  397. package/dist/shared/components-b1e239g3.js +0 -28
  398. package/dist/shared/components-b94t6qtj.js +0 -143
  399. package/dist/shared/components-bsqynhaj.js +0 -179
  400. package/dist/shared/components-c9yr4ed1.js +0 -44
  401. package/dist/shared/components-d3shbwqq.js +0 -95
  402. package/dist/shared/components-dhgk6mbt.js +0 -16
  403. package/dist/shared/components-drxrtnp2.js +0 -25
  404. package/dist/shared/components-f7h57m6t.js +0 -59
  405. package/dist/shared/components-g3eafs70.js +0 -337
  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-mhza2wdn.js +0 -482
  414. package/dist/shared/components-mrbaxt8q.js +0 -62
  415. package/dist/shared/components-pt5ftm4p.js +0 -38
  416. package/dist/shared/components-rtadhd9j.js +0 -64
  417. package/dist/shared/components-tv7b8tet.js +0 -271
  418. package/dist/shared/components-tz4gaf1v.js +0 -23
  419. package/dist/shared/components-wbbckbw8.js +0 -34
  420. package/dist/shared/components-wknae3m4.js +0 -298
  421. package/dist/shared/components-xdqmt6ed.js +0 -20
  422. package/dist/shared/components-xjkdvnbg.js +0 -107
  423. package/dist/shared/components-z3v0n0de.js +0 -11
  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 -575
  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,83 +0,0 @@
1
- import FileDropzone from './index'
2
- import UploadDemo from './upload-demo'
3
- import Field from '../field'
4
-
5
- # Basics
6
-
7
- ## Dropzone
8
-
9
- Drag files over the zone, or click it (or press Enter on it) to pick them. While files are in the air the line says whether all, some or none of them will be taken; files that pass go to the list, the rest to the error.
10
-
11
- <UploadDemo multiple accept=".pdf,image/*" maxSize={5000000} description="PDF or images, up to 5 MB each, three at most" />
12
-
13
- ## Single file
14
-
15
- Without `multiple` the zone takes one file: drag several and it says the rest will be skipped; drag only files of another type and it refuses the drop.
16
-
17
- <div className="w-96 max-w-full">
18
- <FileDropzone accept="image/*" description="PNG or JPG" />
19
- </div>
20
-
21
- ## Compact
22
-
23
- The compact step tightens the padding and steps the text down.
24
-
25
- <div className="w-80 max-w-full">
26
- <FileDropzone size="compact" label="Drop a CSV or click to browse" accept=".csv" />
27
- </div>
28
-
29
- ## Style and attributes
30
-
31
- Props a `<label>` takes (`style`, `title`, `data-*`, `aria-*`, handlers) reach the zone's root. Here an inline `maxWidth` and a tooltip.
32
-
33
- <div className="w-96 max-w-full">
34
- <FileDropzone style={{ maxWidth: 280 }} title="Drop your avatar here" label="Drop an avatar" accept="image/*" />
35
- </div>
36
-
37
- ## Translated
38
-
39
- Every line is a prop.
40
-
41
- <div className="w-96 max-w-full">
42
- <FileDropzone
43
- multiple
44
- label="Presuňte súbory sem alebo kliknite"
45
- activeLabel="Pustite a pridajte"
46
- partialLabel="Niektoré súbory sa vynechajú"
47
- rejectLabel="Tieto súbory nemožno pridať"
48
- description="PDF, najviac 10 MB"
49
- accept=".pdf"
50
- />
51
- </div>
52
-
53
- # States
54
-
55
- Invalid takes the field's destructive ring; disabled dims the zone; read-only takes no files.
56
-
57
- <div className="flex flex-col gap-3 w-96 max-w-full">
58
- <Field invalid>
59
- <Field.Label>Contract</Field.Label>
60
- <FileDropzone accept=".pdf" />
61
- <Field.Error>Attach the signed contract.</Field.Error>
62
- </Field>
63
- <FileDropzone disabled label="Uploads are paused" />
64
- <FileDropzone readOnly label="No file attached" />
65
- </div>
66
-
67
- # File rows
68
-
69
- A row shows one file: its glyph or thumbnail, the name, the size or a status line, and a remove button. `status` sets the glyph, and `progress` fills the bar while uploading.
70
-
71
- <div className="flex flex-col w-96 max-w-full">
72
- <FileDropzone.Row name="Quarterly report.pdf" fileSize={2480000} type="application/pdf" status="done" onRemove={() => {}} />
73
- <FileDropzone.Row name="Site photo.jpg" fileSize={5320000} type="image/jpeg" status="uploading" progress={64} onRemove={() => {}} />
74
- <FileDropzone.Row name="Budget.xlsx" fileSize={84000} status="error" error="Upload failed. Try again." onRemove={() => {}} />
75
- <FileDropzone.Row name="Contract draft.docx" fileSize={1200000} description="Uploaded yesterday" />
76
- </div>
77
-
78
- ## Compact rows
79
-
80
- <div className="flex flex-col w-80 max-w-full">
81
- <FileDropzone.Row size="compact" name="Invoice 0042.pdf" fileSize={182000} locale="sk-SK" onRemove={() => {}} />
82
- <FileDropzone.Row size="compact" name="Receipt.png" fileSize={940000} type="image/png" status="uploading" onRemove={() => {}} />
83
- </div>
@@ -1,201 +0,0 @@
1
- /*
2
- * Local addition (not part of Fluid Functionalism): one file in a list of
3
- * picked or uploaded files, shown by FileDropzone's page as `FileDropzone.Row`.
4
- */
5
-
6
- import { AnimatePresence, motion } from 'motion/react'
7
- import type { ReactNode } from 'react'
8
- import { FIELD_ACTION_RADIUS } from '../../../lib/field-variants'
9
- import { type IconComponent, useIcon } from '../../../lib/icon-context'
10
- import { useReduceMotion } from '../../../lib/reduced-motion'
11
- import { useShape } from '../../../lib/shape-context'
12
- import { type SizeVariant, useSize } from '../../../lib/size-context'
13
- import { spring } from '../../../lib/springs'
14
- import { cn } from '../../../lib/utils'
15
- import Button from '../../button'
16
- import Progress, { Spinner } from '../../progress'
17
- import { formatFileSize } from './variants'
18
-
19
- /** Where a file is in its upload: `idle` (picked), `uploading`, `done` or `error`. */
20
- type FileRowStatus = 'idle' | 'uploading' | 'done' | 'error'
21
-
22
- interface FileRowProps {
23
- /** The picked file: its name, size and type fill the row. */
24
- file?: File
25
- /** File name, for a file you only know by its metadata (one already uploaded). Wins over `file`. */
26
- name?: string
27
- /** File size in bytes. Wins over `file`. */
28
- fileSize?: number
29
- /** MIME type; an image shows the image glyph. Wins over `file`. */
30
- type?: string
31
- /** Image URL shown in place of the glyph, e.g. an object URL of the file or the server's preview. */
32
- thumbnail?: string
33
- /** Glyph in place of the file or image one. */
34
- icon?: IconComponent
35
- /** Where the file is in its upload; sets the status glyph and the progress bar. Defaults to `"idle"`. */
36
- status?: FileRowStatus
37
- /** Upload progress from 0 to 100, shown as a bar while `status` is `"uploading"` (see Progress). Omitted, the bar sweeps. */
38
- progress?: number
39
- /** Accessible name of the upload's bar. Defaults to `"Uploading"`. */
40
- uploadingLabel?: string
41
- /** The line under the name in place of the size, e.g. "Uploaded 2 min ago". */
42
- description?: ReactNode
43
- /** An error message in place of the size line; the row reads as failed. */
44
- error?: ReactNode
45
- /** Shows a remove button and is called when it is pressed. */
46
- onRemove?: () => void
47
- /** Accessible name of the remove button. Defaults to `"Remove file"`. */
48
- removeLabel?: string
49
- /** More controls before the remove button, e.g. a download link or a menu. */
50
- actions?: ReactNode
51
- /** Locale for the size (`1,5 MB` in `"sk-SK"`). Defaults to the browser's. */
52
- locale?: Intl.LocalesArgument
53
- /** Dims the row and its actions. Defaults to `false`. */
54
- disabled?: boolean
55
- /** Pins the row to one step of the size ladder. Defaults to the surrounding SizeProvider. */
56
- size?: SizeVariant
57
- /** Classes for the row. */
58
- className?: string
59
- }
60
-
61
- // Literal tables: UnoCSS only generates the classes it can read whole.
62
- const THUMB = { default: 'size-8', compact: 'size-7' }
63
- const ROW_PAD = { default: 'py-1.5', compact: 'py-1' }
64
-
65
- // Literal table: the spinner at the ladder's glyph size.
66
- const SPINNER = { default: 'size-4', compact: 'size-3.5' }
67
-
68
- function StatusGlyph({ status, size }: { status: FileRowStatus; size: SizeVariant }) {
69
- const Done = useIcon('circle-check')
70
- const Failed = useIcon('circle-alert')
71
- const reduced = useReduceMotion()
72
- const icon = useSize(size).icon
73
-
74
- return (
75
- // Decorative: the bar carries the progress, the meta line the error.
76
- <span aria-hidden="true" className="inline-grid shrink-0 place-items-center">
77
- <AnimatePresence initial={false} mode="popLayout">
78
- {status !== 'idle' && (
79
- <motion.span
80
- key={status}
81
- className={cn(
82
- 'col-start-1 row-start-1 flex',
83
- status === 'done' && 'text-status-success',
84
- status === 'error' && 'text-destructive',
85
- status === 'uploading' && 'text-muted-foreground',
86
- )}
87
- // Under reduced motion the glyphs only fade.
88
- initial={{ opacity: 0, scale: reduced ? 1 : 0.6 }}
89
- animate={{ opacity: 1, scale: 1 }}
90
- exit={{ opacity: 0, scale: reduced ? 1 : 0.8, transition: spring.fast.exit }}
91
- transition={spring.fast}
92
- >
93
- {status === 'done' && <Done size={icon} strokeWidth={2} />}
94
- {status === 'error' && <Failed size={icon} strokeWidth={2} />}
95
- {status === 'uploading' && <Spinner className={SPINNER[size]} />}
96
- </motion.span>
97
- )}
98
- </AnimatePresence>
99
- </span>
100
- )
101
- }
102
-
103
- /** One file in a list: its glyph or thumbnail, name, size or status, and a remove button. */
104
- function FileRow({
105
- file,
106
- name: nameProp,
107
- fileSize: fileSizeProp,
108
- type: typeProp,
109
- thumbnail,
110
- icon,
111
- status = 'idle',
112
- progress,
113
- description,
114
- error,
115
- onRemove,
116
- removeLabel = 'Remove file',
117
- uploadingLabel = 'Uploading',
118
- actions,
119
- locale,
120
- disabled = false,
121
- size: sizeProp,
122
- className,
123
- }: FileRowProps) {
124
- const size = useSize(sizeProp)
125
- const shape = useShape()
126
- const compact = size.variant === 'compact'
127
- const FileIcon = useIcon('file')
128
- const ImageIcon = useIcon('image')
129
- const Remove = useIcon('x')
130
-
131
- const name = nameProp ?? file?.name ?? ''
132
- const bytes = fileSizeProp ?? file?.size
133
- const type = typeProp ?? file?.type ?? ''
134
- const Glyph = icon ?? (type.startsWith('image/') ? ImageIcon : FileIcon)
135
- const shown = error ? 'error' : status
136
- const sizeText = bytes != null ? formatFileSize(bytes, locale) : undefined
137
- const meta =
138
- error ??
139
- description ??
140
- (status === 'uploading' && progress != null ? `${sizeText ?? ''} · ${Math.round(progress)}%` : sizeText)
141
-
142
- return (
143
- <div
144
- data-status={shown}
145
- data-disabled={disabled || undefined}
146
- className={cn(
147
- 'flex min-w-0 items-center transition-opacity duration-fast',
148
- size.gap,
149
- size.itemPx,
150
- ROW_PAD[size.variant],
151
- shape.item,
152
- disabled && 'pointer-events-none opacity-50',
153
- className,
154
- )}
155
- >
156
- <span
157
- className={cn(
158
- 'flex shrink-0 items-center justify-center overflow-hidden bg-muted text-muted-foreground',
159
- THUMB[size.variant],
160
- FIELD_ACTION_RADIUS[shape.variant],
161
- )}
162
- >
163
- {thumbnail ? (
164
- <img src={thumbnail} alt="" className="size-full object-cover" />
165
- ) : (
166
- <Glyph size={size.icon} strokeWidth={1.5} />
167
- )}
168
- </span>
169
-
170
- <div className="flex min-w-0 flex-1 flex-col">
171
- <span className={cn('truncate text-foreground weight-normal', size.text)} title={name}>
172
- {name}
173
- </span>
174
- {meta != null && meta !== '' && (
175
- <span
176
- className={cn(
177
- 'truncate',
178
- compact ? 'text-caption-compact' : 'text-caption',
179
- error ? 'text-destructive weight-medium' : 'text-muted-foreground weight-normal',
180
- )}
181
- >
182
- {meta}
183
- </span>
184
- )}
185
- {shown === 'uploading' && <Progress value={progress ?? null} aria-label={uploadingLabel} className="mt-1" />}
186
- </div>
187
-
188
- <StatusGlyph status={shown} size={size.variant} />
189
- {actions}
190
- {onRemove && (
191
- <Button variant="ghost" size="icon-compact" aria-label={removeLabel} disabled={disabled} onClick={onRemove}>
192
- <Remove strokeWidth={1.5} />
193
- </Button>
194
- )}
195
- </div>
196
- )
197
- }
198
-
199
- export type { FileRowProps, FileRowStatus }
200
- export { FileRow }
201
- export default FileRow
@@ -1,316 +0,0 @@
1
- /*
2
- * Local addition (not part of Fluid Functionalism): a drag-and-drop zone that
3
- * hands picked files over and keeps none (no upload logic), and the row a
4
- * picked or uploaded file shows in (`file-row.tsx`). The zone is a label
5
- * around a visually hidden file input, joined to Base UI's Field like Input.
6
- */
7
-
8
- import { Field } from '@base-ui/react/field'
9
- import { motion } from 'motion/react'
10
- import {
11
- type ChangeEvent,
12
- type CSSProperties,
13
- type DragEvent,
14
- type ForwardRefExoticComponent,
15
- forwardRef,
16
- type LabelHTMLAttributes,
17
- type ReactNode,
18
- type RefAttributes,
19
- useRef,
20
- useState,
21
- } from 'react'
22
- import { useFieldState } from '../../../lib/field-classes'
23
- import { type IconComponent, useIcon } from '../../../lib/icon-context'
24
- import { useReduceMotion } from '../../../lib/reduced-motion'
25
- import { useShape } from '../../../lib/shape-context'
26
- import { type SizeVariant, useSize } from '../../../lib/size-context'
27
- import { spring } from '../../../lib/springs'
28
- import { cn } from '../../../lib/utils'
29
- import { FileRow } from './file-row'
30
- import { type DragVerdict, dragVerdict, type FileRejection, sortFiles } from './variants'
31
-
32
- interface FileDropzoneProps
33
- extends Omit<
34
- LabelHTMLAttributes<HTMLLabelElement>,
35
- 'children' | 'className' | 'style' | 'id' | 'onChange' | 'htmlFor' | 'form'
36
- > {
37
- /** Called with the files that pass `accept`, `maxSize` and the count, after a pick or a drop. */
38
- onFilesChange?: (files: File[]) => void
39
- /** Called with the files turned away and why (`type`, `size`, `count`), after a pick or a drop. */
40
- onFilesRejected?: (rejections: FileRejection[]) => void
41
- /** File types the zone takes, as the file input reads them: `.pdf,image/*`. Defaults to any. */
42
- accept?: string
43
- /** Takes several files at once. Defaults to `false`. */
44
- multiple?: boolean
45
- /** Most files one pick or drop may add; the rest are rejected as `count`. Pass what is left when you keep a list. */
46
- maxFiles?: number
47
- /** Largest file in bytes; bigger ones are rejected as `size`. */
48
- maxSize?: number
49
- /** The main line. Defaults to `"Drop a file here or click to browse"` (`"files"` with `multiple`). */
50
- label?: ReactNode
51
- /** The line under it: the types and sizes the zone takes, e.g. "PDF or PNG, up to 10 MB". */
52
- description?: ReactNode
53
- /** The main line while files the zone takes are dragged over it. Defaults to `"Drop to add"`. */
54
- activeLabel?: ReactNode
55
- /** The main line while some of the dragged files will be taken and the rest turned away (a wrong type, past `maxFiles`). Defaults to `"Some files will be skipped"`. */
56
- partialLabel?: ReactNode
57
- /** The main line while none of the dragged files can be taken; the drop is refused. Defaults to `"These files can't be added"`. */
58
- rejectLabel?: ReactNode
59
- /** Glyph above the labels. Defaults to the `upload` icon. */
60
- icon?: IconComponent
61
- /** Content in place of the glyph and labels. */
62
- children?: ReactNode
63
- /** Id of the file input, for a `Label`'s `htmlFor`. Inside a Field it is wired for you. */
64
- id?: string
65
- /** Tells assistive tech a file is required (`aria-required`). The zone keeps no files, so native validation never blocks a submit: check your own list. Defaults to the surrounding Field's `required`. */
66
- required?: boolean
67
- /** Turns the zone destructive. Defaults to the surrounding Field's `invalid`. */
68
- invalid?: boolean
69
- /** Dims the zone and turns files away. Defaults to the surrounding Field's `disabled`. */
70
- disabled?: boolean
71
- /** Shows the zone without taking files: no browse, no drop, no hover. Defaults to the surrounding Field's `readOnly`. */
72
- readOnly?: boolean
73
- /** Pins the zone to one step of the size ladder: compact tightens the padding and steps the text down. Defaults to the surrounding SizeProvider. */
74
- size?: SizeVariant
75
- /** Classes for the zone. */
76
- className?: string
77
- /** Inline styles for the zone (its `<label>` root). The other attributes of a `<label>` (`title`, `data-*`, `aria-*`, `onClick`) reach it too, and drag handlers run before the zone's own. */
78
- style?: CSSProperties
79
- }
80
-
81
- type DragState = 'idle' | DragVerdict
82
-
83
- // Literal tables: UnoCSS only generates the classes it can read whole.
84
- const PAD = { default: 'px-6 py-8', compact: 'px-4 py-5' }
85
-
86
- type FileDropzoneComponent = ForwardRefExoticComponent<FileDropzoneProps & RefAttributes<HTMLInputElement>> & {
87
- Row: typeof FileRow
88
- }
89
-
90
- /**
91
- * A zone to drop files on, or click to pick them.
92
- *
93
- * Drag files over it and it lights up; the line changes to say whether it
94
- * will take them, reading their types while they are still in the air: all
95
- * of them, some (the rest will be skipped), or none, when it turns
96
- * destructive and refuses the drop. Dropped or picked files are sorted
97
- * against `accept`, `maxSize` and `maxFiles`: the ones that pass go to
98
- * `onFilesChange`, the rest to `onFilesRejected` with a reason. The zone
99
- * keeps none (its input is cleared after every pick, so nothing submits with
100
- * a native form and `required` is only announced), so the list, the upload
101
- * and its errors stay yours. Show each
102
- * file in a `FileDropzone.Row`. Every line is a prop, for translation. The
103
- * zone is a label around a hidden file input, so a click or Enter opens the
104
- * picker, and inside a Field it is labelled and takes the field's state. The
105
- * ref reaches the input: `ref.current.click()` reopens the picker, e.g. to
106
- * replace a file.
107
- *
108
- * Statics:
109
- * - `FileDropzone.Row` (also `FileRow`) — one file: its glyph or
110
- * `thumbnail`, name, size, and a remove button with `onRemove`: `file` (or
111
- * `name` / `fileSize` / `type`), `status` (`idle`, `uploading`, `done`,
112
- * `error`), `progress` (0–100), `error`, `description`, `actions`,
113
- * `removeLabel`, `locale`.
114
- *
115
- * Also exported from this item: `formatFileSize(bytes, locale)`, `sortFiles`
116
- * and `acceptsFile`, plain functions a server can call too.
117
- *
118
- * @example {@include ./examples.mdx}
119
- */
120
- const FileDropzone = forwardRef<HTMLInputElement, FileDropzoneProps>(
121
- (
122
- {
123
- onFilesChange,
124
- onFilesRejected,
125
- accept,
126
- multiple = false,
127
- maxFiles,
128
- maxSize,
129
- label,
130
- description,
131
- activeLabel = 'Drop to add',
132
- partialLabel = 'Some files will be skipped',
133
- rejectLabel = "These files can't be added",
134
- icon,
135
- children,
136
- id,
137
- required,
138
- invalid,
139
- disabled,
140
- readOnly,
141
- size: sizeProp,
142
- className,
143
- style,
144
- onDragEnter: dragEnter,
145
- onDragOver: dragOver,
146
- onDragLeave: dragLeave,
147
- onDrop: dropped,
148
- ...rest
149
- },
150
- ref,
151
- ) => {
152
- const field = useFieldState()
153
- const size = useSize(sizeProp)
154
- const shape = useShape()
155
- const reduced = useReduceMotion()
156
- const Upload = useIcon('upload')
157
- const Glyph = icon ?? Upload
158
- const compact = size.variant === 'compact'
159
-
160
- const isInvalid = invalid ?? field?.invalid ?? false
161
- const isDisabled = disabled ?? field?.disabled ?? false
162
- const isReadOnly = readOnly ?? field?.readOnly ?? false
163
- const closed = isDisabled || isReadOnly
164
-
165
- const [drag, setDrag] = useState<DragState>('idle')
166
- // dragenter / dragleave fire for every child crossed; count them so the
167
- // zone only goes idle when the pointer really leaves.
168
- const depth = useRef(0)
169
-
170
- const hand = (files: File[]) => {
171
- if (!files.length) return
172
- const { accepted, rejected } = sortFiles(files, { accept, maxSize, maxFiles, multiple })
173
- if (accepted.length) onFilesChange?.(accepted)
174
- if (rejected.length) onFilesRejected?.(rejected)
175
- }
176
-
177
- const onDragEnter = (e: DragEvent<HTMLLabelElement>) => {
178
- dragEnter?.(e)
179
- if (closed || !e.dataTransfer.types.includes('Files')) return
180
- e.preventDefault()
181
- depth.current++
182
- const types = [...e.dataTransfer.items].filter(item => item.kind === 'file').map(item => item.type)
183
- // Only a drag where nothing can pass is refused; a mixed one drops, and sortFiles splits it.
184
- setDrag(dragVerdict(types, accept, multiple ? (maxFiles ?? Number.POSITIVE_INFINITY) : 1))
185
- }
186
-
187
- const onDragOver = (e: DragEvent<HTMLLabelElement>) => {
188
- dragOver?.(e)
189
- if (closed || drag === 'idle') return
190
- e.preventDefault()
191
- e.dataTransfer.dropEffect = drag === 'reject' ? 'none' : 'copy'
192
- }
193
-
194
- const onDragLeave = (e: DragEvent<HTMLLabelElement>) => {
195
- dragLeave?.(e)
196
- if (drag === 'idle') return
197
- depth.current = Math.max(depth.current - 1, 0)
198
- if (depth.current === 0) setDrag('idle')
199
- }
200
-
201
- const onDrop = (e: DragEvent<HTMLLabelElement>) => {
202
- dropped?.(e)
203
- if (closed) return
204
- e.preventDefault()
205
- depth.current = 0
206
- setDrag('idle')
207
- hand([...e.dataTransfer.files])
208
- }
209
-
210
- const onChange = (e: ChangeEvent<HTMLInputElement>) => {
211
- hand([...(e.target.files ?? [])])
212
- // Clear it, so picking the same file again still reports it.
213
- e.target.value = ''
214
- }
215
-
216
- const line =
217
- drag === 'accept'
218
- ? activeLabel
219
- : drag === 'partial'
220
- ? partialLabel
221
- : drag === 'reject'
222
- ? rejectLabel
223
- : (label ?? (multiple ? 'Drop files here or click to browse' : 'Drop a file here or click to browse'))
224
-
225
- return (
226
- // biome-ignore lint/a11y/noLabelWithoutControl: the file input inside is the control (Field.Control renders it).
227
- <label
228
- {...rest}
229
- style={style}
230
- onDragEnter={onDragEnter}
231
- onDragOver={onDragOver}
232
- onDragLeave={onDragLeave}
233
- onDrop={onDrop}
234
- data-dragging={drag === 'idle' ? undefined : drag}
235
- data-invalid={isInvalid || undefined}
236
- data-disabled={isDisabled || undefined}
237
- data-readonly={isReadOnly || undefined}
238
- className={cn(
239
- 'group/zone relative flex cursor-pointer flex-col items-center justify-center text-center',
240
- 'border border-dashed border-border transition-[background-color,border-color,opacity] duration-fast',
241
- 'hover:bg-muted/50 has-[:focus-visible]:ring-1 has-[:focus-visible]:ring-focus-ring',
242
- 'data-[dragging=accept]:border-solid data-[dragging=accept]:!border-border data-[dragging=accept]:!bg-muted',
243
- 'data-[dragging=partial]:border-solid data-[dragging=partial]:!border-border data-[dragging=partial]:!bg-muted',
244
- 'data-[invalid]:border-destructive/50 data-[invalid]:hover:bg-destructive-light/60',
245
- 'data-[dragging=reject]:border-solid data-[dragging=reject]:border-destructive/50 data-[dragging=reject]:!bg-destructive-light/60',
246
- 'data-[readonly]:cursor-default data-[readonly]:hover:bg-transparent',
247
- 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
248
- size.gap,
249
- PAD[size.variant],
250
- shape.container,
251
- className,
252
- )}
253
- >
254
- {/* Field.Control: on its own a plain file input, inside a Field it
255
- joins the field's label, description and error. */}
256
- <Field.Control
257
- ref={ref}
258
- id={id}
259
- disabled={closed}
260
- // Not native `required`: the input is cleared after every pick, so it would always be missing.
261
- aria-required={(required ?? field?.required) || undefined}
262
- aria-invalid={isInvalid || undefined}
263
- render={<input type="file" accept={accept} multiple={multiple} onChange={onChange} className="sr-only" />}
264
- />
265
- {children ?? (
266
- <>
267
- <motion.span
268
- className={cn(
269
- 'flex text-muted-foreground transition-[color] duration-fast group-hover/zone:text-foreground group-data-[dragging]/zone:text-foreground',
270
- drag === 'reject' && 'text-destructive group-data-[dragging]/zone:text-destructive',
271
- )}
272
- initial={false}
273
- // The glyph rises to meet the files; with reduced motion it only darkens.
274
- animate={{ y: (drag === 'accept' || drag === 'partial') && !reduced ? -2 : 0 }}
275
- transition={spring.fast}
276
- >
277
- <Glyph
278
- size={size.icon}
279
- strokeWidth={1.5}
280
- className="transition-[stroke-width] duration-fast group-hover/zone:stroke-[2] group-data-[dragging]/zone:stroke-[2]"
281
- />
282
- </motion.span>
283
- <span className="flex flex-col">
284
- <span
285
- className={cn('weight-normal', size.text, drag === 'reject' ? 'text-destructive' : 'text-foreground')}
286
- >
287
- {line}
288
- </span>
289
- {description != null && (
290
- <span
291
- className={cn(
292
- 'text-muted-foreground weight-normal',
293
- compact ? 'text-caption-compact' : 'text-caption',
294
- )}
295
- >
296
- {description}
297
- </span>
298
- )}
299
- </span>
300
- </>
301
- )}
302
- </label>
303
- )
304
- },
305
- ) as FileDropzoneComponent
306
-
307
- FileDropzone.displayName = 'FileDropzone'
308
-
309
- Object.assign(FileDropzone, { Row: FileRow })
310
-
311
- export type { FileRowProps, FileRowStatus } from './file-row'
312
- export type { DragVerdict, FileRejection, FileRejectionReason } from './variants'
313
- export { acceptsFile, dragVerdict, formatFileSize, sortFiles } from './variants'
314
- export type { FileDropzoneProps }
315
- export { FileDropzone, FileRow }
316
- export default FileDropzone
@@ -1,67 +0,0 @@
1
- /*
2
- * Local addition (not part of Fluid Functionalism): the docs stage of the
3
- * FileDropzone page. It keeps the picked files, plays a pretend upload for
4
- * each and shows the rejections in a Field's error, so the example stays
5
- * hook-free. The zone itself keeps no files.
6
- */
7
-
8
- import { useEffect, useState } from 'react'
9
- import Field from '../field'
10
- import FileDropzone, { type FileDropzoneProps, type FileRejection } from './index'
11
-
12
- interface Upload {
13
- file: File
14
- progress: number
15
- }
16
-
17
- const REASONS = { type: "isn't a PDF or an image", size: 'is over 5 MB', count: "doesn't fit: three files at most" }
18
-
19
- export default function UploadDemo(props: FileDropzoneProps) {
20
- const [uploads, setUploads] = useState<Upload[]>([])
21
- const [rejected, setRejected] = useState<FileRejection[]>([])
22
-
23
- // A pretend upload: every file gains a little each tick until it is done.
24
- const busy = uploads.some(upload => upload.progress < 100)
25
- useEffect(() => {
26
- if (!busy) return
27
- const timer = setInterval(
28
- () => setUploads(list => list.map(upload => ({ ...upload, progress: Math.min(upload.progress + 12, 100) }))),
29
- 300,
30
- )
31
- return () => clearInterval(timer)
32
- }, [busy])
33
-
34
- const left = 3 - uploads.length
35
-
36
- return (
37
- <Field invalid={rejected.length > 0} className="w-96 max-w-full gap-2">
38
- <Field.Label>Attachments</Field.Label>
39
- <FileDropzone
40
- {...props}
41
- maxFiles={left}
42
- disabled={left <= 0}
43
- onFilesChange={files => {
44
- setRejected([])
45
- setUploads(list => [...list, ...files.map(file => ({ file, progress: 0 }))])
46
- }}
47
- onFilesRejected={setRejected}
48
- />
49
- <Field.Error>
50
- {rejected.length > 0 && rejected.map(({ file, reason }) => `${file.name} ${REASONS[reason]}.`).join(' ')}
51
- </Field.Error>
52
- {uploads.length > 0 && (
53
- <div className="flex flex-col">
54
- {uploads.map(upload => (
55
- <FileDropzone.Row
56
- key={`${upload.file.name}-${upload.file.lastModified}`}
57
- file={upload.file}
58
- status={upload.progress < 100 ? 'uploading' : 'done'}
59
- progress={upload.progress}
60
- onRemove={() => setUploads(list => list.filter(item => item !== upload))}
61
- />
62
- ))}
63
- </div>
64
- )}
65
- </Field>
66
- )
67
- }