@ahrowe/ui 0.35.0 → 0.37.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 (783) hide show
  1. package/README.md +102 -72
  2. package/dist/cjs-types/common/accordion/accordion.d.ts +4 -0
  3. package/dist/cjs-types/common/accordion/accordion.types.d.ts +21 -0
  4. package/dist/cjs-types/common/accordion/index.d.ts +2 -0
  5. package/dist/cjs-types/common/actionButtons/actionButtons.d.ts +2 -0
  6. package/dist/cjs-types/common/actionButtons/actionButtons.types.d.ts +34 -0
  7. package/dist/cjs-types/common/actionButtons/index.d.ts +2 -0
  8. package/dist/cjs-types/common/actionIcon/actionIcon.d.ts +4 -0
  9. package/dist/cjs-types/common/actionIcon/actionIcon.types.d.ts +15 -0
  10. package/dist/cjs-types/common/actionIcon/index.d.ts +2 -0
  11. package/dist/cjs-types/common/alert/alert.d.ts +4 -0
  12. package/dist/cjs-types/common/alert/alert.types.d.ts +30 -0
  13. package/dist/cjs-types/common/alert/index.d.ts +2 -0
  14. package/dist/cjs-types/common/animatedIcon/animatedIcon.d.ts +3 -0
  15. package/dist/cjs-types/common/animatedIcon/animatedIcon.types.d.ts +25 -0
  16. package/dist/cjs-types/common/animatedIcon/index.d.ts +2 -0
  17. package/dist/cjs-types/common/animatedLogo/animatedLogo.d.ts +4 -0
  18. package/dist/cjs-types/common/animatedLogo/animatedLogo.types.d.ts +35 -0
  19. package/dist/cjs-types/common/animatedLogo/index.d.ts +2 -0
  20. package/dist/cjs-types/common/animatedText/animatedText.d.ts +4 -0
  21. package/dist/cjs-types/common/animatedText/animatedText.types.d.ts +65 -0
  22. package/dist/cjs-types/common/animatedText/index.d.ts +2 -0
  23. package/dist/cjs-types/common/avatar/avatar.d.ts +4 -0
  24. package/dist/cjs-types/common/avatar/avatar.types.d.ts +26 -0
  25. package/dist/cjs-types/common/avatar/avatarGroup.d.ts +4 -0
  26. package/dist/cjs-types/common/avatar/index.d.ts +3 -0
  27. package/dist/cjs-types/common/badge/badge.d.ts +4 -0
  28. package/dist/cjs-types/common/badge/badge.types.d.ts +31 -0
  29. package/dist/cjs-types/common/badge/index.d.ts +2 -0
  30. package/dist/cjs-types/common/bodyEnd/bodyEnd.d.ts +4 -0
  31. package/dist/cjs-types/common/bodyEnd/bodyEnd.types.d.ts +4 -0
  32. package/dist/cjs-types/common/bodyEnd/index.d.ts +2 -0
  33. package/dist/cjs-types/common/breadcrumb/breadcrumb.d.ts +4 -0
  34. package/dist/cjs-types/common/breadcrumb/breadcrumb.types.d.ts +33 -0
  35. package/dist/cjs-types/common/breadcrumb/index.d.ts +2 -0
  36. package/dist/cjs-types/common/button/button.d.ts +9 -0
  37. package/dist/cjs-types/common/button/button.types.d.ts +42 -0
  38. package/dist/cjs-types/common/button/index.d.ts +2 -0
  39. package/dist/cjs-types/common/buttonGroup/buttonGroup.d.ts +4 -0
  40. package/dist/cjs-types/common/buttonGroup/buttonGroup.types.d.ts +12 -0
  41. package/dist/cjs-types/common/buttonGroup/index.d.ts +2 -0
  42. package/dist/cjs-types/common/card/Card.d.ts +4 -0
  43. package/dist/cjs-types/common/card/CardActions.d.ts +4 -0
  44. package/dist/cjs-types/common/card/CardContent.d.ts +4 -0
  45. package/dist/cjs-types/common/card/CardHeader.d.ts +4 -0
  46. package/dist/cjs-types/common/card/CardMedia.d.ts +4 -0
  47. package/dist/cjs-types/common/card/card.types.d.ts +55 -0
  48. package/dist/cjs-types/common/card/index.d.ts +6 -0
  49. package/dist/cjs-types/common/carousel/carousel.d.ts +4 -0
  50. package/dist/cjs-types/common/carousel/carousel.types.d.ts +35 -0
  51. package/dist/cjs-types/common/carousel/index.d.ts +2 -0
  52. package/dist/cjs-types/common/checkbox/checkbox.d.ts +4 -0
  53. package/dist/cjs-types/common/checkbox/checkbox.types.d.ts +27 -0
  54. package/dist/cjs-types/common/checkbox/index.d.ts +2 -0
  55. package/dist/cjs-types/common/chip/chip.d.ts +4 -0
  56. package/dist/cjs-types/common/chip/chip.types.d.ts +35 -0
  57. package/dist/cjs-types/common/chip/chipContainer.d.ts +4 -0
  58. package/dist/cjs-types/common/chip/index.d.ts +3 -0
  59. package/dist/cjs-types/common/colorPicker/colorPicker.d.ts +4 -0
  60. package/dist/cjs-types/common/colorPicker/colorPicker.types.d.ts +25 -0
  61. package/dist/cjs-types/common/colorPicker/index.d.ts +2 -0
  62. package/dist/cjs-types/common/colorPicker/toHex.d.ts +11 -0
  63. package/dist/cjs-types/common/configProvider/configProvider.d.ts +13 -0
  64. package/dist/cjs-types/common/configProvider/configProvider.types.d.ts +133 -0
  65. package/dist/cjs-types/common/configProvider/index.d.ts +6 -0
  66. package/dist/cjs-types/common/configProvider/presentation.types.d.ts +14 -0
  67. package/dist/cjs-types/common/configProvider/useComponentDefaults.d.ts +17 -0
  68. package/dist/cjs-types/common/configProvider/useLabels.d.ts +22 -0
  69. package/dist/cjs-types/common/configProvider/usePresentationDefault.d.ts +8 -0
  70. package/dist/cjs-types/common/confirmModal/confirmModal.d.ts +4 -0
  71. package/dist/cjs-types/common/confirmModal/confirmModal.types.d.ts +24 -0
  72. package/dist/cjs-types/common/confirmModal/index.d.ts +2 -0
  73. package/dist/cjs-types/common/datePicker/components/datePickerMonth/datePickerMonth.d.ts +2 -0
  74. package/dist/cjs-types/common/datePicker/components/datePickerMonth/datePickerMonth.types.d.ts +23 -0
  75. package/dist/cjs-types/common/datePicker/components/datePickerMonth/index.d.ts +1 -0
  76. package/dist/cjs-types/common/datePicker/dateFunctions.d.ts +44 -0
  77. package/dist/cjs-types/common/datePicker/datePicker.d.ts +3 -0
  78. package/dist/cjs-types/common/datePicker/datePicker.types.d.ts +60 -0
  79. package/dist/cjs-types/common/datePicker/index.d.ts +2 -0
  80. package/dist/cjs-types/common/divider/divider.d.ts +4 -0
  81. package/dist/cjs-types/common/divider/divider.types.d.ts +21 -0
  82. package/dist/cjs-types/common/divider/index.d.ts +2 -0
  83. package/dist/cjs-types/common/drawer/drawer.d.ts +4 -0
  84. package/dist/cjs-types/common/drawer/drawer.types.d.ts +15 -0
  85. package/dist/cjs-types/common/drawer/index.d.ts +2 -0
  86. package/dist/cjs-types/common/dropZone/dropZone.d.ts +4 -0
  87. package/dist/cjs-types/common/dropZone/dropZone.types.d.ts +90 -0
  88. package/dist/cjs-types/common/dropZone/index.d.ts +2 -0
  89. package/dist/cjs-types/common/dropdown/dropdown.d.ts +4 -0
  90. package/dist/cjs-types/common/dropdown/dropdown.types.d.ts +47 -0
  91. package/dist/cjs-types/common/dropdown/index.d.ts +2 -0
  92. package/dist/cjs-types/common/emptyState/emptyState.d.ts +3 -0
  93. package/dist/cjs-types/common/emptyState/emptyState.types.d.ts +20 -0
  94. package/dist/cjs-types/common/emptyState/index.d.ts +2 -0
  95. package/dist/cjs-types/common/errorBoundary/errorBoundary.d.ts +14 -0
  96. package/dist/cjs-types/common/errorBoundary/errorBoundary.types.d.ts +57 -0
  97. package/dist/cjs-types/common/errorBoundary/index.d.ts +2 -0
  98. package/dist/cjs-types/common/fab/components/fabBase/fabBase.d.ts +3 -0
  99. package/dist/cjs-types/common/fab/components/fabBase/fabBase.types.d.ts +12 -0
  100. package/dist/cjs-types/common/fab/components/fabBase/index.d.ts +1 -0
  101. package/dist/cjs-types/common/fab/fab.d.ts +3 -0
  102. package/dist/cjs-types/common/fab/fab.types.d.ts +22 -0
  103. package/dist/cjs-types/common/fab/index.d.ts +2 -0
  104. package/dist/cjs-types/common/flip/flip.d.ts +3 -0
  105. package/dist/cjs-types/common/flip/flip.types.d.ts +44 -0
  106. package/dist/cjs-types/common/flip/index.d.ts +2 -0
  107. package/dist/cjs-types/common/floorPlan/floorPlan.faces.d.ts +33 -0
  108. package/dist/cjs-types/common/floorPlan/floorPlan.fixtures.d.ts +35 -0
  109. package/dist/cjs-types/common/floorPlan/floorPlan.geometry.d.ts +111 -0
  110. package/dist/cjs-types/common/floorPlan/floorPlan.graph.d.ts +184 -0
  111. package/dist/cjs-types/common/floorPlan/floorPlan.hit.d.ts +26 -0
  112. package/dist/cjs-types/common/floorPlan/floorPlan.json.d.ts +23 -0
  113. package/dist/cjs-types/common/floorPlan/floorPlan.mesh.d.ts +36 -0
  114. package/dist/cjs-types/common/floorPlan/floorPlan.path.d.ts +59 -0
  115. package/dist/cjs-types/common/floorPlan/floorPlan.plan.d.ts +98 -0
  116. package/dist/cjs-types/common/floorPlan/floorPlan.rooms.d.ts +47 -0
  117. package/dist/cjs-types/common/floorPlan/floorPlan.snap.d.ts +101 -0
  118. package/dist/cjs-types/common/floorPlan/floorPlan.triangulate.d.ts +11 -0
  119. package/dist/cjs-types/common/floorPlan/floorPlan.types.d.ts +276 -0
  120. package/dist/cjs-types/common/floorPlan/index.d.ts +30 -0
  121. package/dist/cjs-types/common/floorPlan/legacySvg.d.ts +27 -0
  122. package/dist/cjs-types/common/hooks/index.d.ts +13 -0
  123. package/dist/cjs-types/common/hooks/useAnchorTracking.d.ts +40 -0
  124. package/dist/cjs-types/common/hooks/useCoarsePointer.d.ts +3 -0
  125. package/dist/cjs-types/common/hooks/useFocusBoundary.d.ts +20 -0
  126. package/dist/cjs-types/common/hooks/useHotkeys.d.ts +45 -0
  127. package/dist/cjs-types/common/hooks/useMediaQuery.d.ts +9 -0
  128. package/dist/cjs-types/common/hooks/useOverlay.d.ts +26 -0
  129. package/dist/cjs-types/common/hooks/useScrollEdges.d.ts +18 -0
  130. package/dist/cjs-types/common/hooks/useSheet.d.ts +19 -0
  131. package/dist/cjs-types/common/hooks/useSwipeDismiss.d.ts +37 -0
  132. package/dist/cjs-types/common/hooks/useVisualViewportSize.d.ts +13 -0
  133. package/dist/cjs-types/common/iconPicker/iconPicker.d.ts +3 -0
  134. package/dist/cjs-types/common/iconPicker/iconPicker.types.d.ts +23 -0
  135. package/dist/cjs-types/common/iconPicker/index.d.ts +2 -0
  136. package/dist/cjs-types/common/idleManager/idleManager.d.ts +3 -0
  137. package/dist/cjs-types/common/idleManager/idleManager.types.d.ts +8 -0
  138. package/dist/cjs-types/common/idleManager/index.d.ts +2 -0
  139. package/dist/cjs-types/common/infiniteBlock/useInfiniteScroll.d.ts +5 -0
  140. package/dist/cjs-types/common/input/index.d.ts +2 -0
  141. package/dist/cjs-types/common/input/input.d.ts +4 -0
  142. package/dist/cjs-types/common/input/input.types.d.ts +84 -0
  143. package/dist/cjs-types/common/inputDropdown/index.d.ts +2 -0
  144. package/dist/cjs-types/common/inputDropdown/inputDropdown.d.ts +3 -0
  145. package/dist/cjs-types/common/inputDropdown/inputDropdown.types.d.ts +36 -0
  146. package/dist/cjs-types/common/interactableDiv/index.d.ts +2 -0
  147. package/dist/cjs-types/common/interactableDiv/interactableDiv.d.ts +8 -0
  148. package/dist/cjs-types/common/kanbanBoard/KanbanBoard.d.ts +3 -0
  149. package/dist/cjs-types/common/kanbanBoard/KanbanColumn.d.ts +45 -0
  150. package/dist/cjs-types/common/kanbanBoard/KanbanItem.d.ts +3 -0
  151. package/dist/cjs-types/common/kanbanBoard/index.d.ts +3 -0
  152. package/dist/cjs-types/common/kanbanBoard/kanbanBoard.types.d.ts +129 -0
  153. package/dist/cjs-types/common/kanbanBoard/kanbanBoard.utils.d.ts +60 -0
  154. package/dist/cjs-types/common/klipyPicker/components/gifPreview/gifPreview.d.ts +3 -0
  155. package/dist/cjs-types/common/klipyPicker/components/gifPreview/gifPreview.types.d.ts +7 -0
  156. package/dist/cjs-types/common/klipyPicker/components/gifPreview/index.d.ts +1 -0
  157. package/dist/cjs-types/common/klipyPicker/components/gifView/gifView.d.ts +3 -0
  158. package/dist/cjs-types/common/klipyPicker/components/gifView/gifView.types.d.ts +4 -0
  159. package/dist/cjs-types/common/klipyPicker/components/gifView/index.d.ts +1 -0
  160. package/dist/cjs-types/common/klipyPicker/index.d.ts +2 -0
  161. package/dist/cjs-types/common/klipyPicker/klipyPicker.d.ts +3 -0
  162. package/dist/cjs-types/common/klipyPicker/klipyPicker.types.d.ts +15 -0
  163. package/dist/cjs-types/common/loading/index.d.ts +1 -0
  164. package/dist/cjs-types/common/loading/spinnerLoading/index.d.ts +2 -0
  165. package/dist/cjs-types/common/loading/spinnerLoading/spinnerLoading.d.ts +6 -0
  166. package/dist/cjs-types/common/maskedInput/index.d.ts +2 -0
  167. package/dist/cjs-types/common/maskedInput/mask.d.ts +48 -0
  168. package/dist/cjs-types/common/maskedInput/maskedInput.d.ts +13 -0
  169. package/dist/cjs-types/common/maskedInput/maskedInput.types.d.ts +38 -0
  170. package/dist/cjs-types/common/menu/index.d.ts +3 -0
  171. package/dist/cjs-types/common/menu/menu.d.ts +14 -0
  172. package/dist/cjs-types/common/menu/menu.types.d.ts +61 -0
  173. package/dist/cjs-types/common/menu/menuHotkeys.d.ts +20 -0
  174. package/dist/cjs-types/common/modal/index.d.ts +2 -0
  175. package/dist/cjs-types/common/modal/modal.d.ts +3 -0
  176. package/dist/cjs-types/common/modal/modal.types.d.ts +31 -0
  177. package/dist/cjs-types/common/multiSelect/index.d.ts +2 -0
  178. package/dist/cjs-types/common/multiSelect/multiSelect.d.ts +4 -0
  179. package/dist/cjs-types/common/multiSelect/multiSelect.types.d.ts +69 -0
  180. package/dist/cjs-types/common/numberInput/index.d.ts +3 -0
  181. package/dist/cjs-types/common/numberInput/numberInput.d.ts +5 -0
  182. package/dist/cjs-types/common/numberInput/numberInput.types.d.ts +76 -0
  183. package/dist/cjs-types/common/numberInput/useStepRepeat.d.ts +17 -0
  184. package/dist/cjs-types/common/optionPicker/index.d.ts +2 -0
  185. package/dist/cjs-types/common/optionPicker/optionPicker.d.ts +4 -0
  186. package/dist/cjs-types/common/optionPicker/optionPicker.types.d.ts +16 -0
  187. package/dist/cjs-types/common/otpInput/index.d.ts +2 -0
  188. package/dist/cjs-types/common/otpInput/otpInput.d.ts +4 -0
  189. package/dist/cjs-types/common/otpInput/otpInput.types.d.ts +60 -0
  190. package/dist/cjs-types/common/overscroll/index.d.ts +2 -0
  191. package/dist/cjs-types/common/overscroll/overscroll.d.ts +2 -0
  192. package/dist/cjs-types/common/overscroll/overscroll.types.d.ts +14 -0
  193. package/dist/cjs-types/common/pagination/index.d.ts +2 -0
  194. package/dist/cjs-types/common/pagination/pagination.d.ts +4 -0
  195. package/dist/cjs-types/common/pagination/pagination.types.d.ts +45 -0
  196. package/dist/cjs-types/common/planCanvas/index.d.ts +2 -0
  197. package/dist/cjs-types/common/planCanvas/planCanvas.d.ts +7 -0
  198. package/dist/cjs-types/common/planCanvas/planCanvas.types.d.ts +64 -0
  199. package/dist/cjs-types/common/popover/index.d.ts +2 -0
  200. package/dist/cjs-types/common/popover/popover.d.ts +3 -0
  201. package/dist/cjs-types/common/popover/popover.types.d.ts +94 -0
  202. package/dist/cjs-types/common/popover/usePopoverPosition.d.ts +45 -0
  203. package/dist/cjs-types/common/progressBar/index.d.ts +2 -0
  204. package/dist/cjs-types/common/progressBar/progressBar.d.ts +5 -0
  205. package/dist/cjs-types/common/progressBar/progressBar.types.d.ts +18 -0
  206. package/dist/cjs-types/common/radioGroup/index.d.ts +2 -0
  207. package/dist/cjs-types/common/radioGroup/radioGroup.d.ts +4 -0
  208. package/dist/cjs-types/common/radioGroup/radioGroup.types.d.ts +45 -0
  209. package/dist/cjs-types/common/rating/index.d.ts +2 -0
  210. package/dist/cjs-types/common/rating/rating.d.ts +4 -0
  211. package/dist/cjs-types/common/rating/rating.types.d.ts +19 -0
  212. package/dist/cjs-types/common/revealLens/index.d.ts +2 -0
  213. package/dist/cjs-types/common/revealLens/revealLens.d.ts +4 -0
  214. package/dist/cjs-types/common/revealLens/revealLens.types.d.ts +24 -0
  215. package/dist/cjs-types/common/ripple/index.d.ts +2 -0
  216. package/dist/cjs-types/common/ripple/ripple.d.ts +5 -0
  217. package/dist/cjs-types/common/ripple/ripple.types.d.ts +16 -0
  218. package/dist/cjs-types/common/roomDrawer/index.d.ts +2 -0
  219. package/dist/cjs-types/common/roomDrawer/roomDrawer.d.ts +3 -0
  220. package/dist/cjs-types/common/roomDrawer/roomDrawer.types.d.ts +308 -0
  221. package/dist/cjs-types/common/roomDrawer/usePlanHistory.d.ts +24 -0
  222. package/dist/cjs-types/common/roomViewer/index.d.ts +2 -0
  223. package/dist/cjs-types/common/roomViewer/roomViewer.d.ts +10 -0
  224. package/dist/cjs-types/common/roomViewer/roomViewer.types.d.ts +91 -0
  225. package/dist/cjs-types/common/scrollFade/index.d.ts +2 -0
  226. package/dist/cjs-types/common/scrollFade/scrollFade.d.ts +4 -0
  227. package/dist/cjs-types/common/scrollFade/scrollFade.types.d.ts +20 -0
  228. package/dist/cjs-types/common/scrollbarProvider/index.d.ts +2 -0
  229. package/dist/cjs-types/common/scrollbarProvider/scrollbarProvider.d.ts +7 -0
  230. package/dist/cjs-types/common/searchInput/index.d.ts +2 -0
  231. package/dist/cjs-types/common/searchInput/searchInput.d.ts +3 -0
  232. package/dist/cjs-types/common/searchInput/searchInput.types.d.ts +28 -0
  233. package/dist/cjs-types/common/sectionHeader/index.d.ts +2 -0
  234. package/dist/cjs-types/common/sectionHeader/sectionHeader.d.ts +4 -0
  235. package/dist/cjs-types/common/sectionHeader/sectionHeader.types.d.ts +27 -0
  236. package/dist/cjs-types/common/sheetBackdrop/index.d.ts +2 -0
  237. package/dist/cjs-types/common/sheetBackdrop/sheetBackdrop.d.ts +16 -0
  238. package/dist/cjs-types/common/sheetBackdrop/sheetBackdrop.types.d.ts +7 -0
  239. package/dist/cjs-types/common/skeleton/index.d.ts +2 -0
  240. package/dist/cjs-types/common/skeleton/skeleton.d.ts +4 -0
  241. package/dist/cjs-types/common/skeleton/skeleton.types.d.ts +22 -0
  242. package/dist/cjs-types/common/slider/index.d.ts +2 -0
  243. package/dist/cjs-types/common/slider/slider.d.ts +3 -0
  244. package/dist/cjs-types/common/slider/slider.types.d.ts +68 -0
  245. package/dist/cjs-types/common/splitButton/index.d.ts +2 -0
  246. package/dist/cjs-types/common/splitButton/splitButton.d.ts +3 -0
  247. package/dist/cjs-types/common/splitButton/splitButton.types.d.ts +35 -0
  248. package/dist/cjs-types/common/stepper/index.d.ts +2 -0
  249. package/dist/cjs-types/common/stepper/stepper.d.ts +3 -0
  250. package/dist/cjs-types/common/stepper/stepper.types.d.ts +77 -0
  251. package/dist/cjs-types/common/sticky/index.d.ts +1 -0
  252. package/dist/cjs-types/common/sticky/sticky.d.ts +3 -0
  253. package/dist/cjs-types/common/sticky/sticky.types.d.ts +37 -0
  254. package/dist/cjs-types/common/sticky/stickyStack.d.ts +51 -0
  255. package/dist/cjs-types/common/switch/index.d.ts +2 -0
  256. package/dist/cjs-types/common/switch/switch.d.ts +4 -0
  257. package/dist/cjs-types/common/switch/switch.types.d.ts +21 -0
  258. package/dist/cjs-types/common/tabHeader/index.d.ts +2 -0
  259. package/dist/cjs-types/common/tabHeader/tabHeader.d.ts +4 -0
  260. package/dist/cjs-types/common/tabHeader/tabHeader.types.d.ts +20 -0
  261. package/dist/cjs-types/common/textarea/index.d.ts +2 -0
  262. package/dist/cjs-types/common/textarea/textarea.d.ts +3 -0
  263. package/dist/cjs-types/common/textarea/textarea.types.d.ts +2 -0
  264. package/dist/cjs-types/common/themeProvider/defaultTheme.d.ts +7 -0
  265. package/dist/cjs-types/common/themeProvider/index.d.ts +4 -0
  266. package/dist/cjs-types/common/themeProvider/lightTheme.d.ts +13 -0
  267. package/dist/cjs-types/common/themeProvider/theme.types.d.ts +272 -0
  268. package/dist/cjs-types/common/themeProvider/themeProvider.d.ts +38 -0
  269. package/dist/cjs-types/common/themeProvider/themeVariablesContext.d.ts +11 -0
  270. package/dist/cjs-types/common/themeProvider/useTheme.d.ts +4 -0
  271. package/dist/cjs-types/common/tilt/index.d.ts +4 -0
  272. package/dist/cjs-types/common/tilt/tilt.d.ts +3 -0
  273. package/dist/cjs-types/common/tilt/tilt.types.d.ts +40 -0
  274. package/dist/cjs-types/common/tilt/tiltMath.d.ts +24 -0
  275. package/dist/cjs-types/common/tiltGroup/index.d.ts +3 -0
  276. package/dist/cjs-types/common/tiltGroup/tiltGroup.d.ts +6 -0
  277. package/dist/cjs-types/common/tiltGroup/tiltGroup.types.d.ts +16 -0
  278. package/dist/cjs-types/common/timeInput/components/clockDial/clockDial.d.ts +3 -0
  279. package/dist/cjs-types/common/timeInput/components/clockDial/clockDial.types.d.ts +24 -0
  280. package/dist/cjs-types/common/timeInput/components/clockDial/index.d.ts +1 -0
  281. package/dist/cjs-types/common/timeInput/index.d.ts +1 -0
  282. package/dist/cjs-types/common/timeInput/timeFunctions.d.ts +36 -0
  283. package/dist/cjs-types/common/timeInput/timeInput.d.ts +3 -0
  284. package/dist/cjs-types/common/timeInput/timeInput.types.d.ts +44 -0
  285. package/dist/cjs-types/common/timeline/index.d.ts +2 -0
  286. package/dist/cjs-types/common/timeline/timeline.d.ts +3 -0
  287. package/dist/cjs-types/common/timeline/timeline.types.d.ts +51 -0
  288. package/dist/cjs-types/common/timer/index.d.ts +2 -0
  289. package/dist/cjs-types/common/timer/timer.chime.d.ts +1 -0
  290. package/dist/cjs-types/common/timer/timer.d.ts +3 -0
  291. package/dist/cjs-types/common/timer/timer.types.d.ts +110 -0
  292. package/dist/cjs-types/common/toast/index.d.ts +3 -0
  293. package/dist/cjs-types/common/toast/toast.d.ts +11 -0
  294. package/dist/cjs-types/common/toast/toast.types.d.ts +50 -0
  295. package/dist/cjs-types/common/toast/toastProvider.d.ts +8 -0
  296. package/dist/cjs-types/common/toast/toastService.d.ts +7 -0
  297. package/dist/cjs-types/common/tooltip/index.d.ts +2 -0
  298. package/dist/cjs-types/common/tooltip/tooltip.d.ts +3 -0
  299. package/dist/cjs-types/common/tooltip/tooltip.types.d.ts +17 -0
  300. package/dist/cjs-types/common/tree/flattenTree.d.ts +3 -0
  301. package/dist/cjs-types/common/tree/index.d.ts +3 -0
  302. package/dist/cjs-types/common/tree/tree.d.ts +4 -0
  303. package/dist/cjs-types/common/tree/tree.types.d.ts +67 -0
  304. package/dist/cjs-types/common/types/actions.types.d.ts +7 -0
  305. package/dist/cjs-types/common/types/baseProps.types.d.ts +29 -0
  306. package/dist/cjs-types/common/types/icon.types.d.ts +17 -0
  307. package/dist/cjs-types/common/types/slots.types.d.ts +4 -0
  308. package/dist/cjs-types/common/utils/activationKey.d.ts +9 -0
  309. package/dist/cjs-types/common/utils/interactiveTarget.d.ts +7 -0
  310. package/dist/cjs-types/common/utils/listNavigation.d.ts +49 -0
  311. package/dist/cjs-types/common/utils/mergeRefs.d.ts +12 -0
  312. package/dist/cjs-types/common/utils/renderIcon.d.ts +29 -0
  313. package/dist/cjs-types/common/utils/scrollAncestors.d.ts +12 -0
  314. package/dist/cjs-types/common/utils/visualViewport.d.ts +7 -0
  315. package/dist/cjs-types/common/virtualList/index.d.ts +2 -0
  316. package/dist/cjs-types/common/virtualList/scroller.d.ts +33 -0
  317. package/dist/cjs-types/common/virtualList/useColumnResize.d.ts +59 -0
  318. package/dist/cjs-types/common/virtualList/useColumns.d.ts +52 -0
  319. package/dist/cjs-types/common/virtualList/useHeaderNavigation.d.ts +22 -0
  320. package/dist/cjs-types/common/virtualList/useRowDrag.d.ts +63 -0
  321. package/dist/cjs-types/common/virtualList/useRowNavigation.d.ts +60 -0
  322. package/dist/cjs-types/common/virtualList/useSelection.d.ts +24 -0
  323. package/dist/cjs-types/common/virtualList/useSorting.d.ts +26 -0
  324. package/dist/cjs-types/common/virtualList/useVirtualWindow.d.ts +55 -0
  325. package/dist/cjs-types/common/virtualList/virtualList.d.ts +5 -0
  326. package/dist/cjs-types/common/virtualList/virtualList.types.d.ts +357 -0
  327. package/dist/cjs-types/common/virtualList/virtualList.utils.d.ts +126 -0
  328. package/dist/cjs-types/common/virtualList/virtualListHeader.d.ts +35 -0
  329. package/dist/cjs-types/common/virtualList/virtualRow.d.ts +62 -0
  330. package/dist/cjs-types/common/wizard/index.d.ts +1 -0
  331. package/dist/cjs-types/common/wizard/wizard.d.ts +3 -0
  332. package/dist/cjs-types/common/wizard/wizard.types.d.ts +12 -0
  333. package/dist/cjs-types/hooks/useWindowSize.d.ts +6 -0
  334. package/dist/cjs-types/index.d.ts +155 -0
  335. package/dist/cjs-types/package.json +3 -0
  336. package/dist/cjs-types/services/formValidation/FormValidatorGroupWithForm.d.ts +18 -0
  337. package/dist/cjs-types/services/formValidation/index.d.ts +5 -0
  338. package/dist/cjs-types/services/formValidation/useFormValidatorGroup.d.ts +10 -0
  339. package/dist/cjs-types/services/formValidation/validatableComponent.d.ts +36 -0
  340. package/dist/cjs-types/services/klipy.d.ts +36 -0
  341. package/dist/cjs-types/services/localization.d.ts +3 -0
  342. package/dist/esm/common/carousel/carousel.mjs +1 -1
  343. package/dist/esm/common/carousel/carousel.mjs.map +1 -1
  344. package/dist/esm/common/carousel/carousel.module.mjs.map +1 -1
  345. package/dist/esm/common/confirmModal/confirmModal.mjs +1 -1
  346. package/dist/esm/common/confirmModal/confirmModal.mjs.map +1 -1
  347. package/dist/esm/common/datePicker/datePicker.mjs +1 -1
  348. package/dist/esm/common/datePicker/datePicker.mjs.map +1 -1
  349. package/dist/esm/common/drawer/drawer.module.mjs.map +1 -1
  350. package/dist/esm/common/dropdown/dropdown.mjs +1 -1
  351. package/dist/esm/common/dropdown/dropdown.mjs.map +1 -1
  352. package/dist/esm/common/dropdown/dropdown.module.mjs +1 -1
  353. package/dist/esm/common/dropdown/dropdown.module.mjs.map +1 -1
  354. package/dist/esm/common/hooks/useHotkeys.mjs +2 -0
  355. package/dist/esm/common/hooks/useHotkeys.mjs.map +1 -0
  356. package/dist/esm/common/hooks/useScrollEdges.mjs +2 -0
  357. package/dist/esm/common/hooks/useScrollEdges.mjs.map +1 -0
  358. package/dist/esm/common/hooks/useSwipeDismiss.mjs +1 -1
  359. package/dist/esm/common/hooks/useSwipeDismiss.mjs.map +1 -1
  360. package/dist/esm/common/infiniteBlock/useInfiniteScroll.mjs +2 -0
  361. package/dist/esm/common/infiniteBlock/useInfiniteScroll.mjs.map +1 -0
  362. package/dist/esm/common/input/input.mjs +1 -1
  363. package/dist/esm/common/input/input.mjs.map +1 -1
  364. package/dist/esm/common/input/input.module.mjs +1 -1
  365. package/dist/esm/common/input/input.module.mjs.map +1 -1
  366. package/dist/esm/common/inputDropdown/inputDropdown.mjs +1 -1
  367. package/dist/esm/common/inputDropdown/inputDropdown.mjs.map +1 -1
  368. package/dist/esm/common/interactableDiv/interactableDiv.mjs +1 -1
  369. package/dist/esm/common/interactableDiv/interactableDiv.mjs.map +1 -1
  370. package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.module.mjs.map +1 -1
  371. package/dist/esm/common/klipyPicker/components/gifView/gifView.module.mjs.map +1 -1
  372. package/dist/esm/common/maskedInput/mask.mjs +2 -0
  373. package/dist/esm/common/maskedInput/mask.mjs.map +1 -0
  374. package/dist/esm/common/maskedInput/maskedInput.mjs +2 -0
  375. package/dist/esm/common/maskedInput/maskedInput.mjs.map +1 -0
  376. package/dist/esm/common/menu/menu.mjs +1 -1
  377. package/dist/esm/common/menu/menu.mjs.map +1 -1
  378. package/dist/esm/common/menu/menu.types.mjs.map +1 -1
  379. package/dist/esm/common/menu/menuHotkeys.mjs +2 -0
  380. package/dist/esm/common/menu/menuHotkeys.mjs.map +1 -0
  381. package/dist/esm/common/modal/modal.mjs +1 -1
  382. package/dist/esm/common/modal/modal.mjs.map +1 -1
  383. package/dist/esm/common/modal/modal.module.mjs +1 -1
  384. package/dist/esm/common/modal/modal.module.mjs.map +1 -1
  385. package/dist/esm/common/multiSelect/multiSelect.mjs +1 -1
  386. package/dist/esm/common/multiSelect/multiSelect.mjs.map +1 -1
  387. package/dist/esm/common/multiSelect/multiSelect.module.mjs +1 -1
  388. package/dist/esm/common/multiSelect/multiSelect.module.mjs.map +1 -1
  389. package/dist/esm/common/otpInput/otpInput.module.mjs.map +1 -1
  390. package/dist/esm/common/popover/usePopoverPosition.mjs +1 -1
  391. package/dist/esm/common/popover/usePopoverPosition.mjs.map +1 -1
  392. package/dist/esm/common/radioGroup/radioGroup.types.mjs.map +1 -1
  393. package/dist/esm/common/rating/rating.module.mjs.map +1 -1
  394. package/dist/esm/common/ripple/ripple.mjs +1 -1
  395. package/dist/esm/common/ripple/ripple.mjs.map +1 -1
  396. package/dist/esm/common/scrollFade/scrollFade.mjs +2 -0
  397. package/dist/esm/common/scrollFade/scrollFade.mjs.map +1 -0
  398. package/dist/esm/common/scrollFade/scrollFade.module.mjs +2 -0
  399. package/dist/esm/common/scrollFade/scrollFade.module.mjs.map +1 -0
  400. package/dist/esm/common/scrollFade/scrollFade.types.mjs +2 -0
  401. package/dist/esm/common/scrollFade/scrollFade.types.mjs.map +1 -0
  402. package/dist/esm/common/sticky/sticky.mjs +1 -1
  403. package/dist/esm/common/sticky/sticky.mjs.map +1 -1
  404. package/dist/esm/common/sticky/stickyStack.mjs +1 -1
  405. package/dist/esm/common/sticky/stickyStack.mjs.map +1 -1
  406. package/dist/esm/common/styles/scrollFade.module.mjs +2 -0
  407. package/dist/esm/common/styles/scrollFade.module.mjs.map +1 -0
  408. package/dist/esm/common/styles/sheet.module.mjs.map +1 -1
  409. package/dist/esm/common/timeInput/timeInput.mjs +1 -1
  410. package/dist/esm/common/timeInput/timeInput.mjs.map +1 -1
  411. package/dist/esm/common/utils/interactiveTarget.mjs +2 -0
  412. package/dist/esm/common/utils/interactiveTarget.mjs.map +1 -0
  413. package/dist/esm/common/utils/listNavigation.mjs +2 -0
  414. package/dist/esm/common/utils/listNavigation.mjs.map +1 -0
  415. package/dist/esm/common/utils/scrollAncestors.mjs +1 -1
  416. package/dist/esm/common/utils/scrollAncestors.mjs.map +1 -1
  417. package/dist/esm/common/virtualList/scroller.mjs +2 -0
  418. package/dist/esm/common/virtualList/scroller.mjs.map +1 -0
  419. package/dist/esm/common/virtualList/useRowDrag.mjs +1 -1
  420. package/dist/esm/common/virtualList/useRowDrag.mjs.map +1 -1
  421. package/dist/esm/common/virtualList/useRowNavigation.mjs +1 -1
  422. package/dist/esm/common/virtualList/useRowNavigation.mjs.map +1 -1
  423. package/dist/esm/common/virtualList/useVirtualWindow.mjs +1 -1
  424. package/dist/esm/common/virtualList/useVirtualWindow.mjs.map +1 -1
  425. package/dist/esm/common/virtualList/virtualList.mjs +1 -1
  426. package/dist/esm/common/virtualList/virtualList.mjs.map +1 -1
  427. package/dist/esm/common/virtualList/virtualList.module.mjs +1 -1
  428. package/dist/esm/common/virtualList/virtualList.module.mjs.map +1 -1
  429. package/dist/esm/common/wizard/wizard.module.mjs.map +1 -1
  430. package/dist/esm/index.mjs +1 -1
  431. package/dist/esm/og.png +0 -0
  432. package/dist/index.cjs +3 -3
  433. package/dist/index.cjs.map +1 -1
  434. package/dist/mcp.js +341 -56
  435. package/dist/og.png +0 -0
  436. package/dist/style.css +1 -1
  437. package/dist/types/common/accordion/accordion.d.ts +1 -1
  438. package/dist/types/common/accordion/accordion.types.d.ts +1 -1
  439. package/dist/types/common/accordion/index.d.ts +2 -2
  440. package/dist/types/common/actionButtons/actionButtons.d.ts +1 -1
  441. package/dist/types/common/actionButtons/actionButtons.types.d.ts +3 -3
  442. package/dist/types/common/actionButtons/index.d.ts +2 -2
  443. package/dist/types/common/actionIcon/actionIcon.d.ts +1 -1
  444. package/dist/types/common/actionIcon/actionIcon.types.d.ts +2 -2
  445. package/dist/types/common/actionIcon/index.d.ts +2 -2
  446. package/dist/types/common/alert/alert.d.ts +1 -1
  447. package/dist/types/common/alert/alert.types.d.ts +2 -2
  448. package/dist/types/common/alert/index.d.ts +2 -2
  449. package/dist/types/common/animatedIcon/animatedIcon.d.ts +1 -1
  450. package/dist/types/common/animatedIcon/animatedIcon.types.d.ts +1 -1
  451. package/dist/types/common/animatedIcon/index.d.ts +2 -2
  452. package/dist/types/common/animatedLogo/animatedLogo.d.ts +1 -1
  453. package/dist/types/common/animatedLogo/animatedLogo.types.d.ts +1 -1
  454. package/dist/types/common/animatedLogo/index.d.ts +2 -2
  455. package/dist/types/common/animatedText/animatedText.d.ts +1 -1
  456. package/dist/types/common/animatedText/animatedText.types.d.ts +1 -1
  457. package/dist/types/common/animatedText/index.d.ts +2 -2
  458. package/dist/types/common/avatar/avatar.d.ts +1 -1
  459. package/dist/types/common/avatar/avatar.types.d.ts +2 -2
  460. package/dist/types/common/avatar/avatarGroup.d.ts +1 -1
  461. package/dist/types/common/avatar/index.d.ts +3 -3
  462. package/dist/types/common/badge/badge.d.ts +1 -1
  463. package/dist/types/common/badge/badge.types.d.ts +1 -1
  464. package/dist/types/common/badge/index.d.ts +2 -2
  465. package/dist/types/common/bodyEnd/bodyEnd.d.ts +1 -1
  466. package/dist/types/common/bodyEnd/index.d.ts +2 -2
  467. package/dist/types/common/breadcrumb/breadcrumb.d.ts +1 -1
  468. package/dist/types/common/breadcrumb/breadcrumb.types.d.ts +2 -2
  469. package/dist/types/common/breadcrumb/index.d.ts +2 -2
  470. package/dist/types/common/button/button.d.ts +1 -1
  471. package/dist/types/common/button/button.types.d.ts +2 -2
  472. package/dist/types/common/button/index.d.ts +2 -2
  473. package/dist/types/common/buttonGroup/buttonGroup.d.ts +1 -1
  474. package/dist/types/common/buttonGroup/buttonGroup.types.d.ts +1 -1
  475. package/dist/types/common/buttonGroup/index.d.ts +2 -2
  476. package/dist/types/common/card/Card.d.ts +1 -1
  477. package/dist/types/common/card/CardActions.d.ts +1 -1
  478. package/dist/types/common/card/CardContent.d.ts +1 -1
  479. package/dist/types/common/card/CardHeader.d.ts +1 -1
  480. package/dist/types/common/card/CardMedia.d.ts +1 -1
  481. package/dist/types/common/card/card.types.d.ts +3 -3
  482. package/dist/types/common/card/index.d.ts +6 -6
  483. package/dist/types/common/carousel/carousel.d.ts +1 -1
  484. package/dist/types/common/carousel/carousel.types.d.ts +1 -1
  485. package/dist/types/common/carousel/index.d.ts +2 -2
  486. package/dist/types/common/checkbox/checkbox.d.ts +1 -1
  487. package/dist/types/common/checkbox/checkbox.types.d.ts +2 -2
  488. package/dist/types/common/checkbox/index.d.ts +2 -2
  489. package/dist/types/common/chip/chip.d.ts +1 -1
  490. package/dist/types/common/chip/chip.types.d.ts +1 -1
  491. package/dist/types/common/chip/chipContainer.d.ts +1 -1
  492. package/dist/types/common/chip/index.d.ts +3 -3
  493. package/dist/types/common/colorPicker/colorPicker.d.ts +1 -1
  494. package/dist/types/common/colorPicker/colorPicker.types.d.ts +1 -1
  495. package/dist/types/common/colorPicker/index.d.ts +2 -2
  496. package/dist/types/common/configProvider/configProvider.d.ts +2 -2
  497. package/dist/types/common/configProvider/configProvider.types.d.ts +44 -44
  498. package/dist/types/common/configProvider/index.d.ts +6 -6
  499. package/dist/types/common/configProvider/useComponentDefaults.d.ts +1 -1
  500. package/dist/types/common/configProvider/useLabels.d.ts +1 -1
  501. package/dist/types/common/configProvider/usePresentationDefault.d.ts +1 -1
  502. package/dist/types/common/confirmModal/confirmModal.d.ts +1 -1
  503. package/dist/types/common/confirmModal/confirmModal.types.d.ts +2 -2
  504. package/dist/types/common/confirmModal/index.d.ts +2 -2
  505. package/dist/types/common/datePicker/components/datePickerMonth/datePickerMonth.d.ts +1 -1
  506. package/dist/types/common/datePicker/components/datePickerMonth/index.d.ts +1 -1
  507. package/dist/types/common/datePicker/datePicker.d.ts +1 -1
  508. package/dist/types/common/datePicker/datePicker.types.d.ts +2 -2
  509. package/dist/types/common/datePicker/index.d.ts +2 -2
  510. package/dist/types/common/divider/divider.d.ts +1 -1
  511. package/dist/types/common/divider/divider.types.d.ts +1 -1
  512. package/dist/types/common/divider/index.d.ts +2 -2
  513. package/dist/types/common/drawer/drawer.d.ts +1 -1
  514. package/dist/types/common/drawer/drawer.types.d.ts +1 -1
  515. package/dist/types/common/drawer/index.d.ts +2 -2
  516. package/dist/types/common/dropZone/dropZone.d.ts +1 -1
  517. package/dist/types/common/dropZone/dropZone.types.d.ts +1 -1
  518. package/dist/types/common/dropZone/index.d.ts +2 -2
  519. package/dist/types/common/dropdown/dropdown.d.ts +1 -1
  520. package/dist/types/common/dropdown/dropdown.types.d.ts +3 -3
  521. package/dist/types/common/dropdown/index.d.ts +2 -2
  522. package/dist/types/common/emptyState/emptyState.d.ts +1 -1
  523. package/dist/types/common/emptyState/emptyState.types.d.ts +2 -2
  524. package/dist/types/common/emptyState/index.d.ts +2 -2
  525. package/dist/types/common/errorBoundary/errorBoundary.d.ts +1 -1
  526. package/dist/types/common/errorBoundary/errorBoundary.types.d.ts +1 -1
  527. package/dist/types/common/errorBoundary/index.d.ts +2 -2
  528. package/dist/types/common/fab/components/fabBase/fabBase.d.ts +1 -1
  529. package/dist/types/common/fab/components/fabBase/fabBase.types.d.ts +1 -1
  530. package/dist/types/common/fab/components/fabBase/index.d.ts +1 -1
  531. package/dist/types/common/fab/fab.d.ts +1 -1
  532. package/dist/types/common/fab/fab.types.d.ts +2 -2
  533. package/dist/types/common/fab/index.d.ts +2 -2
  534. package/dist/types/common/flip/flip.d.ts +1 -1
  535. package/dist/types/common/flip/flip.types.d.ts +1 -1
  536. package/dist/types/common/flip/index.d.ts +2 -2
  537. package/dist/types/common/floorPlan/floorPlan.faces.d.ts +2 -2
  538. package/dist/types/common/floorPlan/floorPlan.fixtures.d.ts +1 -1
  539. package/dist/types/common/floorPlan/floorPlan.geometry.d.ts +1 -1
  540. package/dist/types/common/floorPlan/floorPlan.graph.d.ts +1 -1
  541. package/dist/types/common/floorPlan/floorPlan.hit.d.ts +1 -1
  542. package/dist/types/common/floorPlan/floorPlan.json.d.ts +1 -1
  543. package/dist/types/common/floorPlan/floorPlan.mesh.d.ts +1 -1
  544. package/dist/types/common/floorPlan/floorPlan.path.d.ts +1 -1
  545. package/dist/types/common/floorPlan/floorPlan.plan.d.ts +1 -1
  546. package/dist/types/common/floorPlan/floorPlan.rooms.d.ts +1 -1
  547. package/dist/types/common/floorPlan/floorPlan.snap.d.ts +1 -1
  548. package/dist/types/common/floorPlan/floorPlan.triangulate.d.ts +1 -1
  549. package/dist/types/common/floorPlan/index.d.ts +22 -22
  550. package/dist/types/common/floorPlan/legacySvg.d.ts +2 -2
  551. package/dist/types/common/hooks/index.d.ts +13 -0
  552. package/dist/types/common/hooks/useHotkeys.d.ts +45 -0
  553. package/dist/types/common/hooks/useScrollEdges.d.ts +18 -0
  554. package/dist/types/common/hooks/useSheet.d.ts +1 -1
  555. package/dist/types/common/hooks/useSwipeDismiss.d.ts +6 -2
  556. package/dist/types/common/iconPicker/iconPicker.d.ts +1 -1
  557. package/dist/types/common/iconPicker/iconPicker.types.d.ts +2 -2
  558. package/dist/types/common/iconPicker/index.d.ts +2 -1
  559. package/dist/types/common/idleManager/idleManager.d.ts +1 -1
  560. package/dist/types/common/idleManager/index.d.ts +2 -1
  561. package/dist/types/common/infiniteBlock/useInfiniteScroll.d.ts +5 -0
  562. package/dist/types/common/input/index.d.ts +2 -2
  563. package/dist/types/common/input/input.d.ts +1 -1
  564. package/dist/types/common/input/input.types.d.ts +2 -2
  565. package/dist/types/common/inputDropdown/index.d.ts +2 -1
  566. package/dist/types/common/inputDropdown/inputDropdown.d.ts +1 -1
  567. package/dist/types/common/inputDropdown/inputDropdown.types.d.ts +2 -2
  568. package/dist/types/common/interactableDiv/index.d.ts +1 -1
  569. package/dist/types/common/interactableDiv/interactableDiv.d.ts +1 -1
  570. package/dist/types/common/kanbanBoard/KanbanBoard.d.ts +1 -1
  571. package/dist/types/common/kanbanBoard/KanbanColumn.d.ts +1 -1
  572. package/dist/types/common/kanbanBoard/KanbanItem.d.ts +1 -1
  573. package/dist/types/common/kanbanBoard/index.d.ts +3 -3
  574. package/dist/types/common/kanbanBoard/kanbanBoard.types.d.ts +1 -1
  575. package/dist/types/common/kanbanBoard/kanbanBoard.utils.d.ts +1 -1
  576. package/dist/types/common/klipyPicker/components/gifPreview/gifPreview.d.ts +1 -1
  577. package/dist/types/common/klipyPicker/components/gifPreview/gifPreview.types.d.ts +1 -1
  578. package/dist/types/common/klipyPicker/components/gifPreview/index.d.ts +1 -1
  579. package/dist/types/common/klipyPicker/components/gifView/gifView.d.ts +1 -1
  580. package/dist/types/common/klipyPicker/components/gifView/index.d.ts +1 -1
  581. package/dist/types/common/klipyPicker/index.d.ts +2 -2
  582. package/dist/types/common/klipyPicker/klipyPicker.d.ts +1 -1
  583. package/dist/types/common/klipyPicker/klipyPicker.types.d.ts +1 -1
  584. package/dist/types/common/loading/index.d.ts +1 -2
  585. package/dist/types/common/loading/spinnerLoading/index.d.ts +1 -1
  586. package/dist/types/common/maskedInput/index.d.ts +2 -0
  587. package/dist/types/common/maskedInput/mask.d.ts +48 -0
  588. package/dist/types/common/maskedInput/maskedInput.d.ts +13 -0
  589. package/dist/types/common/maskedInput/maskedInput.types.d.ts +38 -0
  590. package/dist/types/common/menu/index.d.ts +3 -2
  591. package/dist/types/common/menu/menu.d.ts +1 -1
  592. package/dist/types/common/menu/menu.types.d.ts +13 -7
  593. package/dist/types/common/menu/menuHotkeys.d.ts +20 -0
  594. package/dist/types/common/modal/index.d.ts +2 -2
  595. package/dist/types/common/modal/modal.d.ts +1 -1
  596. package/dist/types/common/modal/modal.types.d.ts +6 -3
  597. package/dist/types/common/multiSelect/index.d.ts +2 -2
  598. package/dist/types/common/multiSelect/multiSelect.d.ts +1 -1
  599. package/dist/types/common/multiSelect/multiSelect.types.d.ts +3 -3
  600. package/dist/types/common/numberInput/index.d.ts +2 -2
  601. package/dist/types/common/numberInput/numberInput.d.ts +2 -2
  602. package/dist/types/common/numberInput/numberInput.types.d.ts +2 -2
  603. package/dist/types/common/optionPicker/index.d.ts +2 -2
  604. package/dist/types/common/optionPicker/optionPicker.d.ts +1 -1
  605. package/dist/types/common/optionPicker/optionPicker.types.d.ts +1 -1
  606. package/dist/types/common/otpInput/index.d.ts +2 -2
  607. package/dist/types/common/otpInput/otpInput.d.ts +1 -1
  608. package/dist/types/common/otpInput/otpInput.types.d.ts +2 -2
  609. package/dist/types/common/overscroll/index.d.ts +2 -2
  610. package/dist/types/common/overscroll/overscroll.d.ts +1 -1
  611. package/dist/types/common/pagination/index.d.ts +2 -2
  612. package/dist/types/common/pagination/pagination.d.ts +1 -1
  613. package/dist/types/common/pagination/pagination.types.d.ts +2 -2
  614. package/dist/types/common/planCanvas/index.d.ts +2 -2
  615. package/dist/types/common/planCanvas/planCanvas.d.ts +1 -1
  616. package/dist/types/common/planCanvas/planCanvas.types.d.ts +2 -2
  617. package/dist/types/common/popover/index.d.ts +2 -2
  618. package/dist/types/common/popover/popover.d.ts +1 -1
  619. package/dist/types/common/popover/popover.types.d.ts +2 -2
  620. package/dist/types/common/popover/usePopoverPosition.d.ts +2 -1
  621. package/dist/types/common/progressBar/index.d.ts +2 -2
  622. package/dist/types/common/progressBar/progressBar.d.ts +1 -1
  623. package/dist/types/common/progressBar/progressBar.types.d.ts +1 -1
  624. package/dist/types/common/radioGroup/index.d.ts +2 -2
  625. package/dist/types/common/radioGroup/radioGroup.d.ts +1 -1
  626. package/dist/types/common/radioGroup/radioGroup.types.d.ts +3 -3
  627. package/dist/types/common/rating/index.d.ts +2 -2
  628. package/dist/types/common/rating/rating.d.ts +1 -1
  629. package/dist/types/common/rating/rating.types.d.ts +2 -2
  630. package/dist/types/common/revealLens/index.d.ts +2 -2
  631. package/dist/types/common/revealLens/revealLens.d.ts +1 -1
  632. package/dist/types/common/revealLens/revealLens.types.d.ts +1 -1
  633. package/dist/types/common/ripple/index.d.ts +2 -2
  634. package/dist/types/common/ripple/ripple.d.ts +1 -1
  635. package/dist/types/common/ripple/ripple.types.d.ts +1 -1
  636. package/dist/types/common/roomDrawer/index.d.ts +2 -2
  637. package/dist/types/common/roomDrawer/roomDrawer.d.ts +1 -1
  638. package/dist/types/common/roomDrawer/roomDrawer.types.d.ts +3 -3
  639. package/dist/types/common/roomDrawer/usePlanHistory.d.ts +2 -2
  640. package/dist/types/common/roomViewer/index.d.ts +2 -2
  641. package/dist/types/common/roomViewer/roomViewer.d.ts +1 -1
  642. package/dist/types/common/roomViewer/roomViewer.types.d.ts +3 -3
  643. package/dist/types/common/scrollFade/index.d.ts +2 -0
  644. package/dist/types/common/scrollFade/scrollFade.d.ts +4 -0
  645. package/dist/types/common/scrollFade/scrollFade.types.d.ts +20 -0
  646. package/dist/types/common/scrollbarProvider/index.d.ts +1 -1
  647. package/dist/types/common/searchInput/index.d.ts +2 -2
  648. package/dist/types/common/searchInput/searchInput.d.ts +1 -1
  649. package/dist/types/common/searchInput/searchInput.types.d.ts +1 -1
  650. package/dist/types/common/sectionHeader/index.d.ts +2 -2
  651. package/dist/types/common/sectionHeader/sectionHeader.d.ts +1 -1
  652. package/dist/types/common/sectionHeader/sectionHeader.types.d.ts +3 -3
  653. package/dist/types/common/sheetBackdrop/index.d.ts +2 -2
  654. package/dist/types/common/sheetBackdrop/sheetBackdrop.d.ts +1 -1
  655. package/dist/types/common/skeleton/index.d.ts +2 -2
  656. package/dist/types/common/skeleton/skeleton.d.ts +1 -1
  657. package/dist/types/common/skeleton/skeleton.types.d.ts +1 -1
  658. package/dist/types/common/slider/index.d.ts +2 -2
  659. package/dist/types/common/slider/slider.d.ts +1 -1
  660. package/dist/types/common/slider/slider.types.d.ts +2 -2
  661. package/dist/types/common/splitButton/index.d.ts +2 -2
  662. package/dist/types/common/splitButton/splitButton.d.ts +1 -1
  663. package/dist/types/common/splitButton/splitButton.types.d.ts +4 -4
  664. package/dist/types/common/stepper/index.d.ts +2 -2
  665. package/dist/types/common/stepper/stepper.d.ts +1 -1
  666. package/dist/types/common/stepper/stepper.types.d.ts +2 -2
  667. package/dist/types/common/sticky/index.d.ts +1 -1
  668. package/dist/types/common/sticky/sticky.d.ts +2 -2
  669. package/dist/types/common/sticky/sticky.types.d.ts +16 -1
  670. package/dist/types/common/sticky/stickyStack.d.ts +5 -0
  671. package/dist/types/common/switch/index.d.ts +2 -2
  672. package/dist/types/common/switch/switch.d.ts +1 -1
  673. package/dist/types/common/switch/switch.types.d.ts +2 -2
  674. package/dist/types/common/tabHeader/index.d.ts +2 -2
  675. package/dist/types/common/tabHeader/tabHeader.d.ts +1 -1
  676. package/dist/types/common/tabHeader/tabHeader.types.d.ts +2 -2
  677. package/dist/types/common/textarea/index.d.ts +2 -2
  678. package/dist/types/common/textarea/textarea.d.ts +1 -1
  679. package/dist/types/common/textarea/textarea.types.d.ts +1 -1
  680. package/dist/types/common/themeProvider/defaultTheme.d.ts +1 -1
  681. package/dist/types/common/themeProvider/index.d.ts +4 -4
  682. package/dist/types/common/themeProvider/lightTheme.d.ts +1 -1
  683. package/dist/types/common/themeProvider/theme.types.d.ts +28 -0
  684. package/dist/types/common/themeProvider/themeProvider.d.ts +1 -1
  685. package/dist/types/common/tilt/index.d.ts +4 -4
  686. package/dist/types/common/tilt/tilt.d.ts +1 -1
  687. package/dist/types/common/tilt/tilt.types.d.ts +2 -2
  688. package/dist/types/common/tiltGroup/index.d.ts +3 -3
  689. package/dist/types/common/tiltGroup/tiltGroup.d.ts +1 -1
  690. package/dist/types/common/tiltGroup/tiltGroup.types.d.ts +1 -1
  691. package/dist/types/common/timeInput/components/clockDial/clockDial.d.ts +1 -1
  692. package/dist/types/common/timeInput/components/clockDial/clockDial.types.d.ts +3 -3
  693. package/dist/types/common/timeInput/components/clockDial/index.d.ts +1 -1
  694. package/dist/types/common/timeInput/index.d.ts +1 -1
  695. package/dist/types/common/timeInput/timeInput.d.ts +1 -1
  696. package/dist/types/common/timeInput/timeInput.types.d.ts +2 -2
  697. package/dist/types/common/timeline/index.d.ts +2 -2
  698. package/dist/types/common/timeline/timeline.d.ts +1 -1
  699. package/dist/types/common/timeline/timeline.types.d.ts +2 -2
  700. package/dist/types/common/timer/index.d.ts +2 -2
  701. package/dist/types/common/timer/timer.d.ts +1 -1
  702. package/dist/types/common/timer/timer.types.d.ts +2 -2
  703. package/dist/types/common/toast/index.d.ts +3 -3
  704. package/dist/types/common/toast/toast.d.ts +1 -1
  705. package/dist/types/common/toast/toast.types.d.ts +1 -1
  706. package/dist/types/common/toast/toastProvider.d.ts +1 -1
  707. package/dist/types/common/toast/toastService.d.ts +1 -1
  708. package/dist/types/common/tooltip/index.d.ts +2 -2
  709. package/dist/types/common/tooltip/tooltip.d.ts +1 -1
  710. package/dist/types/common/tree/flattenTree.d.ts +1 -1
  711. package/dist/types/common/tree/index.d.ts +3 -3
  712. package/dist/types/common/tree/tree.d.ts +1 -1
  713. package/dist/types/common/tree/tree.types.d.ts +2 -2
  714. package/dist/types/common/types/actions.types.d.ts +1 -1
  715. package/dist/types/common/types/slots.types.d.ts +1 -1
  716. package/dist/types/common/utils/interactiveTarget.d.ts +7 -0
  717. package/dist/types/common/utils/listNavigation.d.ts +49 -0
  718. package/dist/types/common/utils/renderIcon.d.ts +1 -1
  719. package/dist/types/common/utils/scrollAncestors.d.ts +10 -0
  720. package/dist/types/common/virtualList/index.d.ts +2 -2
  721. package/dist/types/common/virtualList/scroller.d.ts +33 -0
  722. package/dist/types/common/virtualList/useColumnResize.d.ts +1 -1
  723. package/dist/types/common/virtualList/useColumns.d.ts +1 -1
  724. package/dist/types/common/virtualList/useRowDrag.d.ts +7 -2
  725. package/dist/types/common/virtualList/useRowNavigation.d.ts +12 -2
  726. package/dist/types/common/virtualList/useSorting.d.ts +1 -1
  727. package/dist/types/common/virtualList/useVirtualWindow.d.ts +22 -3
  728. package/dist/types/common/virtualList/virtualList.d.ts +3 -3
  729. package/dist/types/common/virtualList/virtualList.types.d.ts +44 -4
  730. package/dist/types/common/virtualList/virtualList.utils.d.ts +1 -1
  731. package/dist/types/common/virtualList/virtualListHeader.d.ts +4 -4
  732. package/dist/types/common/virtualList/virtualRow.d.ts +1 -1
  733. package/dist/types/common/wizard/index.d.ts +1 -1
  734. package/dist/types/common/wizard/wizard.d.ts +1 -1
  735. package/dist/types/common/wizard/wizard.types.d.ts +1 -1
  736. package/dist/types/index.d.ts +154 -153
  737. package/dist/types/services/formValidation/index.d.ts +3 -3
  738. package/dist/types/services/formValidation/useFormValidatorGroup.d.ts +1 -1
  739. package/docs/ActionIcon.md +2 -0
  740. package/docs/CLAUDE.md +124 -230
  741. package/docs/Card.md +1 -1
  742. package/docs/Divider.md +2 -0
  743. package/docs/Dropdown.md +20 -0
  744. package/docs/Hooks.md +232 -0
  745. package/docs/IdleManager.md +38 -8
  746. package/docs/InputDropdown.md +11 -0
  747. package/docs/InteractableDiv.md +7 -1
  748. package/docs/KlipyPicker.md +1 -1
  749. package/docs/Loading.md +57 -14
  750. package/docs/Menu.md +27 -3
  751. package/docs/Modal.md +34 -10
  752. package/docs/MultiSelect.md +2 -2
  753. package/docs/Pagination.md +1 -1
  754. package/docs/Popover.md +4 -0
  755. package/docs/RadioGroup.md +1 -1
  756. package/docs/Rating.md +2 -0
  757. package/docs/Ripple.md +3 -0
  758. package/docs/RoomViewer.md +3 -5
  759. package/docs/ScrollFade.md +77 -0
  760. package/docs/ScrollbarProvider.md +2 -0
  761. package/docs/Slider.md +1 -1
  762. package/docs/Sticky.md +22 -1
  763. package/docs/Timer.md +1 -1
  764. package/docs/VirtualList.md +44 -4
  765. package/docs/Wizard.md +1 -1
  766. package/package.json +33 -11
  767. package/dist/esm/common/infiniteBlock/infiniteBlock.mjs +0 -2
  768. package/dist/esm/common/infiniteBlock/infiniteBlock.mjs.map +0 -1
  769. package/dist/esm/common/infiniteBlock/infiniteBlock.module.mjs +0 -2
  770. package/dist/esm/common/infiniteBlock/infiniteBlock.module.mjs.map +0 -1
  771. package/dist/esm/common/loading/iconLoading/iconLoading.mjs +0 -2
  772. package/dist/esm/common/loading/iconLoading/iconLoading.mjs.map +0 -1
  773. package/dist/esm/common/loading/iconLoading/iconLoading.module.mjs +0 -2
  774. package/dist/esm/common/loading/iconLoading/iconLoading.module.mjs.map +0 -1
  775. package/dist/esm/common/loading/iconLoading/index.mjs +0 -2
  776. package/dist/esm/common/loading/iconLoading/index.mjs.map +0 -1
  777. package/dist/types/common/infiniteBlock/index.d.ts +0 -1
  778. package/dist/types/common/infiniteBlock/infiniteBlock.d.ts +0 -4
  779. package/dist/types/common/infiniteBlock/infiniteBlock.types.d.ts +0 -13
  780. package/dist/types/common/loading/iconLoading/iconLoading.d.ts +0 -5
  781. package/dist/types/common/loading/iconLoading/index.d.ts +0 -2
  782. package/docs/Icon.md +0 -27
  783. package/docs/InfiniteBlock.md +0 -23
