@12-apps/ui 6.38.0 → 6.39.1

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 (334) hide show
  1. package/dist/_internal/components/data-display/DataGrid/DataGrid.body.js +3 -2
  2. package/dist/_internal/components/data-display/DataGrid/DataGrid.cells.js +2 -1
  3. package/dist/_internal/components/data-display/DataGrid/DataGrid.js +4 -4
  4. package/dist/_internal/components/data-display/DataGrid/DataGrid.model.js +2 -1
  5. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +19 -19
  6. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +26 -26
  7. package/dist/_internal/components/data-display/DataViews/SaveViewModal.js +5 -5
  8. package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +4 -4
  9. package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +3 -3
  10. package/dist/_internal/components/data-display/DataViews/base-list-card.js +5 -5
  11. package/dist/_internal/components/data-display/DataViews/data-views-columns.js +2 -2
  12. package/dist/_internal/components/data-display/DataViews/data-views-display-panel.js +3 -3
  13. package/dist/_internal/components/data-display/DataViews/data-views-display-tabs.js +2 -2
  14. package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +8 -8
  15. package/dist/_internal/components/data-display/DataViews/data-views-grid-helpers.js +1 -1
  16. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +16 -16
  17. package/dist/_internal/components/data-display/DataViews/data-views-layout-context.js +1 -1
  18. package/dist/_internal/components/data-display/DataViews/data-views-overflow-costs.js +4 -3
  19. package/dist/_internal/components/data-display/DataViews/data-views-overflow.js +3 -2
  20. package/dist/_internal/components/data-display/DataViews/data-views-scope-tabs.js +2 -2
  21. package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +6 -6
  22. package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +6 -6
  23. package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +5 -5
  24. package/dist/_internal/components/data-display/DataViews/list-card-rails.js +2 -2
  25. package/dist/_internal/components/data-display/DataViews/use-data-views-state.js +3 -3
  26. package/dist/_internal/components/data-display/FleetMap/FleetBody.js +9 -9
  27. package/dist/_internal/components/data-display/FleetMap/FleetCanvas.js +8 -8
  28. package/dist/_internal/components/data-display/FleetMap/FleetMap.js +10 -10
  29. package/dist/_internal/components/data-display/LazyImage/LazyImage.js +1 -1
  30. package/dist/_internal/components/data-display/MapPreview/MapDecorations.js +2 -2
  31. package/dist/_internal/components/data-display/MapPreview/MapPreview.hooks.js +2 -2
  32. package/dist/_internal/components/data-display/MapPreview/MapPreview.js +7 -7
  33. package/dist/_internal/components/data-display/MapPreview/MapTiles.js +2 -2
  34. package/dist/_internal/components/data-display/MapPreview/StaticMapView.js +4 -4
  35. package/dist/_internal/components/data-display/MapPreview/mapProjection.js +3 -3
  36. package/dist/_internal/components/data-display/MapPreview/useMapPreview.js +3 -3
  37. package/dist/_internal/components/data-display/Table/Table.helpers.js +5 -3
  38. package/dist/_internal/components/data-display/Table/Table.hooks.js +2 -1
  39. package/dist/_internal/components/data-display/Table/Table.js +4 -4
  40. package/dist/_internal/components/data-display/Table/TableParts.hooks.js +4 -2
  41. package/dist/_internal/components/data-display/Table/TableParts.js +4 -2
  42. package/dist/_internal/components/data-display/index.js +19 -19
  43. package/dist/_internal/components/form/Calendar/Calendar.js +5 -4
  44. package/dist/_internal/components/form/Calendar/CalendarDay.js +2 -1
  45. package/dist/_internal/components/form/Calendar/CalendarDayCell.js +3 -2
  46. package/dist/_internal/components/form/Calendar/CalendarMonth.js +4 -3
  47. package/dist/_internal/components/form/DateRangePicker/DateRangePicker.js +5 -5
  48. package/dist/_internal/components/form/Switch/Switch.js +4 -4
  49. package/dist/_internal/components/form/Switch/Switch.metrics.js +5 -1
  50. package/dist/_internal/components/form/Switch/Switch.parts.js +3 -3
  51. package/dist/_internal/components/form/Switch/Switch.styles.js +2 -2
  52. package/dist/_internal/components/form/index.js +9 -9
  53. package/dist/_internal/components/index.js +38 -38
  54. package/dist/_internal/components/layout/CardGrid/CardGrid.js +2 -1
  55. package/dist/_internal/components/layout/Resizable/Resizable.helpers.js +8 -3
  56. package/dist/_internal/components/layout/Resizable/Resizable.hooks.js +3 -2
  57. package/dist/_internal/components/layout/Resizable/Resizable.js +4 -3
  58. package/dist/_internal/components/layout/ScrollArea/ScrollArea.helpers.js +1 -1
  59. package/dist/_internal/components/layout/ScrollArea/ScrollArea.js +2 -2
  60. package/dist/_internal/components/layout/index.js +5 -5
  61. package/dist/_internal/components/utility/InfiniteScroll/InfiniteScroll.hooks.js +1 -1
  62. package/dist/_internal/components/utility/InfiniteScroll/InfiniteScroll.js +4 -3
  63. package/dist/_internal/components/utility/InfiniteScroll/InfiniteScroll.parts.js +2 -1
  64. package/dist/_internal/components/utility/VirtualList/VirtualList.hooks.js +6 -3
  65. package/dist/_internal/components/utility/VirtualList/VirtualList.js +3 -2
  66. package/dist/_internal/components/utility/index.js +5 -5
  67. package/dist/{chunk-J2DAQQQH.js → chunk-222HN7GK.js} +33 -64
  68. package/dist/chunk-222HN7GK.js.map +1 -0
  69. package/dist/{chunk-MR2HKBHS.js → chunk-27LOJVR3.js} +2 -2
  70. package/dist/{chunk-S3D5VBHW.js → chunk-3YOXVNO4.js} +7 -7
  71. package/dist/{chunk-CZIX4BW2.js → chunk-4ALF5PB5.js} +3 -3
  72. package/dist/{chunk-XJPJ6ESI.js → chunk-4OAKGKK5.js} +3 -3
  73. package/dist/{chunk-4CHROSWR.js → chunk-5ETBB2DG.js} +2 -2
  74. package/dist/{chunk-ATSHKSSD.js → chunk-5KNDAC24.js} +20 -7
  75. package/dist/chunk-5KNDAC24.js.map +1 -0
  76. package/dist/{chunk-ULTOQ6ZV.js → chunk-5LWB4BYX.js} +80 -89
  77. package/dist/chunk-5LWB4BYX.js.map +1 -0
  78. package/dist/{chunk-46UPILLK.js → chunk-5NT2M2JI.js} +2 -2
  79. package/dist/{chunk-H5BEWPEY.js → chunk-6N2EDWMG.js} +2 -2
  80. package/dist/{chunk-GJQYM3PM.js → chunk-6PU3JYVY.js} +2 -2
  81. package/dist/{chunk-PUBPZOQJ.js → chunk-AG3DY5TH.js} +8 -5
  82. package/dist/chunk-AG3DY5TH.js.map +1 -0
  83. package/dist/{chunk-PPRV4LTM.js → chunk-BWHOCNGW.js} +4 -4
  84. package/dist/chunk-BWHOCNGW.js.map +1 -0
  85. package/dist/{chunk-TUBCN4DJ.js → chunk-CB6DTWD5.js} +7 -7
  86. package/dist/chunk-CB6DTWD5.js.map +1 -0
  87. package/dist/{chunk-ZAY6OA6F.js → chunk-D4FZ3ANG.js} +15 -5
  88. package/dist/chunk-D4FZ3ANG.js.map +1 -0
  89. package/dist/{chunk-Y7F5JBAT.js → chunk-DDRKYNPB.js} +2 -2
  90. package/dist/{chunk-DLJGBJZW.js → chunk-DGMDQHMI.js} +16 -9
  91. package/dist/chunk-DGMDQHMI.js.map +1 -0
  92. package/dist/{chunk-IAGOUTI6.js → chunk-DNT5PZLF.js} +21 -12
  93. package/dist/chunk-DNT5PZLF.js.map +1 -0
  94. package/dist/{chunk-DZA7RSLX.js → chunk-DVSO3EG6.js} +19 -11
  95. package/dist/chunk-DVSO3EG6.js.map +1 -0
  96. package/dist/{chunk-OS6KPL4D.js → chunk-EHYI2WCJ.js} +4 -4
  97. package/dist/{chunk-NB3FGWU4.js → chunk-EQXIW5MQ.js} +2 -2
  98. package/dist/{chunk-C66RGVAS.js → chunk-ERY6D2OV.js} +6 -4
  99. package/dist/chunk-ERY6D2OV.js.map +1 -0
  100. package/dist/{chunk-M2JTIH5M.js → chunk-F44R7US6.js} +2 -2
  101. package/dist/{chunk-AROBXRC5.js → chunk-F7JTIHV5.js} +18 -7
  102. package/dist/chunk-F7JTIHV5.js.map +1 -0
  103. package/dist/{chunk-T7DE44SP.js → chunk-FF2D7V7T.js} +6 -4
  104. package/dist/chunk-FF2D7V7T.js.map +1 -0
  105. package/dist/{chunk-XJJXBUPN.js → chunk-FX26DAFF.js} +2 -2
  106. package/dist/{chunk-R6SN73RX.js → chunk-GLHNMTP6.js} +7 -7
  107. package/dist/{chunk-YU26GBNX.js → chunk-H3AQQOTI.js} +9 -4
  108. package/dist/chunk-H3AQQOTI.js.map +1 -0
  109. package/dist/{chunk-HTZNB6IV.js → chunk-H5ZTIELC.js} +23 -8
  110. package/dist/chunk-H5ZTIELC.js.map +1 -0
  111. package/dist/{chunk-GSFNH4C5.js → chunk-HBP2OU4Q.js} +15 -8
  112. package/dist/chunk-HBP2OU4Q.js.map +1 -0
  113. package/dist/{chunk-I4QA2F4L.js → chunk-HBRQPG7H.js} +5 -5
  114. package/dist/{chunk-HGMBY5LP.js → chunk-HQWJUHR4.js} +18 -11
  115. package/dist/chunk-HQWJUHR4.js.map +1 -0
  116. package/dist/{chunk-CNQUCNEA.js → chunk-I3F4C5SS.js} +3 -3
  117. package/dist/{chunk-UFJYJHQI.js → chunk-J5VWGQSR.js} +2 -2
  118. package/dist/{chunk-MTFCPPZ5.js → chunk-JWZJSXI5.js} +3 -2
  119. package/dist/chunk-JWZJSXI5.js.map +1 -0
  120. package/dist/{chunk-4JFL62K3.js → chunk-K7FSTB2K.js} +3 -3
  121. package/dist/{chunk-FFCJ7NR2.js → chunk-KRQUPE4K.js} +4 -4
  122. package/dist/{chunk-2OYFTSG4.js → chunk-KXLUMEDX.js} +2 -2
  123. package/dist/{chunk-DVAAUWTC.js → chunk-LCHCE2G5.js} +2 -2
  124. package/dist/{chunk-G4HBNILE.js → chunk-LEHMWJNZ.js} +3 -3
  125. package/dist/{chunk-P6TNXBDA.js → chunk-MYKWJCR7.js} +9 -9
  126. package/dist/chunk-MYKWJCR7.js.map +1 -0
  127. package/dist/{chunk-TQ6FPOPD.js → chunk-ODW2D5PN.js} +39 -30
  128. package/dist/chunk-ODW2D5PN.js.map +1 -0
  129. package/dist/{chunk-RZYSKQTS.js → chunk-PCBZYORN.js} +3 -3
  130. package/dist/{chunk-5OBXEMQO.js → chunk-PRIBOWX4.js} +3 -3
  131. package/dist/{chunk-F42MJOHM.js → chunk-PVM7XTLZ.js} +64 -62
  132. package/dist/chunk-PVM7XTLZ.js.map +1 -0
  133. package/dist/{chunk-3TDVGZZN.js → chunk-QBTBRJ2Q.js} +37 -13
  134. package/dist/chunk-QBTBRJ2Q.js.map +1 -0
  135. package/dist/{chunk-2WFDHFK4.js → chunk-QNCWSDXE.js} +26 -11
  136. package/dist/chunk-QNCWSDXE.js.map +1 -0
  137. package/dist/{chunk-PQECNGDE.js → chunk-QSRZOXQI.js} +2 -2
  138. package/dist/{chunk-RHIDWUK7.js → chunk-QUWK7SYN.js} +1 -2
  139. package/dist/chunk-QUWK7SYN.js.map +1 -0
  140. package/dist/{chunk-UN5INW6K.js → chunk-R53ZOW4B.js} +8 -4
  141. package/dist/chunk-R53ZOW4B.js.map +1 -0
  142. package/dist/{chunk-DCJSHYE5.js → chunk-RSDYS5B3.js} +4 -4
  143. package/dist/{chunk-N5GVW6RO.js → chunk-S6IWKDWT.js} +2 -2
  144. package/dist/{chunk-TKC6WHGB.js → chunk-SBIZXZPP.js} +2 -2
  145. package/dist/{chunk-D5SZXH7Q.js → chunk-TNBJ4DK4.js} +7 -3
  146. package/dist/chunk-TNBJ4DK4.js.map +1 -0
  147. package/dist/{chunk-PMOEG36E.js → chunk-XZJM6EPC.js} +8 -6
  148. package/dist/chunk-XZJM6EPC.js.map +1 -0
  149. package/dist/{chunk-QF6LTUCE.js → chunk-Y2X7LYIN.js} +4 -4
  150. package/dist/chunk-Y2X7LYIN.js.map +1 -0
  151. package/dist/{chunk-UEVHI62V.js → chunk-YCCY77W5.js} +2 -2
  152. package/dist/{chunk-DF4K5XVW.js → chunk-YZVR5ROE.js} +14 -6
  153. package/dist/chunk-YZVR5ROE.js.map +1 -0
  154. package/dist/{chunk-AUSUCZYR.js → chunk-ZBVU2YWV.js} +5 -5
  155. package/dist/chunk-ZBVU2YWV.js.map +1 -0
  156. package/dist/{chunk-VZIB5W5L.js → chunk-ZGCPDA3F.js} +2 -2
  157. package/dist/data-display/DataGrid.js +4 -4
  158. package/dist/data-display/DataViews.js +29 -29
  159. package/dist/data-display/FleetMap.js +10 -10
  160. package/dist/data-display/LazyImage.js +1 -1
  161. package/dist/data-display/MapPreview.js +7 -7
  162. package/dist/data-display/Table.js +4 -4
  163. package/dist/form/Calendar.js +5 -4
  164. package/dist/form/DateRangePicker.js +5 -5
  165. package/dist/form/Switch.js +4 -4
  166. package/dist/layout/CardGrid.js +2 -1
  167. package/dist/layout/Resizable.js +4 -3
  168. package/dist/layout/ScrollArea.js +2 -2
  169. package/dist/native/form/Switch.js +3 -1
  170. package/dist/native/form/Switch.js.map +1 -1
  171. package/dist/types/components/data-display/DataGrid/DataGrid.body.d.ts.map +1 -1
  172. package/dist/types/components/data-display/DataGrid/DataGrid.cells.d.ts +4 -2
  173. package/dist/types/components/data-display/DataGrid/DataGrid.cells.d.ts.map +1 -1
  174. package/dist/types/components/data-display/DataGrid/DataGrid.model.d.ts +7 -1
  175. package/dist/types/components/data-display/DataGrid/DataGrid.model.d.ts.map +1 -1
  176. package/dist/types/components/data-display/DataGrid/DataGrid.types.d.ts +10 -4
  177. package/dist/types/components/data-display/DataGrid/DataGrid.types.d.ts.map +1 -1
  178. package/dist/types/components/data-display/DataViews/data-views-columns.d.ts.map +1 -1
  179. package/dist/types/components/data-display/DataViews/data-views-grid-helpers.d.ts +2 -0
  180. package/dist/types/components/data-display/DataViews/data-views-grid-helpers.d.ts.map +1 -1
  181. package/dist/types/components/data-display/DataViews/data-views-layout-context.d.ts +7 -3
  182. package/dist/types/components/data-display/DataViews/data-views-layout-context.d.ts.map +1 -1
  183. package/dist/types/components/data-display/DataViews/data-views-overflow-costs.d.ts +19 -9
  184. package/dist/types/components/data-display/DataViews/data-views-overflow-costs.d.ts.map +1 -1
  185. package/dist/types/components/data-display/DataViews/data-views-overflow.d.ts.map +1 -1
  186. package/dist/types/components/data-display/LazyImage/LazyImage.d.ts.map +1 -1
  187. package/dist/types/components/data-display/LazyImage/LazyImage.types.d.ts +3 -1
  188. package/dist/types/components/data-display/LazyImage/LazyImage.types.d.ts.map +1 -1
  189. package/dist/types/components/data-display/MapPreview/MapTiles.d.ts.map +1 -1
  190. package/dist/types/components/data-display/MapPreview/mapProjection.d.ts +6 -1
  191. package/dist/types/components/data-display/MapPreview/mapProjection.d.ts.map +1 -1
  192. package/dist/types/components/data-display/Table/Table.helpers.d.ts +6 -0
  193. package/dist/types/components/data-display/Table/Table.helpers.d.ts.map +1 -1
  194. package/dist/types/components/data-display/Table/Table.hooks.d.ts +9 -1
  195. package/dist/types/components/data-display/Table/Table.hooks.d.ts.map +1 -1
  196. package/dist/types/components/data-display/Table/Table.types.d.ts +6 -2
  197. package/dist/types/components/data-display/Table/Table.types.d.ts.map +1 -1
  198. package/dist/types/components/data-display/Table/TableParts.d.ts +2 -0
  199. package/dist/types/components/data-display/Table/TableParts.d.ts.map +1 -1
  200. package/dist/types/components/form/Calendar/Calendar.d.ts.map +1 -1
  201. package/dist/types/components/form/Calendar/CalendarDay.d.ts.map +1 -1
  202. package/dist/types/components/form/Calendar/CalendarMonth.d.ts.map +1 -1
  203. package/dist/types/components/form/Switch/Switch.metrics.d.ts +13 -3
  204. package/dist/types/components/form/Switch/Switch.metrics.d.ts.map +1 -1
  205. package/dist/types/components/form/Switch/Switch.styles.d.ts.map +1 -1
  206. package/dist/types/components/layout/CardGrid/CardGrid.d.ts +9 -7
  207. package/dist/types/components/layout/CardGrid/CardGrid.d.ts.map +1 -1
  208. package/dist/types/components/layout/Resizable/Resizable.d.ts.map +1 -1
  209. package/dist/types/components/layout/Resizable/Resizable.helpers.d.ts +21 -9
  210. package/dist/types/components/layout/Resizable/Resizable.helpers.d.ts.map +1 -1
  211. package/dist/types/components/layout/Resizable/Resizable.hooks.d.ts +13 -3
  212. package/dist/types/components/layout/Resizable/Resizable.hooks.d.ts.map +1 -1
  213. package/dist/types/components/layout/Resizable/Resizable.types.d.ts +10 -0
  214. package/dist/types/components/layout/Resizable/Resizable.types.d.ts.map +1 -1
  215. package/dist/types/components/layout/ScrollArea/ScrollArea.d.ts.map +1 -1
  216. package/dist/types/components/layout/ScrollArea/ScrollArea.helpers.d.ts +1 -1
  217. package/dist/types/components/layout/ScrollArea/ScrollArea.helpers.d.ts.map +1 -1
  218. package/dist/types/components/layout/ScrollArea/ScrollArea.types.d.ts +4 -1
  219. package/dist/types/components/layout/ScrollArea/ScrollArea.types.d.ts.map +1 -1
  220. package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.d.ts.map +1 -1
  221. package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.hooks.d.ts +3 -2
  222. package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.hooks.d.ts.map +1 -1
  223. package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.parts.d.ts +3 -2
  224. package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.parts.d.ts.map +1 -1
  225. package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.types.d.ts +9 -0
  226. package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.types.d.ts.map +1 -1
  227. package/dist/types/components/utility/VirtualList/VirtualList.d.ts.map +1 -1
  228. package/dist/types/components/utility/VirtualList/VirtualList.hooks.d.ts +24 -28
  229. package/dist/types/components/utility/VirtualList/VirtualList.hooks.d.ts.map +1 -1
  230. package/dist/types/components/utility/VirtualList/VirtualList.types.d.ts +17 -0
  231. package/dist/types/components/utility/VirtualList/VirtualList.types.d.ts.map +1 -1
  232. package/dist/types-native/components/form/Switch/Switch.metrics.d.ts +13 -3
  233. package/dist/types-native/components/form/Switch/Switch.metrics.d.ts.map +1 -1
  234. package/dist/utility/InfiniteScroll.js +4 -3
  235. package/dist/utility/VirtualList.js +3 -2
  236. package/package.json +1 -1
  237. package/src/components/data-display/DataGrid/DataGrid.body.tsx +27 -7
  238. package/src/components/data-display/DataGrid/DataGrid.cells.tsx +33 -9
  239. package/src/components/data-display/DataGrid/DataGrid.model.ts +24 -11
  240. package/src/components/data-display/DataGrid/DataGrid.types.ts +12 -6
  241. package/src/components/data-display/DataViews/data-views-columns.ts +14 -3
  242. package/src/components/data-display/DataViews/data-views-grid-helpers.tsx +5 -3
  243. package/src/components/data-display/DataViews/data-views-layout-context.tsx +12 -9
  244. package/src/components/data-display/DataViews/data-views-overflow-costs.ts +32 -14
  245. package/src/components/data-display/DataViews/data-views-overflow.ts +40 -26
  246. package/src/components/data-display/LazyImage/LazyImage.tsx +5 -3
  247. package/src/components/data-display/LazyImage/LazyImage.types.ts +3 -1
  248. package/src/components/data-display/MapPreview/MapTiles.tsx +16 -9
  249. package/src/components/data-display/MapPreview/mapProjection.ts +10 -5
  250. package/src/components/data-display/Table/Table.helpers.ts +7 -1
  251. package/src/components/data-display/Table/Table.hooks.ts +16 -5
  252. package/src/components/data-display/Table/Table.types.ts +6 -2
  253. package/src/components/data-display/Table/TableParts.tsx +38 -42
  254. package/src/components/form/Calendar/Calendar.tsx +4 -2
  255. package/src/components/form/Calendar/CalendarDay.tsx +6 -3
  256. package/src/components/form/Calendar/CalendarMonth.tsx +6 -3
  257. package/src/components/form/Switch/Switch.metrics.ts +19 -5
  258. package/src/components/form/Switch/Switch.styles.ts +5 -3
  259. package/src/components/layout/CardGrid/CardGrid.tsx +37 -24
  260. package/src/components/layout/Resizable/Resizable.helpers.ts +43 -21
  261. package/src/components/layout/Resizable/Resizable.hooks.ts +17 -9
  262. package/src/components/layout/Resizable/Resizable.md +9 -5
  263. package/src/components/layout/Resizable/Resizable.tsx +20 -8
  264. package/src/components/layout/Resizable/Resizable.types.ts +10 -0
  265. package/src/components/layout/ScrollArea/ScrollArea.helpers.ts +0 -2
  266. package/src/components/layout/ScrollArea/ScrollArea.tsx +5 -3
  267. package/src/components/layout/ScrollArea/ScrollArea.types.ts +4 -1
  268. package/src/components/utility/InfiniteScroll/InfiniteScroll.hooks.ts +5 -4
  269. package/src/components/utility/InfiniteScroll/InfiniteScroll.parts.tsx +29 -12
  270. package/src/components/utility/InfiniteScroll/InfiniteScroll.tsx +11 -5
  271. package/src/components/utility/InfiniteScroll/InfiniteScroll.types.ts +10 -2
  272. package/src/components/utility/VirtualList/VirtualList.hooks.ts +101 -112
  273. package/src/components/utility/VirtualList/VirtualList.tsx +36 -65
  274. package/src/components/utility/VirtualList/VirtualList.types.ts +20 -3
  275. package/dist/chunk-2WFDHFK4.js.map +0 -1
  276. package/dist/chunk-3TDVGZZN.js.map +0 -1
  277. package/dist/chunk-AROBXRC5.js.map +0 -1
  278. package/dist/chunk-ATSHKSSD.js.map +0 -1
  279. package/dist/chunk-AUSUCZYR.js.map +0 -1
  280. package/dist/chunk-C66RGVAS.js.map +0 -1
  281. package/dist/chunk-D5SZXH7Q.js.map +0 -1
  282. package/dist/chunk-DF4K5XVW.js.map +0 -1
  283. package/dist/chunk-DLJGBJZW.js.map +0 -1
  284. package/dist/chunk-DZA7RSLX.js.map +0 -1
  285. package/dist/chunk-F42MJOHM.js.map +0 -1
  286. package/dist/chunk-GSFNH4C5.js.map +0 -1
  287. package/dist/chunk-HGMBY5LP.js.map +0 -1
  288. package/dist/chunk-HTZNB6IV.js.map +0 -1
  289. package/dist/chunk-IAGOUTI6.js.map +0 -1
  290. package/dist/chunk-J2DAQQQH.js.map +0 -1
  291. package/dist/chunk-MTFCPPZ5.js.map +0 -1
  292. package/dist/chunk-P6TNXBDA.js.map +0 -1
  293. package/dist/chunk-PMOEG36E.js.map +0 -1
  294. package/dist/chunk-PPRV4LTM.js.map +0 -1
  295. package/dist/chunk-PUBPZOQJ.js.map +0 -1
  296. package/dist/chunk-QF6LTUCE.js.map +0 -1
  297. package/dist/chunk-RHIDWUK7.js.map +0 -1
  298. package/dist/chunk-T7DE44SP.js.map +0 -1
  299. package/dist/chunk-TQ6FPOPD.js.map +0 -1
  300. package/dist/chunk-TUBCN4DJ.js.map +0 -1
  301. package/dist/chunk-ULTOQ6ZV.js.map +0 -1
  302. package/dist/chunk-UN5INW6K.js.map +0 -1
  303. package/dist/chunk-YU26GBNX.js.map +0 -1
  304. package/dist/chunk-ZAY6OA6F.js.map +0 -1
  305. /package/dist/{chunk-MR2HKBHS.js.map → chunk-27LOJVR3.js.map} +0 -0
  306. /package/dist/{chunk-S3D5VBHW.js.map → chunk-3YOXVNO4.js.map} +0 -0
  307. /package/dist/{chunk-CZIX4BW2.js.map → chunk-4ALF5PB5.js.map} +0 -0
  308. /package/dist/{chunk-XJPJ6ESI.js.map → chunk-4OAKGKK5.js.map} +0 -0
  309. /package/dist/{chunk-4CHROSWR.js.map → chunk-5ETBB2DG.js.map} +0 -0
  310. /package/dist/{chunk-46UPILLK.js.map → chunk-5NT2M2JI.js.map} +0 -0
  311. /package/dist/{chunk-H5BEWPEY.js.map → chunk-6N2EDWMG.js.map} +0 -0
  312. /package/dist/{chunk-GJQYM3PM.js.map → chunk-6PU3JYVY.js.map} +0 -0
  313. /package/dist/{chunk-Y7F5JBAT.js.map → chunk-DDRKYNPB.js.map} +0 -0
  314. /package/dist/{chunk-OS6KPL4D.js.map → chunk-EHYI2WCJ.js.map} +0 -0
  315. /package/dist/{chunk-NB3FGWU4.js.map → chunk-EQXIW5MQ.js.map} +0 -0
  316. /package/dist/{chunk-M2JTIH5M.js.map → chunk-F44R7US6.js.map} +0 -0
  317. /package/dist/{chunk-XJJXBUPN.js.map → chunk-FX26DAFF.js.map} +0 -0
  318. /package/dist/{chunk-R6SN73RX.js.map → chunk-GLHNMTP6.js.map} +0 -0
  319. /package/dist/{chunk-I4QA2F4L.js.map → chunk-HBRQPG7H.js.map} +0 -0
  320. /package/dist/{chunk-CNQUCNEA.js.map → chunk-I3F4C5SS.js.map} +0 -0
  321. /package/dist/{chunk-UFJYJHQI.js.map → chunk-J5VWGQSR.js.map} +0 -0
  322. /package/dist/{chunk-4JFL62K3.js.map → chunk-K7FSTB2K.js.map} +0 -0
  323. /package/dist/{chunk-FFCJ7NR2.js.map → chunk-KRQUPE4K.js.map} +0 -0
  324. /package/dist/{chunk-2OYFTSG4.js.map → chunk-KXLUMEDX.js.map} +0 -0
  325. /package/dist/{chunk-DVAAUWTC.js.map → chunk-LCHCE2G5.js.map} +0 -0
  326. /package/dist/{chunk-G4HBNILE.js.map → chunk-LEHMWJNZ.js.map} +0 -0
  327. /package/dist/{chunk-RZYSKQTS.js.map → chunk-PCBZYORN.js.map} +0 -0
  328. /package/dist/{chunk-5OBXEMQO.js.map → chunk-PRIBOWX4.js.map} +0 -0
  329. /package/dist/{chunk-PQECNGDE.js.map → chunk-QSRZOXQI.js.map} +0 -0
  330. /package/dist/{chunk-DCJSHYE5.js.map → chunk-RSDYS5B3.js.map} +0 -0
  331. /package/dist/{chunk-N5GVW6RO.js.map → chunk-S6IWKDWT.js.map} +0 -0
  332. /package/dist/{chunk-TKC6WHGB.js.map → chunk-SBIZXZPP.js.map} +0 -0
  333. /package/dist/{chunk-UEVHI62V.js.map → chunk-YCCY77W5.js.map} +0 -0
  334. /package/dist/{chunk-VZIB5W5L.js.map → chunk-ZGCPDA3F.js.map} +0 -0
