@12-apps/ui 6.89.1 → 6.90.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 (288) hide show
  1. package/components-catalog.md +1 -1
  2. package/dist/_internal/components/data-display/Alert/Alert.js +3 -3
  3. package/dist/_internal/components/data-display/Avatar/Avatar.js +4 -4
  4. package/dist/_internal/components/data-display/Avatar/Avatar.view.js +2 -2
  5. package/dist/_internal/components/data-display/CardKit/card-actions-context.js +4 -4
  6. package/dist/_internal/components/data-display/CardKit/use-remove-confirm.js +5 -5
  7. package/dist/_internal/components/data-display/Carousel/Carousel.chrome.js +4 -3
  8. package/dist/_internal/components/data-display/Carousel/Carousel.js +6 -5
  9. package/dist/_internal/components/data-display/Carousel/Carousel.parts.js +3 -2
  10. package/dist/_internal/components/data-display/Chart/Chart.js +3 -3
  11. package/dist/_internal/components/data-display/Chart/SpecChart.js +6 -6
  12. package/dist/_internal/components/data-display/Chart/chart-renderers.js +2 -2
  13. package/dist/_internal/components/data-display/Chart/chart-spec.js +2 -2
  14. package/dist/_internal/components/data-display/DataGrid/DataGrid.js +2 -2
  15. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +48 -23
  16. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +53 -28
  17. package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +1 -1
  18. package/dist/_internal/components/data-display/DataViews/base-list-card-layout.js +1 -1
  19. package/dist/_internal/components/data-display/DataViews/base-list-card.js +3 -3
  20. package/dist/_internal/components/data-display/DataViews/data-views-bar-controls.js +5 -3
  21. package/dist/_internal/components/data-display/DataViews/data-views-day-input.js +1 -1
  22. package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +31 -6
  23. package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +3 -3
  24. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +47 -22
  25. package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +37 -12
  26. package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +32 -7
  27. package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +33 -8
  28. package/dist/_internal/components/data-display/DataViews/data-views-number-input.js +1 -1
  29. package/dist/_internal/components/data-display/DataViews/data-views-preset-chips.js +10 -3
  30. package/dist/_internal/components/data-display/DataViews/data-views-range-bounds.js +47 -0
  31. package/dist/_internal/components/data-display/DataViews/data-views-range-bounds.js.map +1 -0
  32. package/dist/_internal/components/data-display/DataViews/data-views-range-calendar.js +36 -0
  33. package/dist/_internal/components/data-display/DataViews/data-views-range-calendar.js.map +1 -0
  34. package/dist/_internal/components/data-display/DataViews/data-views-range-pill.js +32 -6
  35. package/dist/_internal/components/data-display/DataViews/data-views-range-summary.js +12 -0
  36. package/dist/_internal/components/data-display/DataViews/data-views-range-summary.js.map +1 -0
  37. package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +3 -3
  38. package/dist/_internal/components/data-display/DataViews/data-views-still-anchor.js +9 -0
  39. package/dist/_internal/components/data-display/DataViews/data-views-still-anchor.js.map +1 -0
  40. package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +4 -4
  41. package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +2 -2
  42. package/dist/_internal/components/data-display/DayRuler/DayRuler.js +3 -3
  43. package/dist/_internal/components/data-display/DayRuler/DayRuler.parts.js +2 -2
  44. package/dist/_internal/components/data-display/DayRuler/DayRuler.styles.js +3 -1
  45. package/dist/_internal/components/data-display/FleetMap/FleetBody.js +9 -8
  46. package/dist/_internal/components/data-display/FleetMap/FleetCanvas.js +8 -7
  47. package/dist/_internal/components/data-display/FleetMap/FleetMap.fixtures.js +2 -1
  48. package/dist/_internal/components/data-display/FleetMap/FleetMap.fixtures.js.map +1 -1
  49. package/dist/_internal/components/data-display/FleetMap/FleetMap.js +9 -9
  50. package/dist/_internal/components/data-display/MapPreview/MapControlBar.js +4 -3
  51. package/dist/_internal/components/data-display/MapPreview/MapLayers.js +5 -4
  52. package/dist/_internal/components/data-display/MapPreview/MapMarkers.js +4 -3
  53. package/dist/_internal/components/data-display/MapPreview/MapPreview.helpers.js +3 -2
  54. package/dist/_internal/components/data-display/MapPreview/MapPreview.js +7 -6
  55. package/dist/_internal/components/data-display/index.js +38 -38
  56. package/dist/_internal/components/feedback/NotificationStatusNotice/NotificationStatusNotice.js +4 -4
  57. package/dist/_internal/components/feedback/SequenceResolver/SequenceResolver.js +6 -6
  58. package/dist/_internal/components/feedback/SequenceResolver/SequenceResolver.overview.js +5 -5
  59. package/dist/_internal/components/feedback/SequenceResolver/SequenceResolver.parts.js +4 -4
  60. package/dist/_internal/components/feedback/index.js +7 -7
  61. package/dist/_internal/components/form/Calendar/Calendar.js +5 -5
  62. package/dist/_internal/components/form/Calendar/CalendarDay.js +1 -1
  63. package/dist/_internal/components/form/Calendar/CalendarDayCell.js +2 -2
  64. package/dist/_internal/components/form/Calendar/CalendarMonth.js +3 -3
  65. package/dist/_internal/components/form/Calendar/CalendarSelectorsMonth.js +4 -4
  66. package/dist/_internal/components/form/DateRangePicker/DateRangePicker.hooks.js +3 -3
  67. package/dist/_internal/components/form/DateRangePicker/DateRangePicker.js +10 -10
  68. package/dist/_internal/components/form/DateRangePicker/DateRangePicker.range.js +2 -2
  69. package/dist/_internal/components/form/DateRangePicker/DateRangePickerFields.js +3 -3
  70. package/dist/_internal/components/form/index.js +24 -24
  71. package/dist/_internal/components/index.js +66 -66
  72. package/dist/_internal/en-US.data-display.js +2 -1
  73. package/dist/_internal/pt-BR.data-display.js +2 -1
  74. package/dist/_internal/user-avatar/user-avatar.js +5 -5
  75. package/dist/charts.js +11 -11
  76. package/dist/{chunk-FJ3UZ4RC.js → chunk-2FKWKLSC.js} +5 -3
  77. package/dist/chunk-2FKWKLSC.js.map +1 -0
  78. package/dist/{chunk-BO6MT2S2.js → chunk-3HZKUN5J.js} +7 -6
  79. package/dist/chunk-3HZKUN5J.js.map +1 -0
  80. package/dist/{chunk-TYXFFNPM.js → chunk-3OTGREQG.js} +10 -10
  81. package/dist/{chunk-BEHT4IHH.js → chunk-3X2MA47R.js} +2 -2
  82. package/dist/{chunk-XHIBFBNP.js → chunk-3ZRK3BRN.js} +4 -2
  83. package/dist/chunk-3ZRK3BRN.js.map +1 -0
  84. package/dist/{chunk-X5OGIT2F.js → chunk-4L54KUZV.js} +22 -4
  85. package/dist/chunk-4L54KUZV.js.map +1 -0
  86. package/dist/{chunk-TRYR424I.js → chunk-6LOWZCH7.js} +15 -1
  87. package/dist/chunk-6LOWZCH7.js.map +1 -0
  88. package/dist/{chunk-6WHIJPEF.js → chunk-6PU5P7QT.js} +2 -2
  89. package/dist/chunk-7CUZTWKW.js +52 -0
  90. package/dist/chunk-7CUZTWKW.js.map +1 -0
  91. package/dist/{chunk-JIEVKHOH.js → chunk-7YJYIMWP.js} +7 -7
  92. package/dist/{chunk-YNZUYZ2O.js → chunk-A3DDEKLV.js} +2 -2
  93. package/dist/{chunk-KHREN7Y7.js → chunk-ACM3HHZY.js} +2 -2
  94. package/dist/{chunk-FEKWKWGK.js → chunk-ARGVUTTL.js} +15 -1
  95. package/dist/chunk-ARGVUTTL.js.map +1 -0
  96. package/dist/{chunk-DYHOBKPU.js → chunk-BLZDSCIZ.js} +6 -6
  97. package/dist/{chunk-E2UOEI7N.js → chunk-BV2LOTMC.js} +2 -2
  98. package/dist/{chunk-O63ZROSY.js → chunk-BZBLPXV7.js} +4 -4
  99. package/dist/{chunk-OKRITX4S.js → chunk-CJ6XXM4X.js} +4 -4
  100. package/dist/{chunk-LV6AD6XC.js → chunk-DBI6AMNY.js} +4 -4
  101. package/dist/{chunk-QRRWLLXW.js → chunk-DSBC6O46.js} +2 -2
  102. package/dist/{chunk-3YFDGFEK.js → chunk-DVX4HDNP.js} +2 -2
  103. package/dist/{chunk-CJUK32UH.js → chunk-EEO7M5GU.js} +2 -2
  104. package/dist/{chunk-7XSCEHGA.js → chunk-EOQ6EKTS.js} +7 -7
  105. package/dist/{chunk-5RSK5M6M.js → chunk-FI2CQOGC.js} +63 -126
  106. package/dist/chunk-FI2CQOGC.js.map +1 -0
  107. package/dist/{chunk-Q2ERGAQO.js → chunk-FYAW5GBF.js} +33 -6
  108. package/dist/chunk-FYAW5GBF.js.map +1 -0
  109. package/dist/{chunk-EOJSA2EK.js → chunk-G2PVUPE7.js} +26 -18
  110. package/dist/chunk-G2PVUPE7.js.map +1 -0
  111. package/dist/{chunk-AMLHEKSV.js → chunk-HI7JPDD6.js} +5 -5
  112. package/dist/{chunk-2H6SCVLD.js → chunk-HMEGQKNQ.js} +3 -3
  113. package/dist/chunk-J2AVWIMM.js +60 -0
  114. package/dist/chunk-J2AVWIMM.js.map +1 -0
  115. package/dist/{chunk-7QKIL5YF.js → chunk-J2GDA64N.js} +4 -4
  116. package/dist/{chunk-BAQ3ITZV.js → chunk-JFD742C3.js} +2 -2
  117. package/dist/{chunk-OBA75Y5O.js → chunk-JHWEL4NX.js} +61 -33
  118. package/dist/chunk-JHWEL4NX.js.map +1 -0
  119. package/dist/{chunk-HQCZT6TO.js → chunk-JVOEVTCZ.js} +5 -5
  120. package/dist/{chunk-WAO7UQRS.js → chunk-KANCE4MS.js} +3 -3
  121. package/dist/{chunk-XLU5WFSY.js → chunk-KRBPWTXW.js} +2 -2
  122. package/dist/{chunk-S6D7NOV7.js → chunk-L6JAALMX.js} +3 -3
  123. package/dist/{chunk-72HOUWAW.js → chunk-L6YTVXGN.js} +5 -3
  124. package/dist/{chunk-72HOUWAW.js.map → chunk-L6YTVXGN.js.map} +1 -1
  125. package/dist/chunk-LZNUBQ5I.js +181 -0
  126. package/dist/chunk-LZNUBQ5I.js.map +1 -0
  127. package/dist/{chunk-BECKKDYG.js → chunk-M2M4IDFU.js} +2 -2
  128. package/dist/{chunk-CSGBHYW6.js → chunk-M5Y42AZ4.js} +2 -2
  129. package/dist/chunk-MICX23P4.js +122 -0
  130. package/dist/chunk-MICX23P4.js.map +1 -0
  131. package/dist/{chunk-5CP5Z3YU.js → chunk-MPWA55CF.js} +4 -4
  132. package/dist/{chunk-5KK3I42O.js → chunk-NK6O4NE4.js} +13 -10
  133. package/dist/chunk-NK6O4NE4.js.map +1 -0
  134. package/dist/{chunk-RCTHCXS6.js → chunk-PJNIJIE6.js} +2 -2
  135. package/dist/{chunk-6ATXOJVQ.js → chunk-QADTI63U.js} +4 -4
  136. package/dist/{chunk-MW7P2C2C.js → chunk-QAEO52Z4.js} +2 -2
  137. package/dist/{chunk-5S5K73I6.js → chunk-QSOCOXVL.js} +3 -3
  138. package/dist/{chunk-NQCTANF3.js → chunk-QVDEGBME.js} +7 -7
  139. package/dist/{chunk-BQBEN44R.js → chunk-RDCIST7P.js} +2 -2
  140. package/dist/{chunk-HUXAIQC5.js → chunk-RZ3P4X2I.js} +2 -2
  141. package/dist/{chunk-WJMSND5Q.js → chunk-SCXVTNLE.js} +2 -2
  142. package/dist/{chunk-K6FCSB6T.js → chunk-SK2CTB3O.js} +6 -6
  143. package/dist/{chunk-QLJU7UUI.js → chunk-T7OIVPCO.js} +38 -3
  144. package/dist/chunk-T7OIVPCO.js.map +1 -0
  145. package/dist/{chunk-U2ILXZDG.js → chunk-TB5CRHTF.js} +2 -2
  146. package/dist/{chunk-SB2SEGR6.js → chunk-TIM4PXWN.js} +3 -3
  147. package/dist/{chunk-YDIC6LSP.js → chunk-VCQFDQM3.js} +27 -7
  148. package/dist/chunk-VCQFDQM3.js.map +1 -0
  149. package/dist/chunk-VIMMEADQ.js +164 -0
  150. package/dist/chunk-VIMMEADQ.js.map +1 -0
  151. package/dist/{chunk-6D5AMANO.js → chunk-WH3LUOCQ.js} +2 -2
  152. package/dist/{chunk-OWRQOYUE.js → chunk-WWR6APJR.js} +2 -2
  153. package/dist/{chunk-5BVAUUWL.js → chunk-X37NTEVS.js} +2 -2
  154. package/dist/{chunk-WW3F7DCX.js → chunk-Z2WZDVGG.js} +2 -2
  155. package/dist/{chunk-EXVCVXFX.js → chunk-ZH6NYB6Y.js} +3 -3
  156. package/dist/data-display/Alert.js +3 -3
  157. package/dist/data-display/Avatar.js +4 -4
  158. package/dist/data-display/CardKit.js +11 -11
  159. package/dist/data-display/Carousel.js +6 -5
  160. package/dist/data-display/Chart.js +11 -11
  161. package/dist/data-display/DataGrid.js +2 -2
  162. package/dist/data-display/DataViews.js +60 -35
  163. package/dist/data-display/DayRuler.js +3 -3
  164. package/dist/data-display/FleetMap.js +9 -9
  165. package/dist/data-display/MapPreview.js +7 -6
  166. package/dist/en-US.js +1 -1
  167. package/dist/feedback/NotificationStatusNotice.js +4 -4
  168. package/dist/feedback/SequenceResolver.js +6 -6
  169. package/dist/form/Calendar.js +5 -5
  170. package/dist/form/DateRangePicker.js +10 -10
  171. package/dist/locales.js +5 -5
  172. package/dist/pt-BR.js +1 -1
  173. package/dist/types/components/data-display/DataViews/data-views-bar-controls.d.ts +15 -1
  174. package/dist/types/components/data-display/DataViews/data-views-bar-controls.d.ts.map +1 -1
  175. package/dist/types/components/data-display/DataViews/data-views-copy.d.ts +35 -0
  176. package/dist/types/components/data-display/DataViews/data-views-copy.d.ts.map +1 -1
  177. package/dist/types/components/data-display/DataViews/data-views-day-input.d.ts +7 -1
  178. package/dist/types/components/data-display/DataViews/data-views-day-input.d.ts.map +1 -1
  179. package/dist/types/components/data-display/DataViews/data-views-more-fields.d.ts.map +1 -1
  180. package/dist/types/components/data-display/DataViews/data-views-more-filters.d.ts +5 -3
  181. package/dist/types/components/data-display/DataViews/data-views-more-filters.d.ts.map +1 -1
  182. package/dist/types/components/data-display/DataViews/data-views-number-input.d.ts +10 -2
  183. package/dist/types/components/data-display/DataViews/data-views-number-input.d.ts.map +1 -1
  184. package/dist/types/components/data-display/DataViews/data-views-preset-chips.d.ts +10 -0
  185. package/dist/types/components/data-display/DataViews/data-views-preset-chips.d.ts.map +1 -1
  186. package/dist/types/components/data-display/DataViews/data-views-range-bounds.d.ts +35 -0
  187. package/dist/types/components/data-display/DataViews/data-views-range-bounds.d.ts.map +1 -0
  188. package/dist/types/components/data-display/DataViews/data-views-range-calendar.d.ts +35 -0
  189. package/dist/types/components/data-display/DataViews/data-views-range-calendar.d.ts.map +1 -0
  190. package/dist/types/components/data-display/DataViews/data-views-range-pill.d.ts +2 -11
  191. package/dist/types/components/data-display/DataViews/data-views-range-pill.d.ts.map +1 -1
  192. package/dist/types/components/data-display/DataViews/data-views-range-summary.d.ts +21 -0
  193. package/dist/types/components/data-display/DataViews/data-views-range-summary.d.ts.map +1 -0
  194. package/dist/types/components/data-display/DataViews/data-views-still-anchor.d.ts +45 -0
  195. package/dist/types/components/data-display/DataViews/data-views-still-anchor.d.ts.map +1 -0
  196. package/dist/types/components/data-display/DayRuler/DayRuler.styles.d.ts +6 -1
  197. package/dist/types/components/data-display/DayRuler/DayRuler.styles.d.ts.map +1 -1
  198. package/dist/types/components/data-display/LazyImage/LazyImage.hooks.d.ts +1 -1
  199. package/dist/types/components/form/Calendar/Calendar.d.ts.map +1 -1
  200. package/dist/types/components/form/Calendar/CalendarDay.d.ts +2 -0
  201. package/dist/types/components/form/Calendar/CalendarDay.d.ts.map +1 -1
  202. package/dist/types/components/form/Calendar/CalendarDayCell.d.ts +2 -0
  203. package/dist/types/components/form/Calendar/CalendarDayCell.d.ts.map +1 -1
  204. package/dist/types/components/form/Calendar/CalendarMonth.d.ts +5 -0
  205. package/dist/types/components/form/Calendar/CalendarMonth.d.ts.map +1 -1
  206. package/dist/types/en-US.data-display.d.ts.map +1 -1
  207. package/dist/types/pt-BR.data-display.d.ts.map +1 -1
  208. package/dist/user-avatar.js +5 -5
  209. package/package.json +1 -1
  210. package/src/components/data-display/DataViews/RESPONSIVE-BEHAVIOUR.md +59 -0
  211. package/src/components/data-display/DataViews/data-views-bar-controls.tsx +56 -1
  212. package/src/components/data-display/DataViews/data-views-copy.ts +36 -0
  213. package/src/components/data-display/DataViews/data-views-day-input.tsx +9 -1
  214. package/src/components/data-display/DataViews/data-views-inline-bar.tsx +5 -3
  215. package/src/components/data-display/DataViews/data-views-more-fields.tsx +1 -0
  216. package/src/components/data-display/DataViews/data-views-more-filters.tsx +82 -29
  217. package/src/components/data-display/DataViews/data-views-number-input.tsx +19 -9
  218. package/src/components/data-display/DataViews/data-views-preset-chips.tsx +165 -16
  219. package/src/components/data-display/DataViews/data-views-range-bounds.tsx +223 -0
  220. package/src/components/data-display/DataViews/data-views-range-calendar.tsx +185 -0
  221. package/src/components/data-display/DataViews/data-views-range-pill.tsx +71 -154
  222. package/src/components/data-display/DataViews/data-views-range-summary.tsx +66 -0
  223. package/src/components/data-display/DataViews/data-views-still-anchor.ts +93 -0
  224. package/src/components/data-display/DayRuler/DayRuler.styles.ts +29 -16
  225. package/src/components/form/Calendar/Calendar.md +17 -2
  226. package/src/components/form/Calendar/Calendar.tsx +56 -3
  227. package/src/components/form/Calendar/CalendarDay.tsx +33 -3
  228. package/src/components/form/Calendar/CalendarDayCell.tsx +4 -0
  229. package/src/components/form/Calendar/CalendarMonth.tsx +27 -5
  230. package/src/en-US.data-display.ts +12 -0
  231. package/src/pt-BR.data-display.ts +12 -0
  232. package/dist/chunk-5KK3I42O.js.map +0 -1
  233. package/dist/chunk-5RSK5M6M.js.map +0 -1
  234. package/dist/chunk-7D7CJRL7.js +0 -78
  235. package/dist/chunk-7D7CJRL7.js.map +0 -1
  236. package/dist/chunk-BO6MT2S2.js.map +0 -1
  237. package/dist/chunk-EOJSA2EK.js.map +0 -1
  238. package/dist/chunk-FEKWKWGK.js.map +0 -1
  239. package/dist/chunk-FJ3UZ4RC.js.map +0 -1
  240. package/dist/chunk-OBA75Y5O.js.map +0 -1
  241. package/dist/chunk-Q2ERGAQO.js.map +0 -1
  242. package/dist/chunk-QLJU7UUI.js.map +0 -1
  243. package/dist/chunk-TRYR424I.js.map +0 -1
  244. package/dist/chunk-X5OGIT2F.js.map +0 -1
  245. package/dist/chunk-XHIBFBNP.js.map +0 -1
  246. package/dist/chunk-YDIC6LSP.js.map +0 -1
  247. /package/dist/{chunk-TYXFFNPM.js.map → chunk-3OTGREQG.js.map} +0 -0
  248. /package/dist/{chunk-BEHT4IHH.js.map → chunk-3X2MA47R.js.map} +0 -0
  249. /package/dist/{chunk-6WHIJPEF.js.map → chunk-6PU5P7QT.js.map} +0 -0
  250. /package/dist/{chunk-JIEVKHOH.js.map → chunk-7YJYIMWP.js.map} +0 -0
  251. /package/dist/{chunk-YNZUYZ2O.js.map → chunk-A3DDEKLV.js.map} +0 -0
  252. /package/dist/{chunk-KHREN7Y7.js.map → chunk-ACM3HHZY.js.map} +0 -0
  253. /package/dist/{chunk-DYHOBKPU.js.map → chunk-BLZDSCIZ.js.map} +0 -0
  254. /package/dist/{chunk-E2UOEI7N.js.map → chunk-BV2LOTMC.js.map} +0 -0
  255. /package/dist/{chunk-O63ZROSY.js.map → chunk-BZBLPXV7.js.map} +0 -0
  256. /package/dist/{chunk-OKRITX4S.js.map → chunk-CJ6XXM4X.js.map} +0 -0
  257. /package/dist/{chunk-LV6AD6XC.js.map → chunk-DBI6AMNY.js.map} +0 -0
  258. /package/dist/{chunk-QRRWLLXW.js.map → chunk-DSBC6O46.js.map} +0 -0
  259. /package/dist/{chunk-3YFDGFEK.js.map → chunk-DVX4HDNP.js.map} +0 -0
  260. /package/dist/{chunk-CJUK32UH.js.map → chunk-EEO7M5GU.js.map} +0 -0
  261. /package/dist/{chunk-7XSCEHGA.js.map → chunk-EOQ6EKTS.js.map} +0 -0
  262. /package/dist/{chunk-AMLHEKSV.js.map → chunk-HI7JPDD6.js.map} +0 -0
  263. /package/dist/{chunk-2H6SCVLD.js.map → chunk-HMEGQKNQ.js.map} +0 -0
  264. /package/dist/{chunk-7QKIL5YF.js.map → chunk-J2GDA64N.js.map} +0 -0
  265. /package/dist/{chunk-BAQ3ITZV.js.map → chunk-JFD742C3.js.map} +0 -0
  266. /package/dist/{chunk-HQCZT6TO.js.map → chunk-JVOEVTCZ.js.map} +0 -0
  267. /package/dist/{chunk-WAO7UQRS.js.map → chunk-KANCE4MS.js.map} +0 -0
  268. /package/dist/{chunk-XLU5WFSY.js.map → chunk-KRBPWTXW.js.map} +0 -0
  269. /package/dist/{chunk-S6D7NOV7.js.map → chunk-L6JAALMX.js.map} +0 -0
  270. /package/dist/{chunk-BECKKDYG.js.map → chunk-M2M4IDFU.js.map} +0 -0
  271. /package/dist/{chunk-CSGBHYW6.js.map → chunk-M5Y42AZ4.js.map} +0 -0
  272. /package/dist/{chunk-5CP5Z3YU.js.map → chunk-MPWA55CF.js.map} +0 -0
  273. /package/dist/{chunk-RCTHCXS6.js.map → chunk-PJNIJIE6.js.map} +0 -0
  274. /package/dist/{chunk-6ATXOJVQ.js.map → chunk-QADTI63U.js.map} +0 -0
  275. /package/dist/{chunk-MW7P2C2C.js.map → chunk-QAEO52Z4.js.map} +0 -0
  276. /package/dist/{chunk-5S5K73I6.js.map → chunk-QSOCOXVL.js.map} +0 -0
  277. /package/dist/{chunk-NQCTANF3.js.map → chunk-QVDEGBME.js.map} +0 -0
  278. /package/dist/{chunk-BQBEN44R.js.map → chunk-RDCIST7P.js.map} +0 -0
  279. /package/dist/{chunk-HUXAIQC5.js.map → chunk-RZ3P4X2I.js.map} +0 -0
  280. /package/dist/{chunk-WJMSND5Q.js.map → chunk-SCXVTNLE.js.map} +0 -0
  281. /package/dist/{chunk-K6FCSB6T.js.map → chunk-SK2CTB3O.js.map} +0 -0
  282. /package/dist/{chunk-U2ILXZDG.js.map → chunk-TB5CRHTF.js.map} +0 -0
  283. /package/dist/{chunk-SB2SEGR6.js.map → chunk-TIM4PXWN.js.map} +0 -0
  284. /package/dist/{chunk-6D5AMANO.js.map → chunk-WH3LUOCQ.js.map} +0 -0
  285. /package/dist/{chunk-OWRQOYUE.js.map → chunk-WWR6APJR.js.map} +0 -0
  286. /package/dist/{chunk-5BVAUUWL.js.map → chunk-X37NTEVS.js.map} +0 -0
  287. /package/dist/{chunk-WW3F7DCX.js.map → chunk-Z2WZDVGG.js.map} +0 -0
  288. /package/dist/{chunk-EXVCVXFX.js.map → chunk-ZH6NYB6Y.js.map} +0 -0
