@12-apps/ui 6.89.2 → 6.91.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 (390) hide show
  1. package/components-catalog.md +2 -2
  2. package/dist/_internal/components/data-display/Alert/Alert.js +3 -3
  3. package/dist/_internal/components/data-display/AsyncStateContainer/AsyncStateContainer.js +3 -3
  4. package/dist/_internal/components/data-display/Avatar/Avatar.js +3 -3
  5. package/dist/_internal/components/data-display/Avatar/Avatar.view.js +2 -2
  6. package/dist/_internal/components/data-display/CardKit/card-actions-context.js +4 -4
  7. package/dist/_internal/components/data-display/CardKit/use-remove-confirm.js +5 -5
  8. package/dist/_internal/components/data-display/Carousel/Carousel.chrome.js +4 -3
  9. package/dist/_internal/components/data-display/Carousel/Carousel.js +5 -4
  10. package/dist/_internal/components/data-display/Carousel/Carousel.parts.js +3 -2
  11. package/dist/_internal/components/data-display/Chart/Chart.js +5 -5
  12. package/dist/_internal/components/data-display/Chart/SpecChart.js +8 -8
  13. package/dist/_internal/components/data-display/Chart/chart-context.js +2 -2
  14. package/dist/_internal/components/data-display/Chart/chart-renderers.js +4 -4
  15. package/dist/_internal/components/data-display/Chart/chart-spec.js +2 -2
  16. package/dist/_internal/components/data-display/Chip/Chip.js +3 -3
  17. package/dist/_internal/components/data-display/Chip/Chip.styles.js +2 -2
  18. package/dist/_internal/components/data-display/DataGrid/DataGrid.js +2 -2
  19. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +56 -31
  20. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +64 -39
  21. package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +6 -6
  22. package/dist/_internal/components/data-display/DataViews/base-list-card-layout.js +7 -7
  23. package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +5 -5
  24. package/dist/_internal/components/data-display/DataViews/base-list-card.js +9 -9
  25. package/dist/_internal/components/data-display/DataViews/data-views-bar-controls.js +5 -3
  26. package/dist/_internal/components/data-display/DataViews/data-views-day-input.js +1 -1
  27. package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +31 -6
  28. package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +8 -8
  29. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +53 -28
  30. package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +36 -11
  31. package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +32 -7
  32. package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +33 -8
  33. package/dist/_internal/components/data-display/DataViews/data-views-number-input.js +1 -1
  34. package/dist/_internal/components/data-display/DataViews/data-views-preset-chips.js +10 -3
  35. package/dist/_internal/components/data-display/DataViews/data-views-range-bounds.js +47 -0
  36. package/dist/_internal/components/data-display/DataViews/data-views-range-calendar.js +36 -0
  37. package/dist/_internal/components/data-display/DataViews/data-views-range-calendar.js.map +1 -0
  38. package/dist/_internal/components/data-display/DataViews/data-views-range-pill.js +32 -6
  39. package/dist/_internal/components/data-display/DataViews/data-views-range-summary.js +12 -0
  40. package/dist/_internal/components/data-display/DataViews/data-views-range-summary.js.map +1 -0
  41. package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +3 -3
  42. package/dist/_internal/components/data-display/DataViews/data-views-still-anchor.js +9 -0
  43. package/dist/_internal/components/data-display/DataViews/data-views-still-anchor.js.map +1 -0
  44. package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +5 -5
  45. package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +2 -2
  46. package/dist/_internal/components/data-display/DataViews/list-card-rails.js +4 -4
  47. package/dist/_internal/components/data-display/DataViews/use-data-views-state.js +2 -2
  48. package/dist/_internal/components/data-display/EmptyState/EmptyState.js +2 -2
  49. package/dist/_internal/components/data-display/FleetMap/FleetBody.js +13 -12
  50. package/dist/_internal/components/data-display/FleetMap/FleetCanvas.js +12 -11
  51. package/dist/_internal/components/data-display/FleetMap/FleetMap.fixtures.js +2 -1
  52. package/dist/_internal/components/data-display/FleetMap/FleetMap.fixtures.js.map +1 -1
  53. package/dist/_internal/components/data-display/FleetMap/FleetMap.js +15 -15
  54. package/dist/_internal/components/data-display/InteractiveTooltip/InteractiveTooltip.js +2 -2
  55. package/dist/_internal/components/data-display/Lightbox/Lightbox.js +7 -7
  56. package/dist/_internal/components/data-display/Lightbox/LightboxControls.js +2 -2
  57. package/dist/_internal/components/data-display/Lightbox/LightboxOverlay.js +3 -3
  58. package/dist/_internal/components/data-display/Lightbox/LightboxThumbnails.js +2 -2
  59. package/dist/_internal/components/data-display/MapPreview/MapControlBar.js +4 -3
  60. package/dist/_internal/components/data-display/MapPreview/MapLayers.js +6 -5
  61. package/dist/_internal/components/data-display/MapPreview/MapMarkers.js +5 -4
  62. package/dist/_internal/components/data-display/MapPreview/MapPreview.helpers.js +3 -2
  63. package/dist/_internal/components/data-display/MapPreview/MapPreview.js +11 -10
  64. package/dist/_internal/components/data-display/RegionMap/RegionMap.hooks.js +2 -1
  65. package/dist/_internal/components/data-display/RegionMap/RegionMap.js +4 -3
  66. package/dist/_internal/components/data-display/RegionMap/RegionMap.view.js +19 -0
  67. package/dist/_internal/components/data-display/RegionMap/RegionMap.view.js.map +1 -0
  68. package/dist/_internal/components/data-display/RegionMap/RegionMapDrawing.js +1 -1
  69. package/dist/_internal/components/data-display/SectionOnboarding/SectionOnboarding.js +3 -3
  70. package/dist/_internal/components/data-display/index.js +67 -61
  71. package/dist/_internal/components/feedback/NotificationStatusNotice/NotificationStatusNotice.js +4 -4
  72. package/dist/_internal/components/feedback/SequenceResolver/SequenceResolver.js +6 -6
  73. package/dist/_internal/components/feedback/SequenceResolver/SequenceResolver.overview.js +5 -5
  74. package/dist/_internal/components/feedback/SequenceResolver/SequenceResolver.parts.js +4 -4
  75. package/dist/_internal/components/feedback/index.js +7 -7
  76. package/dist/_internal/components/form/Calendar/Calendar.js +5 -5
  77. package/dist/_internal/components/form/Calendar/CalendarDay.js +1 -1
  78. package/dist/_internal/components/form/Calendar/CalendarDayCell.js +2 -2
  79. package/dist/_internal/components/form/Calendar/CalendarMonth.js +3 -3
  80. package/dist/_internal/components/form/Calendar/CalendarSelectorsMonth.js +4 -4
  81. package/dist/_internal/components/form/DateRangePicker/DateRangePicker.hooks.js +3 -3
  82. package/dist/_internal/components/form/DateRangePicker/DateRangePicker.js +10 -10
  83. package/dist/_internal/components/form/DateRangePicker/DateRangePicker.range.js +2 -2
  84. package/dist/_internal/components/form/DateRangePicker/DateRangePickerFields.js +3 -3
  85. package/dist/_internal/components/form/index.js +24 -24
  86. package/dist/_internal/components/index.js +102 -96
  87. package/dist/_internal/components/layout/SettingCard/SettingCard.js +8 -8
  88. package/dist/_internal/components/layout/SettingCard/SettingCard.parts.js +4 -4
  89. package/dist/_internal/components/layout/SettingCard/SettingCard.summary.js +7 -7
  90. package/dist/_internal/components/layout/SettingCard/SettingGrid.js +5 -5
  91. package/dist/_internal/components/layout/SettingCard/SettingGroup.js +9 -9
  92. package/dist/_internal/components/layout/SettingCard/SettingSwitch.js +8 -8
  93. package/dist/_internal/components/layout/SettingCard/SettingToggle.js +9 -9
  94. package/dist/_internal/components/layout/index.js +12 -12
  95. package/dist/_internal/en-US.data-display.js +2 -1
  96. package/dist/_internal/pt-BR.data-display.js +2 -1
  97. package/dist/_internal/user-avatar/user-avatar.js +4 -4
  98. package/dist/charts.js +11 -11
  99. package/dist/{chunk-FJ3UZ4RC.js → chunk-2FKWKLSC.js} +5 -3
  100. package/dist/chunk-2FKWKLSC.js.map +1 -0
  101. package/dist/{chunk-K2VDRODL.js → chunk-3IDL7NK7.js} +2 -2
  102. package/dist/{chunk-6ATXOJVQ.js → chunk-3JZ3KEQQ.js} +4 -4
  103. package/dist/{chunk-XHIBFBNP.js → chunk-3ZRK3BRN.js} +4 -2
  104. package/dist/chunk-3ZRK3BRN.js.map +1 -0
  105. package/dist/{chunk-EOIRU62W.js → chunk-42D7KBDH.js} +2 -2
  106. package/dist/{chunk-LXIPBHNJ.js → chunk-42TOCPXB.js} +5 -5
  107. package/dist/{chunk-WAO7UQRS.js → chunk-4KWDNGMA.js} +3 -3
  108. package/dist/{chunk-X5OGIT2F.js → chunk-4L54KUZV.js} +22 -4
  109. package/dist/chunk-4L54KUZV.js.map +1 -0
  110. package/dist/{chunk-JIEVKHOH.js → chunk-4QR7LM5F.js} +2 -2
  111. package/dist/{chunk-WJMSND5Q.js → chunk-5E2CRRD4.js} +5 -5
  112. package/dist/{chunk-ZDAAHCIS.js → chunk-5HADIIWN.js} +3 -3
  113. package/dist/{chunk-BP3ZKIPE.js → chunk-64UNVW6D.js} +4 -4
  114. package/dist/{chunk-TRYR424I.js → chunk-6LOWZCH7.js} +15 -1
  115. package/dist/chunk-6LOWZCH7.js.map +1 -0
  116. package/dist/{chunk-6WHIJPEF.js → chunk-6PU5P7QT.js} +2 -2
  117. package/dist/{chunk-7F6D73NL.js → chunk-76DX2IMH.js} +2 -2
  118. package/dist/chunk-7CUZTWKW.js +52 -0
  119. package/dist/chunk-7CUZTWKW.js.map +1 -0
  120. package/dist/{chunk-5RSK5M6M.js → chunk-7NP2JHGM.js} +63 -126
  121. package/dist/chunk-7NP2JHGM.js.map +1 -0
  122. package/dist/{chunk-YNZUYZ2O.js → chunk-A3DDEKLV.js} +2 -2
  123. package/dist/{chunk-FEKWKWGK.js → chunk-ARGVUTTL.js} +15 -1
  124. package/dist/chunk-ARGVUTTL.js.map +1 -0
  125. package/dist/{chunk-BMTIBQQC.js → chunk-BBBHPK2Q.js} +6 -6
  126. package/dist/{chunk-DYHOBKPU.js → chunk-BLZDSCIZ.js} +6 -6
  127. package/dist/{chunk-EUR2ORTN.js → chunk-CSJ7WNXU.js} +2 -2
  128. package/dist/{chunk-OWRQOYUE.js → chunk-DA3D5X5Z.js} +5 -5
  129. package/dist/{chunk-LV6AD6XC.js → chunk-DBI6AMNY.js} +4 -4
  130. package/dist/{chunk-3YFDGFEK.js → chunk-DVX4HDNP.js} +2 -2
  131. package/dist/chunk-DY2I6LMX.js +1 -0
  132. package/dist/chunk-DY2I6LMX.js.map +1 -0
  133. package/dist/{chunk-QKOJ4637.js → chunk-E6K2UZGR.js} +3 -3
  134. package/dist/{chunk-7XSCEHGA.js → chunk-EOQ6EKTS.js} +7 -7
  135. package/dist/chunk-FORAVDJF.js +164 -0
  136. package/dist/chunk-FORAVDJF.js.map +1 -0
  137. package/dist/chunk-FWAY2SAI.js +72 -0
  138. package/dist/chunk-FWAY2SAI.js.map +1 -0
  139. package/dist/{chunk-Q2ERGAQO.js → chunk-FYAW5GBF.js} +33 -6
  140. package/dist/chunk-FYAW5GBF.js.map +1 -0
  141. package/dist/{chunk-GMRQPNG3.js → chunk-G2NVBCF7.js} +20 -25
  142. package/dist/chunk-G2NVBCF7.js.map +1 -0
  143. package/dist/{chunk-Z5WUSI47.js → chunk-G3JFESKD.js} +6 -6
  144. package/dist/{chunk-3EIRRLCQ.js → chunk-HC6OZ7QK.js} +2 -2
  145. package/dist/{chunk-SKIAWOUC.js → chunk-HOPRZEBM.js} +3 -3
  146. package/dist/{chunk-OBA75Y5O.js → chunk-HS662RLW.js} +61 -33
  147. package/dist/chunk-HS662RLW.js.map +1 -0
  148. package/dist/{chunk-O63ZROSY.js → chunk-IWSTMVCA.js} +7 -7
  149. package/dist/chunk-J2AVWIMM.js +60 -0
  150. package/dist/chunk-J2AVWIMM.js.map +1 -0
  151. package/dist/{chunk-7QKIL5YF.js → chunk-J2GDA64N.js} +4 -4
  152. package/dist/{chunk-TZC6KIK2.js → chunk-JG733RMP.js} +5 -5
  153. package/dist/{chunk-CW5Z67NA.js → chunk-JH2XLVWM.js} +2 -2
  154. package/dist/{chunk-TYXFFNPM.js → chunk-JKZPGCN7.js} +11 -11
  155. package/dist/{chunk-QRRWLLXW.js → chunk-JN2IANXD.js} +3 -3
  156. package/dist/{chunk-HQCZT6TO.js → chunk-JVOEVTCZ.js} +5 -5
  157. package/dist/{chunk-GBB23QLL.js → chunk-KJKD6Y6V.js} +3 -3
  158. package/dist/{chunk-XLU5WFSY.js → chunk-L3PDY7CJ.js} +2 -2
  159. package/dist/{chunk-S6D7NOV7.js → chunk-L6JAALMX.js} +3 -3
  160. package/dist/{chunk-72HOUWAW.js → chunk-L6YTVXGN.js} +5 -3
  161. package/dist/{chunk-72HOUWAW.js.map → chunk-L6YTVXGN.js.map} +1 -1
  162. package/dist/chunk-LZNUBQ5I.js +181 -0
  163. package/dist/chunk-LZNUBQ5I.js.map +1 -0
  164. package/dist/{chunk-BECKKDYG.js → chunk-M2M4IDFU.js} +2 -2
  165. package/dist/{chunk-AMLHEKSV.js → chunk-M3XJVD5G.js} +5 -5
  166. package/dist/{chunk-CSGBHYW6.js → chunk-M5Y42AZ4.js} +2 -2
  167. package/dist/chunk-MICX23P4.js +122 -0
  168. package/dist/chunk-MICX23P4.js.map +1 -0
  169. package/dist/{chunk-5CP5Z3YU.js → chunk-MPWA55CF.js} +4 -4
  170. package/dist/{chunk-CJUK32UH.js → chunk-MYTV353T.js} +5 -5
  171. package/dist/{chunk-BO6MT2S2.js → chunk-MZAYIG2I.js} +7 -6
  172. package/dist/chunk-MZAYIG2I.js.map +1 -0
  173. package/dist/{chunk-AKE6KVQG.js → chunk-NGXL4R54.js} +5 -1
  174. package/dist/chunk-NGXL4R54.js.map +1 -0
  175. package/dist/{chunk-BEHT4IHH.js → chunk-NKEFH3RS.js} +6 -6
  176. package/dist/{chunk-NI67M453.js → chunk-PGANINQD.js} +5 -5
  177. package/dist/{chunk-RCTHCXS6.js → chunk-PJNIJIE6.js} +2 -2
  178. package/dist/{chunk-E2UOEI7N.js → chunk-Q3SILZTQ.js} +2 -2
  179. package/dist/{chunk-SB2SEGR6.js → chunk-QHIWV55K.js} +3 -3
  180. package/dist/{chunk-DHAXUVMR.js → chunk-QN7FVZQD.js} +4 -4
  181. package/dist/{chunk-5S5K73I6.js → chunk-QSOCOXVL.js} +3 -3
  182. package/dist/{chunk-NQCTANF3.js → chunk-QVDEGBME.js} +7 -7
  183. package/dist/{chunk-BQBEN44R.js → chunk-RDCIST7P.js} +2 -2
  184. package/dist/{chunk-HUXAIQC5.js → chunk-RZ3P4X2I.js} +2 -2
  185. package/dist/{chunk-QLJU7UUI.js → chunk-T7OIVPCO.js} +38 -3
  186. package/dist/chunk-T7OIVPCO.js.map +1 -0
  187. package/dist/{chunk-U2ILXZDG.js → chunk-TB5CRHTF.js} +2 -2
  188. package/dist/{chunk-X2GWR75Q.js → chunk-TSEBMVYY.js} +3 -3
  189. package/dist/{chunk-OKRITX4S.js → chunk-U2AEM3K4.js} +7 -7
  190. package/dist/{chunk-EXVCVXFX.js → chunk-U2QXQ7D4.js} +6 -6
  191. package/dist/{chunk-K6FCSB6T.js → chunk-U2SAW6DH.js} +2 -2
  192. package/dist/{chunk-DAHSKQBV.js → chunk-UMOHHWXY.js} +2 -2
  193. package/dist/{chunk-YDIC6LSP.js → chunk-VCQFDQM3.js} +27 -7
  194. package/dist/chunk-VCQFDQM3.js.map +1 -0
  195. package/dist/{chunk-P772HCHI.js → chunk-W676GY42.js} +4 -4
  196. package/dist/{chunk-BAQ3ITZV.js → chunk-WCF56ZCD.js} +2 -2
  197. package/dist/{chunk-6D5AMANO.js → chunk-WH3LUOCQ.js} +2 -2
  198. package/dist/{chunk-T2G4LDU5.js → chunk-WLLUARTC.js} +2 -2
  199. package/dist/{chunk-5BVAUUWL.js → chunk-X37NTEVS.js} +2 -2
  200. package/dist/{chunk-5KK3I42O.js → chunk-XILMDEGZ.js} +13 -10
  201. package/dist/chunk-XILMDEGZ.js.map +1 -0
  202. package/dist/{chunk-MW7P2C2C.js → chunk-YGQM6GFQ.js} +2 -2
  203. package/dist/{chunk-WW3F7DCX.js → chunk-Z2WZDVGG.js} +2 -2
  204. package/dist/{chunk-WNNA6YYE.js → chunk-Z7T4EFEC.js} +7 -4
  205. package/dist/chunk-Z7T4EFEC.js.map +1 -0
  206. package/dist/{chunk-LOLYBFYY.js → chunk-ZCNR4DN5.js} +5 -5
  207. package/dist/{chunk-COKPPU42.js → chunk-ZIHSCBMN.js} +12 -12
  208. package/dist/data-display/Alert.js +3 -3
  209. package/dist/data-display/AsyncStateContainer.js +3 -3
  210. package/dist/data-display/Avatar.js +3 -3
  211. package/dist/data-display/CardKit.js +15 -15
  212. package/dist/data-display/Carousel.js +5 -4
  213. package/dist/data-display/Chart.js +11 -11
  214. package/dist/data-display/Chip.js +3 -3
  215. package/dist/data-display/DataGrid.js +2 -2
  216. package/dist/data-display/DataViews.js +75 -50
  217. package/dist/data-display/DayRuler.js +4 -4
  218. package/dist/data-display/EmptyState.js +2 -2
  219. package/dist/data-display/FleetMap.js +15 -15
  220. package/dist/data-display/InteractiveTooltip.js +2 -2
  221. package/dist/data-display/Lightbox.js +7 -7
  222. package/dist/data-display/MapPreview.js +11 -10
  223. package/dist/data-display/RegionMap.js +11 -5
  224. package/dist/data-display/SectionOnboarding.js +3 -3
  225. package/dist/en-US.js +1 -1
  226. package/dist/feedback/NotificationStatusNotice.js +4 -4
  227. package/dist/feedback/SequenceResolver.js +6 -6
  228. package/dist/form/Calendar.js +5 -5
  229. package/dist/form/DateRangePicker.js +10 -10
  230. package/dist/layout/SettingCard.js +12 -12
  231. package/dist/locales.js +5 -5
  232. package/dist/pt-BR.js +1 -1
  233. package/dist/types/components/data-display/DataViews/data-views-bar-controls.d.ts +15 -1
  234. package/dist/types/components/data-display/DataViews/data-views-bar-controls.d.ts.map +1 -1
  235. package/dist/types/components/data-display/DataViews/data-views-copy.d.ts +35 -0
  236. package/dist/types/components/data-display/DataViews/data-views-copy.d.ts.map +1 -1
  237. package/dist/types/components/data-display/DataViews/data-views-day-input.d.ts +7 -1
  238. package/dist/types/components/data-display/DataViews/data-views-day-input.d.ts.map +1 -1
  239. package/dist/types/components/data-display/DataViews/data-views-more-fields.d.ts.map +1 -1
  240. package/dist/types/components/data-display/DataViews/data-views-more-filters.d.ts +5 -3
  241. package/dist/types/components/data-display/DataViews/data-views-more-filters.d.ts.map +1 -1
  242. package/dist/types/components/data-display/DataViews/data-views-number-input.d.ts +10 -2
  243. package/dist/types/components/data-display/DataViews/data-views-number-input.d.ts.map +1 -1
  244. package/dist/types/components/data-display/DataViews/data-views-preset-chips.d.ts +10 -0
  245. package/dist/types/components/data-display/DataViews/data-views-preset-chips.d.ts.map +1 -1
  246. package/dist/types/components/data-display/DataViews/data-views-range-bounds.d.ts +35 -0
  247. package/dist/types/components/data-display/DataViews/data-views-range-bounds.d.ts.map +1 -0
  248. package/dist/types/components/data-display/DataViews/data-views-range-calendar.d.ts +35 -0
  249. package/dist/types/components/data-display/DataViews/data-views-range-calendar.d.ts.map +1 -0
  250. package/dist/types/components/data-display/DataViews/data-views-range-pill.d.ts +2 -11
  251. package/dist/types/components/data-display/DataViews/data-views-range-pill.d.ts.map +1 -1
  252. package/dist/types/components/data-display/DataViews/data-views-range-summary.d.ts +21 -0
  253. package/dist/types/components/data-display/DataViews/data-views-range-summary.d.ts.map +1 -0
  254. package/dist/types/components/data-display/DataViews/data-views-still-anchor.d.ts +45 -0
  255. package/dist/types/components/data-display/DataViews/data-views-still-anchor.d.ts.map +1 -0
  256. package/dist/types/components/data-display/LazyImage/LazyImage.hooks.d.ts +1 -1
  257. package/dist/types/components/data-display/RegionMap/RegionMap.d.ts +4 -1
  258. package/dist/types/components/data-display/RegionMap/RegionMap.d.ts.map +1 -1
  259. package/dist/types/components/data-display/RegionMap/RegionMap.hooks.d.ts +4 -2
  260. package/dist/types/components/data-display/RegionMap/RegionMap.hooks.d.ts.map +1 -1
  261. package/dist/types/components/data-display/RegionMap/RegionMap.types.d.ts +40 -0
  262. package/dist/types/components/data-display/RegionMap/RegionMap.types.d.ts.map +1 -1
  263. package/dist/types/components/data-display/RegionMap/RegionMap.view.d.ts +36 -0
  264. package/dist/types/components/data-display/RegionMap/RegionMap.view.d.ts.map +1 -0
  265. package/dist/types/components/data-display/RegionMap/RegionMapDrawing.d.ts +4 -1
  266. package/dist/types/components/data-display/RegionMap/RegionMapDrawing.d.ts.map +1 -1
  267. package/dist/types/components/data-display/RegionMap/index.d.ts +3 -2
  268. package/dist/types/components/data-display/RegionMap/index.d.ts.map +1 -1
  269. package/dist/types/components/form/Calendar/Calendar.d.ts.map +1 -1
  270. package/dist/types/components/form/Calendar/CalendarDay.d.ts +2 -0
  271. package/dist/types/components/form/Calendar/CalendarDay.d.ts.map +1 -1
  272. package/dist/types/components/form/Calendar/CalendarDayCell.d.ts +2 -0
  273. package/dist/types/components/form/Calendar/CalendarDayCell.d.ts.map +1 -1
  274. package/dist/types/components/form/Calendar/CalendarMonth.d.ts +5 -0
  275. package/dist/types/components/form/Calendar/CalendarMonth.d.ts.map +1 -1
  276. package/dist/types/en-US.data-display.d.ts.map +1 -1
  277. package/dist/types/pt-BR.data-display.d.ts.map +1 -1
  278. package/dist/user-avatar.js +4 -4
  279. package/package.json +1 -1
  280. package/src/components/data-display/DataViews/RESPONSIVE-BEHAVIOUR.md +59 -0
  281. package/src/components/data-display/DataViews/data-views-bar-controls.tsx +56 -1
  282. package/src/components/data-display/DataViews/data-views-copy.ts +36 -0
  283. package/src/components/data-display/DataViews/data-views-day-input.tsx +9 -1
  284. package/src/components/data-display/DataViews/data-views-inline-bar.tsx +5 -3
  285. package/src/components/data-display/DataViews/data-views-more-fields.tsx +1 -0
  286. package/src/components/data-display/DataViews/data-views-more-filters.tsx +82 -29
  287. package/src/components/data-display/DataViews/data-views-number-input.tsx +19 -9
  288. package/src/components/data-display/DataViews/data-views-preset-chips.tsx +165 -16
  289. package/src/components/data-display/DataViews/data-views-range-bounds.tsx +223 -0
  290. package/src/components/data-display/DataViews/data-views-range-calendar.tsx +185 -0
  291. package/src/components/data-display/DataViews/data-views-range-pill.tsx +71 -154
  292. package/src/components/data-display/DataViews/data-views-range-summary.tsx +66 -0
  293. package/src/components/data-display/DataViews/data-views-still-anchor.ts +93 -0
  294. package/src/components/data-display/RegionMap/RegionMap.hooks.ts +24 -33
  295. package/src/components/data-display/RegionMap/RegionMap.md +27 -0
  296. package/src/components/data-display/RegionMap/RegionMap.tsx +7 -1
  297. package/src/components/data-display/RegionMap/RegionMap.types.ts +41 -0
  298. package/src/components/data-display/RegionMap/RegionMap.view.ts +105 -0
  299. package/src/components/data-display/RegionMap/RegionMapDrawing.tsx +11 -0
  300. package/src/components/data-display/RegionMap/index.ts +5 -1
  301. package/src/components/data-display/RegionMap/tests.md +10 -2
  302. package/src/components/form/Calendar/Calendar.md +17 -2
  303. package/src/components/form/Calendar/Calendar.tsx +56 -3
  304. package/src/components/form/Calendar/CalendarDay.tsx +33 -3
  305. package/src/components/form/Calendar/CalendarDayCell.tsx +4 -0
  306. package/src/components/form/Calendar/CalendarMonth.tsx +27 -5
  307. package/src/en-US.data-display.ts +12 -0
  308. package/src/pt-BR.data-display.ts +12 -0
  309. package/dist/chunk-5KK3I42O.js.map +0 -1
  310. package/dist/chunk-5RSK5M6M.js.map +0 -1
  311. package/dist/chunk-7D7CJRL7.js +0 -78
  312. package/dist/chunk-7D7CJRL7.js.map +0 -1
  313. package/dist/chunk-ACFKPE2T.js +0 -1
  314. package/dist/chunk-AKE6KVQG.js.map +0 -1
  315. package/dist/chunk-BO6MT2S2.js.map +0 -1
  316. package/dist/chunk-FEKWKWGK.js.map +0 -1
  317. package/dist/chunk-FJ3UZ4RC.js.map +0 -1
  318. package/dist/chunk-GMRQPNG3.js.map +0 -1
  319. package/dist/chunk-OBA75Y5O.js.map +0 -1
  320. package/dist/chunk-Q2ERGAQO.js.map +0 -1
  321. package/dist/chunk-QLJU7UUI.js.map +0 -1
  322. package/dist/chunk-TRYR424I.js.map +0 -1
  323. package/dist/chunk-WNNA6YYE.js.map +0 -1
  324. package/dist/chunk-X5OGIT2F.js.map +0 -1
  325. package/dist/chunk-XHIBFBNP.js.map +0 -1
  326. package/dist/chunk-YDIC6LSP.js.map +0 -1
  327. /package/dist/{chunk-ACFKPE2T.js.map → _internal/components/data-display/DataViews/data-views-range-bounds.js.map} +0 -0
  328. /package/dist/{chunk-K2VDRODL.js.map → chunk-3IDL7NK7.js.map} +0 -0
  329. /package/dist/{chunk-6ATXOJVQ.js.map → chunk-3JZ3KEQQ.js.map} +0 -0
  330. /package/dist/{chunk-EOIRU62W.js.map → chunk-42D7KBDH.js.map} +0 -0
  331. /package/dist/{chunk-LXIPBHNJ.js.map → chunk-42TOCPXB.js.map} +0 -0
  332. /package/dist/{chunk-WAO7UQRS.js.map → chunk-4KWDNGMA.js.map} +0 -0
  333. /package/dist/{chunk-JIEVKHOH.js.map → chunk-4QR7LM5F.js.map} +0 -0
  334. /package/dist/{chunk-WJMSND5Q.js.map → chunk-5E2CRRD4.js.map} +0 -0
  335. /package/dist/{chunk-ZDAAHCIS.js.map → chunk-5HADIIWN.js.map} +0 -0
  336. /package/dist/{chunk-BP3ZKIPE.js.map → chunk-64UNVW6D.js.map} +0 -0
  337. /package/dist/{chunk-6WHIJPEF.js.map → chunk-6PU5P7QT.js.map} +0 -0
  338. /package/dist/{chunk-7F6D73NL.js.map → chunk-76DX2IMH.js.map} +0 -0
  339. /package/dist/{chunk-YNZUYZ2O.js.map → chunk-A3DDEKLV.js.map} +0 -0
  340. /package/dist/{chunk-BMTIBQQC.js.map → chunk-BBBHPK2Q.js.map} +0 -0
  341. /package/dist/{chunk-DYHOBKPU.js.map → chunk-BLZDSCIZ.js.map} +0 -0
  342. /package/dist/{chunk-EUR2ORTN.js.map → chunk-CSJ7WNXU.js.map} +0 -0
  343. /package/dist/{chunk-OWRQOYUE.js.map → chunk-DA3D5X5Z.js.map} +0 -0
  344. /package/dist/{chunk-LV6AD6XC.js.map → chunk-DBI6AMNY.js.map} +0 -0
  345. /package/dist/{chunk-3YFDGFEK.js.map → chunk-DVX4HDNP.js.map} +0 -0
  346. /package/dist/{chunk-QKOJ4637.js.map → chunk-E6K2UZGR.js.map} +0 -0
  347. /package/dist/{chunk-7XSCEHGA.js.map → chunk-EOQ6EKTS.js.map} +0 -0
  348. /package/dist/{chunk-Z5WUSI47.js.map → chunk-G3JFESKD.js.map} +0 -0
  349. /package/dist/{chunk-3EIRRLCQ.js.map → chunk-HC6OZ7QK.js.map} +0 -0
  350. /package/dist/{chunk-SKIAWOUC.js.map → chunk-HOPRZEBM.js.map} +0 -0
  351. /package/dist/{chunk-O63ZROSY.js.map → chunk-IWSTMVCA.js.map} +0 -0
  352. /package/dist/{chunk-7QKIL5YF.js.map → chunk-J2GDA64N.js.map} +0 -0
  353. /package/dist/{chunk-TZC6KIK2.js.map → chunk-JG733RMP.js.map} +0 -0
  354. /package/dist/{chunk-CW5Z67NA.js.map → chunk-JH2XLVWM.js.map} +0 -0
  355. /package/dist/{chunk-TYXFFNPM.js.map → chunk-JKZPGCN7.js.map} +0 -0
  356. /package/dist/{chunk-QRRWLLXW.js.map → chunk-JN2IANXD.js.map} +0 -0
  357. /package/dist/{chunk-HQCZT6TO.js.map → chunk-JVOEVTCZ.js.map} +0 -0
  358. /package/dist/{chunk-GBB23QLL.js.map → chunk-KJKD6Y6V.js.map} +0 -0
  359. /package/dist/{chunk-XLU5WFSY.js.map → chunk-L3PDY7CJ.js.map} +0 -0
  360. /package/dist/{chunk-S6D7NOV7.js.map → chunk-L6JAALMX.js.map} +0 -0
  361. /package/dist/{chunk-BECKKDYG.js.map → chunk-M2M4IDFU.js.map} +0 -0
  362. /package/dist/{chunk-AMLHEKSV.js.map → chunk-M3XJVD5G.js.map} +0 -0
  363. /package/dist/{chunk-CSGBHYW6.js.map → chunk-M5Y42AZ4.js.map} +0 -0
  364. /package/dist/{chunk-5CP5Z3YU.js.map → chunk-MPWA55CF.js.map} +0 -0
  365. /package/dist/{chunk-CJUK32UH.js.map → chunk-MYTV353T.js.map} +0 -0
  366. /package/dist/{chunk-BEHT4IHH.js.map → chunk-NKEFH3RS.js.map} +0 -0
  367. /package/dist/{chunk-NI67M453.js.map → chunk-PGANINQD.js.map} +0 -0
  368. /package/dist/{chunk-RCTHCXS6.js.map → chunk-PJNIJIE6.js.map} +0 -0
  369. /package/dist/{chunk-E2UOEI7N.js.map → chunk-Q3SILZTQ.js.map} +0 -0
  370. /package/dist/{chunk-SB2SEGR6.js.map → chunk-QHIWV55K.js.map} +0 -0
  371. /package/dist/{chunk-DHAXUVMR.js.map → chunk-QN7FVZQD.js.map} +0 -0
  372. /package/dist/{chunk-5S5K73I6.js.map → chunk-QSOCOXVL.js.map} +0 -0
  373. /package/dist/{chunk-NQCTANF3.js.map → chunk-QVDEGBME.js.map} +0 -0
  374. /package/dist/{chunk-BQBEN44R.js.map → chunk-RDCIST7P.js.map} +0 -0
  375. /package/dist/{chunk-HUXAIQC5.js.map → chunk-RZ3P4X2I.js.map} +0 -0
  376. /package/dist/{chunk-U2ILXZDG.js.map → chunk-TB5CRHTF.js.map} +0 -0
  377. /package/dist/{chunk-X2GWR75Q.js.map → chunk-TSEBMVYY.js.map} +0 -0
  378. /package/dist/{chunk-OKRITX4S.js.map → chunk-U2AEM3K4.js.map} +0 -0
  379. /package/dist/{chunk-EXVCVXFX.js.map → chunk-U2QXQ7D4.js.map} +0 -0
  380. /package/dist/{chunk-K6FCSB6T.js.map → chunk-U2SAW6DH.js.map} +0 -0
  381. /package/dist/{chunk-DAHSKQBV.js.map → chunk-UMOHHWXY.js.map} +0 -0
  382. /package/dist/{chunk-P772HCHI.js.map → chunk-W676GY42.js.map} +0 -0
  383. /package/dist/{chunk-BAQ3ITZV.js.map → chunk-WCF56ZCD.js.map} +0 -0
  384. /package/dist/{chunk-6D5AMANO.js.map → chunk-WH3LUOCQ.js.map} +0 -0
  385. /package/dist/{chunk-T2G4LDU5.js.map → chunk-WLLUARTC.js.map} +0 -0
  386. /package/dist/{chunk-5BVAUUWL.js.map → chunk-X37NTEVS.js.map} +0 -0
  387. /package/dist/{chunk-MW7P2C2C.js.map → chunk-YGQM6GFQ.js.map} +0 -0
  388. /package/dist/{chunk-WW3F7DCX.js.map → chunk-Z2WZDVGG.js.map} +0 -0
  389. /package/dist/{chunk-LOLYBFYY.js.map → chunk-ZCNR4DN5.js.map} +0 -0
  390. /package/dist/{chunk-COKPPU42.js.map → chunk-ZIHSCBMN.js.map} +0 -0
