@ahrowe/ui 0.33.0 → 0.35.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 (566) hide show
  1. package/README.md +101 -40
  2. package/dist/esm/common/accordion/accordion.mjs +1 -1
  3. package/dist/esm/common/accordion/accordion.mjs.map +1 -1
  4. package/dist/esm/common/accordion/accordion.module.mjs +1 -1
  5. package/dist/esm/common/accordion/accordion.module.mjs.map +1 -1
  6. package/dist/esm/common/accordion/accordion.plain.module.mjs +1 -1
  7. package/dist/esm/common/accordion/accordion.plain.module.mjs.map +1 -1
  8. package/dist/esm/common/accordion/accordion.primary.module.mjs +1 -1
  9. package/dist/esm/common/accordion/accordion.primary.module.mjs.map +1 -1
  10. package/dist/esm/common/accordion/accordion.types.mjs +1 -1
  11. package/dist/esm/common/accordion/accordion.types.mjs.map +1 -1
  12. package/dist/esm/common/actionButtons/actionButtons.mjs +1 -1
  13. package/dist/esm/common/actionButtons/actionButtons.mjs.map +1 -1
  14. package/dist/esm/common/actionButtons/actionButtons.module.mjs +1 -1
  15. package/dist/esm/common/actionIcon/actionIcon.mjs +1 -1
  16. package/dist/esm/common/actionIcon/actionIcon.mjs.map +1 -1
  17. package/dist/esm/common/actionIcon/actionIcon.module.mjs +1 -1
  18. package/dist/esm/common/actionIcon/actionIcon.module.mjs.map +1 -1
  19. package/dist/esm/common/alert/alert.mjs +1 -1
  20. package/dist/esm/common/alert/alert.mjs.map +1 -1
  21. package/dist/esm/common/alert/alert.module.mjs +1 -1
  22. package/dist/esm/common/alert/alert.types.mjs +1 -1
  23. package/dist/esm/common/alert/alert.types.mjs.map +1 -1
  24. package/dist/esm/common/animatedIcon/animatedIcon.mjs +1 -1
  25. package/dist/esm/common/animatedIcon/animatedIcon.mjs.map +1 -1
  26. package/dist/esm/common/animatedIcon/animatedIcon.module.mjs +1 -1
  27. package/dist/esm/common/animatedLogo/animatedLogo.mjs +1 -1
  28. package/dist/esm/common/animatedLogo/animatedLogo.mjs.map +1 -1
  29. package/dist/esm/common/animatedLogo/animatedLogo.module.mjs +1 -1
  30. package/dist/esm/common/animatedText/animatedText.mjs +1 -1
  31. package/dist/esm/common/animatedText/animatedText.mjs.map +1 -1
  32. package/dist/esm/common/animatedText/animatedText.module.mjs +1 -1
  33. package/dist/esm/common/animatedText/animatedText.types.mjs +1 -1
  34. package/dist/esm/common/animatedText/animatedText.types.mjs.map +1 -1
  35. package/dist/esm/common/avatar/avatar.mjs +1 -1
  36. package/dist/esm/common/avatar/avatar.mjs.map +1 -1
  37. package/dist/esm/common/avatar/avatar.module.mjs +1 -1
  38. package/dist/esm/common/avatar/avatarGroup.mjs +1 -1
  39. package/dist/esm/common/avatar/avatarGroup.mjs.map +1 -1
  40. package/dist/esm/common/badge/badge.mjs +1 -1
  41. package/dist/esm/common/badge/badge.mjs.map +1 -1
  42. package/dist/esm/common/badge/badge.module.mjs +1 -1
  43. package/dist/esm/common/badge/badge.types.mjs +1 -1
  44. package/dist/esm/common/badge/badge.types.mjs.map +1 -1
  45. package/dist/esm/common/bodyEnd/bodyEnd.mjs +1 -1
  46. package/dist/esm/common/bodyEnd/bodyEnd.mjs.map +1 -1
  47. package/dist/esm/common/breadcrumb/breadcrumb.mjs +1 -1
  48. package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -1
  49. package/dist/esm/common/breadcrumb/breadcrumb.module.mjs +1 -1
  50. package/dist/esm/common/breadcrumb/breadcrumb.module.mjs.map +1 -1
  51. package/dist/esm/common/button/button.mjs +1 -1
  52. package/dist/esm/common/button/button.mjs.map +1 -1
  53. package/dist/esm/common/button/button.module.mjs +1 -1
  54. package/dist/esm/common/button/button.types.mjs +1 -1
  55. package/dist/esm/common/button/button.types.mjs.map +1 -1
  56. package/dist/esm/common/buttonGroup/buttonGroup.mjs +1 -1
  57. package/dist/esm/common/buttonGroup/buttonGroup.mjs.map +1 -1
  58. package/dist/esm/common/buttonGroup/buttonGroup.module.mjs +1 -1
  59. package/dist/esm/common/buttonGroup/buttonGroup.types.mjs +1 -1
  60. package/dist/esm/common/buttonGroup/buttonGroup.types.mjs.map +1 -1
  61. package/dist/esm/common/card/Card.mjs +1 -1
  62. package/dist/esm/common/card/Card.mjs.map +1 -1
  63. package/dist/esm/common/card/CardActions.mjs +1 -1
  64. package/dist/esm/common/card/CardActions.mjs.map +1 -1
  65. package/dist/esm/common/card/CardContent.mjs +1 -1
  66. package/dist/esm/common/card/CardContent.mjs.map +1 -1
  67. package/dist/esm/common/card/CardHeader.mjs +1 -1
  68. package/dist/esm/common/card/CardHeader.mjs.map +1 -1
  69. package/dist/esm/common/card/CardMedia.mjs +1 -1
  70. package/dist/esm/common/card/CardMedia.mjs.map +1 -1
  71. package/dist/esm/common/card/card.module.mjs +1 -1
  72. package/dist/esm/common/card/card.module.mjs.map +1 -1
  73. package/dist/esm/common/card/card.types.mjs +1 -1
  74. package/dist/esm/common/card/card.types.mjs.map +1 -1
  75. package/dist/esm/common/carousel/carousel.mjs +1 -1
  76. package/dist/esm/common/carousel/carousel.mjs.map +1 -1
  77. package/dist/esm/common/carousel/carousel.module.mjs +1 -1
  78. package/dist/esm/common/checkbox/checkbox.mjs +1 -1
  79. package/dist/esm/common/checkbox/checkbox.mjs.map +1 -1
  80. package/dist/esm/common/checkbox/checkbox.module.mjs +1 -1
  81. package/dist/esm/common/checkbox/checkbox.module.mjs.map +1 -1
  82. package/dist/esm/common/chip/chip.mjs +1 -1
  83. package/dist/esm/common/chip/chip.mjs.map +1 -1
  84. package/dist/esm/common/chip/chip.module.mjs +1 -1
  85. package/dist/esm/common/chip/chip.types.mjs +1 -1
  86. package/dist/esm/common/chip/chip.types.mjs.map +1 -1
  87. package/dist/esm/common/chip/chipContainer.mjs +1 -1
  88. package/dist/esm/common/chip/chipContainer.mjs.map +1 -1
  89. package/dist/esm/common/colorPicker/colorPicker.mjs +1 -1
  90. package/dist/esm/common/colorPicker/colorPicker.mjs.map +1 -1
  91. package/dist/esm/common/colorPicker/colorPicker.module.mjs +1 -1
  92. package/dist/esm/common/colorPicker/colorPicker.module.mjs.map +1 -1
  93. package/dist/esm/common/colorPicker/toHex.mjs +1 -1
  94. package/dist/esm/common/colorPicker/toHex.mjs.map +1 -1
  95. package/dist/esm/common/configProvider/configProvider.mjs +1 -1
  96. package/dist/esm/common/configProvider/configProvider.mjs.map +1 -1
  97. package/dist/esm/common/configProvider/presentation.types.mjs +2 -0
  98. package/dist/esm/common/configProvider/presentation.types.mjs.map +1 -0
  99. package/dist/esm/common/configProvider/useComponentDefaults.mjs +1 -1
  100. package/dist/esm/common/configProvider/useComponentDefaults.mjs.map +1 -1
  101. package/dist/esm/common/configProvider/useLabels.mjs +1 -1
  102. package/dist/esm/common/configProvider/useLabels.mjs.map +1 -1
  103. package/dist/esm/common/configProvider/usePresentationDefault.mjs +1 -1
  104. package/dist/esm/common/configProvider/usePresentationDefault.mjs.map +1 -1
  105. package/dist/esm/common/confirmModal/confirmModal.mjs +1 -1
  106. package/dist/esm/common/confirmModal/confirmModal.mjs.map +1 -1
  107. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs +1 -1
  108. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs.map +1 -1
  109. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.module.mjs +1 -1
  110. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.module.mjs.map +1 -1
  111. package/dist/esm/common/datePicker/dateFunctions.mjs +1 -1
  112. package/dist/esm/common/datePicker/dateFunctions.mjs.map +1 -1
  113. package/dist/esm/common/datePicker/datePicker.mjs +1 -1
  114. package/dist/esm/common/datePicker/datePicker.mjs.map +1 -1
  115. package/dist/esm/common/datePicker/datePicker.module.mjs +1 -1
  116. package/dist/esm/common/divider/divider.mjs +1 -1
  117. package/dist/esm/common/divider/divider.mjs.map +1 -1
  118. package/dist/esm/common/divider/divider.module.mjs +1 -1
  119. package/dist/esm/common/divider/divider.types.mjs +1 -1
  120. package/dist/esm/common/divider/divider.types.mjs.map +1 -1
  121. package/dist/esm/common/drawer/drawer.mjs +1 -1
  122. package/dist/esm/common/drawer/drawer.mjs.map +1 -1
  123. package/dist/esm/common/drawer/drawer.module.mjs +1 -1
  124. package/dist/esm/common/dropZone/dropZone.mjs +1 -1
  125. package/dist/esm/common/dropZone/dropZone.mjs.map +1 -1
  126. package/dist/esm/common/dropZone/dropZone.module.mjs +1 -1
  127. package/dist/esm/common/dropZone/dropZone.types.mjs +1 -1
  128. package/dist/esm/common/dropZone/dropZone.types.mjs.map +1 -1
  129. package/dist/esm/common/dropdown/dropdown.mjs +1 -1
  130. package/dist/esm/common/dropdown/dropdown.mjs.map +1 -1
  131. package/dist/esm/common/dropdown/dropdown.module.mjs +1 -1
  132. package/dist/esm/common/dropdown/dropdown.module.mjs.map +1 -1
  133. package/dist/esm/common/emptyState/emptyState.mjs +1 -1
  134. package/dist/esm/common/emptyState/emptyState.mjs.map +1 -1
  135. package/dist/esm/common/emptyState/emptyState.module.mjs +1 -1
  136. package/dist/esm/common/errorBoundary/errorBoundary.mjs +1 -1
  137. package/dist/esm/common/errorBoundary/errorBoundary.mjs.map +1 -1
  138. package/dist/esm/common/errorBoundary/errorBoundary.module.mjs +1 -1
  139. package/dist/esm/common/fab/components/fabBase/fabBase.mjs +1 -1
  140. package/dist/esm/common/fab/components/fabBase/fabBase.mjs.map +1 -1
  141. package/dist/esm/common/fab/components/fabBase/fabBase.module.mjs +1 -1
  142. package/dist/esm/common/fab/fab.mjs +1 -1
  143. package/dist/esm/common/fab/fab.mjs.map +1 -1
  144. package/dist/esm/common/fab/fab.module.mjs +1 -1
  145. package/dist/esm/common/fab/fab.module.mjs.map +1 -1
  146. package/dist/esm/common/flip/flip.mjs +1 -1
  147. package/dist/esm/common/flip/flip.mjs.map +1 -1
  148. package/dist/esm/common/flip/flip.module.mjs +1 -1
  149. package/dist/esm/common/floorPlan/floorPlan.faces.mjs +1 -1
  150. package/dist/esm/common/floorPlan/floorPlan.faces.mjs.map +1 -1
  151. package/dist/esm/common/floorPlan/floorPlan.geometry.mjs +1 -1
  152. package/dist/esm/common/floorPlan/floorPlan.geometry.mjs.map +1 -1
  153. package/dist/esm/common/floorPlan/floorPlan.graph.mjs +1 -1
  154. package/dist/esm/common/floorPlan/floorPlan.graph.mjs.map +1 -1
  155. package/dist/esm/common/floorPlan/floorPlan.hit.mjs +1 -1
  156. package/dist/esm/common/floorPlan/floorPlan.hit.mjs.map +1 -1
  157. package/dist/esm/common/floorPlan/floorPlan.json.mjs +1 -1
  158. package/dist/esm/common/floorPlan/floorPlan.json.mjs.map +1 -1
  159. package/dist/esm/common/floorPlan/floorPlan.mesh.mjs +1 -1
  160. package/dist/esm/common/floorPlan/floorPlan.mesh.mjs.map +1 -1
  161. package/dist/esm/common/floorPlan/floorPlan.path.mjs +1 -1
  162. package/dist/esm/common/floorPlan/floorPlan.path.mjs.map +1 -1
  163. package/dist/esm/common/floorPlan/floorPlan.plan.mjs +1 -1
  164. package/dist/esm/common/floorPlan/floorPlan.plan.mjs.map +1 -1
  165. package/dist/esm/common/floorPlan/floorPlan.rooms.mjs +1 -1
  166. package/dist/esm/common/floorPlan/floorPlan.rooms.mjs.map +1 -1
  167. package/dist/esm/common/floorPlan/floorPlan.snap.mjs +1 -1
  168. package/dist/esm/common/floorPlan/floorPlan.snap.mjs.map +1 -1
  169. package/dist/esm/common/floorPlan/floorPlan.triangulate.mjs +1 -1
  170. package/dist/esm/common/floorPlan/floorPlan.triangulate.mjs.map +1 -1
  171. package/dist/esm/common/floorPlan/floorPlan.types.mjs +1 -1
  172. package/dist/esm/common/floorPlan/floorPlan.types.mjs.map +1 -1
  173. package/dist/esm/common/floorPlan/legacySvg.mjs +1 -1
  174. package/dist/esm/common/floorPlan/legacySvg.mjs.map +1 -1
  175. package/dist/esm/common/hooks/useAnchorTracking.mjs +1 -1
  176. package/dist/esm/common/hooks/useAnchorTracking.mjs.map +1 -1
  177. package/dist/esm/common/hooks/useCoarsePointer.mjs +1 -1
  178. package/dist/esm/common/hooks/useCoarsePointer.mjs.map +1 -1
  179. package/dist/esm/common/hooks/useFocusBoundary.mjs +1 -1
  180. package/dist/esm/common/hooks/useFocusBoundary.mjs.map +1 -1
  181. package/dist/esm/common/hooks/useMediaQuery.mjs +1 -1
  182. package/dist/esm/common/hooks/useMediaQuery.mjs.map +1 -1
  183. package/dist/esm/common/hooks/useOverlay.mjs +1 -1
  184. package/dist/esm/common/hooks/useOverlay.mjs.map +1 -1
  185. package/dist/esm/common/hooks/useSheet.mjs +1 -1
  186. package/dist/esm/common/hooks/useSheet.mjs.map +1 -1
  187. package/dist/esm/common/hooks/useSwipeDismiss.mjs +1 -1
  188. package/dist/esm/common/hooks/useSwipeDismiss.mjs.map +1 -1
  189. package/dist/esm/common/hooks/useVisualViewportSize.mjs +1 -1
  190. package/dist/esm/common/hooks/useVisualViewportSize.mjs.map +1 -1
  191. package/dist/esm/common/iconPicker/iconPicker.mjs +1 -1
  192. package/dist/esm/common/iconPicker/iconPicker.mjs.map +1 -1
  193. package/dist/esm/common/iconPicker/iconPicker.module.mjs +1 -1
  194. package/dist/esm/common/idleManager/idleManager.mjs +1 -1
  195. package/dist/esm/common/idleManager/idleManager.mjs.map +1 -1
  196. package/dist/esm/common/infiniteBlock/infiniteBlock.mjs +1 -1
  197. package/dist/esm/common/infiniteBlock/infiniteBlock.mjs.map +1 -1
  198. package/dist/esm/common/infiniteBlock/infiniteBlock.module.mjs +1 -1
  199. package/dist/esm/common/input/input.mjs +1 -1
  200. package/dist/esm/common/input/input.mjs.map +1 -1
  201. package/dist/esm/common/input/input.module.mjs +1 -1
  202. package/dist/esm/common/input/input.module.mjs.map +1 -1
  203. package/dist/esm/common/input/input.types.mjs +1 -1
  204. package/dist/esm/common/input/input.types.mjs.map +1 -1
  205. package/dist/esm/common/inputDropdown/inputDropdown.mjs +1 -1
  206. package/dist/esm/common/inputDropdown/inputDropdown.mjs.map +1 -1
  207. package/dist/esm/common/inputDropdown/inputDropdown.module.mjs +1 -1
  208. package/dist/esm/common/inputDropdown/inputDropdown.module.mjs.map +1 -1
  209. package/dist/esm/common/interactableDiv/index.mjs +1 -1
  210. package/dist/esm/common/interactableDiv/index.mjs.map +1 -1
  211. package/dist/esm/common/interactableDiv/interactableDiv.mjs +1 -1
  212. package/dist/esm/common/interactableDiv/interactableDiv.mjs.map +1 -1
  213. package/dist/esm/common/interactableDiv/interactableDiv.module.mjs +1 -1
  214. package/dist/esm/common/kanbanBoard/KanbanBoard.mjs +1 -1
  215. package/dist/esm/common/kanbanBoard/KanbanBoard.mjs.map +1 -1
  216. package/dist/esm/common/kanbanBoard/KanbanColumn.mjs +1 -1
  217. package/dist/esm/common/kanbanBoard/KanbanColumn.mjs.map +1 -1
  218. package/dist/esm/common/kanbanBoard/KanbanItem.mjs +1 -1
  219. package/dist/esm/common/kanbanBoard/KanbanItem.mjs.map +1 -1
  220. package/dist/esm/common/kanbanBoard/kanbanBoard.module.mjs +1 -1
  221. package/dist/esm/common/kanbanBoard/kanbanBoard.utils.mjs +1 -1
  222. package/dist/esm/common/kanbanBoard/kanbanBoard.utils.mjs.map +1 -1
  223. package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.mjs +1 -1
  224. package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.mjs.map +1 -1
  225. package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.module.mjs +1 -1
  226. package/dist/esm/common/klipyPicker/components/gifView/gifView.mjs +1 -1
  227. package/dist/esm/common/klipyPicker/components/gifView/gifView.mjs.map +1 -1
  228. package/dist/esm/common/klipyPicker/components/gifView/gifView.module.mjs +1 -1
  229. package/dist/esm/common/klipyPicker/klipyPicker.mjs +1 -1
  230. package/dist/esm/common/klipyPicker/klipyPicker.mjs.map +1 -1
  231. package/dist/esm/common/klipyPicker/klipyPicker.module.mjs +1 -1
  232. package/dist/esm/common/loading/iconLoading/iconLoading.mjs +1 -1
  233. package/dist/esm/common/loading/iconLoading/iconLoading.mjs.map +1 -1
  234. package/dist/esm/common/loading/iconLoading/iconLoading.module.mjs +1 -1
  235. package/dist/esm/common/loading/iconLoading/index.mjs +1 -1
  236. package/dist/esm/common/loading/iconLoading/index.mjs.map +1 -1
  237. package/dist/esm/common/loading/spinnerLoading/index.mjs +1 -1
  238. package/dist/esm/common/loading/spinnerLoading/index.mjs.map +1 -1
  239. package/dist/esm/common/loading/spinnerLoading/spinnerLoading.mjs +1 -1
  240. package/dist/esm/common/loading/spinnerLoading/spinnerLoading.mjs.map +1 -1
  241. package/dist/esm/common/loading/spinnerLoading/spinnerLoading.module.mjs +1 -1
  242. package/dist/esm/common/menu/menu.mjs +2 -0
  243. package/dist/esm/common/menu/menu.mjs.map +1 -0
  244. package/dist/esm/common/menu/menu.module.mjs +2 -0
  245. package/dist/esm/common/menu/menu.module.mjs.map +1 -0
  246. package/dist/esm/common/menu/menu.types.mjs +2 -0
  247. package/dist/esm/common/menu/menu.types.mjs.map +1 -0
  248. package/dist/esm/common/modal/modal.mjs +1 -1
  249. package/dist/esm/common/modal/modal.mjs.map +1 -1
  250. package/dist/esm/common/modal/modal.module.mjs +1 -1
  251. package/dist/esm/common/modal/modal.module.mjs.map +1 -1
  252. package/dist/esm/common/multiSelect/multiSelect.mjs +1 -1
  253. package/dist/esm/common/multiSelect/multiSelect.mjs.map +1 -1
  254. package/dist/esm/common/multiSelect/multiSelect.module.mjs +1 -1
  255. package/dist/esm/common/multiSelect/multiSelect.module.mjs.map +1 -1
  256. package/dist/esm/common/numberInput/index.mjs +1 -1
  257. package/dist/esm/common/numberInput/index.mjs.map +1 -1
  258. package/dist/esm/common/numberInput/numberInput.mjs +1 -1
  259. package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
  260. package/dist/esm/common/numberInput/numberInput.module.mjs +1 -1
  261. package/dist/esm/common/numberInput/useStepRepeat.mjs +1 -1
  262. package/dist/esm/common/numberInput/useStepRepeat.mjs.map +1 -1
  263. package/dist/esm/common/optionPicker/optionPicker.mjs +1 -1
  264. package/dist/esm/common/optionPicker/optionPicker.mjs.map +1 -1
  265. package/dist/esm/common/optionPicker/optionPicker.module.mjs +1 -1
  266. package/dist/esm/common/otpInput/otpInput.mjs +1 -1
  267. package/dist/esm/common/otpInput/otpInput.mjs.map +1 -1
  268. package/dist/esm/common/otpInput/otpInput.module.mjs +1 -1
  269. package/dist/esm/common/otpInput/otpInput.types.mjs +1 -1
  270. package/dist/esm/common/otpInput/otpInput.types.mjs.map +1 -1
  271. package/dist/esm/common/overscroll/overscroll.mjs +1 -1
  272. package/dist/esm/common/overscroll/overscroll.mjs.map +1 -1
  273. package/dist/esm/common/overscroll/overscroll.module.mjs +1 -1
  274. package/dist/esm/common/pagination/pagination.mjs +1 -1
  275. package/dist/esm/common/pagination/pagination.mjs.map +1 -1
  276. package/dist/esm/common/pagination/pagination.module.mjs +1 -1
  277. package/dist/esm/common/planCanvas/planCanvas.mjs +1 -1
  278. package/dist/esm/common/planCanvas/planCanvas.mjs.map +1 -1
  279. package/dist/esm/common/planCanvas/planCanvas.module.mjs +1 -1
  280. package/dist/esm/common/popover/popover.mjs +1 -1
  281. package/dist/esm/common/popover/popover.mjs.map +1 -1
  282. package/dist/esm/common/popover/popover.module.mjs +1 -1
  283. package/dist/esm/common/popover/popover.module.mjs.map +1 -1
  284. package/dist/esm/common/popover/popover.types.mjs +1 -1
  285. package/dist/esm/common/popover/popover.types.mjs.map +1 -1
  286. package/dist/esm/common/popover/usePopoverPosition.mjs +1 -1
  287. package/dist/esm/common/popover/usePopoverPosition.mjs.map +1 -1
  288. package/dist/esm/common/progressBar/progressBar.mjs +1 -1
  289. package/dist/esm/common/progressBar/progressBar.mjs.map +1 -1
  290. package/dist/esm/common/progressBar/progressBar.module.mjs +1 -1
  291. package/dist/esm/common/progressBar/progressBar.module.mjs.map +1 -1
  292. package/dist/esm/common/radioGroup/radioGroup.mjs +1 -1
  293. package/dist/esm/common/radioGroup/radioGroup.mjs.map +1 -1
  294. package/dist/esm/common/radioGroup/radioGroup.module.mjs +1 -1
  295. package/dist/esm/common/radioGroup/radioGroup.module.mjs.map +1 -1
  296. package/dist/esm/common/radioGroup/radioGroup.types.mjs +1 -1
  297. package/dist/esm/common/radioGroup/radioGroup.types.mjs.map +1 -1
  298. package/dist/esm/common/rating/rating.mjs +1 -1
  299. package/dist/esm/common/rating/rating.mjs.map +1 -1
  300. package/dist/esm/common/rating/rating.module.mjs +1 -1
  301. package/dist/esm/common/revealLens/revealLens.mjs +1 -1
  302. package/dist/esm/common/revealLens/revealLens.mjs.map +1 -1
  303. package/dist/esm/common/revealLens/revealLens.module.mjs +1 -1
  304. package/dist/esm/common/ripple/ripple.mjs +1 -1
  305. package/dist/esm/common/ripple/ripple.mjs.map +1 -1
  306. package/dist/esm/common/ripple/ripple.module.mjs +1 -1
  307. package/dist/esm/common/ripple/ripple.module.mjs.map +1 -1
  308. package/dist/esm/common/roomDrawer/roomDrawer.mjs +1 -1
  309. package/dist/esm/common/roomDrawer/roomDrawer.mjs.map +1 -1
  310. package/dist/esm/common/roomDrawer/roomDrawer.module.mjs +1 -1
  311. package/dist/esm/common/roomDrawer/usePlanHistory.mjs +1 -1
  312. package/dist/esm/common/roomDrawer/usePlanHistory.mjs.map +1 -1
  313. package/dist/esm/common/roomViewer/roomViewer.mjs +1 -1
  314. package/dist/esm/common/roomViewer/roomViewer.mjs.map +1 -1
  315. package/dist/esm/common/roomViewer/roomViewer.module.mjs +1 -1
  316. package/dist/esm/common/scrollbarProvider/index.mjs +1 -1
  317. package/dist/esm/common/scrollbarProvider/index.mjs.map +1 -1
  318. package/dist/esm/common/scrollbarProvider/scrollbarProvider.mjs +1 -1
  319. package/dist/esm/common/scrollbarProvider/scrollbarProvider.mjs.map +1 -1
  320. package/dist/esm/common/scrollbarProvider/scrollbarProvider.module.mjs +1 -1
  321. package/dist/esm/common/searchInput/searchInput.mjs +1 -1
  322. package/dist/esm/common/searchInput/searchInput.mjs.map +1 -1
  323. package/dist/esm/common/searchInput/searchInput.module.mjs +1 -1
  324. package/dist/esm/common/sectionHeader/sectionHeader.mjs +1 -1
  325. package/dist/esm/common/sectionHeader/sectionHeader.mjs.map +1 -1
  326. package/dist/esm/common/sectionHeader/sectionHeader.module.mjs +1 -1
  327. package/dist/esm/common/sectionHeader/sectionHeader.types.mjs +1 -1
  328. package/dist/esm/common/sectionHeader/sectionHeader.types.mjs.map +1 -1
  329. package/dist/esm/common/sheetBackdrop/sheetBackdrop.mjs +1 -1
  330. package/dist/esm/common/sheetBackdrop/sheetBackdrop.mjs.map +1 -1
  331. package/dist/esm/common/skeleton/skeleton.mjs +1 -1
  332. package/dist/esm/common/skeleton/skeleton.mjs.map +1 -1
  333. package/dist/esm/common/skeleton/skeleton.module.mjs +1 -1
  334. package/dist/esm/common/skeleton/skeleton.types.mjs +1 -1
  335. package/dist/esm/common/skeleton/skeleton.types.mjs.map +1 -1
  336. package/dist/esm/common/slider/slider.mjs +1 -1
  337. package/dist/esm/common/slider/slider.mjs.map +1 -1
  338. package/dist/esm/common/slider/slider.module.mjs +1 -1
  339. package/dist/esm/common/splitButton/splitButton.mjs +1 -1
  340. package/dist/esm/common/splitButton/splitButton.mjs.map +1 -1
  341. package/dist/esm/common/splitButton/splitButton.module.mjs +1 -1
  342. package/dist/esm/common/splitButton/splitButton.module.mjs.map +1 -1
  343. package/dist/esm/common/stepper/stepper.mjs +1 -1
  344. package/dist/esm/common/stepper/stepper.mjs.map +1 -1
  345. package/dist/esm/common/stepper/stepper.module.mjs +1 -1
  346. package/dist/esm/common/stepper/stepper.types.mjs +1 -1
  347. package/dist/esm/common/stepper/stepper.types.mjs.map +1 -1
  348. package/dist/esm/common/sticky/sticky.mjs +1 -1
  349. package/dist/esm/common/sticky/sticky.mjs.map +1 -1
  350. package/dist/esm/common/sticky/sticky.module.mjs +1 -1
  351. package/dist/esm/common/sticky/stickyStack.mjs +1 -1
  352. package/dist/esm/common/sticky/stickyStack.mjs.map +1 -1
  353. package/dist/esm/common/styles/sheet.module.mjs +1 -1
  354. package/dist/esm/common/styles/sheet.module.mjs.map +1 -1
  355. package/dist/esm/common/switch/switch.mjs +1 -1
  356. package/dist/esm/common/switch/switch.mjs.map +1 -1
  357. package/dist/esm/common/switch/switch.module.mjs +1 -1
  358. package/dist/esm/common/switch/switch.module.mjs.map +1 -1
  359. package/dist/esm/common/tabHeader/tabHeader.mjs +1 -1
  360. package/dist/esm/common/tabHeader/tabHeader.mjs.map +1 -1
  361. package/dist/esm/common/tabHeader/tabHeader.module.mjs +1 -1
  362. package/dist/esm/common/textarea/textarea.mjs +1 -1
  363. package/dist/esm/common/textarea/textarea.mjs.map +1 -1
  364. package/dist/esm/common/themeProvider/defaultTheme.mjs +1 -1
  365. package/dist/esm/common/themeProvider/defaultTheme.mjs.map +1 -1
  366. package/dist/esm/common/themeProvider/lightTheme.mjs +2 -0
  367. package/dist/esm/common/themeProvider/lightTheme.mjs.map +1 -0
  368. package/dist/esm/common/themeProvider/theme.module.mjs +1 -1
  369. package/dist/esm/common/themeProvider/themeProvider.mjs +1 -1
  370. package/dist/esm/common/themeProvider/themeProvider.mjs.map +1 -1
  371. package/dist/esm/common/themeProvider/themeVariablesContext.mjs +1 -1
  372. package/dist/esm/common/themeProvider/themeVariablesContext.mjs.map +1 -1
  373. package/dist/esm/common/themeProvider/useTheme.mjs +1 -1
  374. package/dist/esm/common/themeProvider/useTheme.mjs.map +1 -1
  375. package/dist/esm/common/tilt/tilt.mjs +1 -1
  376. package/dist/esm/common/tilt/tilt.mjs.map +1 -1
  377. package/dist/esm/common/tilt/tilt.module.mjs +1 -1
  378. package/dist/esm/common/tilt/tiltMath.mjs +1 -1
  379. package/dist/esm/common/tilt/tiltMath.mjs.map +1 -1
  380. package/dist/esm/common/tiltGroup/tiltGroup.mjs +1 -1
  381. package/dist/esm/common/tiltGroup/tiltGroup.mjs.map +1 -1
  382. package/dist/esm/common/timeInput/components/clockDial/clockDial.mjs +1 -1
  383. package/dist/esm/common/timeInput/components/clockDial/clockDial.mjs.map +1 -1
  384. package/dist/esm/common/timeInput/components/clockDial/clockDial.module.mjs +1 -1
  385. package/dist/esm/common/timeInput/timeFunctions.mjs +1 -1
  386. package/dist/esm/common/timeInput/timeFunctions.mjs.map +1 -1
  387. package/dist/esm/common/timeInput/timeInput.mjs +1 -1
  388. package/dist/esm/common/timeInput/timeInput.mjs.map +1 -1
  389. package/dist/esm/common/timeInput/timeInput.module.mjs +1 -1
  390. package/dist/esm/common/timeline/timeline.mjs +1 -1
  391. package/dist/esm/common/timeline/timeline.mjs.map +1 -1
  392. package/dist/esm/common/timeline/timeline.module.mjs +1 -1
  393. package/dist/esm/common/timeline/timeline.types.mjs +1 -1
  394. package/dist/esm/common/timeline/timeline.types.mjs.map +1 -1
  395. package/dist/esm/common/timer/timer.chime.mjs +1 -1
  396. package/dist/esm/common/timer/timer.chime.mjs.map +1 -1
  397. package/dist/esm/common/timer/timer.mjs +1 -1
  398. package/dist/esm/common/timer/timer.mjs.map +1 -1
  399. package/dist/esm/common/timer/timer.module.mjs +1 -1
  400. package/dist/esm/common/toast/toast.mjs +1 -1
  401. package/dist/esm/common/toast/toast.mjs.map +1 -1
  402. package/dist/esm/common/toast/toast.module.mjs +1 -1
  403. package/dist/esm/common/toast/toast.module.mjs.map +1 -1
  404. package/dist/esm/common/toast/toastProvider.mjs +1 -1
  405. package/dist/esm/common/toast/toastProvider.mjs.map +1 -1
  406. package/dist/esm/common/toast/toastService.mjs +1 -1
  407. package/dist/esm/common/toast/toastService.mjs.map +1 -1
  408. package/dist/esm/common/tooltip/tooltip.mjs +1 -1
  409. package/dist/esm/common/tooltip/tooltip.mjs.map +1 -1
  410. package/dist/esm/common/tooltip/tooltip.module.mjs +1 -1
  411. package/dist/esm/common/tooltip/tooltip.module.mjs.map +1 -1
  412. package/dist/esm/common/tree/flattenTree.mjs +1 -1
  413. package/dist/esm/common/tree/flattenTree.mjs.map +1 -1
  414. package/dist/esm/common/tree/tree.mjs +1 -1
  415. package/dist/esm/common/tree/tree.mjs.map +1 -1
  416. package/dist/esm/common/tree/tree.module.mjs +1 -1
  417. package/dist/esm/common/tree/tree.module.mjs.map +1 -1
  418. package/dist/esm/common/utils/activationKey.mjs +1 -1
  419. package/dist/esm/common/utils/activationKey.mjs.map +1 -1
  420. package/dist/esm/common/utils/mergeRefs.mjs +2 -0
  421. package/dist/esm/common/utils/mergeRefs.mjs.map +1 -0
  422. package/dist/esm/common/utils/renderIcon.mjs +1 -1
  423. package/dist/esm/common/utils/renderIcon.mjs.map +1 -1
  424. package/dist/esm/common/utils/scrollAncestors.mjs +1 -1
  425. package/dist/esm/common/utils/scrollAncestors.mjs.map +1 -1
  426. package/dist/esm/common/utils/visualViewport.mjs +1 -1
  427. package/dist/esm/common/utils/visualViewport.mjs.map +1 -1
  428. package/dist/esm/common/virtualList/useColumnResize.mjs +1 -1
  429. package/dist/esm/common/virtualList/useColumnResize.mjs.map +1 -1
  430. package/dist/esm/common/virtualList/useColumns.mjs +1 -1
  431. package/dist/esm/common/virtualList/useColumns.mjs.map +1 -1
  432. package/dist/esm/common/virtualList/useHeaderNavigation.mjs +1 -1
  433. package/dist/esm/common/virtualList/useHeaderNavigation.mjs.map +1 -1
  434. package/dist/esm/common/virtualList/useRowDrag.mjs +1 -1
  435. package/dist/esm/common/virtualList/useRowDrag.mjs.map +1 -1
  436. package/dist/esm/common/virtualList/useRowNavigation.mjs +1 -1
  437. package/dist/esm/common/virtualList/useRowNavigation.mjs.map +1 -1
  438. package/dist/esm/common/virtualList/useSelection.mjs +1 -1
  439. package/dist/esm/common/virtualList/useSelection.mjs.map +1 -1
  440. package/dist/esm/common/virtualList/useSorting.mjs +1 -1
  441. package/dist/esm/common/virtualList/useSorting.mjs.map +1 -1
  442. package/dist/esm/common/virtualList/useVirtualWindow.mjs +1 -1
  443. package/dist/esm/common/virtualList/useVirtualWindow.mjs.map +1 -1
  444. package/dist/esm/common/virtualList/virtualList.mjs +1 -1
  445. package/dist/esm/common/virtualList/virtualList.mjs.map +1 -1
  446. package/dist/esm/common/virtualList/virtualList.module.mjs +1 -1
  447. package/dist/esm/common/virtualList/virtualList.module.mjs.map +1 -1
  448. package/dist/esm/common/virtualList/virtualList.utils.mjs +1 -1
  449. package/dist/esm/common/virtualList/virtualList.utils.mjs.map +1 -1
  450. package/dist/esm/common/virtualList/virtualListHeader.mjs +1 -1
  451. package/dist/esm/common/virtualList/virtualListHeader.mjs.map +1 -1
  452. package/dist/esm/common/virtualList/virtualRow.mjs +1 -1
  453. package/dist/esm/common/virtualList/virtualRow.mjs.map +1 -1
  454. package/dist/esm/common/wizard/wizard.mjs +1 -1
  455. package/dist/esm/common/wizard/wizard.mjs.map +1 -1
  456. package/dist/esm/common/wizard/wizard.module.mjs +1 -1
  457. package/dist/esm/hooks/useWindowSize.mjs +1 -1
  458. package/dist/esm/hooks/useWindowSize.mjs.map +1 -1
  459. package/dist/esm/index.mjs +1 -1
  460. package/dist/esm/services/formValidation/FormValidatorGroupWithForm.mjs +1 -1
  461. package/dist/esm/services/formValidation/FormValidatorGroupWithForm.mjs.map +1 -1
  462. package/dist/esm/services/formValidation/index.mjs +1 -1
  463. package/dist/esm/services/formValidation/useFormValidatorGroup.mjs +1 -1
  464. package/dist/esm/services/formValidation/useFormValidatorGroup.mjs.map +1 -1
  465. package/dist/esm/services/formValidation/validatableComponent.mjs +1 -1
  466. package/dist/esm/services/formValidation/validatableComponent.mjs.map +1 -1
  467. package/dist/esm/services/klipy.mjs +1 -1
  468. package/dist/esm/services/klipy.mjs.map +1 -1
  469. package/dist/esm/services/localization.mjs +1 -1
  470. package/dist/esm/services/localization.mjs.map +1 -1
  471. package/dist/index.cjs +3 -3
  472. package/dist/index.cjs.map +1 -1
  473. package/dist/mcp.js +21096 -5
  474. package/dist/style.css +1 -1
  475. package/dist/types/common/actionIcon/actionIcon.types.d.ts +3 -1
  476. package/dist/types/common/card/card.types.d.ts +3 -1
  477. package/dist/types/common/checkbox/checkbox.types.d.ts +3 -1
  478. package/dist/types/common/colorPicker/colorPicker.types.d.ts +4 -0
  479. package/dist/types/common/configProvider/configProvider.d.ts +1 -1
  480. package/dist/types/common/configProvider/configProvider.types.d.ts +6 -3
  481. package/dist/types/common/configProvider/index.d.ts +1 -0
  482. package/dist/types/common/configProvider/presentation.types.d.ts +14 -0
  483. package/dist/types/common/configProvider/usePresentationDefault.d.ts +1 -1
  484. package/dist/types/common/dropdown/dropdown.types.d.ts +1 -1
  485. package/dist/types/common/flip/flip.d.ts +2 -2
  486. package/dist/types/common/flip/flip.types.d.ts +3 -1
  487. package/dist/types/common/hooks/useAnchorTracking.d.ts +1 -1
  488. package/dist/types/common/hooks/useFocusBoundary.d.ts +3 -3
  489. package/dist/types/common/hooks/useSheet.d.ts +1 -1
  490. package/dist/types/common/input/input.types.d.ts +5 -0
  491. package/dist/types/common/interactableDiv/interactableDiv.d.ts +3 -2
  492. package/dist/types/common/loading/spinnerLoading/spinnerLoading.d.ts +0 -5
  493. package/dist/types/common/menu/index.d.ts +2 -0
  494. package/dist/types/common/menu/menu.d.ts +14 -0
  495. package/dist/types/common/menu/menu.types.d.ts +55 -0
  496. package/dist/types/common/modal/modal.types.d.ts +1 -1
  497. package/dist/types/common/multiSelect/multiSelect.types.d.ts +1 -1
  498. package/dist/types/common/numberInput/numberInput.types.d.ts +2 -0
  499. package/dist/types/common/otpInput/otpInput.types.d.ts +2 -0
  500. package/dist/types/common/planCanvas/planCanvas.d.ts +1 -1
  501. package/dist/types/common/planCanvas/planCanvas.types.d.ts +3 -1
  502. package/dist/types/common/popover/popover.types.d.ts +34 -3
  503. package/dist/types/common/popover/usePopoverPosition.d.ts +20 -1
  504. package/dist/types/common/ripple/ripple.d.ts +1 -1
  505. package/dist/types/common/ripple/ripple.types.d.ts +1 -0
  506. package/dist/types/common/roomDrawer/roomDrawer.d.ts +2 -2
  507. package/dist/types/common/roomDrawer/roomDrawer.types.d.ts +3 -1
  508. package/dist/types/common/roomViewer/roomViewer.d.ts +2 -2
  509. package/dist/types/common/roomViewer/roomViewer.types.d.ts +3 -1
  510. package/dist/types/common/searchInput/searchInput.d.ts +1 -1
  511. package/dist/types/common/searchInput/searchInput.types.d.ts +3 -0
  512. package/dist/types/common/splitButton/splitButton.types.d.ts +3 -3
  513. package/dist/types/common/switch/switch.types.d.ts +3 -1
  514. package/dist/types/common/themeProvider/index.d.ts +1 -0
  515. package/dist/types/common/themeProvider/lightTheme.d.ts +13 -0
  516. package/dist/types/common/tilt/tilt.d.ts +2 -2
  517. package/dist/types/common/tilt/tilt.types.d.ts +3 -1
  518. package/dist/types/common/timer/timer.d.ts +2 -2
  519. package/dist/types/common/timer/timer.types.d.ts +3 -1
  520. package/dist/types/common/tooltip/tooltip.d.ts +1 -1
  521. package/dist/types/common/tooltip/tooltip.types.d.ts +7 -0
  522. package/dist/types/common/types/baseProps.types.d.ts +6 -0
  523. package/dist/types/common/utils/mergeRefs.d.ts +12 -0
  524. package/dist/types/common/virtualList/virtualList.d.ts +2 -4
  525. package/dist/types/common/virtualList/virtualList.types.d.ts +3 -1
  526. package/dist/types/index.d.ts +2 -2
  527. package/docs/Accordion.md +9 -0
  528. package/docs/ActionIcon.md +1 -0
  529. package/docs/Breadcrumb.md +2 -2
  530. package/docs/ButtonGroup.md +1 -1
  531. package/docs/CLAUDE.md +38 -1
  532. package/docs/Card.md +2 -1
  533. package/docs/Checkbox.md +1 -0
  534. package/docs/ColorPicker.md +13 -1
  535. package/docs/ConfigProvider.md +2 -2
  536. package/docs/Dropdown.md +1 -1
  537. package/docs/Input.md +1 -0
  538. package/docs/InputDropdown.md +1 -1
  539. package/docs/InteractableDiv.md +2 -0
  540. package/docs/KlipyPicker.md +1 -1
  541. package/docs/Menu.md +107 -0
  542. package/docs/Modal.md +1 -1
  543. package/docs/NumberInput.md +1 -0
  544. package/docs/OtpInput.md +1 -0
  545. package/docs/Popover.md +11 -5
  546. package/docs/SearchInput.md +1 -0
  547. package/docs/SplitButton.md +8 -4
  548. package/docs/Switch.md +1 -0
  549. package/docs/Textarea.md +1 -0
  550. package/docs/ThemeProvider.md +31 -2
  551. package/docs/Tooltip.md +23 -1
  552. package/docs/VirtualList.md +2 -2
  553. package/package.json +8 -7
  554. package/dist/esm/common/floatingMenu/floatingMenu.mjs +0 -2
  555. package/dist/esm/common/floatingMenu/floatingMenu.mjs.map +0 -1
  556. package/dist/esm/common/floatingMenu/floatingMenu.module.mjs +0 -2
  557. package/dist/esm/common/floatingMenu/floatingMenu.module.mjs.map +0 -1
  558. package/dist/esm/common/floatingMenu/floatingMenu.types.mjs +0 -2
  559. package/dist/esm/common/floatingMenu/floatingMenu.types.mjs.map +0 -1
  560. package/dist/esm/common/floatingMenu/useFloatingPosition.mjs +0 -2
  561. package/dist/esm/common/floatingMenu/useFloatingPosition.mjs.map +0 -1
  562. package/dist/types/common/floatingMenu/floatingMenu.d.ts +0 -3
  563. package/dist/types/common/floatingMenu/floatingMenu.types.d.ts +0 -32
  564. package/dist/types/common/floatingMenu/index.d.ts +0 -2
  565. package/dist/types/common/floatingMenu/useFloatingPosition.d.ts +0 -27
  566. package/docs/FloatingMenu.md +0 -90
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.mjs","names":[],"sources":["../../../../package/common/tooltip/tooltip.tsx"],"sourcesContent":["import React, { useLayoutEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\nimport { useFloatingPosition } from '../floatingMenu/useFloatingPosition';\nimport styles from './tooltip.module.pcss';\nimport type { TooltipProps } from './tooltip.types';\n\nexport default function Tooltip({ variant, message = '', isVisible = true, tooltipPosition, onClick }: TooltipProps) {\n const [detailsHovered, setDetailsHovered] = useState(false);\n\n const sentinelRef = useRef<HTMLSpanElement>(null);\n const detailsRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLElement | null>(null);\n const anchorRef = useRef<HTMLDivElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const [triggerWidth, setTriggerWidth] = useState(10);\n\n const shown = variant === 'details' ? detailsHovered : isVisible;\n\n useLayoutEffect(() => {\n triggerRef.current = variant === 'details' ? detailsRef.current : (sentinelRef.current?.parentElement ?? null);\n });\n\n useLayoutEffect(() => {\n if (shown) {\n const rect = triggerRef.current?.getBoundingClientRect();\n setTriggerWidth(rect?.width ?? 10);\n }\n }, [shown]);\n\n useFloatingPosition({\n isOpen: shown,\n triggerRef,\n anchorRef,\n panelRef,\n flipClassName: styles.tooltipAnchorFlip,\n placement: 'top',\n });\n\n const bubble = shown && (\n <BodyEnd>\n <div\n ref={anchorRef}\n className={styles.tooltipAnchor}\n style={{ width: `${triggerWidth}px`, '--tooltip-trigger-width': `${triggerWidth}px` } as React.CSSProperties}\n >\n <div\n ref={panelRef}\n className={cx(variant === 'error' ? styles.tooltipError : styles.tooltipBubble, tooltipPosition)}\n onClick={onClick}\n >\n {message}\n </div>\n </div>\n </BodyEnd>\n );\n\n if (variant === 'details') {\n return (\n <div ref={detailsRef} className={styles.tooltipDetails}>\n <span\n className={styles.tooltipDetailsIcon}\n onMouseEnter={() => setDetailsHovered(true)}\n onMouseLeave={() => setDetailsHovered(false)}\n >\n ?\n </span>\n {bubble}\n </div>\n );\n }\n\n if (variant === 'info' || variant === 'error') {\n return (\n <>\n <span ref={sentinelRef} style={{ display: 'none' }} />\n {bubble}\n </>\n );\n }\n\n return null;\n}\n"],"mappings":"oTAOA,SAAwB,EAAQ,CAAE,UAAS,UAAU,GAAI,YAAY,GAAM,kBAAiB,WAAyB,CACnH,GAAM,CAAC,EAAgB,GAAqB,EAAS,EAAK,EAEpD,EAAc,EAAwB,IAAI,EAC1C,EAAa,EAAuB,IAAI,EACxC,EAAa,EAA2B,IAAI,EAC5C,EAAY,EAAuB,IAAI,EACvC,EAAW,EAAuB,IAAI,EACtC,CAAC,EAAc,GAAmB,EAAS,EAAE,EAE7C,EAAQ,IAAY,UAAY,EAAiB,EAEvD,MAAsB,CACpB,EAAW,QAAU,IAAY,UAAY,EAAW,QAAW,EAAY,SAAS,eAAiB,IAC3G,CAAC,EAED,MAAsB,CACpB,GAAI,EAAO,CACT,IAAM,EAAO,EAAW,SAAS,sBAAsB,EACvD,EAAgB,GAAM,OAAS,EAAE,CACnC,CACF,EAAG,CAAC,CAAK,CAAC,EAEV,EAAoB,CAClB,OAAQ,EACR,aACA,YACA,WACA,cAAe,EAAO,kBACtB,UAAW,KACb,CAAC,EAED,IAAM,EAAS,GACb,EAAC,EAAD,CAAA,SACE,EAAC,MAAD,CACE,IAAK,EACL,UAAW,EAAO,cAClB,MAAO,CAAE,MAAO,GAAG,EAAa,IAAK,0BAA2B,GAAG,EAAa,GAAI,EAEpF,SAAA,EAAC,MAAD,CACE,IAAK,EACL,UAAW,EAAG,IAAY,QAAU,EAAO,aAAe,EAAO,cAAe,CAAe,EACtF,UAER,SAAA,CACE,CAAA,CACF,CAAA,CACE,CAAA,EA2BX,OAxBI,IAAY,UAEZ,EAAC,MAAD,CAAK,IAAK,EAAY,UAAW,EAAO,eAAxC,SAAA,CACE,EAAC,OAAD,CACE,UAAW,EAAO,mBAClB,iBAAoB,EAAkB,EAAI,EAC1C,iBAAoB,EAAkB,EAAK,EAC5C,SAAA,GAEK,CAAA,EACL,CACE,IAIL,IAAY,QAAU,IAAY,QAElC,EAAA,EAAA,CAAA,SAAA,CACE,EAAC,OAAD,CAAM,IAAK,EAAa,MAAO,CAAE,QAAS,MAAO,CAAI,CAAA,EACpD,CACD,CAAA,CAAA,EAIC,IACT"}
1
+ {"version":3,"file":"tooltip.mjs","names":[],"sources":["../../../../package/common/tooltip/tooltip.tsx"],"sourcesContent":["import React, { useEffect, useId, useLayoutEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\nimport { useLabels } from 'components/common/configProvider';\nimport { usePopoverPosition } from '../popover/usePopoverPosition';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport { isSelfActivation } from '../utils/activationKey';\nimport styles from './tooltip.module.pcss';\nimport type { TooltipLabels, TooltipProps } from './tooltip.types';\n\n/** The gap the arrow sits in, between the bubble and the trigger it points at. */\nconst TOOLTIP_OFFSET = 6;\n\nconst DEFAULT_LABELS: Required<TooltipLabels> = { details: 'More information' };\n\nexport default function Tooltip({\n variant,\n message = '',\n isVisible = true,\n tooltipPosition,\n onClick,\n labels,\n}: TooltipProps) {\n const [detailsHovered, setDetailsHovered] = useState(false);\n const text = useLabels('Tooltip', labels, DEFAULT_LABELS);\n\n const sentinelRef = useRef<HTMLSpanElement>(null);\n const detailsRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLElement | null>(null);\n const bubbleRef = useRef<HTMLDivElement>(null);\n // The bubble draws its own arrow in CSS, pointed by `--tooltip-trigger-width`,\n // rather than taking Popover's separate arrow element.\n const arrowRef = useRef<HTMLElement | null>(null);\n const [triggerWidth, setTriggerWidth] = useState(10);\n const bubbleId = useId();\n\n const shown = variant === 'details' ? detailsHovered : isVisible;\n\n useLayoutEffect(() => {\n triggerRef.current = variant === 'details' ? detailsRef.current : (sentinelRef.current?.parentElement ?? null);\n });\n\n // The trigger is whatever element the consumer happened to put the Tooltip inside, so the\n // description can only be attached to it from here, imperatively. Removed again when the\n // bubble goes, since aria-describedby pointing at a missing id reads as no description at all.\n useEffect(() => {\n const trigger = triggerRef.current;\n if (!trigger || !shown) return;\n trigger.setAttribute('aria-describedby', bubbleId);\n return () => trigger.removeAttribute('aria-describedby');\n }, [shown, bubbleId]);\n\n useLayoutEffect(() => {\n if (shown) {\n const rect = triggerRef.current?.getBoundingClientRect();\n setTriggerWidth(rect?.width ?? 10);\n }\n }, [shown]);\n\n usePopoverPosition({\n isOpen: shown,\n placement: PopoverPlacement.Top,\n // An error hangs off the trailing edge of the field it belongs to; the other\n // two off the leading edge, which is where their arrow is drawn.\n align: variant === 'error' ? PopoverAlign.End : PopoverAlign.Start,\n offset: TOOLTIP_OFFSET,\n triggerRef,\n floatingRef: bubbleRef,\n panelRef: bubbleRef,\n arrowRef,\n // A bubble that slid off its trigger's edge to stay on screen would leave its\n // arrow pointing at nothing. Wrapping one more line keeps both.\n shrinkToFit: true,\n });\n\n const bubble = shown && (\n <BodyEnd>\n <div\n ref={bubbleRef}\n id={bubbleId}\n // An error appears in answer to something the user just did, so it has to be announced;\n // the other two only describe what is already focused.\n role={variant === 'error' ? 'alert' : 'tooltip'}\n className={cx(variant === 'error' ? styles.tooltipError : styles.tooltipBubble, tooltipPosition)}\n style={{ '--tooltip-trigger-width': `${triggerWidth}px` } as React.CSSProperties}\n onClick={onClick}\n >\n {message}\n </div>\n </BodyEnd>\n );\n\n if (variant === 'details') {\n return (\n <div ref={detailsRef} className={styles.tooltipDetails}>\n <span\n className={styles.tooltipDetailsIcon}\n role='button'\n tabIndex={0}\n aria-label={text.details}\n aria-expanded={detailsHovered}\n onMouseEnter={() => setDetailsHovered(true)}\n onMouseLeave={() => setDetailsHovered(false)}\n // Hover alone would leave the icon unreachable without a pointer, and it is the only\n // way to read what it explains.\n onFocus={() => setDetailsHovered(true)}\n onBlur={() => setDetailsHovered(false)}\n onKeyDown={(event) => {\n if (!isSelfActivation(event)) return;\n event.preventDefault();\n setDetailsHovered((open) => !open);\n }}\n >\n ?\n </span>\n {bubble}\n </div>\n );\n }\n\n if (variant === 'info' || variant === 'error') {\n return (\n <>\n <span ref={sentinelRef} style={{ display: 'none' }} />\n {bubble}\n </>\n );\n }\n\n return null;\n}\n"],"mappings":"giBAWA,IAAM,EAAiB,EAEjB,EAA0C,CAAE,QAAS,kBAAmB,EAE9E,SAAwB,EAAQ,CAC9B,UACA,UAAU,GACV,YAAY,GACZ,kBACA,UACA,UACe,CACf,GAAM,CAAC,EAAgB,GAAqB,EAAS,EAAK,EACpD,EAAO,EAAU,UAAW,EAAQ,CAAc,EAElD,EAAc,EAAwB,IAAI,EAC1C,EAAa,EAAuB,IAAI,EACxC,EAAa,EAA2B,IAAI,EAC5C,EAAY,EAAuB,IAAI,EAGvC,EAAW,EAA2B,IAAI,EAC1C,CAAC,EAAc,GAAmB,EAAS,EAAE,EAC7C,EAAW,EAAM,EAEjB,EAAQ,IAAY,UAAY,EAAiB,EAEvD,MAAsB,CACpB,EAAW,QAAU,IAAY,UAAY,EAAW,QAAW,EAAY,SAAS,eAAiB,IAC3G,CAAC,EAKD,MAAgB,CACd,IAAM,EAAU,EAAW,QACvB,GAAC,GAAY,EAEjB,OADA,EAAQ,aAAa,mBAAoB,CAAQ,MACpC,EAAQ,gBAAgB,kBAAkB,CACzD,EAAG,CAAC,EAAO,CAAQ,CAAC,EAEpB,MAAsB,CACpB,GAAI,EAAO,CACT,IAAM,EAAO,EAAW,SAAS,sBAAsB,EACvD,EAAgB,GAAM,OAAS,EAAE,CACnC,CACF,EAAG,CAAC,CAAK,CAAC,EAEV,EAAmB,CACjB,OAAQ,EACR,UAAW,EAAiB,IAG5B,MAAO,IAAY,QAAU,EAAa,IAAM,EAAa,MAC7D,OAAQ,EACR,aACA,YAAa,EACb,SAAU,EACV,WAGA,YAAa,EACf,CAAC,EAED,IAAM,EAAS,GACb,EAAC,EAAD,CAAA,SACE,EAAC,MAAD,CACE,IAAK,EACL,GAAI,EAGJ,KAAM,IAAY,QAAU,QAAU,UACtC,UAAW,EAAG,IAAY,QAAU,EAAO,aAAe,EAAO,cAAe,CAAe,EAC/F,MAAO,CAAE,0BAA2B,GAAG,EAAa,GAAI,EAC/C,UAER,SAAA,CACE,CAAA,CACE,CAAA,EAwCX,OArCI,IAAY,UAEZ,EAAC,MAAD,CAAK,IAAK,EAAY,UAAW,EAAO,eAAxC,SAAA,CACE,EAAC,OAAD,CACE,UAAW,EAAO,mBAClB,KAAK,SACL,SAAU,EACV,aAAY,EAAK,QACjB,gBAAe,EACf,iBAAoB,EAAkB,EAAI,EAC1C,iBAAoB,EAAkB,EAAK,EAG3C,YAAe,EAAkB,EAAI,EACrC,WAAc,EAAkB,EAAK,EACrC,UAAY,GAAU,CACf,EAAiB,CAAK,IAC3B,EAAM,eAAe,EACrB,EAAmB,GAAS,CAAC,CAAI,EACnC,EACD,SAAA,GAEK,CAAA,EACL,CACE,IAIL,IAAY,QAAU,IAAY,QAElC,EAAA,EAAA,CAAA,SAAA,CACE,EAAC,OAAD,CAAM,IAAK,EAAa,MAAO,CAAE,QAAS,MAAO,CAAI,CAAA,EACpD,CACD,CAAA,CAAA,EAIC,IACT"}
@@ -1,2 +1,2 @@
1
- var e=`tooltipAnchor_Ew7Xk`,t=`tooltipBubble_uyev0`,n=`tooltip-anchor-flip_qlJyz`,r=`tooltipDetails_R7N16`,i=`tooltipDetails-icon_rsjns`,a=`tooltipError_gUBut`,o={tooltipAnchor:e,tooltipBubble:t,"tooltip-anchor-flip":`tooltip-anchor-flip_qlJyz`,tooltipAnchorFlip:n,tooltipDetails:r,"tooltipDetails-icon":`tooltipDetails-icon_rsjns`,tooltipDetailsIcon:i,tooltipError:a};export{o as default,e as tooltipAnchor,n as tooltipAnchorFlip,t as tooltipBubble,r as tooltipDetails,i as tooltipDetailsIcon,a as tooltipError};
1
+ "use client";var e=`tooltipBubble_uyev0`,t=`tooltipError_gUBut`,n=`tooltipDetails_R7N16`,r=`tooltipDetails-icon_rsjns`,i={tooltipBubble:e,tooltipError:t,tooltipDetails:n,"tooltipDetails-icon":`tooltipDetails-icon_rsjns`,tooltipDetailsIcon:r};export{i as default,e as tooltipBubble,n as tooltipDetails,r as tooltipDetailsIcon,t as tooltipError};
2
2
  //# sourceMappingURL=tooltip.module.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.module.mjs","names":[],"sources":["../../../../package/common/tooltip/tooltip.module.pcss"],"sourcesContent":[".tooltipAnchor {\n /* Resolved once per root so the bubble, its arrow and the badge cannot drift apart. The\n default is an inverse of the theme, not a fixed slate: a tooltip has to separate from\n the page it floats over, and a dark bubble sat almost invisibly on a dark theme. */\n --custom-tooltip-background: var(--tooltip-background, color-mix(in oklab, var(--text-color) 82%, var(--background)));\n --custom-tooltip-color: var(--tooltip-color, var(--background));\n\n position: fixed;\n z-index: 10;\n}\n\n.tooltipBubble {\n position: absolute;\n bottom: 0;\n\n /* The lengths here are em against this bubble's own 0.75em, so the ratios are of 12px,\n not 16, and max-width is a line measure rather than a pixel cap. */\n margin-bottom: 0.5em;\n left: 0;\n border-radius: 0.25em;\n width: max-content;\n max-width: 16.667em;\n font-size: 0.75em;\n background-color: var(--custom-tooltip-background);\n padding: 0.5em 0.75em;\n color: var(--custom-tooltip-color);\n pointer-events: none;\n\n .tooltip-anchor-flip & {\n bottom: auto;\n top: 0;\n margin-bottom: 0;\n margin-top: 0.5em;\n }\n\n &::after {\n content: '';\n position: absolute;\n top: 100%;\n\n /* The offset must stay half the arrow's own width, or it stops pointing at the trigger. */\n left: calc(var(--tooltip-trigger-width, 10px) / 2 - 0.4167em);\n border-width: 0.4167em;\n border-style: solid;\n border-color: var(--custom-tooltip-background) transparent transparent;\n }\n\n .tooltip-anchor-flip &::after {\n top: auto;\n bottom: 100%;\n border-color: transparent transparent var(--custom-tooltip-background);\n }\n}\n\n.tooltipDetails {\n /* Repeated from .tooltipAnchor above: the badge is a second root, rendered without one. */\n --custom-tooltip-background: var(--tooltip-background, color-mix(in oklab, var(--text-color) 82%, var(--background)));\n --custom-tooltip-color: var(--tooltip-color, var(--background));\n\n position: relative;\n display: inline-flex;\n align-items: center;\n\n &-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n /* The theme's base, not a multiple of the font below: that landed a fraction of a pixel short. */\n width: var(--default-font-size);\n height: var(--default-font-size);\n border-radius: 50%;\n\n /* calc, not em: this badge renders inline wherever the consumer puts it, so em would\n measure that text. The bubble above can use em, being portaled to #bodyEnd. */\n font-size: calc(var(--default-font-size) * 0.6875);\n font-weight: 700;\n background-color: var(--custom-tooltip-background);\n color: var(--custom-tooltip-color);\n cursor: default;\n user-select: none;\n }\n}\n\n.tooltipError {\n position: absolute;\n bottom: 0;\n margin-bottom: 0.6em;\n right: 0;\n width: max-content;\n border-radius: 0.3em;\n background-color: var(--error-lighter);\n color: var(--error-color);\n font-size: 0.625em;\n padding: 0.6em 0.9em;\n\n .tooltip-anchor-flip & {\n bottom: auto;\n top: 0;\n margin-bottom: 0;\n margin-top: 0.6em;\n }\n\n &::after {\n content: '';\n position: absolute;\n top: 100%;\n right: 1.2em;\n border-width: 0.5em;\n border-style: solid;\n border-color: var(--error-border-color) transparent transparent transparent;\n }\n\n .tooltip-anchor-flip &::after {\n top: auto;\n bottom: 100%;\n border-color: transparent transparent var(--error-border-color) transparent;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"tooltip.module.mjs","names":[],"sources":["../../../../package/common/tooltip/tooltip.module.pcss"],"sourcesContent":["/* Both bubbles are portaled to the end of the document and placed by\n `usePopoverPosition`, which writes `top`, `left`, `visibility` and\n `data-placement` straight onto them. */\n.tooltipBubble,\n.tooltipError {\n position: fixed;\n z-index: 10;\n width: max-content;\n\n /* So a max-width is the width you actually get, padding included. Without it the\n screen cap below let the box out by its own padding. */\n box-sizing: border-box;\n\n /* Hidden until the first coordinates are written, to avoid a top-left flash. */\n visibility: hidden;\n}\n\n.tooltipBubble {\n /* Resolved on the bubble so it, its arrow and the badge cannot drift apart. The\n default is an inverse of the theme, not a fixed slate: a tooltip has to separate\n from the page it floats over, and a dark bubble sat almost invisibly on a dark\n theme. */\n --custom-tooltip-background: var(--tooltip-background, color-mix(in oklab, var(--text-color) 82%, var(--background)));\n --custom-tooltip-color: var(--tooltip-color, var(--background));\n\n /* The lengths here are em against this bubble's own 0.75em, so the ratios are of 12px,\n not 16, and max-width is a line measure rather than a pixel cap. */\n border-radius: 0.25em;\n\n /* Padding included, per the border-box above. The second term is the screen, with\n the gutter `usePopoverPosition` keeps when it shifts a panel back on-screen: a\n bubble wider than that cannot be clamped into view, only pushed off one edge,\n so it wraps instead. */\n max-width: min(16.667em, calc(100vw - 16px));\n font-size: 0.75em;\n background-color: var(--custom-tooltip-background);\n padding: 0.5em 0.75em;\n color: var(--custom-tooltip-color);\n pointer-events: none;\n\n &::after {\n content: '';\n position: absolute;\n top: 100%;\n\n /* The bubble's leading edge is the trigger's, so half the trigger's width is the\n trigger's centre. The second term must stay half the arrow's own width, or it\n stops pointing at it. */\n left: calc(var(--tooltip-trigger-width, 10px) / 2 - 0.4167em);\n border-width: 0.4167em;\n border-style: solid;\n border-color: var(--custom-tooltip-background) transparent transparent;\n }\n\n &[data-placement='bottom']::after {\n top: auto;\n bottom: 100%;\n border-color: transparent transparent var(--custom-tooltip-background);\n }\n}\n\n.tooltipDetails {\n /* Repeated from .tooltipBubble above: the badge is a second root, rendered without one. */\n --custom-tooltip-background: var(--tooltip-background, color-mix(in oklab, var(--text-color) 82%, var(--background)));\n --custom-tooltip-color: var(--tooltip-color, var(--background));\n\n position: relative;\n display: inline-flex;\n align-items: center;\n\n &-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n /* The theme's base, not a multiple of the font below: that landed a fraction of a pixel short. */\n width: var(--default-font-size);\n height: var(--default-font-size);\n border-radius: 50%;\n\n /* calc, not em: this badge renders inline wherever the consumer puts it, so em would\n measure that text. The bubble above can use em, being portaled to #bodyEnd. */\n font-size: calc(var(--default-font-size) * 0.6875);\n font-weight: 700;\n background-color: var(--custom-tooltip-background);\n color: var(--custom-tooltip-color);\n cursor: default;\n user-select: none;\n }\n}\n\n.tooltipError {\n border-radius: 0.3em;\n\n /* No measure of its own: a validator's message is as long as it is. The screen is\n still the limit, though, the same one the bubble above takes. */\n max-width: calc(100vw - 16px);\n background-color: var(--error-lighter);\n color: var(--error-color);\n font-size: 0.625em;\n padding: 0.6em 0.9em;\n\n &::after {\n content: '';\n position: absolute;\n top: 100%;\n right: 1.2em;\n border-width: 0.5em;\n border-style: solid;\n border-color: var(--error-border-color) transparent transparent transparent;\n }\n\n &[data-placement='bottom']::after {\n top: auto;\n bottom: 100%;\n border-color: transparent transparent var(--error-border-color) transparent;\n }\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- function e(t,n,r=0,i=null){return t.flatMap((a,o)=>{let s=a.children!==void 0,c=s&&n.includes(a.key),l={node:a,level:r,parentKey:i,isBranch:s,isExpanded:c,setSize:t.length,posInSet:o+1};return!c||!a.children?.length?[l]:[l,...e(a.children,n,r+1,a.key)]})}export{e as flattenTree};
1
+ "use client";function e(t,n,r=0,i=null){return t.flatMap((a,o)=>{let s=a.children!==void 0,c=s&&n.includes(a.key),l={node:a,level:r,parentKey:i,isBranch:s,isExpanded:c,setSize:t.length,posInSet:o+1};return!c||!a.children?.length?[l]:[l,...e(a.children,n,r+1,a.key)]})}export{e as flattenTree};
2
2
  //# sourceMappingURL=flattenTree.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"flattenTree.mjs","names":[],"sources":["../../../../package/common/tree/flattenTree.ts"],"sourcesContent":["import type { FlatTreeNode, TreeNode, TreeValue } from './tree.types';\n\n/** The visible nodes in render order. Flat, not nested, deliberately: see docs/Tree.md. */\nexport function flattenTree(\n nodes: TreeNode[],\n expandedKeys: TreeValue[],\n level = 0,\n parentKey: TreeValue | null = null,\n): FlatTreeNode[] {\n return nodes.flatMap((node, index) => {\n const isBranch = node.children !== undefined;\n const isExpanded = isBranch && expandedKeys.includes(node.key);\n const self: FlatTreeNode = {\n node,\n level,\n parentKey,\n isBranch,\n isExpanded,\n setSize: nodes.length,\n posInSet: index + 1,\n };\n if (!isExpanded || !node.children?.length) return [self];\n return [self, ...flattenTree(node.children, expandedKeys, level + 1, node.key)];\n });\n}\n"],"mappings":"AAGA,SAAgB,EACd,EACA,EACA,EAAQ,EACR,EAA8B,KACd,CAChB,OAAO,EAAM,SAAS,EAAM,IAAU,CACpC,IAAM,EAAW,EAAK,WAAa,IAAA,GAC7B,EAAa,GAAY,EAAa,SAAS,EAAK,GAAG,EACvD,EAAqB,CACzB,OACA,QACA,YACA,WACA,aACA,QAAS,EAAM,OACf,SAAU,EAAQ,CACpB,EAEA,MADI,CAAC,GAAc,CAAC,EAAK,UAAU,OAAe,CAAC,CAAI,EAChD,CAAC,EAAM,GAAG,EAAY,EAAK,SAAU,EAAc,EAAQ,EAAG,EAAK,GAAG,CAAC,CAChF,CAAC,CACH"}
1
+ {"version":3,"file":"flattenTree.mjs","names":[],"sources":["../../../../package/common/tree/flattenTree.ts"],"sourcesContent":["import type { FlatTreeNode, TreeNode, TreeValue } from './tree.types';\n\n/** The visible nodes in render order. Flat, not nested, deliberately: see docs/Tree.md. */\nexport function flattenTree(\n nodes: TreeNode[],\n expandedKeys: TreeValue[],\n level = 0,\n parentKey: TreeValue | null = null,\n): FlatTreeNode[] {\n return nodes.flatMap((node, index) => {\n const isBranch = node.children !== undefined;\n const isExpanded = isBranch && expandedKeys.includes(node.key);\n const self: FlatTreeNode = {\n node,\n level,\n parentKey,\n isBranch,\n isExpanded,\n setSize: nodes.length,\n posInSet: index + 1,\n };\n if (!isExpanded || !node.children?.length) return [self];\n return [self, ...flattenTree(node.children, expandedKeys, level + 1, node.key)];\n });\n}\n"],"mappings":"aAGA,SAAgB,EACd,EACA,EACA,EAAQ,EACR,EAA8B,KACd,CAChB,OAAO,EAAM,SAAS,EAAM,IAAU,CACpC,IAAM,EAAW,EAAK,WAAa,IAAA,GAC7B,EAAa,GAAY,EAAa,SAAS,EAAK,GAAG,EACvD,EAAqB,CACzB,OACA,QACA,YACA,WACA,aACA,QAAS,EAAM,OACf,SAAU,EAAQ,CACpB,EAEA,MADI,CAAC,GAAc,CAAC,EAAK,UAAU,OAAe,CAAC,CAAI,EAChD,CAAC,EAAM,GAAG,EAAY,EAAK,SAAU,EAAc,EAAQ,EAAG,EAAK,GAAG,CAAC,CAChF,CAAC,CACH"}
@@ -1,2 +1,2 @@
1
- import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{renderIcon as n}from"../utils/renderIcon.mjs";import r from"../virtualList/virtualList.mjs";import{flattenTree as i}from"./flattenTree.mjs";import a from"./tree.module.mjs";import{useEffect as o,useRef as s,useState as c}from"react";import l from"classnames";import{faChevronRight as u}from"@fortawesome/free-solid-svg-icons";import{jsx as d,jsxs as f}from"react/jsx-runtime";var ee=[],p={empty:`Nothing here`};function m(m){let{nodes:h,expandedKeys:g,defaultExpandedKeys:_=ee,onExpandedChange:v=()=>{},selectedKey:y,defaultSelectedKey:te,onSelect:b=()=>{},expandOnSelect:x=!0,indent:S=20,toggleIcon:C=u,height:w,estimatedRowHeight:T=32,labels:E,disabled:D=!1,"aria-label":O=`Tree`,className:k,style:ne,classNames:A,styles:j,...M}=e(`Tree`,m),N=t(`Tree`,E,p),P=s(new Map),F=s(null),I=s(null),L=w!==void 0,R=g!==void 0,[z,B]=c(_),V=R?g:z,H=y!==void 0,[U,W]=c(te??null),G=H?y:U,K=i(h,V),q=Math.max(0,K.findIndex(e=>e.node.key===G)),J=K[q]?.node.key;function Y(e){R||B(e),v(e)}function X(e){Y(V.includes(e)?V.filter(t=>t!==e):[...V,e])}function Z(e){D||e.node.disabled||(H||W(e.node.key),b(e.node.key,e.node),x&&e.isBranch&&X(e.node.key))}function Q(e){let t=K[e]?.node.key;if(t===void 0)return;let n=P.current.get(t);if(n){n.focus();return}I.current=t,F.current?.scrollToIndex(e,{align:`center`})}o(()=>{let e=I.current;if(e===null)return;let t=P.current.get(e);t&&(t.focus(),I.current=null)});function re(e,t,n){if(!D)switch(e.key){case`ArrowDown`:e.preventDefault(),Q(Math.min(n+1,K.length-1));break;case`ArrowUp`:e.preventDefault(),Q(Math.max(n-1,0));break;case`ArrowRight`:if(e.preventDefault(),!t.isBranch)break;t.isExpanded?Q(n+1):X(t.node.key);break;case`ArrowLeft`:{if(e.preventDefault(),t.isBranch&&t.isExpanded){X(t.node.key);break}let n=K.findIndex(e=>e.node.key===t.parentKey);n>=0&&Q(n);break}case`Home`:e.preventDefault(),Q(0);break;case`End`:e.preventDefault(),Q(K.length-1);break;case`Enter`:case` `:e.preventDefault(),Z(t)}}function $(e,t){let{node:r,level:i,isBranch:o,isExpanded:s}=e,c=r.key===G,u=D||r.disabled;return f(`div`,{ref:e=>{e?P.current.set(r.key,e):P.current.delete(r.key)},role:`treeitem`,"aria-level":i+1,"aria-setsize":e.setSize,"aria-posinset":e.posInSet,"aria-expanded":o?s:void 0,"aria-selected":c,"aria-disabled":u||void 0,tabIndex:r.key===J&&!u?0:-1,className:l(a.treeNode,c&&a.treeNodeSelected,u&&a.treeNodeDisabled,A?.node),style:{paddingLeft:i*S,...j?.node},onClick:()=>Z(e),onKeyDown:n=>re(n,e,t),children:[d(`span`,{className:l(a.treeToggle,s&&a.treeToggleOpen,!o&&a.treeToggleHidden,A?.toggle),style:j?.toggle,"aria-hidden":`true`,onClick:e=>{e.stopPropagation(),!u&&o&&X(r.key)},children:o&&n(C)}),r.icon&&n(r.icon,{className:l(a.treeIcon,A?.icon),style:j?.icon}),d(`span`,{className:l(a.treeLabel,A?.label),style:j?.label,children:r.label})]},r.key)}return d(`div`,{...M,role:`tree`,"aria-label":O,"aria-disabled":D||void 0,tabIndex:L&&!D?0:void 0,onFocus:e=>{e.target===e.currentTarget&&Q(q)},className:l(a.tree,D&&a.treeDisabled,A?.root,k),style:{...ne,...j?.root},children:K.length===0?d(`div`,{className:l(a.treeEmpty,A?.empty),style:j?.empty,children:N.empty}):L?d(r,{ref:F,items:K,height:w,estimatedRowHeight:T,getItemKey:e=>e.node.key,getItemDepth:e=>e.level,ariaRoles:{container:`none`,row:`none`},keyboardNavigation:!1,renderRow:$}):K.map($)})}export{m as default};
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{renderIcon as n}from"../utils/renderIcon.mjs";import r from"../virtualList/virtualList.mjs";import{flattenTree as i}from"./flattenTree.mjs";import a from"./tree.module.mjs";import{useEffect as o,useRef as s,useState as c}from"react";import l from"classnames";import{faChevronRight as u}from"@fortawesome/free-solid-svg-icons";import{jsx as d,jsxs as f}from"react/jsx-runtime";var ee=[],p={empty:`Nothing here`};function m(m){let{nodes:h,expandedKeys:g,defaultExpandedKeys:_=ee,onExpandedChange:v=()=>{},selectedKey:y,defaultSelectedKey:te,onSelect:b=()=>{},expandOnSelect:x=!0,indent:S=20,toggleIcon:C=u,height:w,estimatedRowHeight:T=32,labels:E,disabled:D=!1,"aria-label":O=`Tree`,className:k,style:ne,classNames:A,styles:j,...M}=e(`Tree`,m),N=t(`Tree`,E,p),P=s(new Map),F=s(null),I=s(null),L=w!==void 0,R=g!==void 0,[z,B]=c(_),V=R?g:z,H=y!==void 0,[U,W]=c(te??null),G=H?y:U,K=i(h,V),q=Math.max(0,K.findIndex(e=>e.node.key===G)),J=K[q]?.node.key;function Y(e){R||B(e),v(e)}function X(e){Y(V.includes(e)?V.filter(t=>t!==e):[...V,e])}function Z(e){D||e.node.disabled||(H||W(e.node.key),b(e.node.key,e.node),x&&e.isBranch&&X(e.node.key))}function Q(e){let t=K[e]?.node.key;if(t===void 0)return;let n=P.current.get(t);if(n){n.focus();return}I.current=t,F.current?.scrollToIndex(e,{align:`center`})}o(()=>{let e=I.current;if(e===null)return;let t=P.current.get(e);t&&(t.focus(),I.current=null)});function re(e,t,n){if(!D)switch(e.key){case`ArrowDown`:e.preventDefault(),Q(Math.min(n+1,K.length-1));break;case`ArrowUp`:e.preventDefault(),Q(Math.max(n-1,0));break;case`ArrowRight`:if(e.preventDefault(),!t.isBranch)break;t.isExpanded?Q(n+1):X(t.node.key);break;case`ArrowLeft`:{if(e.preventDefault(),t.isBranch&&t.isExpanded){X(t.node.key);break}let n=K.findIndex(e=>e.node.key===t.parentKey);n>=0&&Q(n);break}case`Home`:e.preventDefault(),Q(0);break;case`End`:e.preventDefault(),Q(K.length-1);break;case`Enter`:case` `:e.preventDefault(),Z(t)}}function $(e,t){let{node:r,level:i,isBranch:o,isExpanded:s}=e,c=r.key===G,u=D||r.disabled;return f(`div`,{ref:e=>{e?P.current.set(r.key,e):P.current.delete(r.key)},role:`treeitem`,"aria-level":i+1,"aria-setsize":e.setSize,"aria-posinset":e.posInSet,"aria-expanded":o?s:void 0,"aria-selected":c,"aria-disabled":u||void 0,tabIndex:r.key===J&&!u?0:-1,className:l(a.treeNode,c&&a.treeNodeSelected,u&&a.treeNodeDisabled,A?.node),style:{paddingLeft:i*S,...j?.node},onClick:()=>Z(e),onKeyDown:n=>re(n,e,t),children:[d(`span`,{className:l(a.treeToggle,s&&a.treeToggleOpen,!o&&a.treeToggleHidden,A?.toggle),style:j?.toggle,"aria-hidden":`true`,onClick:e=>{e.stopPropagation(),!u&&o&&X(r.key)},children:o&&n(C)}),r.icon&&n(r.icon,{className:l(a.treeIcon,A?.icon),style:j?.icon}),d(`span`,{className:l(a.treeLabel,A?.label),style:j?.label,children:r.label})]},r.key)}return d(`div`,{...M,role:`tree`,"aria-label":O,"aria-disabled":D||void 0,tabIndex:L&&!D?0:void 0,onFocus:e=>{e.target===e.currentTarget&&Q(q)},className:l(a.tree,D&&a.treeDisabled,A?.root,k),style:{...ne,...j?.root},children:K.length===0?d(`div`,{className:l(a.treeEmpty,A?.empty),style:j?.empty,children:N.empty}):L?d(r,{ref:F,items:K,height:w,estimatedRowHeight:T,getItemKey:e=>e.node.key,getItemDepth:e=>e.level,ariaRoles:{container:`none`,row:`none`},keyboardNavigation:!1,renderRow:$}):K.map($)})}export{m as default};
2
2
  //# sourceMappingURL=tree.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"tree.mjs","names":[],"sources":["../../../../package/common/tree/tree.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport type { ReactElement } from 'react';\nimport cx from 'classnames';\nimport { faChevronRight } from '@fortawesome/free-solid-svg-icons';\n\nimport VirtualList from 'components/common/virtualList';\nimport type { VirtualListHandle } from 'components/common/virtualList';\nimport { useComponentDefaults, useLabels } from '../configProvider';\nimport { renderIcon } from '../utils/renderIcon';\nimport { flattenTree } from './flattenTree';\nimport type { FlatTreeNode, TreeLabels, TreeProps, TreeValue } from './tree.types';\n\nimport styles from './tree.module.pcss';\n\nconst EMPTY_KEYS: TreeValue[] = [];\n\nconst DEFAULT_LABELS: Required<TreeLabels> = {\n empty: 'Nothing here',\n};\n\nfunction Tree(props: TreeProps): ReactElement {\n const {\n nodes,\n expandedKeys: controlledExpanded,\n defaultExpandedKeys = EMPTY_KEYS,\n onExpandedChange = () => {},\n selectedKey: controlledSelected,\n defaultSelectedKey,\n onSelect = () => {},\n expandOnSelect = true,\n indent = 20,\n toggleIcon = faChevronRight,\n height,\n estimatedRowHeight = 32,\n labels,\n disabled = false,\n 'aria-label': ariaLabel = 'Tree',\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('Tree', props);\n const text = useLabels('Tree', labels, DEFAULT_LABELS);\n\n const nodeRefs = useRef(new Map<TreeValue, HTMLDivElement>());\n const listRef = useRef<VirtualListHandle>(null);\n const pendingFocusRef = useRef<TreeValue | null>(null);\n const isWindowed = height !== undefined;\n\n const isExpandedControlled = controlledExpanded !== undefined;\n const [internalExpanded, setInternalExpanded] = useState<TreeValue[]>(defaultExpandedKeys);\n const expandedKeys = isExpandedControlled ? controlledExpanded : internalExpanded;\n\n const isSelectedControlled = controlledSelected !== undefined;\n const [internalSelected, setInternalSelected] = useState<TreeValue | null>(defaultSelectedKey ?? null);\n const selectedKey = isSelectedControlled ? controlledSelected : internalSelected;\n\n const visible = flattenTree(nodes, expandedKeys);\n\n // Windowed, the tab stop sits on the container instead of this row: a roving tabindex on a row\n // scrolled out of the window would leave the tree with no tab stop at all.\n const activeIndex = Math.max(\n 0,\n visible.findIndex((entry) => entry.node.key === selectedKey),\n );\n const activeKey = visible[activeIndex]?.node.key;\n\n function setExpanded(next: TreeValue[]) {\n if (!isExpandedControlled) setInternalExpanded(next);\n onExpandedChange(next);\n }\n\n function toggle(key: TreeValue) {\n setExpanded(expandedKeys.includes(key) ? expandedKeys.filter((k) => k !== key) : [...expandedKeys, key]);\n }\n\n function select(entry: FlatTreeNode) {\n if (disabled || entry.node.disabled) return;\n if (!isSelectedControlled) setInternalSelected(entry.node.key);\n onSelect(entry.node.key, entry.node);\n if (expandOnSelect && entry.isBranch) toggle(entry.node.key);\n }\n\n function focusAt(index: number) {\n const key = visible[index]?.node.key;\n if (key === undefined) return;\n\n const element = nodeRefs.current.get(key);\n if (element) {\n element.focus();\n return;\n }\n\n // Outside the window, so it has to be scrolled in before it exists to receive focus.\n pendingFocusRef.current = key;\n listRef.current?.scrollToIndex(index, { align: 'center' });\n }\n\n useEffect(() => {\n const key = pendingFocusRef.current;\n if (key === null) return;\n const element = nodeRefs.current.get(key);\n if (element) {\n element.focus();\n pendingFocusRef.current = null;\n }\n });\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>, entry: FlatTreeNode, index: number) {\n if (disabled) return;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n focusAt(Math.min(index + 1, visible.length - 1));\n break;\n case 'ArrowUp':\n event.preventDefault();\n focusAt(Math.max(index - 1, 0));\n break;\n case 'ArrowRight':\n event.preventDefault();\n if (!entry.isBranch) break;\n if (entry.isExpanded) focusAt(index + 1);\n else toggle(entry.node.key);\n break;\n case 'ArrowLeft': {\n event.preventDefault();\n if (entry.isBranch && entry.isExpanded) {\n toggle(entry.node.key);\n break;\n }\n const parentIndex = visible.findIndex((e) => e.node.key === entry.parentKey);\n if (parentIndex >= 0) focusAt(parentIndex);\n break;\n }\n case 'Home':\n event.preventDefault();\n focusAt(0);\n break;\n case 'End':\n event.preventDefault();\n focusAt(visible.length - 1);\n break;\n case 'Enter':\n case ' ':\n event.preventDefault();\n select(entry);\n break;\n default:\n break;\n }\n }\n\n function renderNode(entry: FlatTreeNode, index: number) {\n const { node, level, isBranch, isExpanded } = entry;\n const isSelected = node.key === selectedKey;\n const isDisabled = disabled || node.disabled;\n\n return (\n <div\n key={node.key}\n ref={(el) => {\n if (el) nodeRefs.current.set(node.key, el);\n else nodeRefs.current.delete(node.key);\n }}\n role='treeitem'\n aria-level={level + 1}\n aria-setsize={entry.setSize}\n aria-posinset={entry.posInSet}\n aria-expanded={isBranch ? isExpanded : undefined}\n aria-selected={isSelected}\n aria-disabled={isDisabled || undefined}\n tabIndex={node.key === activeKey && !isDisabled ? 0 : -1}\n className={cx(\n styles.treeNode,\n isSelected && styles.treeNodeSelected,\n isDisabled && styles.treeNodeDisabled,\n classNames?.node,\n )}\n style={{ paddingLeft: level * indent, ...slotStyles?.node }}\n onClick={() => select(entry)}\n onKeyDown={(event) => handleKeyDown(event, entry, index)}\n >\n <span\n className={cx(\n styles.treeToggle,\n isExpanded && styles.treeToggleOpen,\n !isBranch && styles.treeToggleHidden,\n classNames?.toggle,\n )}\n style={slotStyles?.toggle}\n aria-hidden='true'\n onClick={(event) => {\n event.stopPropagation();\n if (!isDisabled && isBranch) toggle(node.key);\n }}\n >\n {isBranch && renderIcon(toggleIcon)}\n </span>\n\n {node.icon &&\n renderIcon(node.icon, {\n className: cx(styles.treeIcon, classNames?.icon),\n style: slotStyles?.icon,\n })}\n\n <span className={cx(styles.treeLabel, classNames?.label)} style={slotStyles?.label}>\n {node.label}\n </span>\n </div>\n );\n }\n\n return (\n <div\n {...rest}\n role='tree'\n aria-label={ariaLabel}\n aria-disabled={disabled || undefined}\n tabIndex={isWindowed && !disabled ? 0 : undefined}\n onFocus={(event) => {\n if (event.target === event.currentTarget) focusAt(activeIndex);\n }}\n className={cx(styles.tree, disabled && styles.treeDisabled, classNames?.root, className)}\n style={{ ...style, ...slotStyles?.root }}\n >\n {visible.length === 0 ? (\n <div className={cx(styles.treeEmpty, classNames?.empty)} style={slotStyles?.empty}>\n {text.empty}\n </div>\n ) : isWindowed ? (\n <VirtualList\n ref={listRef}\n items={visible}\n height={height}\n estimatedRowHeight={estimatedRowHeight}\n getItemKey={(entry) => entry.node.key}\n getItemDepth={(entry) => entry.level}\n ariaRoles={{ container: 'none', row: 'none' }}\n // Tree owns the keyboard: its rows carry the roving tabindex and their\n // own key handling, and a second tab stop here would sit inside it.\n keyboardNavigation={false}\n renderRow={renderNode}\n />\n ) : (\n visible.map(renderNode)\n )}\n </div>\n );\n}\n\nexport default Tree;\n"],"mappings":"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"}
1
+ {"version":3,"file":"tree.mjs","names":[],"sources":["../../../../package/common/tree/tree.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport type { ReactElement } from 'react';\nimport cx from 'classnames';\nimport { faChevronRight } from '@fortawesome/free-solid-svg-icons';\n\nimport VirtualList from 'components/common/virtualList';\nimport type { VirtualListHandle } from 'components/common/virtualList';\nimport { useComponentDefaults, useLabels } from '../configProvider';\nimport { renderIcon } from '../utils/renderIcon';\nimport { flattenTree } from './flattenTree';\nimport type { FlatTreeNode, TreeLabels, TreeProps, TreeValue } from './tree.types';\n\nimport styles from './tree.module.pcss';\n\nconst EMPTY_KEYS: TreeValue[] = [];\n\nconst DEFAULT_LABELS: Required<TreeLabels> = {\n empty: 'Nothing here',\n};\n\nfunction Tree(props: TreeProps): ReactElement {\n const {\n nodes,\n expandedKeys: controlledExpanded,\n defaultExpandedKeys = EMPTY_KEYS,\n onExpandedChange = () => {},\n selectedKey: controlledSelected,\n defaultSelectedKey,\n onSelect = () => {},\n expandOnSelect = true,\n indent = 20,\n toggleIcon = faChevronRight,\n height,\n estimatedRowHeight = 32,\n labels,\n disabled = false,\n 'aria-label': ariaLabel = 'Tree',\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('Tree', props);\n const text = useLabels('Tree', labels, DEFAULT_LABELS);\n\n const nodeRefs = useRef(new Map<TreeValue, HTMLDivElement>());\n const listRef = useRef<VirtualListHandle>(null);\n const pendingFocusRef = useRef<TreeValue | null>(null);\n const isWindowed = height !== undefined;\n\n const isExpandedControlled = controlledExpanded !== undefined;\n const [internalExpanded, setInternalExpanded] = useState<TreeValue[]>(defaultExpandedKeys);\n const expandedKeys = isExpandedControlled ? controlledExpanded : internalExpanded;\n\n const isSelectedControlled = controlledSelected !== undefined;\n const [internalSelected, setInternalSelected] = useState<TreeValue | null>(defaultSelectedKey ?? null);\n const selectedKey = isSelectedControlled ? controlledSelected : internalSelected;\n\n const visible = flattenTree(nodes, expandedKeys);\n\n // Windowed, the tab stop sits on the container instead of this row: a roving tabindex on a row\n // scrolled out of the window would leave the tree with no tab stop at all.\n const activeIndex = Math.max(\n 0,\n visible.findIndex((entry) => entry.node.key === selectedKey),\n );\n const activeKey = visible[activeIndex]?.node.key;\n\n function setExpanded(next: TreeValue[]) {\n if (!isExpandedControlled) setInternalExpanded(next);\n onExpandedChange(next);\n }\n\n function toggle(key: TreeValue) {\n setExpanded(expandedKeys.includes(key) ? expandedKeys.filter((k) => k !== key) : [...expandedKeys, key]);\n }\n\n function select(entry: FlatTreeNode) {\n if (disabled || entry.node.disabled) return;\n if (!isSelectedControlled) setInternalSelected(entry.node.key);\n onSelect(entry.node.key, entry.node);\n if (expandOnSelect && entry.isBranch) toggle(entry.node.key);\n }\n\n function focusAt(index: number) {\n const key = visible[index]?.node.key;\n if (key === undefined) return;\n\n const element = nodeRefs.current.get(key);\n if (element) {\n element.focus();\n return;\n }\n\n // Outside the window, so it has to be scrolled in before it exists to receive focus.\n pendingFocusRef.current = key;\n listRef.current?.scrollToIndex(index, { align: 'center' });\n }\n\n useEffect(() => {\n const key = pendingFocusRef.current;\n if (key === null) return;\n const element = nodeRefs.current.get(key);\n if (element) {\n element.focus();\n pendingFocusRef.current = null;\n }\n });\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>, entry: FlatTreeNode, index: number) {\n if (disabled) return;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n focusAt(Math.min(index + 1, visible.length - 1));\n break;\n case 'ArrowUp':\n event.preventDefault();\n focusAt(Math.max(index - 1, 0));\n break;\n case 'ArrowRight':\n event.preventDefault();\n if (!entry.isBranch) break;\n if (entry.isExpanded) focusAt(index + 1);\n else toggle(entry.node.key);\n break;\n case 'ArrowLeft': {\n event.preventDefault();\n if (entry.isBranch && entry.isExpanded) {\n toggle(entry.node.key);\n break;\n }\n const parentIndex = visible.findIndex((e) => e.node.key === entry.parentKey);\n if (parentIndex >= 0) focusAt(parentIndex);\n break;\n }\n case 'Home':\n event.preventDefault();\n focusAt(0);\n break;\n case 'End':\n event.preventDefault();\n focusAt(visible.length - 1);\n break;\n case 'Enter':\n case ' ':\n event.preventDefault();\n select(entry);\n break;\n default:\n break;\n }\n }\n\n function renderNode(entry: FlatTreeNode, index: number) {\n const { node, level, isBranch, isExpanded } = entry;\n const isSelected = node.key === selectedKey;\n const isDisabled = disabled || node.disabled;\n\n return (\n <div\n key={node.key}\n ref={(el) => {\n if (el) nodeRefs.current.set(node.key, el);\n else nodeRefs.current.delete(node.key);\n }}\n role='treeitem'\n aria-level={level + 1}\n aria-setsize={entry.setSize}\n aria-posinset={entry.posInSet}\n aria-expanded={isBranch ? isExpanded : undefined}\n aria-selected={isSelected}\n aria-disabled={isDisabled || undefined}\n tabIndex={node.key === activeKey && !isDisabled ? 0 : -1}\n className={cx(\n styles.treeNode,\n isSelected && styles.treeNodeSelected,\n isDisabled && styles.treeNodeDisabled,\n classNames?.node,\n )}\n style={{ paddingLeft: level * indent, ...slotStyles?.node }}\n onClick={() => select(entry)}\n onKeyDown={(event) => handleKeyDown(event, entry, index)}\n >\n <span\n className={cx(\n styles.treeToggle,\n isExpanded && styles.treeToggleOpen,\n !isBranch && styles.treeToggleHidden,\n classNames?.toggle,\n )}\n style={slotStyles?.toggle}\n aria-hidden='true'\n onClick={(event) => {\n event.stopPropagation();\n if (!isDisabled && isBranch) toggle(node.key);\n }}\n >\n {isBranch && renderIcon(toggleIcon)}\n </span>\n\n {node.icon &&\n renderIcon(node.icon, {\n className: cx(styles.treeIcon, classNames?.icon),\n style: slotStyles?.icon,\n })}\n\n <span className={cx(styles.treeLabel, classNames?.label)} style={slotStyles?.label}>\n {node.label}\n </span>\n </div>\n );\n }\n\n return (\n <div\n {...rest}\n role='tree'\n aria-label={ariaLabel}\n aria-disabled={disabled || undefined}\n tabIndex={isWindowed && !disabled ? 0 : undefined}\n onFocus={(event) => {\n if (event.target === event.currentTarget) focusAt(activeIndex);\n }}\n className={cx(styles.tree, disabled && styles.treeDisabled, classNames?.root, className)}\n style={{ ...style, ...slotStyles?.root }}\n >\n {visible.length === 0 ? (\n <div className={cx(styles.treeEmpty, classNames?.empty)} style={slotStyles?.empty}>\n {text.empty}\n </div>\n ) : isWindowed ? (\n <VirtualList\n ref={listRef}\n items={visible}\n height={height}\n estimatedRowHeight={estimatedRowHeight}\n getItemKey={(entry) => entry.node.key}\n getItemDepth={(entry) => entry.level}\n ariaRoles={{ container: 'none', row: 'none' }}\n // Tree owns the keyboard: its rows carry the roving tabindex and their\n // own key handling, and a second tab stop here would sit inside it.\n keyboardNavigation={false}\n renderRow={renderNode}\n />\n ) : (\n visible.map(renderNode)\n )}\n </div>\n );\n}\n\nexport default Tree;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var e=`tree_bHT4K`,t=`tree-disabled_bIFfs`,n=`tree-node_XUWMs`,r=`tree-node-selected_j05ku`,i=`tree-node-disabled_FMox6`,a=`tree-toggle_hmqtx`,o=`tree-toggle-open_gTfYS`,s=`tree-toggle-hidden_nYrlV`,c=`tree-icon_0dxsy`,l=`tree-label_BOShA`,u=`tree-empty_Eb3vv`,d={tree:e,"tree-disabled":`tree-disabled_bIFfs`,treeDisabled:t,"tree-node":`tree-node_XUWMs`,treeNode:n,"tree-node-selected":`tree-node-selected_j05ku`,treeNodeSelected:r,"tree-node-disabled":`tree-node-disabled_FMox6`,treeNodeDisabled:i,"tree-toggle":`tree-toggle_hmqtx`,treeToggle:a,"tree-toggle-open":`tree-toggle-open_gTfYS`,treeToggleOpen:o,"tree-toggle-hidden":`tree-toggle-hidden_nYrlV`,treeToggleHidden:s,"tree-icon":`tree-icon_0dxsy`,treeIcon:c,"tree-label":`tree-label_BOShA`,treeLabel:l,"tree-empty":`tree-empty_Eb3vv`,treeEmpty:u};export{d as default,e as tree,t as treeDisabled,u as treeEmpty,c as treeIcon,l as treeLabel,n as treeNode,i as treeNodeDisabled,r as treeNodeSelected,a as treeToggle,s as treeToggleHidden,o as treeToggleOpen};
1
+ "use client";var e=`tree_bHT4K`,t=`tree-disabled_bIFfs`,n=`tree-node_XUWMs`,r=`tree-node-selected_j05ku`,i=`tree-node-disabled_FMox6`,a=`tree-toggle_hmqtx`,o=`tree-toggle-open_gTfYS`,s=`tree-toggle-hidden_nYrlV`,c=`tree-icon_0dxsy`,l=`tree-label_BOShA`,u=`tree-empty_Eb3vv`,d={tree:e,"tree-disabled":`tree-disabled_bIFfs`,treeDisabled:t,"tree-node":`tree-node_XUWMs`,treeNode:n,"tree-node-selected":`tree-node-selected_j05ku`,treeNodeSelected:r,"tree-node-disabled":`tree-node-disabled_FMox6`,treeNodeDisabled:i,"tree-toggle":`tree-toggle_hmqtx`,treeToggle:a,"tree-toggle-open":`tree-toggle-open_gTfYS`,treeToggleOpen:o,"tree-toggle-hidden":`tree-toggle-hidden_nYrlV`,treeToggleHidden:s,"tree-icon":`tree-icon_0dxsy`,treeIcon:c,"tree-label":`tree-label_BOShA`,treeLabel:l,"tree-empty":`tree-empty_Eb3vv`,treeEmpty:u};export{d as default,e as tree,t as treeDisabled,u as treeEmpty,c as treeIcon,l as treeLabel,n as treeNode,i as treeNodeDisabled,r as treeNodeSelected,a as treeToggle,s as treeToggleHidden,o as treeToggleOpen};
2
2
  //# sourceMappingURL=tree.module.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"tree.module.mjs","names":[],"sources":["../../../../package/common/tree/tree.module.pcss"],"sourcesContent":[".tree {\n display: flex;\n flex-direction: column;\n width: 100%;\n color: var(--text-color);\n\n &-disabled {\n opacity: 0.5;\n }\n\n &-node {\n display: flex;\n align-items: center;\n gap: 6px;\n box-sizing: border-box;\n min-height: var(--tree-node-height, 32px);\n padding-right: 8px;\n border-radius: var(--default-border-radius);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n user-select: none;\n\n &:hover {\n background: var(--background-accent);\n }\n\n &:focus-visible {\n outline: var(--focus-border-color, var(--primary-color)) solid 2px;\n outline-offset: -2px;\n }\n\n &-selected {\n background: var(--tree-selected-background, var(--primary-color));\n color: var(--tree-selected-color, var(--text-on-primary));\n\n &:hover {\n background: var(--tree-selected-background, var(--primary-color));\n }\n\n &:focus-visible {\n outline-color: var(--tree-selected-color, var(--text-on-primary));\n }\n }\n\n &-disabled {\n opacity: 0.5;\n cursor: default;\n\n &:hover {\n background: transparent;\n }\n }\n }\n\n &-toggle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 1.25em;\n height: 1.25em;\n font-size: 0.8em;\n border-radius: 50%;\n transition: transform 0.15s;\n\n &-open {\n transform: rotate(90deg);\n }\n\n /* Kept in the layout rather than removed, so leaf labels line up with their siblings'. */\n &-hidden {\n visibility: hidden;\n }\n }\n\n &-icon {\n flex: none;\n width: 1em;\n }\n\n &-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &-empty {\n padding: 12px 8px;\n color: var(--text-dark);\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"tree.module.mjs","names":[],"sources":["../../../../package/common/tree/tree.module.pcss"],"sourcesContent":[".tree {\n display: flex;\n flex-direction: column;\n width: 100%;\n color: var(--text-color);\n\n &-disabled {\n opacity: 0.5;\n }\n\n &-node {\n display: flex;\n align-items: center;\n gap: 6px;\n box-sizing: border-box;\n min-height: var(--tree-node-height, 32px);\n padding-right: 8px;\n border-radius: var(--default-border-radius);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n user-select: none;\n\n &:hover {\n background: var(--background-accent);\n }\n\n &:focus-visible {\n outline: var(--focus-border-color, var(--primary-color)) solid 2px;\n outline-offset: -2px;\n }\n\n &-selected {\n background: var(--tree-selected-background, var(--primary-color));\n color: var(--tree-selected-color, var(--text-on-primary));\n\n &:hover {\n background: var(--tree-selected-background, var(--primary-color));\n }\n\n &:focus-visible {\n outline-color: var(--tree-selected-color, var(--text-on-primary));\n }\n }\n\n &-disabled {\n opacity: 0.5;\n cursor: default;\n\n &:hover {\n background: transparent;\n }\n }\n }\n\n &-toggle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 1.25em;\n height: 1.25em;\n font-size: 0.8em;\n border-radius: 50%;\n transition: transform 0.15s;\n\n &-open {\n transform: rotate(90deg);\n }\n\n /* Kept in the layout rather than removed, so leaf labels line up with their siblings'. */\n &-hidden {\n visibility: hidden;\n }\n }\n\n &-icon {\n flex: none;\n width: 1em;\n }\n\n &-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &-empty {\n padding: 12px 8px;\n color: var(--text-dark);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .tree-toggle {\n transition: none;\n }\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- function e(e){return e.target===e.currentTarget&&(e.key===`Enter`||e.key===` `)}export{e as isSelfActivation};
1
+ "use client";function e(e){return e.target===e.currentTarget&&(e.key===`Enter`||e.key===` `)}export{e as isSelfActivation};
2
2
  //# sourceMappingURL=activationKey.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"activationKey.mjs","names":[],"sources":["../../../../package/common/utils/activationKey.ts"],"sourcesContent":["import type React from 'react';\n\n/**\n * Whether a keydown is a click-equivalent activation of the element the handler sits on.\n *\n * The target check is the important half: keydown bubbles, so without it a Space typed into a\n * nested input activates the container and, once the container calls `preventDefault()`, never\n * reaches the input at all.\n */\nexport function isSelfActivation(event: React.KeyboardEvent): boolean {\n return event.target === event.currentTarget && (event.key === 'Enter' || event.key === ' ');\n}\n"],"mappings":"AASA,SAAgB,EAAiB,EAAqC,CACpE,OAAO,EAAM,SAAW,EAAM,gBAAkB,EAAM,MAAQ,SAAW,EAAM,MAAQ,IACzF"}
1
+ {"version":3,"file":"activationKey.mjs","names":[],"sources":["../../../../package/common/utils/activationKey.ts"],"sourcesContent":["import type React from 'react';\n\n/**\n * Whether a keydown is a click-equivalent activation of the element the handler sits on.\n *\n * The target check is the important half: keydown bubbles, so without it a Space typed into a\n * nested input activates the container and, once the container calls `preventDefault()`, never\n * reaches the input at all.\n */\nexport function isSelfActivation(event: React.KeyboardEvent): boolean {\n return event.target === event.currentTarget && (event.key === 'Enter' || event.key === ' ');\n}\n"],"mappings":"aASA,SAAgB,EAAiB,EAAqC,CACpE,OAAO,EAAM,SAAW,EAAM,gBAAkB,EAAM,MAAQ,SAAW,EAAM,MAAQ,IACzF"}
@@ -0,0 +1,2 @@
1
+ "use client";function e(...e){return t=>{for(let n of e)typeof n==`function`?n(t):n&&(n.current=t)}}export{e as mergeRefs};
2
+ //# sourceMappingURL=mergeRefs.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mergeRefs.mjs","names":[],"sources":["../../../../package/common/utils/mergeRefs.ts"],"sourcesContent":["import type { Ref } from 'react';\n\n/**\n * Fans one element out to several refs, for a component that needs the node itself *and*\n * hands it to the consumer through a `ref` prop.\n *\n * The returned callback is a new function on every render, so React detaches and reattaches\n * it each time (null, then the node). Every ref here is therefore written twice per render,\n * which is fine for storing a node and wrong for anything with a side effect. Call it inline\n * rather than memoising: a memo would have to list the refs it closes over, and a consumer\n * passing an inline callback ref changes that identity every render anyway.\n */\nexport function mergeRefs<T>(...refs: (Ref<T> | undefined)[]): (node: T | null) => void {\n return (node) => {\n for (const ref of refs) {\n if (typeof ref === 'function') ref(node);\n else if (ref) (ref as { current: T | null }).current = node;\n }\n };\n}\n"],"mappings":"aAYA,SAAgB,EAAa,GAAG,EAAwD,CACtF,MAAQ,IAAS,CACf,IAAK,IAAM,KAAO,EACZ,OAAO,GAAQ,WAAY,EAAI,CAAI,EAC9B,IAAK,EAA+B,QAAU,EAE3D,CACF"}
@@ -1,2 +1,2 @@
1
- import{FontAwesomeIcon as e}from"@fortawesome/react-fontawesome";import{jsx as t}from"react/jsx-runtime";function n(e){return typeof e==`object`&&!!e&&`prefix`in e&&`iconName`in e&&`icon`in e}function r(r,i={}){let{className:a,style:o}=i;return r==null?null:n(r)?t(e,{icon:r,className:a,style:o}):a||o?t(`span`,{className:a,style:o,children:r}):r}export{n as isIconDefinition,r as renderIcon};
1
+ "use client";import{FontAwesomeIcon as e}from"@fortawesome/react-fontawesome";import{jsx as t}from"react/jsx-runtime";function n(e){return typeof e==`object`&&!!e&&`prefix`in e&&`iconName`in e&&`icon`in e}function r(r,i={}){let{className:a,style:o}=i;return r==null?null:n(r)?t(e,{icon:r,className:a,style:o}):a||o?t(`span`,{className:a,style:o,children:r}):r}export{n as isIconDefinition,r as renderIcon};
2
2
  //# sourceMappingURL=renderIcon.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"renderIcon.mjs","names":[],"sources":["../../../../package/common/utils/renderIcon.tsx"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport type { IconDefinition } from '@fortawesome/fontawesome-svg-core';\n\nimport type { IconContent } from '../types/icon.types';\n\n/** FontAwesome's own `style` type — `CSSProperties` plus its `--fa-*` variables. */\ntype FaStyle = CSSProperties & Record<`--fa-font-${string}`, string>;\n\ninterface RenderIconOptions {\n /** Class applied to the rendered icon (or to the wrapper span for a custom element). */\n className?: string;\n /** Inline style applied to the rendered icon (or to the wrapper span for a custom element). */\n style?: CSSProperties;\n}\n\n/**\n * Narrows an `IconContent` to a FontAwesome `IconDefinition`.\n *\n * Both halves of the union are plain objects (a React element is one too), so\n * they can only be told apart structurally: an icon definition always carries\n * `prefix`, `iconName` and the `icon` tuple.\n */\nexport function isIconDefinition(icon: IconContent | null | undefined): icon is IconDefinition {\n return typeof icon === 'object' && icon !== null && 'prefix' in icon && 'iconName' in icon && 'icon' in icon;\n}\n\n/**\n * Renders an `icon` prop that may be either a FontAwesome `IconDefinition` or an\n * arbitrary React element.\n *\n * A definition goes through `FontAwesomeIcon`; an element is returned untouched\n * unless a `className`/`style` was given, in which case it is wrapped in a\n * `<span>` carrying them so component and consumer slot styling still lands\n * somewhere. Note that a custom element is not sized by FontAwesome's `1em`\n * geometry — size it yourself if the surrounding layout expects a square icon.\n */\nexport function renderIcon(icon: IconContent | null | undefined, options: RenderIconOptions = {}): ReactNode {\n const { className, style } = options;\n\n if (icon === null || icon === undefined) return null;\n\n if (isIconDefinition(icon)) {\n return <FontAwesomeIcon icon={icon} className={className} style={style as FaStyle} />;\n }\n\n if (className || style) {\n return (\n <span className={className} style={style}>\n {icon}\n </span>\n );\n }\n\n return icon;\n}\n"],"mappings":"yGAuBA,SAAgB,EAAiB,EAA8D,CAC7F,OAAO,OAAO,GAAS,YAAY,GAAiB,WAAY,GAAQ,aAAc,GAAQ,SAAU,CAC1G,CAYA,SAAgB,EAAW,EAAsC,EAA6B,CAAC,EAAc,CAC3G,GAAM,CAAE,YAAW,SAAU,EAgB7B,OAdI,GAAS,KAAmC,KAE5C,EAAiB,CAAI,EAChB,EAAC,EAAD,CAAuB,OAAiB,YAAkB,OAAmB,CAAA,EAGlF,GAAa,EAEb,EAAC,OAAD,CAAiB,YAAkB,QAChC,SAAA,CACG,CAAA,EAIH,CACT"}
1
+ {"version":3,"file":"renderIcon.mjs","names":[],"sources":["../../../../package/common/utils/renderIcon.tsx"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport type { IconDefinition } from '@fortawesome/fontawesome-svg-core';\n\nimport type { IconContent } from '../types/icon.types';\n\n/** FontAwesome's own `style` type — `CSSProperties` plus its `--fa-*` variables. */\ntype FaStyle = CSSProperties & Record<`--fa-font-${string}`, string>;\n\ninterface RenderIconOptions {\n /** Class applied to the rendered icon (or to the wrapper span for a custom element). */\n className?: string;\n /** Inline style applied to the rendered icon (or to the wrapper span for a custom element). */\n style?: CSSProperties;\n}\n\n/**\n * Narrows an `IconContent` to a FontAwesome `IconDefinition`.\n *\n * Both halves of the union are plain objects (a React element is one too), so\n * they can only be told apart structurally: an icon definition always carries\n * `prefix`, `iconName` and the `icon` tuple.\n */\nexport function isIconDefinition(icon: IconContent | null | undefined): icon is IconDefinition {\n return typeof icon === 'object' && icon !== null && 'prefix' in icon && 'iconName' in icon && 'icon' in icon;\n}\n\n/**\n * Renders an `icon` prop that may be either a FontAwesome `IconDefinition` or an\n * arbitrary React element.\n *\n * A definition goes through `FontAwesomeIcon`; an element is returned untouched\n * unless a `className`/`style` was given, in which case it is wrapped in a\n * `<span>` carrying them so component and consumer slot styling still lands\n * somewhere. Note that a custom element is not sized by FontAwesome's `1em`\n * geometry — size it yourself if the surrounding layout expects a square icon.\n */\nexport function renderIcon(icon: IconContent | null | undefined, options: RenderIconOptions = {}): ReactNode {\n const { className, style } = options;\n\n if (icon === null || icon === undefined) return null;\n\n if (isIconDefinition(icon)) {\n return <FontAwesomeIcon icon={icon} className={className} style={style as FaStyle} />;\n }\n\n if (className || style) {\n return (\n <span className={className} style={style}>\n {icon}\n </span>\n );\n }\n\n return icon;\n}\n"],"mappings":"sHAuBA,SAAgB,EAAiB,EAA8D,CAC7F,OAAO,OAAO,GAAS,YAAY,GAAiB,WAAY,GAAQ,aAAc,GAAQ,SAAU,CAC1G,CAYA,SAAgB,EAAW,EAAsC,EAA6B,CAAC,EAAc,CAC3G,GAAM,CAAE,YAAW,SAAU,EAgB7B,OAdI,GAAS,KAAmC,KAE5C,EAAiB,CAAI,EAChB,EAAC,EAAD,CAAuB,OAAiB,YAAkB,OAAmB,CAAA,EAGlF,GAAa,EAEb,EAAC,OAAD,CAAiB,YAAkB,QAChC,SAAA,CACG,CAAA,EAIH,CACT"}
@@ -1,2 +1,2 @@
1
- function e(e){let t=[],n=e.parentElement;for(;n&&n!==document.body&&n!==document.documentElement;){let e=getComputedStyle(n);(e.overflowX!==`visible`||e.overflowY!==`visible`)&&t.push(n),n=n.parentElement}return t}function t(e,t){return t.some(t=>{let n=t.getBoundingClientRect();return e.bottom<=n.top||e.top>=n.bottom||e.right<=n.left||e.left>=n.right})}export{e as getScrollableAncestors,t as isHiddenByAnyAncestor};
1
+ "use client";function e(e){let t=[],n=e.parentElement;for(;n&&n!==document.body&&n!==document.documentElement;){let e=getComputedStyle(n);(e.overflowX!==`visible`||e.overflowY!==`visible`)&&t.push(n),n=n.parentElement}return t}function t(e,t){return t.some(t=>{let n=t.getBoundingClientRect();return e.bottom<=n.top||e.top>=n.bottom||e.right<=n.left||e.left>=n.right})}export{e as getScrollableAncestors,t as isHiddenByAnyAncestor};
2
2
  //# sourceMappingURL=scrollAncestors.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"scrollAncestors.mjs","names":[],"sources":["../../../../package/common/utils/scrollAncestors.ts"],"sourcesContent":["// Scrollable ancestors up to (not including) <body>. This is computed once per open rather\n// than on every scroll tick, since walking the tree and reading computed style forces layout,\n// which is too expensive to repeat at scroll frequency (Floating UI's autoUpdate does the same\n// thing, resolving the ancestor list once via getOverflowAncestors). Plain page/viewport scroll\n// is deliberately left out: a trigger that scrolls off the top of the page already renders its\n// fixed-position anchor off-screen for free.\nexport function getScrollableAncestors(el: HTMLElement): HTMLElement[] {\n const ancestors: HTMLElement[] = [];\n let node = el.parentElement;\n while (node && node !== document.body && node !== document.documentElement) {\n const style = getComputedStyle(node);\n if (style.overflowX !== 'visible' || style.overflowY !== 'visible') ancestors.push(node);\n node = node.parentElement;\n }\n return ancestors;\n}\n\nexport function isHiddenByAnyAncestor(rect: DOMRect, ancestors: HTMLElement[]): boolean {\n return ancestors.some((ancestor) => {\n const a = ancestor.getBoundingClientRect();\n return rect.bottom <= a.top || rect.top >= a.bottom || rect.right <= a.left || rect.left >= a.right;\n });\n}\n"],"mappings":"AAMA,SAAgB,EAAuB,EAAgC,CACrE,IAAM,EAA2B,CAAC,EAC9B,EAAO,EAAG,cACd,KAAO,GAAQ,IAAS,SAAS,MAAQ,IAAS,SAAS,iBAAiB,CAC1E,IAAM,EAAQ,iBAAiB,CAAI,GAC/B,EAAM,YAAc,WAAa,EAAM,YAAc,YAAW,EAAU,KAAK,CAAI,EACvF,EAAO,EAAK,aACd,CACA,OAAO,CACT,CAEA,SAAgB,EAAsB,EAAe,EAAmC,CACtF,OAAO,EAAU,KAAM,GAAa,CAClC,IAAM,EAAI,EAAS,sBAAsB,EACzC,OAAO,EAAK,QAAU,EAAE,KAAO,EAAK,KAAO,EAAE,QAAU,EAAK,OAAS,EAAE,MAAQ,EAAK,MAAQ,EAAE,KAChG,CAAC,CACH"}
1
+ {"version":3,"file":"scrollAncestors.mjs","names":[],"sources":["../../../../package/common/utils/scrollAncestors.ts"],"sourcesContent":["// Scrollable ancestors up to (not including) <body>. This is computed once per open rather\n// than on every scroll tick, since walking the tree and reading computed style forces layout,\n// which is too expensive to repeat at scroll frequency (Floating UI's autoUpdate does the same\n// thing, resolving the ancestor list once via getOverflowAncestors). Plain page/viewport scroll\n// is deliberately left out: a trigger that scrolls off the top of the page already renders its\n// fixed-position anchor off-screen for free.\nexport function getScrollableAncestors(el: HTMLElement): HTMLElement[] {\n const ancestors: HTMLElement[] = [];\n let node = el.parentElement;\n while (node && node !== document.body && node !== document.documentElement) {\n const style = getComputedStyle(node);\n if (style.overflowX !== 'visible' || style.overflowY !== 'visible') ancestors.push(node);\n node = node.parentElement;\n }\n return ancestors;\n}\n\nexport function isHiddenByAnyAncestor(rect: DOMRect, ancestors: HTMLElement[]): boolean {\n return ancestors.some((ancestor) => {\n const a = ancestor.getBoundingClientRect();\n return rect.bottom <= a.top || rect.top >= a.bottom || rect.right <= a.left || rect.left >= a.right;\n });\n}\n"],"mappings":"aAMA,SAAgB,EAAuB,EAAgC,CACrE,IAAM,EAA2B,CAAC,EAC9B,EAAO,EAAG,cACd,KAAO,GAAQ,IAAS,SAAS,MAAQ,IAAS,SAAS,iBAAiB,CAC1E,IAAM,EAAQ,iBAAiB,CAAI,GAC/B,EAAM,YAAc,WAAa,EAAM,YAAc,YAAW,EAAU,KAAK,CAAI,EACvF,EAAO,EAAK,aACd,CACA,OAAO,CACT,CAEA,SAAgB,EAAsB,EAAe,EAAmC,CACtF,OAAO,EAAU,KAAM,GAAa,CAClC,IAAM,EAAI,EAAS,sBAAsB,EACzC,OAAO,EAAK,QAAU,EAAE,KAAO,EAAK,KAAO,EAAE,QAAU,EAAK,OAAS,EAAE,MAAQ,EAAK,MAAQ,EAAE,KAChG,CAAC,CACH"}
@@ -1,2 +1,2 @@
1
- function e(){let e=typeof window<`u`?window.visualViewport:null;return e?{left:e.offsetLeft,top:e.offsetTop,width:e.width,height:e.height}:{left:0,top:0,width:typeof window<`u`?window.innerWidth:0,height:typeof window<`u`?window.innerHeight:0}}export{e as getVisualViewportRect};
1
+ "use client";function e(){let e=typeof window<`u`?window.visualViewport:null;return e?{left:e.offsetLeft,top:e.offsetTop,width:e.width,height:e.height}:{left:0,top:0,width:typeof window<`u`?window.innerWidth:0,height:typeof window<`u`?window.innerHeight:0}}export{e as getVisualViewportRect};
2
2
  //# sourceMappingURL=visualViewport.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"visualViewport.mjs","names":[],"sources":["../../../../package/common/utils/visualViewport.ts"],"sourcesContent":["export interface VisualViewportRect {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\n// `window.visualViewport` reports the actually-visible area, which shrinks (and offsets) when a\n// mobile on-screen keyboard opens — unlike `window.innerWidth`/`innerHeight`, which stay pinned to\n// the full layout viewport. `getBoundingClientRect()` is relative to the layout viewport's origin,\n// so `left`/`top` here let callers translate into the same coordinate space before clamping.\nexport function getVisualViewportRect(): VisualViewportRect {\n const vv = typeof window !== 'undefined' ? window.visualViewport : null;\n if (vv) return { left: vv.offsetLeft, top: vv.offsetTop, width: vv.width, height: vv.height };\n return {\n left: 0,\n top: 0,\n width: typeof window !== 'undefined' ? window.innerWidth : 0,\n height: typeof window !== 'undefined' ? window.innerHeight : 0,\n };\n}\n"],"mappings":"AAWA,SAAgB,GAA4C,CAC1D,IAAM,EAAK,OAAO,OAAW,IAAc,OAAO,eAAiB,KAEnE,OADI,EAAW,CAAE,KAAM,EAAG,WAAY,IAAK,EAAG,UAAW,MAAO,EAAG,MAAO,OAAQ,EAAG,MAAO,EACrF,CACL,KAAM,EACN,IAAK,EACL,MAAO,OAAO,OAAW,IAAc,OAAO,WAAa,EAC3D,OAAQ,OAAO,OAAW,IAAc,OAAO,YAAc,CAC/D,CACF"}
1
+ {"version":3,"file":"visualViewport.mjs","names":[],"sources":["../../../../package/common/utils/visualViewport.ts"],"sourcesContent":["export interface VisualViewportRect {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\n// `window.visualViewport` reports the actually-visible area, which shrinks (and offsets) when a\n// mobile on-screen keyboard opens — unlike `window.innerWidth`/`innerHeight`, which stay pinned to\n// the full layout viewport. `getBoundingClientRect()` is relative to the layout viewport's origin,\n// so `left`/`top` here let callers translate into the same coordinate space before clamping.\nexport function getVisualViewportRect(): VisualViewportRect {\n const vv = typeof window !== 'undefined' ? window.visualViewport : null;\n if (vv) return { left: vv.offsetLeft, top: vv.offsetTop, width: vv.width, height: vv.height };\n return {\n left: 0,\n top: 0,\n width: typeof window !== 'undefined' ? window.innerWidth : 0,\n height: typeof window !== 'undefined' ? window.innerHeight : 0,\n };\n}\n"],"mappings":"aAWA,SAAgB,GAA4C,CAC1D,IAAM,EAAK,OAAO,OAAW,IAAc,OAAO,eAAiB,KAEnE,OADI,EAAW,CAAE,KAAM,EAAG,WAAY,IAAK,EAAG,UAAW,MAAO,EAAG,MAAO,OAAQ,EAAG,MAAO,EACrF,CACL,KAAM,EACN,IAAK,EACL,MAAO,OAAO,OAAW,IAAc,OAAO,WAAa,EAC3D,OAAQ,OAAO,OAAW,IAAc,OAAO,YAAc,CAC/D,CACF"}
@@ -1,2 +1,2 @@
1
- import{columnCellSelector as e,columnWidthVar as t,loadPersistedColumns as n,resolveFrozenWidth as r}from"./virtualList.utils.mjs";import{useCallback as i,useLayoutEffect as a,useRef as o,useState as s}from"react";function c(e){return Math.max(1,e?.minWidth??48)}function l({columns:l,visibleColumnsRef:u,resizableColumns:d,columnWidths:f,onColumnWidthsChange:p,persistColumnsKey:m,rootRef:h}){let g=f!==void 0,[_,v]=s(()=>n(m)?.widths??{}),[y,b]=s(!1),x=g?f:_,S=o(x);S.current=x;let C=i(e=>{g||v(e),p?.(e)},[g,p]),w=i(()=>{let t=h.current,n={...S.current};for(let i of u.current){if(n[i.key]!=null)continue;let a=t?.querySelector(`[aria-rowindex="1"] ${e(i.key)}`),o=a?Math.round(a.getBoundingClientRect().width):0;n[i.key]=o>0?o:r(i)}return n},[h,u]);a(()=>{let e=h.current;if(e)for(let[n,r]of Object.entries(x))e.style.setProperty(t(n),`${r}px`)},[x,h]);let T=i((e,n)=>{h.current?.style.setProperty(t(e),`${n}px`)},[h]),E=i(()=>{g&&requestAnimationFrame(()=>{for(let[e,t]of Object.entries(S.current))T(e,t)})},[T,g]),D=i((e,t)=>{let n=w(),r=c(l?.find(t=>t.key===e)),i={...n,[e]:Math.max(r,Math.round(t(n[e])))};T(e,i[e]),C(i),E()},[T,l,C,w,E]),O=i((e,t)=>{if(e.button!==0)return;e.preventDefault(),e.stopPropagation();let n=e.currentTarget,r=w(),i=r[t],a=e.clientX,o=c(l?.find(e=>e.key===t)),s=i,u=0,d=()=>{u=0,T(t,s)};function f(a){if(u&&cancelAnimationFrame(u),n.releasePointerCapture?.(e.pointerId),n.removeEventListener(`pointermove`,p),n.removeEventListener(`pointerup`,m),n.removeEventListener(`pointercancel`,h),n.removeEventListener(`lostpointercapture`,h),window.removeEventListener(`keydown`,g,!0),document.body.style.cursor=``,document.body.style.userSelect=``,b(!1),a==null){T(t,i);return}a!==i&&C({...r,[t]:a}),E()}function p(e){s=Math.max(o,Math.round(i+e.clientX-a)),u||=requestAnimationFrame(d)}function m(){f(s)}function h(){f(null)}function g(e){e.key===`Escape`&&(e.preventDefault(),f(null))}n.setPointerCapture?.(e.pointerId),n.addEventListener(`pointermove`,p),n.addEventListener(`pointerup`,m),n.addEventListener(`pointercancel`,h),n.addEventListener(`lostpointercapture`,h),window.addEventListener(`keydown`,g,!0),document.body.style.cursor=`col-resize`,document.body.style.userSelect=`none`,b(!0),Object.keys(S.current).length===0&&C(r)},[T,l,C,w,E]),k=i(n=>{let r=h.current;if(!r)return 0;let i=t(n),a=r.style.getPropertyValue(i),o=r.style.getPropertyValue(`--vl-total`);r.style.setProperty(i,`max-content`),r.style.removeProperty(`--vl-total`);let s=0;return r.querySelectorAll(e(n)).forEach(e=>{let t=Math.ceil(e.getBoundingClientRect().width);t>s&&(s=t)}),r.style.setProperty(i,a),o&&r.style.setProperty(`--vl-total`,o),Math.min(s,r.clientWidth)},[h]),A=i(e=>{let t=()=>{let t=k(e);t>0&&D(e,()=>t)};Object.keys(S.current).length>0?t():(C(w()),requestAnimationFrame(t))},[C,w,k,D]),j=i(()=>{let e=h.current;if(e)for(let n of Object.keys(S.current))e.style.removeProperty(t(n));C({})},[C,h]),M=i(e=>d&&e.resizable!==!1,[d]),N=i((e,t)=>D(e,e=>e+t),[D]),P=i(e=>D(e,()=>c(l?.find(t=>t.key===e))),[l,D]),F=i(e=>M(e)?{"aria-hidden":!0,onPointerDown:t=>O(t,e.key),onDoubleClick:t=>{t.stopPropagation(),A(e.key)},onClick:e=>e.stopPropagation()}:null,[A,O,M]);return{widths:x,isFrozen:Object.keys(x).length>0,isResizing:y,reset:j,isResizable:M,resizeBy:N,resizeToMin:P,autoFit:A,getHandleProps:F}}export{l as useColumnResize};
1
+ "use client";import{columnCellSelector as e,columnWidthVar as t,loadPersistedColumns as n,resolveFrozenWidth as r}from"./virtualList.utils.mjs";import{useCallback as i,useLayoutEffect as a,useRef as o,useState as s}from"react";function c(e){return Math.max(1,e?.minWidth??48)}function l({columns:l,visibleColumnsRef:u,resizableColumns:d,columnWidths:f,onColumnWidthsChange:p,persistColumnsKey:m,rootRef:h}){let g=f!==void 0,[_,v]=s(()=>n(m)?.widths??{}),[y,b]=s(!1),x=g?f:_,S=o(x);S.current=x;let C=i(e=>{g||v(e),p?.(e)},[g,p]),w=i(()=>{let t=h.current,n={...S.current};for(let i of u.current){if(n[i.key]!=null)continue;let a=t?.querySelector(`[aria-rowindex="1"] ${e(i.key)}`),o=a?Math.round(a.getBoundingClientRect().width):0;n[i.key]=o>0?o:r(i)}return n},[h,u]);a(()=>{let e=h.current;if(e)for(let[n,r]of Object.entries(x))e.style.setProperty(t(n),`${r}px`)},[x,h]);let T=i((e,n)=>{h.current?.style.setProperty(t(e),`${n}px`)},[h]),E=i(()=>{g&&requestAnimationFrame(()=>{for(let[e,t]of Object.entries(S.current))T(e,t)})},[T,g]),D=i((e,t)=>{let n=w(),r=c(l?.find(t=>t.key===e)),i={...n,[e]:Math.max(r,Math.round(t(n[e])))};T(e,i[e]),C(i),E()},[T,l,C,w,E]),O=i((e,t)=>{if(e.button!==0)return;e.preventDefault(),e.stopPropagation();let n=e.currentTarget,r=w(),i=r[t],a=e.clientX,o=c(l?.find(e=>e.key===t)),s=i,u=0,d=()=>{u=0,T(t,s)};function f(a){if(u&&cancelAnimationFrame(u),n.releasePointerCapture?.(e.pointerId),n.removeEventListener(`pointermove`,p),n.removeEventListener(`pointerup`,m),n.removeEventListener(`pointercancel`,h),n.removeEventListener(`lostpointercapture`,h),window.removeEventListener(`keydown`,g,!0),document.body.style.cursor=``,document.body.style.userSelect=``,b(!1),a==null){T(t,i);return}a!==i&&C({...r,[t]:a}),E()}function p(e){s=Math.max(o,Math.round(i+e.clientX-a)),u||=requestAnimationFrame(d)}function m(){f(s)}function h(){f(null)}function g(e){e.key===`Escape`&&(e.preventDefault(),f(null))}n.setPointerCapture?.(e.pointerId),n.addEventListener(`pointermove`,p),n.addEventListener(`pointerup`,m),n.addEventListener(`pointercancel`,h),n.addEventListener(`lostpointercapture`,h),window.addEventListener(`keydown`,g,!0),document.body.style.cursor=`col-resize`,document.body.style.userSelect=`none`,b(!0),Object.keys(S.current).length===0&&C(r)},[T,l,C,w,E]),k=i(n=>{let r=h.current;if(!r)return 0;let i=t(n),a=r.style.getPropertyValue(i),o=r.style.getPropertyValue(`--vl-total`);r.style.setProperty(i,`max-content`),r.style.removeProperty(`--vl-total`);let s=0;return r.querySelectorAll(e(n)).forEach(e=>{let t=Math.ceil(e.getBoundingClientRect().width);t>s&&(s=t)}),r.style.setProperty(i,a),o&&r.style.setProperty(`--vl-total`,o),Math.min(s,r.clientWidth)},[h]),A=i(e=>{let t=()=>{let t=k(e);t>0&&D(e,()=>t)};Object.keys(S.current).length>0?t():(C(w()),requestAnimationFrame(t))},[C,w,k,D]),j=i(()=>{let e=h.current;if(e)for(let n of Object.keys(S.current))e.style.removeProperty(t(n));C({})},[C,h]),M=i(e=>d&&e.resizable!==!1,[d]),N=i((e,t)=>D(e,e=>e+t),[D]),P=i(e=>D(e,()=>c(l?.find(t=>t.key===e))),[l,D]),F=i(e=>M(e)?{"aria-hidden":!0,onPointerDown:t=>O(t,e.key),onDoubleClick:t=>{t.stopPropagation(),A(e.key)},onClick:e=>e.stopPropagation()}:null,[A,O,M]);return{widths:x,isFrozen:Object.keys(x).length>0,isResizing:y,reset:j,isResizable:M,resizeBy:N,resizeToMin:P,autoFit:A,getHandleProps:F}}export{l as useColumnResize};
2
2
  //# sourceMappingURL=useColumnResize.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useColumnResize.mjs","names":[],"sources":["../../../../package/common/virtualList/useColumnResize.ts"],"sourcesContent":["import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';\n\nimport {\n columnCellSelector,\n columnWidthVar,\n loadPersistedColumns,\n resolveFrozenWidth,\n MIN_COLUMN_WIDTH,\n} from './virtualList.utils';\nimport type { VirtualListColumn } from './virtualList.types';\n\ninterface UseColumnResizeArgs<T> {\n columns?: VirtualListColumn<T>[];\n /**\n * The columns currently rendered, in order. A ref rather than a value because\n * the visible set is derived one hook later, and only the freeze reads it, at\n * event time.\n */\n visibleColumnsRef: React.RefObject<VirtualListColumn<T>[]>;\n resizableColumns: boolean;\n /** Controlled widths. When provided, internal state is ignored. */\n columnWidths?: Record<string, number>;\n onColumnWidthsChange?: (widths: Record<string, number>) => void;\n /** Restores widths saved under this key. Uncontrolled mode only. */\n persistColumnsKey?: string;\n rootRef: React.RefObject<HTMLDivElement | null>;\n}\n\nexport interface UseColumnResizeResult<T> {\n widths: Record<string, number>;\n /**\n * True once every visible column has an exact px width. Nothing moves at that\n * moment, but from then on the layout is pixels rather than `fr`/`fit`.\n */\n isFrozen: boolean;\n isResizing: boolean;\n /** Drops every user width and hands the layout back to the column definitions. */\n reset: () => void;\n /** Whether this column takes a resize at all, by handle or by keyboard. */\n isResizable: (col: VirtualListColumn<T>) => boolean;\n /** Widens (or, negative, narrows) one column. The keyboard entry point. */\n resizeBy: (key: string, delta: number) => void;\n /** Takes one column down to its minimum. */\n resizeToMin: (key: string) => void;\n /** Sizes one column to its widest rendered cell. */\n autoFit: (key: string) => void;\n /** Pointer props for one column's handle, or null when that column can't be resized. */\n getHandleProps: (col: VirtualListColumn<T>) => React.HTMLAttributes<HTMLDivElement> | null;\n}\n\nfunction minWidthFor<T>(col: VirtualListColumn<T> | undefined): number {\n return Math.max(1, col?.minWidth ?? MIN_COLUMN_WIDTH);\n}\n\n/**\n * User column resizing: the width state, and a drag that doesn't go through\n * React.\n *\n * A pointer move writes the dragged column's custom property straight onto the\n * list element. The header and every row read that same property, so one DOM\n * write resizes all of them in a single layout pass. Going through state\n * instead would re-render the header plus every visible row on every frame, and\n * the handle would trail the cursor by one frame, which is the whole difference\n * between this feeling attached to the pointer and feeling cheap. React is told\n * once, on release.\n *\n * The first resize **freezes** every visible column to its measured width. A\n * `fr` track can't express \"this one column is now 240px\" without the others\n * silently absorbing the difference, and once they hit their minimum the dragged\n * edge stops following the cursor, which is the worst moment for it to happen.\n * Frozen, the table is exact pixels and simply scrolls horizontally instead.\n */\nexport function useColumnResize<T>({\n columns,\n visibleColumnsRef,\n resizableColumns,\n columnWidths,\n onColumnWidthsChange,\n persistColumnsKey,\n rootRef,\n}: UseColumnResizeArgs<T>): UseColumnResizeResult<T> {\n const isControlled = columnWidths !== undefined;\n const [internalWidths, setInternalWidths] = useState<Record<string, number>>(\n () => loadPersistedColumns(persistColumnsKey)?.widths ?? {},\n );\n const [isResizing, setIsResizing] = useState(false);\n const effectiveWidths = isControlled ? columnWidths! : internalWidths;\n\n // Read by the pointer handlers, which are installed once per drag and must not\n // capture a stale snapshot of either.\n const widthsRef = useRef(effectiveWidths);\n widthsRef.current = effectiveWidths;\n\n const commit = useCallback(\n (next: Record<string, number>) => {\n if (!isControlled) setInternalWidths(next);\n onColumnWidthsChange?.(next);\n },\n [isControlled, onColumnWidthsChange],\n );\n\n /**\n * Current width of every visible column, measured from the rendered header so\n * the freeze is invisible: the px values are the ones already on screen.\n * Columns that already have a width keep it, and a header cell that can't be\n * measured (jsdom, a display:none list) falls back to its declared width.\n */\n const freeze = useCallback((): Record<string, number> => {\n const root = rootRef.current;\n const next: Record<string, number> = { ...widthsRef.current };\n for (const col of visibleColumnsRef.current) {\n if (next[col.key] != null) continue;\n const cell = root?.querySelector(`[aria-rowindex=\"1\"] ${columnCellSelector(col.key)}`);\n const measured = cell ? Math.round(cell.getBoundingClientRect().width) : 0;\n next[col.key] = measured > 0 ? measured : resolveFrozenWidth(col);\n }\n return next;\n }, [rootRef, visibleColumnsRef]);\n\n // The widths live on the element as custom properties, written from here and\n // from the drag, never through React's `style`. One owner means a drag's\n // imperative writes can't be clobbered by a render that happens to land\n // mid-gesture, and the steady state still follows the committed widths.\n useLayoutEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n for (const [key, width] of Object.entries(effectiveWidths))\n root.style.setProperty(columnWidthVar(key), `${width}px`);\n }, [effectiveWidths, rootRef]);\n\n const applyWidth = useCallback(\n (key: string, width: number) => {\n rootRef.current?.style.setProperty(columnWidthVar(key), `${width}px`);\n },\n [rootRef],\n );\n\n /**\n * In controlled mode the drag has already written widths the prop may not\n * agree with. A frame later either the consumer has accepted them (the ref\n * holds the new values and this writes them again, a no-op) or it hasn't, and\n * the columns snap back to what the prop says. Without it a rejected width\n * would stay on screen, since nothing re-rendered to correct it.\n */\n const syncControlled = useCallback(() => {\n if (!isControlled) return;\n requestAnimationFrame(() => {\n for (const [key, width] of Object.entries(widthsRef.current)) applyWidth(key, width);\n });\n }, [applyWidth, isControlled]);\n\n const resize = useCallback(\n (key: string, toWidth: (from: number) => number) => {\n const base = freeze();\n const min = minWidthFor(columns?.find((c) => c.key === key));\n const next = { ...base, [key]: Math.max(min, Math.round(toWidth(base[key]))) };\n applyWidth(key, next[key]);\n commit(next);\n syncControlled();\n },\n [applyWidth, columns, commit, freeze, syncControlled],\n );\n\n const beginDrag = useCallback(\n (event: React.PointerEvent<HTMLDivElement>, key: string) => {\n if (event.button !== 0) return;\n // The handle sits on top of the header's sort button; without this the\n // drag would also count as a click on it.\n event.preventDefault();\n event.stopPropagation();\n\n const handle = event.currentTarget;\n const base = freeze();\n const startWidth = base[key];\n const startX = event.clientX;\n const min = minWidthFor(columns?.find((c) => c.key === key));\n\n let width = startWidth;\n let frame = 0;\n const paint = () => {\n frame = 0;\n applyWidth(key, width);\n };\n\n function finish(commitWidth: number | null) {\n if (frame) cancelAnimationFrame(frame);\n handle.releasePointerCapture?.(event.pointerId);\n handle.removeEventListener('pointermove', onMove);\n handle.removeEventListener('pointerup', onUp);\n handle.removeEventListener('pointercancel', onCancel);\n handle.removeEventListener('lostpointercapture', onCancel);\n window.removeEventListener('keydown', onKeyDown, true);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n setIsResizing(false);\n if (commitWidth == null) {\n // The freeze was committed at pointerdown and stays: on its own it\n // changes nothing the user can see. Only the drag is undone.\n applyWidth(key, startWidth);\n return;\n }\n if (commitWidth !== startWidth) commit({ ...base, [key]: commitWidth });\n syncControlled();\n }\n\n function onMove(moveEvent: PointerEvent) {\n // Always from the values captured at pointerdown, never from the\n // element's current geometry: re-measuring mid-drag lets rounding\n // accumulate and the handle slides away from the cursor.\n width = Math.max(min, Math.round(startWidth + moveEvent.clientX - startX));\n if (!frame) frame = requestAnimationFrame(paint);\n }\n function onUp() {\n finish(width);\n }\n function onCancel() {\n finish(null);\n }\n function onKeyDown(keyEvent: KeyboardEvent) {\n if (keyEvent.key !== 'Escape') return;\n keyEvent.preventDefault();\n finish(null);\n }\n\n handle.setPointerCapture?.(event.pointerId);\n handle.addEventListener('pointermove', onMove);\n handle.addEventListener('pointerup', onUp);\n handle.addEventListener('pointercancel', onCancel);\n handle.addEventListener('lostpointercapture', onCancel);\n window.addEventListener('keydown', onKeyDown, true);\n // On the body, not on the handle: the pointer leaves the handle as soon as\n // the drag starts, and the cursor must not flicker back to the default.\n document.body.style.cursor = 'col-resize';\n document.body.style.userSelect = 'none';\n setIsResizing(true);\n // Committing the freeze up front, rather than on release: until React has\n // rendered the frozen template, the tracks are still `fr`/`fit` and read\n // no custom property, so the drag would move nothing at all.\n if (Object.keys(widthsRef.current).length === 0) commit(base);\n },\n [applyWidth, columns, commit, freeze, syncControlled],\n );\n\n /**\n * Width the column would need for its widest cell, measured by sizing its\n * track to `max-content` for one synchronous layout.\n *\n * Reading `scrollWidth` off the cells instead reports the *min*-content width:\n * a body cell is free to wrap, so long text never overflows it, it only makes\n * the row taller, and the widest thing that can't wrap is a single word.\n * `max-content` is the width with no wrapping at all, which is what fitting a\n * column means. The header and every row are separate grids, so each sizes its\n * own track independently and all of them have to be read: the widest is the\n * one width that fits the whole column.\n */\n const measureAutoFit = useCallback(\n (key: string): number => {\n const root = rootRef.current;\n if (!root) return 0;\n const widthProperty = columnWidthVar(key);\n const previousWidth = root.style.getPropertyValue(widthProperty);\n // `--vl-total` is a calc() over these same properties, so it turns invalid\n // while one of them holds a keyword, and the header and body would be left\n // with an unresolvable width mid-measurement.\n const previousTotal = root.style.getPropertyValue('--vl-total');\n\n root.style.setProperty(widthProperty, 'max-content');\n root.style.removeProperty('--vl-total');\n let measured = 0;\n root.querySelectorAll(columnCellSelector(key)).forEach((cell) => {\n const width = Math.ceil(cell.getBoundingClientRect().width);\n if (width > measured) measured = width;\n });\n root.style.setProperty(widthProperty, previousWidth);\n if (previousTotal) root.style.setProperty('--vl-total', previousTotal);\n\n // Only the rendered rows are measurable, so this fits what is on screen.\n return Math.min(measured, root.clientWidth);\n },\n [rootRef],\n );\n\n const autoFit = useCallback(\n (key: string) => {\n const run = () => {\n const measured = measureAutoFit(key);\n if (measured > 0) resize(key, () => measured);\n };\n // Until the frozen template has rendered, the tracks read no custom\n // property and sizing one to `max-content` measures nothing. A drag has\n // already frozen by the time its double-click lands; a keyboard `End` on\n // an untouched list has not, so it waits for the render it just asked for.\n if (Object.keys(widthsRef.current).length > 0) run();\n else {\n commit(freeze());\n requestAnimationFrame(run);\n }\n },\n [commit, freeze, measureAutoFit, resize],\n );\n\n const reset = useCallback(() => {\n const root = rootRef.current;\n // The layout effect only ever writes the widths it has, so the properties of\n // the ones being dropped have to be cleared here or they would linger and\n // reappear with the next freeze.\n if (root) for (const key of Object.keys(widthsRef.current)) root.style.removeProperty(columnWidthVar(key));\n commit({});\n }, [commit, rootRef]);\n\n const isResizable = useCallback(\n (col: VirtualListColumn<T>) => resizableColumns && col.resizable !== false,\n [resizableColumns],\n );\n\n const resizeBy = useCallback((key: string, delta: number) => resize(key, (w) => w + delta), [resize]);\n\n const resizeToMin = useCallback(\n (key: string) => resize(key, () => minWidthFor(columns?.find((c) => c.key === key))),\n [columns, resize],\n );\n\n const getHandleProps = useCallback(\n (col: VirtualListColumn<T>): React.HTMLAttributes<HTMLDivElement> | null => {\n if (!isResizable(col)) return null;\n return {\n // Deliberately not focusable, and hidden from assistive technology: the\n // keyboard path is Alt plus the arrow keys on the header cell itself, so\n // a second tab stop per column would buy nothing and cost a lot.\n 'aria-hidden': true,\n onPointerDown: (event: React.PointerEvent<HTMLDivElement>) => beginDrag(event, col.key),\n onDoubleClick: (event: React.MouseEvent) => {\n event.stopPropagation();\n autoFit(col.key);\n },\n onClick: (event: React.MouseEvent) => event.stopPropagation(),\n };\n },\n [autoFit, beginDrag, isResizable],\n );\n\n return {\n widths: effectiveWidths,\n isFrozen: Object.keys(effectiveWidths).length > 0,\n isResizing,\n reset,\n isResizable,\n resizeBy,\n resizeToMin,\n autoFit,\n getHandleProps,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useColumnResize.mjs","names":[],"sources":["../../../../package/common/virtualList/useColumnResize.ts"],"sourcesContent":["import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';\n\nimport {\n columnCellSelector,\n columnWidthVar,\n loadPersistedColumns,\n resolveFrozenWidth,\n MIN_COLUMN_WIDTH,\n} from './virtualList.utils';\nimport type { VirtualListColumn } from './virtualList.types';\n\ninterface UseColumnResizeArgs<T> {\n columns?: VirtualListColumn<T>[];\n /**\n * The columns currently rendered, in order. A ref rather than a value because\n * the visible set is derived one hook later, and only the freeze reads it, at\n * event time.\n */\n visibleColumnsRef: React.RefObject<VirtualListColumn<T>[]>;\n resizableColumns: boolean;\n /** Controlled widths. When provided, internal state is ignored. */\n columnWidths?: Record<string, number>;\n onColumnWidthsChange?: (widths: Record<string, number>) => void;\n /** Restores widths saved under this key. Uncontrolled mode only. */\n persistColumnsKey?: string;\n rootRef: React.RefObject<HTMLDivElement | null>;\n}\n\nexport interface UseColumnResizeResult<T> {\n widths: Record<string, number>;\n /**\n * True once every visible column has an exact px width. Nothing moves at that\n * moment, but from then on the layout is pixels rather than `fr`/`fit`.\n */\n isFrozen: boolean;\n isResizing: boolean;\n /** Drops every user width and hands the layout back to the column definitions. */\n reset: () => void;\n /** Whether this column takes a resize at all, by handle or by keyboard. */\n isResizable: (col: VirtualListColumn<T>) => boolean;\n /** Widens (or, negative, narrows) one column. The keyboard entry point. */\n resizeBy: (key: string, delta: number) => void;\n /** Takes one column down to its minimum. */\n resizeToMin: (key: string) => void;\n /** Sizes one column to its widest rendered cell. */\n autoFit: (key: string) => void;\n /** Pointer props for one column's handle, or null when that column can't be resized. */\n getHandleProps: (col: VirtualListColumn<T>) => React.HTMLAttributes<HTMLDivElement> | null;\n}\n\nfunction minWidthFor<T>(col: VirtualListColumn<T> | undefined): number {\n return Math.max(1, col?.minWidth ?? MIN_COLUMN_WIDTH);\n}\n\n/**\n * User column resizing: the width state, and a drag that doesn't go through\n * React.\n *\n * A pointer move writes the dragged column's custom property straight onto the\n * list element. The header and every row read that same property, so one DOM\n * write resizes all of them in a single layout pass. Going through state\n * instead would re-render the header plus every visible row on every frame, and\n * the handle would trail the cursor by one frame, which is the whole difference\n * between this feeling attached to the pointer and feeling cheap. React is told\n * once, on release.\n *\n * The first resize **freezes** every visible column to its measured width. A\n * `fr` track can't express \"this one column is now 240px\" without the others\n * silently absorbing the difference, and once they hit their minimum the dragged\n * edge stops following the cursor, which is the worst moment for it to happen.\n * Frozen, the table is exact pixels and simply scrolls horizontally instead.\n */\nexport function useColumnResize<T>({\n columns,\n visibleColumnsRef,\n resizableColumns,\n columnWidths,\n onColumnWidthsChange,\n persistColumnsKey,\n rootRef,\n}: UseColumnResizeArgs<T>): UseColumnResizeResult<T> {\n const isControlled = columnWidths !== undefined;\n const [internalWidths, setInternalWidths] = useState<Record<string, number>>(\n () => loadPersistedColumns(persistColumnsKey)?.widths ?? {},\n );\n const [isResizing, setIsResizing] = useState(false);\n const effectiveWidths = isControlled ? columnWidths! : internalWidths;\n\n // Read by the pointer handlers, which are installed once per drag and must not\n // capture a stale snapshot of either.\n const widthsRef = useRef(effectiveWidths);\n widthsRef.current = effectiveWidths;\n\n const commit = useCallback(\n (next: Record<string, number>) => {\n if (!isControlled) setInternalWidths(next);\n onColumnWidthsChange?.(next);\n },\n [isControlled, onColumnWidthsChange],\n );\n\n /**\n * Current width of every visible column, measured from the rendered header so\n * the freeze is invisible: the px values are the ones already on screen.\n * Columns that already have a width keep it, and a header cell that can't be\n * measured (jsdom, a display:none list) falls back to its declared width.\n */\n const freeze = useCallback((): Record<string, number> => {\n const root = rootRef.current;\n const next: Record<string, number> = { ...widthsRef.current };\n for (const col of visibleColumnsRef.current) {\n if (next[col.key] != null) continue;\n const cell = root?.querySelector(`[aria-rowindex=\"1\"] ${columnCellSelector(col.key)}`);\n const measured = cell ? Math.round(cell.getBoundingClientRect().width) : 0;\n next[col.key] = measured > 0 ? measured : resolveFrozenWidth(col);\n }\n return next;\n }, [rootRef, visibleColumnsRef]);\n\n // The widths live on the element as custom properties, written from here and\n // from the drag, never through React's `style`. One owner means a drag's\n // imperative writes can't be clobbered by a render that happens to land\n // mid-gesture, and the steady state still follows the committed widths.\n useLayoutEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n for (const [key, width] of Object.entries(effectiveWidths))\n root.style.setProperty(columnWidthVar(key), `${width}px`);\n }, [effectiveWidths, rootRef]);\n\n const applyWidth = useCallback(\n (key: string, width: number) => {\n rootRef.current?.style.setProperty(columnWidthVar(key), `${width}px`);\n },\n [rootRef],\n );\n\n /**\n * In controlled mode the drag has already written widths the prop may not\n * agree with. A frame later either the consumer has accepted them (the ref\n * holds the new values and this writes them again, a no-op) or it hasn't, and\n * the columns snap back to what the prop says. Without it a rejected width\n * would stay on screen, since nothing re-rendered to correct it.\n */\n const syncControlled = useCallback(() => {\n if (!isControlled) return;\n requestAnimationFrame(() => {\n for (const [key, width] of Object.entries(widthsRef.current)) applyWidth(key, width);\n });\n }, [applyWidth, isControlled]);\n\n const resize = useCallback(\n (key: string, toWidth: (from: number) => number) => {\n const base = freeze();\n const min = minWidthFor(columns?.find((c) => c.key === key));\n const next = { ...base, [key]: Math.max(min, Math.round(toWidth(base[key]))) };\n applyWidth(key, next[key]);\n commit(next);\n syncControlled();\n },\n [applyWidth, columns, commit, freeze, syncControlled],\n );\n\n const beginDrag = useCallback(\n (event: React.PointerEvent<HTMLDivElement>, key: string) => {\n if (event.button !== 0) return;\n // The handle sits on top of the header's sort button; without this the\n // drag would also count as a click on it.\n event.preventDefault();\n event.stopPropagation();\n\n const handle = event.currentTarget;\n const base = freeze();\n const startWidth = base[key];\n const startX = event.clientX;\n const min = minWidthFor(columns?.find((c) => c.key === key));\n\n let width = startWidth;\n let frame = 0;\n const paint = () => {\n frame = 0;\n applyWidth(key, width);\n };\n\n function finish(commitWidth: number | null) {\n if (frame) cancelAnimationFrame(frame);\n handle.releasePointerCapture?.(event.pointerId);\n handle.removeEventListener('pointermove', onMove);\n handle.removeEventListener('pointerup', onUp);\n handle.removeEventListener('pointercancel', onCancel);\n handle.removeEventListener('lostpointercapture', onCancel);\n window.removeEventListener('keydown', onKeyDown, true);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n setIsResizing(false);\n if (commitWidth == null) {\n // The freeze was committed at pointerdown and stays: on its own it\n // changes nothing the user can see. Only the drag is undone.\n applyWidth(key, startWidth);\n return;\n }\n if (commitWidth !== startWidth) commit({ ...base, [key]: commitWidth });\n syncControlled();\n }\n\n function onMove(moveEvent: PointerEvent) {\n // Always from the values captured at pointerdown, never from the\n // element's current geometry: re-measuring mid-drag lets rounding\n // accumulate and the handle slides away from the cursor.\n width = Math.max(min, Math.round(startWidth + moveEvent.clientX - startX));\n if (!frame) frame = requestAnimationFrame(paint);\n }\n function onUp() {\n finish(width);\n }\n function onCancel() {\n finish(null);\n }\n function onKeyDown(keyEvent: KeyboardEvent) {\n if (keyEvent.key !== 'Escape') return;\n keyEvent.preventDefault();\n finish(null);\n }\n\n handle.setPointerCapture?.(event.pointerId);\n handle.addEventListener('pointermove', onMove);\n handle.addEventListener('pointerup', onUp);\n handle.addEventListener('pointercancel', onCancel);\n handle.addEventListener('lostpointercapture', onCancel);\n window.addEventListener('keydown', onKeyDown, true);\n // On the body, not on the handle: the pointer leaves the handle as soon as\n // the drag starts, and the cursor must not flicker back to the default.\n document.body.style.cursor = 'col-resize';\n document.body.style.userSelect = 'none';\n setIsResizing(true);\n // Committing the freeze up front, rather than on release: until React has\n // rendered the frozen template, the tracks are still `fr`/`fit` and read\n // no custom property, so the drag would move nothing at all.\n if (Object.keys(widthsRef.current).length === 0) commit(base);\n },\n [applyWidth, columns, commit, freeze, syncControlled],\n );\n\n /**\n * Width the column would need for its widest cell, measured by sizing its\n * track to `max-content` for one synchronous layout.\n *\n * Reading `scrollWidth` off the cells instead reports the *min*-content width:\n * a body cell is free to wrap, so long text never overflows it, it only makes\n * the row taller, and the widest thing that can't wrap is a single word.\n * `max-content` is the width with no wrapping at all, which is what fitting a\n * column means. The header and every row are separate grids, so each sizes its\n * own track independently and all of them have to be read: the widest is the\n * one width that fits the whole column.\n */\n const measureAutoFit = useCallback(\n (key: string): number => {\n const root = rootRef.current;\n if (!root) return 0;\n const widthProperty = columnWidthVar(key);\n const previousWidth = root.style.getPropertyValue(widthProperty);\n // `--vl-total` is a calc() over these same properties, so it turns invalid\n // while one of them holds a keyword, and the header and body would be left\n // with an unresolvable width mid-measurement.\n const previousTotal = root.style.getPropertyValue('--vl-total');\n\n root.style.setProperty(widthProperty, 'max-content');\n root.style.removeProperty('--vl-total');\n let measured = 0;\n root.querySelectorAll(columnCellSelector(key)).forEach((cell) => {\n const width = Math.ceil(cell.getBoundingClientRect().width);\n if (width > measured) measured = width;\n });\n root.style.setProperty(widthProperty, previousWidth);\n if (previousTotal) root.style.setProperty('--vl-total', previousTotal);\n\n // Only the rendered rows are measurable, so this fits what is on screen.\n return Math.min(measured, root.clientWidth);\n },\n [rootRef],\n );\n\n const autoFit = useCallback(\n (key: string) => {\n const run = () => {\n const measured = measureAutoFit(key);\n if (measured > 0) resize(key, () => measured);\n };\n // Until the frozen template has rendered, the tracks read no custom\n // property and sizing one to `max-content` measures nothing. A drag has\n // already frozen by the time its double-click lands; a keyboard `End` on\n // an untouched list has not, so it waits for the render it just asked for.\n if (Object.keys(widthsRef.current).length > 0) run();\n else {\n commit(freeze());\n requestAnimationFrame(run);\n }\n },\n [commit, freeze, measureAutoFit, resize],\n );\n\n const reset = useCallback(() => {\n const root = rootRef.current;\n // The layout effect only ever writes the widths it has, so the properties of\n // the ones being dropped have to be cleared here or they would linger and\n // reappear with the next freeze.\n if (root) for (const key of Object.keys(widthsRef.current)) root.style.removeProperty(columnWidthVar(key));\n commit({});\n }, [commit, rootRef]);\n\n const isResizable = useCallback(\n (col: VirtualListColumn<T>) => resizableColumns && col.resizable !== false,\n [resizableColumns],\n );\n\n const resizeBy = useCallback((key: string, delta: number) => resize(key, (w) => w + delta), [resize]);\n\n const resizeToMin = useCallback(\n (key: string) => resize(key, () => minWidthFor(columns?.find((c) => c.key === key))),\n [columns, resize],\n );\n\n const getHandleProps = useCallback(\n (col: VirtualListColumn<T>): React.HTMLAttributes<HTMLDivElement> | null => {\n if (!isResizable(col)) return null;\n return {\n // Deliberately not focusable, and hidden from assistive technology: the\n // keyboard path is Alt plus the arrow keys on the header cell itself, so\n // a second tab stop per column would buy nothing and cost a lot.\n 'aria-hidden': true,\n onPointerDown: (event: React.PointerEvent<HTMLDivElement>) => beginDrag(event, col.key),\n onDoubleClick: (event: React.MouseEvent) => {\n event.stopPropagation();\n autoFit(col.key);\n },\n onClick: (event: React.MouseEvent) => event.stopPropagation(),\n };\n },\n [autoFit, beginDrag, isResizable],\n );\n\n return {\n widths: effectiveWidths,\n isFrozen: Object.keys(effectiveWidths).length > 0,\n isResizing,\n reset,\n isResizable,\n resizeBy,\n resizeToMin,\n autoFit,\n getHandleProps,\n };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{COLUMN_STORAGE_PREFIX as e,buildColumnTemplate as t,buildFrozenTemplate as n,columnWidthVar as r,isColumnInitiallyVisible as i,loadPersistedColumns as a,measureCellWidth as o}from"./virtualList.utils.mjs";import{useCallback as s,useEffect as c,useLayoutEffect as l,useRef as u,useState as d}from"react";function f({columns:f,items:p,multiSelect:m,visibleColumnKeys:h,onVisibleColumnsChange:g,persistColumnsKey:_,showColumnToggle:v,userWidths:y,isFrozen:b,rootRef:x,startIndex:S,endIndex:C,containerHeight:w,containerWidth:T}){let E=h!==void 0,[D,O]=d(!1),[k,A]=d({}),[j,M]=d(()=>{let e=a(_);return new Set((f??[]).filter(t=>i(t,e)).map(e=>e.key))}),N=u(new Set((f??[]).map(e=>e.key)));c(()=>{if(E)return;let e=f??[],t=new Set(e.map(e=>e.key)),n=N.current,r=t.size===n.size;if(r){for(let e of t)if(!n.has(e)){r=!1;break}}if(r)return;N.current=t;let o=a(_);M(t=>{let r=new Set;for(let a of e)n.has(a.key)?t.has(a.key)&&r.add(a.key):i(a,o)&&r.add(a.key);return r})},[f,E,_]),c(()=>{if(E||!_||typeof window>`u`)return;let t=f??[];if(t.length!==0&&j.size!==0)try{window.localStorage.setItem(e+_,JSON.stringify({visible:[...j],known:t.map(e=>e.key),widths:y}))}catch{}},[j,f,E,_,y]);let P=E?new Set(h):j,F=(f??[]).filter(e=>e.lockVisible).map(e=>e.key),I=F.some(e=>!P.has(e))?new Set([...P,...F]):P,L=!!f?.length,R=L?f.filter(e=>I.has(e.key)):[],z=L?f.filter(e=>!e.defaultHidden&&!I.has(e.key)).length:0,B=L?`${m&&L?`40px `:``}${b?n(R):t(R,k)}`:void 0,V=v!==!1&&L&&f.some(e=>!e.hideFromToggle),H={};if(b&&L){let e=R.map(e=>`var(${r(e.key)}, 160px)`);m&&e.unshift(`40px`),V&&e.push(`32px`),H[`--vl-total`]=`calc(${e.join(` + `)})`}let U=R.filter(e=>e.width.type===`fit`),W=!b&&U.length>0,G=U.map(e=>e.key).join(`|`),[K,q]=d({key:G,items:p});(K.key!==G||K.items!==p)&&(q({key:G,items:p}),Object.keys(k).length>0&&A({}));let J=s(()=>{let e=x.current;if(!e)return;let t=new Map;e.querySelectorAll(`[data-fit-key]`).forEach(e=>{let n=e,r=n.getAttribute(`data-fit-key`);if(!r)return;let i=o(n);i>(t.get(r)??0)&&t.set(r,i)}),t.size!==0&&A(n=>{let r=!1,i={...n};for(let[a,o]of t){if(o<=0)continue;let t=Math.min(Math.ceil(o),e.clientWidth);t>(n[a]??0)&&(i[a]=t,r=!0)}return r?i:n})},[x]),[Y]=d(()=>typeof ResizeObserver>`u`?null:new ResizeObserver(()=>J())),X=u(new Set);c(()=>()=>{Y?.disconnect(),X.current.clear()},[Y]),l(()=>{if(!W)return;let e=x.current;if(!e||(J(),!Y))return;let t=new Set(e.querySelectorAll(`[data-fit-key]`)),n=X.current;for(let e of n)t.has(e)||(Y.unobserve(e),n.delete(e));for(let e of t)n.has(e)||(Y.observe(e),n.add(e))},[x,W,G,k,S,C,w,T,p,J,Y]),c(()=>{if(!W)return;let e=0,t=requestAnimationFrame(()=>{J(),e=requestAnimationFrame(()=>J())});return()=>{cancelAnimationFrame(t),cancelAnimationFrame(e)}},[W,G,p,J]);let Z=s(()=>A({}),[]);function Q(e){if(f?.find(t=>t.key===e)?.lockVisible)return;let t=new Set(I);if(t.has(e)){if(t.size<=1)return;t.delete(e)}else t.add(e);let n=[...t];E||M(t),g?.(n)}return{hasColumns:L,visibleColumns:R,columnTemplate:B,widthVars:H,shouldShowToggle:V,effectiveVisible:I,manuallyHiddenCount:z,toggleOpen:D,setToggleOpen:O,handleToggleColumn:Q,recalculateColumns:Z}}export{f as useColumns};
1
+ "use client";import{COLUMN_STORAGE_PREFIX as e,buildColumnTemplate as t,buildFrozenTemplate as n,columnWidthVar as r,isColumnInitiallyVisible as i,loadPersistedColumns as a,measureCellWidth as o}from"./virtualList.utils.mjs";import{useCallback as s,useEffect as c,useLayoutEffect as l,useRef as u,useState as d}from"react";function f({columns:f,items:p,multiSelect:m,visibleColumnKeys:h,onVisibleColumnsChange:g,persistColumnsKey:_,showColumnToggle:v,userWidths:y,isFrozen:b,rootRef:x,startIndex:S,endIndex:C,containerHeight:w,containerWidth:T}){let E=h!==void 0,[D,O]=d(!1),[k,A]=d({}),[j,M]=d(()=>{let e=a(_);return new Set((f??[]).filter(t=>i(t,e)).map(e=>e.key))}),N=u(new Set((f??[]).map(e=>e.key)));c(()=>{if(E)return;let e=f??[],t=new Set(e.map(e=>e.key)),n=N.current,r=t.size===n.size;if(r){for(let e of t)if(!n.has(e)){r=!1;break}}if(r)return;N.current=t;let o=a(_);M(t=>{let r=new Set;for(let a of e)n.has(a.key)?t.has(a.key)&&r.add(a.key):i(a,o)&&r.add(a.key);return r})},[f,E,_]),c(()=>{if(E||!_||typeof window>`u`)return;let t=f??[];if(t.length!==0&&j.size!==0)try{window.localStorage.setItem(e+_,JSON.stringify({visible:[...j],known:t.map(e=>e.key),widths:y}))}catch{}},[j,f,E,_,y]);let P=E?new Set(h):j,F=(f??[]).filter(e=>e.lockVisible).map(e=>e.key),I=F.some(e=>!P.has(e))?new Set([...P,...F]):P,L=!!f?.length,R=L?f.filter(e=>I.has(e.key)):[],z=L?f.filter(e=>!e.defaultHidden&&!I.has(e.key)).length:0,B=L?`${m&&L?`40px `:``}${b?n(R):t(R,k)}`:void 0,V=v!==!1&&L&&f.some(e=>!e.hideFromToggle),H={};if(b&&L){let e=R.map(e=>`var(${r(e.key)}, 160px)`);m&&e.unshift(`40px`),V&&e.push(`32px`),H[`--vl-total`]=`calc(${e.join(` + `)})`}let U=R.filter(e=>e.width.type===`fit`),W=!b&&U.length>0,G=U.map(e=>e.key).join(`|`),[K,q]=d({key:G,items:p});(K.key!==G||K.items!==p)&&(q({key:G,items:p}),Object.keys(k).length>0&&A({}));let J=s(()=>{let e=x.current;if(!e)return;let t=new Map;e.querySelectorAll(`[data-fit-key]`).forEach(e=>{let n=e,r=n.getAttribute(`data-fit-key`);if(!r)return;let i=o(n);i>(t.get(r)??0)&&t.set(r,i)}),t.size!==0&&A(n=>{let r=!1,i={...n};for(let[a,o]of t){if(o<=0)continue;let t=Math.min(Math.ceil(o),e.clientWidth);t>(n[a]??0)&&(i[a]=t,r=!0)}return r?i:n})},[x]),[Y]=d(()=>typeof ResizeObserver>`u`?null:new ResizeObserver(()=>J())),X=u(new Set);c(()=>()=>{Y?.disconnect(),X.current.clear()},[Y]),l(()=>{if(!W)return;let e=x.current;if(!e||(J(),!Y))return;let t=new Set(e.querySelectorAll(`[data-fit-key]`)),n=X.current;for(let e of n)t.has(e)||(Y.unobserve(e),n.delete(e));for(let e of t)n.has(e)||(Y.observe(e),n.add(e))},[x,W,G,k,S,C,w,T,p,J,Y]),c(()=>{if(!W)return;let e=0,t=requestAnimationFrame(()=>{J(),e=requestAnimationFrame(()=>J())});return()=>{cancelAnimationFrame(t),cancelAnimationFrame(e)}},[W,G,p,J]);let Z=s(()=>A({}),[]);function Q(e){if(f?.find(t=>t.key===e)?.lockVisible)return;let t=new Set(I);if(t.has(e)){if(t.size<=1)return;t.delete(e)}else t.add(e);let n=[...t];E||M(t),g?.(n)}return{hasColumns:L,visibleColumns:R,columnTemplate:B,widthVars:H,shouldShowToggle:V,effectiveVisible:I,manuallyHiddenCount:z,toggleOpen:D,setToggleOpen:O,handleToggleColumn:Q,recalculateColumns:Z}}export{f as useColumns};
2
2
  //# sourceMappingURL=useColumns.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useColumns.mjs","names":[],"sources":["../../../../package/common/virtualList/useColumns.ts"],"sourcesContent":["import React, { useState, useRef, useEffect, useLayoutEffect, useCallback } from 'react';\n\nimport {\n buildColumnTemplate,\n buildFrozenTemplate,\n columnWidthVar,\n DEFAULT_FROZEN_WIDTH,\n measureCellWidth,\n loadPersistedColumns,\n isColumnInitiallyVisible,\n COLUMN_STORAGE_PREFIX,\n type PersistedColumns,\n} from './virtualList.utils';\nimport type { VirtualListColumn } from './virtualList.types';\n\ninterface UseColumnsArgs<T> {\n columns?: VirtualListColumn<T>[];\n items: T[];\n multiSelect: boolean;\n visibleColumnKeys?: string[];\n onVisibleColumnsChange?: (keys: string[]) => void;\n persistColumnsKey?: string;\n showColumnToggle?: boolean;\n /** User-set column widths, from `useColumnResize`. */\n userWidths: Record<string, number>;\n /** Whether those widths have taken over the layout. */\n isFrozen: boolean;\n rootRef: React.RefObject<HTMLDivElement | null>;\n /** Visible-window bounds — re-measure `fit` columns as new cells scroll in. */\n startIndex: number;\n endIndex: number;\n containerHeight: number;\n /** Re-measure `fit` columns when the container width settles (e.g. after a route transition). */\n containerWidth: number;\n}\n\nexport interface UseColumnsResult<T> {\n hasColumns: boolean;\n visibleColumns: VirtualListColumn<T>[];\n columnTemplate: string | undefined;\n /**\n * Custom properties for the list element: the total width of a frozen layout,\n * as a `calc()` over the per-column properties so that rewriting one width\n * during a drag updates the total without any bookkeeping.\n */\n widthVars: React.CSSProperties;\n shouldShowToggle: boolean;\n effectiveVisible: Set<string>;\n /** How many default-visible columns the user has hidden (excludes defaultHidden). */\n manuallyHiddenCount: number;\n toggleOpen: boolean;\n setToggleOpen: React.Dispatch<React.SetStateAction<boolean>>;\n handleToggleColumn: (key: string) => void;\n /** Imperative escape hatch: drop fit-column pins so they re-measure on the\n * next layout. For out-of-band content changes that don't flow through a new\n * `items` array or `columns` set (which reset automatically). */\n recalculateColumns: () => void;\n}\n\n/**\n * Table-mode column logic: visibility (controlled or uncontrolled, with\n * localStorage persistence and runtime reconciliation), the toggle popover, and\n * `fit`-column width measurement that pins one shared px track across the header\n * and every row grid so they stay aligned.\n */\nexport function useColumns<T>({\n columns,\n items,\n multiSelect,\n visibleColumnKeys,\n onVisibleColumnsChange,\n persistColumnsKey,\n showColumnToggle,\n userWidths,\n isFrozen,\n rootRef,\n startIndex,\n endIndex,\n containerHeight,\n containerWidth,\n}: UseColumnsArgs<T>): UseColumnsResult<T> {\n const isControlled = visibleColumnKeys !== undefined;\n const [toggleOpen, setToggleOpen] = useState(false);\n // Measured px widths for `fit` columns, keyed by column key. Pinning these\n // into the shared column template keeps the header and rows aligned (a raw\n // `fit-content` track resolves per-grid and drifts). See the effects below.\n const [fitWidths, setFitWidths] = useState<Record<string, number>>({});\n\n const [internalVisibleKeys, setInternalVisibleKeys] = useState<Set<string>>(() => {\n const persisted = loadPersistedColumns(persistColumnsKey);\n return new Set((columns ?? []).filter((c) => isColumnInitiallyVisible(c, persisted)).map((c) => c.key));\n });\n // The set of column keys the internal visibility state was last reconciled\n // against. The lazy initializer above only runs at mount, so without this a\n // list that mounts in list mode (no columns) and later switches to table mode\n // would keep an empty visible set and render no columns.\n const knownColumnKeysRef = useRef<Set<string>>(new Set((columns ?? []).map((c) => c.key)));\n\n // Re-derive internal visibility when the column set changes at runtime: new\n // columns get their saved/default visibility, removed columns drop out, and\n // existing columns keep whatever the user toggled them to. This is also what\n // applies persisted settings when a list switches from list mode to table\n // mode (columns absent at mount, supplied later).\n useEffect(() => {\n if (isControlled) return;\n const cols = columns ?? [];\n const currentKeys = new Set(cols.map((c) => c.key));\n const known = knownColumnKeysRef.current;\n let identical = currentKeys.size === known.size;\n if (identical)\n for (const k of currentKeys)\n if (!known.has(k)) {\n identical = false;\n break;\n }\n if (identical) return;\n knownColumnKeysRef.current = currentKeys;\n const persisted = loadPersistedColumns(persistColumnsKey);\n setInternalVisibleKeys((prev) => {\n const next = new Set<string>();\n for (const c of cols) {\n if (known.has(c.key)) {\n if (prev.has(c.key)) next.add(c.key); // preserve the current-session choice\n } else if (isColumnInitiallyVisible(c, persisted)) {\n next.add(c.key); // newly-added column: saved setting, else defaultHidden\n }\n }\n return next;\n });\n }, [columns, isControlled, persistColumnsKey]);\n\n // Persist visibility whenever it changes (uncontrolled mode only). Skip while\n // there are no columns, or the transient empty state during a list→table\n // switch before the reconcile effect above has filled in the visible set —\n // writing then would clobber the saved config with an empty set.\n useEffect(() => {\n if (isControlled || !persistColumnsKey || typeof window === 'undefined') return;\n const cols = columns ?? [];\n if (cols.length === 0 || internalVisibleKeys.size === 0) return;\n try {\n window.localStorage.setItem(\n COLUMN_STORAGE_PREFIX + persistColumnsKey,\n JSON.stringify({\n visible: [...internalVisibleKeys],\n known: cols.map((c) => c.key),\n widths: userWidths,\n } satisfies PersistedColumns),\n );\n } catch {\n // Storage full or unavailable — non-fatal, just don't persist.\n }\n }, [internalVisibleKeys, columns, isControlled, persistColumnsKey, userWidths]);\n\n // Locked columns can never be hidden — force them into the visible set even if\n // a controlled `visibleColumnKeys` or persisted state omits them. Only clone\n // (rather than mutate the state Set) when a locked key is actually missing;\n // in uncontrolled mode they're already present via isColumnInitiallyVisible.\n const baseVisible: Set<string> = isControlled ? new Set(visibleColumnKeys) : internalVisibleKeys;\n const lockedKeys = (columns ?? []).filter((c) => c.lockVisible).map((c) => c.key);\n const effectiveVisible: Set<string> = lockedKeys.some((k) => !baseVisible.has(k))\n ? new Set([...baseVisible, ...lockedKeys])\n : baseVisible;\n\n const hasColumns = !!columns?.length;\n const visibleColumns = hasColumns ? columns!.filter((c) => effectiveVisible.has(c.key)) : [];\n // A column counts as \"manually hidden\" only if it's default-visible yet\n // currently hidden — a defaultHidden column being hidden is its default\n // state, not a user choice, so it never contributes to the chip.\n const manuallyHiddenCount = hasColumns\n ? columns!.filter((c) => !c.defaultHidden && !effectiveVisible.has(c.key)).length\n : 0;\n const selectPrefix = multiSelect && hasColumns ? '40px ' : '';\n const columnTemplate = hasColumns\n ? `${selectPrefix}${isFrozen ? buildFrozenTemplate(visibleColumns) : buildColumnTemplate(visibleColumns, fitWidths)}`\n : undefined;\n // Hide the gear entirely when nothing is left to toggle (every column opts out).\n const shouldShowToggle = showColumnToggle !== false && hasColumns && columns!.some((c) => !c.hideFromToggle);\n\n // Sum of the tracks, so the header and body can stretch past the viewport and\n // the list scrolls horizontally instead of clipping. Kept as a `calc()` over\n // the same custom properties the tracks read, so a drag rewriting one of them\n // resizes the row canvas in the same layout pass.\n const widthVars: React.CSSProperties = {};\n if (isFrozen && hasColumns) {\n const parts = visibleColumns.map((c) => `var(${columnWidthVar(c.key)}, ${DEFAULT_FROZEN_WIDTH}px)`);\n if (multiSelect) parts.unshift('40px');\n if (shouldShowToggle) parts.push('32px');\n (widthVars as Record<string, string>)['--vl-total'] = `calc(${parts.join(' + ')})`;\n }\n\n // ── `fit` column width measurement ──────────────────────────────────────────\n const fitColumns = visibleColumns.filter((c) => c.width.type === 'fit');\n // A frozen layout is exact px and ignores the pins, so measuring would only\n // fight the user: `measureFitWidths` never shrinks a column, and every drag\n // narrower than the content would be undone on the next scroll frame.\n const hasFit = !isFrozen && fitColumns.length > 0;\n const fitColKey = fitColumns.map((c) => c.key).join('|');\n\n // Drop the measured pins when the data or the fit-column set changes, so the\n // measure effect below re-reads the true intrinsic width on the next pass —\n // this is what lets a column shrink (during scroll the effect only grows it,\n // to avoid jitter). Resetting state during render is React's recommended\n // pattern for \"reset on prop change\" and avoids a cascading effect render.\n const [fitReset, setFitReset] = useState<{ key: string; items: T[] }>({ key: fitColKey, items });\n if (fitReset.key !== fitColKey || fitReset.items !== items) {\n setFitReset({ key: fitColKey, items });\n if (Object.keys(fitWidths).length > 0) setFitWidths({});\n }\n\n // Measure every fit cell currently in the DOM (header + visible rows), keyed\n // by its `data-fit-key`, and grow each column's pin to the widest. Reading the\n // key off the DOM (rather than closing over `fitColumns`) keeps this a stable\n // callback the ResizeObserver below can reuse. `measureCellWidth` reports the\n // true content width even when the cell is pinned narrower, so a later pass\n // always recovers a column first measured while it was still empty.\n const measureFitWidths = useCallback(() => {\n const root = rootRef.current;\n if (!root) return;\n const maxByKey = new Map<string, number>();\n root.querySelectorAll('[data-fit-key]').forEach((node) => {\n const el = node as HTMLElement;\n const key = el.getAttribute('data-fit-key');\n if (!key) return;\n const w = measureCellWidth(el);\n if (w > (maxByKey.get(key) ?? 0)) maxByKey.set(key, w);\n });\n if (maxByKey.size === 0) return;\n setFitWidths((prev) => {\n let changed = false;\n const next = { ...prev };\n for (const [key, max] of maxByKey) {\n if (max <= 0) continue;\n // Cap at the viewport width so one oversized cell can't blow out layout.\n const pinned = Math.min(Math.ceil(max), root.clientWidth);\n if (pinned > (prev[key] ?? 0)) {\n next[key] = pinned;\n changed = true;\n }\n }\n return changed ? next : prev;\n });\n }, [rootRef]);\n\n // One ResizeObserver shared across all fit cells. It re-measures whenever a\n // cell's box changes — crucially when content first appears after mount (which\n // changes the cell's height even while its width is pinned), so a too-early or\n // empty-cell measure self-corrects instead of sticking. Its initial callback\n // also fires once after layout settles, covering route transitions and other\n // post-mount layout shifts without depending on font/rAF timing.\n const [fitObserver] = useState<ResizeObserver | null>(() =>\n typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(() => measureFitWidths()),\n );\n const observedRef = useRef<Set<Element>>(new Set());\n useEffect(\n () => () => {\n fitObserver?.disconnect();\n observedRef.current.clear();\n },\n [fitObserver],\n );\n\n // Measure synchronously (before paint, so a wider row scrolling in never shows\n // a clipped frame), then *diff* the observed set rather than re-observing every\n // cell. Re-observing fires a redundant ResizeObserver callback per node, and\n // `startIndex`/`endIndex` change every scroll frame — so observing only the\n // cells that entered (and dropping the ones that left) keeps stable, already\n // pinned cells from generating any observer traffic while scrolling. A newly\n // entered cell still fires exactly once, which is when we want to measure it.\n useLayoutEffect(() => {\n if (!hasFit) return;\n const root = rootRef.current;\n if (!root) return;\n measureFitWidths();\n if (!fitObserver) return;\n const current = new Set<Element>(root.querySelectorAll('[data-fit-key]'));\n const observed = observedRef.current;\n for (const el of observed)\n if (!current.has(el)) {\n fitObserver.unobserve(el);\n observed.delete(el);\n }\n for (const el of current)\n if (!observed.has(el)) {\n fitObserver.observe(el);\n observed.add(el);\n }\n }, [\n rootRef,\n hasFit,\n fitColKey,\n fitWidths,\n startIndex,\n endIndex,\n containerHeight,\n containerWidth,\n items,\n measureFitWidths,\n fitObserver,\n ]);\n\n // Cheap insurance: re-measure on the next two frames after mount / data /\n // fit-column changes, in case the icons (or the injected FontAwesome sizing\n // CSS) resolve a frame after the first synchronous pass. Safe and scoped —\n // measureFitWidths only ever grows a pin, and this runs on mount / data change\n // (not every scroll frame), so it keeps the diff-observe perf win.\n useEffect(() => {\n if (!hasFit) return;\n let raf2 = 0;\n const raf1 = requestAnimationFrame(() => {\n measureFitWidths();\n raf2 = requestAnimationFrame(() => measureFitWidths());\n });\n return () => {\n cancelAnimationFrame(raf1);\n cancelAnimationFrame(raf2);\n };\n }, [hasFit, fitColKey, items, measureFitWidths]);\n\n // Force a fresh fit-column measure regardless of current pins. Always installs\n // a new empty object so the measure layout effect re-runs even when nothing\n // was pinned (e.g. content changed while the column was still fit-content).\n const recalculateColumns = useCallback(() => setFitWidths({}), []);\n\n function handleToggleColumn(key: string) {\n // Locked columns can't be toggled off.\n if (columns?.find((c) => c.key === key)?.lockVisible) return;\n const next = new Set(effectiveVisible);\n if (next.has(key)) {\n if (next.size <= 1) return;\n next.delete(key);\n } else {\n next.add(key);\n }\n const nextArray = [...next];\n if (!isControlled) setInternalVisibleKeys(next);\n onVisibleColumnsChange?.(nextArray);\n }\n\n return {\n hasColumns,\n visibleColumns,\n columnTemplate,\n widthVars,\n shouldShowToggle,\n effectiveVisible,\n manuallyHiddenCount,\n toggleOpen,\n setToggleOpen,\n handleToggleColumn,\n recalculateColumns,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useColumns.mjs","names":[],"sources":["../../../../package/common/virtualList/useColumns.ts"],"sourcesContent":["import React, { useState, useRef, useEffect, useLayoutEffect, useCallback } from 'react';\n\nimport {\n buildColumnTemplate,\n buildFrozenTemplate,\n columnWidthVar,\n DEFAULT_FROZEN_WIDTH,\n measureCellWidth,\n loadPersistedColumns,\n isColumnInitiallyVisible,\n COLUMN_STORAGE_PREFIX,\n type PersistedColumns,\n} from './virtualList.utils';\nimport type { VirtualListColumn } from './virtualList.types';\n\ninterface UseColumnsArgs<T> {\n columns?: VirtualListColumn<T>[];\n items: T[];\n multiSelect: boolean;\n visibleColumnKeys?: string[];\n onVisibleColumnsChange?: (keys: string[]) => void;\n persistColumnsKey?: string;\n showColumnToggle?: boolean;\n /** User-set column widths, from `useColumnResize`. */\n userWidths: Record<string, number>;\n /** Whether those widths have taken over the layout. */\n isFrozen: boolean;\n rootRef: React.RefObject<HTMLDivElement | null>;\n /** Visible-window bounds — re-measure `fit` columns as new cells scroll in. */\n startIndex: number;\n endIndex: number;\n containerHeight: number;\n /** Re-measure `fit` columns when the container width settles (e.g. after a route transition). */\n containerWidth: number;\n}\n\nexport interface UseColumnsResult<T> {\n hasColumns: boolean;\n visibleColumns: VirtualListColumn<T>[];\n columnTemplate: string | undefined;\n /**\n * Custom properties for the list element: the total width of a frozen layout,\n * as a `calc()` over the per-column properties so that rewriting one width\n * during a drag updates the total without any bookkeeping.\n */\n widthVars: React.CSSProperties;\n shouldShowToggle: boolean;\n effectiveVisible: Set<string>;\n /** How many default-visible columns the user has hidden (excludes defaultHidden). */\n manuallyHiddenCount: number;\n toggleOpen: boolean;\n setToggleOpen: React.Dispatch<React.SetStateAction<boolean>>;\n handleToggleColumn: (key: string) => void;\n /** Imperative escape hatch: drop fit-column pins so they re-measure on the\n * next layout. For out-of-band content changes that don't flow through a new\n * `items` array or `columns` set (which reset automatically). */\n recalculateColumns: () => void;\n}\n\n/**\n * Table-mode column logic: visibility (controlled or uncontrolled, with\n * localStorage persistence and runtime reconciliation), the toggle popover, and\n * `fit`-column width measurement that pins one shared px track across the header\n * and every row grid so they stay aligned.\n */\nexport function useColumns<T>({\n columns,\n items,\n multiSelect,\n visibleColumnKeys,\n onVisibleColumnsChange,\n persistColumnsKey,\n showColumnToggle,\n userWidths,\n isFrozen,\n rootRef,\n startIndex,\n endIndex,\n containerHeight,\n containerWidth,\n}: UseColumnsArgs<T>): UseColumnsResult<T> {\n const isControlled = visibleColumnKeys !== undefined;\n const [toggleOpen, setToggleOpen] = useState(false);\n // Measured px widths for `fit` columns, keyed by column key. Pinning these\n // into the shared column template keeps the header and rows aligned (a raw\n // `fit-content` track resolves per-grid and drifts). See the effects below.\n const [fitWidths, setFitWidths] = useState<Record<string, number>>({});\n\n const [internalVisibleKeys, setInternalVisibleKeys] = useState<Set<string>>(() => {\n const persisted = loadPersistedColumns(persistColumnsKey);\n return new Set((columns ?? []).filter((c) => isColumnInitiallyVisible(c, persisted)).map((c) => c.key));\n });\n // The set of column keys the internal visibility state was last reconciled\n // against. The lazy initializer above only runs at mount, so without this a\n // list that mounts in list mode (no columns) and later switches to table mode\n // would keep an empty visible set and render no columns.\n const knownColumnKeysRef = useRef<Set<string>>(new Set((columns ?? []).map((c) => c.key)));\n\n // Re-derive internal visibility when the column set changes at runtime: new\n // columns get their saved/default visibility, removed columns drop out, and\n // existing columns keep whatever the user toggled them to. This is also what\n // applies persisted settings when a list switches from list mode to table\n // mode (columns absent at mount, supplied later).\n useEffect(() => {\n if (isControlled) return;\n const cols = columns ?? [];\n const currentKeys = new Set(cols.map((c) => c.key));\n const known = knownColumnKeysRef.current;\n let identical = currentKeys.size === known.size;\n if (identical)\n for (const k of currentKeys)\n if (!known.has(k)) {\n identical = false;\n break;\n }\n if (identical) return;\n knownColumnKeysRef.current = currentKeys;\n const persisted = loadPersistedColumns(persistColumnsKey);\n setInternalVisibleKeys((prev) => {\n const next = new Set<string>();\n for (const c of cols) {\n if (known.has(c.key)) {\n if (prev.has(c.key)) next.add(c.key); // preserve the current-session choice\n } else if (isColumnInitiallyVisible(c, persisted)) {\n next.add(c.key); // newly-added column: saved setting, else defaultHidden\n }\n }\n return next;\n });\n }, [columns, isControlled, persistColumnsKey]);\n\n // Persist visibility whenever it changes (uncontrolled mode only). Skip while\n // there are no columns, or the transient empty state during a list→table\n // switch before the reconcile effect above has filled in the visible set —\n // writing then would clobber the saved config with an empty set.\n useEffect(() => {\n if (isControlled || !persistColumnsKey || typeof window === 'undefined') return;\n const cols = columns ?? [];\n if (cols.length === 0 || internalVisibleKeys.size === 0) return;\n try {\n window.localStorage.setItem(\n COLUMN_STORAGE_PREFIX + persistColumnsKey,\n JSON.stringify({\n visible: [...internalVisibleKeys],\n known: cols.map((c) => c.key),\n widths: userWidths,\n } satisfies PersistedColumns),\n );\n } catch {\n // Storage full or unavailable — non-fatal, just don't persist.\n }\n }, [internalVisibleKeys, columns, isControlled, persistColumnsKey, userWidths]);\n\n // Locked columns can never be hidden — force them into the visible set even if\n // a controlled `visibleColumnKeys` or persisted state omits them. Only clone\n // (rather than mutate the state Set) when a locked key is actually missing;\n // in uncontrolled mode they're already present via isColumnInitiallyVisible.\n const baseVisible: Set<string> = isControlled ? new Set(visibleColumnKeys) : internalVisibleKeys;\n const lockedKeys = (columns ?? []).filter((c) => c.lockVisible).map((c) => c.key);\n const effectiveVisible: Set<string> = lockedKeys.some((k) => !baseVisible.has(k))\n ? new Set([...baseVisible, ...lockedKeys])\n : baseVisible;\n\n const hasColumns = !!columns?.length;\n const visibleColumns = hasColumns ? columns!.filter((c) => effectiveVisible.has(c.key)) : [];\n // A column counts as \"manually hidden\" only if it's default-visible yet\n // currently hidden — a defaultHidden column being hidden is its default\n // state, not a user choice, so it never contributes to the chip.\n const manuallyHiddenCount = hasColumns\n ? columns!.filter((c) => !c.defaultHidden && !effectiveVisible.has(c.key)).length\n : 0;\n const selectPrefix = multiSelect && hasColumns ? '40px ' : '';\n const columnTemplate = hasColumns\n ? `${selectPrefix}${isFrozen ? buildFrozenTemplate(visibleColumns) : buildColumnTemplate(visibleColumns, fitWidths)}`\n : undefined;\n // Hide the gear entirely when nothing is left to toggle (every column opts out).\n const shouldShowToggle = showColumnToggle !== false && hasColumns && columns!.some((c) => !c.hideFromToggle);\n\n // Sum of the tracks, so the header and body can stretch past the viewport and\n // the list scrolls horizontally instead of clipping. Kept as a `calc()` over\n // the same custom properties the tracks read, so a drag rewriting one of them\n // resizes the row canvas in the same layout pass.\n const widthVars: React.CSSProperties = {};\n if (isFrozen && hasColumns) {\n const parts = visibleColumns.map((c) => `var(${columnWidthVar(c.key)}, ${DEFAULT_FROZEN_WIDTH}px)`);\n if (multiSelect) parts.unshift('40px');\n if (shouldShowToggle) parts.push('32px');\n (widthVars as Record<string, string>)['--vl-total'] = `calc(${parts.join(' + ')})`;\n }\n\n // ── `fit` column width measurement ──────────────────────────────────────────\n const fitColumns = visibleColumns.filter((c) => c.width.type === 'fit');\n // A frozen layout is exact px and ignores the pins, so measuring would only\n // fight the user: `measureFitWidths` never shrinks a column, and every drag\n // narrower than the content would be undone on the next scroll frame.\n const hasFit = !isFrozen && fitColumns.length > 0;\n const fitColKey = fitColumns.map((c) => c.key).join('|');\n\n // Drop the measured pins when the data or the fit-column set changes, so the\n // measure effect below re-reads the true intrinsic width on the next pass —\n // this is what lets a column shrink (during scroll the effect only grows it,\n // to avoid jitter). Resetting state during render is React's recommended\n // pattern for \"reset on prop change\" and avoids a cascading effect render.\n const [fitReset, setFitReset] = useState<{ key: string; items: T[] }>({ key: fitColKey, items });\n if (fitReset.key !== fitColKey || fitReset.items !== items) {\n setFitReset({ key: fitColKey, items });\n if (Object.keys(fitWidths).length > 0) setFitWidths({});\n }\n\n // Measure every fit cell currently in the DOM (header + visible rows), keyed\n // by its `data-fit-key`, and grow each column's pin to the widest. Reading the\n // key off the DOM (rather than closing over `fitColumns`) keeps this a stable\n // callback the ResizeObserver below can reuse. `measureCellWidth` reports the\n // true content width even when the cell is pinned narrower, so a later pass\n // always recovers a column first measured while it was still empty.\n const measureFitWidths = useCallback(() => {\n const root = rootRef.current;\n if (!root) return;\n const maxByKey = new Map<string, number>();\n root.querySelectorAll('[data-fit-key]').forEach((node) => {\n const el = node as HTMLElement;\n const key = el.getAttribute('data-fit-key');\n if (!key) return;\n const w = measureCellWidth(el);\n if (w > (maxByKey.get(key) ?? 0)) maxByKey.set(key, w);\n });\n if (maxByKey.size === 0) return;\n setFitWidths((prev) => {\n let changed = false;\n const next = { ...prev };\n for (const [key, max] of maxByKey) {\n if (max <= 0) continue;\n // Cap at the viewport width so one oversized cell can't blow out layout.\n const pinned = Math.min(Math.ceil(max), root.clientWidth);\n if (pinned > (prev[key] ?? 0)) {\n next[key] = pinned;\n changed = true;\n }\n }\n return changed ? next : prev;\n });\n }, [rootRef]);\n\n // One ResizeObserver shared across all fit cells. It re-measures whenever a\n // cell's box changes — crucially when content first appears after mount (which\n // changes the cell's height even while its width is pinned), so a too-early or\n // empty-cell measure self-corrects instead of sticking. Its initial callback\n // also fires once after layout settles, covering route transitions and other\n // post-mount layout shifts without depending on font/rAF timing.\n const [fitObserver] = useState<ResizeObserver | null>(() =>\n typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(() => measureFitWidths()),\n );\n const observedRef = useRef<Set<Element>>(new Set());\n useEffect(\n () => () => {\n fitObserver?.disconnect();\n observedRef.current.clear();\n },\n [fitObserver],\n );\n\n // Measure synchronously (before paint, so a wider row scrolling in never shows\n // a clipped frame), then *diff* the observed set rather than re-observing every\n // cell. Re-observing fires a redundant ResizeObserver callback per node, and\n // `startIndex`/`endIndex` change every scroll frame — so observing only the\n // cells that entered (and dropping the ones that left) keeps stable, already\n // pinned cells from generating any observer traffic while scrolling. A newly\n // entered cell still fires exactly once, which is when we want to measure it.\n useLayoutEffect(() => {\n if (!hasFit) return;\n const root = rootRef.current;\n if (!root) return;\n measureFitWidths();\n if (!fitObserver) return;\n const current = new Set<Element>(root.querySelectorAll('[data-fit-key]'));\n const observed = observedRef.current;\n for (const el of observed)\n if (!current.has(el)) {\n fitObserver.unobserve(el);\n observed.delete(el);\n }\n for (const el of current)\n if (!observed.has(el)) {\n fitObserver.observe(el);\n observed.add(el);\n }\n }, [\n rootRef,\n hasFit,\n fitColKey,\n fitWidths,\n startIndex,\n endIndex,\n containerHeight,\n containerWidth,\n items,\n measureFitWidths,\n fitObserver,\n ]);\n\n // Cheap insurance: re-measure on the next two frames after mount / data /\n // fit-column changes, in case the icons (or the injected FontAwesome sizing\n // CSS) resolve a frame after the first synchronous pass. Safe and scoped —\n // measureFitWidths only ever grows a pin, and this runs on mount / data change\n // (not every scroll frame), so it keeps the diff-observe perf win.\n useEffect(() => {\n if (!hasFit) return;\n let raf2 = 0;\n const raf1 = requestAnimationFrame(() => {\n measureFitWidths();\n raf2 = requestAnimationFrame(() => measureFitWidths());\n });\n return () => {\n cancelAnimationFrame(raf1);\n cancelAnimationFrame(raf2);\n };\n }, [hasFit, fitColKey, items, measureFitWidths]);\n\n // Force a fresh fit-column measure regardless of current pins. Always installs\n // a new empty object so the measure layout effect re-runs even when nothing\n // was pinned (e.g. content changed while the column was still fit-content).\n const recalculateColumns = useCallback(() => setFitWidths({}), []);\n\n function handleToggleColumn(key: string) {\n // Locked columns can't be toggled off.\n if (columns?.find((c) => c.key === key)?.lockVisible) return;\n const next = new Set(effectiveVisible);\n if (next.has(key)) {\n if (next.size <= 1) return;\n next.delete(key);\n } else {\n next.add(key);\n }\n const nextArray = [...next];\n if (!isControlled) setInternalVisibleKeys(next);\n onVisibleColumnsChange?.(nextArray);\n }\n\n return {\n hasColumns,\n visibleColumns,\n columnTemplate,\n widthVars,\n shouldShowToggle,\n effectiveVisible,\n manuallyHiddenCount,\n toggleOpen,\n setToggleOpen,\n handleToggleColumn,\n recalculateColumns,\n };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{useRef as e,useState as t}from"react";function n(n){let[r,i]=t(0),a=e([]),o=Math.min(r,Math.max(0,n-1));o!==r&&i(o);function s(e){let t=Math.max(0,Math.min(e,n-1));i(t),a.current[t]?.focus()}function c(e){return{tabIndex:e===o?0:-1,ref:t=>{a.current[e]=t},onFocus:()=>i(e)}}function l(e,t){if(e.altKey||e.ctrlKey||e.metaKey)return!1;switch(e.key){case`ArrowRight`:s(t+1);break;case`ArrowLeft`:s(t-1);break;case`Home`:s(0);break;case`End`:s(n-1);break;default:return!1}return e.preventDefault(),e.stopPropagation(),!0}return{getStationProps:c,handleNavigationKey:l}}export{n as useHeaderNavigation};
1
+ "use client";import{useRef as e,useState as t}from"react";function n(n){let[r,i]=t(0),a=e([]),o=Math.min(r,Math.max(0,n-1));o!==r&&i(o);function s(e){let t=Math.max(0,Math.min(e,n-1));i(t),a.current[t]?.focus()}function c(e){return{tabIndex:e===o?0:-1,ref:t=>{a.current[e]=t},onFocus:()=>i(e)}}function l(e,t){if(e.altKey||e.ctrlKey||e.metaKey)return!1;switch(e.key){case`ArrowRight`:s(t+1);break;case`ArrowLeft`:s(t-1);break;case`Home`:s(0);break;case`End`:s(n-1);break;default:return!1}return e.preventDefault(),e.stopPropagation(),!0}return{getStationProps:c,handleNavigationKey:l}}export{n as useHeaderNavigation};
2
2
  //# sourceMappingURL=useHeaderNavigation.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useHeaderNavigation.mjs","names":[],"sources":["../../../../package/common/virtualList/useHeaderNavigation.ts"],"sourcesContent":["import React, { useRef, useState } from 'react';\n\ninterface StationProps {\n tabIndex: number;\n ref: (el: HTMLElement | null) => void;\n onFocus: () => void;\n}\n\ninterface UseHeaderNavigationResult {\n getStationProps: (index: number) => StationProps;\n /** True when the key moved the focus, so the caller stops handling it. */\n handleNavigationKey: (event: React.KeyboardEvent, index: number) => boolean;\n}\n\n/**\n * Roving tab stop across the header: the select-all cell, every column header,\n * and the column menu are stations, and arrow keys move between them.\n *\n * Without it each of those is its own tab stop, so a table with eight sortable,\n * resizable columns takes seventeen presses of Tab before the data. The stops\n * also belong together: they all act on the same header, which is exactly the\n * case the roving pattern exists for.\n */\nexport function useHeaderNavigation(stationCount: number): UseHeaderNavigationResult {\n const [activeIndex, setActiveIndex] = useState(0);\n const stationsRef = useRef<(HTMLElement | null)[]>([]);\n\n // Hiding a column can shrink the header past the active station. Clamping\n // during render rather than in an effect keeps the header from painting a\n // single frame with no tab stop at all.\n const active = Math.min(activeIndex, Math.max(0, stationCount - 1));\n if (active !== activeIndex) setActiveIndex(active);\n\n function focusStation(index: number) {\n const next = Math.max(0, Math.min(index, stationCount - 1));\n setActiveIndex(next);\n stationsRef.current[next]?.focus();\n }\n\n function getStationProps(index: number): StationProps {\n return {\n tabIndex: index === active ? 0 : -1,\n ref: (el: HTMLElement | null) => {\n stationsRef.current[index] = el;\n },\n // Also fires for a click, which keeps the tab stop where the user last\n // was rather than snapping back to the first column.\n onFocus: () => setActiveIndex(index),\n };\n }\n\n function handleNavigationKey(event: React.KeyboardEvent, index: number): boolean {\n // Alt is the resize modifier, so those combinations belong to the station.\n if (event.altKey || event.ctrlKey || event.metaKey) return false;\n switch (event.key) {\n case 'ArrowRight':\n focusStation(index + 1);\n break;\n case 'ArrowLeft':\n focusStation(index - 1);\n break;\n case 'Home':\n focusStation(0);\n break;\n case 'End':\n focusStation(stationCount - 1);\n break;\n default:\n return false;\n }\n event.preventDefault();\n event.stopPropagation();\n return true;\n }\n\n return { getStationProps, handleNavigationKey };\n}\n"],"mappings":"6CAuBA,SAAgB,EAAoB,EAAiD,CACnF,GAAM,CAAC,EAAa,GAAkB,EAAS,CAAC,EAC1C,EAAc,EAA+B,CAAC,CAAC,EAK/C,EAAS,KAAK,IAAI,EAAa,KAAK,IAAI,EAAG,EAAe,CAAC,CAAC,EAC9D,IAAW,GAAa,EAAe,CAAM,EAEjD,SAAS,EAAa,EAAe,CACnC,IAAM,EAAO,KAAK,IAAI,EAAG,KAAK,IAAI,EAAO,EAAe,CAAC,CAAC,EAC1D,EAAe,CAAI,EACnB,EAAY,QAAQ,EAAK,EAAE,MAAM,CACnC,CAEA,SAAS,EAAgB,EAA6B,CACpD,MAAO,CACL,SAAU,IAAU,EAAS,EAAI,GACjC,IAAM,GAA2B,CAC/B,EAAY,QAAQ,GAAS,CAC/B,EAGA,YAAe,EAAe,CAAK,CACrC,CACF,CAEA,SAAS,EAAoB,EAA4B,EAAwB,CAE/E,GAAI,EAAM,QAAU,EAAM,SAAW,EAAM,QAAS,MAAO,GAC3D,OAAQ,EAAM,IAAd,CACE,IAAK,aACH,EAAa,EAAQ,CAAC,EACtB,MACF,IAAK,YACH,EAAa,EAAQ,CAAC,EACtB,MACF,IAAK,OACH,EAAa,CAAC,EACd,MACF,IAAK,MACH,EAAa,EAAe,CAAC,EAC7B,MACF,QACE,MAAO,EACX,CAGA,OAFA,EAAM,eAAe,EACrB,EAAM,gBAAgB,EACf,EACT,CAEA,MAAO,CAAE,kBAAiB,qBAAoB,CAChD"}
1
+ {"version":3,"file":"useHeaderNavigation.mjs","names":[],"sources":["../../../../package/common/virtualList/useHeaderNavigation.ts"],"sourcesContent":["import React, { useRef, useState } from 'react';\n\ninterface StationProps {\n tabIndex: number;\n ref: (el: HTMLElement | null) => void;\n onFocus: () => void;\n}\n\ninterface UseHeaderNavigationResult {\n getStationProps: (index: number) => StationProps;\n /** True when the key moved the focus, so the caller stops handling it. */\n handleNavigationKey: (event: React.KeyboardEvent, index: number) => boolean;\n}\n\n/**\n * Roving tab stop across the header: the select-all cell, every column header,\n * and the column menu are stations, and arrow keys move between them.\n *\n * Without it each of those is its own tab stop, so a table with eight sortable,\n * resizable columns takes seventeen presses of Tab before the data. The stops\n * also belong together: they all act on the same header, which is exactly the\n * case the roving pattern exists for.\n */\nexport function useHeaderNavigation(stationCount: number): UseHeaderNavigationResult {\n const [activeIndex, setActiveIndex] = useState(0);\n const stationsRef = useRef<(HTMLElement | null)[]>([]);\n\n // Hiding a column can shrink the header past the active station. Clamping\n // during render rather than in an effect keeps the header from painting a\n // single frame with no tab stop at all.\n const active = Math.min(activeIndex, Math.max(0, stationCount - 1));\n if (active !== activeIndex) setActiveIndex(active);\n\n function focusStation(index: number) {\n const next = Math.max(0, Math.min(index, stationCount - 1));\n setActiveIndex(next);\n stationsRef.current[next]?.focus();\n }\n\n function getStationProps(index: number): StationProps {\n return {\n tabIndex: index === active ? 0 : -1,\n ref: (el: HTMLElement | null) => {\n stationsRef.current[index] = el;\n },\n // Also fires for a click, which keeps the tab stop where the user last\n // was rather than snapping back to the first column.\n onFocus: () => setActiveIndex(index),\n };\n }\n\n function handleNavigationKey(event: React.KeyboardEvent, index: number): boolean {\n // Alt is the resize modifier, so those combinations belong to the station.\n if (event.altKey || event.ctrlKey || event.metaKey) return false;\n switch (event.key) {\n case 'ArrowRight':\n focusStation(index + 1);\n break;\n case 'ArrowLeft':\n focusStation(index - 1);\n break;\n case 'Home':\n focusStation(0);\n break;\n case 'End':\n focusStation(stationCount - 1);\n break;\n default:\n return false;\n }\n event.preventDefault();\n event.stopPropagation();\n return true;\n }\n\n return { getStationProps, handleNavigationKey };\n}\n"],"mappings":"0DAuBA,SAAgB,EAAoB,EAAiD,CACnF,GAAM,CAAC,EAAa,GAAkB,EAAS,CAAC,EAC1C,EAAc,EAA+B,CAAC,CAAC,EAK/C,EAAS,KAAK,IAAI,EAAa,KAAK,IAAI,EAAG,EAAe,CAAC,CAAC,EAC9D,IAAW,GAAa,EAAe,CAAM,EAEjD,SAAS,EAAa,EAAe,CACnC,IAAM,EAAO,KAAK,IAAI,EAAG,KAAK,IAAI,EAAO,EAAe,CAAC,CAAC,EAC1D,EAAe,CAAI,EACnB,EAAY,QAAQ,EAAK,EAAE,MAAM,CACnC,CAEA,SAAS,EAAgB,EAA6B,CACpD,MAAO,CACL,SAAU,IAAU,EAAS,EAAI,GACjC,IAAM,GAA2B,CAC/B,EAAY,QAAQ,GAAS,CAC/B,EAGA,YAAe,EAAe,CAAK,CACrC,CACF,CAEA,SAAS,EAAoB,EAA4B,EAAwB,CAE/E,GAAI,EAAM,QAAU,EAAM,SAAW,EAAM,QAAS,MAAO,GAC3D,OAAQ,EAAM,IAAd,CACE,IAAK,aACH,EAAa,EAAQ,CAAC,EACtB,MACF,IAAK,YACH,EAAa,EAAQ,CAAC,EACtB,MACF,IAAK,OACH,EAAa,CAAC,EACd,MACF,IAAK,MACH,EAAa,EAAe,CAAC,EAC7B,MACF,QACE,MAAO,EACX,CAGA,OAFA,EAAM,eAAe,EACrB,EAAM,gBAAgB,EACf,EACT,CAEA,MAAO,CAAE,kBAAiB,qBAAoB,CAChD"}
@@ -1,2 +1,2 @@
1
- import e from"./virtualList.module.mjs";import{lastDescendantIndex as t,resolveReorderTarget as n,resolveTreeDropTarget as r}from"./virtualList.utils.mjs";import{useCallback as i,useEffect as a,useLayoutEffect as o,useRef as s,useState as c}from"react";function l({reorderable:l,treeReorder:u,onReorder:d,onTreeDrop:f,longPressDelay:ee,dragHandle:p,treeIndentPx:m,keys:h,depths:g,isGroupAt:_,rootRef:v,keysRef:y}){let b=s(null),[x,S]=c(null),[C,w]=c(null),T=s(null),E=s(d),D=s(f),O=s(u),k=s(g),A=s(_),j=s(!0),M=s(null),[N,te]=c(null),P=s(null),F=s(!1),I=s(null),L=s(0),R=s(0),z=s(null),B=s(!1),V=s(null),H=s(0),U=s(0),W=s(0),[G]=c(()=>typeof window<`u`&&typeof window.matchMedia==`function`&&window.matchMedia(`(pointer: coarse)`).matches);o(()=>{E.current=d,D.current=f,O.current=u,k.current=g,T.current=C,A.current=_});function K(e){G||M.current!==e&&(M.current=e,te(e))}function ne(e,t){t.buttons===0&&K(t.target.closest(`[data-drag-handle]`)?e:null)}function re(e){e.buttons===0&&K(null)}function ie(e,t){if(t.button!==0)return;let n=!!t.target.closest(`[data-drag-handle]`);j.current=n,n&&K(e)}function ae(e,t){if(p&&!j.current){t.preventDefault();return}b.current=e,S(e),u&&w(null)}function oe(e,n,i){let a=b.current;if(a==null)return null;let o=h.indexOf(a);if(o!==-1&&e>=o&&e<=t(o,g))return null;let s=r(n,i.top,i.height,_(e));return{key:h[e],position:s}}function se(e,t){t.preventDefault();let n=t.currentTarget.getBoundingClientRect(),r=oe(e,t.clientY,n);w(e=>e?.key===r?.key&&e?.position===r?.position?e:r)}function ce(){let e=b.current,t=T.current;e!=null&&t&&t.key!==e&&f?.(e,t)}function le(e){e.preventDefault(),ce(),w(null),b.current=null,S(null),K(null)}function ue(){w(null),b.current=null,S(null),K(null)}function de(e,t){t.preventDefault();let r=b.current;if(r==null)return;let i=h.indexOf(r),a=t.currentTarget.getBoundingClientRect(),o=n(i,e,t.clientY,a.top,a.height);o!=null&&d?.(i,o)}function fe(){b.current=null,S(null),K(null)}let q=i(e=>{let i=b.current,a=v.current;if(i==null||!a)return;let o=V.current?R.current-H.current+W.current/2:R.current,s=document.elementFromPoint(e,o),c=s&&a.contains(s)?s.closest(`[data-index]`):null;if(!c)return;let l=Number(c.dataset.index);if(Number.isNaN(l))return;let u=y.current.indexOf(i),d=c.getBoundingClientRect();if(O.current){let e=y.current,n=k.current;if(u!==-1&&l>=u&&l<=t(u,n)){w(null);return}let i=r(o,d.top,d.height,A.current(l)),a={key:e[l],position:i};w(e=>e?.key===a.key&&e?.position===a.position?e:a);return}let f=n(u,l,o,d.top,d.height);f!=null&&E.current?.(u,f)},[v,y]),J=i(()=>{let e=V.current;e&&(e.style.transform=`translate(${U.current}px, ${R.current-H.current}px)`)},[]),Y=i(()=>{let e=v.current;if(!e||!F.current){z.current=null;return}let t=e.getBoundingClientRect(),n=L.current,r=R.current,i=0;n>=t.left&&n<=t.right&&r>=t.top&&r<=t.bottom&&(r<t.top+48?i=-Math.min(18,Math.ceil((t.top+48-r)/3)):r>t.bottom-48&&(i=Math.min(18,Math.ceil((r-(t.bottom-48))/3)))),i!==0&&(e.scrollTop+=i,q(n)),z.current=requestAnimationFrame(Y)},[q,v]),X=i(()=>{if(P.current!=null&&(clearTimeout(P.current),P.current=null),window.removeEventListener(`touchmove`,Z),window.removeEventListener(`touchend`,X),window.removeEventListener(`touchcancel`,X),z.current!=null&&(cancelAnimationFrame(z.current),z.current=null),V.current&&=(V.current.remove(),null),document.body.style.touchAction=``,document.body.style.overscrollBehavior=``,F.current&&(B.current=!0,setTimeout(()=>{B.current=!1},350),O.current)){let e=b.current,t=T.current;e!=null&&t&&t.key!==e&&D.current?.(e,t)}w(null),F.current=!1,I.current=null,b.current=null,S(null)},[]),Z=i(e=>{let t=e.touches[0];if(t){if(L.current=t.clientX,R.current=t.clientY,!F.current){let e=I.current;e!=null&&Math.abs(t.clientY-e)>10&&P.current!=null&&(clearTimeout(P.current),P.current=null);return}e.cancelable&&e.preventDefault(),J(),q(t.clientX)}},[q,J]);function pe(e,t){if(!l&&!u||p&&!t.target.closest(`[data-drag-handle]`)||P.current!=null||F.current)return;let n=t.touches[0];n&&(I.current=n.clientY,L.current=n.clientX,R.current=n.clientY,window.addEventListener(`touchmove`,Z,{passive:!1}),window.addEventListener(`touchend`,X),window.addEventListener(`touchcancel`,X),P.current=window.setTimeout(()=>{P.current=null,F.current=!0,b.current=e,S(e),navigator.vibrate?.(10),document.body.style.touchAction=`none`,document.body.style.overscrollBehavior=`none`,me(e),z.current??=requestAnimationFrame(Y)},ee))}function me(t){let n=v.current;if(!n)return;let r=y.current.indexOf(t),i=n.querySelector(`[data-index="${r}"]`);if(!i)return;let a=i.getBoundingClientRect();H.current=R.current-a.top,U.current=a.left,W.current=a.height;let o=i.cloneNode(!0);o.removeAttribute(`data-index`),o.setAttribute(`data-drag-clone`,`true`),o.setAttribute(`aria-hidden`,`true`),o.classList.add(e.virtualListDragClone),Object.assign(o.style,{position:`fixed`,left:`0`,top:`0`,width:`${a.width}px`,height:`${a.height}px`,margin:`0`,opacity:`1`,pointerEvents:`none`,zIndex:`3`,background:`var(--background)`,boxShadow:`var(--card-shadow)`,borderRadius:`var(--default-border-radius)`}),n.appendChild(o),V.current=o,J()}a(()=>X,[X]);let Q=l||u,$=Q&&!G;function he(e,t){let n=u&&C?.key===t?C.position:void 0;return{reorderable:Q&&!p,mouseDragEnabled:$,draggable:$&&(!p||t===N)||void 0,isDragging:Q&&t===x,onMouseDown:Q&&p?e=>ie(t,e):void 0,onMouseOver:Q&&p?e=>ne(t,e):void 0,onMouseLeave:Q&&p?re:void 0,onDragStart:Q?e=>ae(t,e):void 0,onDragOver:u?t=>se(e,t):l?t=>de(e,t):void 0,onDragEnd:u?ue:l?fe:void 0,onDrop:u?le:void 0,onTouchStart:Q?e=>pe(t,e):void 0,dropPosition:n,dropIndentPx:n?(g[e]??0)*m:void 0}}function ge(){return B.current?(B.current=!1,!0):!1}return{draggingKey:x,dragEnabled:Q,getRowDragProps:he,consumeSuppressedClick:ge}}export{l as useRowDrag};
1
+ "use client";import e from"./virtualList.module.mjs";import{lastDescendantIndex as t,resolveReorderTarget as n,resolveTreeDropTarget as r}from"./virtualList.utils.mjs";import{useCallback as i,useEffect as a,useLayoutEffect as o,useRef as s,useState as c}from"react";function l({reorderable:l,treeReorder:u,onReorder:d,onTreeDrop:f,longPressDelay:ee,dragHandle:p,treeIndentPx:m,keys:h,depths:g,isGroupAt:_,rootRef:v,keysRef:y}){let b=s(null),[x,S]=c(null),[C,w]=c(null),T=s(null),E=s(d),D=s(f),O=s(u),k=s(g),A=s(_),j=s(!0),M=s(null),[N,te]=c(null),P=s(null),F=s(!1),I=s(null),L=s(0),R=s(0),z=s(null),B=s(!1),V=s(null),H=s(0),U=s(0),W=s(0),[G]=c(()=>typeof window<`u`&&typeof window.matchMedia==`function`&&window.matchMedia(`(pointer: coarse)`).matches);o(()=>{E.current=d,D.current=f,O.current=u,k.current=g,T.current=C,A.current=_});function K(e){G||M.current!==e&&(M.current=e,te(e))}function ne(e,t){t.buttons===0&&K(t.target.closest(`[data-drag-handle]`)?e:null)}function re(e){e.buttons===0&&K(null)}function ie(e,t){if(t.button!==0)return;let n=!!t.target.closest(`[data-drag-handle]`);j.current=n,n&&K(e)}function ae(e,t){if(p&&!j.current){t.preventDefault();return}b.current=e,S(e),u&&w(null)}function oe(e,n,i){let a=b.current;if(a==null)return null;let o=h.indexOf(a);if(o!==-1&&e>=o&&e<=t(o,g))return null;let s=r(n,i.top,i.height,_(e));return{key:h[e],position:s}}function se(e,t){t.preventDefault();let n=t.currentTarget.getBoundingClientRect(),r=oe(e,t.clientY,n);w(e=>e?.key===r?.key&&e?.position===r?.position?e:r)}function ce(){let e=b.current,t=T.current;e!=null&&t&&t.key!==e&&f?.(e,t)}function le(e){e.preventDefault(),ce(),w(null),b.current=null,S(null),K(null)}function ue(){w(null),b.current=null,S(null),K(null)}function de(e,t){t.preventDefault();let r=b.current;if(r==null)return;let i=h.indexOf(r),a=t.currentTarget.getBoundingClientRect(),o=n(i,e,t.clientY,a.top,a.height);o!=null&&d?.(i,o)}function fe(){b.current=null,S(null),K(null)}let q=i(e=>{let i=b.current,a=v.current;if(i==null||!a)return;let o=V.current?R.current-H.current+W.current/2:R.current,s=document.elementFromPoint(e,o),c=s&&a.contains(s)?s.closest(`[data-index]`):null;if(!c)return;let l=Number(c.dataset.index);if(Number.isNaN(l))return;let u=y.current.indexOf(i),d=c.getBoundingClientRect();if(O.current){let e=y.current,n=k.current;if(u!==-1&&l>=u&&l<=t(u,n)){w(null);return}let i=r(o,d.top,d.height,A.current(l)),a={key:e[l],position:i};w(e=>e?.key===a.key&&e?.position===a.position?e:a);return}let f=n(u,l,o,d.top,d.height);f!=null&&E.current?.(u,f)},[v,y]),J=i(()=>{let e=V.current;e&&(e.style.transform=`translate(${U.current}px, ${R.current-H.current}px)`)},[]),Y=i(()=>{let e=v.current;if(!e||!F.current){z.current=null;return}let t=e.getBoundingClientRect(),n=L.current,r=R.current,i=0;n>=t.left&&n<=t.right&&r>=t.top&&r<=t.bottom&&(r<t.top+48?i=-Math.min(18,Math.ceil((t.top+48-r)/3)):r>t.bottom-48&&(i=Math.min(18,Math.ceil((r-(t.bottom-48))/3)))),i!==0&&(e.scrollTop+=i,q(n)),z.current=requestAnimationFrame(Y)},[q,v]),X=i(()=>{if(P.current!=null&&(clearTimeout(P.current),P.current=null),window.removeEventListener(`touchmove`,Z),window.removeEventListener(`touchend`,X),window.removeEventListener(`touchcancel`,X),z.current!=null&&(cancelAnimationFrame(z.current),z.current=null),V.current&&=(V.current.remove(),null),document.body.style.touchAction=``,document.body.style.overscrollBehavior=``,F.current&&(B.current=!0,setTimeout(()=>{B.current=!1},350),O.current)){let e=b.current,t=T.current;e!=null&&t&&t.key!==e&&D.current?.(e,t)}w(null),F.current=!1,I.current=null,b.current=null,S(null)},[]),Z=i(e=>{let t=e.touches[0];if(t){if(L.current=t.clientX,R.current=t.clientY,!F.current){let e=I.current;e!=null&&Math.abs(t.clientY-e)>10&&P.current!=null&&(clearTimeout(P.current),P.current=null);return}e.cancelable&&e.preventDefault(),J(),q(t.clientX)}},[q,J]);function pe(e,t){if(!l&&!u||p&&!t.target.closest(`[data-drag-handle]`)||P.current!=null||F.current)return;let n=t.touches[0];n&&(I.current=n.clientY,L.current=n.clientX,R.current=n.clientY,window.addEventListener(`touchmove`,Z,{passive:!1}),window.addEventListener(`touchend`,X),window.addEventListener(`touchcancel`,X),P.current=window.setTimeout(()=>{P.current=null,F.current=!0,b.current=e,S(e),navigator.vibrate?.(10),document.body.style.touchAction=`none`,document.body.style.overscrollBehavior=`none`,me(e),z.current??=requestAnimationFrame(Y)},ee))}function me(t){let n=v.current;if(!n)return;let r=y.current.indexOf(t),i=n.querySelector(`[data-index="${r}"]`);if(!i)return;let a=i.getBoundingClientRect();H.current=R.current-a.top,U.current=a.left,W.current=a.height;let o=i.cloneNode(!0);o.removeAttribute(`data-index`),o.setAttribute(`data-drag-clone`,`true`),o.setAttribute(`aria-hidden`,`true`),o.classList.add(e.virtualListDragClone),Object.assign(o.style,{position:`fixed`,left:`0`,top:`0`,width:`${a.width}px`,height:`${a.height}px`,margin:`0`,opacity:`1`,pointerEvents:`none`,zIndex:`3`,background:`var(--background)`,boxShadow:`var(--card-shadow)`,borderRadius:`var(--default-border-radius)`}),n.appendChild(o),V.current=o,J()}a(()=>X,[X]);let Q=l||u,$=Q&&!G;function he(e,t){let n=u&&C?.key===t?C.position:void 0;return{reorderable:Q&&!p,mouseDragEnabled:$,draggable:$&&(!p||t===N)||void 0,isDragging:Q&&t===x,onMouseDown:Q&&p?e=>ie(t,e):void 0,onMouseOver:Q&&p?e=>ne(t,e):void 0,onMouseLeave:Q&&p?re:void 0,onDragStart:Q?e=>ae(t,e):void 0,onDragOver:u?t=>se(e,t):l?t=>de(e,t):void 0,onDragEnd:u?ue:l?fe:void 0,onDrop:u?le:void 0,onTouchStart:Q?e=>pe(t,e):void 0,dropPosition:n,dropIndentPx:n?(g[e]??0)*m:void 0}}function ge(){return B.current?(B.current=!1,!0):!1}return{draggingKey:x,dragEnabled:Q,getRowDragProps:he,consumeSuppressedClick:ge}}export{l as useRowDrag};
2
2
  //# sourceMappingURL=useRowDrag.mjs.map