@@ -17,14 +17,17 @@ import Box from '@mui/material/Box/index.js';
17
17
  import Button from '@mui/material/Button/index.js';
18
18
  import Popover from '@mui/material/Popover/index.js';
19
19
  import Typography from '@mui/material/Typography/index.js';
20
- import React, { useState } from 'react';
20
+ import useMediaQuery from '@mui/material/useMediaQuery/index.js';
21
+ import { useTheme, type Theme } from '@mui/material/styles/index.js';
22
+ import React, { useContext } from 'react';
21
23
 
22
24
  import { useDataViewsCopy } from "./data-views-copy-context";
23
25
  import { TableFilter } from '../../layout/TableFilter';
24
- import { DayBoundInput } from './data-views-day-input';
25
- import { NumberBoundInput } from './data-views-number-input';
26
+ import { TableFilterContext } from '../../layout/TableFilter/TableFilterContext';
26
27
  import { RangePresets } from './data-views-preset-chips';
27
- import { useOutsideResetKey } from './data-views-range-reset';
28
+ import { RangeBounds } from './data-views-range-bounds';
29
+ import { RangeSummary } from './data-views-range-summary';
30
+ import { useStillAnchor } from './data-views-still-anchor';
28
31
  import { presetsFor } from './data-views-range-presets';