@@ -6,16 +6,19 @@ import {
6
6
  geometryCache,
7
7
  hitRegion,
8
8
  projectionAt,
9
- viewBoxFor,
10
9
  type DrawnRegion,
11
10
  type PlaneBox,
11
+ type Projection,
12
12
  } from './RegionMap.helpers';
13
- import type { RegionMapProps, RegionMapRegion } from './RegionMap.types';
13
+ import type { RegionMapProps } from './RegionMap.types';
14
+ import { centreOf, reachBox, viewWithin } from './RegionMap.view';
14
15
 
15
16
  /** What the drawing needs, derived from the props. */
16
17
  export interface RegionMapModel {
17
18
  /** The square shown, or null when there is nothing to centre on. */
18
19
  view: PlaneBox | null;
20
+ /** The projection drawn with, or null when there is nothing to centre on. */
21
+ projection: Projection | null;
19
22
  drawn: DrawnRegion[];
20
23
  /** Radii drawn, in metres; empty without circles. */
21
24
  radii: number[];
@@ -28,15 +31,6 @@ export interface RegionMapModel {
28
31
  /** A tap reaches an area this close: a share of the view (~8 px on a phone). */
29
32
  const TOLERANCE_SHARE = 1 / 45;
30
33
 
31
- /** The middle of every area, for a map with no centre of its own. */
32
- function centreOf(regions: readonly RegionMapRegion[]): { latitude: number; longitude: number } | null {
33
- const points = regions.flatMap((r) => r.rings.flat());
34
- const lats = extent(points.map(([lat]) => lat));
35
- const lngs = extent(points.map(([, lng]) => lng));
36
- if (lats === null || lngs === null) return null;
37
- return { latitude: (lats.min + lats.max) / 2, longitude: (lngs.min + lngs.max) / 2 };
38
- }
39
-
40
34
  /** The click, in the drawing's own coordinates — or null where it cannot be read. */
41
35
  function svgPoint(event: React.MouseEvent<SVGSVGElement>): { x: number; y: number } | null {
42
36
  const svg = event.currentTarget;
@@ -46,16 +40,6 @@ function svgPoint(event: React.MouseEvent<SVGSVGElement>): { x: number; y: numbe
46
40
  return { x: point.x, y: point.y };
47
41
  }
48
42
 
49
- /** The view: the outermost circle when there is one, else every area's box. */
50
- function viewOf(outermostMetres: number | null, drawable: () => (PlaneBox | null)[]): PlaneBox | null {
51
- if (outermostMetres !== null) return viewBoxFor(outermostMetres, null);
52
- const boxes = drawable().filter((box): box is PlaneBox => box !== null);
53
- const xs = extent(boxes.flatMap((b) => [b.minX, b.minX + b.spanX]));
54
- const ys = extent(boxes.flatMap((b) => [b.minY, b.minY + b.spanY]));
55
- if (xs === null || ys === null) return null;
56
- return viewBoxFor(null, { minX: xs.min, minY: ys.min, spanX: xs.max - xs.min, spanY: ys.max - ys.min });
57
- }
58
-
59
43
  /** Which area a click or tap means — see `useRegionMap`. */
60
44
  function tappedRegion(
61
45
  event: React.MouseEvent<SVGSVGElement>,
@@ -74,16 +58,18 @@ function tappedRegion(
74
58
  );
75
59
  }
76
60
 
77
- /** The geometry cache for a centre, or null without one. */
78
- function useGeometry(
79
- origin: { latitude: number; longitude: number } | null,
80
- ): ReturnType<typeof geometryCache> | null {
61
+ /** The projection and geometry cache for a centre, or nulls without one. */
62
+ function useGeometry(origin: { latitude: number; longitude: number } | null): {
63
+ projection: Projection | null;
64
+ geometryOf: ReturnType<typeof geometryCache> | null;
65
+ } {
81
66
  const lat = origin?.latitude ?? null;
82
67
  const lng = origin?.longitude ?? null;
83
- return React.useMemo(
84
- () => (lat === null || lng === null ? null : geometryCache(projectionAt({ latitude: lat, longitude: lng }))),
85
- [lat, lng],
86
- );
68
+ return React.useMemo(() => {
69
+ if (lat === null || lng === null) return { projection: null, geometryOf: null };
70
+ const projection = projectionAt({ latitude: lat, longitude: lng });
71
+ return { projection, geometryOf: geometryCache(projection) };
72
+ }, [lat, lng]);
87
73
  }
88
74
 
89
75
  /**
@@ -101,13 +87,18 @@ export function useRegionMap({
101
87
  regions,
102
88
  center,
103
89
  circles = [],
90
+ reach,
104
91
  onToggle,
105
- }: Pick<RegionMapProps, 'regions' | 'center' | 'circles' | 'onToggle'>): RegionMapModel {
106
- const geometryOf = useGeometry(center ?? centreOf(regions));
92
+ }: Pick<RegionMapProps, 'regions' | 'center' | 'circles' | 'reach' | 'onToggle'>): RegionMapModel {
93
+ const { projection, geometryOf } = useGeometry(center ?? centreOf(regions));
107
94
  const radii = circles.map((c) => c.radiusMetres);
108
95
  const outermostMetres = extent(radii)?.max ?? null;
109
96
  const view =
110
- geometryOf === null ? null : viewOf(outermostMetres, () => regions.map((r) => geometryOf(r.rings).bounds));
97
+ projection === null || geometryOf === null
98
+ ? null
99
+ : viewWithin(outermostMetres, reach === undefined ? null : reachBox(reach, projection), () =>
100
+ regions.map((r) => geometryOf(r.rings).bounds),
101
+ );
111
102
  const drawn = geometryOf && view ? drawOrder(regions, geometryOf, view) : [];
112
103
  const pointerType = React.useRef<string>('mouse');
113
104
 
@@ -121,5 +112,5 @@ export function useRegionMap({
121
112
  if (hit) onToggle(hit);
122
113
  };
123
114
 
124
- return { view, drawn, radii, outermostMetres, onPointerDown, onClick };
115
+ return { view, projection, drawn, radii, outermostMetres, onPointerDown, onClick };
125
116
  }
@@ -75,6 +75,27 @@ clipped at an edge — the map reads the same at 320 px and at 1600 px. The
75
75
  drawing is square; `maxHeight` caps it on a wide screen, and where it sits in a
76
76
  wider box is the host's call.
77
77
 
78
+ ### A host can draw inside it, at its scale
79
+
80
+ A host often has something of its own to show over the areas — a band served
81
+ past the largest circle, a route, a marker — and laying a second SVG over the
82
+ drawing means copying its view math and losing its frame. So:
83
+
84
+ - `reach` (`{ radiusMetres }` or `{ bounds }`) is an extent the view must ALSO
85
+ fit, before the 12% margin. With circles the view stays centred on the centre
86
+ and grows to the reach's farthest edge, so a ring stays a circle in the
87
+ middle; without circles the view fits the areas and the reach together. A
88
+ reach no radius describes — the outlines of some areas — is a box:
89
+ `boundsOfRings(rings)`. Omit it and the view is exactly what it was.
90
+ - `overlay(layer)` draws inside the SVG with `layer.view` and
91
+ `layer.projection` (`projectionAt(center)`), over the excluded hatch and
92
+ under the circles, highlights and centre. It sits in a `pointer-events: none`
93
+ group, so a tap still reaches the area beneath.
94
+ - `regionMapView(props)` returns the same view for HTML laid over the drawing
95
+ (a pill on a circle, a note): a point `p` sits at `(p.x - view.minX) /
96
+ view.spanX` across; with circles the view is centred and its half-side is
97
+ `view.spanX / 2`.
98
+
78
99
  ## Props
79
100
 
80
101
  | prop | type | default | what it does |
@@ -82,6 +103,8 @@ wider box is the host's call.
82
103
  | `regions` | `readonly RegionMapRegion[]` | — | the areas; drawn when any part is in view |
83
104
  | `center` | `{ latitude, longitude } \| null` | — | centre, dot and circles; `null` centres on the areas, no dot |
84
105
  | `circles` | `readonly { radiusMetres }[]` | `[]` | dashed circles; the view fits the largest |
106
+ | `reach` | `{ radiusMetres } \| { bounds: { south, west, north, east } }` | — | an extent the view must also fit (margin on top) |
107
+ | `overlay` | `(layer: { view, projection }) => ReactNode` | — | a host layer inside the SVG, under the circles, tap-transparent |
85
108
  | `onToggle` | `(id: string) => void` | — | a tap or a list press; omit for read-only |
86
109
  | `highlightedIds` | `readonly string[]` | `[]` | areas to point at (a search's hits), outlined and named |
87
110
  | `copy` | `RegionMapCopy` | — | every word |
@@ -117,6 +140,10 @@ wider box is the host's call.
117
140
  `[latitude, longitude]` points; outlines usually travel this way.
118
141
  - `hitRegion(regions, point, tolerance)` and `projectionAt(center)` — the hit
119
142
  test and projection the component uses, for a host that draws its own layer.
143
+ - `regionMapView({ regions, center, circles, reach })` — the view the
144
+ component shows for those props, in projected metres, for HTML laid over it.
145
+ - `boundsOfRings(rings)` — the latitude/longitude box around some outlines,
146
+ for a `reach` no radius describes.
120
147
 
121
148
  ## Example
122
149
 
@@ -29,6 +29,9 @@ const NO_IDS: readonly string[] = [];
29
29
  * is that path. A finger's tap takes the SMALLEST area within a few pixels'
30
30
  * worth of metres (`hitRegion`), so a sliver beside a big area can be hit
31
31
  * from the map; one too thin even for that is still on the list.
32
+ * - **The host can draw inside it.** `reach` widens the view past the largest
33
+ * circle and `overlay` draws a layer in the SVG at the map's own projection,
34
+ * tap-transparent; `regionMapView` gives the same view to HTML laid over it.
32
35
  * - **A toggle is cheap.** Geometry is projected once per `rings` identity,
33
36
  * and the base layer is memoised, so a tap re-renders the hatch and labels.
34
37
  */
@@ -36,6 +39,8 @@ export function RegionMap({
36
39
  regions,
37
40
  center,
38
41
  circles,
42
+ reach,
43
+ overlay,
39
44
  onToggle,
40
45
  highlightedIds = NO_IDS,
41
46
  copy,
@@ -46,7 +51,7 @@ export function RegionMap({
46
51
  dataTestId = 'region-map',
47
52
  }: RegionMapProps): React.JSX.Element | null {
48
53
  const theme = useTheme();
49
- const model = useRegionMap({ regions, center, circles, onToggle });
54
+ const model = useRegionMap({ regions, center, circles, reach, onToggle });
50
55
  const { view } = model;
51
56
  if (view === null && regions.length === 0) return null;
52
57
  return (
@@ -55,6 +60,7 @@ export function RegionMap({
55
60
  <>
56
61
  <RegionMapDrawing
57
62
  model={{ ...model, view }}
63
+ overlay={overlay}
58
64
  showCenter={center !== null}
59
65
  highlightedIds={highlightedIds}
60
66
  maxHeight={maxHeight}
@@ -7,6 +7,10 @@
7
7
  * every word arrives through `copy`.
8
8
  */
9
9
 
10
+ import type React from 'react';
11
+
12
+ import type { PlaneBox, Projection } from './RegionMap.helpers';
13
+
10
14
  /** A latitude/longitude pair, in that order. */
11
15
  export type RegionMapPoint = readonly [latitude: number, longitude: number];
12
16
 
@@ -50,6 +54,29 @@ export interface RegionMapCircle {
50
54
  radiusMetres: number;
51
55
  }
52
56
 
57
+ /** A latitude/longitude box, by its four edges in degrees. */
58
+ export interface RegionMapBounds {
59
+ south: number;
60
+ west: number;
61
+ north: number;
62
+ east: number;
63
+ }
64
+
65
+ /**
66
+ * An extent the view must fit besides its circles: a radius around the centre,
67
+ * or a box — e.g. the bounds of some outlines (`boundsOfRings`), for a reach
68
+ * no single radius describes.
69
+ */
70
+ export type RegionMapReach = { radiusMetres: number } | { bounds: RegionMapBounds };
71
+
72
+ /** What a host overlay is drawn with: the map's own view and projection. */
73
+ export interface RegionMapLayer {
74
+ /** The SVG viewBox, in projected metres. */
75
+ view: PlaneBox;
76
+ /** The projection the map draws with — `projectionAt(center)`. */
77
+ projection: Projection;
78
+ }
79
+
53
80
  /** Every word the map prints or announces. */
54
81
  export interface RegionMapCopy {
55
82
  /** The drawing's accessible name (`role="img"`). */
@@ -95,6 +122,20 @@ export interface RegionMapProps {
95
122
  center: { latitude: number; longitude: number } | null;
96
123
  /** Circles around the centre; the view fits the largest. */
97
124
  circles?: readonly RegionMapCircle[];
125
+ /**
126
+ * An extent the view must ALSO fit, before its margin — something the host
127
+ * draws past the largest circle. With circles the view stays centred on the
128
+ * centre and grows to the reach's farthest edge; without, it fits the areas
129
+ * and the reach together. Omit it and the view is the circles' (or areas').
130
+ */
131
+ reach?: RegionMapReach;
132
+ /**
133
+ * A host layer drawn INSIDE the drawing's SVG, over the excluded hatch and
134
+ * under the circles, highlights and centre, so it shares the map's view,
135
+ * projection and frame. It is wrapped in `pointer-events: none`: taps go
136
+ * through it to the areas. Return SVG elements, in projected metres.
137
+ */
138
+ overlay?: (layer: RegionMapLayer) => React.ReactNode;
98
139
  /**
99
140
  * A tap on an area, or a press of its list button. Omit it and the map is
100
141
  * read-only: nothing is tappable and the list rows are not buttons.
@@ -0,0 +1,105 @@
1
+ import {
2
+ extent,
3
+ planeBounds,
4
+ projectionAt,
5
+ projectRings,
6
+ viewBoxFor,
7
+ type PlaneBox,
8
+ type Projection,
9
+ } from './RegionMap.helpers';
10
+ import type {
11
+ RegionMapBounds,
12
+ RegionMapCircle,
13
+ RegionMapReach,
14
+ RegionMapRegion,
15
+ RegionMapRing,
16
+ } from './RegionMap.types';
17
+
18
+ // What `RegionMap` shows: its view, given the circles, the areas and a host's
19
+ // `reach` — pure, so a host laying HTML over the drawing computes the same one.
20
+
21
+ /** The smallest box holding every given box, or null with none. */
22
+ export function unionBox(boxes: readonly (PlaneBox | null)[]): PlaneBox | null {
23
+ const real = boxes.filter((box): box is PlaneBox => box !== null);
24
+ const xs = extent(real.flatMap((b) => [b.minX, b.minX + b.spanX]));
25
+ const ys = extent(real.flatMap((b) => [b.minY, b.minY + b.spanY]));
26
+ if (xs === null || ys === null) return null;
27
+ return { minX: xs.min, minY: ys.min, spanX: xs.max - xs.min, spanY: ys.max - ys.min };
28
+ }
29
+
30
+ /** The latitude/longitude box around some outlines — a `reach` no radius describes. */
31
+ export function boundsOfRings(rings: readonly RegionMapRing[]): RegionMapBounds | null {
32
+ const points = rings.flat();
33
+ const lats = extent(points.map(([latitude]) => latitude));
34
+ const lngs = extent(points.map(([, longitude]) => longitude));
35
+ if (lats === null || lngs === null) return null;
36
+ return { south: lats.min, west: lngs.min, north: lats.max, east: lngs.max };
37
+ }
38
+
39
+ /** A `reach` as a box in projected metres (a radius is a square around the centre). */
40
+ export function reachBox(reach: RegionMapReach, projection: Projection): PlaneBox | null {
41
+ if ('radiusMetres' in reach) {
42
+ const r = reach.radiusMetres;
43
+ return Number.isFinite(r) && r > 0 ? { minX: -r, minY: -r, spanX: r * 2, spanY: r * 2 } : null;
44
+ }
45
+ const { south, west, north, east } = reach.bounds;
46
+ const a = projection.project([north, west]);
47
+ const b = projection.project([south, east]);
48
+ return unionBox([{ minX: a.x, minY: a.y, spanX: 0, spanY: 0 }, { minX: b.x, minY: b.y, spanX: 0, spanY: 0 }]);
49
+ }
50
+
51
+ /** How far the box reaches from the centre along either axis — the half-side of a centred square holding it. */
52
+ function farthestEdge(box: PlaneBox): number {
53
+ return Math.max(Math.abs(box.minX), Math.abs(box.minX + box.spanX), Math.abs(box.minY), Math.abs(box.minY + box.spanY));
54
+ }
55
+
56
+ /**
57
+ * The view, given what it must fit: the outermost circle and the `reach` with
58
+ * the margin on top, still centred on the centre; else every area and the
59
+ * reach together. Without a reach it is exactly `viewBoxFor`'s.
60
+ */
61
+ export function viewWithin(
62
+ outermostMetres: number | null,
63
+ reach: PlaneBox | null,
64
+ areaBoxes: () => readonly (PlaneBox | null)[],
65
+ ): PlaneBox | null {
66
+ if (outermostMetres !== null) {
67
+ return viewBoxFor(Math.max(outermostMetres, reach === null ? 0 : farthestEdge(reach)), null);
68
+ }
69
+ return viewBoxFor(null, unionBox([...areaBoxes(), reach]));
70
+ }
71
+
72
+ /** The middle of every area, for a map with no centre of its own. */
73
+ export function centreOf(regions: readonly RegionMapRegion[]): { latitude: number; longitude: number } | null {
74
+ const bounds = boundsOfRings(regions.flatMap((r) => r.rings));
75
+ if (bounds === null) return null;
76
+ return { latitude: (bounds.south + bounds.north) / 2, longitude: (bounds.west + bounds.east) / 2 };
77
+ }
78
+
79
+ /**
80
+ * The square `RegionMap` shows for these props, in projected metres around
81
+ * `center` (or the areas' middle) — for a host that lays its own HTML over the
82
+ * drawing at the same scale: a point `p` sits at
83
+ * `(p.x - view.minX) / view.spanX` across. With circles the view is centred,
84
+ * so its half-side is `view.spanX / 2`.
85
+ */
86
+ export function regionMapView({
87
+ regions,
88
+ center,
89
+ circles = [],
90
+ reach,
91
+ }: {
92
+ regions: readonly RegionMapRegion[];
93
+ center: { latitude: number; longitude: number } | null;
94
+ circles?: readonly RegionMapCircle[];
95
+ reach?: RegionMapReach;
96
+ }): PlaneBox | null {
97
+ const origin = center ?? centreOf(regions);
98
+ if (origin === null) return null;
99
+ const projection = projectionAt(origin);
100
+ return viewWithin(
101
+ extent(circles.map((c) => c.radiusMetres))?.max ?? null,
102
+ reach === undefined ? null : reachBox(reach, projection),
103
+ () => regions.map((r) => planeBounds(projectRings(r.rings, projection))),
104
+ );
105
+ }
@@ -8,9 +8,12 @@ import { rem, remPx } from '../../../tokens/relative';
8
8
  import { labelPosition, type AreaGeometry, type DrawnRegion, type PlaneBox } from './RegionMap.helpers';
9
9
  import type { RegionMapModel } from './RegionMap.hooks';
10
10
  import { labelOrder, placeLabels } from './RegionMap.labels';
11
+ import type { RegionMapLayer } from './RegionMap.types';
11
12
 
12
13
  export interface RegionMapDrawingProps {
13
14
  model: RegionMapModel & { view: PlaneBox };
15
+ /** The host's layer, drawn inside the SVG under the circles (`RegionMapProps.overlay`). */
16
+ overlay?: (layer: RegionMapLayer) => React.ReactNode;
14
17
  showCenter: boolean;
15
18
  highlightedIds: readonly string[];
16
19
  maxHeight: string | undefined;
@@ -32,6 +35,7 @@ export interface RegionMapDrawingProps {
32
35
  */
33
36
  export function RegionMapDrawing({
34
37
  model,
38
+ overlay,
35
39
  showCenter,
36
40
  highlightedIds,
37
41
  maxHeight,
@@ -78,6 +82,13 @@ export function RegionMapDrawing({
78
82
  <Hatch id={hatchId} pitch={view.spanX / 70} theme={theme} />
79
83
  <BaseAreas areas={base} testId={testId} theme={theme} />
80
84
  <ExcludedAreas drawn={drawn} hatchId={hatchId} testId={testId} theme={theme} />
85
+ {overlay && model.projection && (
86
+ // `pointer-events` is inherited in SVG: nothing the host draws here
87
+ // takes a tap from the areas beneath.
88
+ <g pointerEvents="none" data-testid={`${testId}-overlay`}>
89
+ {overlay({ view, projection: model.projection })}
90
+ </g>
91
+ )}
81
92
  <Circles radii={model.radii} theme={theme} />
82
93
  <Highlights areas={highlighted} testId={testId} theme={theme} />
83
94
  {showCenter && (
@@ -1,13 +1,17 @@
1
1
  export { RegionMap } from './RegionMap';
2
2
  export { decodePolyline, hitRegion, projectionAt } from './RegionMap.helpers';
3
- export type { AreaGeometry, PlanePoint, PlaneRegion } from './RegionMap.helpers';
3
+ export { boundsOfRings, regionMapView } from './RegionMap.view';
4
+ export type { AreaGeometry, PlaneBox, PlanePoint, PlaneRegion, Projection } from './RegionMap.helpers';
4
5
  export type {
6
+ RegionMapBounds,
5
7
  RegionMapCircle,
6
8
  RegionMapCopy,
9
+ RegionMapLayer,
7
10
  RegionMapListMode,
8
11
  RegionMapListSort,
9
12
  RegionMapPoint,
10
13
  RegionMapProps,
14
+ RegionMapReach,
11
15
  RegionMapRegion,
12
16
  RegionMapRing,
13
17
  } from './RegionMap.types';
@@ -6,12 +6,20 @@
6
6
  - [x] `__tests__/region-map-helpers.test.ts` — the geometry: even-odd with a
7
7
  hole, distance, which area a tap means (hole, smallest, sliver within the
8
8
  tolerance even from inside a big neighbour, nothing beyond it), the view,
9
- label placement, `extent` on 200k values, the projection and the decoder
9
+ label placement, `extent` on 200k values, the projection and the decoder;
10
+ the view with a reach (none is today's view, a radius past the circle
11
+ grows it centred, a smaller one never shrinks it, a box off to one side
12
+ by its farthest edge, areas and reach together with no circle, a
13
+ non-positive radius ignored) and `boundsOfRings`
10
14
  - [x] `__tests__/region-map.test.tsx` — what is drawn (areas, hatch + name for
11
15
  excluded only, several highlights, nothing with no centre and no areas),
12
16
  what a tap reports, read-only, and the list (collapsed by default with its
13
17
  count, `aria-expanded`, `aria-pressed`, state in words, outside areas off
14
- the list and out of the count, `listed`, sort by name, detail, `none`)
18
+ the list and out of the count, `listed`, sort by name, detail, `none`),
19
+ and the reach and overlay (viewBox unchanged without a reach, widened as
20
+ `regionMapView` says with one, the overlay inside the SVG in a
21
+ `pointer-events: none` group with the map's view and projection, a tap
22
+ still reaching the area beneath, no group without an overlay)
15
23
 
16
24
  ## Storybook Tests Status
17
25
 
@@ -209,11 +209,26 @@ month/year buttons rather than squeezing them (`SelectorsFitA320Sheet`).
209
209
 
210
210
  ## Accessibility
211
211
 
212
- - Container month: `role="grid"`, labelled by month/year (e.g., `aria-labelledby="cal-2025-09"`).
212
+ - Container month: `role="grid"`, named by its month and year in `locale`
213
+ (`aria-label="outubro de 2026"`). It used to point `aria-labelledby` at an id
214
+ nothing carried, so the grid had no name (FUT-4144).
213
215
  - Weekday headers: `role="columnheader"`, short names with `abbr` for SR if needed.
214
216
  - Day cells: `role="gridcell"`, `aria-selected` true for selected day(s). For ranges, set `aria-selected="true"` on all in range or use `aria-current="date"` for today.
217
+ - Each visible day is named whole, in `locale`: `aria-label="1 de outubro de 2026"`
218
+ (`"October 1, 2026"` in en-US). The cell's text is the bare number, which in a
219
+ two-month range calendar names two different days (FUT-4144).
220
+ - The arrows of the default caption carry `labels.previousMonth`/`nextMonth`
221
+ when the host passes `labels`; without `labels` they stay as they were.
215
222
  - Disabled days: `aria-disabled="true"`.
216
- - Keyboard support (roving focus within the grid):
223
+ - With `showOutsideDays={false}` an outside day is an inert, `aria-hidden`
224
+ placeholder: no button, no name, no tab stop. Visible outside days are
225
+ unchanged.
226
+ - Keyboard support (roving focus within the grid). When a NAVIGATION key is
227
+ pressed on a day (the reader tabbed or clicked onto it), focus follows the tab
228
+ stop to the new day in its own month (never its muted copy in the month
229
+ beside it), across a month change too. Enter, Space, Tab and Escape move no
230
+ day and never move focus; with focus on the container it stays there, as
231
+ before:
217
232
  - Arrow keys: move by 1 day (left/right) or 1 week (up/down).
218
233
  - Home/End: move to start/end of week.
219
234
  - PageUp/PageDown: previous/next month (with Shift for year).
@@ -1,7 +1,7 @@
1
1
  import type { SxProps, Theme } from '@mui/material/styles/index.js';
2
2
  import Box from '@mui/material/Box/index.js';
3
3
  import Paper from '@mui/material/Paper/index.js';
4
- import React, { useCallback, useRef } from 'react';
4
+ import React, { useCallback, useEffect, useRef } from 'react';
5
5
 
6
6
  import { EN_US_UI_LABELS } from '../../../en-US.labels';
7
7
  import { rem, sxRem } from '../../../tokens/relative';
@@ -9,6 +9,7 @@ import { resolveLabels } from '../../../utils/resolve-labels';
9
9
 
10
10
  import { resolveCalendarProps } from './Calendar.helpers';
11
11
  import { useCalendar } from './Calendar.hooks';
12
+ import { navigateFocus } from './Calendar.keyboard';
12
13
  import { useCalendarPicker } from './Calendar.picker';
13
14
  import type { CalendarProps, ResolvedCalendarProps } from './Calendar.types';
14
15
  import type { DayCellContext } from './CalendarDayCell';
@@ -32,6 +33,7 @@ type CalendarState = ReturnType<typeof useCalendar>;
32
33
 
33
34
  const buildDayContext = (props: ResolvedCalendarProps, calendar: CalendarState): DayCellContext => ({
34
35
  selectionMode: props.selectionMode,
36
+ locale: props.locale,
35
37
  value: props.value,
36
38
  range: props.range,
37
39
  showOutsideDays: props.showOutsideDays,
@@ -60,6 +62,45 @@ const useRootRef = (forwarded: React.ForwardedRef<HTMLDivElement>) => {
60
62
  return { rootRef, setRoot };
61
63
  };
62
64
 
65
+ /** The tab stop as a day of its OWN month — side by side, an outside copy of it comes first in the DOM. */
66
+ const OWN_MONTH_STOP = '[role="gridcell"][tabindex="0"][data-in-month="true"]';
67
+ const ANY_STOP = '[role="gridcell"][tabindex="0"]';
68
+
69
+ /**
70
+ * Keeps the keyboard's place visible when it is on a DAY.
71
+ *
72
+ * The arrows move the grid's one tab stop (`focusedDate`), and that is enough
73
+ * while the container holds focus. But a reader who tabbed onto a day, or
74
+ * clicked one, has focus on that day's button: the tab stop moved and focus
75
+ * stayed behind on a cell that is no longer it, so the ring sat on the old day
76
+ * and a month change unmounted it under the reader.
77
+ *
78
+ * So a NAVIGATION key pressed on a day notes where the tab stop was, and once
79
+ * it has moved, focus follows it to the day in its own month. Any other key —
80
+ * Enter, Tab, Escape — clears the note: Enter re-sets the same day and must
81
+ * leave focus alone, and a stale note would pull focus into the grid on the
82
+ * next mouse pick.
83
+ */
84
+ const useFollowDayFocus = (
85
+ rootRef: React.RefObject<HTMLDivElement | null>,
86
+ focusedDate: Date,
87
+ firstDayOfWeek: number,
88
+ ) => {
89
+ const movedFrom = useRef<number | null>(null);
90
+ useEffect(() => {
91
+ const from = movedFrom.current;
92
+ movedFrom.current = null;
93
+ if (from === null || from === focusedDate.getTime()) return;
94
+ const root = rootRef.current;
95
+ (root?.querySelector<HTMLElement>(OWN_MONTH_STOP) ?? root?.querySelector<HTMLElement>(ANY_STOP))?.focus();
96
+ }, [rootRef, focusedDate]);
97
+ return (event: React.KeyboardEvent) => {
98
+ const onDay = (event.target as HTMLElement).getAttribute('role') === 'gridcell';
99
+ const moves = navigateFocus(event.key, focusedDate, { firstDayOfWeek, shiftKey: event.shiftKey }) !== null;
100
+ movedFrom.current = onDay && moves ? focusedDate.getTime() : null;
101
+ };
102
+ };
103
+
63
104
  export const Calendar = React.forwardRef<HTMLDivElement, CalendarProps>((componentProps, ref) => {
64
105
  const props = resolveCalendarProps(componentProps);
65
106
  const { monthsToShow, locale, renderHeader, renderFooter, className, ariaLabel } = props;
@@ -69,6 +110,8 @@ export const Calendar = React.forwardRef<HTMLDivElement, CalendarProps>((compone
69
110
  const bounds = { minDate: props.minDate, maxDate: props.maxDate };
70
111
  const picker = useCalendarPicker({ rootRef, bounds, ...calendar });
71
112
  const dayContext = buildDayContext(props, calendar);
113
+ const noteKeyTarget = useFollowDayFocus(rootRef, calendar.focusedDate, props.firstDayOfWeek);
114
+ const labels = resolveLabels(EN_US_UI_LABELS.calendar, props.labels);
72
115
  // The selectors caption always resolves to one month (see the helpers).
73
116
  const firstMonth = calendar.monthMatrices[0];
74
117
 
@@ -81,7 +124,14 @@ export const Calendar = React.forwardRef<HTMLDivElement, CalendarProps>((compone
81
124
  tabIndex={0}
82
125
  // The day keys belong to the days: with a month or year grid open there
83
126
  // is no focused day on screen to move.
84
- onKeyDown={picker.view === 'days' ? calendar.handleKeyDown : undefined}
127
+ onKeyDown={
128
+ picker.view === 'days'
129
+ ? (event) => {
130
+ noteKeyTarget(event);
131
+ calendar.handleKeyDown(event);
132
+ }
133
+ : undefined
134
+ }
85
135
  data-testid="calendar-container"
86
136
  sx={containerSx(monthsToShow)}
87
137
  >
@@ -93,7 +143,7 @@ export const Calendar = React.forwardRef<HTMLDivElement, CalendarProps>((compone
93
143
  weekdayNames={calendar.weekdayNames}
94
144
  dayContext={dayContext}
95
145
  bounds={bounds}
96
- labels={resolveLabels(EN_US_UI_LABELS.calendar, props.labels)}
146
+ labels={labels}
97
147
  picker={picker}
98
148
  onPreviousMonth={() => {
99
149
  picker.showDays();
@@ -114,6 +164,9 @@ export const Calendar = React.forwardRef<HTMLDivElement, CalendarProps>((compone
114
164
  locale={locale}
115
165
  weekdayNames={calendar.weekdayNames}
116
166
  renderHeader={renderHeader}
167
+ // Only a host that passed `labels` gets named arrows: without
168
+ // them the arrows caption stays exactly as it always was.
169
+ labels={props.labels ? labels : undefined}
117
170
  onPreviousMonth={calendar.goToPreviousMonth}
118
171
  onNextMonth={calendar.goToNextMonth}
119
172
  dayContext={dayContext}
@@ -114,8 +114,11 @@ const dayCellSx = (day: DayRenderArgs, band: DayBand, visible: boolean): SxProps
114
114
  color: colorFor(day, visible),
115
115
  opacity: !day.inCurrentMonth && visible ? 0.5 : 1,
116
116
  fontWeight: day.today || isEndpoint(day) ? 'bold' : 'normal',
117
- '&:nth-of-type(7n + 1)': { borderStartStartRadius: BAND_RADIUS, borderEndStartRadius: BAND_RADIUS },
118
- '&:nth-of-type(7n)': { borderStartEndRadius: BAND_RADIUS, borderEndEndRadius: BAND_RADIUS },
117
+ // `nth-child`, counting every cell of the week: a hidden outside day is an
118
+ // inert `span` placeholder (FUT-4144), and `nth-of-type` counted only the
119
+ // buttons, so the caps landed mid-week in a month with hidden outside days.
120
+ '&:nth-child(7n + 1)': { borderStartStartRadius: BAND_RADIUS, borderEndStartRadius: BAND_RADIUS },
121
+ '&:nth-child(7n)': { borderStartEndRadius: BAND_RADIUS, borderEndEndRadius: BAND_RADIUS },
119
122
  '&::before': {
120
123
  content: '""',
121
124
  position: 'absolute',
@@ -140,8 +143,18 @@ const dayCellSx = (day: DayRenderArgs, band: DayBand, visible: boolean): SxProps
140
143
  },
141
144
  });
142
145
 
146
+ /**
147
+ * A day's spoken name, whole: "1 de outubro de 2026". The cell's text is the
148
+ * bare number, which a screen reader would read as "1" — in a two-month range
149
+ * calendar that is two different days.
150
+ */
151
+ const dayName = (date: Date, locale: string): string =>
152
+ date.toLocaleDateString(locale, { day: 'numeric', month: 'long', year: 'numeric' });
153
+
143
154
  export interface CalendarDayProps {
144
155
  day: DayRenderArgs;
156
+ /** BCP-47 tag the day's accessible name is written in. Default: en-US. */
157
+ locale?: string;
145
158
  band: DayBand;
146
159
  focused: boolean;
147
160
  showOutsideDays: boolean;
@@ -153,6 +166,7 @@ export interface CalendarDayProps {
153
166
 
154
167
  export const CalendarDay: FC<CalendarDayProps> = ({
155
168
  day,
169
+ locale = 'en-US',
156
170
  band,
157
171
  focused,
158
172
  showOutsideDays,
@@ -164,6 +178,20 @@ export const CalendarDay: FC<CalendarDayProps> = ({
164
178
  const visible = day.inCurrentMonth || showOutsideDays;
165
179
  const state: DayState = { ...day, outside: !day.inCurrentMonth, focused };
166
180
 
181
+ // A day hidden by `showOutsideDays={false}` keeps its place in the grid and
182
+ // nothing else: no button to click in a blank, no name, no tab stop that
183
+ // cannot be seen (FUT-4144).
184
+ if (!visible) {
185
+ return (
186
+ <Box
187
+ component="span"
188
+ aria-hidden="true"
189
+ data-testid="calendar-outside-placeholder"
190
+ sx={{ width: COLUMN_SIZE, maxWidth: '100%', aspectRatio: CELL_RATIO, justifySelf: 'stretch' }}
191
+ />
192
+ );
193
+ }
194
+
167
195
  return (
168
196
  <Box
169
197
  component="button"
@@ -172,6 +200,8 @@ export const CalendarDay: FC<CalendarDayProps> = ({
172
200
  aria-selected={day.selected}
173
201
  aria-disabled={day.disabled}
174
202
  aria-current={day.today ? 'date' : undefined}
203
+ aria-label={dayName(day.date, locale)}
204
+ data-in-month={day.inCurrentMonth}
175
205
  className={dayClassNames(state, dayClassName?.(day))}
176
206
  data-testid={`calendar-date-${day.date.getDate()}`}
177
207
  onClick={() => onSelect(day.date)}
@@ -185,7 +215,7 @@ export const CalendarDay: FC<CalendarDayProps> = ({
185
215
  {day.today && (
186
216
  <Box component="span" data-testid="calendar-today" sx={{ display: 'none' }} />
187
217
  )}
188
- {visible ? day.date.getDate() : ''}
218
+ {day.date.getDate()}
189
219
  </Box>
190
220
  );
191
221
  };