@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.
- package/components-catalog.md +1 -1
- package/dist/_internal/components/data-display/Alert/Alert.js +3 -3
- package/dist/_internal/components/data-display/Avatar/Avatar.js +4 -4
- package/dist/_internal/components/data-display/Avatar/Avatar.view.js +2 -2
- package/dist/_internal/components/data-display/CardKit/card-actions-context.js +4 -4
- package/dist/_internal/components/data-display/CardKit/use-remove-confirm.js +5 -5
- package/dist/_internal/components/data-display/Carousel/Carousel.chrome.js +4 -3
- package/dist/_internal/components/data-display/Carousel/Carousel.js +6 -5
- package/dist/_internal/components/data-display/Carousel/Carousel.parts.js +3 -2
- package/dist/_internal/components/data-display/Chart/Chart.js +3 -3
- package/dist/_internal/components/data-display/Chart/SpecChart.js +6 -6
- package/dist/_internal/components/data-display/Chart/chart-renderers.js +2 -2
- package/dist/_internal/components/data-display/Chart/chart-spec.js +2 -2
- package/dist/_internal/components/data-display/DataGrid/DataGrid.js +2 -2
- package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +48 -23
- package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +53 -28
- package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +1 -1
- package/dist/_internal/components/data-display/DataViews/base-list-card-layout.js +1 -1
- package/dist/_internal/components/data-display/DataViews/base-list-card.js +3 -3
- package/dist/_internal/components/data-display/DataViews/data-views-bar-controls.js +5 -3
- package/dist/_internal/components/data-display/DataViews/data-views-day-input.js +1 -1
- package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +31 -6
- package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +3 -3
- package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +47 -22
- package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +37 -12
- package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +32 -7
- package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +33 -8
- package/dist/_internal/components/data-display/DataViews/data-views-number-input.js +1 -1
- package/dist/_internal/components/data-display/DataViews/data-views-preset-chips.js +10 -3
- package/dist/_internal/components/data-display/DataViews/data-views-range-bounds.js +47 -0
- package/dist/_internal/components/data-display/DataViews/data-views-range-bounds.js.map +1 -0
- package/dist/_internal/components/data-display/DataViews/data-views-range-calendar.js +36 -0
- package/dist/_internal/components/data-display/DataViews/data-views-range-calendar.js.map +1 -0
- package/dist/_internal/components/data-display/DataViews/data-views-range-pill.js +32 -6
- package/dist/_internal/components/data-display/DataViews/data-views-range-summary.js +12 -0
- package/dist/_internal/components/data-display/DataViews/data-views-range-summary.js.map +1 -0
- package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +3 -3
- package/dist/_internal/components/data-display/DataViews/data-views-still-anchor.js +9 -0
- package/dist/_internal/components/data-display/DataViews/data-views-still-anchor.js.map +1 -0
- package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +4 -4
- package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +2 -2
- package/dist/_internal/components/data-display/DayRuler/DayRuler.js +3 -3
- package/dist/_internal/components/data-display/DayRuler/DayRuler.parts.js +2 -2
- package/dist/_internal/components/data-display/DayRuler/DayRuler.styles.js +3 -1
- package/dist/_internal/components/data-display/FleetMap/FleetBody.js +9 -8
- package/dist/_internal/components/data-display/FleetMap/FleetCanvas.js +8 -7
- package/dist/_internal/components/data-display/FleetMap/FleetMap.fixtures.js +2 -1
- package/dist/_internal/components/data-display/FleetMap/FleetMap.fixtures.js.map +1 -1
- package/dist/_internal/components/data-display/FleetMap/FleetMap.js +9 -9
- package/dist/_internal/components/data-display/MapPreview/MapControlBar.js +4 -3
- package/dist/_internal/components/data-display/MapPreview/MapLayers.js +5 -4
- package/dist/_internal/components/data-display/MapPreview/MapMarkers.js +4 -3
- package/dist/_internal/components/data-display/MapPreview/MapPreview.helpers.js +3 -2
- package/dist/_internal/components/data-display/MapPreview/MapPreview.js +7 -6
- package/dist/_internal/components/data-display/index.js +38 -38
- package/dist/_internal/components/feedback/NotificationStatusNotice/NotificationStatusNotice.js +4 -4
- package/dist/_internal/components/feedback/SequenceResolver/SequenceResolver.js +6 -6
- package/dist/_internal/components/feedback/SequenceResolver/SequenceResolver.overview.js +5 -5
- package/dist/_internal/components/feedback/SequenceResolver/SequenceResolver.parts.js +4 -4
- package/dist/_internal/components/feedback/index.js +7 -7
- package/dist/_internal/components/form/Calendar/Calendar.js +5 -5
- package/dist/_internal/components/form/Calendar/CalendarDay.js +1 -1
- package/dist/_internal/components/form/Calendar/CalendarDayCell.js +2 -2
- package/dist/_internal/components/form/Calendar/CalendarMonth.js +3 -3
- package/dist/_internal/components/form/Calendar/CalendarSelectorsMonth.js +4 -4
- package/dist/_internal/components/form/DateRangePicker/DateRangePicker.hooks.js +3 -3
- package/dist/_internal/components/form/DateRangePicker/DateRangePicker.js +10 -10
- package/dist/_internal/components/form/DateRangePicker/DateRangePicker.range.js +2 -2
- package/dist/_internal/components/form/DateRangePicker/DateRangePickerFields.js +3 -3
- package/dist/_internal/components/form/index.js +24 -24
- package/dist/_internal/components/index.js +66 -66
- package/dist/_internal/en-US.data-display.js +2 -1
- package/dist/_internal/pt-BR.data-display.js +2 -1
- package/dist/_internal/user-avatar/user-avatar.js +5 -5
- package/dist/charts.js +11 -11
- package/dist/{chunk-FJ3UZ4RC.js → chunk-2FKWKLSC.js} +5 -3
- package/dist/chunk-2FKWKLSC.js.map +1 -0
- package/dist/{chunk-BO6MT2S2.js → chunk-3HZKUN5J.js} +7 -6
- package/dist/chunk-3HZKUN5J.js.map +1 -0
- package/dist/{chunk-TYXFFNPM.js → chunk-3OTGREQG.js} +10 -10
- package/dist/{chunk-BEHT4IHH.js → chunk-3X2MA47R.js} +2 -2
- package/dist/{chunk-XHIBFBNP.js → chunk-3ZRK3BRN.js} +4 -2
- package/dist/chunk-3ZRK3BRN.js.map +1 -0
- package/dist/{chunk-X5OGIT2F.js → chunk-4L54KUZV.js} +22 -4
- package/dist/chunk-4L54KUZV.js.map +1 -0
- package/dist/{chunk-TRYR424I.js → chunk-6LOWZCH7.js} +15 -1
- package/dist/chunk-6LOWZCH7.js.map +1 -0
- package/dist/{chunk-6WHIJPEF.js → chunk-6PU5P7QT.js} +2 -2
- package/dist/chunk-7CUZTWKW.js +52 -0
- package/dist/chunk-7CUZTWKW.js.map +1 -0
- package/dist/{chunk-JIEVKHOH.js → chunk-7YJYIMWP.js} +7 -7
- package/dist/{chunk-YNZUYZ2O.js → chunk-A3DDEKLV.js} +2 -2
- package/dist/{chunk-KHREN7Y7.js → chunk-ACM3HHZY.js} +2 -2
- package/dist/{chunk-FEKWKWGK.js → chunk-ARGVUTTL.js} +15 -1
- package/dist/chunk-ARGVUTTL.js.map +1 -0
- package/dist/{chunk-DYHOBKPU.js → chunk-BLZDSCIZ.js} +6 -6
- package/dist/{chunk-E2UOEI7N.js → chunk-BV2LOTMC.js} +2 -2
- package/dist/{chunk-O63ZROSY.js → chunk-BZBLPXV7.js} +4 -4
- package/dist/{chunk-OKRITX4S.js → chunk-CJ6XXM4X.js} +4 -4
- package/dist/{chunk-LV6AD6XC.js → chunk-DBI6AMNY.js} +4 -4
- package/dist/{chunk-QRRWLLXW.js → chunk-DSBC6O46.js} +2 -2
- package/dist/{chunk-3YFDGFEK.js → chunk-DVX4HDNP.js} +2 -2
- package/dist/{chunk-CJUK32UH.js → chunk-EEO7M5GU.js} +2 -2
- package/dist/{chunk-7XSCEHGA.js → chunk-EOQ6EKTS.js} +7 -7
- package/dist/{chunk-5RSK5M6M.js → chunk-FI2CQOGC.js} +63 -126
- package/dist/chunk-FI2CQOGC.js.map +1 -0
- package/dist/{chunk-Q2ERGAQO.js → chunk-FYAW5GBF.js} +33 -6
- package/dist/chunk-FYAW5GBF.js.map +1 -0
- package/dist/{chunk-EOJSA2EK.js → chunk-G2PVUPE7.js} +26 -18
- package/dist/chunk-G2PVUPE7.js.map +1 -0
- package/dist/{chunk-AMLHEKSV.js → chunk-HI7JPDD6.js} +5 -5
- package/dist/{chunk-2H6SCVLD.js → chunk-HMEGQKNQ.js} +3 -3
- package/dist/chunk-J2AVWIMM.js +60 -0
- package/dist/chunk-J2AVWIMM.js.map +1 -0
- package/dist/{chunk-7QKIL5YF.js → chunk-J2GDA64N.js} +4 -4
- package/dist/{chunk-BAQ3ITZV.js → chunk-JFD742C3.js} +2 -2
- package/dist/{chunk-OBA75Y5O.js → chunk-JHWEL4NX.js} +61 -33
- package/dist/chunk-JHWEL4NX.js.map +1 -0
- package/dist/{chunk-HQCZT6TO.js → chunk-JVOEVTCZ.js} +5 -5
- package/dist/{chunk-WAO7UQRS.js → chunk-KANCE4MS.js} +3 -3
- package/dist/{chunk-XLU5WFSY.js → chunk-KRBPWTXW.js} +2 -2
- package/dist/{chunk-S6D7NOV7.js → chunk-L6JAALMX.js} +3 -3
- package/dist/{chunk-72HOUWAW.js → chunk-L6YTVXGN.js} +5 -3
- package/dist/{chunk-72HOUWAW.js.map → chunk-L6YTVXGN.js.map} +1 -1
- package/dist/chunk-LZNUBQ5I.js +181 -0
- package/dist/chunk-LZNUBQ5I.js.map +1 -0
- package/dist/{chunk-BECKKDYG.js → chunk-M2M4IDFU.js} +2 -2
- package/dist/{chunk-CSGBHYW6.js → chunk-M5Y42AZ4.js} +2 -2
- package/dist/chunk-MICX23P4.js +122 -0
- package/dist/chunk-MICX23P4.js.map +1 -0
- package/dist/{chunk-5CP5Z3YU.js → chunk-MPWA55CF.js} +4 -4
- package/dist/{chunk-5KK3I42O.js → chunk-NK6O4NE4.js} +13 -10
- package/dist/chunk-NK6O4NE4.js.map +1 -0
- package/dist/{chunk-RCTHCXS6.js → chunk-PJNIJIE6.js} +2 -2
- package/dist/{chunk-6ATXOJVQ.js → chunk-QADTI63U.js} +4 -4
- package/dist/{chunk-MW7P2C2C.js → chunk-QAEO52Z4.js} +2 -2
- package/dist/{chunk-5S5K73I6.js → chunk-QSOCOXVL.js} +3 -3
- package/dist/{chunk-NQCTANF3.js → chunk-QVDEGBME.js} +7 -7
- package/dist/{chunk-BQBEN44R.js → chunk-RDCIST7P.js} +2 -2
- package/dist/{chunk-HUXAIQC5.js → chunk-RZ3P4X2I.js} +2 -2
- package/dist/{chunk-WJMSND5Q.js → chunk-SCXVTNLE.js} +2 -2
- package/dist/{chunk-K6FCSB6T.js → chunk-SK2CTB3O.js} +6 -6
- package/dist/{chunk-QLJU7UUI.js → chunk-T7OIVPCO.js} +38 -3
- package/dist/chunk-T7OIVPCO.js.map +1 -0
- package/dist/{chunk-U2ILXZDG.js → chunk-TB5CRHTF.js} +2 -2
- package/dist/{chunk-SB2SEGR6.js → chunk-TIM4PXWN.js} +3 -3
- package/dist/{chunk-YDIC6LSP.js → chunk-VCQFDQM3.js} +27 -7
- package/dist/chunk-VCQFDQM3.js.map +1 -0
- package/dist/chunk-VIMMEADQ.js +164 -0
- package/dist/chunk-VIMMEADQ.js.map +1 -0
- package/dist/{chunk-6D5AMANO.js → chunk-WH3LUOCQ.js} +2 -2
- package/dist/{chunk-OWRQOYUE.js → chunk-WWR6APJR.js} +2 -2
- package/dist/{chunk-5BVAUUWL.js → chunk-X37NTEVS.js} +2 -2
- package/dist/{chunk-WW3F7DCX.js → chunk-Z2WZDVGG.js} +2 -2
- package/dist/{chunk-EXVCVXFX.js → chunk-ZH6NYB6Y.js} +3 -3
- package/dist/data-display/Alert.js +3 -3
- package/dist/data-display/Avatar.js +4 -4
- package/dist/data-display/CardKit.js +11 -11
- package/dist/data-display/Carousel.js +6 -5
- package/dist/data-display/Chart.js +11 -11
- package/dist/data-display/DataGrid.js +2 -2
- package/dist/data-display/DataViews.js +60 -35
- package/dist/data-display/DayRuler.js +3 -3
- package/dist/data-display/FleetMap.js +9 -9
- package/dist/data-display/MapPreview.js +7 -6
- package/dist/en-US.js +1 -1
- package/dist/feedback/NotificationStatusNotice.js +4 -4
- package/dist/feedback/SequenceResolver.js +6 -6
- package/dist/form/Calendar.js +5 -5
- package/dist/form/DateRangePicker.js +10 -10
- package/dist/locales.js +5 -5
- package/dist/pt-BR.js +1 -1
- package/dist/types/components/data-display/DataViews/data-views-bar-controls.d.ts +15 -1
- package/dist/types/components/data-display/DataViews/data-views-bar-controls.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-copy.d.ts +35 -0
- package/dist/types/components/data-display/DataViews/data-views-copy.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-day-input.d.ts +7 -1
- package/dist/types/components/data-display/DataViews/data-views-day-input.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-more-fields.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-more-filters.d.ts +5 -3
- package/dist/types/components/data-display/DataViews/data-views-more-filters.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-number-input.d.ts +10 -2
- package/dist/types/components/data-display/DataViews/data-views-number-input.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-preset-chips.d.ts +10 -0
- package/dist/types/components/data-display/DataViews/data-views-preset-chips.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-range-bounds.d.ts +35 -0
- package/dist/types/components/data-display/DataViews/data-views-range-bounds.d.ts.map +1 -0
- package/dist/types/components/data-display/DataViews/data-views-range-calendar.d.ts +35 -0
- package/dist/types/components/data-display/DataViews/data-views-range-calendar.d.ts.map +1 -0
- package/dist/types/components/data-display/DataViews/data-views-range-pill.d.ts +2 -11
- package/dist/types/components/data-display/DataViews/data-views-range-pill.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-range-summary.d.ts +21 -0
- package/dist/types/components/data-display/DataViews/data-views-range-summary.d.ts.map +1 -0
- package/dist/types/components/data-display/DataViews/data-views-still-anchor.d.ts +45 -0
- package/dist/types/components/data-display/DataViews/data-views-still-anchor.d.ts.map +1 -0
- package/dist/types/components/data-display/DayRuler/DayRuler.styles.d.ts +6 -1
- package/dist/types/components/data-display/DayRuler/DayRuler.styles.d.ts.map +1 -1
- package/dist/types/components/data-display/LazyImage/LazyImage.hooks.d.ts +1 -1
- package/dist/types/components/form/Calendar/Calendar.d.ts.map +1 -1
- package/dist/types/components/form/Calendar/CalendarDay.d.ts +2 -0
- package/dist/types/components/form/Calendar/CalendarDay.d.ts.map +1 -1
- package/dist/types/components/form/Calendar/CalendarDayCell.d.ts +2 -0
- package/dist/types/components/form/Calendar/CalendarDayCell.d.ts.map +1 -1
- package/dist/types/components/form/Calendar/CalendarMonth.d.ts +5 -0
- package/dist/types/components/form/Calendar/CalendarMonth.d.ts.map +1 -1
- package/dist/types/en-US.data-display.d.ts.map +1 -1
- package/dist/types/pt-BR.data-display.d.ts.map +1 -1
- package/dist/user-avatar.js +5 -5
- package/package.json +1 -1
- package/src/components/data-display/DataViews/RESPONSIVE-BEHAVIOUR.md +59 -0
- package/src/components/data-display/DataViews/data-views-bar-controls.tsx +56 -1
- package/src/components/data-display/DataViews/data-views-copy.ts +36 -0
- package/src/components/data-display/DataViews/data-views-day-input.tsx +9 -1
- package/src/components/data-display/DataViews/data-views-inline-bar.tsx +5 -3
- package/src/components/data-display/DataViews/data-views-more-fields.tsx +1 -0
- package/src/components/data-display/DataViews/data-views-more-filters.tsx +82 -29
- package/src/components/data-display/DataViews/data-views-number-input.tsx +19 -9
- package/src/components/data-display/DataViews/data-views-preset-chips.tsx +165 -16
- package/src/components/data-display/DataViews/data-views-range-bounds.tsx +223 -0
- package/src/components/data-display/DataViews/data-views-range-calendar.tsx +185 -0
- package/src/components/data-display/DataViews/data-views-range-pill.tsx +71 -154
- package/src/components/data-display/DataViews/data-views-range-summary.tsx +66 -0
- package/src/components/data-display/DataViews/data-views-still-anchor.ts +93 -0
- package/src/components/data-display/DayRuler/DayRuler.styles.ts +29 -16
- package/src/components/form/Calendar/Calendar.md +17 -2
- package/src/components/form/Calendar/Calendar.tsx +56 -3
- package/src/components/form/Calendar/CalendarDay.tsx +33 -3
- package/src/components/form/Calendar/CalendarDayCell.tsx +4 -0
- package/src/components/form/Calendar/CalendarMonth.tsx +27 -5
- package/src/en-US.data-display.ts +12 -0
- package/src/pt-BR.data-display.ts +12 -0
- package/dist/chunk-5KK3I42O.js.map +0 -1
- package/dist/chunk-5RSK5M6M.js.map +0 -1
- package/dist/chunk-7D7CJRL7.js +0 -78
- package/dist/chunk-7D7CJRL7.js.map +0 -1
- package/dist/chunk-BO6MT2S2.js.map +0 -1
- package/dist/chunk-EOJSA2EK.js.map +0 -1
- package/dist/chunk-FEKWKWGK.js.map +0 -1
- package/dist/chunk-FJ3UZ4RC.js.map +0 -1
- package/dist/chunk-OBA75Y5O.js.map +0 -1
- package/dist/chunk-Q2ERGAQO.js.map +0 -1
- package/dist/chunk-QLJU7UUI.js.map +0 -1
- package/dist/chunk-TRYR424I.js.map +0 -1
- package/dist/chunk-X5OGIT2F.js.map +0 -1
- package/dist/chunk-XHIBFBNP.js.map +0 -1
- package/dist/chunk-YDIC6LSP.js.map +0 -1
- /package/dist/{chunk-TYXFFNPM.js.map → chunk-3OTGREQG.js.map} +0 -0
- /package/dist/{chunk-BEHT4IHH.js.map → chunk-3X2MA47R.js.map} +0 -0
- /package/dist/{chunk-6WHIJPEF.js.map → chunk-6PU5P7QT.js.map} +0 -0
- /package/dist/{chunk-JIEVKHOH.js.map → chunk-7YJYIMWP.js.map} +0 -0
- /package/dist/{chunk-YNZUYZ2O.js.map → chunk-A3DDEKLV.js.map} +0 -0
- /package/dist/{chunk-KHREN7Y7.js.map → chunk-ACM3HHZY.js.map} +0 -0
- /package/dist/{chunk-DYHOBKPU.js.map → chunk-BLZDSCIZ.js.map} +0 -0
- /package/dist/{chunk-E2UOEI7N.js.map → chunk-BV2LOTMC.js.map} +0 -0
- /package/dist/{chunk-O63ZROSY.js.map → chunk-BZBLPXV7.js.map} +0 -0
- /package/dist/{chunk-OKRITX4S.js.map → chunk-CJ6XXM4X.js.map} +0 -0
- /package/dist/{chunk-LV6AD6XC.js.map → chunk-DBI6AMNY.js.map} +0 -0
- /package/dist/{chunk-QRRWLLXW.js.map → chunk-DSBC6O46.js.map} +0 -0
- /package/dist/{chunk-3YFDGFEK.js.map → chunk-DVX4HDNP.js.map} +0 -0
- /package/dist/{chunk-CJUK32UH.js.map → chunk-EEO7M5GU.js.map} +0 -0
- /package/dist/{chunk-7XSCEHGA.js.map → chunk-EOQ6EKTS.js.map} +0 -0
- /package/dist/{chunk-AMLHEKSV.js.map → chunk-HI7JPDD6.js.map} +0 -0
- /package/dist/{chunk-2H6SCVLD.js.map → chunk-HMEGQKNQ.js.map} +0 -0
- /package/dist/{chunk-7QKIL5YF.js.map → chunk-J2GDA64N.js.map} +0 -0
- /package/dist/{chunk-BAQ3ITZV.js.map → chunk-JFD742C3.js.map} +0 -0
- /package/dist/{chunk-HQCZT6TO.js.map → chunk-JVOEVTCZ.js.map} +0 -0
- /package/dist/{chunk-WAO7UQRS.js.map → chunk-KANCE4MS.js.map} +0 -0
- /package/dist/{chunk-XLU5WFSY.js.map → chunk-KRBPWTXW.js.map} +0 -0
- /package/dist/{chunk-S6D7NOV7.js.map → chunk-L6JAALMX.js.map} +0 -0
- /package/dist/{chunk-BECKKDYG.js.map → chunk-M2M4IDFU.js.map} +0 -0
- /package/dist/{chunk-CSGBHYW6.js.map → chunk-M5Y42AZ4.js.map} +0 -0
- /package/dist/{chunk-5CP5Z3YU.js.map → chunk-MPWA55CF.js.map} +0 -0
- /package/dist/{chunk-RCTHCXS6.js.map → chunk-PJNIJIE6.js.map} +0 -0
- /package/dist/{chunk-6ATXOJVQ.js.map → chunk-QADTI63U.js.map} +0 -0
- /package/dist/{chunk-MW7P2C2C.js.map → chunk-QAEO52Z4.js.map} +0 -0
- /package/dist/{chunk-5S5K73I6.js.map → chunk-QSOCOXVL.js.map} +0 -0
- /package/dist/{chunk-NQCTANF3.js.map → chunk-QVDEGBME.js.map} +0 -0
- /package/dist/{chunk-BQBEN44R.js.map → chunk-RDCIST7P.js.map} +0 -0
- /package/dist/{chunk-HUXAIQC5.js.map → chunk-RZ3P4X2I.js.map} +0 -0
- /package/dist/{chunk-WJMSND5Q.js.map → chunk-SCXVTNLE.js.map} +0 -0
- /package/dist/{chunk-K6FCSB6T.js.map → chunk-SK2CTB3O.js.map} +0 -0
- /package/dist/{chunk-U2ILXZDG.js.map → chunk-TB5CRHTF.js.map} +0 -0
- /package/dist/{chunk-SB2SEGR6.js.map → chunk-TIM4PXWN.js.map} +0 -0
- /package/dist/{chunk-6D5AMANO.js.map → chunk-WH3LUOCQ.js.map} +0 -0
- /package/dist/{chunk-OWRQOYUE.js.map → chunk-WWR6APJR.js.map} +0 -0
- /package/dist/{chunk-5BVAUUWL.js.map → chunk-X37NTEVS.js.map} +0 -0
- /package/dist/{chunk-WW3F7DCX.js.map → chunk-Z2WZDVGG.js.map} +0 -0
- /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
|
|
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 {
|
|
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 {
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
301
|
-
anchorEl={anchor}
|
|
220
|
+
{...still.popoverProps}
|
|
302
221
|
onClose={() => {
|
|
303
|
-
|
|
222
|
+
still.close();
|
|
304
223
|
onOpenChange?.(false);
|
|
305
224
|
}}
|
|
306
|
-
|
|
307
|
-
|
|
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
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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"`,
|
|
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
|
-
-
|
|
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={
|
|
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={
|
|
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}
|