@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,105 +0,0 @@
1
- /*
2
- * Local addition (not part of Fluid Functionalism): the docs stage of the
3
- * Combobox page's remote example. A fake server answers each query after a
4
- * beat, a page at a time, so the example stays hook-free.
5
- */
6
-
7
- import { useEffect, useState } from 'react'
8
- import Button from '../../button'
9
- import Combobox from './index'
10
-
11
- const CITIES = [
12
- 'Amsterdam',
13
- 'Athens',
14
- 'Barcelona',
15
- 'Berlin',
16
- 'Bratislava',
17
- 'Brussels',
18
- 'Bucharest',
19
- 'Budapest',
20
- 'Copenhagen',
21
- 'Dublin',
22
- 'Helsinki',
23
- 'Kyiv',
24
- 'Lisbon',
25
- 'Ljubljana',
26
- 'London',
27
- 'Madrid',
28
- 'Oslo',
29
- 'Paris',
30
- 'Prague',
31
- 'Riga',
32
- 'Rome',
33
- 'Sofia',
34
- 'Stockholm',
35
- 'Tallinn',
36
- 'Vienna',
37
- 'Vilnius',
38
- 'Warsaw',
39
- 'Zagreb',
40
- ]
41
-
42
- const PAGE = 6
43
-
44
- interface RemoteDemoProps {
45
- /** How long the fake server takes, in ms. Defaults to `600`. */
46
- latency?: number
47
- }
48
-
49
- export default function RemoteDemo({ latency = 600 }: RemoteDemoProps) {
50
- const [query, setQuery] = useState('')
51
- const [limit, setLimit] = useState(PAGE)
52
- const [items, setItems] = useState<string[]>([])
53
- const [total, setTotal] = useState(0)
54
- const [loading, setLoading] = useState(true)
55
- // Base UI's change details tell typing from a pick that rewrites the field.
56
- const [reason, setReason] = useState<string>()
57
-
58
- useEffect(() => {
59
- setLoading(true)
60
- const timer = setTimeout(() => {
61
- const matches = CITIES.filter(city => city.toLowerCase().includes(query.trim().toLowerCase()))
62
- setItems(matches.slice(0, limit))
63
- setTotal(matches.length)
64
- setLoading(false)
65
- }, latency)
66
- return () => clearTimeout(timer)
67
- }, [query, limit, latency])
68
-
69
- return (
70
- <div className="w-72 max-w-full">
71
- <Combobox
72
- items={items}
73
- filter={null}
74
- loading={loading}
75
- inputValue={query}
76
- onInputValueChange={(next, details) => {
77
- setQuery(next)
78
- setLimit(PAGE)
79
- setReason(details.reason)
80
- }}
81
- >
82
- <Combobox.Input placeholder="Search a city…" />
83
- <Combobox.Content
84
- footer={
85
- items.length < total ? (
86
- <Button variant="ghost" size="compact" className="w-full" onClick={() => setLimit(limit + PAGE)}>
87
- Load more ({total - items.length})
88
- </Button>
89
- ) : undefined
90
- }
91
- >
92
- <Combobox.Empty>No city matches.</Combobox.Empty>
93
- <Combobox.List>
94
- {item => (
95
- <Combobox.Item key={String(item)} value={String(item)}>
96
- {String(item)}
97
- </Combobox.Item>
98
- )}
99
- </Combobox.List>
100
- </Combobox.Content>
101
- </Combobox>
102
- {reason && <p className="mt-1 pl-3 text-caption text-muted-foreground">Last text change: {reason}</p>}
103
- </div>
104
- )
105
- }
@@ -1,45 +0,0 @@
1
- import Calendar from './index'
2
- import { de } from 'react-day-picker/locale'
3
-
4
- # Single day
5
-
6
- Scroll through the months, or jump with the month and year columns.
7
-
8
- <Calendar mode="single" selected={new Date(2026, 9, 9)} />
9
-
10
- # Range
11
-
12
- `mode="range"` picks a span of days.
13
-
14
- <Calendar mode="range" selected={{ from: new Date(2026, 9, 9), to: new Date(2026, 9, 15) }} />
15
-
16
- # German
17
-
18
- A react-day-picker locale names the months and weekdays and starts the week on its first day.
19
-
20
- <Calendar mode="single" locale={de} selected={new Date(2026, 9, 9)} />
21
-
22
- # Columns first
23
-
24
- `columnsSide="start"` stands the year and month columns before the days.
25
-
26
- <Calendar mode="single" columnsSide="start" selected={new Date(2026, 9, 9)} />
27
-
28
- # Narrow
29
-
30
- Without room for the columns, they turn into strips above the days.
31
-
32
- <div className="w-72 max-w-full">
33
- <Calendar mode="single" selected={new Date(2026, 9, 9)} />
34
- </div>
35
-
36
- # Fixed height
37
-
38
- A height class on the calendar sets its height in both layouts, with the columns beside the days or above them. The calendar needs a bounded height for this: without one every month in the window renders and it opens on the window start.
39
-
40
- <div className="flex flex-wrap items-start gap-4">
41
- <Calendar mode="single" className="h-72" selected={new Date(2026, 9, 9)} />
42
- <div className="w-72 max-w-full">
43
- <Calendar mode="single" className="h-72" selected={new Date(2026, 9, 9)} />
44
- </div>
45
- </div>
@@ -1,370 +0,0 @@
1
- /*
2
- * Local addition (not part of Fluid Functionalism): a scrolling calendar on
3
- * react-day-picker (daypicker.dev), styled through its `classNames` and
4
- * custom components with DS utilities (its stylesheet isn't loaded). Props
5
- * pass through to DayPicker, the way shadcn's Calendar does.
6
- */
7
-
8
- import {
9
- addDays,
10
- addYears,
11
- endOfYear,
12
- format,
13
- isSameYear,
14
- type Locale,
15
- startOfMonth,
16
- startOfWeek,
17
- startOfYear,
18
- } from 'date-fns'
19
- import {
20
- Fragment,
21
- type ReactElement,
22
- type ReactNode,
23
- useCallback,
24
- useEffect,
25
- useLayoutEffect,
26
- useMemo,
27
- useRef,
28
- useState,
29
- } from 'react'
30
- import { type DayButtonProps, DayPicker, type DayPickerProps, type DayProps, type MonthProps } from 'react-day-picker'
31
- import { defaultLocale, fieldLabel } from '../../../../lib/date-locale'
32
- import { dividedColumns, ScrollColumn } from '../../../../lib/scroll-column'
33
- import { useShape } from '../../../../lib/shape-context'
34
- import { type SizeVariant, useSize } from '../../../../lib/size-context'
35
- import { cn } from '../../../../lib/utils'
36
- import { SizeProvider } from '../../../../primitives/sizes'
37
- import { monthKey, useMonthWindow } from './use-month-window'
38
-
39
- const WEEKEND = { dayOfWeek: [0, 6] }
40
-
41
- /** The day picked for the columns' dot and the first scroll: a single date, or a range's start. */
42
- function pickedDate(props: DayPickerProps): Date | undefined {
43
- if (props.mode === 'single') return props.selected
44
- if (props.mode === 'range') return props.selected?.from
45
- return undefined
46
- }
47
-
48
- /** Stamps each month with its key, so the window can find and measure it. */
49
- function Month({ calendarMonth, displayIndex: _, ...props }: MonthProps) {
50
- return <div {...props} data-calendar-month={monthKey(calendarMonth.date)} />
51
- }
52
-
53
- /** The day's cell: draws a range's band behind the pills. */
54
- function Day({ day: _, modifiers, className, ...props }: DayProps) {
55
- const start = modifiers.range_start && !modifiers.range_end
56
- const end = modifiers.range_end && !modifiers.range_start
57
- return (
58
- <td
59
- {...props}
60
- className={cn(
61
- 'relative p-0',
62
- // FF's fills: a committed span is `bg-active` (Checkbox's merged
63
- // rows), the preview one step lighter at `bg-hover`.
64
- !modifiers.hidden && modifiers.range_middle && 'bg-active',
65
- !modifiers.hidden && modifiers.preview && !modifiers.selected && 'bg-hover',
66
- (start || end) && 'before:absolute before:inset-y-0 before:bg-active',
67
- start && 'before:start-1/2 before:end-0',
68
- end && 'before:start-0 before:end-1/2',
69
- className,
70
- )}
71
- />
72
- )
73
- }
74
-
75
- function DayButton({ day: _, modifiers, className, ...props }: DayButtonProps) {
76
- const ref = useRef<HTMLButtonElement>(null)
77
- // DayPicker's own DayButton does this: keyboard focus follows `focused`.
78
- useEffect(() => {
79
- if (modifiers.focused) ref.current?.focus()
80
- }, [modifiers.focused])
81
- const shape = useShape()
82
- const sizeClasses = useSize()
83
- const pill = modifiers.selected && !modifiers.range_middle
84
-
85
- return (
86
- <button
87
- ref={ref}
88
- {...props}
89
- className={cn(
90
- 'relative flex items-center justify-center tabular-nums outline-none cursor-pointer',
91
- 'transition-[color,background-color] duration-fast focus-visible:ring-1 focus-visible:ring-focus-ring',
92
- 'disabled:opacity-50 disabled:cursor-default',
93
- sizeClasses.variant === 'compact' ? 'size-7' : 'size-9',
94
- sizeClasses.text,
95
- shape.item,
96
- // FF keeps red for errors: weekends step back to the muted text.
97
- modifiers.weekend && 'text-muted-foreground',
98
- modifiers.today &&
99
- 'after:absolute after:bottom-1 after:left-1/2 after:size-1 after:-translate-x-1/2 after:rounded-full after:bg-current',
100
- // Foreground is FF's primary (its primary button's fill), text-background on it.
101
- pill ? 'bg-foreground text-background weight-semibold hover:bg-foreground/90' : 'enabled:hover:bg-hover',
102
- className,
103
- )}
104
- />
105
- )
106
- }
107
-
108
- /** The Calendar's own props, beside DayPicker's. */
109
- interface CalendarOwnProps {
110
- /** The locale: a react-day-picker / date-fns locale (`import { de } from 'react-day-picker/locale'`). Names months and weekdays, picks the first day of the week. Defaults to `enUS`. */
111
- locale?: Locale
112
- /** Pins the calendar to one step of the size ladder (36px days, compact 28px). Defaults to the surrounding SizeProvider. */
113
- size?: SizeVariant
114
- /** Which side of the days the month and year columns stand on; the month column keeps next to the days. Defaults to `'end'`. */
115
- columnsSide?: 'start' | 'end'
116
- /** Accessible names of the month and year columns (`{ month, year }`). Default to the locale's names for the fields. */
117
- columnLabels?: { month?: string; year?: string }
118
- /** More columns, given the layout's orientation — the date picker's hours and minutes. */
119
- extraColumns?: (orientation: 'vertical' | 'horizontal') => ReactNode
120
- /** Which side of the days the extra columns stand on, outside the month and year columns when they share it. Defaults to `'end'`. */
121
- extraColumnsSide?: 'start' | 'end'
122
- /** Classes for the calendar's box. */
123
- className?: string
124
- }
125
-
126
- /** DayPicker's props (`mode`, `selected`, `onSelect`, matchers…) and the Calendar's own. */
127
- type CalendarProps = DayPickerProps & CalendarOwnProps
128
-
129
- /**
130
- * A calendar that scrolls through the months instead of paging, with month
131
- * and year columns to jump by.
132
- *
133
- * Months run on in one list, each under its name, with the weekday row pinned
134
- * above them; weekends step back to the muted text and today carries a dot. The month column
135
- * marks the month being read and the year column its year, so either works
136
- * as a scrollbar you can click: a month or a year scrolls the calendar there.
137
- * The picked day, month and year show a filled pill or a dot. The columns
138
- * stand after the days by default; `columnsSide="start"` puts them before
139
- * (and `extraColumnsSide` places any extra ones). When the calendar is too
140
- * narrow for them, they turn into strips above it. The list renders a window of months and moves it as you scroll, so the
141
- * range is as long as `startMonth` / `endMonth` allow (100 years back and 50
142
- * ahead by default).
143
- *
144
- * It is react-day-picker's DayPicker underneath: `mode` (`'single'`,
145
- * `'range'`), `selected` / `onSelect`, `disabled` and `hidden` matchers,
146
- * `modifiers`, `weekStartsOn`, `dir` and the other DayPicker props pass
147
- * through. Its navigation props don't apply: the calendar scrolls.
148
- * DatePicker and DateRangePicker put it in a field.
149
- *
150
- * @example {@include ./examples.mdx}
151
- */
152
- function Calendar({
153
- locale = defaultLocale,
154
- size,
155
- columnsSide = 'end',
156
- columnLabels,
157
- extraColumns,
158
- extraColumnsSide = 'end',
159
- className,
160
- ...props
161
- }: CalendarProps): ReactElement {
162
- const sizeClasses = useSize(size)
163
- const picked = pickedDate(props)
164
- const today = useMemo(() => new Date(), [])
165
- const start = startOfMonth(props.startMonth ?? startOfYear(addYears(today, -100)))
166
- const end = startOfMonth(props.endMonth ?? endOfYear(addYears(today, 50)))
167
- const anchor = picked ?? props.month ?? props.defaultMonth ?? today
168
- const scroll = useMonthWindow(start, end, anchor)
169
- const { jumpTo, visible } = scroll
170
-
171
- // Before the first measure, the month the list opens on.
172
- const currentKey = scroll.current ?? monthKey(anchor)
173
- const yearInView = Number(currentKey.slice(0, 4))
174
- const monthInView = Number(currentKey.slice(5, 7)) - 1
175
-
176
- // A pick from outside the calendar (typed into a picker's field) scrolls to it.
177
- const pickedTime = picked?.getTime()
178
- const pickedRef = useRef(pickedTime)
179
- useEffect(() => {
180
- if (pickedTime === pickedRef.current) return
181
- pickedRef.current = pickedTime
182
- if (pickedTime !== undefined && !visible.includes(monthKey(new Date(pickedTime)))) jumpTo(new Date(pickedTime))
183
- }, [pickedTime, jumpTo, visible])
184
-
185
- // The columns stand beside the grid while they fit, and turn into strips
186
- // above it when they don't. The width they need is remembered, so the
187
- // strips only turn back once there is room again.
188
- const rootRef = useRef<HTMLDivElement>(null)
189
- const [wide, setWide] = useState(true)
190
- const needed = useRef(0)
191
- useLayoutEffect(() => {
192
- const root = rootRef.current
193
- if (!root) return
194
- const check = () => {
195
- if (wide && root.scrollWidth > root.clientWidth + 1) {
196
- needed.current = root.scrollWidth
197
- setWide(false)
198
- } else if (!wide && root.clientWidth >= needed.current) setWide(true)
199
- }
200
- check()
201
- const observer = new ResizeObserver(check)
202
- observer.observe(root)
203
- return () => observer.disconnect()
204
- }, [wide])
205
-
206
- // Turning changes the grid's height: put the picked day (or today) back in the middle.
207
- const turned = useRef(wide)
208
- useLayoutEffect(() => {
209
- if (turned.current === wide) return
210
- turned.current = wide
211
- scroll.centreDay(picked ?? today)
212
- })
213
-
214
- // Range picking previews the span under the pointer before the second click.
215
- const [hovered, setHovered] = useState<Date>()
216
- const from = props.mode === 'range' ? props.selected?.from : undefined
217
- const previewing = from && props.mode === 'range' && !props.selected?.to && hovered
218
- const preview = previewing ? (hovered < from ? { from: hovered, to: from } : { from, to: hovered }) : false
219
-
220
- const weekStartsOn = props.weekStartsOn ?? locale.options?.weekStartsOn ?? 0
221
- const weekdays = useMemo(() => {
222
- const first = startOfWeek(today, { weekStartsOn })
223
- return Array.from({ length: 7 }, (_, i) => addDays(first, i))
224
- }, [today, weekStartsOn])
225
-
226
- const months = useMemo(
227
- () =>
228
- Array.from({ length: 12 }, (_, m) => ({
229
- value: m,
230
- label: format(new Date(2000, m, 1), 'LLL', { locale }),
231
- disabled: new Date(yearInView, m, 1) < start || new Date(yearInView, m, 1) > end,
232
- })),
233
- [locale, yearInView, start.getTime(), end.getTime()],
234
- )
235
- const years = useMemo(
236
- () =>
237
- Array.from({ length: end.getFullYear() - start.getFullYear() + 1 }, (_, i) => {
238
- const year = start.getFullYear() + i
239
- return { value: year, label: String(year) }
240
- }),
241
- [start.getFullYear(), end.getFullYear()],
242
- )
243
-
244
- const jumpToYear = useCallback((year: number) => jumpTo(new Date(year, monthInView, 1)), [jumpTo, monthInView])
245
- const orientation = wide ? 'vertical' : 'horizontal'
246
- const column = wide ? 'w-16 shrink-0' : 'w-full'
247
-
248
- const monthColumn = (
249
- <ScrollColumn
250
- key="month"
251
- label={columnLabels?.month ?? fieldLabel(locale, 'month')}
252
- options={months}
253
- value={picked && isSameYear(picked, new Date(yearInView, 0, 1)) ? picked.getMonth() : null}
254
- follow={monthInView}
255
- inView={m => m === monthInView}
256
- onValueChange={m => jumpTo(new Date(yearInView, m, 1))}
257
- orientation={orientation}
258
- className={column}
259
- />
260
- )
261
- const yearColumn = (
262
- <ScrollColumn
263
- key="year"
264
- label={columnLabels?.year ?? fieldLabel(locale, 'year')}
265
- options={years}
266
- value={picked?.getFullYear() ?? null}
267
- follow={yearInView}
268
- inView={y => y === yearInView}
269
- onValueChange={jumpToYear}
270
- orientation={orientation}
271
- className={column}
272
- />
273
- )
274
- const extras = extraColumns?.(orientation)
275
- // Outward from the days: the month column, the year column, then the extras.
276
- // Keyed fragments, so a side's children keep their identity as the extras come and go.
277
- const extrasPart = extras ? <Fragment key="extras">{extras}</Fragment> : null
278
- const before = [extraColumnsSide === 'start' && extrasPart, columnsSide === 'start' && [yearColumn, monthColumn]]
279
- const after = [columnsSide === 'end' && [monthColumn, yearColumn], extraColumnsSide === 'end' && extrasPart]
280
- const side = (place: 'start' | 'end') =>
281
- wide
282
- ? cn(dividedColumns, 'h-full shrink-0 border-border', place === 'start' ? 'border-e' : 'border-s')
283
- : 'order-first flex w-full flex-col [&>*]:border-b [&>*]:border-border'
284
-
285
- const grid = (
286
- <div className={cn('flex min-h-0 shrink-0 flex-col', wide ? 'h-full' : 'flex-1 self-center')}>
287
- <div aria-hidden className="flex border-b border-border px-1 pb-1">
288
- {weekdays.map(day => (
289
- <span
290
- key={day.getDay()}
291
- className={cn(
292
- 'flex items-center justify-center text-caption',
293
- sizeClasses.variant === 'compact' ? 'w-7' : 'w-9',
294
- 'text-muted-foreground',
295
- )}
296
- >
297
- {format(day, 'EEEEEE', { locale })}
298
- </span>
299
- ))}
300
- </div>
301
- <div
302
- ref={scroll.scrollerRef}
303
- onScroll={scroll.measure}
304
- className="relative min-h-0 flex-1 overflow-y-auto overflow-x-hidden px-1 scrollbar-hide scroll-fade [--scroll-fade-size:16px] [overflow-anchor:none]"
305
- >
306
- <DayPicker
307
- {...props}
308
- locale={locale}
309
- month={scroll.first}
310
- numberOfMonths={scroll.count}
311
- startMonth={start}
312
- endMonth={end}
313
- onMonthChange={scroll.recentre}
314
- hideNavigation
315
- hideWeekdays
316
- showOutsideDays={false}
317
- modifiers={{ weekend: WEEKEND, preview, ...props.modifiers }}
318
- onDayMouseEnter={(date, modifiers, e) => {
319
- setHovered(date)
320
- props.onDayMouseEnter?.(date, modifiers, e)
321
- }}
322
- onDayMouseLeave={(date, modifiers, e) => {
323
- setHovered(undefined)
324
- props.onDayMouseLeave?.(date, modifiers, e)
325
- }}
326
- formatters={{
327
- // The current year's months go by name alone, the rest with their year.
328
- formatCaption: month => format(month, isSameYear(month, today) ? 'LLLL' : 'LLLL y', { locale }),
329
- ...props.formatters,
330
- }}
331
- components={{ Month, Day, DayButton, ...props.components }}
332
- classNames={{
333
- months: 'flex flex-col',
334
- month: 'pb-2',
335
- month_caption: cn(
336
- 'px-2 pt-2 pb-1 text-subtitle weight-semibold',
337
- sizeClasses.variant === 'compact' && 'text-subtitle-compact',
338
- ),
339
- month_grid: 'border-collapse',
340
- ...props.classNames,
341
- }}
342
- />
343
- </div>
344
- </div>
345
- )
346
-
347
- const content = (
348
- <div
349
- ref={rootRef}
350
- dir={props.dir}
351
- className={cn(
352
- 'flex w-max max-w-full overflow-hidden',
353
- wide ? 'h-80 flex-row' : 'h-[min(30rem,65dvh)] flex-col',
354
- className,
355
- )}
356
- >
357
- {/* Strips are reordered by CSS, not in the tree, so turning doesn't remount the grid. */}
358
- {before.some(Boolean) ? <div className={side('start')}>{before}</div> : null}
359
- {grid}
360
- {after.some(Boolean) ? <div className={side('end')}>{after}</div> : null}
361
- </div>
362
- )
363
-
364
- return size ? <SizeProvider size={size}>{content}</SizeProvider> : content
365
- }
366
-
367
- export type { CalendarProps }
368
- export { Calendar }
369
-
370
- export default Calendar
@@ -1,173 +0,0 @@
1
- import { addMonths, differenceInCalendarMonths, format, startOfMonth } from 'date-fns'
2
- import { useCallback, useLayoutEffect, useRef, useState } from 'react'
3
-
4
- /** Months rendered at once, and how far the window moves when the reader nears its edge. */
5
- const WINDOW = 25
6
- const SHIFT = 12
7
-
8
- const monthKey = (date: Date) => format(date, 'yyyy-MM')
9
-
10
- /** A rendered month's element in the scroller (the Calendar's `Month` stamps the key). */
11
- const findMonth = (scroller: HTMLElement, key: string) =>
12
- scroller.querySelector<HTMLElement>(`[data-calendar-month="${key}"]`)
13
-
14
- /** What the next layout pass scrolls to: back to where the reader was, a month's top, or a day in the middle. */
15
- interface Pending {
16
- keep?: { key: string; delta: number }
17
- month?: string
18
- day?: Date
19
- }
20
-
21
- /**
22
- * The calendar's scroll: an endless-feeling list of months between `start` and
23
- * `end` that renders only `WINDOW` of them. Nearing either rendered edge moves
24
- * the window by `SHIFT` months and puts the reader back on the month they were
25
- * reading. Also reports the months in view, for the month and year columns.
26
- */
27
- function useMonthWindow(start: Date, end: Date, anchor: Date) {
28
- const total = differenceInCalendarMonths(end, start) + 1
29
- const count = Math.min(WINDOW, total)
30
- const startTime = start.getTime()
31
-
32
- const clamp = useCallback(
33
- (first: Date) => {
34
- const from = new Date(startTime)
35
- const last = addMonths(from, total - count)
36
- return first < from ? from : first > last ? last : startOfMonth(first)
37
- },
38
- [startTime, total, count],
39
- )
40
-
41
- const [first, setFirst] = useState(() => clamp(addMonths(startOfMonth(anchor), -Math.floor(WINDOW / 2))))
42
- const [visible, setVisible] = useState<string[]>([])
43
- // The month taking up most of the view: the one the columns mark.
44
- const [current, setCurrent] = useState<string>()
45
- const scrollerRef = useRef<HTMLDivElement>(null)
46
- const firstRef = useRef(first)
47
- firstRef.current = first
48
- const pending = useRef<Pending | null>({ day: anchor })
49
- // Set while a smooth jump runs: moving the window under it would cut it short.
50
- const settling = useRef(false)
51
-
52
- const topMonth = useCallback(() => {
53
- const scroller = scrollerRef.current
54
- if (!scroller) return undefined
55
- const top = scroller.scrollTop
56
- return [...scroller.querySelectorAll<HTMLElement>('[data-calendar-month]')].find(
57
- el => el.offsetTop + el.offsetHeight > top,
58
- )
59
- }, [])
60
-
61
- const moveWindow = useCallback(
62
- (nextFirst: Date, target?: string) => {
63
- const next = clamp(nextFirst)
64
- if (next.getTime() === firstRef.current.getTime()) return
65
- const scroller = scrollerRef.current
66
- const top = topMonth()
67
- pending.current = {
68
- month: target,
69
- keep:
70
- scroller && top
71
- ? { key: top.dataset.calendarMonth ?? '', delta: top.offsetTop - scroller.scrollTop }
72
- : undefined,
73
- }
74
- setFirst(next)
75
- },
76
- [clamp, topMonth],
77
- )
78
-
79
- /** Scrolls a rendered day into the middle of the list, at once. */
80
- const centreDay = useCallback((date: Date) => {
81
- const scroller = scrollerRef.current
82
- const day = scroller?.querySelector<HTMLElement>(`[data-day="${format(date, 'yyyy-MM-dd')}"]`)
83
- if (!scroller || !day) return
84
- const s = scroller.getBoundingClientRect()
85
- const d = day.getBoundingClientRect()
86
- // In layout pixels: the panel may still be scaled by its opening morph.
87
- const scale = s.height / scroller.offsetHeight || 1
88
- scroller.scrollTop += (d.top - s.top) / scale - (scroller.clientHeight - day.offsetHeight) / 2
89
- }, [])
90
-
91
- /** Reports the months in view and, when `move` is set, shifts the window if the reader is near its edge. */
92
- const read = useCallback(
93
- (move: boolean) => {
94
- const scroller = scrollerRef.current
95
- if (!scroller) return
96
- const top = scroller.scrollTop
97
- const bottom = top + scroller.clientHeight
98
- const shown = [...scroller.querySelectorAll<HTMLElement>('[data-calendar-month]')]
99
- .map(el => ({
100
- key: el.dataset.calendarMonth ?? '',
101
- height: Math.min(bottom, el.offsetTop + el.offsetHeight) - Math.max(top, el.offsetTop),
102
- }))
103
- .filter(m => m.height > 0)
104
- const inView = shown.map(m => m.key)
105
- setVisible(prev => (prev.join() === inView.join() ? prev : inView))
106
- setCurrent(
107
- shown.reduce<(typeof shown)[number] | undefined>((a, m) => (a && a.height >= m.height ? a : m), undefined)?.key,
108
- )
109
- if (!move || settling.current) return
110
-
111
- // A reader this close to an edge moves the window. The margin is capped well inside what a shift
112
- // gives back, so a list with no height of its own (a height class the stylesheet lacks, `h-auto`)
113
- // can't keep the reader "near" an edge after every move and walk the window to the end of the range.
114
- const margin = Math.min(scroller.clientHeight, scroller.scrollHeight / 4)
115
- if (top < margin) moveWindow(addMonths(firstRef.current, -SHIFT))
116
- else if (scroller.scrollHeight - bottom < margin) moveWindow(addMonths(firstRef.current, SHIFT))
117
- },
118
- [moveWindow],
119
- )
120
- const measure = useCallback(() => read(true), [read])
121
-
122
- // Runs after the window moves (and on mount) to restore the reader's place.
123
- useLayoutEffect(() => {
124
- const scroller = scrollerRef.current
125
- const p = pending.current
126
- pending.current = null
127
- if (!scroller || !p) return
128
- const target = p.month && findMonth(scroller, p.month)
129
- const kept = p.keep && findMonth(scroller, p.keep.key)
130
- if (target) scroller.scrollTop = target.offsetTop
131
- else if (kept && p.keep) scroller.scrollTop = kept.offsetTop - p.keep.delta
132
- else if (p.day) centreDay(p.day)
133
- // Reports only: moving the window from here would nest one update inside the last, and
134
- // the scroll the restore causes calls `measure` for the next shift.
135
- read(false)
136
- }, [first])
137
-
138
- /** Scrolls a month to the top: smoothly when it is rendered, else by moving the window to it. */
139
- const jumpTo = useCallback(
140
- (month: Date, behavior: ScrollBehavior = 'smooth') => {
141
- const scroller = scrollerRef.current
142
- const key = monthKey(month)
143
- const el = scroller && findMonth(scroller, key)
144
- if (!scroller || !el) {
145
- moveWindow(addMonths(startOfMonth(month), -Math.floor(WINDOW / 2)), key)
146
- return
147
- }
148
- if (behavior === 'smooth') {
149
- settling.current = true
150
- const done = () => {
151
- settling.current = false
152
- scroller.removeEventListener('scrollend', done)
153
- measure()
154
- }
155
- scroller.addEventListener('scrollend', done)
156
- // Browsers without `scrollend` (and a jump that doesn't move) still settle.
157
- setTimeout(done, 600)
158
- }
159
- scroller.scrollTo({ top: el.offsetTop, behavior })
160
- },
161
- [measure, moveWindow],
162
- )
163
-
164
- /** Keyboard focus left the window: recentre it on that month and keep the reader's place. */
165
- const recentre = useCallback(
166
- (month: Date) => moveWindow(addMonths(startOfMonth(month), -Math.floor(WINDOW / 2))),
167
- [moveWindow],
168
- )
169
-
170
- return { first, count, visible, current, scrollerRef, measure, jumpTo, recentre, centreDay }
171
- }
172
-
173
- export { monthKey, useMonthWindow }