@@ -1 +1 @@
1
- {"version":3,"file":"input.module.mjs","names":[],"sources":["../../../../package/common/input/input.module.pcss"],"sourcesContent":["/* Chrome fills a field on page load without firing anything React can see, and an animation\n bound to the pseudo-class is the only hook it offers. The declarations are inert on purpose;\n the pair exists to be listened for — see handleAutofillAnimation in input.tsx. */\n@keyframes inputAutofillStart {\n from {\n opacity: 1;\n }\n}\n\n@keyframes inputAutofillEnd {\n from {\n opacity: 1;\n }\n}\n\n.required-mark {\n padding: 0 0 0 4px;\n color: var(--required-mark-color, var(--error-color));\n}\n\n.input {\n position: relative;\n width: 100%;\n\n --input-notch-height: 1.75em;\n --input-icon-size: 1.2em;\n --input-icon-offset: 0.6em;\n --input-icon-gutter: 2.2em;\n\n /* The visible border lives on `fieldset`/`container` below, not this root — buried inside a\n `<label>`, out of reach of a plain ancestor selector. --group-radius-* are custom properties\n (not defined here) that a wrapping ButtonGroup sets per corner on the position it occupies;\n unlike border-radius itself they inherit through any nesting depth, so they reach these\n descendants and flatten the right corners when this Input sits inside a ButtonGroup. */\n --input-radius: var(--group-radius-tl, var(--default-border-radius))\n var(--group-radius-tr, var(--default-border-radius)) var(--group-radius-br, var(--default-border-radius))\n var(--group-radius-bl, var(--default-border-radius));\n\n &-placeholder {\n position: absolute;\n top: 50%;\n left: 7px;\n transform: translateY(-50%);\n transition: all 0.2s;\n opacity: 0;\n user-select: none;\n pointer-events: none;\n\n &-shown {\n animation: 0.2s fadeIn 0.3s forwards;\n }\n\n &-multiline {\n top: 14px;\n transform: translateY(0);\n }\n }\n\n &-matLabel {\n position: absolute;\n transition: all 0.3s;\n left: 7px;\n right: 0;\n top: 50%;\n transform: translateY(-50%);\n font-size: 1em;\n color: var(--input-label-resting-color, var(--text-light));\n pointer-events: none;\n user-select: none;\n\n &-floating {\n inset: 0 0 auto 14px;\n font-size: 0.8em;\n color: var(--input-label-floating-color, var(--text-color));\n transform: translateY(-50%);\n }\n\n &-multiline {\n top: 14px;\n transform: translateY(0);\n }\n }\n\n &-fieldset {\n position: absolute;\n width: 100%;\n margin: 0;\n padding: 0;\n min-width: 0;\n box-sizing: border-box;\n border-radius: var(--input-radius);\n font-size: 0.8em;\n inset: calc(var(--input-notch-height) / -2) 0 0;\n padding-left: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: var(--border-color);\n pointer-events: none;\n user-select: none;\n\n &-no-notch {\n /* Only Firefox actually renders the reserved notch space as a visible overlap on\n label-less inputs (e.g. crossing a divider directly above it in a tightly-packed\n layout like the sidebar search box); Chrome's rendering was never broken, just\n consistently sized with every other input. @supports (-moz-appearance: none) is a\n reliable Firefox-only feature query, so this scopes the fix to where it's needed\n instead of changing every browser's sizing. */\n @supports (-moz-appearance: none) {\n inset: 0;\n }\n }\n\n &-legend {\n display: block;\n max-width: 0;\n transition: max-width 0.2s;\n white-space: nowrap;\n padding: 0;\n\n &-active {\n max-width: 300px;\n }\n\n span {\n line-height: var(--input-notch-height);\n padding: 0 5px;\n opacity: 0;\n }\n\n span:empty {\n padding: 0.000001px;\n }\n }\n }\n\n &-iconLeft {\n .input-matLabel {\n left: var(--input-icon-gutter);\n\n &-floating {\n left: calc(var(--input-icon-gutter) + 0.5em);\n }\n }\n\n .input-placeholder {\n left: var(--input-icon-gutter);\n }\n\n .input-fieldset {\n padding-left: var(--input-icon-gutter);\n }\n }\n\n &-container {\n display: flex;\n align-items: center;\n border-radius: var(--input-radius);\n background-color: var(--input-background);\n transition: border-color;\n cursor: text;\n height: 100%;\n\n &-multiline {\n overflow: hidden;\n padding-top: 10px;\n align-items: flex-start;\n }\n\n &-border {\n transition: border-color;\n background-color: var(--input-background);\n outline: none;\n\n &-focused {\n outline-color: var(--focus-border-color, var(--primary-color));\n border-color: var(--focus-border-color, var(--primary-color));\n }\n\n &-searchFocused {\n outline-color: var(--search-input-color);\n outline-width: 2px;\n border-color: var(--search-input-color);\n }\n\n &-invalid {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n\n &-invalid:hover {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n\n &-error {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n }\n }\n\n &-label {\n display: flex;\n color: var(--text-color);\n height: 100%;\n\n &-column {\n flex-direction: column;\n }\n\n &-text {\n margin-right: 5px;\n margin-bottom: 6px;\n display: flex;\n align-items: center;\n color: color(var(--border-color) lightness(40%));\n background-color: transparent;\n font-size: 12px;\n position: absolute;\n top: -15px;\n white-space: nowrap;\n }\n }\n\n &-upper-right-label {\n position: absolute;\n transform: translateY(calc(-100% - 1.5px));\n right: 8px;\n min-height: 12px;\n font-size: 12px;\n color: color(var(--border-color) lightness(40%));\n }\n\n &-field {\n appearance: none;\n -webkit-appearance: none;\n font-family: inherit;\n font-size: inherit;\n box-sizing: border-box;\n resize: none;\n width: 100%;\n border: none;\n border-radius: var(--default-border-radius);\n overflow: hidden;\n line-height: 1.25;\n color: var(--text-color);\n background: transparent;\n\n &:focus {\n outline: none;\n }\n\n &::placeholder {\n color: var(--text-light);\n }\n\n /* Chrome overrides `background` and `color` on an autofilled field outright. Clipping the\n background to the glyphs is what removes it: the page cannot win on colour, but it can\n say where a background paints, and -webkit-text-fill-color then beats the text colour.\n The field is transparent either way, so what shows through is whatever is really behind\n it — no surface has to declare itself, which an inset-shadow cover-up would have needed. */\n &:-webkit-autofill,\n &:-webkit-autofill:hover,\n &:-webkit-autofill:focus,\n &:-webkit-autofill:active {\n animation-name: inputAutofillStart;\n animation-duration: 1ms;\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: var(--text-color);\n caret-color: var(--text-color);\n }\n\n &:not(:-webkit-autofill) {\n animation-name: inputAutofillEnd;\n animation-duration: 1ms;\n }\n\n /* The browser's own search-cancel decoration doesn't match the theme — Search has its own\n themed clear icon (see isSearchCleared in input.tsx) that replaces it. */\n &::-webkit-search-cancel-button,\n &::-webkit-search-decoration {\n -webkit-appearance: none;\n appearance: none;\n display: none;\n }\n\n &-withIcon {\n padding-right: var(--input-icon-gutter) !important;\n\n &-left {\n padding-right: 0.643em !important;\n padding-left: var(--input-icon-gutter) !important;\n }\n }\n\n &-suffix {\n padding-right: 9px;\n }\n\n &-date {\n padding: 6px 9px;\n color-scheme: dark;\n\n svg {\n color: var(--input-icon-color);\n }\n }\n\n &-default {\n padding: 8px 7.5px 6px;\n }\n\n &[disabled] {\n background-color: var(--disabled-input-color);\n color: var(--disabled-font-color);\n -webkit-text-fill-color: var(--disabled-font-color);\n opacity: 1;\n\n &::placeholder {\n color: var(--disabled-font-color);\n -webkit-text-fill-color: var(--disabled-font-color);\n }\n }\n\n &-readOnly {\n cursor: default;\n color: var(--text-dark);\n -webkit-text-fill-color: var(--text-dark);\n }\n\n &-uppercase {\n text-transform: uppercase;\n }\n\n &-multiline {\n overflow-y: auto;\n resize: vertical;\n padding-top: 4px;\n min-height: 30px;\n\n &-autoResize {\n resize: none;\n overflow: hidden;\n }\n }\n\n &-icon {\n appearance: none;\n -webkit-appearance: none;\n box-sizing: border-box;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n background-color: transparent;\n border: none;\n position: absolute;\n outline: none;\n right: var(--input-icon-offset);\n color: var(--input-icon-color);\n width: var(--input-icon-size) !important;\n height: var(--input-icon-size) !important;\n user-select: none;\n top: 50%;\n transform: translateY(-50%);\n\n &:focus-visible {\n outline: 1px solid var(--focus-border-color, var(--primary-color));\n outline-offset: 2px;\n }\n\n &-left {\n left: var(--input-icon-offset);\n }\n\n &-notClickable {\n pointer-events: none;\n }\n }\n }\n\n &-error {\n height: 1em;\n padding-top: 3px;\n color: var(--error-font-color);\n font-size: 11px;\n }\n\n @keyframes fadeIn {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 0.5;\n }\n }\n}\n\n/* The label's glide between resting and floating is the motion; it still moves, just instantly. */\n@media (prefers-reduced-motion: reduce) {\n .input-matLabel,\n .input-placeholder {\n transition: none;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"input.module.mjs","names":[],"sources":["../../../../package/common/input/input.module.pcss"],"sourcesContent":["/* Chrome fills a field on page load without firing anything React can see, and an animation\n bound to the pseudo-class is the only hook it offers. The declarations are inert on purpose;\n the pair exists to be listened for — see handleAutofillAnimation in input.tsx. */\n@keyframes inputAutofillStart {\n from {\n opacity: 1;\n }\n}\n\n@keyframes inputAutofillEnd {\n from {\n opacity: 1;\n }\n}\n\n.required-mark {\n padding: 0 0 0 4px;\n color: var(--required-mark-color, var(--error-color));\n}\n\n.input {\n position: relative;\n width: 100%;\n\n --input-notch-height: 1.75em;\n --input-icon-size: 1.2em;\n --input-icon-offset: 0.6em;\n --input-icon-gutter: 2.2em;\n\n /* The visible border lives on `fieldset`/`container` below, not this root — buried inside a\n `<label>`, out of reach of a plain ancestor selector. --group-radius-* are custom properties\n (not defined here) that a wrapping ButtonGroup sets per corner on the position it occupies;\n unlike border-radius itself they inherit through any nesting depth, so they reach these\n descendants and flatten the right corners when this Input sits inside a ButtonGroup. */\n --input-radius: var(--group-radius-tl, var(--default-border-radius))\n var(--group-radius-tr, var(--default-border-radius)) var(--group-radius-br, var(--default-border-radius))\n var(--group-radius-bl, var(--default-border-radius));\n\n &-placeholder {\n position: absolute;\n top: 50%;\n left: 7px;\n transform: translateY(-50%);\n transition: all 0.2s;\n opacity: 0;\n user-select: none;\n pointer-events: none;\n\n &-shown {\n animation: 0.2s fadeIn 0.3s forwards;\n }\n\n &-multiline {\n top: 14px;\n transform: translateY(0);\n }\n }\n\n &-matLabel {\n position: absolute;\n transition: all 0.3s;\n left: 7px;\n right: 0;\n top: 50%;\n transform: translateY(-50%);\n font-size: 1em;\n color: var(--input-label-resting-color, var(--text-light));\n pointer-events: none;\n user-select: none;\n\n &-floating {\n inset: 0 0 auto 14px;\n font-size: 0.8em;\n color: var(--input-label-floating-color, var(--text-color));\n transform: translateY(-50%);\n }\n\n &-multiline {\n top: 14px;\n transform: translateY(0);\n }\n }\n\n &-fieldset {\n position: absolute;\n width: 100%;\n margin: 0;\n padding: 0;\n min-width: 0;\n box-sizing: border-box;\n border-radius: var(--input-radius);\n font-size: 0.8em;\n inset: calc(var(--input-notch-height) / -2) 0 0;\n padding-left: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: var(--border-color);\n pointer-events: none;\n user-select: none;\n\n &-legend {\n display: block;\n\n /* Not taken from the text: an empty span gets no line box, which raised a label-less\n field's border half a notch. */\n height: var(--input-notch-height);\n max-width: 0;\n transition: max-width 0.2s;\n white-space: nowrap;\n padding: 0;\n\n &-active {\n max-width: 300px;\n }\n\n span {\n line-height: var(--input-notch-height);\n padding: 0 5px;\n opacity: 0;\n }\n\n span:empty {\n padding: 0;\n }\n }\n }\n\n &-iconLeft {\n .input-matLabel {\n left: var(--input-icon-gutter);\n\n &-floating {\n left: calc(var(--input-icon-gutter) + 0.5em);\n }\n }\n\n .input-placeholder {\n left: var(--input-icon-gutter);\n }\n\n .input-fieldset {\n padding-left: var(--input-icon-gutter);\n }\n }\n\n &-container {\n display: flex;\n align-items: center;\n border-radius: var(--input-radius);\n background-color: var(--input-background);\n transition: border-color;\n cursor: text;\n height: 100%;\n\n &-multiline {\n overflow: hidden;\n padding-top: 10px;\n align-items: flex-start;\n }\n\n &-border {\n transition: border-color;\n background-color: var(--input-background);\n outline: none;\n\n &-focused {\n outline-color: var(--focus-border-color, var(--primary-color));\n border-color: var(--focus-border-color, var(--primary-color));\n }\n\n &-searchFocused {\n outline-color: var(--search-input-color);\n outline-width: 2px;\n border-color: var(--search-input-color);\n }\n\n &-invalid {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n\n &-invalid:hover {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n\n &-error {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n }\n }\n\n &-label {\n display: flex;\n color: var(--text-color);\n height: 100%;\n\n &-column {\n flex-direction: column;\n }\n\n &-text {\n margin-right: 5px;\n margin-bottom: 6px;\n display: flex;\n align-items: center;\n color: color(var(--border-color) lightness(40%));\n background-color: transparent;\n font-size: 12px;\n position: absolute;\n top: -15px;\n white-space: nowrap;\n }\n }\n\n &-upper-right-label {\n position: absolute;\n transform: translateY(calc(-100% - 1.5px));\n right: 8px;\n min-height: 12px;\n font-size: 12px;\n color: color(var(--border-color) lightness(40%));\n }\n\n &-field {\n appearance: none;\n -webkit-appearance: none;\n font-family: inherit;\n font-size: inherit;\n box-sizing: border-box;\n resize: none;\n width: 100%;\n border: none;\n border-radius: var(--default-border-radius);\n overflow: hidden;\n line-height: 1.25;\n color: var(--text-color);\n background: transparent;\n\n &:focus {\n outline: none;\n }\n\n &::placeholder {\n color: var(--text-light);\n }\n\n /* Chrome overrides `background` and `color` on an autofilled field outright. Clipping the\n background to the glyphs is what removes it: the page cannot win on colour, but it can\n say where a background paints, and -webkit-text-fill-color then beats the text colour.\n The field is transparent either way, so what shows through is whatever is really behind\n it — no surface has to declare itself, which an inset-shadow cover-up would have needed. */\n &:-webkit-autofill,\n &:-webkit-autofill:hover,\n &:-webkit-autofill:focus,\n &:-webkit-autofill:active {\n animation-name: inputAutofillStart;\n animation-duration: 1ms;\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: var(--text-color);\n caret-color: var(--text-color);\n }\n\n &:not(:-webkit-autofill) {\n animation-name: inputAutofillEnd;\n animation-duration: 1ms;\n }\n\n /* The browser's own search-cancel decoration doesn't match the theme — Search has its own\n themed clear icon (see isSearchCleared in input.tsx) that replaces it. */\n &::-webkit-search-cancel-button,\n &::-webkit-search-decoration {\n -webkit-appearance: none;\n appearance: none;\n display: none;\n }\n\n &-withIcon {\n padding-right: var(--input-icon-gutter) !important;\n\n &-left {\n padding-right: 0.643em !important;\n padding-left: var(--input-icon-gutter) !important;\n }\n }\n\n &-suffix {\n padding-right: 9px;\n }\n\n &-date {\n padding: 6px 9px;\n color-scheme: dark;\n\n svg {\n color: var(--input-icon-color);\n }\n }\n\n &-default {\n padding: 8px 7.5px 6px;\n }\n\n &[disabled] {\n background-color: var(--disabled-input-color);\n color: var(--disabled-font-color);\n -webkit-text-fill-color: var(--disabled-font-color);\n opacity: 1;\n\n &::placeholder {\n color: var(--disabled-font-color);\n -webkit-text-fill-color: var(--disabled-font-color);\n }\n }\n\n &-readOnly {\n cursor: default;\n color: var(--text-dark);\n -webkit-text-fill-color: var(--text-dark);\n }\n\n &-uppercase {\n text-transform: uppercase;\n }\n\n &-multiline {\n overflow-y: auto;\n resize: vertical;\n padding-top: 4px;\n min-height: 30px;\n\n &-autoResize {\n resize: none;\n overflow: hidden;\n }\n }\n\n &-icon {\n appearance: none;\n -webkit-appearance: none;\n box-sizing: border-box;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n background-color: transparent;\n border: none;\n position: absolute;\n outline: none;\n right: var(--input-icon-offset);\n color: var(--input-icon-color);\n width: var(--input-icon-size) !important;\n height: var(--input-icon-size) !important;\n user-select: none;\n top: 50%;\n transform: translateY(-50%);\n\n &:focus-visible {\n outline: 1px solid var(--focus-border-color, var(--primary-color));\n outline-offset: 2px;\n }\n\n &-left {\n left: var(--input-icon-offset);\n }\n\n &-notClickable {\n pointer-events: none;\n }\n }\n }\n\n &-error {\n height: 1em;\n padding-top: 3px;\n color: var(--error-font-color);\n font-size: 11px;\n }\n\n @keyframes fadeIn {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 0.5;\n }\n }\n}\n\n/* The label's glide between resting and floating is the motion; it still moves, just instantly. */\n@media (prefers-reduced-motion: reduce) {\n .input-matLabel,\n .input-placeholder {\n transition: none;\n }\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{PopoverAlign as t,PopoverPlacement as n}from"../popover/popover.types.mjs";import r from"../popover/popover.mjs";import i from"../input/input.mjs";import a from"./inputDropdown.module.mjs";import{useCallback as o,useEffect as s,useLayoutEffect as c,useMemo as l,useRef as u,useState as d}from"react";import f from"classnames";import{jsx as p}from"react/jsx-runtime";function m(e,t){return t?t.value??``:e??``}function h(e,t){let n=t.find(t=>t.value===e);return n?n.label??n.value:e}function g(g){let{label:_=``,value:v=``,formValidator:y=null,error:b,isRequired:x=!1,items:S=[],allowCustomValue:C=!1,maxItems:w=100,className:T,style:E,classNames:D,styles:O,onSelect:k=()=>null,onChange:A,placeholder:j=``,readOnly:M=!1,...N}=e(`InputDropdown`,g),P=m(v,y),[,F]=d(0),I=u(y);s(()=>{if(I.current=y,!y)return;let e=()=>F(e=>e+1);return y.registerOnUpdateListener(e),()=>{y.removeOnUpdateListener(e)}},[y]);let L=x||!!y?.validators.find(e=>e.validatorId===`required`),[R,z]=d(()=>h(P,S)),[B,V]=d(P),[H,U]=d(!1),[W,G]=d(null),K=u(null),q=u(null),J=u(null),Y=O?.dropdown?.fontSize;if(c(()=>{let e=q.current,t=J.current;H&&e&&t&&Y==null&&(t.style.fontSize=window.getComputedStyle(e).fontSize)},[H,Y]),P!==B){V(P);let e=S.find(e=>e.value===P);e?z(e.label??e.value):C&&z(P)}let X=l(()=>{let e=R.toLowerCase(),t=[];for(let n of S)if((n.label??n.value).toLowerCase().includes(e)&&(t.push(n),w>0&&t.length>=w))break;return t},[S,R,w]),Z=()=>{M||(K.current&&=(clearTimeout(K.current),null),U(!0))},Q=()=>{I.current&&(I.current.touched=!0),K.current=setTimeout(()=>{U(!1),K.current=null,C||z(h(P,S))},100)},$=o(e=>{z(e.label??e.value),U(!1),G(null),y&&y.set(e.value),A&&A(e.value),k(e.value)},[y,A,k]),ee=o(e=>{M||(e.key===`ArrowUp`?(e.preventDefault(),G(e=>e?e-1:null)):e.key===`ArrowDown`?(e.preventDefault(),G(e=>e===null?0:Math.min(e+1,X.length-1))):e.key===`Enter`&&(W!==null&&X[W]?$(X[W]):C&&(U(!1),G(null))))},[X,W,$,C,M]),te=p(`div`,{ref:J,className:f(a.dropdown,D?.dropdown),style:O?.dropdown,children:p(`div`,{className:a.dropdownScroll,children:X.map((e,t)=>p(`div`,{className:f(a.dropdownItem,W===t&&a.dropdownItemHighlighted,D?.item),style:O?.item,onMouseDown:e=>e.preventDefault(),onClick:()=>$(e),children:e.label??e.value},`${t}_${e.label}_${e.value}`))})});return p(`div`,{...N,ref:q,className:f(a.inputDropdown,D?.root,T),style:{...O?.root,...E},onFocus:Z,onBlur:Q,onKeyDown:ee,children:p(r,{isOpen:H&&!M,onOpenChange:e=>{e||U(!1)},placement:n.Bottom,align:t.Start,offset:0,withArrow:!1,constrainWidth:!1,closeOnTriggerClick:!1,focusOnOpen:!1,classNames:{panel:a.inputDropdownPanel},content:te,children:p(i,{autoComplete:`off`,label:_,value:R,readOnly:M,formValidator:null,isRequired:L,isValid:y?!y.touched||!y.hasError():!b,errorMessage:y?y.touched?y.getCurrentErrorMessage()??``:``:b??``,onChange:e=>{if(z(e),G(null),U(!0),C)y&&y.set(e),A&&A(e);else if(e===``)y&&y.set(``),A&&A(``),k(``);else{let t=S.find(t=>(t.label??t.value).toLowerCase()===e.toLowerCase());t&&(y&&y.set(t.value),A&&A(t.value),k(t.value))}},placeholder:j})})})}export{g as default};
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{PopoverAlign as t,PopoverPlacement as n}from"../popover/popover.types.mjs";import ee from"../popover/popover.mjs";import r from"../input/input.mjs";import{nextIndex as i,scrollOptionIntoView as a}from"../utils/listNavigation.mjs";import o from"./inputDropdown.module.mjs";import{useCallback as s,useEffect as c,useLayoutEffect as l,useMemo as u,useRef as d,useState as f}from"react";import p from"classnames";import{jsx as m}from"react/jsx-runtime";function h(e,t){return t?t.value??``:e??``}function g(e,t){let n=t.find(t=>t.value===e);return n?n.label??n.value:e}var te={wrap:!1};function _(_){let{label:v=``,value:y=``,formValidator:b=null,error:x,isRequired:S=!1,items:C=[],allowCustomValue:w=!1,maxItems:T=100,className:E,style:D,classNames:O,styles:k,onSelect:A=()=>null,onChange:j,placeholder:M=``,readOnly:N=!1,...P}=e(`InputDropdown`,_),F=h(y,b),[,I]=f(0),L=d(b);c(()=>{if(L.current=b,!b)return;let e=()=>I(e=>e+1);return b.registerOnUpdateListener(e),()=>{b.removeOnUpdateListener(e)}},[b]);let R=S||!!b?.validators.find(e=>e.validatorId===`required`),[z,B]=f(()=>g(F,C)),[V,H]=f(F),[U,W]=f(!1),[G,K]=f(null),q=d(null),J=d(null),Y=d(null),X=d(null),Z=k?.dropdown?.fontSize;if(l(()=>{let e=J.current,t=Y.current;U&&e&&t&&Z==null&&(t.style.fontSize=window.getComputedStyle(e).fontSize)},[U,Z]),F!==V){H(F);let e=C.find(e=>e.value===F);e?B(e.label??e.value):w&&B(F)}let Q=u(()=>{let e=z.toLowerCase(),t=[];for(let n of C)if((n.label??n.value).toLowerCase().includes(e)&&(t.push(n),T>0&&t.length>=T))break;return t},[C,z,T]),ne=()=>{N||(q.current&&=(clearTimeout(q.current),null),W(!0))},re=()=>{L.current&&(L.current.touched=!0),q.current=setTimeout(()=>{W(!1),q.current=null,w||B(g(F,C))},100)};c(()=>{U&&G!==null&&a(X.current,X.current?.children[G])},[U,G]);let $=s(e=>{B(e.label??e.value),W(!1),K(null),b&&b.set(e.value),j&&j(e.value),A(e.value)},[b,j,A]),ie=s(e=>{if(!N){if(e.key===`ArrowUp`||e.key===`ArrowDown`){e.preventDefault();let t=e.key===`ArrowDown`?1:-1;K(e=>e!==null&&e===(t===1?Q.length-1:0)?null:i(e,t,Q.length,te))}else e.key===`Enter`&&(G!==null&&Q[G]?(e.preventDefault(),$(Q[G])):w&&(W(!1),K(null)))}},[Q,G,$,w,N]),ae=m(`div`,{ref:Y,className:p(o.dropdown,O?.dropdown),style:k?.dropdown,children:m(`div`,{ref:X,className:o.dropdownScroll,children:Q.map((e,t)=>m(`div`,{className:p(o.dropdownItem,G===t&&o.dropdownItemHighlighted,O?.item),style:k?.item,onMouseDown:e=>e.preventDefault(),onClick:()=>$(e),children:e.label??e.value},`${t}_${e.label}_${e.value}`))})});return m(`div`,{...P,ref:J,className:p(o.inputDropdown,O?.root,E),style:{...k?.root,...D},onFocus:ne,onBlur:re,onKeyDown:ie,children:m(ee,{isOpen:U&&!N,onOpenChange:e=>{e||W(!1)},placement:n.Bottom,align:t.Start,offset:0,withArrow:!1,constrainWidth:!1,closeOnTriggerClick:!1,focusOnOpen:!1,classNames:{panel:o.inputDropdownPanel},content:ae,children:m(r,{autoComplete:`off`,label:v,value:z,readOnly:N,formValidator:null,isRequired:R,isValid:b?!b.touched||!b.hasError():!x,errorMessage:b?b.touched?b.getCurrentErrorMessage()??``:``:x??``,onChange:e=>{if(B(e),K(null),W(!0),w)b&&b.set(e),j&&j(e);else if(e===``)b&&b.set(``),j&&j(``),A(``);else{let t=C.find(t=>(t.label??t.value).toLowerCase()===e.toLowerCase());t&&(b&&b.set(t.value),j&&j(t.value),A(t.value))}},placeholder:M})})})}export{_ as default};
2
2
  //# sourceMappingURL=inputDropdown.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"inputDropdown.mjs","names":[],"sources":["../../../../package/common/inputDropdown/inputDropdown.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport styles from './inputDropdown.module.pcss';\nimport Input from '../input';\nimport Popover from '../popover';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport { useComponentDefaults } from '../configProvider';\nimport type { InputDropdownItem, InputDropdownProps } from './inputDropdown.types';\n\nfunction getKeyFromProps(value: string | undefined, formValidator: InputDropdownProps['formValidator']): string {\n return formValidator ? ((formValidator.value as string) ?? '') : (value ?? '');\n}\n\nfunction labelForKey(key: string, items: InputDropdownItem[]): string {\n const match = items.find((item) => item.value === key);\n return match ? (match.label ?? match.value) : key;\n}\n\nexport default function InputDropdown(props: InputDropdownProps) {\n const {\n label = '',\n value = '',\n formValidator = null,\n error,\n isRequired = false,\n items = [],\n allowCustomValue = false,\n maxItems = 100,\n className,\n style,\n classNames,\n styles: slotStyles,\n onSelect = () => null,\n onChange,\n placeholder = '',\n readOnly = false,\n ...rest\n } = useComponentDefaults('InputDropdown', props);\n const currentKey = getKeyFromProps(value, formValidator);\n const [, forceUpdate] = useState(0);\n const fvRef = useRef(formValidator);\n\n useEffect(() => {\n fvRef.current = formValidator;\n if (!formValidator) return;\n const listener = () => forceUpdate((n) => n + 1);\n formValidator.registerOnUpdateListener(listener);\n return () => {\n formValidator.removeOnUpdateListener(listener);\n };\n }, [formValidator]);\n\n const computedIsRequired =\n isRequired || !!formValidator?.validators.find((v) => (v as { validatorId?: string }).validatorId === 'required');\n\n const [inputText, setInputText] = useState(() => labelForKey(currentKey, items));\n const [prevKey, setPrevKey] = useState(currentKey);\n const [isMenuShown, setIsMenuShown] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState<number | null>(null);\n const hideTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLDivElement>(null);\n\n const menuFontSizeOverride = slotStyles?.dropdown?.fontSize;\n useLayoutEffect(() => {\n const trigger = triggerRef.current;\n const menu = anchorRef.current;\n if (!isMenuShown || !trigger || !menu || menuFontSizeOverride != null) return;\n menu.style.fontSize = window.getComputedStyle(trigger).fontSize;\n }, [isMenuShown, menuFontSizeOverride]);\n\n // Sync display text when the controlled key changes externally (e.g. parent reset).\n if (currentKey !== prevKey) {\n setPrevKey(currentKey);\n const match = items.find((item) => item.value === currentKey);\n if (match) setInputText(match.label ?? match.value);\n else if (allowCustomValue) setInputText(currentKey);\n }\n\n const currItems = useMemo(() => {\n const needle = inputText.toLowerCase();\n const matches: InputDropdownItem[] = [];\n for (const item of items) {\n if (!(item.label ?? item.value).toLowerCase().includes(needle)) continue;\n matches.push(item);\n if (maxItems > 0 && matches.length >= maxItems) break;\n }\n return matches;\n }, [items, inputText, maxItems]);\n\n const handleFocus = () => {\n if (readOnly) return;\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n setIsMenuShown(true);\n };\n\n const handleBlur = () => {\n if (fvRef.current) fvRef.current.touched = true;\n hideTimeoutRef.current = setTimeout(() => {\n setIsMenuShown(false);\n hideTimeoutRef.current = null;\n // Without custom values, uncommitted typed text is invalid — snap the\n // display back to the currently selected item's label.\n if (!allowCustomValue) setInputText(labelForKey(currentKey, items));\n }, 100);\n };\n\n const handleSelect = useCallback(\n (item: InputDropdownItem) => {\n setInputText(item.label ?? item.value);\n setIsMenuShown(false);\n setHighlightedIndex(null);\n if (formValidator) formValidator.set(item.value);\n if (onChange) onChange(item.value);\n onSelect(item.value);\n },\n [formValidator, onChange, onSelect],\n );\n\n const onKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n if (readOnly) return;\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n setHighlightedIndex((idx) => (!idx ? null : idx - 1));\n } else if (event.key === 'ArrowDown') {\n event.preventDefault();\n setHighlightedIndex((idx) => (idx === null ? 0 : Math.min(idx + 1, currItems.length - 1)));\n } else if (event.key === 'Enter') {\n if (highlightedIndex !== null && currItems[highlightedIndex]) {\n handleSelect(currItems[highlightedIndex]);\n } else if (allowCustomValue) {\n setIsMenuShown(false);\n setHighlightedIndex(null);\n }\n }\n },\n [currItems, highlightedIndex, handleSelect, allowCustomValue, readOnly],\n );\n\n const menu = (\n <div ref={anchorRef} className={cx(styles.dropdown, classNames?.dropdown)} style={slotStyles?.dropdown}>\n <div className={styles.dropdownScroll}>\n {currItems.map((item, key) => (\n <div\n key={`${key}_${item.label}_${item.value}`}\n className={cx(\n styles.dropdownItem,\n highlightedIndex === key && styles.dropdownItemHighlighted,\n classNames?.item,\n )}\n style={slotStyles?.item}\n // Prevent the input from blurring before the click resolves.\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleSelect(item)}\n >\n {item.label ?? item.value}\n </div>\n ))}\n </div>\n </div>\n );\n\n return (\n <div\n {...rest}\n ref={triggerRef}\n className={cx(styles.inputDropdown, classNames?.root, className)}\n style={{ ...slotStyles?.root, ...style }}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={onKeyDown}\n >\n <Popover\n // The field owns the open state: it opens on typing and closes on blur, on\n // a pick, or on Escape. Only a close is taken from Popover, which is the\n // outside click its portaled panel would otherwise not see.\n isOpen={isMenuShown && !readOnly}\n onOpenChange={(next) => {\n if (!next) setIsMenuShown(false);\n }}\n placement={PopoverPlacement.Bottom}\n align={PopoverAlign.Start}\n offset={0}\n withArrow={false}\n constrainWidth={false}\n closeOnTriggerClick={false}\n focusOnOpen={false}\n classNames={{ panel: styles.inputDropdownPanel }}\n content={menu}\n >\n <Input\n // A combobox renders its own suggestion list; the browser's autofill dropdown\n // opens on top of it, so two lists compete for the same space.\n autoComplete='off'\n label={label}\n value={inputText}\n readOnly={readOnly}\n formValidator={null}\n isRequired={computedIsRequired}\n isValid={formValidator ? (formValidator.touched ? !formValidator.hasError() : true) : !error}\n errorMessage={\n formValidator\n ? formValidator.touched\n ? (formValidator.getCurrentErrorMessage() ?? '')\n : ''\n : (error ?? '')\n }\n onChange={(text) => {\n setInputText(text);\n setHighlightedIndex(null);\n setIsMenuShown(true);\n if (allowCustomValue) {\n if (formValidator) formValidator.set(text);\n if (onChange) onChange(text);\n } else if (text === '') {\n if (formValidator) formValidator.set('');\n if (onChange) onChange('');\n onSelect('');\n } else {\n // Emit when the typed text exactly matches an item's label/value.\n const match = items.find((item) => (item.label ?? item.value).toLowerCase() === text.toLowerCase());\n if (match) {\n if (formValidator) formValidator.set(match.value);\n if (onChange) onChange(match.value);\n onSelect(match.value);\n }\n }\n }}\n placeholder={placeholder}\n />\n </Popover>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"inputDropdown.mjs","names":[],"sources":["../../../../package/common/inputDropdown/inputDropdown.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport styles from './inputDropdown.module.pcss';\nimport Input from '../input';\nimport Popover from '../popover';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport { useComponentDefaults } from '../configProvider';\nimport type { InputDropdownItem, InputDropdownProps } from './inputDropdown.types';\nimport { nextIndex, scrollOptionIntoView } from '../utils/listNavigation';\n\nfunction getKeyFromProps(value: string | undefined, formValidator: InputDropdownProps['formValidator']): string {\n return formValidator ? ((formValidator.value as string) ?? '') : (value ?? '');\n}\n\nfunction labelForKey(key: string, items: InputDropdownItem[]): string {\n const match = items.find((item) => item.value === key);\n return match ? (match.label ?? match.value) : key;\n}\n\n/**\n * The suggestions do not wrap: the list is filtered by what is being typed, so running off one\n * end and reappearing at the other reads as the list having changed under the caret.\n */\nconst NO_WRAP = { wrap: false };\n\nexport default function InputDropdown(props: InputDropdownProps) {\n const {\n label = '',\n value = '',\n formValidator = null,\n error,\n isRequired = false,\n items = [],\n allowCustomValue = false,\n maxItems = 100,\n className,\n style,\n classNames,\n styles: slotStyles,\n onSelect = () => null,\n onChange,\n placeholder = '',\n readOnly = false,\n ...rest\n } = useComponentDefaults('InputDropdown', props);\n const currentKey = getKeyFromProps(value, formValidator);\n const [, forceUpdate] = useState(0);\n const fvRef = useRef(formValidator);\n\n useEffect(() => {\n fvRef.current = formValidator;\n if (!formValidator) return;\n const listener = () => forceUpdate((n) => n + 1);\n formValidator.registerOnUpdateListener(listener);\n return () => {\n formValidator.removeOnUpdateListener(listener);\n };\n }, [formValidator]);\n\n const computedIsRequired =\n isRequired || !!formValidator?.validators.find((v) => (v as { validatorId?: string }).validatorId === 'required');\n\n const [inputText, setInputText] = useState(() => labelForKey(currentKey, items));\n const [prevKey, setPrevKey] = useState(currentKey);\n const [isMenuShown, setIsMenuShown] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState<number | null>(null);\n const hideTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLDivElement>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n\n const menuFontSizeOverride = slotStyles?.dropdown?.fontSize;\n useLayoutEffect(() => {\n const trigger = triggerRef.current;\n const menu = anchorRef.current;\n if (!isMenuShown || !trigger || !menu || menuFontSizeOverride != null) return;\n menu.style.fontSize = window.getComputedStyle(trigger).fontSize;\n }, [isMenuShown, menuFontSizeOverride]);\n\n // Sync display text when the controlled key changes externally (e.g. parent reset).\n if (currentKey !== prevKey) {\n setPrevKey(currentKey);\n const match = items.find((item) => item.value === currentKey);\n if (match) setInputText(match.label ?? match.value);\n else if (allowCustomValue) setInputText(currentKey);\n }\n\n const currItems = useMemo(() => {\n const needle = inputText.toLowerCase();\n const matches: InputDropdownItem[] = [];\n for (const item of items) {\n if (!(item.label ?? item.value).toLowerCase().includes(needle)) continue;\n matches.push(item);\n if (maxItems > 0 && matches.length >= maxItems) break;\n }\n return matches;\n }, [items, inputText, maxItems]);\n\n const handleFocus = () => {\n if (readOnly) return;\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n setIsMenuShown(true);\n };\n\n const handleBlur = () => {\n if (fvRef.current) fvRef.current.touched = true;\n hideTimeoutRef.current = setTimeout(() => {\n setIsMenuShown(false);\n hideTimeoutRef.current = null;\n // Without custom values, uncommitted typed text is invalid — snap the\n // display back to the currently selected item's label.\n if (!allowCustomValue) setInputText(labelForKey(currentKey, items));\n }, 100);\n };\n\n useEffect(() => {\n if (!isMenuShown || highlightedIndex === null) return;\n scrollOptionIntoView(scrollRef.current, scrollRef.current?.children[highlightedIndex]);\n }, [isMenuShown, highlightedIndex]);\n\n const handleSelect = useCallback(\n (item: InputDropdownItem) => {\n setInputText(item.label ?? item.value);\n setIsMenuShown(false);\n setHighlightedIndex(null);\n if (formValidator) formValidator.set(item.value);\n if (onChange) onChange(item.value);\n onSelect(item.value);\n },\n [formValidator, onChange, onSelect],\n );\n\n const onKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n if (readOnly) return;\n if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {\n event.preventDefault();\n const step = event.key === 'ArrowDown' ? 1 : -1;\n setHighlightedIndex((idx) => {\n // The text being typed is part of the cycle, so both ends lead back to it and on round\n // to the far end: last → text → first, first → text → last. That is how a browser's own\n // address bar behaves, and it is why this list does not wrap straight around the way\n // Dropdown and MultiSelect do — they have no typed text to pass through.\n const atFarEnd = idx !== null && idx === (step === 1 ? currItems.length - 1 : 0);\n return atFarEnd ? null : nextIndex(idx, step, currItems.length, NO_WRAP);\n });\n } else if (event.key === 'Enter') {\n if (highlightedIndex !== null && currItems[highlightedIndex]) {\n // This Enter picked a suggestion, so it must not also reach the form around the field.\n // Without this the browser's implicit submission runs as well, and choosing from the\n // list submitted the form underneath the user. The blank state deliberately does not\n // do this: Enter there means the text as typed, and submitting is a fair reading of it.\n event.preventDefault();\n handleSelect(currItems[highlightedIndex]);\n } else if (allowCustomValue) {\n setIsMenuShown(false);\n setHighlightedIndex(null);\n }\n }\n },\n [currItems, highlightedIndex, handleSelect, allowCustomValue, readOnly],\n );\n\n const menu = (\n <div ref={anchorRef} className={cx(styles.dropdown, classNames?.dropdown)} style={slotStyles?.dropdown}>\n <div ref={scrollRef} className={styles.dropdownScroll}>\n {currItems.map((item, key) => (\n <div\n key={`${key}_${item.label}_${item.value}`}\n className={cx(\n styles.dropdownItem,\n highlightedIndex === key && styles.dropdownItemHighlighted,\n classNames?.item,\n )}\n style={slotStyles?.item}\n // Prevent the input from blurring before the click resolves.\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleSelect(item)}\n >\n {item.label ?? item.value}\n </div>\n ))}\n </div>\n </div>\n );\n\n return (\n <div\n {...rest}\n ref={triggerRef}\n className={cx(styles.inputDropdown, classNames?.root, className)}\n style={{ ...slotStyles?.root, ...style }}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={onKeyDown}\n >\n <Popover\n // The field owns the open state: it opens on typing and closes on blur, on\n // a pick, or on Escape. Only a close is taken from Popover, which is the\n // outside click its portaled panel would otherwise not see.\n isOpen={isMenuShown && !readOnly}\n onOpenChange={(next) => {\n if (!next) setIsMenuShown(false);\n }}\n placement={PopoverPlacement.Bottom}\n align={PopoverAlign.Start}\n offset={0}\n withArrow={false}\n constrainWidth={false}\n closeOnTriggerClick={false}\n focusOnOpen={false}\n classNames={{ panel: styles.inputDropdownPanel }}\n content={menu}\n >\n <Input\n // A combobox renders its own suggestion list; the browser's autofill dropdown\n // opens on top of it, so two lists compete for the same space.\n autoComplete='off'\n label={label}\n value={inputText}\n readOnly={readOnly}\n formValidator={null}\n isRequired={computedIsRequired}\n isValid={formValidator ? (formValidator.touched ? !formValidator.hasError() : true) : !error}\n errorMessage={\n formValidator\n ? formValidator.touched\n ? (formValidator.getCurrentErrorMessage() ?? '')\n : ''\n : (error ?? '')\n }\n onChange={(text) => {\n setInputText(text);\n setHighlightedIndex(null);\n setIsMenuShown(true);\n if (allowCustomValue) {\n if (formValidator) formValidator.set(text);\n if (onChange) onChange(text);\n } else if (text === '') {\n if (formValidator) formValidator.set('');\n if (onChange) onChange('');\n onSelect('');\n } else {\n // Emit when the typed text exactly matches an item's label/value.\n const match = items.find((item) => (item.label ?? item.value).toLowerCase() === text.toLowerCase());\n if (match) {\n if (formValidator) formValidator.set(match.value);\n if (onChange) onChange(match.value);\n onSelect(match.value);\n }\n }\n }}\n placeholder={placeholder}\n />\n </Popover>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use client";import{isSelfActivation as e}from"../utils/activationKey.mjs";import t from"./interactableDiv.module.mjs";import{useCallback as n}from"react";import r from"classnames";import{jsx as i}from"react/jsx-runtime";function a({className:a,children:o,onClick:s,onKeyDown:c,tabIndex:l,ref:u,...d}){let f=n(t=>{e(t)&&(t.key===` `&&t.preventDefault(),t.currentTarget.click()),c?.(t)},[c]);return i(`div`,{className:r(t.interactableDiv,a),onClick:s,tabIndex:l===void 0?s?0:void 0:l??void 0,role:s?`button`:void 0,onKeyDown:f,ref:u,...d,children:o})}export{a as default};
1
+ "use client";import{isSelfActivation as e}from"../utils/activationKey.mjs";import{isInteractiveTarget as t}from"../utils/interactiveTarget.mjs";import n from"./interactableDiv.module.mjs";import{useCallback as r}from"react";import i from"classnames";import{jsx as a}from"react/jsx-runtime";function o({className:o,children:s,onClick:c,onKeyDown:l,tabIndex:u,ref:d,...f}){let p=r(e=>{t(e.target,e.currentTarget)||c?.(e)},[c]),m=r(t=>{e(t)&&(t.key===` `&&t.preventDefault(),t.currentTarget.click()),l?.(t)},[l]);return a(`div`,{className:i(n.interactableDiv,o),onClick:c?p:void 0,tabIndex:u===void 0?c?0:void 0:u??void 0,role:c?`button`:void 0,onKeyDown:m,ref:d,...f,children:s})}export{o as default};
2
2
  //# sourceMappingURL=interactableDiv.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"interactableDiv.mjs","names":[],"sources":["../../../../package/common/interactableDiv/interactableDiv.tsx"],"sourcesContent":["import cx from 'classnames';\nimport React, { useCallback, type KeyboardEvent, type ReactElement } from 'react';\n\nimport styles from './interactableDiv.module.pcss';\nimport type { DataProps } from '../types/baseProps.types';\nimport { isSelfActivation } from '../utils/activationKey';\n\ninterface Properties extends DataProps, Omit<React.HTMLAttributes<HTMLDivElement>, 'tabIndex'> {\n tabIndex?: number | null;\n ref?: React.Ref<HTMLDivElement>;\n}\n\nfunction InteractableDiv({\n className,\n children,\n onClick,\n onKeyDown,\n tabIndex,\n ref,\n ...props\n}: Properties): ReactElement {\n const onKeyDownHandler = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (isSelfActivation(e)) {\n if (e.key === ' ') e.preventDefault();\n // A real click, the way a native button answers Enter and Space, rather\n // than calling `onClick` directly: it arrives as a MouseEvent instead of\n // a keyboard event wearing one, and it bubbles, so a parent that owns the\n // click sees it too. That parent is how a `Popover` or `Menu` opens from\n // a trigger that is not a button.\n e.currentTarget.click();\n }\n onKeyDown?.(e);\n },\n [onKeyDown],\n );\n\n // Compared to undefined rather than using ??, so an explicit null still means \"no tabindex\"\n // instead of falling through to the default.\n return (\n <div\n className={cx(styles.interactableDiv, className)}\n onClick={onClick}\n tabIndex={tabIndex === undefined ? (onClick ? 0 : undefined) : (tabIndex ?? undefined)}\n role={onClick ? 'button' : undefined}\n onKeyDown={onKeyDownHandler}\n ref={ref}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nexport default InteractableDiv;\n"],"mappings":"6NAYA,SAAS,EAAgB,CACvB,YACA,WACA,UACA,YACA,WACA,MACA,GAAG,GACwB,CAC3B,IAAM,EAAmB,EACtB,GAAqC,CAChC,EAAiB,CAAC,IAChB,EAAE,MAAQ,KAAK,EAAE,eAAe,EAMpC,EAAE,cAAc,MAAM,GAExB,IAAY,CAAC,CACf,EACA,CAAC,CAAS,CACZ,EAIA,OACE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,gBAAiB,CAAS,EACtC,UACT,SAAU,IAAa,IAAA,GAAa,EAAU,EAAI,IAAA,GAAc,GAAY,IAAA,GAC5E,KAAM,EAAU,SAAW,IAAA,GAC3B,UAAW,EACN,MACL,GAAI,EAEH,UACE,CAAA,CAET"}
1
+ {"version":3,"file":"interactableDiv.mjs","names":[],"sources":["../../../../package/common/interactableDiv/interactableDiv.tsx"],"sourcesContent":["import cx from 'classnames';\nimport React, { useCallback, type KeyboardEvent, type MouseEvent, type ReactElement } from 'react';\n\nimport styles from './interactableDiv.module.pcss';\nimport type { DataProps } from '../types/baseProps.types';\nimport { isSelfActivation } from '../utils/activationKey';\nimport { isInteractiveTarget } from '../utils/interactiveTarget';\n\ninterface Properties extends DataProps, Omit<React.HTMLAttributes<HTMLDivElement>, 'tabIndex'> {\n tabIndex?: number | null;\n ref?: React.Ref<HTMLDivElement>;\n}\n\nfunction InteractableDiv({\n className,\n children,\n onClick,\n onKeyDown,\n tabIndex,\n ref,\n ...props\n}: Properties): ReactElement {\n const onClickHandler = useCallback(\n (e: MouseEvent<HTMLDivElement>) => {\n // The pointer half of `isSelfActivation`: while only keydown checked its target, a click\n // into a card's text field counted as pressing the card and a Space typed into it did not.\n if (isInteractiveTarget(e.target, e.currentTarget)) return;\n onClick?.(e);\n },\n [onClick],\n );\n\n const onKeyDownHandler = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (isSelfActivation(e)) {\n if (e.key === ' ') e.preventDefault();\n // A real click, the way a native button answers Enter and Space, rather\n // than calling `onClick` directly: it arrives as a MouseEvent instead of\n // a keyboard event wearing one, and it bubbles, so a parent that owns the\n // click sees it too. That parent is how a `Popover` or `Menu` opens from\n // a trigger that is not a button.\n e.currentTarget.click();\n }\n onKeyDown?.(e);\n },\n [onKeyDown],\n );\n\n // Compared to undefined rather than using ??, so an explicit null still means \"no tabindex\"\n // instead of falling through to the default.\n return (\n <div\n className={cx(styles.interactableDiv, className)}\n onClick={onClick ? onClickHandler : undefined}\n tabIndex={tabIndex === undefined ? (onClick ? 0 : undefined) : (tabIndex ?? undefined)}\n role={onClick ? 'button' : undefined}\n onKeyDown={onKeyDownHandler}\n ref={ref}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nexport default InteractableDiv;\n"],"mappings":"kSAaA,SAAS,EAAgB,CACvB,YACA,WACA,UACA,YACA,WACA,MACA,GAAG,GACwB,CAC3B,IAAM,EAAiB,EACpB,GAAkC,CAG7B,EAAoB,EAAE,OAAQ,EAAE,aAAa,GACjD,IAAU,CAAC,CACb,EACA,CAAC,CAAO,CACV,EAEM,EAAmB,EACtB,GAAqC,CAChC,EAAiB,CAAC,IAChB,EAAE,MAAQ,KAAK,EAAE,eAAe,EAMpC,EAAE,cAAc,MAAM,GAExB,IAAY,CAAC,CACf,EACA,CAAC,CAAS,CACZ,EAIA,OACE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,gBAAiB,CAAS,EAC/C,QAAS,EAAU,EAAiB,IAAA,GACpC,SAAU,IAAa,IAAA,GAAa,EAAU,EAAI,IAAA,GAAc,GAAY,IAAA,GAC5E,KAAM,EAAU,SAAW,IAAA,GAC3B,UAAW,EACN,MACL,GAAI,EAEH,UACE,CAAA,CAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"gifPreview.module.mjs","names":[],"sources":["../../../../../../package/common/klipyPicker/components/gifPreview/gifPreview.module.pcss"],"sourcesContent":[".gifPreview {\n width: min(420px, 90vw);\n aspect-ratio: 1;\n display: flex;\n flex-wrap: wrap;\n\n --gif-preview-gap-size: 5px;\n\n gap: var(--gif-preview-gap-size);\n position: relative;\n justify-content: center;\n overflow: auto;\n\n &-image {\n background-position: center;\n background-size: cover;\n width: 100%;\n height: 100%;\n\n &-container {\n aspect-ratio: 1;\n background: linear-gradient(\n 45deg,\n var(--primary-color) 10%,\n var(--primary-lighter),\n var(--primary-accent),\n var(--primary-color) 85%\n );\n background-size: 500% 500%;\n animation: gradientBottomLeftToTopRight 1s infinite linear;\n border-radius: var(--default-border-radius);\n overflow: hidden;\n width: min(calc(140px - var(--gif-preview-gap-size)), calc(33.3% - var(--gif-preview-gap-size)));\n }\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"gifPreview.module.mjs","names":[],"sources":["../../../../../../package/common/klipyPicker/components/gifPreview/gifPreview.module.pcss"],"sourcesContent":[".gifPreview {\n width: min(420px, 90vw);\n aspect-ratio: 1;\n display: flex;\n flex-wrap: wrap;\n\n --gif-preview-gap-size: 5px;\n\n gap: var(--gif-preview-gap-size);\n position: relative;\n justify-content: center;\n overflow: auto;\n\n &-image {\n background-position: center;\n background-size: cover;\n width: 100%;\n height: 100%;\n\n &-container {\n aspect-ratio: 1;\n background: linear-gradient(\n 45deg,\n var(--primary-color) 10%,\n var(--primary-lighter),\n var(--primary-accent),\n var(--primary-color) 85%\n );\n background-size: 500% 500%;\n animation: gradientBottomLeftToTopRight 1s infinite linear;\n border-radius: var(--default-border-radius);\n overflow: hidden;\n width: min(calc(140px - var(--gif-preview-gap-size)), calc(33.3% - var(--gif-preview-gap-size)));\n }\n }\n}\n\n/* The gradient stops sweeping and stays a plain block, which still reads as \"loading\". */\n@media (prefers-reduced-motion: reduce) {\n .gifPreview-image-container {\n animation: none;\n }\n}\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"gifView.module.mjs","names":[],"sources":["../../../../../../package/common/klipyPicker/components/gifView/gifView.module.pcss"],"sourcesContent":[".gifView {\n display: flex;\n justify-content: center;\n align-items: center;\n position: relative;\n\n img {\n max-width: 100%;\n border-radius: var(--default-border-radius);\n overflow: hidden;\n }\n\n &-loading {\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n background: linear-gradient(\n 45deg,\n var(--primary-color) 10%,\n var(--primary-lighter),\n var(--primary-accent),\n var(--primary-color) 85%\n );\n background-size: 500% 500%;\n animation: gradientBottomLeftToTopRight 1s infinite linear;\n border-radius: var(--default-border-radius);\n overflow: hidden;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"gifView.module.mjs","names":[],"sources":["../../../../../../package/common/klipyPicker/components/gifView/gifView.module.pcss"],"sourcesContent":[".gifView {\n display: flex;\n justify-content: center;\n align-items: center;\n position: relative;\n\n img {\n max-width: 100%;\n border-radius: var(--default-border-radius);\n overflow: hidden;\n }\n\n &-loading {\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n background: linear-gradient(\n 45deg,\n var(--primary-color) 10%,\n var(--primary-lighter),\n var(--primary-accent),\n var(--primary-color) 85%\n );\n background-size: 500% 500%;\n animation: gradientBottomLeftToTopRight 1s infinite linear;\n border-radius: var(--default-border-radius);\n overflow: hidden;\n }\n}\n\n/* The gradient stops sweeping and stays a plain block, which still reads as \"loading\". */\n@media (prefers-reduced-motion: reduce) {\n .gifView-loading {\n animation: none;\n }\n}\n"],"mappings":""}
@@ -0,0 +1,2 @@
1
+ "use client";var e=e=>e!==void 0&&e>=`0`&&e<=`9`;function t(e){let t=[];for(let n=0;n<e.length;n++)e[n]===`9`&&t.push(n);return t}function n(t,n,r){return[...n].map((n,i)=>n===`9`?e(t[i])?t[i]:r:n).join(``)}function r(e,t,n){return e>=t.length?n.length:t[e]}function i(e,t){let n=t.findIndex(t=>t>=e);return n===-1?t.length:n}function a(e,t){for(let n=t.length-1;n>=0;n--)if(t[n]<e)return n;return-1}function o(r,i,a){let o=t(i),s=n(r,i,a),c=o.findIndex(t=>!e(s[t]));return c===-1?i.length:o[c]}function s(e,t,n){let r=Math.max(0,Math.min(e.length,e.length-(t.length-n))),i=0;for(;i<r&&i<n&&e[i]===t[i];)i++;return{from:i,to:r,inserted:t.slice(i,n)}}function c(o,c,l,u,d){let f=t(u),p=[...n(o,u,d)],m=e=>r(e,f,u),h=(e,t)=>f.filter(n=>n>=e&&n<t),{from:g,to:_,inserted:v}=s(o,c,l),y=[...v].filter(e);if(v.length>0&&y.length===0){let e=i(g,f);return{value:p.join(``),selection:{start:m(e),end:m(e)}}}if(v.length===0){let e=h(g,_),t=a(g,f),n=e.length>0?e:t===-1?[]:[f[t]];for(let e of n)p[e]=d;let r=e.length>0?i(g,f):Math.max(t,0);return{value:p.join(``),selection:{start:m(r),end:m(r)}}}for(let e of h(g,_))p[e]=d;let b=i(g,f);if(b>=f.length){let t=f.findIndex(t=>!e(p[t]));t!==-1&&(b=t)}for(let e of y){if(b>=f.length)break;p[f[b]]=e,b++}return{value:p.join(``),selection:{start:m(b),end:m(b)}}}function l(n,r){return!t(r).some(t=>e(n[t]))}export{o as firstEmptyCaret,l as isBlank,c as maskChange,t as slotIndices,n as toMask};
2
+ //# sourceMappingURL=mask.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mask.mjs","names":[],"sources":["../../../../package/common/maskedInput/mask.ts"],"sourcesContent":["/**\n * A fixed-width digit mask: `99:99`, `99.99.9999`.\n *\n * Fixed means every character keeps its position. Clearing a digit in the middle leaves a hole\n * rather than pulling the rest left, which is what a date or a time wants: deleting the month\n * out of `11.11.2025` must not turn the year into the month.\n *\n * `9` marks a slot that takes a digit. Every other character is a literal the caret steps over\n * and the user cannot type into.\n */\n\nconst DIGIT_SLOT = '9';\n\nexport interface MaskSelection {\n start: number;\n end: number;\n}\n\nexport interface MaskState {\n value: string;\n selection: MaskSelection | null;\n}\n\nconst isDigit = (character: string | undefined): boolean =>\n character !== undefined && character >= '0' && character <= '9';\n\n/** The mask indices that take a digit, in order. */\nexport function slotIndices(mask: string): number[] {\n const slots: number[] = [];\n for (let index = 0; index < mask.length; index++) if (mask[index] === DIGIT_SLOT) slots.push(index);\n return slots;\n}\n\n/** The mask with every slot empty: `__.__.____`. */\nexport function emptyMask(mask: string, placeholder: string): string {\n return [...mask].map((character) => (character === DIGIT_SLOT ? placeholder : character)).join('');\n}\n\n/**\n * Any string as one character per mask index, so slots can be read and written by position.\n *\n * Every other function here assumes a value exactly as long as the mask, with literals where the\n * mask has them. Putting a value through this is what guarantees that, whether it came from a\n * keystroke, from a consumer's state, or from nothing at all.\n */\nexport function toMask(value: string, mask: string, placeholder: string): string {\n return [...mask]\n .map((maskCharacter, index) => {\n if (maskCharacter !== DIGIT_SLOT) return maskCharacter;\n return isDigit(value[index]) ? value[index] : placeholder;\n })\n .join('');\n}\n\n/** Where the caret belongs so the next digit typed lands in `slot`. */\nfunction caretForSlot(slot: number, slots: number[], mask: string): number {\n return slot >= slots.length ? mask.length : slots[slot];\n}\n\n/** The first slot at or after `index`, or the slot count when there is none. */\nfunction slotAtOrAfter(index: number, slots: number[]): number {\n const found = slots.findIndex((position) => position >= index);\n return found === -1 ? slots.length : found;\n}\n\n/** The last slot strictly before `index`, or -1. */\nfunction slotBefore(index: number, slots: number[]): number {\n for (let slot = slots.length - 1; slot >= 0; slot--) if (slots[slot] < index) return slot;\n return -1;\n}\n\n/**\n * Where the caret belongs when the field is entered: the first slot with no digit in it.\n *\n * A mask is as wide when empty as when full, so a click lands wherever it likes, and clicking at\n * the end of `__.__.____` would otherwise leave the caret past every slot with nowhere to put the\n * next digit.\n */\nexport function firstEmptyCaret(value: string, mask: string, placeholder: string): number {\n const slots = slotIndices(mask);\n const filled = toMask(value, mask, placeholder);\n const empty = slots.findIndex((index) => !isDigit(filled[index]));\n return empty === -1 ? mask.length : slots[empty];\n}\n\n/** One edit, as the region of the old value it replaced and the text it put there. */\nfunction editOf(previous: string, raw: string, caret: number) {\n // Everything after the caret is untouched, so the replaced region ends exactly as far from the\n // end of the old value as the caret is from the end of the new one. This is what the caret is\n // for: a prefix/suffix diff alone cannot tell a forward Delete from a Backspace one place along,\n // nor typing `1` over a `1` from typing nothing at all.\n const to = Math.max(0, Math.min(previous.length, previous.length - (raw.length - caret)));\n\n let from = 0;\n while (from < to && from < caret && previous[from] === raw[from]) from++;\n\n return { from, to, inserted: raw.slice(from, caret) };\n}\n\n/**\n * What the field should show after the browser has changed its raw text, and where the caret\n * belongs.\n *\n * Works from the edit rather than from key events, so a paste, a drag, a replaced selection, an\n * autofill and a keystroke all arrive the same way.\n */\nexport function maskChange(previous: string, raw: string, caret: number, mask: string, placeholder: string): MaskState {\n const slots = slotIndices(mask);\n const characters = [...toMask(previous, mask, placeholder)];\n const at = (slot: number) => caretForSlot(slot, slots, mask);\n const held = (from: number, to: number) => slots.filter((index) => index >= from && index < to);\n\n const { from, to, inserted } = editOf(previous, raw, caret);\n const digits = [...inserted].filter(isDigit);\n\n // Something was typed that the mask has no room for: a separator the mask already draws, a\n // letter, a symbol. The old library dropped these, and so does this — writing nothing would\n // still be wrong, because the browser has already put the character in the field.\n if (inserted.length > 0 && digits.length === 0) {\n const caretSlot = slotAtOrAfter(from, slots);\n return { value: characters.join(''), selection: { start: at(caretSlot), end: at(caretSlot) } };\n }\n\n if (inserted.length === 0) {\n const touched = held(from, to);\n\n // Backspace over a literal reads as deleting only that literal, which the user cannot have\n // meant: nothing they typed is there. Take the digit in front of it instead, the way the\n // caret would have if it had never been allowed to rest on a literal.\n const previousSlot = slotBefore(from, slots);\n const target = touched.length > 0 ? touched : previousSlot === -1 ? [] : [slots[previousSlot]];\n\n for (const index of target) characters[index] = placeholder;\n const caretSlot = touched.length > 0 ? slotAtOrAfter(from, slots) : Math.max(previousSlot, 0);\n return { value: characters.join(''), selection: { start: at(caretSlot), end: at(caretSlot) } };\n }\n\n // A replaced selection clears what it covered first, so typing over a highlighted month does\n // not leave its second digit behind.\n for (const index of held(from, to)) characters[index] = placeholder;\n\n let slot = slotAtOrAfter(from, slots);\n // Typed past the last slot: a mask is as wide empty as full, so a click can leave the caret\n // there with nothing after it. Fall back to the first slot still free, which is where the digit\n // was going to end up anyway. A value with no free slot is left alone, as it should be.\n if (slot >= slots.length) {\n const free = slots.findIndex((index) => !isDigit(characters[index]));\n if (free !== -1) slot = free;\n }\n\n for (const digit of digits) {\n if (slot >= slots.length) break;\n characters[slots[slot]] = digit;\n slot++;\n }\n\n return { value: characters.join(''), selection: { start: at(slot), end: at(slot) } };\n}\n\n/** Whether a masked value holds no digits at all, so the field reads as empty. */\nexport function isBlank(value: string, mask: string): boolean {\n return !slotIndices(mask).some((index) => isDigit(value[index]));\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use client";import{mergeRefs as e}from"../utils/mergeRefs.mjs";import{firstEmptyCaret as t,isBlank as n,maskChange as r,toMask as i}from"./mask.mjs";import{useLayoutEffect as a,useRef as o,useState as s}from"react";import{jsx as c}from"react/jsx-runtime";function l(l){let{mask:u,maskPlaceholder:d=`_`,value:f=``,onChange:p,beforeMaskedStateChange:m,onFocus:h,onBlur:g,onClick:_,ref:v,...y}=l,b=o(null),[x,S]=s(!1),C=o(null);a(()=>{C.current!==null&&(b.current?.setSelectionRange(C.current,C.current),C.current=null)});let w=n(f,u),T=w?x?i(``,u,d):``:i(f,u,d),E=e=>{C.current=e,b.current?.setSelectionRange(e,e)},D=e=>{let a=e.target,o=a.value,s=r(T,o,a.selectionStart??o.length,u,d),c=m?m({previousState:{value:T,selection:null},nextState:s}):s,l=i(c.value,u,d),f=c.selection?.start??t(l,u,d);if(l===T){a.value=T,E(f);return}C.current=f,p?.(n(l,u)?``:l)},O=e=>{S(!0),w&&(C.current=0),h?.(e)},k=e=>{let n=e.currentTarget,r=t(T,u,d);n.selectionStart===n.selectionEnd&&(n.selectionStart??0)>r&&n.setSelectionRange(r,r),_?.(e)},A=e=>{S(!1),g?.(e)};return c(`input`,{...y,ref:e(b,v),value:T,onChange:D,onFocus:O,onBlur:A,onClick:k,inputMode:`numeric`})}export{l as default};
2
+ //# sourceMappingURL=maskedInput.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maskedInput.mjs","names":[],"sources":["../../../../package/common/maskedInput/maskedInput.tsx"],"sourcesContent":["import { useLayoutEffect, useRef, useState } from 'react';\nimport type React from 'react';\n\nimport { mergeRefs } from '../utils/mergeRefs';\nimport { firstEmptyCaret, isBlank, maskChange, toMask } from './mask';\nimport type { MaskedInputProps } from './maskedInput.types';\n\n/**\n * A text input under a fixed digit mask, used by `DatePicker` and `TimeInput` through `Input`'s\n * `customInput`. Internal: consumers reach it through those two.\n *\n * Controlled, with one exception. An empty field shows nothing until it is focused, and then shows\n * the bare mask, so a form full of `__.__.____` does not greet someone who has typed nothing. That\n * mask is display only and is never reported through `onChange`, or every untouched date field\n * would submit a value made of underscores.\n */\nfunction MaskedInput(props: MaskedInputProps) {\n const {\n mask,\n maskPlaceholder = '_',\n value = '',\n onChange,\n beforeMaskedStateChange,\n onFocus,\n onBlur,\n onClick,\n ref,\n ...rest\n } = props;\n\n const inputRef = useRef<HTMLInputElement>(null);\n const [isFocused, setIsFocused] = useState(false);\n /**\n * Where the caret belongs after the value the parent holds comes back to us. Set during the\n * change and applied on the next paint, because the browser puts the caret at the end of any\n * value it did not compute itself.\n */\n const caretRef = useRef<number | null>(null);\n\n useLayoutEffect(() => {\n if (caretRef.current === null) return;\n inputRef.current?.setSelectionRange(caretRef.current, caretRef.current);\n caretRef.current = null;\n });\n\n const blank = isBlank(value, mask);\n // Everything below assumes a value exactly as long as the mask. The prop is whatever the parent\n // holds, which on a first render can be a date from somewhere else entirely, so it is put\n // through the mask rather than trusted.\n const display = blank ? (isFocused ? toMask('', mask, maskPlaceholder) : '') : toMask(value, mask, maskPlaceholder);\n\n const setCaret = (position: number) => {\n caretRef.current = position;\n inputRef.current?.setSelectionRange(position, position);\n };\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n const input = event.target;\n const raw = input.value;\n const nextState = maskChange(display, raw, input.selectionStart ?? raw.length, mask, maskPlaceholder);\n\n const state = beforeMaskedStateChange\n ? beforeMaskedStateChange({ previousState: { value: display, selection: null }, nextState })\n : nextState;\n\n const next = toMask(state.value, mask, maskPlaceholder);\n const caret = state.selection?.start ?? firstEmptyCaret(next, mask, maskPlaceholder);\n\n // Nothing came of it — a letter typed into an empty field, or a separator the mask already\n // draws. React re-renders nothing when the value it holds has not changed, so the caret has\n // to be put back here; the layout effect will not run.\n if (next === display) {\n input.value = display;\n setCaret(caret);\n return;\n }\n\n caretRef.current = caret;\n onChange?.(isBlank(next, mask) ? '' : next);\n };\n\n const handleFocus = (event: React.FocusEvent<HTMLInputElement>) => {\n setIsFocused(true);\n // Only when the mask is about to appear. The field showed nothing a moment ago, so whatever\n // caret the browser picked was measured against an empty string. A field with something in it\n // keeps the caret where the user put it, and `handleClick` pulls it back only if it landed\n // past the last free slot.\n if (blank) caretRef.current = 0;\n onFocus?.(event);\n };\n\n /**\n * A click can leave the caret past every slot, because a mask is as wide empty as full. Runs on\n * click rather than on focus: the browser sets the selection on mouse *up*, after focus, so at\n * focus time there is nothing reliable to read.\n */\n const handleClick = (event: React.MouseEvent<HTMLInputElement>) => {\n const input = event.currentTarget;\n const limit = firstEmptyCaret(display, mask, maskPlaceholder);\n // A drag that selected something is left alone; so is a caret already inside the filled part.\n if (input.selectionStart === input.selectionEnd && (input.selectionStart ?? 0) > limit) {\n input.setSelectionRange(limit, limit);\n }\n onClick?.(event);\n };\n\n const handleBlur = (event: React.FocusEvent<HTMLInputElement>) => {\n setIsFocused(false);\n onBlur?.(event);\n };\n\n return (\n <input\n {...rest}\n ref={mergeRefs(inputRef, ref)}\n value={display}\n onChange={handleChange}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onClick={handleClick}\n inputMode='numeric'\n />\n );\n}\n\nexport default MaskedInput;\n"],"mappings":"gQAgBA,SAAS,EAAY,EAAyB,CAC5C,GAAM,CACJ,OACA,kBAAkB,IAClB,QAAQ,GACR,WACA,0BACA,UACA,SACA,UACA,MACA,GAAG,GACD,EAEE,EAAW,EAAyB,IAAI,EACxC,CAAC,EAAW,GAAgB,EAAS,EAAK,EAM1C,EAAW,EAAsB,IAAI,EAE3C,MAAsB,CAChB,EAAS,UAAY,OACzB,EAAS,SAAS,kBAAkB,EAAS,QAAS,EAAS,OAAO,EACtE,EAAS,QAAU,KACrB,CAAC,EAED,IAAM,EAAQ,EAAQ,EAAO,CAAI,EAI3B,EAAU,EAAS,EAAY,EAAO,GAAI,EAAM,CAAe,EAAI,GAAM,EAAO,EAAO,EAAM,CAAe,EAE5G,EAAY,GAAqB,CACrC,EAAS,QAAU,EACnB,EAAS,SAAS,kBAAkB,EAAU,CAAQ,CACxD,EAEM,EAAgB,GAA+C,CACnE,IAAM,EAAQ,EAAM,OACd,EAAM,EAAM,MACZ,EAAY,EAAW,EAAS,EAAK,EAAM,gBAAkB,EAAI,OAAQ,EAAM,CAAe,EAE9F,EAAQ,EACV,EAAwB,CAAE,cAAe,CAAE,MAAO,EAAS,UAAW,IAAK,EAAG,WAAU,CAAC,EACzF,EAEE,EAAO,EAAO,EAAM,MAAO,EAAM,CAAe,EAChD,EAAQ,EAAM,WAAW,OAAS,EAAgB,EAAM,EAAM,CAAe,EAKnF,GAAI,IAAS,EAAS,CACpB,EAAM,MAAQ,EACd,EAAS,CAAK,EACd,MACF,CAEA,EAAS,QAAU,EACnB,IAAW,EAAQ,EAAM,CAAI,EAAI,GAAK,CAAI,CAC5C,EAEM,EAAe,GAA8C,CACjE,EAAa,EAAI,EAKb,IAAO,EAAS,QAAU,GAC9B,IAAU,CAAK,CACjB,EAOM,EAAe,GAA8C,CACjE,IAAM,EAAQ,EAAM,cACd,EAAQ,EAAgB,EAAS,EAAM,CAAe,EAExD,EAAM,iBAAmB,EAAM,eAAiB,EAAM,gBAAkB,GAAK,GAC/E,EAAM,kBAAkB,EAAO,CAAK,EAEtC,IAAU,CAAK,CACjB,EAEM,EAAc,GAA8C,CAChE,EAAa,EAAK,EAClB,IAAS,CAAK,CAChB,EAEA,OACE,EAAC,QAAD,CACE,GAAI,EACJ,IAAK,EAAU,EAAU,CAAG,EAC5B,MAAO,EACP,SAAU,EACV,QAAS,EACT,OAAQ,EACR,QAAS,EACT,UAAU,SACX,CAAA,CAEL"}
@@ -1,2 +1,2 @@
1
- "use client";import{renderIcon as e}from"../utils/renderIcon.mjs";import{PopoverAlign as t,PopoverPlacement as n}from"../popover/popover.types.mjs";import{useFocusBoundary as r}from"../hooks/useFocusBoundary.mjs";import i from"../popover/popover.mjs";import a from"./menu.module.mjs";import{isMenuAction as o,isMenuHeading as s,isMenuSeparator as c}from"./menu.types.mjs";import{cloneElement as l,isValidElement as u,useEffect as d,useId as f,useRef as p,useState as m}from"react";import h from"classnames";import{jsx as g,jsxs as _}from"react/jsx-runtime";var v=600;function y(e,t,n){for(let r=1;r<=e.length;r++){let i=(t+n*r+e.length*r)%e.length,a=e[i];if(o(a)&&!a.disabled)return i}return-1}function b(e){return e.findIndex(e=>o(e)&&!e.disabled)}function x(e){for(let t=e.length-1;t>=0;t--){let n=e[t];if(o(n)&&!n.disabled)return t}return-1}function S({items:S,children:C,onAction:w,isOpen:T,onOpenChange:ee,placement:E=n.Bottom,align:D=t.Start,presentation:O,className:k,style:A,classNames:j,styles:M,...N}){let P=T!==void 0,[F,I]=m(!1),L=P?T:F,[R,z]=m(-1),B=p([]),V=p(null),H=p(null),{restoreFocusToTrigger:U,focusAfterTrigger:W}=r({triggerRef:V,contentRef:H}),G=f(),K=p(`first`),q=p({query:``,timer:void 0}),J=p(!1);function Y(e,t=!1){e&&(J.current=t),P||I(e),ee?.(e)}d(()=>{if(!L)return;if(!J.current){z(-1);return}let e=K.current===`last`?x(S):b(S);z(e);let t=requestAnimationFrame(()=>{B.current[e]?.focus()});return()=>{cancelAnimationFrame(t),K.current=`first`}},[L,S]),d(()=>()=>clearTimeout(q.current.timer),[]);function X(e){e<0||(z(e),B.current[e]?.focus())}function Z(e){Y(!1),e&&U()}function Q(e){if(e.length!==1||!e.trim())return!1;clearTimeout(q.current.timer),q.current.query+=e.toLowerCase(),q.current.timer=setTimeout(()=>{q.current.query=``},v);let t=q.current.query,n=t.length>1&&[...t].every(e=>e===t[0]),r=n?t[0]:t,i=n||t.length===1?R:R-1;for(let e=1;e<=S.length;e++){let t=(i+e+S.length)%S.length,n=S[t];if(o(n)&&!n.disabled&&(B.current[t]?.textContent?.trim().toLowerCase()??``).startsWith(r))return X(t),!0}return!1}function $(e){if(e.key===`ArrowDown`||e.key===`ArrowUp`){if(e.preventDefault(),e.stopPropagation(),L){X(e.key===`ArrowUp`?x(S):b(S));return}K.current=e.key===`ArrowUp`?`last`:`first`,Y(!0,!0)}}function te(e){switch(e.key){case`ArrowDown`:X(y(S,R,1));break;case`ArrowUp`:X(y(S,R,-1));break;case`Home`:X(b(S));break;case`End`:X(x(S));break;case`Escape`:Z(!0);break;case`Tab`:Z(!1),e.shiftKey?U():W();break;default:if(!Q(e.key))return}e.preventDefault(),e.stopPropagation()}function ne(e){let t=S[e];o(t)&&!t.disabled&&(t.onClick?.(),w?.(t.id),Z(!0))}let re=u(C)?l(C,{"aria-haspopup":C.props[`aria-haspopup`]??`menu`,"aria-expanded":C.props[`aria-expanded`]??L,"aria-controls":L?C.props[`aria-controls`]??G:C.props[`aria-controls`]}):C,ie=g(`div`,{ref:H,id:G,role:`menu`,className:h(a.menu,j?.menu),style:M?.menu,onKeyDown:te,children:S.map((t,n)=>c(t)?g(`div`,{role:`separator`,className:h(a.menuSeparator,j?.separator),style:M?.separator},`separator-${n}`):s(t)?g(`div`,{role:`presentation`,className:h(a.menuHeading,j?.heading),style:M?.heading,children:t.heading},`heading-${n}`):_(`button`,{ref:e=>{B.current[n]=e},type:`button`,role:`menuitem`,disabled:t.disabled,tabIndex:n===R?0:-1,className:h(a.menuItem,t.danger&&a.menuItemDanger,j?.item),style:M?.item,onClick:()=>ne(n),onMouseEnter:()=>z(n),children:[t.icon!=null&&e(t.icon,{className:h(a.menuItemIcon,j?.itemIcon),style:M?.itemIcon}),g(`span`,{className:h(a.menuItemLabel,j?.itemLabel),style:M?.itemLabel,children:t.label}),t.shortcut!=null&&g(`span`,{className:h(a.menuItemShortcut,j?.itemShortcut),style:M?.itemShortcut,children:t.shortcut})]},t.id))});return g(i,{...N,isOpen:L,onOpenChange:(e,{fromKeyboard:t})=>Y(e,t),placement:E,align:D,presentation:O,content:ie,focusOnOpen:!1,constrainWidth:!1,classNames:{panel:a.menuPanel},className:h(k,j?.root),style:{...A,...M?.root},children:g(`span`,{ref:V,className:h(a.menuTrigger,j?.trigger),style:M?.trigger,onKeyDown:$,children:re})})}export{S as default};
1
+ "use client";import{renderIcon as e}from"../utils/renderIcon.mjs";import{PopoverAlign as t,PopoverPlacement as n}from"../popover/popover.types.mjs";import{useFocusBoundary as r}from"../hooks/useFocusBoundary.mjs";import i from"../popover/popover.mjs";import a from"./menu.module.mjs";import{formatHotkey as o}from"../hooks/useHotkeys.mjs";import{isMenuAction as s,isMenuHeading as c,isMenuSeparator as l}from"./menu.types.mjs";import{cloneElement as u,isValidElement as d,useEffect as f,useId as p,useRef as m,useState as h}from"react";import g from"classnames";import{jsx as _,jsxs as v}from"react/jsx-runtime";var y=600;function b(e,t,n){for(let r=1;r<=e.length;r++){let i=(t+n*r+e.length*r)%e.length,a=e[i];if(s(a)&&!a.disabled)return i}return-1}function x(e){return e.findIndex(e=>s(e)&&!e.disabled)}function S(e){for(let t=e.length-1;t>=0;t--){let n=e[t];if(s(n)&&!n.disabled)return t}return-1}function C({items:C,children:w,onAction:T,isOpen:E,onOpenChange:D,placement:O=n.Bottom,align:k=t.Start,presentation:A,className:j,style:M,classNames:N,styles:P,...F}){let I=E!==void 0,[ee,L]=h(!1),R=I?E:ee,[z,B]=h(-1),V=m([]),H=m(null),U=m(null),{restoreFocusToTrigger:W,focusAfterTrigger:G}=r({triggerRef:H,contentRef:U}),K=p(),q=m(`first`),J=m({query:``,timer:void 0}),Y=m(!1);function X(e,t=!1){e&&(Y.current=t),I||L(e),D?.(e)}let Z=m(C);f(()=>{Z.current=C}),f(()=>{if(!R)return;if(!Y.current){B(-1);return}let e=Z.current,t=q.current===`last`?S(e):x(e);B(t);let n=requestAnimationFrame(()=>{V.current[t]?.focus()});return()=>{cancelAnimationFrame(n),q.current=`first`}},[R]),f(()=>()=>clearTimeout(J.current.timer),[]);function Q(e){e<0||(B(e),V.current[e]?.focus())}function $(e){X(!1),e&&W()}function te(e){if(e.length!==1||!e.trim())return!1;clearTimeout(J.current.timer),J.current.query+=e.toLowerCase(),J.current.timer=setTimeout(()=>{J.current.query=``},y);let t=J.current.query,n=t.length>1&&[...t].every(e=>e===t[0]),r=n?t[0]:t,i=n||t.length===1?z:z-1;for(let e=1;e<=C.length;e++){let t=(i+e+C.length)%C.length,n=C[t];if(s(n)&&!n.disabled&&(V.current[t]?.textContent?.trim().toLowerCase()??``).startsWith(r))return Q(t),!0}return!1}function ne(e){if(e.key===`ArrowDown`||e.key===`ArrowUp`){if(e.preventDefault(),e.stopPropagation(),R){Q(e.key===`ArrowUp`?S(C):x(C));return}q.current=e.key===`ArrowUp`?`last`:`first`,X(!0,!0)}}function re(e){switch(e.key){case`ArrowDown`:Q(b(C,z,1));break;case`ArrowUp`:Q(z<0?S(C):b(C,z,-1));break;case`Home`:Q(x(C));break;case`End`:Q(S(C));break;case`Escape`:$(!0);break;case`Tab`:$(!1),e.shiftKey?W():G();break;default:if(!te(e.key))return}e.preventDefault(),e.stopPropagation()}function ie(e){let t=C[e];s(t)&&!t.disabled&&(t.onClick?.(),T?.(t.id),$(!0))}let ae=d(w)?u(w,{"aria-haspopup":w.props[`aria-haspopup`]??`menu`,"aria-expanded":w.props[`aria-expanded`]??R,"aria-controls":R?w.props[`aria-controls`]??K:w.props[`aria-controls`]}):w,oe=_(`div`,{ref:U,id:K,role:`menu`,className:g(a.menu,N?.menu),style:P?.menu,onKeyDown:re,children:C.map((t,n)=>l(t)?_(`div`,{role:`separator`,className:g(a.menuSeparator,N?.separator),style:P?.separator},`separator-${n}`):c(t)?_(`div`,{role:`presentation`,className:g(a.menuHeading,N?.heading),style:P?.heading,children:t.heading},`heading-${n}`):v(`button`,{ref:e=>{V.current[n]=e},type:`button`,role:`menuitem`,disabled:t.disabled,tabIndex:n===z?0:-1,className:g(a.menuItem,t.danger&&a.menuItemDanger,N?.item),style:P?.item,onClick:()=>ie(n),onMouseEnter:()=>B(n),children:[t.icon!=null&&e(t.icon,{className:g(a.menuItemIcon,N?.itemIcon),style:P?.itemIcon}),_(`span`,{className:g(a.menuItemLabel,N?.itemLabel),style:P?.itemLabel,children:t.label}),t.shortcut!=null&&_(`span`,{className:g(a.menuItemShortcut,N?.itemShortcut),style:P?.itemShortcut,children:o(t.shortcut)})]},t.id))});return _(i,{...F,isOpen:R,onOpenChange:(e,{fromKeyboard:t})=>X(e,t),placement:O,align:k,presentation:A,content:oe,focusOnOpen:!1,constrainWidth:!1,classNames:{panel:a.menuPanel},className:g(j,N?.root),style:{...M,...P?.root},children:_(`span`,{ref:H,className:g(a.menuTrigger,N?.trigger),style:P?.trigger,onKeyDown:ne,children:ae})})}export{C as default};
2
2
  //# sourceMappingURL=menu.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"menu.mjs","names":[],"sources":["../../../../package/common/menu/menu.tsx"],"sourcesContent":["import { cloneElement, isValidElement, useEffect, useId, useRef, useState, type ReactElement } from 'react';\nimport cx from 'classnames';\n\nimport styles from './menu.module.pcss';\nimport Popover from '../popover';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport { renderIcon } from '../utils/renderIcon';\nimport { useFocusBoundary } from '../hooks/useFocusBoundary';\nimport { isMenuAction, isMenuHeading, isMenuSeparator, type MenuEntry, type MenuProps } from './menu.types';\n\n/** How long a typed run stays one search before it starts over. */\nconst TYPEAHEAD_RESET_MS = 600;\n\n/** Index of the next action that can be focused, wrapping, or -1 if there is none. */\nfunction nextEnabled(items: MenuEntry[], from: number, step: 1 | -1): number {\n for (let i = 1; i <= items.length; i++) {\n // The `items.length * i` term only keeps the value positive for a backwards\n // step; JavaScript's `%` would otherwise return a negative index.\n const index = (from + step * i + items.length * i) % items.length;\n const entry = items[index];\n if (isMenuAction(entry) && !entry.disabled) return index;\n }\n return -1;\n}\n\nfunction firstEnabled(items: MenuEntry[]): number {\n return items.findIndex((entry) => isMenuAction(entry) && !entry.disabled);\n}\n\nfunction lastEnabled(items: MenuEntry[]): number {\n for (let i = items.length - 1; i >= 0; i--) {\n const entry = items[i];\n if (isMenuAction(entry) && !entry.disabled) return i;\n }\n return -1;\n}\n\n/**\n * A menu of actions on a trigger of your choosing.\n *\n * `Popover` does the anchoring, portalling and outside-click work but takes\n * arbitrary `content`, which leaves every consumer to write their own `ul`/`li`\n * and, in practice, to leave out the roles and the arrow keys. This is that list,\n * done once: `role=\"menu\"`, a roving focus that skips disabled entries, Escape\n * back to the trigger, and separators and headings that stay out of the keyboard\n * order.\n */\nfunction Menu({\n items,\n children,\n onAction,\n isOpen: controlledOpen,\n onOpenChange,\n placement = PopoverPlacement.Bottom,\n align = PopoverAlign.Start,\n presentation,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: MenuProps): ReactElement {\n const isControlled = controlledOpen !== undefined;\n const [internalOpen, setInternalOpen] = useState(false);\n const isOpen = isControlled ? controlledOpen : internalOpen;\n\n const [activeIndex, setActiveIndex] = useState(-1);\n const itemRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const triggerRef = useRef<HTMLSpanElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n // Tab leaves the panel in both directions, so the menu needs the same boundary\n // Popover uses: back to the trigger, or on to whatever follows it.\n const { restoreFocusToTrigger, focusAfterTrigger } = useFocusBoundary({ triggerRef, contentRef: menuRef });\n const menuId = useId();\n // Which end to land on when the menu opens: `ArrowUp` on the trigger opens at\n // the bottom, everything else at the top.\n const openAtRef = useRef<'first' | 'last'>('first');\n const typeahead = useRef<{ query: string; timer: ReturnType<typeof setTimeout> | undefined }>({\n query: '',\n timer: undefined,\n });\n\n // Whether a key opened the menu, which decides between landing the focus on an\n // entry and leaving it on the trigger. Set from Popover, which is what sees the\n // trigger's events, or here when an arrow key did the opening.\n const openedByKeyboardRef = useRef(false);\n\n function setOpen(next: boolean, fromKeyboard = false) {\n if (next) openedByKeyboardRef.current = fromKeyboard;\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n }\n\n // Focus follows the active entry rather than the menu keeping focus and\n // pointing at it: the items are real buttons, so Enter and Space are theirs.\n // Popover's own `focusOnOpen` would take the first focusable and stop there;\n // the active index has to move with it, so the menu does it itself.\n useEffect(() => {\n if (!isOpen) return;\n // A pointer open leaves the focus where the pointer put it. A highlight on an\n // entry nobody pointed at reads as a selection, and the mouse is about to land\n // somewhere else anyway; the first arrow key moves in, see the trigger's keys.\n if (!openedByKeyboardRef.current) {\n setActiveIndex(-1);\n return;\n }\n const target = openAtRef.current === 'last' ? lastEnabled(items) : firstEnabled(items);\n setActiveIndex(target);\n // The panel is portalled and animated in, so its buttons exist a frame later.\n const frame = requestAnimationFrame(() => {\n itemRefs.current[target]?.focus();\n });\n return () => {\n cancelAnimationFrame(frame);\n openAtRef.current = 'first';\n };\n }, [isOpen, items]);\n\n useEffect(() => () => clearTimeout(typeahead.current.timer), []);\n\n function moveTo(index: number) {\n if (index < 0) return;\n setActiveIndex(index);\n itemRefs.current[index]?.focus();\n }\n\n function close(returnFocus: boolean) {\n setOpen(false);\n if (returnFocus) restoreFocusToTrigger();\n }\n\n /**\n * Jumps to the next entry whose label starts with what has been typed. The\n * text comes off the rendered button rather than the `label` prop, which is a\n * `ReactNode` and may be an icon, a badge or anything else.\n */\n function handleTypeahead(key: string): boolean {\n if (key.length !== 1 || !key.trim()) return false;\n clearTimeout(typeahead.current.timer);\n typeahead.current.query += key.toLowerCase();\n typeahead.current.timer = setTimeout(() => {\n typeahead.current.query = '';\n }, TYPEAHEAD_RESET_MS);\n\n const query = typeahead.current.query;\n // A repeated single character walks through the entries starting with it,\n // rather than sticking to the first one.\n const repeated = query.length > 1 && [...query].every((c) => c === query[0]);\n const needle = repeated ? query[0] : query;\n const from = repeated || query.length === 1 ? activeIndex : activeIndex - 1;\n\n for (let i = 1; i <= items.length; i++) {\n const index = (from + i + items.length) % items.length;\n const entry = items[index];\n if (!isMenuAction(entry) || entry.disabled) continue;\n const text = itemRefs.current[index]?.textContent?.trim().toLowerCase() ?? '';\n if (text.startsWith(needle)) {\n moveTo(index);\n return true;\n }\n }\n return false;\n }\n\n /** The trigger's own keys, which decide where the menu opens. */\n function handleTriggerKeyDown(event: React.KeyboardEvent) {\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return;\n // Popover opens on these keys too; letting both act would be harmless but\n // this keeps the decision about where to land in one place.\n event.preventDefault();\n event.stopPropagation();\n // Already open means a pointer opened it and the focus never left the trigger,\n // since an entry's own keys never reach here. This is the key that moves in.\n if (isOpen) {\n moveTo(event.key === 'ArrowUp' ? lastEnabled(items) : firstEnabled(items));\n return;\n }\n openAtRef.current = event.key === 'ArrowUp' ? 'last' : 'first';\n setOpen(true, true);\n }\n\n function handleKeyDown(event: React.KeyboardEvent) {\n switch (event.key) {\n case 'ArrowDown':\n moveTo(nextEnabled(items, activeIndex, 1));\n break;\n case 'ArrowUp':\n moveTo(nextEnabled(items, activeIndex, -1));\n break;\n case 'Home':\n moveTo(firstEnabled(items));\n break;\n case 'End':\n moveTo(lastEnabled(items));\n break;\n // Popover handles both of these too, but only once the focus has actually\n // reached the panel: its Escape restores focus on that condition, and its\n // Tab handling acts at the first and last focusable. A menu focuses its\n // first entry a frame after opening, so a key pressed in between would\n // fall through. Here they are unconditional, which is also what a menu\n // wants from Tab: leave, whatever is focused.\n case 'Escape':\n close(true);\n break;\n case 'Tab':\n // Carry on from the trigger, as if the panel had never been in the tab\n // order. Closing and letting the browser take it from here would move on\n // from an entry that is about to be removed, which lands at the top of\n // the document.\n close(false);\n if (event.shiftKey) restoreFocusToTrigger();\n else focusAfterTrigger();\n break;\n default:\n if (!handleTypeahead(event.key)) return;\n }\n event.preventDefault();\n event.stopPropagation();\n }\n\n function handleAction(index: number) {\n const entry = items[index];\n if (!isMenuAction(entry) || entry.disabled) return;\n entry.onClick?.();\n onAction?.(entry.id);\n close(true);\n }\n\n // A screen reader has no way to tell that this button opens a menu unless the\n // button itself says so. Only filled in where the consumer has not, so a\n // trigger that describes itself keeps doing that.\n const triggerWithMenuSemantics = isValidElement<Record<string, unknown>>(children)\n ? cloneElement(children, {\n 'aria-haspopup': children.props['aria-haspopup'] ?? 'menu',\n 'aria-expanded': children.props['aria-expanded'] ?? isOpen,\n 'aria-controls': isOpen ? (children.props['aria-controls'] ?? menuId) : children.props['aria-controls'],\n })\n : children;\n\n const content = (\n <div\n ref={menuRef}\n id={menuId}\n role='menu'\n className={cx(styles.menu, classNames?.menu)}\n style={slotStyles?.menu}\n onKeyDown={handleKeyDown}\n >\n {items.map((entry, index) => {\n if (isMenuSeparator(entry))\n return (\n <div\n // Separators and headings carry no id of their own, and reordering\n // the list re-renders it wholesale anyway.\n key={`separator-${index}`}\n role='separator'\n className={cx(styles.menuSeparator, classNames?.separator)}\n style={slotStyles?.separator}\n />\n );\n\n if (isMenuHeading(entry))\n return (\n <div\n key={`heading-${index}`}\n role='presentation'\n className={cx(styles.menuHeading, classNames?.heading)}\n style={slotStyles?.heading}\n >\n {entry.heading}\n </div>\n );\n\n return (\n <button\n key={entry.id}\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n type='button'\n role='menuitem'\n disabled={entry.disabled}\n // One tab stop for the whole menu: the arrow keys move between items.\n tabIndex={index === activeIndex ? 0 : -1}\n className={cx(styles.menuItem, entry.danger && styles.menuItemDanger, classNames?.item)}\n style={slotStyles?.item}\n onClick={() => handleAction(index)}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {entry.icon != null &&\n renderIcon(entry.icon, {\n className: cx(styles.menuItemIcon, classNames?.itemIcon),\n style: slotStyles?.itemIcon,\n })}\n <span className={cx(styles.menuItemLabel, classNames?.itemLabel)} style={slotStyles?.itemLabel}>\n {entry.label}\n </span>\n {entry.shortcut != null && (\n <span className={cx(styles.menuItemShortcut, classNames?.itemShortcut)} style={slotStyles?.itemShortcut}>\n {entry.shortcut}\n </span>\n )}\n </button>\n );\n })}\n </div>\n );\n\n return (\n <Popover\n {...rest}\n isOpen={isOpen}\n onOpenChange={(next, { fromKeyboard }) => setOpen(next, fromKeyboard)}\n placement={placement}\n align={align}\n presentation={presentation}\n content={content}\n // The list pads its own rows, so a hover highlight reaches the panel edge,\n // and it sizes itself. Focus is the menu's own business, see above.\n focusOnOpen={false}\n constrainWidth={false}\n classNames={{ panel: styles.menuPanel }}\n className={cx(className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n <span\n ref={triggerRef}\n className={cx(styles.menuTrigger, classNames?.trigger)}\n style={slotStyles?.trigger}\n onKeyDown={handleTriggerKeyDown}\n >\n {triggerWithMenuSemantics}\n </span>\n </Popover>\n );\n}\n\nexport default Menu;\n"],"mappings":"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"}
1
+ {"version":3,"file":"menu.mjs","names":[],"sources":["../../../../package/common/menu/menu.tsx"],"sourcesContent":["import { cloneElement, isValidElement, useEffect, useId, useRef, useState, type ReactElement } from 'react';\nimport cx from 'classnames';\n\nimport styles from './menu.module.pcss';\nimport Popover from '../popover';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport { renderIcon } from '../utils/renderIcon';\nimport { useFocusBoundary } from '../hooks/useFocusBoundary';\nimport { formatHotkey } from '../hooks/useHotkeys';\nimport { isMenuAction, isMenuHeading, isMenuSeparator, type MenuEntry, type MenuProps } from './menu.types';\n\n/** How long a typed run stays one search before it starts over. */\nconst TYPEAHEAD_RESET_MS = 600;\n\n/** Index of the next action that can be focused, wrapping, or -1 if there is none. */\nfunction nextEnabled(items: MenuEntry[], from: number, step: 1 | -1): number {\n for (let i = 1; i <= items.length; i++) {\n // The `items.length * i` term only keeps the value positive for a backwards\n // step; JavaScript's `%` would otherwise return a negative index.\n const index = (from + step * i + items.length * i) % items.length;\n const entry = items[index];\n if (isMenuAction(entry) && !entry.disabled) return index;\n }\n return -1;\n}\n\nfunction firstEnabled(items: MenuEntry[]): number {\n return items.findIndex((entry) => isMenuAction(entry) && !entry.disabled);\n}\n\nfunction lastEnabled(items: MenuEntry[]): number {\n for (let i = items.length - 1; i >= 0; i--) {\n const entry = items[i];\n if (isMenuAction(entry) && !entry.disabled) return i;\n }\n return -1;\n}\n\n/**\n * A menu of actions on a trigger of your choosing.\n *\n * `Popover` does the anchoring, portalling and outside-click work but takes\n * arbitrary `content`, which leaves every consumer to write their own `ul`/`li`\n * and, in practice, to leave out the roles and the arrow keys. This is that list,\n * done once: `role=\"menu\"`, a roving focus that skips disabled entries, Escape\n * back to the trigger, and separators and headings that stay out of the keyboard\n * order.\n */\nfunction Menu({\n items,\n children,\n onAction,\n isOpen: controlledOpen,\n onOpenChange,\n placement = PopoverPlacement.Bottom,\n align = PopoverAlign.Start,\n presentation,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: MenuProps): ReactElement {\n const isControlled = controlledOpen !== undefined;\n const [internalOpen, setInternalOpen] = useState(false);\n const isOpen = isControlled ? controlledOpen : internalOpen;\n\n const [activeIndex, setActiveIndex] = useState(-1);\n const itemRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const triggerRef = useRef<HTMLSpanElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n // Tab leaves the panel in both directions, so the menu needs the same boundary\n // Popover uses: back to the trigger, or on to whatever follows it.\n const { restoreFocusToTrigger, focusAfterTrigger } = useFocusBoundary({ triggerRef, contentRef: menuRef });\n const menuId = useId();\n // Which end to land on when the menu opens: `ArrowUp` on the trigger opens at\n // the bottom, everything else at the top.\n const openAtRef = useRef<'first' | 'last'>('first');\n const typeahead = useRef<{ query: string; timer: ReturnType<typeof setTimeout> | undefined }>({\n query: '',\n timer: undefined,\n });\n\n // Whether a key opened the menu, which decides between landing the focus on an\n // entry and leaving it on the trigger. Set from Popover, which is what sees the\n // trigger's events, or here when an arrow key did the opening.\n const openedByKeyboardRef = useRef(false);\n\n function setOpen(next: boolean, fromKeyboard = false) {\n if (next) openedByKeyboardRef.current = fromKeyboard;\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n }\n\n // The effect below needs the entries, but must not re-run when the array is rebuilt. A consumer\n // writes `items={[…]}` inline, so it is a new identity on every render of *their* component:\n // keyed off it, any parent re-render while the menu was open threw the focus back to the first\n // entry, mid-navigation. Declared above the effect that reads it, so it has already run.\n const itemsRef = useRef(items);\n useEffect(() => {\n itemsRef.current = items;\n });\n\n // Focus follows the active entry rather than the menu keeping focus and\n // pointing at it: the items are real buttons, so Enter and Space are theirs.\n // Popover's own `focusOnOpen` would take the first focusable and stop there;\n // the active index has to move with it, so the menu does it itself.\n useEffect(() => {\n if (!isOpen) return;\n // A pointer open leaves the focus where the pointer put it. A highlight on an\n // entry nobody pointed at reads as a selection, and the mouse is about to land\n // somewhere else anyway; the first arrow key moves in, see the trigger's keys.\n if (!openedByKeyboardRef.current) {\n setActiveIndex(-1);\n return;\n }\n const entries = itemsRef.current;\n const target = openAtRef.current === 'last' ? lastEnabled(entries) : firstEnabled(entries);\n setActiveIndex(target);\n // The panel is portalled and animated in, so its buttons exist a frame later.\n const frame = requestAnimationFrame(() => {\n itemRefs.current[target]?.focus();\n });\n return () => {\n cancelAnimationFrame(frame);\n openAtRef.current = 'first';\n };\n }, [isOpen]);\n\n useEffect(() => () => clearTimeout(typeahead.current.timer), []);\n\n function moveTo(index: number) {\n if (index < 0) return;\n setActiveIndex(index);\n itemRefs.current[index]?.focus();\n }\n\n function close(returnFocus: boolean) {\n setOpen(false);\n if (returnFocus) restoreFocusToTrigger();\n }\n\n /**\n * Jumps to the next entry whose label starts with what has been typed. The\n * text comes off the rendered button rather than the `label` prop, which is a\n * `ReactNode` and may be an icon, a badge or anything else.\n */\n function handleTypeahead(key: string): boolean {\n if (key.length !== 1 || !key.trim()) return false;\n clearTimeout(typeahead.current.timer);\n typeahead.current.query += key.toLowerCase();\n typeahead.current.timer = setTimeout(() => {\n typeahead.current.query = '';\n }, TYPEAHEAD_RESET_MS);\n\n const query = typeahead.current.query;\n // A repeated single character walks through the entries starting with it,\n // rather than sticking to the first one.\n const repeated = query.length > 1 && [...query].every((c) => c === query[0]);\n const needle = repeated ? query[0] : query;\n const from = repeated || query.length === 1 ? activeIndex : activeIndex - 1;\n\n for (let i = 1; i <= items.length; i++) {\n const index = (from + i + items.length) % items.length;\n const entry = items[index];\n if (!isMenuAction(entry) || entry.disabled) continue;\n const text = itemRefs.current[index]?.textContent?.trim().toLowerCase() ?? '';\n if (text.startsWith(needle)) {\n moveTo(index);\n return true;\n }\n }\n return false;\n }\n\n /** The trigger's own keys, which decide where the menu opens. */\n function handleTriggerKeyDown(event: React.KeyboardEvent) {\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return;\n // Popover opens on these keys too; letting both act would be harmless but\n // this keeps the decision about where to land in one place.\n event.preventDefault();\n event.stopPropagation();\n // Already open means a pointer opened it and the focus never left the trigger,\n // since an entry's own keys never reach here. This is the key that moves in.\n if (isOpen) {\n moveTo(event.key === 'ArrowUp' ? lastEnabled(items) : firstEnabled(items));\n return;\n }\n openAtRef.current = event.key === 'ArrowUp' ? 'last' : 'first';\n setOpen(true, true);\n }\n\n function handleKeyDown(event: React.KeyboardEvent) {\n switch (event.key) {\n case 'ArrowDown':\n moveTo(nextEnabled(items, activeIndex, 1));\n break;\n case 'ArrowUp':\n // Stepping back from \"nothing active\" lands two short of the end, so the end is named.\n moveTo(activeIndex < 0 ? lastEnabled(items) : nextEnabled(items, activeIndex, -1));\n break;\n case 'Home':\n moveTo(firstEnabled(items));\n break;\n case 'End':\n moveTo(lastEnabled(items));\n break;\n // Popover handles both of these too, but only once the focus has actually\n // reached the panel: its Escape restores focus on that condition, and its\n // Tab handling acts at the first and last focusable. A menu focuses its\n // first entry a frame after opening, so a key pressed in between would\n // fall through. Here they are unconditional, which is also what a menu\n // wants from Tab: leave, whatever is focused.\n case 'Escape':\n close(true);\n break;\n case 'Tab':\n // Carry on from the trigger, as if the panel had never been in the tab\n // order. Closing and letting the browser take it from here would move on\n // from an entry that is about to be removed, which lands at the top of\n // the document.\n close(false);\n if (event.shiftKey) restoreFocusToTrigger();\n else focusAfterTrigger();\n break;\n default:\n if (!handleTypeahead(event.key)) return;\n }\n event.preventDefault();\n event.stopPropagation();\n }\n\n function handleAction(index: number) {\n const entry = items[index];\n if (!isMenuAction(entry) || entry.disabled) return;\n entry.onClick?.();\n onAction?.(entry.id);\n close(true);\n }\n\n // A screen reader has no way to tell that this button opens a menu unless the\n // button itself says so. Only filled in where the consumer has not, so a\n // trigger that describes itself keeps doing that.\n const triggerWithMenuSemantics = isValidElement<Record<string, unknown>>(children)\n ? cloneElement(children, {\n 'aria-haspopup': children.props['aria-haspopup'] ?? 'menu',\n 'aria-expanded': children.props['aria-expanded'] ?? isOpen,\n 'aria-controls': isOpen ? (children.props['aria-controls'] ?? menuId) : children.props['aria-controls'],\n })\n : children;\n\n const content = (\n <div\n ref={menuRef}\n id={menuId}\n role='menu'\n className={cx(styles.menu, classNames?.menu)}\n style={slotStyles?.menu}\n onKeyDown={handleKeyDown}\n >\n {items.map((entry, index) => {\n if (isMenuSeparator(entry))\n return (\n <div\n // Separators and headings carry no id of their own, and reordering\n // the list re-renders it wholesale anyway.\n key={`separator-${index}`}\n role='separator'\n className={cx(styles.menuSeparator, classNames?.separator)}\n style={slotStyles?.separator}\n />\n );\n\n if (isMenuHeading(entry))\n return (\n <div\n key={`heading-${index}`}\n role='presentation'\n className={cx(styles.menuHeading, classNames?.heading)}\n style={slotStyles?.heading}\n >\n {entry.heading}\n </div>\n );\n\n return (\n <button\n key={entry.id}\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n type='button'\n role='menuitem'\n disabled={entry.disabled}\n // One tab stop for the whole menu: the arrow keys move between items.\n tabIndex={index === activeIndex ? 0 : -1}\n className={cx(styles.menuItem, entry.danger && styles.menuItemDanger, classNames?.item)}\n style={slotStyles?.item}\n onClick={() => handleAction(index)}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {entry.icon != null &&\n renderIcon(entry.icon, {\n className: cx(styles.menuItemIcon, classNames?.itemIcon),\n style: slotStyles?.itemIcon,\n })}\n <span className={cx(styles.menuItemLabel, classNames?.itemLabel)} style={slotStyles?.itemLabel}>\n {entry.label}\n </span>\n {entry.shortcut != null && (\n <span className={cx(styles.menuItemShortcut, classNames?.itemShortcut)} style={slotStyles?.itemShortcut}>\n {formatHotkey(entry.shortcut)}\n </span>\n )}\n </button>\n );\n })}\n </div>\n );\n\n return (\n <Popover\n {...rest}\n isOpen={isOpen}\n onOpenChange={(next, { fromKeyboard }) => setOpen(next, fromKeyboard)}\n placement={placement}\n align={align}\n presentation={presentation}\n content={content}\n // The list pads its own rows, so a hover highlight reaches the panel edge,\n // and it sizes itself. Focus is the menu's own business, see above.\n focusOnOpen={false}\n constrainWidth={false}\n classNames={{ panel: styles.menuPanel }}\n className={cx(className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n <span\n ref={triggerRef}\n className={cx(styles.menuTrigger, classNames?.trigger)}\n style={slotStyles?.trigger}\n onKeyDown={handleTriggerKeyDown}\n >\n {triggerWithMenuSemantics}\n </span>\n </Popover>\n );\n}\n\nexport default Menu;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"menu.types.mjs","names":[],"sources":["../../../../package/common/menu/menu.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\nimport type { IconContent } from '../types/icon.types';\nimport type { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport type { Presentation } from '../configProvider/presentation.types';\n\n/** One thing the menu can do. */\nexport interface MenuAction {\n /** Stable id, also what `onAction` reports. */\n id: string;\n label: ReactNode;\n icon?: IconContent;\n /**\n * Keyboard hint on the trailing edge, e.g. `⌘K`. Display only: binding the\n * shortcut is yours, since only you know what else is listening.\n */\n shortcut?: ReactNode;\n disabled?: boolean;\n /** Renders in the destructive colour. For deleting, discarding, revoking. */\n danger?: boolean;\n onClick?: () => void;\n}\n\n/** A line between groups of actions. */\nexport interface MenuSeparator {\n separator: true;\n}\n\n/** A label over the actions that follow it. */\nexport interface MenuHeading {\n heading: ReactNode;\n}\n\nexport type MenuEntry = MenuAction | MenuSeparator | MenuHeading;\n\nexport function isMenuSeparator(entry: MenuEntry): entry is MenuSeparator {\n return 'separator' in entry;\n}\n\nexport function isMenuHeading(entry: MenuEntry): entry is MenuHeading {\n return 'heading' in entry;\n}\n\nexport function isMenuAction(entry: MenuEntry): entry is MenuAction {\n return !isMenuSeparator(entry) && !isMenuHeading(entry);\n}\n\nexport type MenuSlots =\n | 'root'\n | 'trigger'\n | 'menu'\n | 'item'\n | 'itemIcon'\n | 'itemLabel'\n | 'itemShortcut'\n | 'separator'\n | 'heading';\n\nexport interface MenuProps extends Omit<HtmlProps, 'onSelect'> {\n /** What the menu offers, in the order it is read. */\n items: MenuEntry[];\n /** The element that opens the menu. */\n children?: ReactNode;\n /** Called with the id of the action that was picked, after its own `onClick`. */\n onAction?: (id: string) => void;\n /** Controlled open state. Leave it out to let the menu manage its own. */\n isOpen?: boolean;\n onOpenChange?: (isOpen: boolean) => void;\n /** Which side of the trigger the menu opens on (default `Bottom`). */\n placement?: PopoverPlacement;\n /** Which edge it lines up with on the cross axis (default `Start`). */\n align?: PopoverAlign;\n /** Anchored to the trigger, pinned to the bottom of the screen, or the latter only on touch. */\n presentation?: Presentation;\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<MenuSlots>;\n styles?: SlotStyles<MenuSlots>;\n}\n"],"mappings":"aAmCA,SAAgB,EAAgB,EAA0C,CACxE,MAAO,cAAe,CACxB,CAEA,SAAgB,EAAc,EAAwC,CACpE,MAAO,YAAa,CACtB,CAEA,SAAgB,EAAa,EAAuC,CAClE,MAAO,CAAC,EAAgB,CAAK,GAAK,CAAC,EAAc,CAAK,CACxD"}
1
+ {"version":3,"file":"menu.types.mjs","names":[],"sources":["../../../../package/common/menu/menu.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\nimport type { IconContent } from '../types/icon.types';\nimport type { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport type { Presentation } from '../configProvider/presentation.types';\n\n/** One thing the menu can do. */\nexport interface MenuAction {\n /** Stable id, also what `onAction` reports. */\n id: string;\n label: ReactNode;\n icon?: IconContent;\n /**\n * A keyboard shortcut for this action, in `useHotkeys` spelling: `'mod+k'`,\n * `'shift+f2'`, `'delete'`. Shown on the trailing edge written for the\n * platform: `⌘K` on an Apple one, `Ctrl+K` elsewhere.\n *\n * The menu draws it and nothing more. Binding is yours, because only the app\n * knows what else is listening and whether the shortcut should work at all\n * times or only while the menu is open. `menuHotkeys` turns these entries\n * into a `useHotkeys` map, so the one spelling covers both ends.\n */\n shortcut?: string;\n disabled?: boolean;\n /** Renders in the destructive colour. For deleting, discarding, revoking. */\n danger?: boolean;\n onClick?: () => void;\n}\n\n/** A line between groups of actions. */\nexport interface MenuSeparator {\n separator: true;\n}\n\n/** A label over the actions that follow it. */\nexport interface MenuHeading {\n heading: ReactNode;\n}\n\nexport type MenuEntry = MenuAction | MenuSeparator | MenuHeading;\n\nexport function isMenuSeparator(entry: MenuEntry): entry is MenuSeparator {\n return 'separator' in entry;\n}\n\nexport function isMenuHeading(entry: MenuEntry): entry is MenuHeading {\n return 'heading' in entry;\n}\n\nexport function isMenuAction(entry: MenuEntry): entry is MenuAction {\n return !isMenuSeparator(entry) && !isMenuHeading(entry);\n}\n\nexport type MenuSlots =\n | 'root'\n | 'trigger'\n | 'menu'\n | 'item'\n | 'itemIcon'\n | 'itemLabel'\n | 'itemShortcut'\n | 'separator'\n | 'heading';\n\nexport interface MenuProps extends Omit<HtmlProps, 'onSelect'> {\n /** What the menu offers, in the order it is read. */\n items: MenuEntry[];\n /** The element that opens the menu. */\n children?: ReactNode;\n /** Called with the id of the action that was picked, after its own `onClick`. */\n onAction?: (id: string) => void;\n /** Controlled open state. Leave it out to let the menu manage its own. */\n isOpen?: boolean;\n onOpenChange?: (isOpen: boolean) => void;\n /** Which side of the trigger the menu opens on (default `Bottom`). */\n placement?: PopoverPlacement;\n /** Which edge it lines up with on the cross axis (default `Start`). */\n align?: PopoverAlign;\n /** Anchored to the trigger, pinned to the bottom of the screen, or the latter only on touch. */\n presentation?: Presentation;\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<MenuSlots>;\n styles?: SlotStyles<MenuSlots>;\n}\n"],"mappings":"aAyCA,SAAgB,EAAgB,EAA0C,CACxE,MAAO,cAAe,CACxB,CAEA,SAAgB,EAAc,EAAwC,CACpE,MAAO,YAAa,CACtB,CAEA,SAAgB,EAAa,EAAuC,CAClE,MAAO,CAAC,EAAgB,CAAK,GAAK,CAAC,EAAc,CAAK,CACxD"}
@@ -0,0 +1,2 @@
1
+ "use client";import{isMenuAction as e}from"./menu.types.mjs";function t(t,n){let r={};for(let i of t)e(i)&&!i.disabled&&i.shortcut&&(r[i.shortcut]=()=>{i.onClick?.(),n?.(i.id)});return r}export{t as menuHotkeys};
2
+ //# sourceMappingURL=menuHotkeys.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menuHotkeys.mjs","names":[],"sources":["../../../../package/common/menu/menuHotkeys.ts"],"sourcesContent":["import type { HotkeyMap } from '../hooks/useHotkeys';\nimport { isMenuAction, type MenuEntry } from './menu.types';\n\n/**\n * The bindings for a menu's `shortcut` entries, to hand to `useHotkeys` yourself.\n *\n * The menu draws a shortcut but never listens for one, because only the app knows what else is\n * listening: binding it here as well as in an app's own keymap would run the action twice, and\n * whether a shortcut should work at all times or only while the menu is open is the app's\n * question, not the menu's. Calling this keeps the answer in one spelling, so the hint the menu\n * draws cannot drift from what actually fires.\n *\n * ```tsx\n * useHotkeys(menuHotkeys(items, run)); // whenever the page is up\n * useHotkeys(menuHotkeys(items, run), { enabled: isOpen }); // only while the menu is open\n * ```\n *\n * Runs each entry the way clicking it does: its own `onClick`, then `onAction`. A `disabled`\n * entry, and an entry with no `shortcut`, is left out.\n */\nexport function menuHotkeys(items: MenuEntry[], onAction?: (id: string) => void): HotkeyMap {\n const bindings: HotkeyMap = {};\n for (const entry of items) {\n if (!isMenuAction(entry) || entry.disabled || !entry.shortcut) continue;\n bindings[entry.shortcut] = () => {\n entry.onClick?.();\n onAction?.(entry.id);\n };\n }\n return bindings;\n}\n"],"mappings":"6DAoBA,SAAgB,EAAY,EAAoB,EAA4C,CAC1F,IAAM,EAAsB,CAAC,EAC7B,IAAK,IAAM,KAAS,EACb,EAAa,CAAK,GAAK,GAAM,UAAa,EAAM,WACrD,EAAS,EAAM,cAAkB,CAC/B,EAAM,UAAU,EAChB,IAAW,EAAM,EAAE,CACrB,GAEF,OAAO,CACT"}
@@ -1,2 +1,2 @@
1
- "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{usePresentationDefault as n}from"../configProvider/usePresentationDefault.mjs";import r from"../bodyEnd/bodyEnd.mjs";import i from"../styles/sheet.module.mjs";import{useVisualViewportSize as a}from"../hooks/useVisualViewportSize.mjs";import o from"../hooks/useSheet.mjs";import{useOverlay as s}from"../hooks/useOverlay.mjs";import c from"./modal.module.mjs";import{useEffect as l,useId as u,useRef as d,useState as f}from"react";import p from"classnames";import{FontAwesomeIcon as m}from"@fortawesome/react-fontawesome";import{faXmark as h}from"@fortawesome/free-solid-svg-icons";import{jsx as g,jsxs as _}from"react/jsx-runtime";var v={close:`Close`};function y(y){let{children:b=null,title:x=``,isOpen:S=!1,onClose:C=()=>null,className:w=``,style:T,hideHeader:E=!1,closeOnEscape:D=!0,presentation:O,classNames:k,styles:A,labels:j,...M}=e(`Modal`,y),N=t(`Modal`,j,v),[P,F]=f(S),[I,L]=f(S),R=d(null),z=u(),{height:B,offsetTop:V}=a(),H=n(),{isSheet:U,sheetStyle:W}=o(O??H);if(l(()=>{S?(F(S),setTimeout(()=>L(!0),1)):(L(!1),setTimeout(()=>F(S),300))},[S]),s({isActive:P&&I,containerRef:R,onEscape:D?C:void 0}),!P)return null;let G=!E&&!!x;return g(r,{children:_(`div`,{className:p(c.modalContainer,k?.container),style:{height:B,top:V,...A?.container},children:[g(`div`,{className:p(c.modalWrapper,I&&c.modalWrapperShown,k?.backdrop),style:A?.backdrop,onClick:C}),I&&_(`div`,{...M,ref:R,role:`dialog`,"aria-modal":`true`,"aria-labelledby":G?z:void 0,tabIndex:-1,className:p(c.modal,I&&c.modalShown,U&&[i.sheet,i.sheetSurface,c.modalSheet],w,k?.modal),style:{...U?W:void 0,...T,...A?.modal},onClick:e=>e.stopPropagation(),children:[!E&&_(`div`,{className:p(c.modalHeader,k?.header),style:A?.header,children:[g(`div`,{id:z,className:k?.title,style:A?.title,children:x}),g(`button`,{type:`button`,onClick:C,"aria-label":N.close,className:p(c.modalCloseButton,k?.closeButton),style:A?.closeButton,children:g(m,{icon:h})})]}),g(`div`,{className:p(c.modalBody,k?.body),style:A?.body,children:b})]})]})})}export{y as default};
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{usePresentationDefault as n}from"../configProvider/usePresentationDefault.mjs";import r from"../bodyEnd/bodyEnd.mjs";import i from"../styles/sheet.module.mjs";import{useVisualViewportSize as a}from"../hooks/useVisualViewportSize.mjs";import o from"../hooks/useSheet.mjs";import{useOverlay as s}from"../hooks/useOverlay.mjs";import c from"../styles/scrollFade.module.mjs";import l from"./modal.module.mjs";import{useScrollEdges as u}from"../hooks/useScrollEdges.mjs";import{useEffect as d,useId as f,useRef as p,useState as m}from"react";import h from"classnames";import{FontAwesomeIcon as g}from"@fortawesome/react-fontawesome";import{faXmark as _}from"@fortawesome/free-solid-svg-icons";import{jsx as v,jsxs as y}from"react/jsx-runtime";var b={close:`Close`};function x(x){let{children:S=null,title:C=``,isOpen:w=!1,onClose:T=()=>null,footer:E=null,className:D=``,style:O,hideHeader:k=!1,closeOnEscape:A=!0,presentation:j,classNames:M,styles:N,labels:P,...F}=e(`Modal`,x),I=t(`Modal`,P,b),[L,R]=m(w),[z,B]=m(w),V=p(null),H=p(null),U=f(),{height:W,offsetTop:G}=a(),K=n(),{isSheet:q,sheetStyle:J}=o(j??K);d(()=>{w?(R(w),setTimeout(()=>B(!0),1)):(B(!1),setTimeout(()=>R(w),300))},[w]),s({isActive:L&&z,containerRef:V,onEscape:A?T:void 0});let{hasStart:Y,hasEnd:X}=u(H,{isEnabled:L&&z});if(!L)return null;let Z=!k&&!!C;return v(r,{children:y(`div`,{className:h(l.modalContainer,M?.container),style:{height:W,top:G,...N?.container},children:[v(`div`,{className:h(l.modalWrapper,z&&l.modalWrapperShown,M?.backdrop),style:N?.backdrop,onClick:T}),z&&y(`div`,{...F,ref:V,role:`dialog`,"aria-modal":`true`,"aria-labelledby":Z?U:void 0,tabIndex:-1,className:h(l.modal,z&&l.modalShown,q&&[i.sheet,i.sheetSurface,l.modalSheet],D,M?.modal),style:{...q?J:void 0,...O,...N?.modal},onClick:e=>e.stopPropagation(),children:[!k&&y(`div`,{className:h(l.modalHeader,M?.header),style:N?.header,children:[v(`div`,{id:U,className:M?.title,style:N?.title,children:C}),v(`button`,{type:`button`,onClick:T,"aria-label":I.close,className:h(l.modalCloseButton,M?.closeButton),style:N?.closeButton,children:v(g,{icon:_})})]}),v(`div`,{ref:H,className:h(l.modalBody,c.scrollFade,c.scrollFadeY,Y&&c.scrollFadeFadedStart,X&&c.scrollFadeFadedEnd,M?.body),style:N?.body,children:S}),E&&v(`div`,{className:h(l.modalFooter,M?.footer),style:N?.footer,children:E})]})]})})}export{x as default};
2
2
  //# sourceMappingURL=modal.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"modal.mjs","names":[],"sources":["../../../../package/common/modal/modal.tsx"],"sourcesContent":["import cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './modal.module.pcss';\nimport sheetStyles from 'components/common/styles/sheet.module.pcss';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faXmark as closeIcon } from '@fortawesome/free-solid-svg-icons';\nimport { ModalProps } from './modal.types';\nimport type { ModalLabels } from './modal.types';\nimport { useEffect, useId, useRef, useState } from 'react';\nimport { useVisualViewportSize } from 'components/common/hooks/useVisualViewportSize';\nimport { useOverlay } from 'components/common/hooks/useOverlay';\nimport { useSheet } from 'components/common/hooks/useSheet';\nimport { useComponentDefaults, useLabels, usePresentationDefault } from 'components/common/configProvider';\n\nconst DEFAULT_LABELS: Required<ModalLabels> = {\n close: 'Close',\n};\n\nfunction Modal(props: ModalProps) {\n const {\n children = null,\n title = '',\n isOpen = false,\n onClose = () => null,\n className = '',\n style,\n hideHeader = false,\n closeOnEscape = true,\n presentation: presentationProp,\n classNames,\n styles: slotStyles,\n labels,\n ...rest\n } = useComponentDefaults('Modal', props);\n const text = useLabels('Modal', labels, DEFAULT_LABELS);\n const [isRendered, setIsRendered] = useState(isOpen);\n const [animateIn, setAnimateIn] = useState(isOpen);\n const modalRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n // Centering/sizing against the actually-visible viewport (not the full layout viewport) keeps\n // the modal — and whatever's focused inside it — from ending up under a mobile keyboard.\n const { height: viewportHeight, offsetTop: viewportOffsetTop } = useVisualViewportSize();\n // Explicit prop → this component's global default → the app-wide one. There's no built-in\n // fallback to add: `Default` and no presentation at all both mean the ordinary centred dialog.\n const appPresentation = usePresentationDefault();\n const presentation = presentationProp ?? appPresentation;\n const { isSheet, sheetStyle } = useSheet(presentation);\n\n useEffect(() => {\n if (isOpen) {\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setIsRendered(isOpen);\n setTimeout(() => setAnimateIn(true), 1);\n } else {\n setAnimateIn(false);\n setTimeout(() => setIsRendered(isOpen), 300);\n }\n }, [isOpen]);\n\n // Keyed on `animateIn` rather than `isOpen`, because the panel this needs to focus and trap\n // focus inside of only mounts once that flips.\n useOverlay({\n isActive: isRendered && animateIn,\n containerRef: modalRef,\n onEscape: closeOnEscape ? onClose : undefined,\n });\n\n if (!isRendered) return null;\n\n const hasHeaderTitle = !hideHeader && !!title;\n\n return (\n <BodyEnd>\n <div\n className={cx(styles.modalContainer, classNames?.container)}\n style={{ height: viewportHeight, top: viewportOffsetTop, ...slotStyles?.container }}\n >\n <div\n className={cx(styles.modalWrapper, animateIn && styles.modalWrapperShown, classNames?.backdrop)}\n style={slotStyles?.backdrop}\n onClick={onClose}\n />\n {animateIn && (\n <div\n {...rest}\n ref={modalRef}\n role='dialog'\n aria-modal='true'\n aria-labelledby={hasHeaderTitle ? titleId : undefined}\n // Focusable so the trap has somewhere to put focus when the content has no tabbables.\n tabIndex={-1}\n className={cx(\n styles.modal,\n animateIn && styles.modalShown,\n // The panel is its own sheet surface here: there's no inner panel to fill, since\n // Modal already splits itself into a fixed header and a scrolling body.\n isSheet && [sheetStyles.sheet, sheetStyles.sheetSurface, styles.modalSheet],\n className,\n classNames?.modal,\n )}\n style={{ ...(isSheet ? sheetStyle : undefined), ...style, ...slotStyles?.modal }}\n onClick={(e) => e.stopPropagation()}\n >\n {!hideHeader && (\n <div className={cx(styles.modalHeader, classNames?.header)} style={slotStyles?.header}>\n <div id={titleId} className={classNames?.title} style={slotStyles?.title}>\n {title}\n </div>\n <button\n type='button'\n onClick={onClose}\n aria-label={text.close}\n className={cx(styles.modalCloseButton, classNames?.closeButton)}\n style={slotStyles?.closeButton}\n >\n <FontAwesomeIcon icon={closeIcon} />\n </button>\n </div>\n )}\n <div className={cx(styles.modalBody, classNames?.body)} style={slotStyles?.body}>\n {children}\n </div>\n </div>\n )}\n </div>\n </BodyEnd>\n );\n}\n\nexport default Modal;\n"],"mappings":"wxBAeA,IAAM,EAAwC,CAC5C,MAAO,OACT,EAEA,SAAS,EAAM,EAAmB,CAChC,GAAM,CACJ,WAAW,KACX,QAAQ,GACR,SAAS,GACT,cAAgB,KAChB,YAAY,GACZ,QACA,aAAa,GACb,gBAAgB,GAChB,aAAc,EACd,aACA,OAAQ,EACR,SACA,GAAG,GACD,EAAqB,QAAS,CAAK,EACjC,EAAO,EAAU,QAAS,EAAQ,CAAc,EAChD,CAAC,EAAY,GAAiB,EAAS,CAAM,EAC7C,CAAC,EAAW,GAAgB,EAAS,CAAM,EAC3C,EAAW,EAAuB,IAAI,EACtC,EAAU,EAAM,EAGhB,CAAE,OAAQ,EAAgB,UAAW,GAAsB,EAAsB,EAGjF,EAAkB,EAAuB,EAEzC,CAAE,UAAS,cAAe,EADX,GAAoB,CACY,EAqBrD,GAnBA,MAAgB,CACV,GAEF,EAAc,CAAM,EACpB,eAAiB,EAAa,EAAI,EAAG,CAAC,IAEtC,EAAa,EAAK,EAClB,eAAiB,EAAc,CAAM,EAAG,GAAG,EAE/C,EAAG,CAAC,CAAM,CAAC,EAIX,EAAW,CACT,SAAU,GAAc,EACxB,aAAc,EACd,SAAU,EAAgB,EAAU,IAAA,EACtC,CAAC,EAEG,CAAC,EAAY,OAAO,KAExB,IAAM,EAAiB,CAAC,GAAc,CAAC,CAAC,EAExC,OACE,EAAC,EAAD,CAAA,SACE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,eAAgB,GAAY,SAAS,EAC1D,MAAO,CAAE,OAAQ,EAAgB,IAAK,EAAmB,GAAG,GAAY,SAAU,EAFpF,SAAA,CAIE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,aAAc,GAAa,EAAO,kBAAmB,GAAY,QAAQ,EAC9F,MAAO,GAAY,SACnB,QAAS,CACV,CAAA,EACA,GACC,EAAC,MAAD,CACE,GAAI,EACJ,IAAK,EACL,KAAK,SACL,aAAW,OACX,kBAAiB,EAAiB,EAAU,IAAA,GAE5C,SAAU,GACV,UAAW,EACT,EAAO,MACP,GAAa,EAAO,WAGpB,GAAW,CAAC,EAAY,MAAO,EAAY,aAAc,EAAO,UAAU,EAC1E,EACA,GAAY,KACd,EACA,MAAO,CAAE,GAAI,EAAU,EAAa,IAAA,GAAY,GAAG,EAAO,GAAG,GAAY,KAAM,EAC/E,QAAU,GAAM,EAAE,gBAAgB,EAlBpC,SAAA,CAoBG,CAAC,GACA,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,YAAa,GAAY,MAAM,EAAG,MAAO,GAAY,OAA/E,SAAA,CACE,EAAC,MAAD,CAAK,GAAI,EAAS,UAAW,GAAY,MAAO,MAAO,GAAY,MAChE,SAAA,CACE,CAAA,EACL,EAAC,SAAD,CACE,KAAK,SACL,QAAS,EACT,aAAY,EAAK,MACjB,UAAW,EAAG,EAAO,iBAAkB,GAAY,WAAW,EAC9D,MAAO,GAAY,YAEnB,SAAA,EAAC,EAAD,CAAiB,KAAM,CAAY,CAAA,CAC7B,CAAA,CACL,CAEP,CAAA,EAAA,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,UAAW,GAAY,IAAI,EAAG,MAAO,GAAY,KACxE,UACE,CAAA,CACF,CAEJ,CAAA,CAAA,CACE,CAAA,CAAA,CAAA,CAEb"}
1
+ {"version":3,"file":"modal.mjs","names":[],"sources":["../../../../package/common/modal/modal.tsx"],"sourcesContent":["import cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './modal.module.pcss';\nimport sheetStyles from 'components/common/styles/sheet.module.pcss';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faXmark as closeIcon } from '@fortawesome/free-solid-svg-icons';\nimport { ModalProps } from './modal.types';\nimport type { ModalLabels } from './modal.types';\nimport { useEffect, useId, useRef, useState } from 'react';\nimport { useVisualViewportSize } from 'components/common/hooks/useVisualViewportSize';\nimport { useOverlay } from 'components/common/hooks/useOverlay';\nimport { useSheet } from 'components/common/hooks/useSheet';\nimport { useScrollEdges } from 'components/common/hooks/useScrollEdges';\nimport fadeStyles from 'components/common/styles/scrollFade.module.pcss';\nimport { useComponentDefaults, useLabels, usePresentationDefault } from 'components/common/configProvider';\n\nconst DEFAULT_LABELS: Required<ModalLabels> = {\n close: 'Close',\n};\n\nfunction Modal(props: ModalProps) {\n const {\n children = null,\n title = '',\n isOpen = false,\n onClose = () => null,\n footer = null,\n className = '',\n style,\n hideHeader = false,\n closeOnEscape = true,\n presentation: presentationProp,\n classNames,\n styles: slotStyles,\n labels,\n ...rest\n } = useComponentDefaults('Modal', props);\n const text = useLabels('Modal', labels, DEFAULT_LABELS);\n const [isRendered, setIsRendered] = useState(isOpen);\n const [animateIn, setAnimateIn] = useState(isOpen);\n const modalRef = useRef<HTMLDivElement>(null);\n const bodyRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n // Centering/sizing against the actually-visible viewport (not the full layout viewport) keeps\n // the modal — and whatever's focused inside it — from ending up under a mobile keyboard.\n const { height: viewportHeight, offsetTop: viewportOffsetTop } = useVisualViewportSize();\n // Explicit prop → this component's global default → the app-wide one. There's no built-in\n // fallback to add: `Default` and no presentation at all both mean the ordinary centred dialog.\n const appPresentation = usePresentationDefault();\n const presentation = presentationProp ?? appPresentation;\n const { isSheet, sheetStyle } = useSheet(presentation);\n\n useEffect(() => {\n if (isOpen) {\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setIsRendered(isOpen);\n setTimeout(() => setAnimateIn(true), 1);\n } else {\n setAnimateIn(false);\n setTimeout(() => setIsRendered(isOpen), 300);\n }\n }, [isOpen]);\n\n // Keyed on `animateIn` rather than `isOpen`, because the panel this needs to focus and trap\n // focus inside of only mounts once that flips.\n useOverlay({\n isActive: isRendered && animateIn,\n containerRef: modalRef,\n onEscape: closeOnEscape ? onClose : undefined,\n });\n\n const { hasStart, hasEnd } = useScrollEdges(bodyRef, { isEnabled: isRendered && animateIn });\n\n if (!isRendered) return null;\n\n const hasHeaderTitle = !hideHeader && !!title;\n\n return (\n <BodyEnd>\n <div\n className={cx(styles.modalContainer, classNames?.container)}\n style={{ height: viewportHeight, top: viewportOffsetTop, ...slotStyles?.container }}\n >\n <div\n className={cx(styles.modalWrapper, animateIn && styles.modalWrapperShown, classNames?.backdrop)}\n style={slotStyles?.backdrop}\n onClick={onClose}\n />\n {animateIn && (\n <div\n {...rest}\n ref={modalRef}\n role='dialog'\n aria-modal='true'\n aria-labelledby={hasHeaderTitle ? titleId : undefined}\n // Focusable so the trap has somewhere to put focus when the content has no tabbables.\n tabIndex={-1}\n className={cx(\n styles.modal,\n animateIn && styles.modalShown,\n // The panel is its own sheet surface here: there's no inner panel to fill, since\n // Modal already splits itself into a fixed header and a scrolling body.\n isSheet && [sheetStyles.sheet, sheetStyles.sheetSurface, styles.modalSheet],\n className,\n classNames?.modal,\n )}\n style={{ ...(isSheet ? sheetStyle : undefined), ...style, ...slotStyles?.modal }}\n onClick={(e) => e.stopPropagation()}\n >\n {!hideHeader && (\n <div className={cx(styles.modalHeader, classNames?.header)} style={slotStyles?.header}>\n <div id={titleId} className={classNames?.title} style={slotStyles?.title}>\n {title}\n </div>\n <button\n type='button'\n onClick={onClose}\n aria-label={text.close}\n className={cx(styles.modalCloseButton, classNames?.closeButton)}\n style={slotStyles?.closeButton}\n >\n <FontAwesomeIcon icon={closeIcon} />\n </button>\n </div>\n )}\n <div\n ref={bodyRef}\n className={cx(\n styles.modalBody,\n fadeStyles.scrollFade,\n fadeStyles.scrollFadeY,\n hasStart && fadeStyles.scrollFadeFadedStart,\n hasEnd && fadeStyles.scrollFadeFadedEnd,\n classNames?.body,\n )}\n style={slotStyles?.body}\n >\n {children}\n </div>\n {footer && (\n <div className={cx(styles.modalFooter, classNames?.footer)} style={slotStyles?.footer}>\n {footer}\n </div>\n )}\n </div>\n )}\n </div>\n </BodyEnd>\n );\n}\n\nexport default Modal;\n"],"mappings":"o4BAiBA,IAAM,EAAwC,CAC5C,MAAO,OACT,EAEA,SAAS,EAAM,EAAmB,CAChC,GAAM,CACJ,WAAW,KACX,QAAQ,GACR,SAAS,GACT,cAAgB,KAChB,SAAS,KACT,YAAY,GACZ,QACA,aAAa,GACb,gBAAgB,GAChB,aAAc,EACd,aACA,OAAQ,EACR,SACA,GAAG,GACD,EAAqB,QAAS,CAAK,EACjC,EAAO,EAAU,QAAS,EAAQ,CAAc,EAChD,CAAC,EAAY,GAAiB,EAAS,CAAM,EAC7C,CAAC,EAAW,GAAgB,EAAS,CAAM,EAC3C,EAAW,EAAuB,IAAI,EACtC,EAAU,EAAuB,IAAI,EACrC,EAAU,EAAM,EAGhB,CAAE,OAAQ,EAAgB,UAAW,GAAsB,EAAsB,EAGjF,EAAkB,EAAuB,EAEzC,CAAE,UAAS,cAAe,EADX,GAAoB,CACY,EAErD,MAAgB,CACV,GAEF,EAAc,CAAM,EACpB,eAAiB,EAAa,EAAI,EAAG,CAAC,IAEtC,EAAa,EAAK,EAClB,eAAiB,EAAc,CAAM,EAAG,GAAG,EAE/C,EAAG,CAAC,CAAM,CAAC,EAIX,EAAW,CACT,SAAU,GAAc,EACxB,aAAc,EACd,SAAU,EAAgB,EAAU,IAAA,EACtC,CAAC,EAED,GAAM,CAAE,WAAU,UAAW,EAAe,EAAS,CAAE,UAAW,GAAc,CAAU,CAAC,EAE3F,GAAI,CAAC,EAAY,OAAO,KAExB,IAAM,EAAiB,CAAC,GAAc,CAAC,CAAC,EAExC,OACE,EAAC,EAAD,CAAA,SACE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,eAAgB,GAAY,SAAS,EAC1D,MAAO,CAAE,OAAQ,EAAgB,IAAK,EAAmB,GAAG,GAAY,SAAU,EAFpF,SAAA,CAIE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,aAAc,GAAa,EAAO,kBAAmB,GAAY,QAAQ,EAC9F,MAAO,GAAY,SACnB,QAAS,CACV,CAAA,EACA,GACC,EAAC,MAAD,CACE,GAAI,EACJ,IAAK,EACL,KAAK,SACL,aAAW,OACX,kBAAiB,EAAiB,EAAU,IAAA,GAE5C,SAAU,GACV,UAAW,EACT,EAAO,MACP,GAAa,EAAO,WAGpB,GAAW,CAAC,EAAY,MAAO,EAAY,aAAc,EAAO,UAAU,EAC1E,EACA,GAAY,KACd,EACA,MAAO,CAAE,GAAI,EAAU,EAAa,IAAA,GAAY,GAAG,EAAO,GAAG,GAAY,KAAM,EAC/E,QAAU,GAAM,EAAE,gBAAgB,EAlBpC,SAAA,CAoBG,CAAC,GACA,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,YAAa,GAAY,MAAM,EAAG,MAAO,GAAY,OAA/E,SAAA,CACE,EAAC,MAAD,CAAK,GAAI,EAAS,UAAW,GAAY,MAAO,MAAO,GAAY,MAChE,SAAA,CACE,CAAA,EACL,EAAC,SAAD,CACE,KAAK,SACL,QAAS,EACT,aAAY,EAAK,MACjB,UAAW,EAAG,EAAO,iBAAkB,GAAY,WAAW,EAC9D,MAAO,GAAY,YAEnB,SAAA,EAAC,EAAD,CAAiB,KAAM,CAAY,CAAA,CAC7B,CAAA,CACL,IAEP,EAAC,MAAD,CACE,IAAK,EACL,UAAW,EACT,EAAO,UACP,EAAW,WACX,EAAW,YACX,GAAY,EAAW,qBACvB,GAAU,EAAW,mBACrB,GAAY,IACd,EACA,MAAO,GAAY,KAElB,UACE,CAAA,EACJ,GACC,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,YAAa,GAAY,MAAM,EAAG,MAAO,GAAY,OAC5E,SAAA,CACE,CAAA,CAEJ,CAEJ,CAAA,CAAA,CACE,CAAA,CAAA,CAAA,CAEb"}
@@ -1,2 +1,2 @@
1
- "use client";var e=`modal_L-Fkd`,t=`slideIn_RVIHR`,n=`fadeIn_XSuIE`,r=`modal-sheet_WkXR4`,i=`modal-container_qwKIm`,a=`modal-header_DhsRr`,o=`modal-body_Mmn0-`,s=`modal-close-button_UMZjq`,c=`modal-wrapper_r5wzq`,l=`modal-wrapper-shown_F0BgK`,u={modal:e,slideIn:t,fadeIn:n,"modal-sheet":`modal-sheet_WkXR4`,modalSheet:r,"modal-container":`modal-container_qwKIm`,modalContainer:i,"modal-header":`modal-header_DhsRr`,modalHeader:a,"modal-body":`modal-body_Mmn0-`,modalBody:o,"modal-close-button":`modal-close-button_UMZjq`,modalCloseButton:s,"modal-wrapper":`modal-wrapper_r5wzq`,modalWrapper:c,"modal-wrapper-shown":`modal-wrapper-shown_F0BgK`,modalWrapperShown:l};export{u as default,n as fadeIn,e as modal,o as modalBody,s as modalCloseButton,i as modalContainer,a as modalHeader,r as modalSheet,c as modalWrapper,l as modalWrapperShown,t as slideIn};
1
+ "use client";var e=`modal_L-Fkd`,t=`slideIn_RVIHR`,n=`fadeIn_XSuIE`,r=`modal-sheet_WkXR4`,i=`modal-container_qwKIm`,a=`modal-header_DhsRr`,o=`modal-body_Mmn0-`,s=`modal-footer_idArP`,c=`modal-close-button_UMZjq`,l=`modal-wrapper_r5wzq`,u=`modal-wrapper-shown_F0BgK`,d={modal:e,slideIn:t,fadeIn:n,"modal-sheet":`modal-sheet_WkXR4`,modalSheet:r,"modal-container":`modal-container_qwKIm`,modalContainer:i,"modal-header":`modal-header_DhsRr`,modalHeader:a,"modal-body":`modal-body_Mmn0-`,modalBody:o,"modal-footer":`modal-footer_idArP`,modalFooter:s,"modal-close-button":`modal-close-button_UMZjq`,modalCloseButton:c,"modal-wrapper":`modal-wrapper_r5wzq`,modalWrapper:l,"modal-wrapper-shown":`modal-wrapper-shown_F0BgK`,modalWrapperShown:u};export{d as default,n as fadeIn,e as modal,o as modalBody,c as modalCloseButton,i as modalContainer,s as modalFooter,a as modalHeader,r as modalSheet,l as modalWrapper,u as modalWrapperShown,t as slideIn};
2
2
  //# sourceMappingURL=modal.module.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"modal.module.mjs","names":[],"sources":["../../../../package/common/modal/modal.module.pcss"],"sourcesContent":[".modal {\n padding: 16px;\n border-radius: var(--default-border-radius);\n background: var(--background-modal);\n color: var(--text-color);\n font-family: var(--default-font);\n box-sizing: border-box;\n position: relative;\n display: flex;\n flex-direction: column;\n transform-origin: bottom center;\n animation:\n slideIn 0.2s,\n fadeIn 0.3s forwards;\n max-width: 95%;\n max-height: 95%;\n\n /* The panel itself never scrolls, so the header stays put; `&-body` is what scrolls. */\n overflow: hidden;\n\n @media (width <= 767px) {\n max-width: 100%;\n max-height: 100%;\n }\n\n /* A sheet-presented modal carries forms and detail views, not a short menu, so it takes more\n of the screen than the shared default — and keeps the panel's own 16px at the bottom edge. */\n &-sheet {\n --sheet-max-height: 90dvh;\n --sheet-safe-padding: 16px;\n }\n\n &-container {\n position: fixed;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n top: 0;\n left: 0;\n }\n\n &-header {\n display: flex;\n gap: 8px;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n flex: 0 0 auto;\n\n div {\n overflow: hidden;\n text-overflow: ellipsis;\n }\n }\n\n &-body {\n /* `min-height: 0` lets this shrink below its content's height so it, not the panel, scrolls. */\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n margin: -0.6em;\n padding: 0.6em;\n }\n\n &-close-button {\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 0;\n color: inherit;\n font-size: inherit;\n line-height: 1;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &-wrapper {\n position: fixed;\n width: 100%;\n height: 100%;\n background: #00000052;\n top: 0;\n left: 0;\n transition: all 0.3s ease-in-out;\n opacity: 0;\n\n &-shown {\n opacity: 1;\n }\n }\n}\n\n@keyframes slideIn {\n from {\n transform: scale(0);\n }\n\n to {\n transform: scale(0.99);\n }\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 1;\n }\n}\n\n/* Only the scale-in goes; the backdrop and the panel still fade, which is not motion.\n `slideIn` ends at scale(0.99) and the panel has no transform of its own, so dropping the\n animation lands it at scale(1) rather than leaving it collapsed. */\n@media (prefers-reduced-motion: reduce) {\n .modal {\n animation: fadeIn 0.3s forwards;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"modal.module.mjs","names":[],"sources":["../../../../package/common/modal/modal.module.pcss"],"sourcesContent":[".modal {\n /* Theme tokens resolved once, each with a built-in fallback. Set any of the public\n `--modal-*` variables via ThemeProvider (theme-wide) or `style` (per instance) to\n override; unset ones fall back to the values below. */\n --custom-modal-padding: var(--modal-padding, var(--spacing-l));\n --custom-modal-gap: var(--modal-gap, var(--spacing-l));\n\n /* Half the gap, so the scroll port's clipping edge — where the divider sits — lands midway\n between the chrome and where the content rests, with the same room either side. Flush\n against the chrome (bleed = gap) reads as a sliced line of text colliding with the title;\n an unrelated value (this was `0.6em`) puts it at a distance that drifts with the font size. */\n --custom-modal-body-bleed: var(--modal-body-bleed, calc(var(--custom-modal-gap) / 2));\n\n /* The panel never comes closer to the screen edge than its own padding, at every size. A\n percentage instead reads as a different inset on every screen, and pairing one with a\n breakpoint made the two axes disagree: 5% of a 390px width is 19.5px but 5% of a 780px\n height is 39px, so the same rule came out narrower and taller than the default on one phone. */\n --custom-modal-max-width: var(--modal-max-width, calc(100% - 2 * var(--custom-modal-padding)));\n --custom-modal-max-height: var(--modal-max-height, calc(100% - 2 * var(--custom-modal-padding)));\n\n padding: var(--custom-modal-padding);\n border-radius: var(--default-border-radius);\n background: var(--background-modal);\n color: var(--text-color);\n font-family: var(--default-font);\n box-sizing: border-box;\n position: relative;\n display: flex;\n flex-direction: column;\n transform-origin: bottom center;\n animation:\n slideIn 0.2s,\n fadeIn 0.3s forwards;\n max-width: var(--custom-modal-max-width);\n max-height: var(--custom-modal-max-height);\n\n /* The panel itself never scrolls, so the header stays put; `&-body` is what scrolls. */\n overflow: hidden;\n\n /* A sheet-presented modal carries forms and detail views, not a short menu, so it takes more\n of the screen than the shared default — and keeps the panel's own padding at the bottom edge. */\n &-sheet {\n --sheet-max-height: 90dvh;\n --sheet-safe-padding: var(--custom-modal-padding);\n }\n\n &-container {\n position: fixed;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n top: 0;\n left: 0;\n }\n\n &-header {\n display: flex;\n gap: var(--spacing-m);\n justify-content: space-between;\n align-items: center;\n margin-bottom: var(--custom-modal-gap);\n flex: 0 0 auto;\n\n div {\n overflow: hidden;\n text-overflow: ellipsis;\n }\n }\n\n &-body {\n /* `min-height: 0` lets this shrink below its content's height so it, not the panel, scrolls. */\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n\n /* A negative margin cancelled by an equal padding, so a focus ring or a floating label at\n the body's edge isn't clipped by the scroll container. Override the pair with\n `--modal-body-bleed`, never with a plain `padding`, which drops the negative half and\n brings the clipping back. See `docs/Modal.md` for what the two do together. */\n margin: calc(-1 * var(--custom-modal-body-bleed));\n padding: var(--custom-modal-body-bleed);\n\n /* The mask lives in `styles/scrollFade.module.pcss`; the component applies it along with the\n modifiers saying which end genuinely hides content. The run has to clear the port's own\n padding before any content fades at all, hence gap + bleed. Set here as the shared sheet's\n private length rather than as `--scroll-fade-length`, which would inherit down into a\n `ScrollFade` nested in the body. */\n --custom-scroll-fade-length: var(\n --modal-scroll-fade,\n calc(var(--custom-modal-gap) + var(--custom-modal-body-bleed))\n );\n }\n\n &-footer {\n margin-top: var(--custom-modal-gap);\n flex: 0 0 auto;\n }\n\n &-close-button {\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 0;\n color: inherit;\n font-size: inherit;\n line-height: 1;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &-wrapper {\n position: fixed;\n width: 100%;\n height: 100%;\n background: #00000052;\n top: 0;\n left: 0;\n transition: all 0.3s ease-in-out;\n opacity: 0;\n\n &-shown {\n opacity: 1;\n }\n }\n}\n\n@keyframes slideIn {\n from {\n transform: scale(0);\n }\n\n to {\n transform: scale(0.99);\n }\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 1;\n }\n}\n\n/* Only the scale-in goes; the backdrop and the panel still fade, which is not motion.\n `slideIn` ends at scale(0.99) and the panel has no transform of its own, so dropping the\n animation lands it at scale(1) rather than leaving it collapsed. */\n@media (prefers-reduced-motion: reduce) {\n .modal {\n animation: fadeIn 0.3s forwards;\n }\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{PopoverAlign as n,PopoverPlacement as r,PopoverTrigger as ee}from"../popover/popover.types.mjs";import te from"../popover/popover.mjs";import ne from"../chip/chip.mjs";import re from"../tooltip/tooltip.mjs";import ie from"../searchInput/searchInput.mjs";import i from"./multiSelect.module.mjs";import{useEffect as a,useId as ae,useRef as o,useState as s}from"react";import c from"classnames";import{FontAwesomeIcon as l}from"@fortawesome/react-fontawesome";import{faCheck as oe,faChevronDown as se,faXmark as ce}from"@fortawesome/free-solid-svg-icons";import{jsx as u,jsxs as d}from"react/jsx-runtime";var le=[],ue={clearSelection:`Clear selection`,create:e=>`Add "${e}"`,searchPlaceholder:`Search…`,empty:`No matches`};function f(f){let{items:p,value:m,defaultValue:de=[],onChange:fe=()=>{},label:h=``,alwaysFloatLabel:pe=!1,placeholder:g=``,searchable:me=!1,allowCustomValues:_=!1,maxSelected:v,clearable:he=!0,disabled:y=!1,readOnly:b=!1,presentation:ge,formValidator:x=null,errorMessage:_e=``,isValid:ve=!0,className:ye,style:be,classNames:S,styles:C,onMouseEnter:xe,onMouseLeave:Se,onFocus:Ce,onBlur:we,labels:Te,...Ee}=e(`MultiSelect`,f),w=t(`MultiSelect`,Te,ue),T=o(null),E=o(null),D=o(null),O=ae(),[De,Oe]=s(de),[k,ke]=s(!1),[A,j]=s(``),[M,N]=s(0),[P,F]=s(!1),[Ae,I]=s(!1),[L,je]=s(),R=o(x),[,Me]=s(0);a(()=>{R.current=x;let e=R.current;if(!e)return;e.label=h,e.validate();let t=()=>Me(e=>e+1);return e.registerOnUpdateListener(t),()=>{e.removeOnUpdateListener(t)}},[x,h]);let z=m!==void 0&&!x,B=x?x.value:z?m:De,V=Array.isArray(B)?B:le,H=x?x.touched&&x.hasError():!ve||!!_e,Ne=x?x.getCurrentErrorMessage():_e||``,U=!y&&!b,W=v!==void 0&&V.length>=v,G=pe||k||P||V.length>0,K=me||_,q=A.trim(),J=K?q.toLowerCase():``,Pe=J?p.filter(e=>e.label.toLowerCase().includes(J)):p,Fe=_&&q.length>0&&!W&&!p.some(e=>e.label.toLowerCase()===J||String(e.key).toLowerCase()===J)&&!V.some(e=>String(e).toLowerCase()===J),Y=Fe?[...Pe,{key:q,label:w.create(q)}]:Pe,Ie=V.map(e=>p.find(t=>t.key===e)??(_?{key:e,label:String(e)}:void 0)).filter(e=>e!==void 0);function X(e){x?x.set(e):z||Oe(e),fe(e)}function Z(e){U&&!e.disabled&&(V.includes(e.key)?X(V.filter(t=>t!==e.key)):W||X([...V,e.key]),Fe&&e.key===q&&j(``))}function Le(){T.current?.contains(document.activeElement)&&E.current?.focus()}function Q(e){(!e||U)&&(ke(e),e?(je(E.current?.offsetWidth),N(0)):(j(``),R.current&&(R.current.touched=!0)))}a(()=>{k&&K&&D.current?.querySelector(`input`)?.focus()},[k,K]);function $(e){if(U){if(!k){e.key===`ArrowDown`||e.key===`Enter`||e.key===` `?(e.preventDefault(),Q(!0)):e.key===`Backspace`&&V.length>0&&X(V.slice(0,-1));return}if(e.key===`ArrowDown`||e.key===`ArrowUp`){if(e.preventDefault(),Y.length===0)return;let t=e.key===`ArrowDown`?1:-1;N(e=>(e+t+Y.length)%Y.length)}else if(e.key===`Home`||e.key===`End`)e.preventDefault(),N(e.key===`Home`?0:Y.length-1);else if(e.key===`Enter`){e.preventDefault();let t=Y[M];t&&Z(t)}else e.key===`Backspace`&&!A&&V.length>0&&X(V.slice(0,-1))}}let Re=d(`div`,{className:c(i.multiSelectPanel,S?.panel),style:C?.panel,children:[K&&u(`div`,{ref:D,className:c(i.multiSelectSearch,S?.search),style:C?.search,children:u(ie,{value:A,onChange:e=>{j(e),N(0)},placeholder:w.searchPlaceholder,onKeyDown:$})}),u(`div`,{id:O,role:`listbox`,"aria-multiselectable":`true`,"aria-label":h||void 0,className:c(i.multiSelectOptions,S?.options),style:C?.options,children:Y.length===0?u(`div`,{className:c(i.multiSelectEmpty,S?.empty),style:C?.empty,children:w.empty}):Y.map((e,t)=>{let n=V.includes(e.key),r=e.disabled||W&&!n;return d(`div`,{id:`${O}-${t}`,role:`option`,"aria-selected":n,"aria-disabled":r||void 0,className:c(i.multiSelectOption,t===M&&i.multiSelectOptionActive,n&&i.multiSelectOptionSelected,r&&i.multiSelectOptionDisabled,S?.option),style:C?.option,onMouseDown:e=>e.preventDefault(),onMouseEnter:()=>N(t),onClick:()=>Z(e),children:[u(`span`,{className:c(i.multiSelectOptionCheck,S?.optionCheck),style:C?.optionCheck,children:n&&u(l,{icon:oe})}),u(`span`,{className:c(i.multiSelectOptionLabel,S?.optionLabel),style:C?.optionLabel,children:e.label})]},e.key)})})]});return d(`div`,{...Ee,ref:T,className:c(i.multiSelect,y&&i.multiSelectDisabled,S?.root,ye),style:{...be,...C?.root},onMouseEnter:e=>{I(!0),xe?.(e)},onMouseLeave:e=>{I(!1),Se?.(e)},onFocus:e=>{F(!0),Ce?.(e)},onBlur:e=>{e.currentTarget.contains(e.relatedTarget)||(F(!1),we?.(e))},children:[u(te,{isOpen:k,onOpenChange:Q,trigger:ee.Click,placement:r.Bottom,align:n.Start,offset:4,withArrow:!1,focusOnOpen:K,constrainWidth:!1,width:`trigger`,disabled:!U,presentation:ge,content:Re,styles:{panel:L?{minWidth:L}:void 0},children:d(`div`,{ref:E,role:`combobox`,tabIndex:y?-1:0,"aria-expanded":k,"aria-haspopup":`listbox`,"aria-controls":O,"aria-activedescendant":k&&Y.length>0?`${O}-${M}`:void 0,"aria-disabled":y||void 0,"aria-readonly":b||void 0,className:c(i.multiSelectControl,S?.control),style:C?.control,onKeyDown:$,children:[g&&Ie.length===0&&u(`span`,{className:c(i.multiSelectPlaceholder,(!h||G)&&i.multiSelectPlaceholderShown,!h&&i.multiSelectPlaceholderInstant,S?.placeholder),style:C?.placeholder,children:g}),u(`div`,{className:c(i.multiSelectValues,S?.values),style:C?.values,children:Ie.map(e=>u(ne,{text:e.label,showRemoveIcon:U,labels:{remove:`Remove ${e.label}`},onMouseDown:e=>e.preventDefault(),onRemove:()=>{Z(e),Le()},className:c(i.multiSelectChip,S?.chip),style:C?.chip},e.key))}),he&&U&&V.length>0&&u(`button`,{type:`button`,tabIndex:-1,"aria-label":w.clearSelection,className:c(i.multiSelectClearButton,S?.clearButton),style:C?.clearButton,onMouseDown:e=>e.preventDefault(),onClick:e=>{e.stopPropagation(),X([]),Le()},children:u(l,{icon:ce})}),u(l,{icon:se,className:c(i.multiSelectIcon,k&&i.multiSelectIconOpen,S?.icon),style:C?.icon}),h&&u(`div`,{className:c(i.multiSelectLabel,G&&i.multiSelectLabelFloating,S?.label),style:C?.label,children:h}),u(`fieldset`,{className:c(i.multiSelectFieldset,!h&&i.multiSelectFieldsetNoNotch,(P||k)&&i.multiSelectFieldsetFocused,H&&i.multiSelectFieldsetError,S?.fieldset),style:C?.fieldset,children:u(`legend`,{className:c(i.multiSelectFieldsetLegend,G&&i.multiSelectFieldsetLegendActive),children:u(`span`,{children:h})})})]})}),u(re,{variant:`error`,message:Ne,isVisible:H&&(P||Ae)})]})}export{f as default};
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{PopoverAlign as n,PopoverPlacement as r,PopoverTrigger as ee}from"../popover/popover.types.mjs";import te from"../popover/popover.mjs";import ne from"../chip/chip.mjs";import re from"../tooltip/tooltip.mjs";import{edgeIndex as ie,nextIndex as ae,scrollOptionIntoView as oe}from"../utils/listNavigation.mjs";import se from"../searchInput/searchInput.mjs";import i from"./multiSelect.module.mjs";import{useEffect as a,useId as ce,useRef as o,useState as s}from"react";import c from"classnames";import{FontAwesomeIcon as l}from"@fortawesome/react-fontawesome";import{faCheck as le,faChevronDown as ue,faXmark as de}from"@fortawesome/free-solid-svg-icons";import{jsx as u,jsxs as d}from"react/jsx-runtime";var fe=[],pe={clearSelection:`Clear selection`,create:e=>`Add "${e}"`,searchPlaceholder:`Search…`,empty:`No matches`};function f(f){let{items:p,value:m,defaultValue:me=[],onChange:he=()=>{},label:h=``,alwaysFloatLabel:ge=!1,placeholder:g=``,searchable:_e=!1,allowCustomValues:_=!1,maxSelected:v,clearable:ve=!0,disabled:y=!1,readOnly:b=!1,presentation:ye,formValidator:x=null,errorMessage:S=``,isValid:be=!0,className:xe,style:Se,classNames:C,styles:w,onMouseEnter:Ce,onMouseLeave:we,onFocus:Te,onBlur:Ee,labels:De,...Oe}=e(`MultiSelect`,f),T=t(`MultiSelect`,De,pe),E=o(null),D=o(null),O=o(null),k=o(null),A=ce(),[ke,Ae]=s(me),[j,je]=s(!1),[M,N]=s(``),[P,F]=s(0),[I,L]=s(!1),[Me,Ne]=s(!1),[Pe,Fe]=s(),R=o(x),[,Ie]=s(0);a(()=>{R.current=x;let e=R.current;if(!e)return;e.label=h,e.validate();let t=()=>Ie(e=>e+1);return e.registerOnUpdateListener(t),()=>{e.removeOnUpdateListener(t)}},[x,h]);let z=m!==void 0&&!x,B=x?x.value:z?m:ke,V=Array.isArray(B)?B:fe,H=x?x.touched&&x.hasError():!be||!!S,Le=x?x.getCurrentErrorMessage():S||``,U=!y&&!b,W=v!==void 0&&V.length>=v,G=ge||j||I||V.length>0,K=_e||_,q=M.trim(),J=K?q.toLowerCase():``,Y=J?p.filter(e=>e.label.toLowerCase().includes(J)):p,X=_&&q.length>0&&!W&&!p.some(e=>e.label.toLowerCase()===J||String(e.key).toLowerCase()===J)&&!V.some(e=>String(e).toLowerCase()===J),Z=X?[...Y,{key:q,label:T.create(q)}]:Y,Re=V.map(e=>p.find(t=>t.key===e)??(_?{key:e,label:String(e)}:void 0)).filter(e=>e!==void 0);function Q(e){x?x.set(e):z||Ae(e),he(e)}function $(e){U&&!e.disabled&&(V.includes(e.key)?Q(V.filter(t=>t!==e.key)):W||Q([...V,e.key]),X&&e.key===q&&N(``))}function ze(){E.current?.contains(document.activeElement)&&D.current?.focus()}function Be(e){(!e||U)&&(je(e),e?(Fe(D.current?.offsetWidth),F(0)):(N(``),R.current&&(R.current.touched=!0)))}a(()=>{j&&K&&O.current?.querySelector(`input`)?.focus()},[j,K]),a(()=>{j&&oe(k.current,document.getElementById(`${A}-${P}`))},[j,P,A]);let Ve={isDisabled:e=>{let t=Z[e];return!!t.disabled||W&&!V.includes(t.key)}};function He(e){if(U){if(!j){e.key===`ArrowDown`||e.key===`Enter`||e.key===` `?(e.preventDefault(),Be(!0)):e.key===`Backspace`&&V.length>0&&Q(V.slice(0,-1));return}if(e.key===`ArrowDown`||e.key===`ArrowUp`)e.preventDefault(),F(ae(P,e.key===`ArrowDown`?1:-1,Z.length,Ve)??0);else if(e.key===`Home`||e.key===`End`)e.preventDefault(),F(ie(e.key===`Home`?`first`:`last`,Z.length,Ve)??0);else if(e.key===`Enter`){e.preventDefault();let t=Z[P];t&&$(t)}else e.key===`Backspace`&&!M&&V.length>0&&Q(V.slice(0,-1))}}let Ue=d(`div`,{className:c(i.multiSelectPanel,C?.panel),style:w?.panel,children:[K&&u(`div`,{ref:O,className:c(i.multiSelectSearch,C?.search),style:w?.search,children:u(se,{value:M,onChange:e=>{N(e),F(0)},placeholder:T.searchPlaceholder,onKeyDown:He})}),u(`div`,{ref:k,id:A,role:`listbox`,"aria-multiselectable":`true`,"aria-label":h||void 0,className:c(i.multiSelectOptions,C?.options),style:w?.options,children:Z.length===0?u(`div`,{className:c(i.multiSelectEmpty,C?.empty),style:w?.empty,children:T.empty}):Z.map((e,t)=>{let n=V.includes(e.key),r=e.disabled||W&&!n;return d(`div`,{id:`${A}-${t}`,role:`option`,"aria-selected":n,"aria-disabled":r||void 0,className:c(i.multiSelectOption,t===P&&i.multiSelectOptionActive,n&&i.multiSelectOptionSelected,r&&i.multiSelectOptionDisabled,C?.option),style:w?.option,onMouseDown:e=>e.preventDefault(),onMouseEnter:()=>F(t),onClick:()=>$(e),children:[u(`span`,{className:c(i.multiSelectOptionCheck,C?.optionCheck),style:w?.optionCheck,children:n&&u(l,{icon:le})}),u(`span`,{className:c(i.multiSelectOptionLabel,C?.optionLabel),style:w?.optionLabel,children:e.label})]},e.key)})})]});return d(`div`,{...Oe,ref:E,className:c(i.multiSelect,y&&i.multiSelectDisabled,C?.root,xe),style:{...Se,...w?.root},onMouseEnter:e=>{Ne(!0),Ce?.(e)},onMouseLeave:e=>{Ne(!1),we?.(e)},onFocus:e=>{L(!0),Te?.(e)},onBlur:e=>{e.currentTarget.contains(e.relatedTarget)||(L(!1),Ee?.(e))},children:[u(te,{isOpen:j,onOpenChange:Be,trigger:ee.Click,placement:r.Bottom,align:n.Start,offset:4,withArrow:!1,focusOnOpen:K,constrainWidth:!1,width:`trigger`,disabled:!U,presentation:ye,content:Ue,styles:{panel:Pe?{minWidth:Pe}:void 0},children:d(`div`,{ref:D,role:`combobox`,tabIndex:y?-1:0,"aria-expanded":j,"aria-haspopup":`listbox`,"aria-controls":A,"aria-activedescendant":j&&Z.length>0?`${A}-${P}`:void 0,"aria-disabled":y||void 0,"aria-readonly":b||void 0,className:c(i.multiSelectControl,C?.control),style:w?.control,onKeyDown:He,children:[g&&Re.length===0&&u(`span`,{className:c(i.multiSelectPlaceholder,(!h||G)&&i.multiSelectPlaceholderShown,!h&&i.multiSelectPlaceholderInstant,C?.placeholder),style:w?.placeholder,children:g}),u(`div`,{className:c(i.multiSelectValues,C?.values),style:w?.values,children:Re.map(e=>u(ne,{text:e.label,showRemoveIcon:U,labels:{remove:`Remove ${e.label}`},onMouseDown:e=>e.preventDefault(),onRemove:()=>{$(e),ze()},className:c(i.multiSelectChip,C?.chip),style:w?.chip},e.key))}),ve&&U&&V.length>0&&u(`button`,{type:`button`,tabIndex:-1,"aria-label":T.clearSelection,className:c(i.multiSelectClearButton,C?.clearButton),style:w?.clearButton,onMouseDown:e=>e.preventDefault(),onClick:e=>{e.stopPropagation(),Q([]),ze()},children:u(l,{icon:de})}),u(l,{icon:ue,className:c(i.multiSelectIcon,j&&i.multiSelectIconOpen,C?.icon),style:w?.icon}),h&&u(`div`,{className:c(i.multiSelectLabel,G&&i.multiSelectLabelFloating,C?.label),style:w?.label,children:h}),u(`fieldset`,{className:c(i.multiSelectFieldset,(I||j)&&i.multiSelectFieldsetFocused,H&&i.multiSelectFieldsetError,C?.fieldset),style:w?.fieldset,children:u(`legend`,{className:c(i.multiSelectFieldsetLegend,G&&i.multiSelectFieldsetLegendActive),children:u(`span`,{children:h})})})]})}),u(re,{variant:`error`,message:Le,isVisible:H&&(I||Me)})]})}export{f as default};
2
2
  //# sourceMappingURL=multiSelect.mjs.map