29
32
  import {
30
33
  isRangeInverted,
@@ -36,126 +39,10 @@ import type { RangeFieldConfig, RangeValue } from './data-views-types';
36
39
  import { fieldRadiusPx } from '../../../tokens/field-radius';
37
40
  import { fieldHeight } from '../../../tokens/field-height';
38
41
  import { fieldEdge } from '../../../tokens/field-edge';
39
- import { sxRem } from '../../../tokens/relative';
40
-
41
-
42
-
43
- /**
44
- * One end of the range. A day keeps its `AAAA-MM-DD` string verbatim (the form
45
- * both the field and the backend speak) and is typed through the masked
46
- * `dd/mm/aaaa` field rather than a native date input — see
47
- * {@link DayBoundInput} for why. A number parses, and an unparseable/blank
48
- * entry CLEARS the bound rather than writing `NaN`.
49
- */
50
- function BoundField<T extends Record<string, unknown>>({
51
- field,
52
- label,
53
- value,
54
- onChange,
55
- testId,
56
- }: {
57
- field: RangeFieldConfig<T>;
58
- label: string;
59
- value: number | string | undefined;
60
- onChange: (bound: number | string | undefined) => void;
61
- testId: string;
62
- }): React.JSX.Element {
63
- const copy = useDataViewsCopy();
64
- if (field.kind === 'day') {
65
- return (
66
- <DayBoundInput
67
- mask={copy.filters.dayMask}
68
- invalidMessage={copy.filters.dayInvalid}
69
- label={label}
70
- value={value == null ? undefined : String(value)}
71
- onChange={onChange}
72
- testId={testId}
73
- />
74
- );
75
- }
76
- return (
77
- <NumberBoundInput
78
- label={label}
79
- value={value}
80
- unit={field.unit}
81
- onChange={onChange}
82
- testId={testId}
83
- />
84
- );
85
- }
42
+ import { rem, remPx, sxRem } from '../../../tokens/relative';
86
43
 
87
-
88
- /**
89
- * The `De`/`Até` pair for a range — shared by the pill's popover and the
90
- * slide-in panel's day fields, so the two surfaces cannot drift on what a bound
91
- * accepts or how it clears.
92
- */
93
- export function RangeBounds<T extends Record<string, unknown>>({
94
- field,
95
- value,
96
- onChange,
97
- testId,
98
- }: {
99
- field: RangeFieldConfig<T>;
100
- value: RangeValue;
101
- onChange: (range: RangeValue) => void;
102
- testId: string;
103
- }): React.JSX.Element {
104
- const copy = useDataViewsCopy();
105
- const inverted = isRangeInverted(value);
106
- const { key, emitted } = useOutsideResetKey(value);
107
- return (
108
- <Box data-testid={`${testId}-panel`}>
109
- {/* Above the inputs, not below: the presets are the answer for most
110
- merchants, and the two date pickers are the escape hatch. */}
111
- <Box sx={{ '&:not(:empty)': { mb: 1.5 } }}>
112
- <RangePresets presets={presetsFor(field, copy)} value={value} onChange={onChange} testId={testId} />
113
- </Box>
114
- {/* Top-aligned: a day that does not exist grows ITS field by a message
115
- line, and centring would push the other box half a line down. The two
116
- boxes are one height, so with no message this is the same row. */}
117
- <Box sx={{ display: 'flex', alignItems: 'flex-start', gap: 1.5 }}>
118
- <BoundField
119
- key={`min-${key}`}
120
- field={field}
121
- label={copy.filters.rangeStart}
122
- value={value.min}
123
- onChange={(min) => onChange(emitted({ ...value, min }))}
124
- testId={`${testId}-min`}
125
- />
126
- <BoundField
127
- key={`max-${key}`}
128
- field={field}
129
- label={copy.filters.rangeEnd}
130
- value={value.max}
131
- onChange={(max) => onChange(emitted({ ...value, max }))}
132
- testId={`${testId}-max`}
133
- />
134
- </Box>
135
- {inverted && (
136
- <Typography
137
- component="p"
138
- data-testid={`${testId}-inverted`}
139
- sx={{ mt: 0.75, fontSize: sxRem(12), color: 'error.main' }}
140
- >
141
- {copy.filters.rangeInvalid}
142
- </Typography>
143
- )}
144
- {/* BOTH days are in the result. Saying so is FUT-668's other half: the
145
- bounds compare as ISO strings precisely so `até` keeps its whole day,
146
- and nothing on screen would otherwise tell the merchant that. */}
147
- {field.kind === 'day' && !inverted && (
148
- <Typography
149
- component="p"
150
- data-testid={`${testId}-inclusive`}
151
- sx={{ mt: 0.75, fontSize: sxRem(12), color: 'text.disabled' }}
152
- >
153
- {copy.filters.rangeInclusiveNote}
154
- </Typography>
155
- )}
156
- </Box>
157
- );
158
- }
44
+ // Re-exported: the pair moved to its own file, and its importers keep their path.
45
+ export { RangeBounds };
159
46
 
160
47
  /**
161
48
  * The pill + its popover. Bounds commit on change (the list is server-driven, so
@@ -265,6 +152,38 @@ function RangeTrigger<T extends Record<string, unknown>>({
265
152
  );
266
153
  }
267
154
 
155
+ /**
156
+ * How many months the pill's calendar shows: two from the theme's `md` up,
157
+ * where the popover has the ~670px they take; one below it.
158
+ *
159
+ * A media query, not an `sx` breakpoint, because it decides what to RENDER —
160
+ * CSS cannot un-render a second month. `up('md')` so that where nothing can be
161
+ * measured (a test, the server) the answer is the one month that always fits.
162
+ */
163
+ function useCalendarMonths(): 1 | 2 {
164
+ const theme = useTheme();
165
+ return useMediaQuery(theme.breakpoints.up('md')) ? 2 : 1;
166
+ }
167
+
168
+ /**
169
+ * The day popover's width. Below `sm` it takes the screen's (less the
170
+ * popover's own 16px margins, which its `maxWidth` already keeps), so the boxes
171
+ * and the month share it instead of leaving a strip of grid beside a narrow
172
+ * card. From `sm` to `md` it holds one month, and sized to its content the
173
+ * preset row alone stretched it to ~515px with the month hugging the left and
174
+ * a band of nothing beside it; 400 keeps the month and the boxes one width.
175
+ * From `md` its content — two months — sets it.
176
+ */
177
+ const DAY_PAPER_SX = (theme: Theme) => ({
178
+ width: { xs: '100%', sm: rem(theme, 400), md: 'auto' },
179
+ // Below `sm` 8px from each edge and 8px of padding, so the month gets the
180
+ // 280px seven 40px day columns need: at 320 it had 256 and every day was a
181
+ // 33px target (FUT-4144 UI review).
182
+ maxWidth: { xs: `calc(100% - ${rem(theme, 16)})`, sm: `calc(100% - ${rem(theme, 32)})` },
183
+ p: { xs: 1, sm: 2 },
184
+ });
185
+
186
+
268
187
  export function RangePill<T extends Record<string, unknown>>({
269
188
  field,
270
189
  value,
@@ -279,10 +198,11 @@ export function RangePill<T extends Record<string, unknown>>({
279
198
  onOpenChange?: (open: boolean) => void;
280
199
  testIdPrefix: string;
281
200
  }): React.JSX.Element {
282
- const copy = useDataViewsCopy();
283
- const [anchor, setAnchor] = useState<HTMLElement | null>(null);
284
- const active = isRangeSet(value);
201
+ const still = useStillAnchor();
285
202
  const testId = `${testIdPrefix}-range-${field.id}`;
203
+ const calendarMonths = useCalendarMonths();
204
+ const theme = useTheme();
205
+ const phone = useMediaQuery(theme.breakpoints.down('sm'));
286
206
  return (
287
207
  <>
288
208
  <RangeTrigger
@@ -290,42 +210,30 @@ export function RangePill<T extends Record<string, unknown>>({
290
210
  value={value}
291
211
  onChange={onChange}
292
212
  onOpen={(element) => {
293
- setAnchor(element);
213
+ still.open(element);
294
214
  onOpenChange?.(true);
295
215
  }}
296
- open={Boolean(anchor)}
216
+ open={Boolean(still.anchor)}
297
217
  testId={testId}
298
218
  />
299
219
  <Popover
300
- open={Boolean(anchor)}
301
- anchorEl={anchor}
220
+ {...still.popoverProps}
302
221
  onClose={() => {
303
- setAnchor(null);
222
+ still.close();
304
223
  onOpenChange?.(false);
305
224
  }}
306
- anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
307
- slotProps={{ paper: { sx: { p: 2, mt: 0.5 } } }}
225
+ // Below `sm` a day popover keeps 8px from the screen's edges instead of 16.
226
+ marginThreshold={field.kind === 'day' && phone ? remPx(theme, 8) : undefined}
227
+ slotProps={{ paper: { ref: still.paperRef, sx: [{ p: 2, mt: 0.5 }, field.kind === 'day' && DAY_PAPER_SX] } }}
308
228
  >
309
- <RangeBounds field={field} value={value} onChange={onChange} testId={testId} />
310
- {/* An inverted window is not an error the merchant must fix before the
311
- list responds — it simply matches nothing, and saying so beats an
312
- empty grid with no explanation (FUT-668). */}
313
- {active && (
314
- <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 2, mt: 1.5 }}>
315
- <Typography component="span" sx={{ fontSize: sxRem(12), color: 'text.secondary' }}>
316
- {rangeChipLabel(field, value)}
317
- </Typography>
318
- <Button
319
- variant="text"
320
- size="small"
321
- onClick={() => onChange({})}
322
- data-testid={`${testId}-clear`}
323
- sx={{ textTransform: 'none' }}
324
- >
325
- {copy.filters.clear}
326
- </Button>
327
- </Box>
328
- )}
229
+ <RangeBounds
230
+ field={field}
231
+ value={value}
232
+ onChange={onChange}
233
+ testId={testId}
234
+ calendarMonths={calendarMonths}
235
+ />
236
+ <RangeSummary field={field} value={value} onClear={() => onChange({})} testId={testId} />
329
237
  </Popover>
330
238
  </>
331
239
  );
@@ -349,13 +257,22 @@ export function PanelRangeField<T extends Record<string, unknown>>({
349
257
  testId: string;
350
258
  }): React.JSX.Element {
351
259
  const copy = useDataViewsCopy();
260
+ // The slide-in panel stays mounted while closed; its calendar does not.
261
+ // Outside a `TableFilter` (the "Mais" sheet, a test) the pair is on screen.
262
+ const panel = useContext(TableFilterContext);
352
263
  if (field.kind === "day") {
353
264
  return (
354
265
  <Box sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
355
266
  <Typography component="span" sx={{ fontSize: sxRem(12), fontWeight: 500, color: "text.secondary" }}>
356
267
  {field.label}
357
268
  </Typography>
358
- <RangeBounds field={field} value={value} onChange={onChange} testId={testId} />
269
+ <RangeBounds
270
+ field={field}
271
+ value={value}
272
+ onChange={onChange}
273
+ testId={testId}
274
+ showCalendar={panel ? panel.open : true}
275
+ />
359
276
  </Box>
360
277
  );
361
278
  }
@@ -0,0 +1,66 @@
1
+ 'use client';
2
+
3
+ import Box from '@mui/material/Box/index.js';
4
+ import Button from '@mui/material/Button/index.js';
5
+ import Typography from '@mui/material/Typography/index.js';
6
+ import React from 'react';
7
+
8
+ import { useDataViewsCopy } from './data-views-copy-context';
9
+ import { isRangeSet, rangeChipLabel } from './data-views-range-values';
10
+ import type { RangeFieldConfig, RangeValue } from './data-views-types';
11
+ import { sxRem } from '../../../tokens/relative';
12
+
13
+ /**
14
+ * The applied window in words, and "Limpar".
15
+ *
16
+ * An inverted window is not an error the merchant must fix before the list
17
+ * responds — it simply matches nothing, and saying so beats an empty grid with
18
+ * no explanation (FUT-668).
19
+ *
20
+ * A DAY filter keeps the row's height while nothing is applied: its first tap
21
+ * on the calendar applies a bound, and a row appearing then grew the popover
22
+ * 26px and moved it 32px up at 320×568, the day under the finger with it
23
+ * (FUT-4144 UI review round 2). The held row is invisible and inert.
24
+ */
25
+ export function RangeSummary<T extends Record<string, unknown>>({
26
+ field,
27
+ value,
28
+ onClear,
29
+ testId,
30
+ }: {
31
+ field: RangeFieldConfig<T>;
32
+ value: RangeValue;
33
+ onClear: () => void;
34
+ testId: string;
35
+ }): React.JSX.Element | null {
36
+ const copy = useDataViewsCopy();
37
+ const active = isRangeSet(value);
38
+ if (!active && field.kind !== 'day') return null;
39
+ return (
40
+ <Box
41
+ aria-hidden={active ? undefined : true}
42
+ sx={{
43
+ display: 'flex',
44
+ alignItems: 'center',
45
+ justifyContent: 'space-between',
46
+ gap: 2,
47
+ mt: { xs: 0.5, sm: 1.5 },
48
+ visibility: active ? undefined : 'hidden',
49
+ }}
50
+ >
51
+ <Typography component="span" sx={{ fontSize: sxRem(12), color: 'text.secondary' }}>
52
+ {active ? rangeChipLabel(field, value) : field.label}
53
+ </Typography>
54
+ <Button
55
+ variant="text"
56
+ size="small"
57
+ onClick={active ? onClear : undefined}
58
+ tabIndex={active ? undefined : -1}
59
+ data-testid={active ? `${testId}-clear` : undefined}
60
+ sx={{ textTransform: 'none' }}
61
+ >
62
+ {copy.filters.clear}
63
+ </Button>
64
+ </Box>
65
+ );
66
+ }
@@ -0,0 +1,93 @@
1
+ 'use client';
2
+
3
+ import type { PopoverActions } from '@mui/material/Popover/index.js';
4
+ import { useCallback, useEffect, useRef, useState, type RefObject } from 'react';
5
+
6
+ /**
7
+ * What the popover hangs from: the trigger's box as it was when it opened —
8
+ * a MUI "virtual element", so the popover keeps its own anchor origin.
9
+ */
10
+ interface StillElement {
11
+ nodeType: 1;
12
+ getBoundingClientRect: () => DOMRect;
13
+ }
14
+
15
+ const stillOf = (element: HTMLElement): StillElement => {
16
+ const box = element.getBoundingClientRect();
17
+ return { nodeType: 1, getBoundingClientRect: () => box };
18
+ };
19
+
20
+ /**
21
+ * A popover that holds STILL while it is open (FUT-4144 UI review round 2).
22
+ *
23
+ * Anchored to an element, a popover follows it. A filter applied from inside
24
+ * one grows the toolbar a "Limpar" and a badge, the trigger moves, and the
25
+ * panel jumped 55px sideways under the finger that had just tapped a day. The
26
+ * point it hangs from is read once, when it opens — and again only when the
27
+ * window itself is resized, which is the one move a reader expects it to make.
28
+ *
29
+ * The other move it makes is when its own HEIGHT changes after it was placed
30
+ * (a preset row settling into a select once measured, a refused day's message):
31
+ * MUI places a popover once, so a taller one ran off a 320×568 screen. The
32
+ * paper's size is watched and the popover re-placed, which moves it only when
33
+ * its height really changed — never on a tap that leaves it the same size.
34
+ *
35
+ * Spread `popoverProps` onto a MUI `Popover` and pass `paperRef` as the paper
36
+ * slot's `ref`.
37
+ */
38
+ export function useStillAnchor(): {
39
+ anchor: HTMLElement | null;
40
+ open: (element: HTMLElement) => void;
41
+ close: () => void;
42
+ paperRef: (node: HTMLDivElement | null) => void;
43
+ popoverProps: {
44
+ open: boolean;
45
+ anchorEl: StillElement | null;
46
+ anchorOrigin: { vertical: 'bottom'; horizontal: 'left' };
47
+ action: RefObject<PopoverActions | null>;
48
+ };
49
+ } {
50
+ const [anchor, setAnchor] = useState<HTMLElement | null>(null);
51
+ const [still, setStill] = useState<StillElement | null>(null);
52
+ const action = useRef<PopoverActions | null>(null);
53
+ const observer = useRef<ResizeObserver | null>(null);
54
+ const paperRef = useCallback((node: HTMLDivElement | null) => {
55
+ observer.current?.disconnect();
56
+ observer.current = null;
57
+ if (!node || typeof ResizeObserver === 'undefined') return;
58
+ let height = node.offsetHeight;
59
+ observer.current = new ResizeObserver(() => {
60
+ if (node.offsetHeight === height) return;
61
+ height = node.offsetHeight;
62
+ action.current?.updatePosition();
63
+ });
64
+ observer.current.observe(node);
65
+ }, []);
66
+
67
+ useEffect(() => {
68
+ if (!anchor) return undefined;
69
+ // A trigger unmounted while its panel is open reads a zero box: keep the
70
+ // frozen one rather than send the panel to the corner.
71
+ const follow = (): void => {
72
+ if (anchor.isConnected) setStill(stillOf(anchor));
73
+ };
74
+ window.addEventListener('resize', follow);
75
+ return () => window.removeEventListener('resize', follow);
76
+ }, [anchor]);
77
+
78
+ return {
79
+ anchor,
80
+ open: (element) => {
81
+ setStill(stillOf(element));
82
+ setAnchor(element);
83
+ },
84
+ close: () => setAnchor(null),
85
+ paperRef,
86
+ popoverProps: {
87
+ open: Boolean(anchor),
88
+ anchorEl: anchor ? still : null,
89
+ anchorOrigin: { vertical: 'bottom', horizontal: 'left' },
90
+ action,
91
+ },
92
+ };
93
+ }
@@ -1,8 +1,7 @@
1
- import type { CSSObject, SxProps, Theme } from '@mui/material/styles/index.js';
1
+ import { alpha, type CSSObject, type SxProps, type Theme } from '@mui/material/styles/index.js';
2
2
 
3
3
  import { FIELD_BORDER_WIDTH } from '../../../tokens/field-height.core';
4
4
  import { rem, sxRem } from '../../../tokens/relative';
5
- import { softSignal } from '../../../tokens/surfaces';
6
5
  import { actualBarColor, blockToneStyles, breakHatch } from '../ScheduleGrid/schedule-tones';
7
6
  import type { ScheduleBlockTone } from '../ScheduleGrid/ScheduleGrid.types';
8
7
  import { DAY_RULER_METRICS as M } from './DayRuler.metrics';
@@ -58,21 +57,35 @@ export function coverageSx(hours: number): SxProps<Theme> {
58
57
  });
59
58
  }
60
59
 
60
+ /**
61
+ * How strongly a staffed hour is filled: the prototype's tonal success step, deeper with each
62
+ * person on the escala (0.18 + 0.09 per person, at most 0.85). An empty hour has none.
63
+ */
64
+ export function coverageStrength(count: number): number {
65
+ if (count <= 0) return 0;
66
+ return Math.min(0.85, 0.18 + count * 0.09);
67
+ }
68
+
61
69
  export function coverageCellSx(count: number): SxProps<Theme> {
62
- return (theme: Theme) => ({
63
- display: 'flex',
64
- alignItems: 'center',
65
- justifyContent: 'center',
66
- fontSize: rem(theme, M.coverage.font),
67
- borderRadius: rem(theme, M.coverage.radius),
68
- color: theme.palette.text.primary,
69
- // A tonal fill, as the prototype's coverage line draws it — never an outline (FUT-3831): a staffed
70
- // hour reads by its fill alone; the hairline stays transparent so a count never shifts its cell.
71
- backgroundColor: count > 0 ? softSignal(theme, 'success') : theme.palette.action.hover,
72
- border: '1px solid transparent',
73
- minWidth: 0,
74
- overflow: 'hidden',
75
- });
70
+ return (theme: Theme) => {
71
+ const strength = coverageStrength(count);
72
+ return {
73
+ display: 'flex',
74
+ alignItems: 'center',
75
+ justifyContent: 'center',
76
+ fontSize: rem(theme, M.coverage.font),
77
+ borderRadius: rem(theme, M.coverage.radius),
78
+ color: theme.palette.text.primary,
79
+ // A tonal fill, as the prototype's coverage line draws it — never an outline (FUT-3831). It is
80
+ // the success colour over the page, so a staffed hour is LIGHTER than an empty one in dark mode
81
+ // and plainly green in light, where the soft-signal blend read as the empty grey. The hairline
82
+ // stays transparent so a count never shifts its cell.
83
+ backgroundColor: strength > 0 ? alpha(theme.palette.success.main, strength) : theme.palette.action.hover,
84
+ border: '1px solid transparent',
85
+ minWidth: 0,
86
+ overflow: 'hidden',
87
+ };
88
+ };
76
89
  }
77
90
 
78
91
  export const axisSx: SxProps<Theme> = (theme: Theme) => ({
@@ -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}