@@ -6,12 +6,15 @@ import Typography from '@mui/material/Typography/index.js';
6
6
  import type { FC } from 'react';
7
7
  import React from 'react';
8
8
 
9
+ import { sxRem } from '../../../tokens/relative';
10
+
9
11
  import { getMonthName } from './Calendar.dates';
10
12
  import type { CalendarProps, MonthMatrix } from './Calendar.types';
11
13
  import type { DayCellContext } from './CalendarDayCell';
12
14
  import { CalendarDayCell } from './CalendarDayCell';
13
15
 
14
- const SPACER_WIDTH = 32;
16
+ /** The nav spacer's width and the weekday row's height, 32 design px through the type scale. */
17
+ const SPACER_WIDTH = sxRem(32);
15
18
 
16
19
  const GRID_SX = { display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 0.5 } as const;
17
20
 
@@ -66,7 +69,7 @@ const WeekdayHeader: FC<{ weekdayNames: string[] }> = ({ weekdayNames }) => (
66
69
  alignItems: 'center',
67
70
  justifyContent: 'center',
68
71
  height: SPACER_WIDTH,
69
- fontSize: '0.875rem',
72
+ fontSize: sxRem(14),
70
73
  fontWeight: 'bold',
71
74
  color: 'text.secondary',
72
75
  }}
@@ -109,7 +112,7 @@ export const CalendarMonth: FC<CalendarMonthProps> = ({
109
112
  January's 5th and February's. Without a per-month hook a test can only
110
113
  reach a day positionally, which is exactly what the flakiness gate
111
114
  refuses. Additive: `calendar-grid` below is unchanged. */
112
- <Box sx={{ minWidth: 280 }} data-testid={`calendar-month-${monthIndex}`}>
115
+ <Box sx={{ minWidth: sxRem(280) }} data-testid={`calendar-month-${monthIndex}`}>
113
116
  <MonthNavHeader
114
117
  title={title}
115
118
  showPrevious={monthIndex === 0}
@@ -87,12 +87,26 @@ export const MUI_SHADOWS: Record<number, string> = {
87
87
  3: ELEVATION_SHADOWS[3],
88
88
  };
89
89
 
90
- /** The iOS thumb's own three-layer shadow, which the web writes out literally. */
91
- export const IOS_THUMB_SHADOW = `0 3px 1px 0 ${alpha(SWITCH_BLACK, 0.04)}, 0 3px 8px 0 ${alpha(SWITCH_BLACK, 0.12)}, 0 1px 0 0 ${alpha(SWITCH_BLACK, 0.08)}`;
90
+ /**
91
+ * How a shadow builder writes one of its lengths. Native takes the px as they
92
+ * stand ({@link AS_PX}); the web hands in its type scale (`rem`), so the iOS
93
+ * shadows scale with the theme like every other length it draws.
94
+ */
95
+ export type ShadowLength = (px: number) => string;
96
+
97
+ /** A length written as the px it was drawn at — what native reads. */
98
+ export const AS_PX: ShadowLength = (value) => `${value}px`;
99
+
100
+ /** The iOS thumb's own three-layer shadow. */
101
+ export const iosThumbShadow = (length: ShadowLength = AS_PX): string =>
102
+ `0 ${length(3)} ${length(1)} 0 ${alpha(SWITCH_BLACK, 0.04)}, 0 ${length(3)} ${length(8)} 0 ${alpha(SWITCH_BLACK, 0.12)}, 0 ${length(1)} 0 0 ${alpha(SWITCH_BLACK, 0.08)}`;
103
+
104
+ /** {@link iosThumbShadow} in px, as native draws it. */
105
+ export const IOS_THUMB_SHADOW = iosThumbShadow();
92
106
 
93
- /** The iOS track's inset hairline. */
94
- export const iosTrackShadow = (): string =>
95
- `inset 0 0 0 0.5px ${alpha(SWITCH_BLACK, 0.1)}, inset 0 2px 3px ${alpha(SWITCH_BLACK, 0.12)}`;
107
+ /** The iOS track's inset hairline and inner shade. */
108
+ export const iosTrackShadow = (length: ShadowLength = AS_PX): string =>
109
+ `inset 0 0 0 ${length(0.5)} ${alpha(SWITCH_BLACK, 0.1)}, inset 0 ${length(2)} ${length(3)} ${alpha(SWITCH_BLACK, 0.12)}`;
96
110
 
97
111
  /** The resting track: a black wash on iOS, the disabled ink elsewhere. */
98
112
  export const TRACK_ALPHA = { ios: 0.1, android: 0.2, other: 0.3 } as const;
@@ -12,7 +12,6 @@ import {
12
12
  import {
13
13
  DISABLED,
14
14
  IOS_BASE_OFFSET,
15
- IOS_THUMB_SHADOW,
16
15
  IOS_TRAVEL_INSET,
17
16
  SWITCH_GLASS,
18
17
  SWITCH_GLOW,
@@ -30,6 +29,7 @@ import {
30
29
  TRACK_LABEL,
31
30
  TRACK_RADIUS,
32
31
  geometryOf,
32
+ iosThumbShadow,
33
33
  iosTrackShadow,
34
34
  lookOf,
35
35
  seconds,
@@ -108,7 +108,9 @@ const lengthOrPercent = (theme: Theme, value: number | string): string =>
108
108
  typeof value === 'number' ? rem(theme, value) : value;
109
109
 
110
110
  const thumbShadow = (theme: Theme, look: SwitchLook): string =>
111
- look === 'ios' ? IOS_THUMB_SHADOW : (theme.shadows[THUMB_ELEVATION[look]] ?? 'none');
111
+ look === 'ios'
112
+ ? iosThumbShadow((px) => rem(theme, px))
113
+ : (theme.shadows[THUMB_ELEVATION[look]] ?? 'none');
112
114
 
113
115
  /** The ripple that expands from the thumb on hover. */
114
116
  const rippleOverlay = (palette: ColorPalette): CSSObject => ({
@@ -356,7 +358,7 @@ const trackSx = (
356
358
  opacity: 1,
357
359
  transition: `all ${seconds(SWITCH_TRANSITION.ms)} ${SWITCH_TRANSITION.easing}`,
358
360
  position: 'relative',
359
- boxShadow: look === 'ios' ? iosTrackShadow() : 'none',
361
+ boxShadow: look === 'ios' ? iosTrackShadow((px) => rem(theme, px)) : 'none',
360
362
  ...(glass && {
361
363
  backgroundColor: alpha(theme.palette.background.paper, SWITCH_GLASS.trackAlpha),
362
364
  backdropFilter: `blur(${rem(theme, SWITCH_GLASS.trackBlur)})`,
@@ -1,11 +1,13 @@
1
+ import { useTheme, type Theme } from "@mui/material/styles/index.js";
1
2
  import { Children, type CSSProperties, type ReactNode, type Ref } from "react";
2
3
 
4
+ import { rem } from "../../../tokens/relative";
3
5
  import { cn } from "../../../utils/cn";
4
6
 
5
7
  /**
6
8
  * How the grid turns surplus row space into layout:
7
9
  *
8
- * - `"fixed"` — every column is exactly `cardWidth` px; leftover row space is
10
+ * - `"fixed"` — every column is exactly `cardWidth` design px; leftover row space is
9
11
  * spread as even gutters (`justify-content: space-around`). Cards never resize;
10
12
  * the column count changes with the viewport. This is the original tabwoah
11
13
  * card-grid behavior.
@@ -14,7 +16,7 @@ import { cn } from "../../../utils/cn";
14
16
  * left-aligned at a single track's width rather than stretching edge to edge.
15
17
  * - `"scroll"` — a single row that scrolls horizontally, with fluid-width cards
16
18
  * sized from the container so that exactly {@link SCROLL_VISIBLE_CARDS} cards
17
- * plus a {@link SCROLL_PEEK_WIDTH}px sliver of the next one fit on screen (up
19
+ * plus a `GRID.peekPx` sliver of the next one fit on screen (up
18
20
  * to `maxCardWidth`, past which more cards simply fit). The sliver is the
19
21
  * point: it makes the rail visibly continue past the fold, so the row reads as
20
22
  * swipeable instead of as a finished pair of cards. Wrapping is off; the row
@@ -23,19 +25,27 @@ import { cn } from "../../../utils/cn";
23
25
  */
24
26
  export type CardGridVariant = "fixed" | "fluid" | "scroll";
25
27
 
26
- /** The grid gap, in px — mirrors the `gap: 1rem` below, for the scroll math. */
27
- const GRID_GAP = 16;
28
+ /**
29
+ * The grid's own lengths, in design px — every one drawn through `rem`, so the
30
+ * `gap` the grid lays out with and the gap the scroll track math reserves are
31
+ * the same length at any type scale.
32
+ */
33
+ const GRID = {
34
+ /** Between cards: the grid's `gap`, and what the scroll math reserves per gap. */
35
+ gapPx: 16,
36
+ /**
37
+ * `scroll`: the next card left visible past the last whole one — the
38
+ * "there's more, swipe" hint. Wide enough to read as a clipped card (rounded
39
+ * edge + a slice of its photo) rather than as a rendering glitch.
40
+ */
41
+ peekPx: 28,
42
+ /** Under the row — the tabwoah original's Tailwind `pb-0.5`. */
43
+ paddingBottomPx: 2,
44
+ } as const;
28
45
 
29
46
  /** `scroll`: how many WHOLE cards the rail commits to showing at once. */
30
47
  const SCROLL_VISIBLE_CARDS = 2;
31
48
 
32
- /**
33
- * `scroll`: px of the next card left visible past the last whole one — the
34
- * "there's more, swipe" hint. Wide enough to read as a clipped card (rounded
35
- * edge + a slice of its photo) rather than as a rendering glitch.
36
- */
37
- const SCROLL_PEEK_WIDTH = 28;
38
-
39
49
  /**
40
50
  * The `scroll` track width: the widest a card can be while the container still
41
51
  * shows `SCROLL_VISIBLE_CARDS` of them plus the peek — or, when there is nothing
@@ -46,25 +56,27 @@ const SCROLL_PEEK_WIDTH = 28;
46
56
  * that follow them (one between each pair, one before the peeked card), and the
47
57
  * peek. With no overflow there are only N-1 gaps and no peek.
48
58
  */
49
- function scrollTrackWidth(count: number, max: number): string {
59
+ function scrollTrackWidth(theme: Theme, count: number, max: number): string {
50
60
  const tracks = Math.max(1, Math.min(count, SCROLL_VISIBLE_CARDS));
51
61
  const overflows = count > tracks;
52
62
  const gaps = overflows ? tracks : tracks - 1;
53
- const reserved = gaps * GRID_GAP + (overflows ? SCROLL_PEEK_WIDTH : 0);
54
- return `min(${max}px, calc((100% - ${reserved}px) / ${tracks}))`;
63
+ const reserved = gaps * GRID.gapPx + (overflows ? GRID.peekPx : 0);
64
+ return `min(${rem(theme, max)}, calc((100% - ${rem(theme, reserved)}) / ${tracks}))`;
55
65
  }
56
66
 
57
67
  interface CardGridProps {
58
68
  /**
59
- * `"fixed"`: the exact column width in px. `"fluid"`: the minimum column width
69
+ * `"fixed"`: the exact column width. `"fluid"`: the minimum column width
60
70
  * (columns grow from here). `"scroll"`: only seeds the default `maxCardWidth`
61
71
  * — a scroll track has no minimum, because a minimum is exactly what would
62
72
  * break the "two cards plus a peek" promise on a narrow phone.
73
+ *
74
+ * Design px, scaled with the theme's type scale.
63
75
  */
64
76
  cardWidth: number;
65
77
  /**
66
- * `"scroll"` only: the maximum fluid card width in px. Defaults to
67
- * `1.6 × cardWidth`.
78
+ * `"scroll"` only: the maximum fluid card width. Defaults to
79
+ * `1.6 × cardWidth`. Design px, scaled with the theme's type scale.
68
80
  */
69
81
  maxCardWidth?: number;
70
82
  /** Layout behavior — see {@link CardGridVariant}. Defaults to `"fixed"`. */
@@ -84,8 +96,8 @@ interface CardGridProps {
84
96
  *
85
97
  * Ported from the tabwoah card grid (the `"fixed"` variant is verbatim). The one
86
98
  * adaptation: that app is Tailwind (`className="grid gap-4 pb-0.5"`); this one
87
- * has no Tailwind, so those three utilities (display:grid, gap 1rem,
88
- * padding-bottom 2px) live in `style`.
99
+ * has no Tailwind, so those three utilities (display:grid, gap 16 design px,
100
+ * padding-bottom 2 design px) live in `style`, drawn through `rem`.
89
101
  */
90
102
  export function CardGrid({
91
103
  cardWidth,
@@ -96,10 +108,11 @@ export function CardGrid({
96
108
  containerRef,
97
109
  children,
98
110
  }: CardGridProps) {
111
+ const theme = useTheme();
99
112
  const style: CSSProperties = {
100
113
  display: "grid",
101
- gap: "1rem",
102
- paddingBottom: "2px",
114
+ gap: rem(theme, GRID.gapPx),
115
+ paddingBottom: rem(theme, GRID.paddingBottomPx),
103
116
  };
104
117
 
105
118
  if (variant === "scroll") {
@@ -109,14 +122,14 @@ export function CardGrid({
109
122
  // always fit (see `scrollTrackWidth`). Scroll-snap makes a swipe settle on a
110
123
  // card boundary instead of drifting mid-card.
111
124
  style.gridAutoFlow = "column";
112
- style.gridAutoColumns = scrollTrackWidth(Children.count(children), max);
125
+ style.gridAutoColumns = scrollTrackWidth(theme, Children.count(children), max);
113
126
  style.overflowX = "auto";
114
127
  style.overflowY = "hidden";
115
128
  style.scrollSnapType = "x mandatory";
116
129
  } else if (variant === "fluid") {
117
- style.gridTemplateColumns = `repeat(auto-fill, minmax(${cardWidth}px, 1fr))`;
130
+ style.gridTemplateColumns = `repeat(auto-fill, minmax(${rem(theme, cardWidth)}, 1fr))`;
118
131
  } else {
119
- style.gridTemplateColumns = `repeat(auto-fill, ${cardWidth}px)`;
132
+ style.gridTemplateColumns = `repeat(auto-fill, ${rem(theme, cardWidth)})`;
120
133
  // `space-around` only distributes leftover width in the fixed variant; the
121
134
  // fluid variant consumes it via `1fr` and scroll overflows instead.
122
135
  style.justifyContent = "space-around";
@@ -1,7 +1,10 @@
1
1
  import type { Theme } from '@mui/material/styles/index.js';
2
2
 
3
+ import { rem, remPx } from '../../../tokens/relative';
4
+
3
5
  import type { ResizableProps, ResizableVariant, ResizeHandle } from './Resizable.types';
4
6
 
7
+ /** One axis's clamp, in the px a drag runs in. */
5
8
  export interface Axis {
6
9
  min: number;
7
10
  max: number;
@@ -80,16 +83,30 @@ export const handleStyle = (theme: Theme, handle: ResizeHandle, active: boolean)
80
83
 
81
84
  switch (handle) {
82
85
  case 'right':
83
- return { ...baseStyle, top: 0, right: -2, width: 4, height: '100%', cursor: 'ew-resize' };
86
+ return {
87
+ ...baseStyle,
88
+ top: 0,
89
+ right: rem(theme, -2),
90
+ width: rem(theme, 4),
91
+ height: '100%',
92
+ cursor: 'ew-resize',
93
+ };
84
94
  case 'bottom':
85
- return { ...baseStyle, bottom: -2, left: 0, width: '100%', height: 4, cursor: 'ns-resize' };
95
+ return {
96
+ ...baseStyle,
97
+ bottom: rem(theme, -2),
98
+ left: 0,
99
+ width: '100%',
100
+ height: rem(theme, 4),
101
+ cursor: 'ns-resize',
102
+ };
86
103
  case 'bottomRight':
87
104
  return {
88
105
  ...baseStyle,
89
- bottom: -2,
90
- right: -2,
91
- width: 8,
92
- height: 8,
106
+ bottom: rem(theme, -2),
107
+ right: rem(theme, -2),
108
+ width: rem(theme, 8),
109
+ height: rem(theme, 8),
93
110
  cursor: 'nw-resize',
94
111
  borderRadius: '50%',
95
112
  };
@@ -98,30 +115,35 @@ export const handleStyle = (theme: Theme, handle: ResizeHandle, active: boolean)
98
115
  }
99
116
  };
100
117
 
101
- type ResizableDefaultedKeys =
102
- | 'variant'
103
- | 'width'
104
- | 'height'
105
- | 'minWidth'
106
- | 'maxWidth'
107
- | 'minHeight'
108
- | 'maxHeight'
109
- | 'disabled';
118
+ type ResizableDefaultedKeys = 'variant' | 'disabled';
110
119
 
111
120
  type ResolvedResizableProps = ResizableProps &
112
121
  Required<Pick<ResizableProps, ResizableDefaultedKeys>>;
113
122
 
114
123
  const RESIZABLE_DEFAULTS: Pick<ResizableProps, ResizableDefaultedKeys> = {
115
124
  variant: 'both',
116
- width: 200,
117
- height: 200,
118
- minWidth: 50,
119
- maxWidth: 1000,
120
- minHeight: 50,
121
- maxHeight: 1000,
122
125
  disabled: false,
123
126
  };
124
127
 
128
+ /** The box's own defaults, in design px: where it starts, and its clamp. */
129
+ const DEFAULT_BOX_PX = { start: 200, min: 50, max: 1000 } as const;
130
+
131
+ /**
132
+ * Where the box starts, in the px a drag runs in. The consumer's sizes are
133
+ * design px, like every other size in the package; a drag is pointer pixels,
134
+ * so the live size is px from here on.
135
+ */
136
+ export const startSizePx = (theme: Theme, width?: number, height?: number) => ({
137
+ width: remPx(theme, width ?? DEFAULT_BOX_PX.start),
138
+ height: remPx(theme, height ?? DEFAULT_BOX_PX.start),
139
+ });
140
+
141
+ /** One axis's clamp, from the consumer's design px to the px a drag runs in. */
142
+ export const axisPx = (theme: Theme, min?: number, max?: number): Axis => ({
143
+ min: remPx(theme, min ?? DEFAULT_BOX_PX.min),
144
+ max: remPx(theme, max ?? DEFAULT_BOX_PX.max),
145
+ });
146
+
125
147
  // Strips explicitly-undefined props before the merge, so `minWidth={undefined}`
126
148
  // still falls back to the default exactly as a destructuring default would.
127
149
  const definedProps = (props: ResizableProps): Partial<ResizableProps> =>
@@ -5,9 +5,12 @@ import { resizedTo } from './Resizable.helpers';
5
5
  import type { ResizeHandle } from './Resizable.types';
6
6
 
7
7
  interface ResizeArgs {
8
- width: number;
9
- height: number;
8
+ /** Where the box starts, in px (`startSizePx`); a new object re-seats the box. */
9
+ start: { width: number; height: number };
10
+ /** The clamp, in px (`axisPx` per axis). */
10
11
  bounds: Bounds;
12
+ /** Rendered px per design px (`remPx(theme, 1)`) — `onResize` reports design px. */
13
+ pxPerDesignPx: number;
11
14
  disabled: boolean;
12
15
  onResize?: (width: number, height: number) => void;
13
16
  }
@@ -16,17 +19,21 @@ interface ResizeArgs {
16
19
  * Tracks the box's size across a drag. The listeners live on the document rather
17
20
  * than the handle, so the pointer can leave the handle — or the component — mid
18
21
  * drag without the resize sticking.
22
+ *
23
+ * The live size is px, because a drag is pointer pixels. What `onResize`
24
+ * reports is design px — the unit the consumer's `width`/`height` are in — so a
25
+ * controlled box (`onResize` feeding `width`) stays put at any type scale.
19
26
  */
20
- export const useResize = ({ width, height, bounds, disabled, onResize }: ResizeArgs) => {
21
- const [size, setSize] = useState({ width, height });
27
+ export const useResize = ({ start, bounds, pxPerDesignPx, disabled, onResize }: ResizeArgs) => {
28
+ const [size, setSize] = useState(start);
22
29
  const [isResizing, setIsResizing] = useState(false);
23
30
  const startPos = useRef({ x: 0, y: 0 });
24
31
  const startSize = useRef({ width: 0, height: 0 });
25
32
  const activeHandle = useRef<ResizeHandle | null>(null);
26
33
 
27
34
  React.useEffect(() => {
28
- setSize({ width, height });
29
- }, [width, height]);
35
+ setSize(start);
36
+ }, [start]);
30
37
 
31
38
  const handleMouseDown = useCallback(
32
39
  (e: React.MouseEvent, handle: ResizeHandle) => {
@@ -38,7 +45,8 @@ export const useResize = ({ width, height, bounds, disabled, onResize }: ResizeA
38
45
  setIsResizing(true);
39
46
  activeHandle.current = handle;
40
47
  startPos.current = { x: e.clientX, y: e.clientY };
41
- startSize.current = { width: size.width, height: size.height };
48
+ // State is replaced on every change, never mutated, so holding it is a snapshot.
49
+ startSize.current = size;
42
50
 
43
51
  const handleMouseMove = (move: globalThis.MouseEvent) => {
44
52
  const delta = {
@@ -48,7 +56,7 @@ export const useResize = ({ width, height, bounds, disabled, onResize }: ResizeA
48
56
  const next = resizedTo(handle, delta, startSize.current, bounds);
49
57
 
50
58
  setSize(next);
51
- onResize?.(next.width, next.height);
59
+ onResize?.(next.width / pxPerDesignPx, next.height / pxPerDesignPx);
52
60
  };
53
61
 
54
62
  const handleMouseUp = () => {
@@ -61,7 +69,7 @@ export const useResize = ({ width, height, bounds, disabled, onResize }: ResizeA
61
69
  document.addEventListener('mousemove', handleMouseMove);
62
70
  document.addEventListener('mouseup', handleMouseUp);
63
71
  },
64
- [disabled, size, bounds, onResize],
72
+ [disabled, size, bounds, pxPerDesignPx, onResize],
65
73
  );
66
74
 
67
75
  return { size, isResizing, activeHandle, handleMouseDown };
@@ -51,18 +51,22 @@ import { Resizable } from '@procurement/ui';
51
51
  | -------------- | ---------------------------------------- | ------------------------------------ | ------------------------------------------------ |
52
52
  | `children` | `ReactNode` | - | Content to render inside the resizable container |
53
53
  | `variant` | `'horizontal' \| 'vertical' \| 'both'` | `'both'` | Resize direction constraint |
54
- | `width` | `number` | `300` | Initial width in pixels |
55
- | `height` | `number` | `200` | Initial height in pixels |
54
+ | `width` | `number` | `200` | Initial width, design px (scales with the theme's type scale) |
55
+ | `height` | `number` | `200` | Initial height, design px (scales with the theme's type scale) |
56
56
  | `minWidth` | `number` | `50` | Minimum width constraint |
57
- | `maxWidth` | `number` | - | Maximum width constraint |
57
+ | `maxWidth` | `number` | `1000` | Maximum width constraint |
58
58
  | `minHeight` | `number` | `50` | Minimum height constraint |
59
- | `maxHeight` | `number` | - | Maximum height constraint |
60
- | `onResize` | `(dimensions: ResizeDimensions) => void` | - | Callback fired during resize with new dimensions |
59
+ | `maxHeight` | `number` | `1000` | Maximum height constraint |
60
+ | `onResize` | `(width: number, height: number) => void` | - | Fired during resize with the new size, in design px |
61
61
  | `disabled` | `boolean` | `false` | Disables resize functionality |
62
62
  | `handles` | `HandlePosition[]` | `['right', 'bottom', 'bottomRight']` | Array of handle positions |
63
63
  | `className` | `string` | - | Additional CSS class name |
64
64
  | `data-testid` | `string` | - | Test ID for automated testing |
65
65
 
66
+ Every size prop — and what `onResize` reports — is in design px, the unit the
67
+ whole package draws in, scaled with the theme's type scale (`remPx`). A drag
68
+ follows the pointer in real pixels.
69
+
66
70
  ## Handle Positions
67
71
 
68
72
  The `handles` prop accepts an array of the following positions:
@@ -2,7 +2,15 @@ import Box from '@mui/material/Box/index.js';
2
2
  import { useTheme } from '@mui/material/styles/index.js';
3
3
  import React, { useMemo } from 'react';
4
4
 
5
- import { defaultHandles, handleStyle, resolveResizableProps } from './Resizable.helpers';
5
+ import { remPx } from '../../../tokens/relative';
6
+
7
+ import {
8
+ axisPx,
9
+ defaultHandles,
10
+ handleStyle,
11
+ resolveResizableProps,
12
+ startSizePx,
13
+ } from './Resizable.helpers';
6
14
  import { useResize } from './Resizable.hooks';
7
15
  import type { ResizableProps } from './Resizable.types';
8
16
 
@@ -10,8 +18,8 @@ export const Resizable: React.FC<ResizableProps> = (rawProps) => {
10
18
  const {
11
19
  children,
12
20
  variant,
13
- width: initialWidth,
14
- height: initialHeight,
21
+ width,
22
+ height,
15
23
  minWidth,
16
24
  maxWidth,
17
25
  minHeight,
@@ -24,18 +32,20 @@ export const Resizable: React.FC<ResizableProps> = (rawProps) => {
24
32
  ...rest
25
33
  } = resolveResizableProps(rawProps);
26
34
  const theme = useTheme();
35
+ // Keyed apart: a new `start` re-seats the box, which a changed clamp must not do.
36
+ const start = useMemo(() => startSizePx(theme, width, height), [theme, width, height]);
27
37
  const bounds = useMemo(
28
38
  () => ({
29
- width: { min: minWidth, max: maxWidth },
30
- height: { min: minHeight, max: maxHeight },
39
+ width: axisPx(theme, minWidth, maxWidth),
40
+ height: axisPx(theme, minHeight, maxHeight),
31
41
  }),
32
- [minWidth, maxWidth, minHeight, maxHeight],
42
+ [theme, minWidth, maxWidth, minHeight, maxHeight],
33
43
  );
34
44
 
35
45
  const { size, isResizing, activeHandle, handleMouseDown } = useResize({
36
- width: initialWidth,
37
- height: initialHeight,
46
+ start,
38
47
  bounds,
48
+ pxPerDesignPx: remPx(theme, 1),
39
49
  disabled,
40
50
  onResize,
41
51
  });
@@ -49,6 +59,8 @@ export const Resizable: React.FC<ResizableProps> = (rawProps) => {
49
59
  data-testid={dataTestId}
50
60
  sx={{
51
61
  position: 'relative',
62
+ // The live size: the start and the clamp came through `remPx`, the rest
63
+ // is pointer pixels dragged, so it is px as it stands.
52
64
  width: size.width,
53
65
  height: size.height,
54
66
  border: `1px solid ${theme.palette.divider}`,
@@ -14,12 +14,22 @@ export type ResizeHandle =
14
14
  export interface ResizableProps {
15
15
  children: ReactNode;
16
16
  variant?: ResizableVariant;
17
+ /** Starting width (default 200). Design px, scaled with the theme's type scale. */
17
18
  width?: number;
19
+ /** Starting height (default 200). Design px, scaled with the theme's type scale. */
18
20
  height?: number;
21
+ /** Narrowest a drag can make it (default 50). Design px, scaled with the theme's type scale. */
19
22
  minWidth?: number;
23
+ /** Widest a drag can make it (default 1000). Design px, scaled with the theme's type scale. */
20
24
  maxWidth?: number;
25
+ /** Shortest a drag can make it (default 50). Design px, scaled with the theme's type scale. */
21
26
  minHeight?: number;
27
+ /** Tallest a drag can make it (default 1000). Design px, scaled with the theme's type scale. */
22
28
  maxHeight?: number;
29
+ /**
30
+ * Fired on every drag step with the new size, in design px — the unit `width`
31
+ * and `height` take, so feeding it back keeps a controlled box where it is.
32
+ */
23
33
  onResize?: (width: number, height: number) => void;
24
34
  disabled?: boolean;
25
35
  handles?: ResizeHandle[];
@@ -10,7 +10,6 @@ type ScrollAreaDefaultedKeys =
10
10
  | 'smoothScroll'
11
11
  | 'variant'
12
12
  | 'scrollToTopButton'
13
- | 'scrollToTopThreshold'
14
13
  | 'contentPadding'
15
14
  | 'alwaysShowScrollbar'
16
15
  | 'disabled'
@@ -30,7 +29,6 @@ const SCROLL_AREA_DEFAULTS: Pick<ScrollAreaProps, ScrollAreaDefaultedKeys> = {
30
29
  smoothScroll: true,
31
30
  variant: 'default',
32
31
  scrollToTopButton: false,
33
- scrollToTopThreshold: 100,
34
32
  contentPadding: 0,
35
33
  alwaysShowScrollbar: false,
36
34
  disabled: false,
@@ -8,7 +8,7 @@ import type { SxProps, Theme } from '@mui/material/styles/index.js';
8
8
  import type { FC } from 'react';
9
9
  import React, { useCallback, useEffect, useRef, useState } from 'react';
10
10
 
11
- import { rem, sxRem } from '../../../tokens/relative';
11
+ import { rem, remPx, sxRem } from '../../../tokens/relative';
12
12
 
13
13
  import type { ResolvedScrollAreaProps } from './ScrollArea.helpers';
14
14
  import { resolveScrollAreaProps } from './ScrollArea.helpers';
@@ -105,6 +105,7 @@ const useScrollArea = (
105
105
  scrollToTopThreshold,
106
106
  smoothScroll } = props;
107
107
 
108
+ const theme = useTheme();
108
109
  const { scrollRef, setScrollRef, containerDimensions } = useObservedScrollRef({
109
110
  externalScrollRef,
110
111
  onResize });
@@ -121,12 +122,13 @@ const useScrollArea = (
121
122
  noteScroll();
122
123
 
123
124
  if (scrollToTopButton && scrollRef.current) {
124
- setShowScrollToTop(scrollRef.current.scrollTop > scrollToTopThreshold);
125
+ // 100 design px unless the caller says, in the px `scrollTop` is measured in.
126
+ setShowScrollToTop(scrollRef.current.scrollTop > remPx(theme, scrollToTopThreshold ?? 100));
125
127
  }
126
128
 
127
129
  onScroll?.(event);
128
130
  },
129
- [disabled, noteScroll, scrollToTopButton, scrollToTopThreshold, onScroll, scrollRef],
131
+ [disabled, noteScroll, scrollToTopButton, scrollToTopThreshold, onScroll, scrollRef, theme],
130
132
  );
131
133
 
132
134
  const scrollToTop = useCallback(() => {
@@ -63,7 +63,10 @@ export interface ScrollAreaBase extends Omit<BoxProps, 'ref'> {
63
63
  /** Scroll event handler */
64
64
  onScroll?: (event: React.UIEvent<HTMLDivElement>) => void;
65
65
 
66
- /** Threshold for showing scroll-to-top button (in pixels) */
66
+ /**
67
+ * How far down the scroll-to-top button appears (default 100) — design px,
68
+ * scaled with the theme's type scale.
69
+ */
67
70
  scrollToTopThreshold?: number;
68
71
 
69
72
  /** Custom scrollbar color */
@@ -19,7 +19,8 @@ const resolveScrollable = (scrollableTarget: ScrollableTarget): Element | null =
19
19
 
20
20
  interface ObserverArgs {
21
21
  testMode: boolean;
22
- threshold: number;
22
+ /** The observer's `rootMargin` — px, which is all `IntersectionObserver` takes. */
23
+ rootMargin: string;
23
24
  scrollableTarget: ScrollableTarget;
24
25
  }
25
26
 
@@ -28,7 +29,7 @@ interface ObserverArgs {
28
29
  * it fire before the sentinel is actually on screen, so the next page is already
29
30
  * loading by the time the user reaches the bottom.
30
31
  */
31
- export const useSentinel = ({ testMode, threshold, scrollableTarget }: ObserverArgs) => {
32
+ export const useSentinel = ({ testMode, rootMargin, scrollableTarget }: ObserverArgs) => {
32
33
  const sentinelRef = useRef<HTMLDivElement>(null);
33
34
  const [isIntersecting, setIsIntersecting] = useState(false);
34
35
 
@@ -43,7 +44,7 @@ export const useSentinel = ({ testMode, threshold, scrollableTarget }: ObserverA
43
44
  },
44
45
  {
45
46
  root: resolveScrollable(scrollableTarget) || undefined,
46
- rootMargin: `${threshold}px`,
47
+ rootMargin,
47
48
  threshold: 0,
48
49
  },
49
50
  );
@@ -51,7 +52,7 @@ export const useSentinel = ({ testMode, threshold, scrollableTarget }: ObserverA
51
52
  observer.observe(sentinelRef.current);
52
53
 
53
54
  return () => observer.disconnect();
54
- }, [testMode, threshold, scrollableTarget]);
55
+ }, [testMode, rootMargin, scrollableTarget]);
55
56
 
56
57
  return { sentinelRef, isIntersecting };
57
58
  };