@12-apps/ui 6.38.0 → 6.39.1
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/dist/_internal/components/data-display/DataGrid/DataGrid.body.js +3 -2
- package/dist/_internal/components/data-display/DataGrid/DataGrid.cells.js +2 -1
- package/dist/_internal/components/data-display/DataGrid/DataGrid.js +4 -4
- package/dist/_internal/components/data-display/DataGrid/DataGrid.model.js +2 -1
- package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +19 -19
- package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +26 -26
- package/dist/_internal/components/data-display/DataViews/SaveViewModal.js +5 -5
- package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +4 -4
- package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +3 -3
- package/dist/_internal/components/data-display/DataViews/base-list-card.js +5 -5
- package/dist/_internal/components/data-display/DataViews/data-views-columns.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-display-panel.js +3 -3
- package/dist/_internal/components/data-display/DataViews/data-views-display-tabs.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +8 -8
- package/dist/_internal/components/data-display/DataViews/data-views-grid-helpers.js +1 -1
- package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +16 -16
- package/dist/_internal/components/data-display/DataViews/data-views-layout-context.js +1 -1
- package/dist/_internal/components/data-display/DataViews/data-views-overflow-costs.js +4 -3
- package/dist/_internal/components/data-display/DataViews/data-views-overflow.js +3 -2
- package/dist/_internal/components/data-display/DataViews/data-views-scope-tabs.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +6 -6
- package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +6 -6
- package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +5 -5
- package/dist/_internal/components/data-display/DataViews/list-card-rails.js +2 -2
- package/dist/_internal/components/data-display/DataViews/use-data-views-state.js +3 -3
- package/dist/_internal/components/data-display/FleetMap/FleetBody.js +9 -9
- package/dist/_internal/components/data-display/FleetMap/FleetCanvas.js +8 -8
- package/dist/_internal/components/data-display/FleetMap/FleetMap.js +10 -10
- package/dist/_internal/components/data-display/LazyImage/LazyImage.js +1 -1
- package/dist/_internal/components/data-display/MapPreview/MapDecorations.js +2 -2
- package/dist/_internal/components/data-display/MapPreview/MapPreview.hooks.js +2 -2
- package/dist/_internal/components/data-display/MapPreview/MapPreview.js +7 -7
- package/dist/_internal/components/data-display/MapPreview/MapTiles.js +2 -2
- package/dist/_internal/components/data-display/MapPreview/StaticMapView.js +4 -4
- package/dist/_internal/components/data-display/MapPreview/mapProjection.js +3 -3
- package/dist/_internal/components/data-display/MapPreview/useMapPreview.js +3 -3
- package/dist/_internal/components/data-display/Table/Table.helpers.js +5 -3
- package/dist/_internal/components/data-display/Table/Table.hooks.js +2 -1
- package/dist/_internal/components/data-display/Table/Table.js +4 -4
- package/dist/_internal/components/data-display/Table/TableParts.hooks.js +4 -2
- package/dist/_internal/components/data-display/Table/TableParts.js +4 -2
- package/dist/_internal/components/data-display/index.js +19 -19
- package/dist/_internal/components/form/Calendar/Calendar.js +5 -4
- package/dist/_internal/components/form/Calendar/CalendarDay.js +2 -1
- package/dist/_internal/components/form/Calendar/CalendarDayCell.js +3 -2
- package/dist/_internal/components/form/Calendar/CalendarMonth.js +4 -3
- package/dist/_internal/components/form/DateRangePicker/DateRangePicker.js +5 -5
- package/dist/_internal/components/form/Switch/Switch.js +4 -4
- package/dist/_internal/components/form/Switch/Switch.metrics.js +5 -1
- package/dist/_internal/components/form/Switch/Switch.parts.js +3 -3
- package/dist/_internal/components/form/Switch/Switch.styles.js +2 -2
- package/dist/_internal/components/form/index.js +9 -9
- package/dist/_internal/components/index.js +38 -38
- package/dist/_internal/components/layout/CardGrid/CardGrid.js +2 -1
- package/dist/_internal/components/layout/Resizable/Resizable.helpers.js +8 -3
- package/dist/_internal/components/layout/Resizable/Resizable.hooks.js +3 -2
- package/dist/_internal/components/layout/Resizable/Resizable.js +4 -3
- package/dist/_internal/components/layout/ScrollArea/ScrollArea.helpers.js +1 -1
- package/dist/_internal/components/layout/ScrollArea/ScrollArea.js +2 -2
- package/dist/_internal/components/layout/index.js +5 -5
- package/dist/_internal/components/utility/InfiniteScroll/InfiniteScroll.hooks.js +1 -1
- package/dist/_internal/components/utility/InfiniteScroll/InfiniteScroll.js +4 -3
- package/dist/_internal/components/utility/InfiniteScroll/InfiniteScroll.parts.js +2 -1
- package/dist/_internal/components/utility/VirtualList/VirtualList.hooks.js +6 -3
- package/dist/_internal/components/utility/VirtualList/VirtualList.js +3 -2
- package/dist/_internal/components/utility/index.js +5 -5
- package/dist/{chunk-J2DAQQQH.js → chunk-222HN7GK.js} +33 -64
- package/dist/chunk-222HN7GK.js.map +1 -0
- package/dist/{chunk-MR2HKBHS.js → chunk-27LOJVR3.js} +2 -2
- package/dist/{chunk-S3D5VBHW.js → chunk-3YOXVNO4.js} +7 -7
- package/dist/{chunk-CZIX4BW2.js → chunk-4ALF5PB5.js} +3 -3
- package/dist/{chunk-XJPJ6ESI.js → chunk-4OAKGKK5.js} +3 -3
- package/dist/{chunk-4CHROSWR.js → chunk-5ETBB2DG.js} +2 -2
- package/dist/{chunk-ATSHKSSD.js → chunk-5KNDAC24.js} +20 -7
- package/dist/chunk-5KNDAC24.js.map +1 -0
- package/dist/{chunk-ULTOQ6ZV.js → chunk-5LWB4BYX.js} +80 -89
- package/dist/chunk-5LWB4BYX.js.map +1 -0
- package/dist/{chunk-46UPILLK.js → chunk-5NT2M2JI.js} +2 -2
- package/dist/{chunk-H5BEWPEY.js → chunk-6N2EDWMG.js} +2 -2
- package/dist/{chunk-GJQYM3PM.js → chunk-6PU3JYVY.js} +2 -2
- package/dist/{chunk-PUBPZOQJ.js → chunk-AG3DY5TH.js} +8 -5
- package/dist/chunk-AG3DY5TH.js.map +1 -0
- package/dist/{chunk-PPRV4LTM.js → chunk-BWHOCNGW.js} +4 -4
- package/dist/chunk-BWHOCNGW.js.map +1 -0
- package/dist/{chunk-TUBCN4DJ.js → chunk-CB6DTWD5.js} +7 -7
- package/dist/chunk-CB6DTWD5.js.map +1 -0
- package/dist/{chunk-ZAY6OA6F.js → chunk-D4FZ3ANG.js} +15 -5
- package/dist/chunk-D4FZ3ANG.js.map +1 -0
- package/dist/{chunk-Y7F5JBAT.js → chunk-DDRKYNPB.js} +2 -2
- package/dist/{chunk-DLJGBJZW.js → chunk-DGMDQHMI.js} +16 -9
- package/dist/chunk-DGMDQHMI.js.map +1 -0
- package/dist/{chunk-IAGOUTI6.js → chunk-DNT5PZLF.js} +21 -12
- package/dist/chunk-DNT5PZLF.js.map +1 -0
- package/dist/{chunk-DZA7RSLX.js → chunk-DVSO3EG6.js} +19 -11
- package/dist/chunk-DVSO3EG6.js.map +1 -0
- package/dist/{chunk-OS6KPL4D.js → chunk-EHYI2WCJ.js} +4 -4
- package/dist/{chunk-NB3FGWU4.js → chunk-EQXIW5MQ.js} +2 -2
- package/dist/{chunk-C66RGVAS.js → chunk-ERY6D2OV.js} +6 -4
- package/dist/chunk-ERY6D2OV.js.map +1 -0
- package/dist/{chunk-M2JTIH5M.js → chunk-F44R7US6.js} +2 -2
- package/dist/{chunk-AROBXRC5.js → chunk-F7JTIHV5.js} +18 -7
- package/dist/chunk-F7JTIHV5.js.map +1 -0
- package/dist/{chunk-T7DE44SP.js → chunk-FF2D7V7T.js} +6 -4
- package/dist/chunk-FF2D7V7T.js.map +1 -0
- package/dist/{chunk-XJJXBUPN.js → chunk-FX26DAFF.js} +2 -2
- package/dist/{chunk-R6SN73RX.js → chunk-GLHNMTP6.js} +7 -7
- package/dist/{chunk-YU26GBNX.js → chunk-H3AQQOTI.js} +9 -4
- package/dist/chunk-H3AQQOTI.js.map +1 -0
- package/dist/{chunk-HTZNB6IV.js → chunk-H5ZTIELC.js} +23 -8
- package/dist/chunk-H5ZTIELC.js.map +1 -0
- package/dist/{chunk-GSFNH4C5.js → chunk-HBP2OU4Q.js} +15 -8
- package/dist/chunk-HBP2OU4Q.js.map +1 -0
- package/dist/{chunk-I4QA2F4L.js → chunk-HBRQPG7H.js} +5 -5
- package/dist/{chunk-HGMBY5LP.js → chunk-HQWJUHR4.js} +18 -11
- package/dist/chunk-HQWJUHR4.js.map +1 -0
- package/dist/{chunk-CNQUCNEA.js → chunk-I3F4C5SS.js} +3 -3
- package/dist/{chunk-UFJYJHQI.js → chunk-J5VWGQSR.js} +2 -2
- package/dist/{chunk-MTFCPPZ5.js → chunk-JWZJSXI5.js} +3 -2
- package/dist/chunk-JWZJSXI5.js.map +1 -0
- package/dist/{chunk-4JFL62K3.js → chunk-K7FSTB2K.js} +3 -3
- package/dist/{chunk-FFCJ7NR2.js → chunk-KRQUPE4K.js} +4 -4
- package/dist/{chunk-2OYFTSG4.js → chunk-KXLUMEDX.js} +2 -2
- package/dist/{chunk-DVAAUWTC.js → chunk-LCHCE2G5.js} +2 -2
- package/dist/{chunk-G4HBNILE.js → chunk-LEHMWJNZ.js} +3 -3
- package/dist/{chunk-P6TNXBDA.js → chunk-MYKWJCR7.js} +9 -9
- package/dist/chunk-MYKWJCR7.js.map +1 -0
- package/dist/{chunk-TQ6FPOPD.js → chunk-ODW2D5PN.js} +39 -30
- package/dist/chunk-ODW2D5PN.js.map +1 -0
- package/dist/{chunk-RZYSKQTS.js → chunk-PCBZYORN.js} +3 -3
- package/dist/{chunk-5OBXEMQO.js → chunk-PRIBOWX4.js} +3 -3
- package/dist/{chunk-F42MJOHM.js → chunk-PVM7XTLZ.js} +64 -62
- package/dist/chunk-PVM7XTLZ.js.map +1 -0
- package/dist/{chunk-3TDVGZZN.js → chunk-QBTBRJ2Q.js} +37 -13
- package/dist/chunk-QBTBRJ2Q.js.map +1 -0
- package/dist/{chunk-2WFDHFK4.js → chunk-QNCWSDXE.js} +26 -11
- package/dist/chunk-QNCWSDXE.js.map +1 -0
- package/dist/{chunk-PQECNGDE.js → chunk-QSRZOXQI.js} +2 -2
- package/dist/{chunk-RHIDWUK7.js → chunk-QUWK7SYN.js} +1 -2
- package/dist/chunk-QUWK7SYN.js.map +1 -0
- package/dist/{chunk-UN5INW6K.js → chunk-R53ZOW4B.js} +8 -4
- package/dist/chunk-R53ZOW4B.js.map +1 -0
- package/dist/{chunk-DCJSHYE5.js → chunk-RSDYS5B3.js} +4 -4
- package/dist/{chunk-N5GVW6RO.js → chunk-S6IWKDWT.js} +2 -2
- package/dist/{chunk-TKC6WHGB.js → chunk-SBIZXZPP.js} +2 -2
- package/dist/{chunk-D5SZXH7Q.js → chunk-TNBJ4DK4.js} +7 -3
- package/dist/chunk-TNBJ4DK4.js.map +1 -0
- package/dist/{chunk-PMOEG36E.js → chunk-XZJM6EPC.js} +8 -6
- package/dist/chunk-XZJM6EPC.js.map +1 -0
- package/dist/{chunk-QF6LTUCE.js → chunk-Y2X7LYIN.js} +4 -4
- package/dist/chunk-Y2X7LYIN.js.map +1 -0
- package/dist/{chunk-UEVHI62V.js → chunk-YCCY77W5.js} +2 -2
- package/dist/{chunk-DF4K5XVW.js → chunk-YZVR5ROE.js} +14 -6
- package/dist/chunk-YZVR5ROE.js.map +1 -0
- package/dist/{chunk-AUSUCZYR.js → chunk-ZBVU2YWV.js} +5 -5
- package/dist/chunk-ZBVU2YWV.js.map +1 -0
- package/dist/{chunk-VZIB5W5L.js → chunk-ZGCPDA3F.js} +2 -2
- package/dist/data-display/DataGrid.js +4 -4
- package/dist/data-display/DataViews.js +29 -29
- package/dist/data-display/FleetMap.js +10 -10
- package/dist/data-display/LazyImage.js +1 -1
- package/dist/data-display/MapPreview.js +7 -7
- package/dist/data-display/Table.js +4 -4
- package/dist/form/Calendar.js +5 -4
- package/dist/form/DateRangePicker.js +5 -5
- package/dist/form/Switch.js +4 -4
- package/dist/layout/CardGrid.js +2 -1
- package/dist/layout/Resizable.js +4 -3
- package/dist/layout/ScrollArea.js +2 -2
- package/dist/native/form/Switch.js +3 -1
- package/dist/native/form/Switch.js.map +1 -1
- package/dist/types/components/data-display/DataGrid/DataGrid.body.d.ts.map +1 -1
- package/dist/types/components/data-display/DataGrid/DataGrid.cells.d.ts +4 -2
- package/dist/types/components/data-display/DataGrid/DataGrid.cells.d.ts.map +1 -1
- package/dist/types/components/data-display/DataGrid/DataGrid.model.d.ts +7 -1
- package/dist/types/components/data-display/DataGrid/DataGrid.model.d.ts.map +1 -1
- package/dist/types/components/data-display/DataGrid/DataGrid.types.d.ts +10 -4
- package/dist/types/components/data-display/DataGrid/DataGrid.types.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-columns.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-grid-helpers.d.ts +2 -0
- package/dist/types/components/data-display/DataViews/data-views-grid-helpers.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-layout-context.d.ts +7 -3
- package/dist/types/components/data-display/DataViews/data-views-layout-context.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-overflow-costs.d.ts +19 -9
- package/dist/types/components/data-display/DataViews/data-views-overflow-costs.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-overflow.d.ts.map +1 -1
- package/dist/types/components/data-display/LazyImage/LazyImage.d.ts.map +1 -1
- package/dist/types/components/data-display/LazyImage/LazyImage.types.d.ts +3 -1
- package/dist/types/components/data-display/LazyImage/LazyImage.types.d.ts.map +1 -1
- package/dist/types/components/data-display/MapPreview/MapTiles.d.ts.map +1 -1
- package/dist/types/components/data-display/MapPreview/mapProjection.d.ts +6 -1
- package/dist/types/components/data-display/MapPreview/mapProjection.d.ts.map +1 -1
- package/dist/types/components/data-display/Table/Table.helpers.d.ts +6 -0
- package/dist/types/components/data-display/Table/Table.helpers.d.ts.map +1 -1
- package/dist/types/components/data-display/Table/Table.hooks.d.ts +9 -1
- package/dist/types/components/data-display/Table/Table.hooks.d.ts.map +1 -1
- package/dist/types/components/data-display/Table/Table.types.d.ts +6 -2
- package/dist/types/components/data-display/Table/Table.types.d.ts.map +1 -1
- package/dist/types/components/data-display/Table/TableParts.d.ts +2 -0
- package/dist/types/components/data-display/Table/TableParts.d.ts.map +1 -1
- package/dist/types/components/form/Calendar/Calendar.d.ts.map +1 -1
- package/dist/types/components/form/Calendar/CalendarDay.d.ts.map +1 -1
- package/dist/types/components/form/Calendar/CalendarMonth.d.ts.map +1 -1
- package/dist/types/components/form/Switch/Switch.metrics.d.ts +13 -3
- package/dist/types/components/form/Switch/Switch.metrics.d.ts.map +1 -1
- package/dist/types/components/form/Switch/Switch.styles.d.ts.map +1 -1
- package/dist/types/components/layout/CardGrid/CardGrid.d.ts +9 -7
- package/dist/types/components/layout/CardGrid/CardGrid.d.ts.map +1 -1
- package/dist/types/components/layout/Resizable/Resizable.d.ts.map +1 -1
- package/dist/types/components/layout/Resizable/Resizable.helpers.d.ts +21 -9
- package/dist/types/components/layout/Resizable/Resizable.helpers.d.ts.map +1 -1
- package/dist/types/components/layout/Resizable/Resizable.hooks.d.ts +13 -3
- package/dist/types/components/layout/Resizable/Resizable.hooks.d.ts.map +1 -1
- package/dist/types/components/layout/Resizable/Resizable.types.d.ts +10 -0
- package/dist/types/components/layout/Resizable/Resizable.types.d.ts.map +1 -1
- package/dist/types/components/layout/ScrollArea/ScrollArea.d.ts.map +1 -1
- package/dist/types/components/layout/ScrollArea/ScrollArea.helpers.d.ts +1 -1
- package/dist/types/components/layout/ScrollArea/ScrollArea.helpers.d.ts.map +1 -1
- package/dist/types/components/layout/ScrollArea/ScrollArea.types.d.ts +4 -1
- package/dist/types/components/layout/ScrollArea/ScrollArea.types.d.ts.map +1 -1
- package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.d.ts.map +1 -1
- package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.hooks.d.ts +3 -2
- package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.hooks.d.ts.map +1 -1
- package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.parts.d.ts +3 -2
- package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.parts.d.ts.map +1 -1
- package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.types.d.ts +9 -0
- package/dist/types/components/utility/InfiniteScroll/InfiniteScroll.types.d.ts.map +1 -1
- package/dist/types/components/utility/VirtualList/VirtualList.d.ts.map +1 -1
- package/dist/types/components/utility/VirtualList/VirtualList.hooks.d.ts +24 -28
- package/dist/types/components/utility/VirtualList/VirtualList.hooks.d.ts.map +1 -1
- package/dist/types/components/utility/VirtualList/VirtualList.types.d.ts +17 -0
- package/dist/types/components/utility/VirtualList/VirtualList.types.d.ts.map +1 -1
- package/dist/types-native/components/form/Switch/Switch.metrics.d.ts +13 -3
- package/dist/types-native/components/form/Switch/Switch.metrics.d.ts.map +1 -1
- package/dist/utility/InfiniteScroll.js +4 -3
- package/dist/utility/VirtualList.js +3 -2
- package/package.json +1 -1
- package/src/components/data-display/DataGrid/DataGrid.body.tsx +27 -7
- package/src/components/data-display/DataGrid/DataGrid.cells.tsx +33 -9
- package/src/components/data-display/DataGrid/DataGrid.model.ts +24 -11
- package/src/components/data-display/DataGrid/DataGrid.types.ts +12 -6
- package/src/components/data-display/DataViews/data-views-columns.ts +14 -3
- package/src/components/data-display/DataViews/data-views-grid-helpers.tsx +5 -3
- package/src/components/data-display/DataViews/data-views-layout-context.tsx +12 -9
- package/src/components/data-display/DataViews/data-views-overflow-costs.ts +32 -14
- package/src/components/data-display/DataViews/data-views-overflow.ts +40 -26
- package/src/components/data-display/LazyImage/LazyImage.tsx +5 -3
- package/src/components/data-display/LazyImage/LazyImage.types.ts +3 -1
- package/src/components/data-display/MapPreview/MapTiles.tsx +16 -9
- package/src/components/data-display/MapPreview/mapProjection.ts +10 -5
- package/src/components/data-display/Table/Table.helpers.ts +7 -1
- package/src/components/data-display/Table/Table.hooks.ts +16 -5
- package/src/components/data-display/Table/Table.types.ts +6 -2
- package/src/components/data-display/Table/TableParts.tsx +38 -42
- package/src/components/form/Calendar/Calendar.tsx +4 -2
- package/src/components/form/Calendar/CalendarDay.tsx +6 -3
- package/src/components/form/Calendar/CalendarMonth.tsx +6 -3
- package/src/components/form/Switch/Switch.metrics.ts +19 -5
- package/src/components/form/Switch/Switch.styles.ts +5 -3
- package/src/components/layout/CardGrid/CardGrid.tsx +37 -24
- package/src/components/layout/Resizable/Resizable.helpers.ts +43 -21
- package/src/components/layout/Resizable/Resizable.hooks.ts +17 -9
- package/src/components/layout/Resizable/Resizable.md +9 -5
- package/src/components/layout/Resizable/Resizable.tsx +20 -8
- package/src/components/layout/Resizable/Resizable.types.ts +10 -0
- package/src/components/layout/ScrollArea/ScrollArea.helpers.ts +0 -2
- package/src/components/layout/ScrollArea/ScrollArea.tsx +5 -3
- package/src/components/layout/ScrollArea/ScrollArea.types.ts +4 -1
- package/src/components/utility/InfiniteScroll/InfiniteScroll.hooks.ts +5 -4
- package/src/components/utility/InfiniteScroll/InfiniteScroll.parts.tsx +29 -12
- package/src/components/utility/InfiniteScroll/InfiniteScroll.tsx +11 -5
- package/src/components/utility/InfiniteScroll/InfiniteScroll.types.ts +10 -2
- package/src/components/utility/VirtualList/VirtualList.hooks.ts +101 -112
- package/src/components/utility/VirtualList/VirtualList.tsx +36 -65
- package/src/components/utility/VirtualList/VirtualList.types.ts +20 -3
- package/dist/chunk-2WFDHFK4.js.map +0 -1
- package/dist/chunk-3TDVGZZN.js.map +0 -1
- package/dist/chunk-AROBXRC5.js.map +0 -1
- package/dist/chunk-ATSHKSSD.js.map +0 -1
- package/dist/chunk-AUSUCZYR.js.map +0 -1
- package/dist/chunk-C66RGVAS.js.map +0 -1
- package/dist/chunk-D5SZXH7Q.js.map +0 -1
- package/dist/chunk-DF4K5XVW.js.map +0 -1
- package/dist/chunk-DLJGBJZW.js.map +0 -1
- package/dist/chunk-DZA7RSLX.js.map +0 -1
- package/dist/chunk-F42MJOHM.js.map +0 -1
- package/dist/chunk-GSFNH4C5.js.map +0 -1
- package/dist/chunk-HGMBY5LP.js.map +0 -1
- package/dist/chunk-HTZNB6IV.js.map +0 -1
- package/dist/chunk-IAGOUTI6.js.map +0 -1
- package/dist/chunk-J2DAQQQH.js.map +0 -1
- package/dist/chunk-MTFCPPZ5.js.map +0 -1
- package/dist/chunk-P6TNXBDA.js.map +0 -1
- package/dist/chunk-PMOEG36E.js.map +0 -1
- package/dist/chunk-PPRV4LTM.js.map +0 -1
- package/dist/chunk-PUBPZOQJ.js.map +0 -1
- package/dist/chunk-QF6LTUCE.js.map +0 -1
- package/dist/chunk-RHIDWUK7.js.map +0 -1
- package/dist/chunk-T7DE44SP.js.map +0 -1
- package/dist/chunk-TQ6FPOPD.js.map +0 -1
- package/dist/chunk-TUBCN4DJ.js.map +0 -1
- package/dist/chunk-ULTOQ6ZV.js.map +0 -1
- package/dist/chunk-UN5INW6K.js.map +0 -1
- package/dist/chunk-YU26GBNX.js.map +0 -1
- package/dist/chunk-ZAY6OA6F.js.map +0 -1
- /package/dist/{chunk-MR2HKBHS.js.map → chunk-27LOJVR3.js.map} +0 -0
- /package/dist/{chunk-S3D5VBHW.js.map → chunk-3YOXVNO4.js.map} +0 -0
- /package/dist/{chunk-CZIX4BW2.js.map → chunk-4ALF5PB5.js.map} +0 -0
- /package/dist/{chunk-XJPJ6ESI.js.map → chunk-4OAKGKK5.js.map} +0 -0
- /package/dist/{chunk-4CHROSWR.js.map → chunk-5ETBB2DG.js.map} +0 -0
- /package/dist/{chunk-46UPILLK.js.map → chunk-5NT2M2JI.js.map} +0 -0
- /package/dist/{chunk-H5BEWPEY.js.map → chunk-6N2EDWMG.js.map} +0 -0
- /package/dist/{chunk-GJQYM3PM.js.map → chunk-6PU3JYVY.js.map} +0 -0
- /package/dist/{chunk-Y7F5JBAT.js.map → chunk-DDRKYNPB.js.map} +0 -0
- /package/dist/{chunk-OS6KPL4D.js.map → chunk-EHYI2WCJ.js.map} +0 -0
- /package/dist/{chunk-NB3FGWU4.js.map → chunk-EQXIW5MQ.js.map} +0 -0
- /package/dist/{chunk-M2JTIH5M.js.map → chunk-F44R7US6.js.map} +0 -0
- /package/dist/{chunk-XJJXBUPN.js.map → chunk-FX26DAFF.js.map} +0 -0
- /package/dist/{chunk-R6SN73RX.js.map → chunk-GLHNMTP6.js.map} +0 -0
- /package/dist/{chunk-I4QA2F4L.js.map → chunk-HBRQPG7H.js.map} +0 -0
- /package/dist/{chunk-CNQUCNEA.js.map → chunk-I3F4C5SS.js.map} +0 -0
- /package/dist/{chunk-UFJYJHQI.js.map → chunk-J5VWGQSR.js.map} +0 -0
- /package/dist/{chunk-4JFL62K3.js.map → chunk-K7FSTB2K.js.map} +0 -0
- /package/dist/{chunk-FFCJ7NR2.js.map → chunk-KRQUPE4K.js.map} +0 -0
- /package/dist/{chunk-2OYFTSG4.js.map → chunk-KXLUMEDX.js.map} +0 -0
- /package/dist/{chunk-DVAAUWTC.js.map → chunk-LCHCE2G5.js.map} +0 -0
- /package/dist/{chunk-G4HBNILE.js.map → chunk-LEHMWJNZ.js.map} +0 -0
- /package/dist/{chunk-RZYSKQTS.js.map → chunk-PCBZYORN.js.map} +0 -0
- /package/dist/{chunk-5OBXEMQO.js.map → chunk-PRIBOWX4.js.map} +0 -0
- /package/dist/{chunk-PQECNGDE.js.map → chunk-QSRZOXQI.js.map} +0 -0
- /package/dist/{chunk-DCJSHYE5.js.map → chunk-RSDYS5B3.js.map} +0 -0
- /package/dist/{chunk-N5GVW6RO.js.map → chunk-S6IWKDWT.js.map} +0 -0
- /package/dist/{chunk-TKC6WHGB.js.map → chunk-SBIZXZPP.js.map} +0 -0
- /package/dist/{chunk-UEVHI62V.js.map → chunk-YCCY77W5.js.map} +0 -0
- /package/dist/{chunk-VZIB5W5L.js.map → chunk-ZGCPDA3F.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/layout/CardGrid/CardGrid.tsx"],"sourcesContent":["import { Children, type CSSProperties, type ReactNode, type Ref } from \"react\";\n\nimport { cn } from \"../../../utils/cn\";\n\n/**\n * How the grid turns surplus row space into layout:\n *\n * - `\"fixed\"` — every column is exactly `cardWidth` px; leftover row space is\n * spread as even gutters (`justify-content: space-around`). Cards never resize;\n * the column count changes with the viewport. This is the original tabwoah\n * card-grid behavior.\n * - `\"fluid\"` — every column is *at least* `cardWidth` px and stretches (`1fr`)\n * to fill the row, so cards grow to use the whole width. A lone card stays\n * left-aligned at a single track's width rather than stretching edge to edge.\n * - `\"scroll\"` — a single row that scrolls horizontally, with fluid-width cards\n * sized from the container so that exactly {@link SCROLL_VISIBLE_CARDS} cards\n * plus a {@link SCROLL_PEEK_WIDTH}px sliver of the next one fit on screen (up\n * to `maxCardWidth`, past which more cards simply fit). The sliver is the\n * point: it makes the rail visibly continue past the fold, so the row reads as\n * swipeable instead of as a finished pair of cards. Wrapping is off; the row\n * overflows on the x and scroll-snaps to each card's start so a swipe lands on\n * a clean card boundary.\n */\nexport type CardGridVariant = \"fixed\" | \"fluid\" | \"scroll\";\n\n/** The grid gap, in px — mirrors the `gap: 1rem` below, for the scroll math. */\nconst GRID_GAP = 16;\n\n/** `scroll`: how many WHOLE cards the rail commits to showing at once. */\nconst SCROLL_VISIBLE_CARDS = 2;\n\n/**\n * `scroll`: px of the next card left visible past the last whole one — the\n * \"there's more, swipe\" hint. Wide enough to read as a clipped card (rounded\n * edge + a slice of its photo) rather than as a rendering glitch.\n */\nconst SCROLL_PEEK_WIDTH = 28;\n\n/**\n * The `scroll` track width: the widest a card can be while the container still\n * shows `SCROLL_VISIBLE_CARDS` of them plus the peek — or, when there is nothing\n * to scroll to, while the cards still divide the row evenly. Capped at `max` so\n * a desktop-width rail packs in more cards instead of inflating them.\n *\n * The container (`100%`) has to cover, in the overflow case: N cards, the N gaps\n * that follow them (one between each pair, one before the peeked card), and the\n * peek. With no overflow there are only N-1 gaps and no peek.\n */\nfunction scrollTrackWidth(count: number, max: number): string {\n const tracks = Math.max(1, Math.min(count, SCROLL_VISIBLE_CARDS));\n const overflows = count > tracks;\n const gaps = overflows ? tracks : tracks - 1;\n const reserved = gaps * GRID_GAP + (overflows ? SCROLL_PEEK_WIDTH : 0);\n return `min(${max}px, calc((100% - ${reserved}px) / ${tracks}))`;\n}\n\ninterface CardGridProps {\n /**\n * `\"fixed\"`: the exact column width in px. `\"fluid\"`: the minimum column width\n * (columns grow from here). `\"scroll\"`: only seeds the default `maxCardWidth`\n * — a scroll track has no minimum, because a minimum is exactly what would\n * break the \"two cards plus a peek\" promise on a narrow phone.\n */\n cardWidth: number;\n /**\n * `\"scroll\"` only: the maximum fluid card width in px. Defaults to\n * `1.6 × cardWidth`.\n */\n maxCardWidth?: number;\n /** Layout behavior — see {@link CardGridVariant}. Defaults to `\"fixed\"`. */\n variant?: CardGridVariant;\n /** Additional classes appended to the default grid container */\n className?: string;\n /** `data-testid` for the grid container */\n gridTestId?: string;\n /** Ref forwarded to the grid container (used by `useMaxRowsHeight` clipping). */\n containerRef?: Ref<HTMLDivElement>;\n children: ReactNode;\n}\n\n/**\n * Shared grid container for card layouts. Renders responsive columns via CSS\n * grid, in one of three variants (see {@link CardGridVariant}).\n *\n * Ported from the tabwoah card grid (the `\"fixed\"` variant is verbatim). The one\n * adaptation: that app is Tailwind (`className=\"grid gap-4 pb-0.5\"`); this one\n * has no Tailwind, so those three utilities (display:grid, gap 1rem,\n * padding-bottom 2px) live in `style`.\n */\nexport function CardGrid({\n cardWidth,\n maxCardWidth,\n variant = \"fixed\",\n className,\n gridTestId,\n containerRef,\n children,\n}: CardGridProps) {\n const style: CSSProperties = {\n display: \"grid\",\n gap: \"1rem\",\n paddingBottom: \"2px\",\n };\n\n if (variant === \"scroll\") {\n const max = maxCardWidth ?? Math.round(cardWidth * 1.6);\n // One row, laid out as implicit columns, that scrolls sideways. Each column\n // is derived from the container so two whole cards plus a peek of the third\n // always fit (see `scrollTrackWidth`). Scroll-snap makes a swipe settle on a\n // card boundary instead of drifting mid-card.\n style.gridAutoFlow = \"column\";\n style.gridAutoColumns = scrollTrackWidth(Children.count(children), max);\n style.overflowX = \"auto\";\n style.overflowY = \"hidden\";\n style.scrollSnapType = \"x mandatory\";\n } else if (variant === \"fluid\") {\n style.gridTemplateColumns = `repeat(auto-fill, minmax(${cardWidth}px, 1fr))`;\n } else {\n style.gridTemplateColumns = `repeat(auto-fill, ${cardWidth}px)`;\n // `space-around` only distributes leftover width in the fixed variant; the\n // fluid variant consumes it via `1fr` and scroll overflows instead.\n style.justifyContent = \"space-around\";\n }\n\n // In the scroll variant each card is a snap target, so a swipe aligns to its\n // start. The snap-align sits on a wrapper (the grid item) so callers' children\n // stay untouched; the other variants render children directly.\n const content =\n variant === \"scroll\"\n ? Children.map(children, (child) => (\n <div style={{ scrollSnapAlign: \"start\" }}>{child}</div>\n ))\n : children;\n\n return (\n <div ref={containerRef} className={cn(className)} style={style} data-testid={gridTestId}>\n {content}\n </div>\n );\n}\n"],"mappings":";;;;;AAAA,SAAS,gBAA8D;AAkI7D;AAxGV,IAAM,WAAW;AAGjB,IAAM,uBAAuB;AAO7B,IAAM,oBAAoB;AAY1B,SAAS,iBAAiB,OAAe,KAAqB;AAC5D,QAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,oBAAoB,CAAC;AAChE,QAAM,YAAY,QAAQ;AAC1B,QAAM,OAAO,YAAY,SAAS,SAAS;AAC3C,QAAM,WAAW,OAAO,YAAY,YAAY,oBAAoB;AACpE,SAAO,OAAO,GAAG,oBAAoB,QAAQ,SAAS,MAAM;AAC9D;AAmCO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkB;AAChB,QAAM,QAAuB;AAAA,IAC3B,SAAS;AAAA,IACT,KAAK;AAAA,IACL,eAAe;AAAA,EACjB;AAEA,MAAI,YAAY,UAAU;AACxB,UAAM,MAAM,gBAAgB,KAAK,MAAM,YAAY,GAAG;AAKtD,UAAM,eAAe;AACrB,UAAM,kBAAkB,iBAAiB,SAAS,MAAM,QAAQ,GAAG,GAAG;AACtE,UAAM,YAAY;AAClB,UAAM,YAAY;AAClB,UAAM,iBAAiB;AAAA,EACzB,WAAW,YAAY,SAAS;AAC9B,UAAM,sBAAsB,4BAA4B,SAAS;AAAA,EACnE,OAAO;AACL,UAAM,sBAAsB,qBAAqB,SAAS;AAG1D,UAAM,iBAAiB;AAAA,EACzB;AAKA,QAAM,UACJ,YAAY,WACR,SAAS,IAAI,UAAU,CAAC,UACtB,oBAAC,SAAI,OAAO,EAAE,iBAAiB,QAAQ,GAAI,iBAAM,CAClD,IACD;AAEN,SACE,oBAAC,SAAI,KAAK,cAAc,WAAW,GAAG,SAAS,GAAG,OAAc,eAAa,YAC1E,mBACH;AAEJ;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/layout/Resizable/Resizable.helpers.ts"],"sourcesContent":["import type { Theme } from '@mui/material/styles/index.js';\n\nimport type { ResizableProps, ResizableVariant, ResizeHandle } from './Resizable.types';\n\nexport interface Axis {\n min: number;\n max: number;\n}\n\nexport interface Bounds {\n width: Axis;\n height: Axis;\n}\n\nexport const defaultHandles = (variant: ResizableVariant): ResizeHandle[] => {\n switch (variant) {\n case 'horizontal':\n return ['right'];\n case 'vertical':\n return ['bottom'];\n default:\n return ['right', 'bottom', 'bottomRight'];\n }\n};\n\nconst HORIZONTAL_GROW: readonly ResizeHandle[] = ['right', 'topRight', 'bottomRight'];\nconst HORIZONTAL_SHRINK: readonly ResizeHandle[] = ['left', 'topLeft', 'bottomLeft'];\nconst VERTICAL_GROW: readonly ResizeHandle[] = ['bottom', 'bottomLeft', 'bottomRight'];\nconst VERTICAL_SHRINK: readonly ResizeHandle[] = ['top', 'topLeft', 'topRight'];\n\nconst clamp = (value: number, { min, max }: Axis): number =>\n Math.max(min, Math.min(max, value));\n\n/**\n * A handle on the right or bottom edge grows the box by the drag distance; one on\n * the left or top shrinks it by the same amount, because the opposite edge is\n * what stays put. A handle on neither edge of this axis leaves it alone.\n */\nconst alongAxis = (\n handle: ResizeHandle,\n grow: readonly ResizeHandle[],\n shrink: readonly ResizeHandle[],\n start: number,\n delta: number,\n bounds: Axis,\n): number => {\n if (grow.includes(handle)) return clamp(start + delta, bounds);\n if (shrink.includes(handle)) return clamp(start - delta, bounds);\n return start;\n};\n\nexport const resizedTo = (\n handle: ResizeHandle,\n delta: { x: number; y: number },\n start: { width: number; height: number },\n bounds: Bounds,\n) => ({\n width: alongAxis(handle, HORIZONTAL_GROW, HORIZONTAL_SHRINK, start.width, delta.x, bounds.width),\n height: alongAxis(\n handle,\n VERTICAL_GROW,\n VERTICAL_SHRINK,\n start.height,\n delta.y,\n bounds.height,\n ),\n});\n\nexport const handleStyle = (theme: Theme, handle: ResizeHandle, active: boolean) => {\n const baseStyle = {\n position: 'absolute' as const,\n backgroundColor: theme.palette.primary.main,\n opacity: 0,\n transition: theme.transitions.create('opacity'),\n '&:hover': {\n opacity: 0.3,\n },\n ...(active ? { opacity: 0.5 } : {}),\n };\n\n switch (handle) {\n case 'right':\n return { ...baseStyle, top: 0, right: -2, width: 4, height: '100%', cursor: 'ew-resize' };\n case 'bottom':\n return { ...baseStyle, bottom: -2, left: 0, width: '100%', height: 4, cursor: 'ns-resize' };\n case 'bottomRight':\n return {\n ...baseStyle,\n bottom: -2,\n right: -2,\n width: 8,\n height: 8,\n cursor: 'nw-resize',\n borderRadius: '50%',\n };\n default:\n return baseStyle;\n }\n};\n\ntype ResizableDefaultedKeys =\n | 'variant'\n | 'width'\n | 'height'\n | 'minWidth'\n | 'maxWidth'\n | 'minHeight'\n | 'maxHeight'\n | 'disabled';\n\ntype ResolvedResizableProps = ResizableProps &\n Required<Pick<ResizableProps, ResizableDefaultedKeys>>;\n\nconst RESIZABLE_DEFAULTS: Pick<ResizableProps, ResizableDefaultedKeys> = {\n variant: 'both',\n width: 200,\n height: 200,\n minWidth: 50,\n maxWidth: 1000,\n minHeight: 50,\n maxHeight: 1000,\n disabled: false,\n};\n\n// Strips explicitly-undefined props before the merge, so `minWidth={undefined}`\n// still falls back to the default exactly as a destructuring default would.\nconst definedProps = (props: ResizableProps): Partial<ResizableProps> =>\n Object.fromEntries(\n Object.entries(props).filter(([, value]) => value !== undefined),\n ) as Partial<ResizableProps>;\n\nexport const resolveResizableProps = (props: ResizableProps): ResolvedResizableProps =>\n ({ ...RESIZABLE_DEFAULTS, ...definedProps(props) }) as ResolvedResizableProps;\n"],"mappings":";AAcO,IAAM,iBAAiB,CAAC,YAA8C;AAC3E,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,aAAO,CAAC,OAAO;AAAA,IACjB,KAAK;AACH,aAAO,CAAC,QAAQ;AAAA,IAClB;AACE,aAAO,CAAC,SAAS,UAAU,aAAa;AAAA,EAC5C;AACF;AAEA,IAAM,kBAA2C,CAAC,SAAS,YAAY,aAAa;AACpF,IAAM,oBAA6C,CAAC,QAAQ,WAAW,YAAY;AACnF,IAAM,gBAAyC,CAAC,UAAU,cAAc,aAAa;AACrF,IAAM,kBAA2C,CAAC,OAAO,WAAW,UAAU;AAE9E,IAAM,QAAQ,CAAC,OAAe,EAAE,KAAK,IAAI,MACvC,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAOpC,IAAM,YAAY,CAChB,QACA,MACA,QACA,OACA,OACA,WACW;AACX,MAAI,KAAK,SAAS,MAAM,EAAG,QAAO,MAAM,QAAQ,OAAO,MAAM;AAC7D,MAAI,OAAO,SAAS,MAAM,EAAG,QAAO,MAAM,QAAQ,OAAO,MAAM;AAC/D,SAAO;AACT;AAEO,IAAM,YAAY,CACvB,QACA,OACA,OACA,YACI;AAAA,EACJ,OAAO,UAAU,QAAQ,iBAAiB,mBAAmB,MAAM,OAAO,MAAM,GAAG,OAAO,KAAK;AAAA,EAC/F,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AACF;AAEO,IAAM,cAAc,CAAC,OAAc,QAAsB,WAAoB;AAClF,QAAM,YAAY;AAAA,IAChB,UAAU;AAAA,IACV,iBAAiB,MAAM,QAAQ,QAAQ;AAAA,IACvC,SAAS;AAAA,IACT,YAAY,MAAM,YAAY,OAAO,SAAS;AAAA,IAC9C,WAAW;AAAA,MACT,SAAS;AAAA,IACX;AAAA,IACA,GAAI,SAAS,EAAE,SAAS,IAAI,IAAI,CAAC;AAAA,EACnC;AAEA,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,EAAE,GAAG,WAAW,KAAK,GAAG,OAAO,IAAI,OAAO,GAAG,QAAQ,QAAQ,QAAQ,YAAY;AAAA,IAC1F,KAAK;AACH,aAAO,EAAE,GAAG,WAAW,QAAQ,IAAI,MAAM,GAAG,OAAO,QAAQ,QAAQ,GAAG,QAAQ,YAAY;AAAA,IAC5F,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,cAAc;AAAA,MAChB;AAAA,IACF;AACE,aAAO;AAAA,EACX;AACF;AAeA,IAAM,qBAAmE;AAAA,EACvE,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,UAAU;AAAA,EACV,WAAW;AAAA,EACX,WAAW;AAAA,EACX,UAAU;AACZ;AAIA,IAAM,eAAe,CAAC,UACpB,OAAO;AAAA,EACL,OAAO,QAAQ,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,MAAS;AACjE;AAEK,IAAM,wBAAwB,CAAC,WACnC,EAAE,GAAG,oBAAoB,GAAG,aAAa,KAAK,EAAE;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/DataGrid/DataGrid.cells.tsx"],"sourcesContent":["/**\n * The DataGrid's cell and row renderers.\n *\n * Components rather than closures over the grid's scope: as inline `render*`\n * functions they could reach every piece of the component's state, which is how\n * the body grew past 700 lines. Each one now states exactly what it needs.\n */\nimport ArrowDownward from '@mui/icons-material/ArrowDownward';\nimport ArrowUpward from '@mui/icons-material/ArrowUpward';\nimport ExpandLess from '@mui/icons-material/ExpandLess';\nimport ExpandMore from '@mui/icons-material/ExpandMore';\nimport UnfoldMore from '@mui/icons-material/UnfoldMore';\nimport Button from '@mui/material/Button/index.js';\nimport Checkbox from '@mui/material/Checkbox/index.js';\nimport IconButton from '@mui/material/IconButton/index.js';\nimport TableCell from '@mui/material/TableCell/index.js';\nimport TableRow from '@mui/material/TableRow/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport { useTheme } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport { cellValue } from './DataGrid.rows';\nimport type { DataGridModel } from './DataGrid.model';\nimport type { DataGridProps, GridColumn, GridSort } from './DataGrid.types';\n\n/** The glyph for a column's current sort state — unsorted included. */\nfunction SortIcon({ dir }: { dir: GridSort['dir'] | undefined }): React.JSX.Element {\n if (!dir) return <UnfoldMore fontSize=\"small\" sx={{ opacity: 0.5 }} />;\n return dir === 'asc' ? <ArrowUpward fontSize=\"small\" /> : <ArrowDownward fontSize=\"small\" />;\n}\n\n/** `aria-sort`'s three values, which are not the same words as `SortDirection`. */\nfunction ariaSort(dir: GridSort['dir'] | undefined): 'none' | 'ascending' | 'descending' {\n if (!dir) return 'none';\n return dir === 'asc' ? 'ascending' : 'descending';\n}\n\nexport interface HeaderCellProps<T extends Record<string, unknown>> {\n column: GridColumn<T>;\n sort: GridSort | undefined;\n sortable: boolean;\n stickyHeader: boolean;\n headerHeight: number;\n onSort: (columnId: string) => void;\n}\n\nexport function HeaderCell<T extends Record<string, unknown>>({\n column,\n sort,\n sortable,\n stickyHeader,\n headerHeight,\n onSort,\n}: HeaderCellProps<T>): React.JSX.Element {\n const theme = useTheme();\n const content = column.headerCell ? column.headerCell(column) : column.header;\n return (\n <TableCell\n data-slot=\"header-cell\"\n data-sort={sort?.dir ?? 'none'}\n sx={{\n position: stickyHeader ? 'sticky' : 'static',\n top: 0,\n zIndex: 1,\n backgroundColor: theme.palette.background.paper,\n borderBottom: `1px solid ${theme.palette.divider}`,\n height: headerHeight,\n minWidth: column.minWidth,\n maxWidth: column.maxWidth,\n width: column.width,\n }}\n role=\"columnheader\"\n aria-sort={ariaSort(sort?.dir)}\n >\n {sortable ? (\n <Button\n onClick={() => onSort(column.id)}\n sx={{\n justifyContent: 'flex-start',\n textTransform: 'none',\n fontWeight: 500,\n color: 'inherit',\n p: 0,\n minWidth: 0,\n '&:hover': { backgroundColor: 'transparent', opacity: 0.8 },\n }}\n endIcon={<SortIcon dir={sort?.dir} />}\n aria-label={column.ariaLabel ?? `Sort by ${String(column.header)}`}\n >\n {content}\n </Button>\n ) : (\n <Typography variant=\"subtitle2\" fontWeight={500}>\n {content}\n </Typography>\n )}\n </TableCell>\n );\n}\n\nexport interface DataCellProps<T extends Record<string, unknown>> {\n row: T;\n rowIndex: number;\n rowId: string | number;\n column: GridColumn<T>;\n rowHeight: number;\n editing: NonNullable<DataGridProps<T>['editing']>;\n model: Pick<DataGridModel<T>, 'editingCell' | 'setEditingCell'>;\n}\n\nexport function DataCell<T extends Record<string, unknown>>({\n row,\n rowIndex,\n rowId,\n column,\n rowHeight,\n editing,\n model,\n}: DataCellProps<T>): React.JSX.Element {\n const value = cellValue(row, column);\n const isEditing =\n model.editingCell?.rowId === rowId && model.editingCell?.colId === column.id;\n const content = column.cell\n ? column.cell({ value, row, rowIndex, col: column })\n : String(value ?? '');\n return (\n <TableCell\n data-slot=\"cell\"\n data-col-id={column.id}\n data-editing={isEditing}\n sx={{\n minWidth: column.minWidth,\n maxWidth: column.maxWidth,\n width: column.width,\n height: rowHeight,\n }}\n role=\"gridcell\"\n tabIndex={-1}\n >\n {isEditing && column.editor\n ? column.editor({\n value,\n row,\n onChange: () => undefined,\n commit: () => {\n editing.onEditCommit?.({ rowId, colId: column.id, value, row });\n model.setEditingCell(null);\n },\n cancel: () => model.setEditingCell(null),\n })\n : content}\n </TableCell>\n );\n}\n\nexport interface GridRowProps<T extends Record<string, unknown>> {\n row: T;\n index: number;\n rowId: string | number;\n isSelected: boolean;\n isExpanded: boolean;\n totalColumns: number;\n model: DataGridModel<T>;\n props: DataGridProps<T>;\n}\n\n/** The leading checkbox / chevron cells, which exist only for enabled features. */\nfunction RowControls<T extends Record<string, unknown>>({\n row,\n index,\n rowId,\n isSelected,\n isExpanded,\n model,\n props,\n}: GridRowProps<T>): React.JSX.Element {\n const { selection = { mode: 'none' }, expansion } = props;\n return (\n <>\n {selection.mode !== 'none' && (\n <TableCell padding=\"checkbox\">\n <Checkbox\n checked={isSelected}\n onChange={(event) => model.onToggleRow(rowId, event.target.checked)}\n inputProps={{ 'aria-label': `Select row ${index + 1}` }}\n />\n </TableCell>\n )}\n {expansion && (\n <TableCell padding=\"checkbox\">\n {expansion.isRowExpandable?.(row) === false ? null : (\n <IconButton\n size=\"small\"\n // Stopped so a host that opens the record on a row click does not\n // ALSO open it here: the chevron is its own control.\n onClick={(event) => {\n event.stopPropagation();\n model.onToggleExpansion(rowId);\n }}\n aria-expanded={isExpanded}\n aria-label={\n isExpanded\n ? (expansion.collapseLabel ?? 'Collapse row')\n : (expansion.expandLabel ?? 'Expand row')\n }\n data-slot=\"expand-toggle\"\n >\n {isExpanded ? <ExpandLess /> : <ExpandMore />}\n </IconButton>\n )}\n </TableCell>\n )}\n </>\n );\n}\n\nexport function GridRow<T extends Record<string, unknown>>(\n rowProps: GridRowProps<T>,\n): React.JSX.Element {\n const { row, index, rowId, isSelected, isExpanded, totalColumns, model, props } = rowProps;\n const theme = useTheme();\n const expansion = props.expansion;\n return (\n <React.Fragment>\n <TableRow\n data-slot=\"row\"\n data-selected={isSelected}\n data-expanded={isExpanded}\n sx={{\n '&:hover': { backgroundColor: theme.palette.action.hover },\n ...(isSelected && { backgroundColor: theme.palette.action.selected }),\n height: model.rowHeight,\n }}\n role=\"row\"\n aria-selected={isSelected}\n >\n <RowControls {...rowProps} />\n {model.visibleColumns.map((column) => (\n <DataCell\n key={column.id}\n row={row}\n rowIndex={index}\n rowId={rowId}\n column={column}\n rowHeight={model.rowHeight}\n editing={props.editing ?? { mode: 'none' }}\n model={model}\n />\n ))}\n </TableRow>\n {expansion && isExpanded && expansion.isRowExpandable?.(row) !== false && (\n <TableRow data-slot=\"row-detail\">\n <TableCell colSpan={totalColumns}>{expansion.render(row, index)}</TableCell>\n </TableRow>\n )}\n </React.Fragment>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/utility/InfiniteScroll/InfiniteScroll.parts.tsx"],"sourcesContent":["import Alert from '@mui/material/Alert/index.js';\nimport Box from '@mui/material/Box/index.js';\nimport CircularProgress from '@mui/material/CircularProgress/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport React from 'react';\n\nimport type { InfiniteScrollProps } from './InfiniteScroll.types';\n\ntype Variant = NonNullable<InfiniteScrollProps['variant']>;\n\nconst CENTERED = {\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n p: 2,\n} as const;\n\nexport const DefaultLoader: React.FC<{ loadingText: string }> = ({ loadingText }) => (\n <Box sx={CENTERED}>\n <CircularProgress size={24} />\n <Typography variant=\"body2\" sx={{ ml: 1 }}>\n {loadingText}\n </Typography>\n </Box>\n);\n\nexport const DefaultEndMessage: React.FC<{ endText: string }> = ({ endText }) => (\n <Box sx={CENTERED}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {endText}\n </Typography>\n </Box>\n);\n\nexport const DefaultError: React.FC<{ error: Error }> = ({ error }) => (\n <Alert severity=\"error\" sx={{ m: 2 }}>\n {error.message || 'An error occurred while loading more items'}\n </Alert>\n);\n\n/**\n * `horizontal` scrolls along a row; `reverse` stacks bottom-up, for a chat log\n * that loads older messages as you scroll away from the newest.\n */\nexport const containerStyles = (variant: Variant, width?: number | string) => {\n const horizontal = variant === 'horizontal';\n const base = {\n width: horizontal ? width || '100%' : '100%',\n height: horizontal ? '100%' : 'auto',\n overflowX: horizontal ? 'auto' : 'hidden',\n overflowY: horizontal ? 'hidden' : 'visible',\n display: 'flex',\n flexDirection: horizontal ? 'row' : 'column',\n };\n\n return variant === 'reverse' ? { ...base, flexDirection: 'column-reverse' } : base;\n};\n"],"mappings":";AAAA,OAAO,WAAW;AAClB,OAAO,SAAS;AAChB,OAAO,sBAAsB;AAC7B,OAAO,gBAAgB;AAerB,SACE,KADF;AARF,IAAM,WAAW;AAAA,EACf,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,GAAG;AACL;AAEO,IAAM,gBAAmD,CAAC,EAAE,YAAY,MAC7E,qBAAC,OAAI,IAAI,UACP;AAAA,sBAAC,oBAAiB,MAAM,IAAI;AAAA,EAC5B,oBAAC,cAAW,SAAQ,SAAQ,IAAI,EAAE,IAAI,EAAE,GACrC,uBACH;AAAA,GACF;AAGK,IAAM,oBAAmD,CAAC,EAAE,QAAQ,MACzE,oBAAC,OAAI,IAAI,UACP,8BAAC,cAAW,SAAQ,SAAQ,OAAM,kBAC/B,mBACH,GACF;AAGK,IAAM,eAA2C,CAAC,EAAE,MAAM,MAC/D,oBAAC,SAAM,UAAS,SAAQ,IAAI,EAAE,GAAG,EAAE,GAChC,gBAAM,WAAW,8CACpB;AAOK,IAAM,kBAAkB,CAAC,SAAkB,UAA4B;AAC5E,QAAM,aAAa,YAAY;AAC/B,QAAM,OAAO;AAAA,IACX,OAAO,aAAa,SAAS,SAAS;AAAA,IACtC,QAAQ,aAAa,SAAS;AAAA,IAC9B,WAAW,aAAa,SAAS;AAAA,IACjC,WAAW,aAAa,WAAW;AAAA,IACnC,SAAS;AAAA,IACT,eAAe,aAAa,QAAQ;AAAA,EACtC;AAEA,SAAO,YAAY,YAAY,EAAE,GAAG,MAAM,eAAe,iBAAiB,IAAI;AAChF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/form/Switch/Switch.styles.ts"],"sourcesContent":["import { alpha } from '@mui/material/styles/index.js';\nimport type { CSSObject, Theme } from '@mui/material/styles/index.js';\n\nimport {\n bounceAnimation,\n glowAnimation,\n pulseAnimation,\n rippleAnimation,\n shimmerAnimation,\n spinAnimation,\n} from './Switch.animations';\nimport {\n DISABLED,\n IOS_BASE_OFFSET,\n IOS_THUMB_SHADOW,\n IOS_TRAVEL_INSET,\n SWITCH_GLASS,\n SWITCH_GLOW,\n NEUTRAL_CONTRAST,\n SWITCH_FOCUS_RING,\n SWITCH_GRADIENT,\n SWITCH_HOVER,\n SWITCH_PULSE,\n SWITCH_RIPPLE,\n SWITCH_SPINNER,\n SWITCH_TRANSITION,\n RESTING_THUMB,\n THUMB_ELEVATION,\n THUMB_RADIUS,\n TRACK_LABEL,\n TRACK_RADIUS,\n geometryOf,\n iosTrackShadow,\n lookOf,\n seconds,\n showsTrackLabels,\n trackColor,\n type SwitchGeometry,\n type SwitchLook,\n} from './Switch.metrics';\nimport type { SwitchVariant } from './Switch.base';\n\nimport { absoluteInk, controlNeutral, neutralTones } from '../../../tokens/ink';\nimport { rem } from '../../../tokens/relative';\nimport { inkOver } from '../../../tokens/theme';\nimport type { ColorValue, SizeValue } from '../../../tokens/vocabulary';\n\n// Every number below comes from `./Switch.metrics`, which the native renderer\n// reads too — see its header. The palette and the shadows stay on the MUI\n// theme so a host that re-themes either keeps moving the web.\ninterface ColorPalette {\n main: string;\n dark?: string;\n light?: string;\n contrastText?: string;\n}\n\n/** `neutral` is not a MUI palette entry, so it is the controls' neutral tone. */\nconst neutralPalette = (theme: Theme): ColorPalette => controlNeutral(theme);\n\n/**\n * Resolves a colour name to a full palette, filling any step the theme leaves\n * out from `main` and then from the primary palette. `danger` is this\n * component's name for the error palette; the rest map straight through.\n */\nconst getColorFromTheme = (theme: Theme, color: string): ColorPalette => {\n if (color === 'neutral') {\n return neutralPalette(theme);\n }\n\n const colorMap: Record<string, ColorPalette | undefined> = {\n primary: theme.palette.primary,\n secondary: theme.palette.secondary,\n success: theme.palette.success,\n warning: theme.palette.warning,\n info: theme.palette.info,\n danger: theme.palette.error,\n };\n const palette = colorMap[color] ?? theme.palette.primary;\n const { primary } = theme.palette;\n\n return {\n main: palette.main || primary.main,\n dark: palette.dark || palette.main || primary.dark,\n light: palette.light || palette.main || primary.light,\n contrastText: palette.contrastText || NEUTRAL_CONTRAST,\n };\n};\n\nexport interface SwitchFlags {\n customVariant?: SwitchVariant;\n customColor?: ColorValue;\n customSize?: SizeValue;\n glow?: boolean;\n glass?: boolean;\n gradient?: boolean;\n trackWidth?: number;\n trackHeight?: number;\n onText?: string;\n offText?: string;\n loading?: boolean;\n ripple?: boolean;\n pulse?: boolean;\n}\n\n/** A metrics radius on the web: its px through the type scale, a percentage as-is. */\nconst lengthOrPercent = (theme: Theme, value: number | string): string =>\n typeof value === 'number' ? rem(theme, value) : value;\n\nconst thumbShadow = (theme: Theme, look: SwitchLook): string =>\n look === 'ios' ? IOS_THUMB_SHADOW : (theme.shadows[THUMB_ELEVATION[look]] ?? 'none');\n\n/** The ripple that expands from the thumb on hover. */\nconst rippleOverlay = (palette: ColorPalette): CSSObject => ({\n content: '\"\"',\n position: 'absolute',\n top: '50%',\n left: '50%',\n width: '100%',\n height: '100%',\n borderRadius: '50%',\n background: alpha(palette.main, SWITCH_RIPPLE.alpha),\n animation: `${rippleAnimation} ${seconds(SWITCH_RIPPLE.ms)} ease-out`,\n transform: 'translate(-50%, -50%)',\n pointerEvents: 'none',\n});\n\n/**\n * The ink on the CHECKED track — the thumb, the `on` wording and any on-icon\n * (FUT-1924).\n *\n * All three stated `#fff`, and the checked track is `palette.main`: the one\n * surface in this component the TENANT picks. A store with a pale brand got a\n * white thumb on a pale green bar, which does not read as a knob at all — the\n * switch looks OFF while it is on, so this is a state a user misreads rather\n * than a colour they dislike.\n *\n * The `gradient` flag paints the track `light → main → dark`, so the fills the\n * thumb travels over are handed over together and {@link inkOver} takes the\n * worst of them.\n *\n * The RESTING track is not here on purpose: it is `theme.palette.action.disabled`\n * washed over the page, which no tenant chooses, and a white thumb on it is the\n * conventional look in both modes.\n */\nconst checkedInk = (flags: SwitchFlags, palette: ColorPalette): string => {\n const fills = flags.gradient\n ? [palette.light || palette.main, palette.main, palette.dark || palette.main]\n : [palette.main];\n\n return inkOver(fills, palette.contrastText || NEUTRAL_CONTRAST);\n};\n\n/** The checked track: the filled bar behind the thumb once the switch is on. */\nconst checkedTrack = (theme: Theme, flags: SwitchFlags, palette: ColorPalette): CSSObject => ({\n backgroundColor: palette.main,\n opacity: 1,\n border: 0,\n position: 'relative',\n overflow: 'hidden',\n ...(flags.glow && {\n animation: `${glowAnimation(theme)} ${seconds(SWITCH_GLOW.ms)} ease-in-out infinite`,\n boxShadow: `0 0 ${rem(theme, SWITCH_GLOW.blur)} ${alpha(palette.main, SWITCH_GLOW.alpha)}, inset 0 0 ${rem(theme, SWITCH_GLOW.insetBlur)} ${alpha(palette.main, SWITCH_GLOW.insetAlpha)}`,\n }),\n ...(flags.gradient && {\n background: `linear-gradient(${SWITCH_GRADIENT.checked.angleDeg}deg, ${palette.light || palette.main} ${SWITCH_GRADIENT.checked.stops[0]}%, ${palette.main} ${SWITCH_GRADIENT.checked.stops[1]}%, ${palette.dark || palette.main} ${SWITCH_GRADIENT.checked.stops[2]}%)`,\n backgroundSize: '200% 100%',\n animation: `${shimmerAnimation} ${seconds(SWITCH_GRADIENT.shimmerMs)} ease infinite`,\n }),\n});\n\nconst switchBaseSx = (\n theme: Theme,\n flags: SwitchFlags,\n palette: ColorPalette,\n geometry: SwitchGeometry,\n look: SwitchLook,\n): CSSObject => {\n const { width, thumbSize, padding } = geometry;\n const isIos = look === 'ios';\n\n return {\n padding: rem(theme, padding),\n margin: 0,\n transitionDuration: `${SWITCH_TRANSITION.ms}ms`,\n transitionTimingFunction: SWITCH_TRANSITION.easing,\n ...(isIos && { transform: `translateX(${rem(theme, IOS_BASE_OFFSET)})` }),\n '&:hover': {\n '& .MuiSwitch-thumb': {\n transform: flags.loading ? 'none' : `scale(${SWITCH_HOVER.thumbScale})`,\n boxShadow: `${theme.shadows[SWITCH_HOVER.elevation]}, 0 0 ${rem(theme, SWITCH_HOVER.blur)} ${alpha(palette.main, SWITCH_HOVER.alpha)}`,\n },\n ...(flags.ripple && { '&::after': rippleOverlay(palette) }),\n },\n '&.Mui-checked': {\n // The thumb travels the track minus its own width and both paddings; the\n // iOS look insets differently, so it gets its own distance.\n transform: `translateX(${rem(theme, width - thumbSize - padding * 2)})`,\n color: checkedInk(flags, palette),\n '& .MuiSwitch-thumb': {\n animation: flags.loading ? 'none' : `${bounceAnimation} ${seconds(SWITCH_TRANSITION.ms)} ease-out`,\n /*\n GLASS KEEPS ITS WASH AND GAINS AN OUTLINE (FUT-2067).\n\n It used to keep the wash and nothing else, on the argument that a\n translucent thumb MEANS to show the track through itself, so painting\n it opaque would be repainting the variant rather than fixing it. The\n first half of that is still true and this still does not touch the\n fill. The second half was doing more work than the number supports:\n `SWITCH_GLASS.thumbAlpha` is **0.9**, so nine parts in ten of the knob\n are `background.paper` and one part is the track. On a pale brand that\n composites to within about 1.1:1 of the bar it is sitting on — the\n same \"reads as OFF while it is on\" state FUT-1924 exists for, in the\n one variant whose own argument points AT the tenant-controlled\n surface.\n\n So the separation moves to the EDGE, which is the thing a glass\n surface is allowed to have. The colour is {@link checkedInk} — the\n same derivation the opaque thumb gets, so there is one rule for \"what\n reads on this track\" rather than two — at full strength rather than\n the `divider` hairline at `borderAlpha` 0.2 the resting thumb wears,\n which on a pale track is not an outline at all.\n\n Checked only. The resting track is `action.disabled` washed over the\n page, which no tenant chooses, so the quiet hairline stays right\n there — the same split {@link checkedInk}'s own docblock makes.\n */\n ...(flags.glass\n ? { borderColor: checkedInk(flags, palette) }\n : { backgroundColor: checkedInk(flags, palette) }),\n },\n '& + .MuiSwitch-track': checkedTrack(theme, flags, palette),\n '&.Mui-disabled + .MuiSwitch-track': { opacity: DISABLED.checkedTrackOpacity },\n ...(isIos && { transform: `translateX(${rem(theme, width - thumbSize - IOS_TRAVEL_INSET)})` }),\n },\n '&.Mui-focusVisible .MuiSwitch-thumb': {\n color: palette.main,\n border: `${rem(theme, SWITCH_FOCUS_RING.width)} solid ${alpha(palette.main, SWITCH_FOCUS_RING.alpha)}`,\n },\n '&.Mui-disabled .MuiSwitch-thumb': { color: neutralTones(theme).surface },\n '&.Mui-disabled + .MuiSwitch-track': { opacity: DISABLED.trackOpacity },\n };\n};\n\nconst thumbSx = (\n theme: Theme,\n flags: SwitchFlags,\n palette: ColorPalette,\n thumbSize: number,\n look: SwitchLook,\n): CSSObject => ({\n width: rem(theme, thumbSize),\n height: rem(theme, thumbSize),\n borderRadius: lengthOrPercent(theme, THUMB_RADIUS[look](thumbSize)),\n // `.Mui-checked` above replaces this for the brand-filled track; see\n // {@link RESTING_THUMB} for why the resting one stays white.\n backgroundColor: RESTING_THUMB,\n boxShadow: thumbShadow(theme, look),\n transition: `all ${seconds(SWITCH_TRANSITION.ms)} ${SWITCH_TRANSITION.easing}`,\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n ...(flags.glass && {\n backgroundColor: alpha(theme.palette.background.paper, SWITCH_GLASS.thumbAlpha),\n backdropFilter: `blur(${rem(theme, SWITCH_GLASS.thumbBlur)})`,\n border: `1px solid ${alpha(theme.palette.divider, SWITCH_GLASS.borderAlpha)}`,\n }),\n ...(flags.pulse && { animation: `${pulseAnimation} ${seconds(SWITCH_PULSE.ms)} ease-in-out infinite` }),\n ...(flags.loading && {\n // A spinner drawn inside the thumb rather than over the whole control.\n '&::after': {\n content: '\"\"',\n position: 'absolute',\n width: rem(theme, thumbSize * SWITCH_SPINNER.sizeRatio),\n height: rem(theme, thumbSize * SWITCH_SPINNER.sizeRatio),\n border: `${rem(theme, SWITCH_SPINNER.borderWidth)} solid ${palette.main}`,\n borderTop: `${rem(theme, SWITCH_SPINNER.borderWidth)} solid transparent`,\n borderRadius: '50%',\n animation: `${spinAnimation} ${seconds(SWITCH_SPINNER.ms)} linear infinite`,\n },\n }),\n ...(look === 'material' && {\n '&::before': {\n content: '\"\"',\n position: 'absolute',\n width: '100%',\n height: '100%',\n borderRadius: 'inherit',\n backgroundColor: palette.main,\n opacity: 0,\n transform: 'scale(0)',\n transition: 'all 0.3s ease',\n },\n }),\n});\n\n/** The on/off wording the `label` variant prints inside the track. */\nconst trackLabels = (\n theme: Theme,\n flags: SwitchFlags,\n palette: ColorPalette,\n onText?: string,\n offText?: string,\n): CSSObject => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingLeft: theme.spacing(TRACK_LABEL.insetUnits),\n paddingRight: theme.spacing(TRACK_LABEL.insetUnits),\n fontSize: rem(theme, TRACK_LABEL.fontSize),\n fontWeight: TRACK_LABEL.fontWeight,\n color: theme.palette.text.secondary,\n '&::before, &::after': {\n content: '\"\"',\n position: 'absolute',\n fontSize: rem(theme, TRACK_LABEL.fontSize),\n fontWeight: TRACK_LABEL.fontWeight,\n top: '50%',\n transform: 'translateY(-50%)',\n zIndex: 1,\n },\n ...(onText && {\n '&::before': {\n content: `\"${onText}\"`,\n left: theme.spacing(TRACK_LABEL.insetUnits),\n // The `on` word sits at the end the thumb travels TO, which is the\n // filled half of the track once checked.\n color: checkedInk(flags, palette),\n },\n }),\n ...(offText && {\n '&::after': {\n content: `\"${offText}\"`,\n right: theme.spacing(TRACK_LABEL.insetUnits),\n color: theme.palette.text.secondary,\n },\n }),\n});\n\nconst trackSx = (\n theme: Theme,\n flags: SwitchFlags,\n palette: ColorPalette,\n height: number,\n look: SwitchLook,\n): CSSObject => {\n const { glass, gradient, onText, offText, customVariant } = flags;\n\n return {\n borderRadius: rem(theme, TRACK_RADIUS[look](height)),\n backgroundColor: trackColor(\n { black: absoluteInk(theme).black, disabled: theme.palette.action.disabled },\n look,\n ),\n opacity: 1,\n transition: `all ${seconds(SWITCH_TRANSITION.ms)} ${SWITCH_TRANSITION.easing}`,\n position: 'relative',\n boxShadow: look === 'ios' ? iosTrackShadow() : 'none',\n ...(glass && {\n backgroundColor: alpha(theme.palette.background.paper, SWITCH_GLASS.trackAlpha),\n backdropFilter: `blur(${rem(theme, SWITCH_GLASS.trackBlur)})`,\n border: `1px solid ${alpha(theme.palette.divider, SWITCH_GLASS.borderAlpha)}`,\n }),\n ...(gradient &&\n !glass && {\n background: `linear-gradient(${SWITCH_GRADIENT.resting.angleDeg}deg, ${alpha(palette.light || palette.main, SWITCH_GRADIENT.resting.lightAlpha)}, ${alpha(palette.main, SWITCH_GRADIENT.resting.mainAlpha)})`,\n }),\n ...(showsTrackLabels(customVariant, onText, offText) &&\n trackLabels(theme, flags, palette, onText, offText)),\n };\n};\n\n/**\n * The same checked-track ink, for the two ICONS the control overlays on the\n * track — which are drawn as components rather than styles, so they cannot\n * reach {@link checkedInk} directly.\n */\nexport const onTrackInk = (theme: Theme, flags: SwitchFlags): string =>\n checkedInk(flags, getColorFromTheme(theme, flags.customColor ?? 'primary'));\n\nexport const switchSx = (theme: Theme, flags: SwitchFlags): CSSObject => {\n const palette = getColorFromTheme(theme, flags.customColor ?? 'primary');\n const geometry = geometryOf(flags.customSize, flags.trackWidth, flags.trackHeight);\n const look = lookOf(flags.customVariant);\n\n return {\n width: rem(theme, geometry.width),\n height: rem(theme, geometry.height),\n padding: 0,\n overflow: 'visible',\n '& .MuiSwitch-switchBase': switchBaseSx(theme, flags, palette, geometry, look),\n '& .MuiSwitch-thumb': thumbSx(theme, flags, palette, geometry.thumbSize, look),\n '& .MuiSwitch-track': trackSx(theme, flags, palette, geometry.height, look),\n };\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/layout/ScrollArea/ScrollArea.tsx"],"sourcesContent":["import KeyboardArrowUp from '@mui/icons-material/KeyboardArrowUp';\nimport Box from '@mui/material/Box/index.js';\nimport CircularProgress from '@mui/material/CircularProgress/index.js';\nimport Fab from '@mui/material/Fab/index.js';\nimport Zoom from '@mui/material/Zoom/index.js';\nimport { alpha, useTheme } from '@mui/material/styles/index.js';\nimport type { SxProps, Theme } from '@mui/material/styles/index.js';\nimport type { FC } from 'react';\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { rem, sxRem } from '../../../tokens/relative';\n\nimport type { ResolvedScrollAreaProps } from './ScrollArea.helpers';\nimport { resolveScrollAreaProps } from './ScrollArea.helpers';\nimport { sizeCss } from './ScrollArea.styles';\nimport type { ScrollAreaProps } from './ScrollArea.types';\nimport { ScrollAreaContent } from './ScrollAreaContent';\nimport { ScrollViewport } from './ScrollViewport';\n\n// Owns the scroll container ref (merging in any ref the caller passed) and\n// reports size changes through a ResizeObserver.\nconst useObservedScrollRef = ({\n externalScrollRef,\n onResize }: {\n externalScrollRef?: React.Ref<HTMLDivElement>;\n onResize?: ScrollAreaProps['onResize'];\n}) => {\n const internalScrollRef = useRef<HTMLDivElement>(null);\n const [containerDimensions, setContainerDimensions] = useState({ width: 0, height: 0 });\n\n // Track container dimensions with ResizeObserver\n useEffect(() => {\n if (!internalScrollRef.current) return;\n\n const resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (entry) {\n const { width, height } = entry.contentRect;\n setContainerDimensions({ width, height });\n onResize?.({ width, height });\n }\n });\n\n resizeObserver.observe(internalScrollRef.current);\n return () => resizeObserver.disconnect();\n }, [onResize]);\n\n // Callback ref that updates both internal and external refs\n const setScrollRef = useCallback(\n (node: HTMLDivElement | null) => {\n // Update internal ref\n (internalScrollRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n // Update external ref if provided\n if (externalScrollRef) {\n (externalScrollRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n }\n },\n [externalScrollRef],\n );\n\n // Use internal ref for accessing the element\n\n return { scrollRef: internalScrollRef, setScrollRef, containerDimensions };\n};\n\n// Scroll position, the transient \"is scrolling\" flag that drives auto-hide, the\n// observed container size, and the scroll-to-top affordance.\n// The scrollbar shows while scrolling and hides once movement stops.\nconst useAutoHide = ({\n autoHide,\n alwaysShowScrollbar,\n autoHideDelay }: {\n autoHide: boolean;\n alwaysShowScrollbar: boolean;\n autoHideDelay: number;\n}) => {\n const [isScrolling, setIsScrolling] = useState(false);\n const timeoutRef = useRef<number | undefined>(undefined);\n\n const noteScroll = useCallback(() => {\n if (!autoHide || alwaysShowScrollbar) return;\n\n setIsScrolling(true);\n window.clearTimeout(timeoutRef.current);\n timeoutRef.current = window.setTimeout(() => setIsScrolling(false), autoHideDelay);\n }, [autoHide, alwaysShowScrollbar, autoHideDelay]);\n\n useEffect(() => () => window.clearTimeout(timeoutRef.current), []);\n\n return { isScrolling, noteScroll };\n};\n\nconst useScrollArea = (\n props: ResolvedScrollAreaProps & { externalScrollRef?: React.Ref<HTMLDivElement> },\n) => {\n const {\n disabled,\n onScroll,\n onResize,\n externalScrollRef,\n autoHide,\n autoHideDelay,\n alwaysShowScrollbar,\n scrollToTopButton,\n scrollToTopThreshold,\n smoothScroll } = props;\n\n const { scrollRef, setScrollRef, containerDimensions } = useObservedScrollRef({\n externalScrollRef,\n onResize });\n const [showScrollToTop, setShowScrollToTop] = useState(false);\n const { isScrolling, noteScroll } = useAutoHide({\n autoHide,\n alwaysShowScrollbar,\n autoHideDelay });\n\n const handleScroll = useCallback(\n (event: React.UIEvent<HTMLDivElement>) => {\n if (disabled) return;\n\n noteScroll();\n\n if (scrollToTopButton && scrollRef.current) {\n setShowScrollToTop(scrollRef.current.scrollTop > scrollToTopThreshold);\n }\n\n onScroll?.(event);\n },\n [disabled, noteScroll, scrollToTopButton, scrollToTopThreshold, onScroll, scrollRef],\n );\n\n const scrollToTop = useCallback(() => {\n scrollRef.current?.scrollTo({ top: 0, behavior: smoothScroll ? 'smooth' : 'auto' });\n }, [smoothScroll, scrollRef]);\n\n return {\n scrollRef,\n setScrollRef,\n isScrolling,\n showScrollToTop,\n containerDimensions,\n handleScroll,\n scrollToTop };\n};\n\nconst LoadingOverlay: FC = () => (\n <Box\n sx={{\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n zIndex: 10 }}\n >\n <CircularProgress />\n </Box>\n);\n\n// The label is guarded at the call site rather than defaulted: the props union\n// already makes it required alongside `scrollToTopButton`, and a fab with an\n// empty accessible name is the exact failure this port exists to remove.\nconst ScrollToTopFab: FC<{\n visible: boolean;\n glass: boolean;\n scrollToTopLabel: string;\n onClick: () => void;\n}> = ({\n visible,\n glass,\n scrollToTopLabel,\n onClick }) => {\n const theme = useTheme();\n\n return (\n <Zoom in={visible}>\n <Fab\n size=\"small\"\n aria-label={scrollToTopLabel}\n onClick={onClick}\n sx={{\n position: 'absolute',\n bottom: sxRem(16),\n right: sxRem(16),\n zIndex: 1,\n backgroundColor: glass\n ? alpha(theme.palette.primary.main, 0.2)\n : theme.palette.primary.main,\n backdropFilter: glass ? `blur(${rem(theme, 10)})` : 'none',\n '&:hover': {\n backgroundColor: glass\n ? alpha(theme.palette.primary.main, 0.3)\n : theme.palette.primary.dark } }}\n >\n <KeyboardArrowUp />\n </Fab>\n </Zoom>\n );\n};\n\n/** The outer box: its size props through the type scale, then the caller's `sx`. */\nfunction outerBoxSx(\n theme: Theme,\n size: Pick<ScrollAreaProps, 'width' | 'height' | 'maxHeight' | 'maxWidth'>,\n sx: ScrollAreaProps['sx'],\n): SxProps<Theme> {\n return {\n position: 'relative',\n width: sizeCss(theme, size.width),\n height: sizeCss(theme, size.height),\n maxHeight: sizeCss(theme, size.maxHeight),\n maxWidth: sizeCss(theme, size.maxWidth),\n ...sx,\n } as SxProps<Theme>;\n}\n\nexport const ScrollArea: React.FC<ScrollAreaProps> = (componentProps) => {\n const theme = useTheme();\n const resolved = resolveScrollAreaProps(componentProps);\n const {\n regionLabel,\n scrollToTopLabel,\n children,\n width: _width,\n height: _height,\n maxHeight: _maxHeight,\n maxWidth: _maxWidth,\n orientation: _orientation,\n scrollbarSize: _scrollbarSize,\n autoHide,\n autoHideDelay: _autoHideDelay,\n smoothScroll: _smoothScroll,\n variant,\n onScroll: _onScroll,\n scrollToTopButton,\n scrollToTopThreshold: _scrollToTopThreshold,\n scrollbarColor: _scrollbarColor,\n scrollbarTrackColor: _scrollbarTrackColor,\n contentPadding: _contentPadding,\n alwaysShowScrollbar,\n disabled,\n loading,\n emptyContent,\n testId,\n scrollRef: externalScrollRef,\n onResize: _onResize,\n sx,\n ...props\n } = resolved;\n\n const { scrollRef, setScrollRef, isScrolling, showScrollToTop, containerDimensions, handleScroll, scrollToTop } =\n useScrollArea({ ...resolved, externalScrollRef });\n\n // Auto-hide keeps the scrollbar out of the way until the user is scrolling.\n const shouldShowScrollbar = alwaysShowScrollbar || !autoHide || isScrolling;\n\n return (\n <Box\n data-testid={testId}\n sx={outerBoxSx(theme, resolved, sx)}\n {...props}\n >\n <ScrollViewport\n {...resolved}\n regionLabel={regionLabel}\n shouldShowScrollbar={shouldShowScrollbar}\n setScrollRef={setScrollRef}\n onScroll={handleScroll}\n >\n <ScrollAreaContent\n emptyContent={emptyContent}\n scrollRef={scrollRef}\n containerWidth={containerDimensions.width}\n >\n {children}\n </ScrollAreaContent>\n </ScrollViewport>\n\n {loading && <LoadingOverlay />}\n\n {scrollToTopButton && scrollToTopLabel && !disabled && !loading && (\n <ScrollToTopFab\n scrollToTopLabel={scrollToTopLabel}\n visible={showScrollToTop}\n glass={variant === 'glass'}\n onClick={scrollToTop}\n />\n )}\n </Box>\n );\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/form/Switch/Switch.metrics.ts"],"sourcesContent":["import type { SwitchVariant } from './Switch.base';\nimport { alpha } from '../../../tokens/color';\nimport { ABSOLUTE_INK, ELEVATION_SHADOWS, NEUTRAL_RAMP } from '../../../tokens/ink.core';\nimport type { SizeValue } from '../../../tokens/vocabulary';\n\n/**\n * THE NUMBERS BOTH `Switch` RENDERERS DRAW WITH.\n *\n * `Switch.styles.ts` (web, emotion over MUI's `Switch`) and\n * `Switch.native.tsx` (React Native, drawing the track and thumb itself) read\n * this one table: the geometry per size, the four looks' radii and shadows,\n * the resting track colours, and the type the label, the description and the\n * helper are set in.\n *\n * Spacing is in SPACING UNITS where the web writes `theme.spacing(n)`;\n * everything else is px, a ratio or an alpha.\n */\n\n/** MUI's `palette.common.black`, which `UiTheme` does not carry. */\nexport const SWITCH_BLACK = ABSOLUTE_INK.black;\n\nexport interface SwitchGeometry {\n width: number;\n height: number;\n padding: number;\n thumbSize: number;\n}\n\nexport const SWITCH_SIZES: Record<SizeValue, SwitchGeometry> = {\n xs: { width: 34, height: 18, padding: 1, thumbSize: 14 },\n sm: { width: 42, height: 22, padding: 1, thumbSize: 18 },\n md: { width: 50, height: 26, padding: 1, thumbSize: 22 },\n lg: { width: 58, height: 30, padding: 2, thumbSize: 24 },\n xl: { width: 66, height: 34, padding: 2, thumbSize: 28 },\n};\n\n/** The four platform looks. `label` prints its wording on a `default` track. */\nexport type SwitchLook = 'ios' | 'android' | 'material' | 'default';\n\nexport const lookOf = (variant?: string): SwitchLook => {\n if (variant === 'ios') return 'ios';\n if (variant === 'android') return 'android';\n if (variant === 'material') return 'material';\n return 'default';\n};\n\n/** Track geometry once the caller's overrides and the size preset are combined. */\nexport const geometryOf = (size: SizeValue | undefined, width?: number, height?: number): SwitchGeometry => {\n const preset = SWITCH_SIZES[size as SizeValue] ?? SWITCH_SIZES.md;\n return { ...preset, width: width || preset.width, height: height || preset.height };\n};\n\n/**\n * The thumb's corner. `'50%'` is what the web emits; a renderer with no\n * percentage radius asks {@link thumbRadius} for the px instead.\n */\nexport const THUMB_RADIUS: Record<SwitchLook, (thumbSize: number) => number | string> = {\n ios: () => '50%',\n android: () => 4,\n material: (thumbSize) => thumbSize / 3,\n default: () => '50%',\n};\n\nexport const TRACK_RADIUS: Record<SwitchLook, (height: number) => number> = {\n ios: (height) => height / 2,\n android: (height) => height / 3,\n material: (height) => height / 2.5,\n default: (height) => height / 2,\n};\n\n/** The web's `'50%'` as the px a circle of this size needs. */\nexport const thumbRadius = (look: SwitchLook, thumbSize: number): number => {\n const radius = THUMB_RADIUS[look](thumbSize);\n return typeof radius === 'number' ? radius : thumbSize / 2;\n};\n\n/**\n * The elevation the thumb rests at per look — an INDEX into `theme.shadows`,\n * not the shadow itself, so a host that re-themes MUI's elevations keeps\n * moving the web. {@link MUI_SHADOWS} carries MUI's own values for the native\n * side, which has no `theme.shadows` to read.\n */\nexport const THUMB_ELEVATION: Record<SwitchLook, number> = { ios: 0, android: 3, material: 2, default: 2 };\n\nexport const MUI_SHADOWS: Record<number, string> = {\n 2: ELEVATION_SHADOWS[2],\n 3: ELEVATION_SHADOWS[3],\n};\n\n/** The iOS thumb's own three-layer shadow, which the web writes out literally. */\nexport const IOS_THUMB_SHADOW = `0 3px 1px 0 ${alpha(SWITCH_BLACK, 0.04)}, 0 3px 8px 0 ${alpha(SWITCH_BLACK, 0.12)}, 0 1px 0 0 ${alpha(SWITCH_BLACK, 0.08)}`;\n\n/** The iOS track's inset hairline. */\nexport const iosTrackShadow = (): string =>\n `inset 0 0 0 0.5px ${alpha(SWITCH_BLACK, 0.1)}, inset 0 2px 3px ${alpha(SWITCH_BLACK, 0.12)}`;\n\n/** The resting track: a black wash on iOS, the disabled ink elsewhere. */\nexport const TRACK_ALPHA = { ios: 0.1, android: 0.2, other: 0.3 } as const;\n\n/**\n * `black` is MUI's `palette.common.black` on the web and {@link SWITCH_BLACK}\n * on native, whose theme has no `common` — the same `#000` either way, passed\n * in rather than assumed so a host that themes it still moves the web.\n */\nexport const trackColor = (ink: { black: string; disabled: string }, look: SwitchLook): string => {\n if (look === 'ios') return alpha(ink.black, TRACK_ALPHA.ios);\n const strength = look === 'android' ? TRACK_ALPHA.android : TRACK_ALPHA.other;\n return alpha(ink.disabled, strength);\n};\n\n/** How far the thumb travels, and where it starts. iOS insets differently. */\nexport const thumbTravel = (look: SwitchLook, geometry: SwitchGeometry): { rest: number; travel: number } => {\n const { width, thumbSize, padding } = geometry;\n if (look === 'ios') {\n // The web nudges the whole switch base 2px right and shortens the trip.\n return { rest: padding + IOS_BASE_OFFSET, travel: width - thumbSize - IOS_TRAVEL_INSET };\n }\n return { rest: padding, travel: width - thumbSize - padding * 2 };\n};\n\nexport const IOS_BASE_OFFSET = 2;\nexport const IOS_TRAVEL_INSET = 4;\n\n/** MUI's 300ms `cubic-bezier(0.4, 0, 0.2, 1)`, on everything the switch moves. */\nexport const SWITCH_TRANSITION = { ms: 300, easing: 'cubic-bezier(0.4, 0, 0.2, 1)' } as const;\n\n/** The disabled treatment: the thumb greys and the track fades. */\nexport const DISABLED = { trackOpacity: 0.3, checkedTrackOpacity: 0.5, thumbGrey: 100 } as const;\n\n/** `glass`: a paper wash under a blur, inside a faint divider hairline. */\nexport const SWITCH_GLASS = {\n trackAlpha: 0.1,\n thumbAlpha: 0.9,\n borderAlpha: 0.2,\n trackBlur: 20,\n thumbBlur: 10,\n} as const;\n\n/** `gradient`: the checked track runs light → main → dark; the resting one is fainter. */\nexport const SWITCH_GRADIENT = {\n checked: { angleDeg: 90, stops: [0, 50, 100] },\n resting: { angleDeg: 135, lightAlpha: 0.3, mainAlpha: 0.2 },\n shimmerMs: 3000,\n} as const;\n\n/** `glow`: a halo of the hue around the checked track, breathing every two seconds. */\nexport const SWITCH_GLOW = { blur: 10, alpha: 0.6, insetBlur: 10, insetAlpha: 0.2, ms: 2000 } as const;\n\n/** `pulse`: the thumb breathes; `ripple`: a wash of the hue expands under the pointer. */\nexport const SWITCH_PULSE = { ms: 2000, minOpacity: 0.7, minScale: 0.95 } as const;\nexport const SWITCH_RIPPLE = { alpha: 0.2, ms: 600, scale: 2 } as const;\n\n/** `loading`: a 2px ring inside the thumb, turning once a second. */\nexport const SWITCH_SPINNER = { sizeRatio: 0.6, borderWidth: 2, ms: 1000 } as const;\n\n/** The two icons overlaid on the track, at their own size per step of the scale. */\nexport const SWITCH_ICON_SIZES: Record<SizeValue, number> = { xs: 12, sm: 14, md: 16, lg: 18, xl: 20 };\n/** Where a shown icon sits, and how small a hidden one is drawn. */\nexport const SWITCH_ICON = { inset: 4, hiddenScale: 0.8 } as const;\n\n/** The wording the `label` variant prints inside the track: 0.75rem at 500, 8px in. */\nexport const TRACK_LABEL = { fontSize: 12, fontWeight: 500, insetUnits: 1 } as const;\n\n/** MUI's `body2` for the label, `caption` for the description and the helper text. */\nexport const SWITCH_LABEL = { fontSize: 14, lineHeight: 1.43, fontWeight: 500 } as const;\nexport const SWITCH_DESCRIPTION = { fontSize: 12, lineHeight: 1.66, marginTopUnits: 0.5 } as const;\nexport const SWITCH_HELPER = { fontSize: 12, lineHeight: 1.66, marginTopUnits: 1 } as const;\n\n/** The label row: 16px from the control beside it, 8px above or below it. */\nexport const LABEL_GAP_UNITS = { beside: 2, stacked: 1 } as const;\n\n/**\n * The minimum height of a touch target, in px (FUT-1905).\n *\n * No entry in {@link SWITCH_SIZES} reaches it — `xl`, the largest, is 34px tall\n * and `md` is 26 — so a consumer cannot buy a legal target by passing a bigger\n * `size`. The label is what clears it: see `SwitchLabel` in `Switch.parts.tsx`.\n */\nexport const TAP_TARGET_MIN = 40;\n\n/**\n * `neutral`'s three greys, and the literals the web falls back to for a theme\n * whose grey ramp omits a step. Same three steps `Button` draws its neutral\n * from.\n */\nexport const NEUTRAL_GREY = { main: 700, dark: 800, light: 500 } as const;\nexport const NEUTRAL_FALLBACK = {\n main: NEUTRAL_RAMP[NEUTRAL_GREY.main],\n dark: NEUTRAL_RAMP[NEUTRAL_GREY.dark],\n light: NEUTRAL_RAMP[NEUTRAL_GREY.light],\n} as const;\nexport const NEUTRAL_CONTRAST = ABSOLUTE_INK.white;\n\n/**\n * The RESTING thumb — the knob while the switch is off (FUT-1924).\n *\n * It stays white, and the reason is worth stating because the checked thumb no\n * longer is: the resting track is `theme.palette.action.disabled` washed over\n * the page, which no tenant picks, and a white knob on it is the conventional\n * look in both modes. The CHECKED track is `palette.main`, a colour the tenant\n * does pick, and that is where a stated white was a defect. See `checkedInk`\n * in `Switch.styles.ts` and its native twin.\n */\nexport const RESTING_THUMB = ABSOLUTE_INK.white;\n\n/** Hover: the thumb lifts a shade and takes a halo of the hue. */\nexport const SWITCH_HOVER = { thumbScale: 1.05, elevation: 4, blur: 12, alpha: 0.2 } as const;\n\n/** Focus: MUI rings the thumb rather than moving it. */\nexport const SWITCH_FOCUS_RING = { width: 6, alpha: 0.2 } as const;\n\n/** A duration as the CSS the web has always emitted: `2000` → `2s`. */\nexport const seconds = (ms: number): string => `${ms / 1000}s`;\n\n/** Whether this variant prints its wording inside the track. */\nexport const showsTrackLabels = (variant: SwitchVariant | undefined, onText?: string, offText?: string): boolean =>\n variant === 'label' && Boolean(onText ?? offText);\n"],"mappings":";;;;;;;;;;AAmBO,IAAM,eAAe,aAAa;AASlC,IAAM,eAAkD;AAAA,EAC7D,IAAI,EAAE,OAAO,IAAI,QAAQ,IAAI,SAAS,GAAG,WAAW,GAAG;AAAA,EACvD,IAAI,EAAE,OAAO,IAAI,QAAQ,IAAI,SAAS,GAAG,WAAW,GAAG;AAAA,EACvD,IAAI,EAAE,OAAO,IAAI,QAAQ,IAAI,SAAS,GAAG,WAAW,GAAG;AAAA,EACvD,IAAI,EAAE,OAAO,IAAI,QAAQ,IAAI,SAAS,GAAG,WAAW,GAAG;AAAA,EACvD,IAAI,EAAE,OAAO,IAAI,QAAQ,IAAI,SAAS,GAAG,WAAW,GAAG;AACzD;AAKO,IAAM,SAAS,CAAC,YAAiC;AACtD,MAAI,YAAY,MAAO,QAAO;AAC9B,MAAI,YAAY,UAAW,QAAO;AAClC,MAAI,YAAY,WAAY,QAAO;AACnC,SAAO;AACT;AAGO,IAAM,aAAa,CAAC,MAA6B,OAAgB,WAAoC;AAC1G,QAAM,SAAS,aAAa,IAAiB,KAAK,aAAa;AAC/D,SAAO,EAAE,GAAG,QAAQ,OAAO,SAAS,OAAO,OAAO,QAAQ,UAAU,OAAO,OAAO;AACpF;AAMO,IAAM,eAA2E;AAAA,EACtF,KAAK,MAAM;AAAA,EACX,SAAS,MAAM;AAAA,EACf,UAAU,CAAC,cAAc,YAAY;AAAA,EACrC,SAAS,MAAM;AACjB;AAEO,IAAM,eAA+D;AAAA,EAC1E,KAAK,CAAC,WAAW,SAAS;AAAA,EAC1B,SAAS,CAAC,WAAW,SAAS;AAAA,EAC9B,UAAU,CAAC,WAAW,SAAS;AAAA,EAC/B,SAAS,CAAC,WAAW,SAAS;AAChC;AAGO,IAAM,cAAc,CAAC,MAAkB,cAA8B;AAC1E,QAAM,SAAS,aAAa,IAAI,EAAE,SAAS;AAC3C,SAAO,OAAO,WAAW,WAAW,SAAS,YAAY;AAC3D;AAQO,IAAM,kBAA8C,EAAE,KAAK,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,EAAE;AAElG,IAAM,cAAsC;AAAA,EACjD,GAAG,kBAAkB,CAAC;AAAA,EACtB,GAAG,kBAAkB,CAAC;AACxB;AAGO,IAAM,mBAAmB,eAAe,MAAM,cAAc,IAAI,CAAC,iBAAiB,MAAM,cAAc,IAAI,CAAC,eAAe,MAAM,cAAc,IAAI,CAAC;AAGnJ,IAAM,iBAAiB,MAC5B,qBAAqB,MAAM,cAAc,GAAG,CAAC,qBAAqB,MAAM,cAAc,IAAI,CAAC;AAGtF,IAAM,cAAc,EAAE,KAAK,KAAK,SAAS,KAAK,OAAO,IAAI;AAOzD,IAAM,aAAa,CAAC,KAA0C,SAA6B;AAChG,MAAI,SAAS,MAAO,QAAO,MAAM,IAAI,OAAO,YAAY,GAAG;AAC3D,QAAM,WAAW,SAAS,YAAY,YAAY,UAAU,YAAY;AACxE,SAAO,MAAM,IAAI,UAAU,QAAQ;AACrC;AAGO,IAAM,cAAc,CAAC,MAAkB,aAA+D;AAC3G,QAAM,EAAE,OAAO,WAAW,QAAQ,IAAI;AACtC,MAAI,SAAS,OAAO;AAElB,WAAO,EAAE,MAAM,UAAU,iBAAiB,QAAQ,QAAQ,YAAY,iBAAiB;AAAA,EACzF;AACA,SAAO,EAAE,MAAM,SAAS,QAAQ,QAAQ,YAAY,UAAU,EAAE;AAClE;AAEO,IAAM,kBAAkB;AACxB,IAAM,mBAAmB;AAGzB,IAAM,oBAAoB,EAAE,IAAI,KAAK,QAAQ,+BAA+B;AAG5E,IAAM,WAAW,EAAE,cAAc,KAAK,qBAAqB,KAAK,WAAW,IAAI;AAG/E,IAAM,eAAe;AAAA,EAC1B,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,WAAW;AAAA,EACX,WAAW;AACb;AAGO,IAAM,kBAAkB;AAAA,EAC7B,SAAS,EAAE,UAAU,IAAI,OAAO,CAAC,GAAG,IAAI,GAAG,EAAE;AAAA,EAC7C,SAAS,EAAE,UAAU,KAAK,YAAY,KAAK,WAAW,IAAI;AAAA,EAC1D,WAAW;AACb;AAGO,IAAM,cAAc,EAAE,MAAM,IAAI,OAAO,KAAK,WAAW,IAAI,YAAY,KAAK,IAAI,IAAK;AAGrF,IAAM,eAAe,EAAE,IAAI,KAAM,YAAY,KAAK,UAAU,KAAK;AACjE,IAAM,gBAAgB,EAAE,OAAO,KAAK,IAAI,KAAK,OAAO,EAAE;AAGtD,IAAM,iBAAiB,EAAE,WAAW,KAAK,aAAa,GAAG,IAAI,IAAK;AAGlE,IAAM,oBAA+C,EAAE,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG;AAE9F,IAAM,cAAc,EAAE,OAAO,GAAG,aAAa,IAAI;AAGjD,IAAM,cAAc,EAAE,UAAU,IAAI,YAAY,KAAK,YAAY,EAAE;AAGnE,IAAM,eAAe,EAAE,UAAU,IAAI,YAAY,MAAM,YAAY,IAAI;AACvE,IAAM,qBAAqB,EAAE,UAAU,IAAI,YAAY,MAAM,gBAAgB,IAAI;AACjF,IAAM,gBAAgB,EAAE,UAAU,IAAI,YAAY,MAAM,gBAAgB,EAAE;AAG1E,IAAM,kBAAkB,EAAE,QAAQ,GAAG,SAAS,EAAE;AAShD,IAAM,iBAAiB;AAOvB,IAAM,eAAe,EAAE,MAAM,KAAK,MAAM,KAAK,OAAO,IAAI;AACxD,IAAM,mBAAmB;AAAA,EAC9B,MAAM,aAAa,aAAa,IAAI;AAAA,EACpC,MAAM,aAAa,aAAa,IAAI;AAAA,EACpC,OAAO,aAAa,aAAa,KAAK;AACxC;AACO,IAAM,mBAAmB,aAAa;AAYtC,IAAM,gBAAgB,aAAa;AAGnC,IAAM,eAAe,EAAE,YAAY,MAAM,WAAW,GAAG,MAAM,IAAI,OAAO,IAAI;AAG5E,IAAM,oBAAoB,EAAE,OAAO,GAAG,OAAO,IAAI;AAGjD,IAAM,UAAU,CAAC,OAAuB,GAAG,KAAK,GAAI;AAGpD,IAAM,mBAAmB,CAAC,SAAoC,QAAiB,YACpF,YAAY,WAAW,QAAQ,UAAU,OAAO;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/Table/Table.hooks.ts"],"sourcesContent":["import { useTheme } from '@mui/material/styles/index.js';\nimport useMediaQuery from '@mui/material/useMediaQuery/index.js';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport type { ColumnConfig, TableProps } from './Table.types';\n\nexport const useVirtualScrolling = (\n data: Record<string, unknown>[],\n rowHeight: number,\n containerHeight: number,\n overscan: number = 5\n) => {\n const [scrollTop, setScrollTop] = useState(0);\n \n const visibleItems = useMemo(() => {\n const visibleHeight = containerHeight;\n const startIndex = Math.floor(scrollTop / rowHeight);\n const endIndex = Math.min(\n data.length,\n Math.ceil((scrollTop + visibleHeight) / rowHeight)\n );\n \n const start = Math.max(0, startIndex - overscan);\n const end = Math.min(data.length, endIndex + overscan);\n \n return {\n startIndex: start,\n endIndex: end,\n items: data.slice(start, end),\n totalHeight: data.length * rowHeight,\n offsetY: start * rowHeight,\n };\n }, [data, rowHeight, containerHeight, scrollTop, overscan]);\n\n const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {\n setScrollTop(e.currentTarget.scrollTop);\n }, []);\n\n return { visibleItems, handleScroll };\n};\n\n// Responsive Hook\n\nconst useResponsive = (\n columns: ColumnConfig[],\n columnPriorities?: number[]\n) => {\n const theme = useTheme();\n const isMobile = useMediaQuery(theme.breakpoints.down('md'));\n const isTablet = useMediaQuery(theme.breakpoints.down('lg'));\n \n const [hiddenColumns, setHiddenColumns] = useState<number[]>([]);\n const [columnMenuAnchor, setColumnMenuAnchor] = useState<null | HTMLElement>(null);\n\n useEffect(() => {\n if (!columnPriorities) return;\n \n let columnsToHide: number[] = [];\n \n if (isMobile) {\n // Hide lowest priority columns on mobile\n columnsToHide = columnPriorities\n .map((priority, index) => ({ priority, index }))\n .sort((a, b) => b.priority - a.priority)\n .slice(0, Math.floor(columns.length / 2))\n .map(item => item.index);\n } else if (isTablet) {\n // Hide some columns on tablet\n columnsToHide = columnPriorities\n .map((priority, index) => ({ priority, index }))\n .sort((a, b) => b.priority - a.priority)\n .slice(0, Math.floor(columns.length / 3))\n .map(item => item.index);\n }\n \n setHiddenColumns(columnsToHide);\n }, [isMobile, isTablet, columnPriorities, columns.length]);\n\n const visibleColumns = columns.filter((_, index) => !hiddenColumns.includes(index));\n\n return {\n visibleColumns,\n hiddenColumns,\n isMobile,\n columnMenuAnchor,\n setColumnMenuAnchor,\n setHiddenColumns,\n };\n};\n\n// Enhanced Table Header Component\n// Visible/hidden column split for responsive mode, plus row selection.\nexport const useTableSelection = ({\n columns,\n data,\n responsive,\n columnPriorities,\n selectedRows,\n rowKeyExtractor,\n onSelectionChange,\n}: {\n columns?: ColumnConfig[];\n data: TableProps['data'];\n responsive?: boolean;\n columnPriorities?: number[];\n selectedRows: (string | number)[];\n rowKeyExtractor?: (row: Record<string, unknown>, index: number) => string | number;\n onSelectionChange?: TableProps['onSelectionChange'];\n}) => {\n \n // Use responsive hook if responsive mode is enabled\n const {\n visibleColumns,\n hiddenColumns,\n isMobile,\n columnMenuAnchor,\n setColumnMenuAnchor,\n setHiddenColumns,\n } = useResponsive(\n columns || [],\n responsive ? columnPriorities : undefined\n );\n\n // Handle selection changes\n const handleSelectionChange = useCallback((rowKey: string | number, selected: boolean) => {\n if (!onSelectionChange) return;\n \n let newSelection: (string | number)[];\n if (selected) {\n newSelection = [...selectedRows, rowKey];\n } else {\n newSelection = selectedRows.filter(key => key !== rowKey);\n }\n onSelectionChange(newSelection);\n }, [selectedRows, onSelectionChange]);\n\n const handleSelectAll = useCallback((selected: boolean) => {\n if (!onSelectionChange || !data) return;\n \n if (selected) {\n const allKeys = data.map((rowData, index) => \n rowKeyExtractor ? rowKeyExtractor(rowData, index) : (rowData.id as string | number) || index\n );\n onSelectionChange(allKeys);\n } else {\n onSelectionChange([]);\n }\n }, [data, onSelectionChange, rowKeyExtractor]);\n\n // Loading state\n\n return {\n visibleColumns,\n hiddenColumns,\n isMobile,\n columnMenuAnchor,\n setColumnMenuAnchor,\n setHiddenColumns,\n handleSelectionChange,\n handleSelectAll,\n };\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/DataGrid/DataGrid.model.ts"],"sourcesContent":["/**\n * The DataGrid's STATE, in one hook.\n *\n * The component used to hold all of it inline, which made its body 700 lines\n * long and put the row pipeline, the virtualization window and the JSX in one\n * scope where any of them could reach any other. Split out, each piece is a\n * hook with named inputs and the render is left with nothing to do but render.\n *\n * Controlled/uncontrolled is resolved in ONE place per feature: a caller that\n * passes `sorting.sortBy` owns the sort, and a caller that does not gets the\n * internal state — the component never holds a second, divergent copy.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type React from 'react';\n\nimport { processRows } from './DataGrid.rows';\nimport type {\n DataGridProps,\n GridColumn,\n GridFilter,\n GridSort,\n SortDirection,\n} from './DataGrid.types';\n\nconst DEFAULT_ROW_HEIGHT = 52;\nconst DEFAULT_PAGE_SIZE = 50;\n/** Rows rendered on either side of the window, so a fast scroll stays filled. */\nconst OVERSCAN_COUNT = 20;\n/** Below this many rows, virtualization costs more than it saves. */\nconst VIRTUALIZATION_THRESHOLD = 100;\n/** The initial (and reset) window size, before a scroll has measured anything. */\nconst INITIAL_WINDOW = 50;\n/** Re-window only past this much drift, so a scroll is not one setState per pixel. */\nconst WINDOW_DRIFT = 5;\n\n/** Which id is being edited, or `null`. */\nexport interface EditingCell {\n rowId: string | number;\n colId: string;\n}\n\n/** The visible slice of a virtualized body. */\nexport interface VisibleRange {\n start: number;\n end: number;\n}\n\n/** Everything the render needs, and nothing it has to derive. */\nexport interface DataGridModel<T extends Record<string, unknown>> {\n containerRef: React.RefObject<HTMLDivElement | null>;\n rowHeight: number;\n visibleColumns: GridColumn<T>[];\n processedRows: T[];\n visibleRows: T[];\n visibleRange: VisibleRange;\n virtualized: boolean;\n sortBy: readonly GridSort[];\n selectedRowIds: Array<string | number>;\n selectedRowIdsSet: ReadonlySet<string | number>;\n expandedRowIdsSet: ReadonlySet<string | number>;\n editingCell: EditingCell | null;\n setEditingCell: (cell: EditingCell | null) => void;\n setSelectedRowIds: (ids: Array<string | number>) => void;\n onSort: (columnId: string) => void;\n onToggleRow: (rowId: string | number, isSelected: boolean) => void;\n onToggleExpansion: (rowId: string | number) => void;\n onScroll: (event: React.UIEvent<HTMLDivElement>) => void;\n}\n\n/** The row height a density implies. */\nfunction densityHeight(base: number, density: DataGridProps['density']): number {\n if (density === 'compact') return Math.max(base * 0.8, 32);\n if (density === 'spacious') return base * 1.2;\n return base;\n}\n\n/** The rows this render should show, with every client-mode step resolved. */\nfunction useProcessedRows<T extends Record<string, unknown>>(\n props: DataGridProps<T>,\n columnMap: ReadonlyMap<string, GridColumn<T>>,\n sortBy: readonly GridSort[],\n filters: readonly GridFilter[],\n): T[] {\n const { rows, filtering = {}, sorting = {}, pagination, virtualizeRows = true } = props;\n const pageIndex = pagination?.pageIndex ?? 0;\n const pageSize = pagination?.pageSize ?? DEFAULT_PAGE_SIZE;\n return useMemo(\n () =>\n processRows({\n rows,\n columnMap,\n filters,\n sortBy,\n needsFiltering: filtering.mode === 'client' && filters.length > 0,\n needsSorting: sorting.mode === 'client' && sortBy.length > 0,\n // Virtualization already slices; doing both would page a page.\n needsPagination: pagination?.mode === 'client' && !virtualizeRows,\n pageIndex,\n pageSize,\n }),\n [\n rows,\n columnMap,\n filters,\n sortBy,\n filtering.mode,\n sorting.mode,\n pagination?.mode,\n virtualizeRows,\n pageIndex,\n pageSize,\n ],\n );\n}\n\n/**\n * The virtualization window and the scroll handler that moves it.\n *\n * Throttled through `requestAnimationFrame`, and only committed once the window\n * has drifted meaningfully — a `setState` per scroll event re-renders every\n * visible row for a movement the eye cannot see.\n */\nfunction useRowWindow(\n rowCount: number,\n rowHeight: number,\n enabled: boolean,\n): { range: VisibleRange; onScroll: (event: React.UIEvent<HTMLDivElement>) => void } {\n const [range, setRange] = useState<VisibleRange>({ start: 0, end: INITIAL_WINDOW });\n const rafRef = useRef<number | null>(null);\n\n useEffect(() => {\n if (rowCount < range.end) setRange({ start: 0, end: Math.min(INITIAL_WINDOW, rowCount) });\n }, [rowCount, range.end]);\n\n useEffect(\n () => () => {\n if (rafRef.current !== null) window.cancelAnimationFrame(rafRef.current);\n },\n [],\n );\n\n const onScroll = useCallback(\n (event: React.UIEvent<HTMLDivElement>) => {\n if (!enabled) return;\n const { scrollTop, clientHeight } = event.currentTarget;\n if (rafRef.current !== null) window.cancelAnimationFrame(rafRef.current);\n rafRef.current = window.requestAnimationFrame(() => {\n const first = Math.floor(scrollTop / rowHeight);\n const visible = Math.ceil(clientHeight / rowHeight);\n const start = Math.max(0, first - OVERSCAN_COUNT);\n const end = Math.min(first + visible + OVERSCAN_COUNT, rowCount);\n setRange((current) =>\n Math.abs(start - current.start) > WINDOW_DRIFT ||\n Math.abs(end - current.end) > WINDOW_DRIFT\n ? { start, end }\n : current,\n );\n rafRef.current = null;\n });\n },\n [enabled, rowHeight, rowCount],\n );\n\n return { range, onScroll };\n}\n\n/** The next `sortBy` for a header press: asc → desc → unsorted. */\nfunction nextSortBy(current: readonly GridSort[], columnId: string): GridSort[] {\n const existing = current.find((sort) => sort.id === columnId);\n let dir: SortDirection = 'asc';\n if (existing?.dir === 'asc') dir = 'desc';\n else if (existing?.dir === 'desc') dir = null;\n return dir ? [{ id: columnId, dir }] : current.filter((sort) => sort.id !== columnId);\n}\n\n/** Selection + expansion, each resolved once against its controlled prop. */\nfunction useRowFlags<T extends Record<string, unknown>>(\n props: DataGridProps<T>,\n): Pick<\n DataGridModel<T>,\n | 'selectedRowIds'\n | 'selectedRowIdsSet'\n | 'expandedRowIdsSet'\n | 'setSelectedRowIds'\n | 'onToggleRow'\n | 'onToggleExpansion'\n> {\n const { selection = { mode: 'none' }, expansion } = props;\n const [internalSelected, setInternalSelected] = useState(selection.defaultSelectedRowIds ?? []);\n const [internalExpanded, setInternalExpanded] = useState(expansion?.defaultExpandedRowIds ?? []);\n const selectedRowIds = selection.selectedRowIds ?? internalSelected;\n const expandedRowIds = expansion?.expandedRowIds ?? internalExpanded;\n\n const commitSelected = useCallback(\n (ids: Array<string | number>) => {\n if (selection.onChangeSelected) selection.onChangeSelected(ids);\n else setInternalSelected(ids);\n },\n [selection],\n );\n\n return {\n selectedRowIds,\n selectedRowIdsSet: useMemo(() => new Set(selectedRowIds), [selectedRowIds]),\n expandedRowIdsSet: useMemo(() => new Set(expandedRowIds), [expandedRowIds]),\n setSelectedRowIds: commitSelected,\n onToggleRow: (rowId, isSelected) => {\n if (selection.mode === 'single') commitSelected(isSelected ? [rowId] : []);\n else if (selection.mode === 'multi') {\n commitSelected(\n isSelected\n ? [...selectedRowIds, rowId]\n : selectedRowIds.filter((id) => id !== rowId),\n );\n }\n },\n onToggleExpansion: (rowId) => {\n if (!expansion) return;\n const next = expandedRowIds.includes(rowId)\n ? expandedRowIds.filter((id) => id !== rowId)\n : [...expandedRowIds, rowId];\n if (expansion.onChangeExpanded) expansion.onChangeExpanded(next);\n else setInternalExpanded(next);\n },\n };\n}\n\n/**\n * A header press, routed to whoever owns the sort: the server (which must\n * re-query — sorting the current page locally would reorder one page of a\n * dataset and call it sorted), the caller's `onChangeSortBy`, or internal state.\n */\nfunction useSortHandler<T extends Record<string, unknown>>(\n props: DataGridProps<T>,\n sortBy: readonly GridSort[],\n filters: readonly GridFilter[],\n setInternalSortBy: (next: GridSort[]) => void,\n): (columnId: string) => void {\n const { sorting = {}, pagination, onRequestData } = props;\n return useCallback(\n (columnId: string) => {\n const next = nextSortBy(sortBy, columnId);\n if (sorting.mode === 'server' && onRequestData) {\n onRequestData({\n pageIndex: pagination?.pageIndex ?? 0,\n pageSize: pagination?.pageSize ?? DEFAULT_PAGE_SIZE,\n sortBy: next,\n filters: [...filters],\n });\n return;\n }\n if (sorting.onChangeSortBy) sorting.onChangeSortBy(next);\n else setInternalSortBy(next);\n },\n [sortBy, sorting, onRequestData, pagination, filters, setInternalSortBy],\n );\n}\n\n/**\n * Sort and filter, each resolved ONCE against its controlled prop: a caller\n * that passes `sorting.sortBy` owns the sort, and one that does not gets the\n * internal state. The grid never holds a second, divergent copy.\n */\nfunction useSortAndFilter<T extends Record<string, unknown>>(\n props: DataGridProps<T>,\n): {\n sortBy: readonly GridSort[];\n filters: readonly GridFilter[];\n setInternalSortBy: (next: GridSort[]) => void;\n} {\n const { sorting = {}, filtering = {} } = props;\n const [internalSortBy, setInternalSortBy] = useState<GridSort[]>(sorting.defaultSortBy ?? []);\n const [internalFilters] = useState<GridFilter[]>(filtering.defaultFilters ?? []);\n return {\n sortBy: sorting.sortBy ?? internalSortBy,\n filters: filtering.filters ?? internalFilters,\n setInternalSortBy,\n };\n}\n\nexport function useDataGridModel<T extends Record<string, unknown>>(\n props: DataGridProps<T>,\n): DataGridModel<T> {\n const { columns } = props;\n const containerRef = useRef<HTMLDivElement>(null);\n const [editingCell, setEditingCell] = useState<EditingCell | null>(null);\n const { sortBy, filters, setInternalSortBy } = useSortAndFilter(props);\n const rowHeight = densityHeight(props.rowHeight ?? DEFAULT_ROW_HEIGHT, props.density);\n const columnMap = useMemo(\n () => new Map(columns.map((column) => [column.id, column])),\n [columns],\n );\n const visibleColumns = useMemo(() => columns.filter((column) => !column.hidden), [columns]);\n const processedRows = useProcessedRows(props, columnMap, sortBy, filters);\n const virtualized =\n (props.virtualizeRows ?? true) && processedRows.length > VIRTUALIZATION_THRESHOLD;\n const { range, onScroll } = useRowWindow(processedRows.length, rowHeight, virtualized);\n const onSort = useSortHandler(props, sortBy, filters, setInternalSortBy);\n\n return {\n containerRef,\n rowHeight,\n visibleColumns,\n processedRows,\n visibleRows: virtualized ? processedRows.slice(range.start, range.end) : processedRows,\n visibleRange: range,\n virtualized,\n sortBy,\n editingCell,\n setEditingCell,\n onSort,\n onScroll,\n ...useRowFlags(props),\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/layout/Resizable/Resizable.tsx"],"sourcesContent":["import Box from '@mui/material/Box/index.js';\nimport { useTheme } from '@mui/material/styles/index.js';\nimport React, { useMemo } from 'react';\n\nimport { defaultHandles, handleStyle, resolveResizableProps } from './Resizable.helpers';\nimport { useResize } from './Resizable.hooks';\nimport type { ResizableProps } from './Resizable.types';\n\nexport const Resizable: React.FC<ResizableProps> = (rawProps) => {\n const {\n children,\n variant,\n width: initialWidth,\n height: initialHeight,\n minWidth,\n maxWidth,\n minHeight,\n maxHeight,\n onResize,\n disabled,\n handles,\n className,\n 'data-testid': dataTestId,\n ...rest\n } = resolveResizableProps(rawProps);\n const theme = useTheme();\n const bounds = useMemo(\n () => ({\n width: { min: minWidth, max: maxWidth },\n height: { min: minHeight, max: maxHeight },\n }),\n [minWidth, maxWidth, minHeight, maxHeight],\n );\n\n const { size, isResizing, activeHandle, handleMouseDown } = useResize({\n width: initialWidth,\n height: initialHeight,\n bounds,\n disabled,\n onResize,\n });\n\n const activeHandles = handles || defaultHandles(variant);\n\n return (\n <Box\n {...rest}\n className={className}\n data-testid={dataTestId}\n sx={{\n position: 'relative',\n width: size.width,\n height: size.height,\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: theme.spacing(0.5),\n overflow: 'hidden',\n userSelect: isResizing ? 'none' : 'auto',\n '&:hover .resize-handle': {\n opacity: 0.3,\n },\n }}\n >\n {children}\n {!disabled &&\n activeHandles.map((handle) => (\n <Box\n key={handle}\n className=\"resize-handle\"\n data-testid={dataTestId ? `${dataTestId}-handle-${handle}` : undefined}\n sx={handleStyle(theme, handle, isResizing && activeHandle.current === handle)}\n onMouseDown={(e) => handleMouseDown(e, handle)}\n />\n ))}\n </Box>\n );\n};\n"],"mappings":";;;;;;;;;;AAAA,OAAO,SAAS;AAChB,SAAS,gBAAgB;AACzB,SAAgB,eAAe;AA2C3B,SAoBM,KApBN;AArCG,IAAM,YAAsC,CAAC,aAAa;AAC/D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf,GAAG;AAAA,EACL,IAAI,sBAAsB,QAAQ;AAClC,QAAM,QAAQ,SAAS;AACvB,QAAM,SAAS;AAAA,IACb,OAAO;AAAA,MACL,OAAO,EAAE,KAAK,UAAU,KAAK,SAAS;AAAA,MACtC,QAAQ,EAAE,KAAK,WAAW,KAAK,UAAU;AAAA,IAC3C;AAAA,IACA,CAAC,UAAU,UAAU,WAAW,SAAS;AAAA,EAC3C;AAEA,QAAM,EAAE,MAAM,YAAY,cAAc,gBAAgB,IAAI,UAAU;AAAA,IACpE,OAAO;AAAA,IACP,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,gBAAgB,WAAW,eAAe,OAAO;AAEvD,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA,eAAa;AAAA,MACb,IAAI;AAAA,QACF,UAAU;AAAA,QACV,OAAO,KAAK;AAAA,QACZ,QAAQ,KAAK;AAAA,QACb,QAAQ,aAAa,MAAM,QAAQ,OAAO;AAAA,QAC1C,cAAc,MAAM,QAAQ,GAAG;AAAA,QAC/B,UAAU;AAAA,QACV,YAAY,aAAa,SAAS;AAAA,QAClC,0BAA0B;AAAA,UACxB,SAAS;AAAA,QACX;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,QACA,CAAC,YACA,cAAc,IAAI,CAAC,WACjB;AAAA,UAAC;AAAA;AAAA,YAEC,WAAU;AAAA,YACV,eAAa,aAAa,GAAG,UAAU,WAAW,MAAM,KAAK;AAAA,YAC7D,IAAI,YAAY,OAAO,QAAQ,cAAc,aAAa,YAAY,MAAM;AAAA,YAC5E,aAAa,CAAC,MAAM,gBAAgB,GAAG,MAAM;AAAA;AAAA,UAJxC;AAAA,QAKP,CACD;AAAA;AAAA;AAAA,EACL;AAEJ;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/utility/VirtualList/VirtualList.hooks.ts"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport type { VirtualGridProps, VirtualListProps } from './VirtualList.types';\n\ntype ScrollEvent = React.UIEvent<HTMLDivElement> | Event;\ntype ListItems = VirtualListProps['items'];\ntype ListVariant = NonNullable<VirtualListProps['variant']>;\ntype ItemHeight = (index: number) => number;\n\n// Handles both React synthetic events and native DOM events, since the same\n// handler serves an internal onScroll and an external container's listener.\nconst scrollOffsets = (event: ScrollEvent) => {\n const target = (event as React.UIEvent<HTMLDivElement>).currentTarget || (event as Event).target;\n const element = target as HTMLElement;\n return { top: element.scrollTop, left: element.scrollLeft };\n};\n\n/**\n * When the caller owns the scroll container, the component cannot attach\n * `onScroll` through JSX and has to subscribe to that element directly.\n */\nconst useExternalScrollListener = (\n scrollContainerRef: VirtualListProps['scrollContainerRef'],\n handleScroll: (event: Event) => void,\n) => {\n useEffect(() => {\n if (!scrollContainerRef?.current) return;\n\n const element = scrollContainerRef.current;\n const scrollHandler = (e: Event) => handleScroll(e);\n\n element.addEventListener('scroll', scrollHandler);\n return () => element.removeEventListener('scroll', scrollHandler);\n }, [scrollContainerRef, handleScroll]);\n};\n\n/**\n * Tracks the scroll offset whether it arrives through our own `onScroll` or\n * through a container the caller owns, and hands both offsets to `report` so a\n * grid can pass on the horizontal one too.\n */\nconst useScrollTop = (\n scrollContainerRef: VirtualListProps['scrollContainerRef'],\n report: (top: number, left: number) => void,\n) => {\n const [scrollTop, setScrollTop] = useState(0);\n\n const handleScroll = useCallback(\n (event: ScrollEvent) => {\n const { top, left } = scrollOffsets(event);\n setScrollTop(top);\n report(top, left);\n },\n [report],\n );\n\n useExternalScrollListener(scrollContainerRef, handleScroll);\n\n return { scrollTop, handleScroll };\n};\n\ninterface HeightArgs {\n items: ListItems;\n variant: ListVariant;\n itemHeight: number;\n estimatedItemHeight: number;\n}\n\n/**\n * Fixed lists know every height up front. Variable ones prefer the item's own\n * declared height, fall back to a measurement taken on a previous render, and\n * only then guess.\n */\nconst useItemHeight = ({\n items,\n variant,\n itemHeight,\n estimatedItemHeight,\n}: HeightArgs): ItemHeight => {\n const measured = useRef<Map<number, number>>(new Map());\n\n return useCallback(\n (index: number): number => {\n if (variant !== 'variable') {\n return itemHeight;\n }\n\n return items[index]?.height || measured.current.get(index) || estimatedItemHeight;\n },\n [variant, itemHeight, estimatedItemHeight, items],\n );\n};\n\nconst useTotalHeight = (\n items: ListItems,\n variant: ListVariant,\n itemHeight: number,\n getItemHeight: ItemHeight,\n) =>\n useMemo(() => {\n if (variant === 'fixed') {\n return items.length * itemHeight;\n }\n\n let sum = 0;\n for (let i = 0; i < items.length; i++) {\n sum += getItemHeight(i);\n }\n return sum;\n }, [items.length, variant, itemHeight, getItemHeight]);\n\ninterface RangeArgs {\n count: number;\n scrollTop: number;\n height: number;\n overscan: number;\n itemHeight: number;\n getItemHeight: ItemHeight;\n}\n\n// Walks forward accumulating heights until it passes the viewport's top edge, then\n// its bottom edge. Linear in the number of items, which is why fixed lists take\n// the arithmetic shortcut instead.\nconst variableRange = ({ count, scrollTop, height, overscan, getItemHeight }: RangeArgs) => {\n let accumulated = 0;\n let startIndex = 0;\n let endIndex = count - 1;\n\n for (let i = 0; i < count; i++) {\n if (accumulated + getItemHeight(i) > scrollTop) {\n startIndex = Math.max(0, i - overscan);\n break;\n }\n accumulated += getItemHeight(i);\n }\n\n accumulated = 0;\n for (let i = 0; i <= startIndex; i++) {\n accumulated += getItemHeight(i);\n }\n\n for (let i = startIndex; i < count; i++) {\n if (accumulated > scrollTop + height) {\n endIndex = Math.min(count - 1, i + overscan);\n break;\n }\n accumulated += getItemHeight(i);\n }\n\n return { startIndex, endIndex };\n};\n\nconst fixedRange = ({ count, scrollTop, height, overscan, itemHeight }: RangeArgs) => ({\n startIndex: Math.max(0, Math.floor(scrollTop / itemHeight) - overscan),\n endIndex: Math.min(count - 1, Math.ceil((scrollTop + height) / itemHeight) + overscan),\n});\n\nconst useItemOffset = (\n variant: ListVariant,\n itemHeight: number,\n getItemHeight: ItemHeight,\n): ItemHeight =>\n useCallback(\n (index: number): number => {\n if (variant === 'fixed') {\n return index * itemHeight;\n }\n\n let offset = 0;\n for (let i = 0; i < index; i++) {\n offset += getItemHeight(i);\n }\n return offset;\n },\n [variant, itemHeight, getItemHeight],\n );\n\ninterface ListArgs {\n items: ListItems;\n variant: ListVariant;\n height: number;\n itemHeight: number;\n estimatedItemHeight: number;\n overscan: number;\n onScroll: VirtualListProps['onScroll'];\n scrollContainerRef: VirtualListProps['scrollContainerRef'];\n}\n\nexport const useVirtualList = ({\n items,\n variant,\n height,\n itemHeight,\n estimatedItemHeight,\n overscan,\n onScroll,\n scrollContainerRef,\n}: ListArgs) => {\n const getItemHeight = useItemHeight({ items, variant, itemHeight, estimatedItemHeight });\n const getItemOffset = useItemOffset(variant, itemHeight, getItemHeight);\n const totalHeight = useTotalHeight(items, variant, itemHeight, getItemHeight);\n\n const report = useCallback((top: number) => onScroll?.(top), [onScroll]);\n const { scrollTop, handleScroll } = useScrollTop(scrollContainerRef, report);\n\n const visibleItems = useMemo(() => {\n const args = { count: items.length, scrollTop, height, overscan, itemHeight, getItemHeight };\n const { startIndex, endIndex } = variant === 'fixed' ? fixedRange(args) : variableRange(args);\n const result = [];\n\n for (let i = startIndex; i <= endIndex; i++) {\n const item = items[i];\n if (!item) continue;\n\n result.push({\n item,\n index: i,\n style: {\n position: 'absolute' as const,\n top: getItemOffset(i),\n left: 0,\n width: '100%',\n height: getItemHeight(i),\n },\n });\n }\n\n return result;\n }, [items, scrollTop, height, overscan, variant, itemHeight, getItemOffset, getItemHeight]);\n\n return { totalHeight, visibleItems, handleScroll };\n};\n\ninterface GridArgs {\n items: VirtualGridProps['items'];\n height: number;\n width: number | string;\n columnCount: number;\n rowHeight: number;\n columnWidth?: number;\n gap: number;\n overscan: number;\n onScroll: VirtualGridProps['onScroll'];\n scrollContainerRef: VirtualGridProps['scrollContainerRef'];\n}\n\nconst useColumnWidth = (\n columnWidth: number | undefined,\n width: number | string,\n columnCount: number,\n gap: number,\n) =>\n useMemo(() => {\n if (columnWidth) return columnWidth;\n\n const containerWidth = typeof width === 'number' ? width : 300; // fallback\n return (containerWidth - (columnCount - 1) * gap) / columnCount;\n }, [columnWidth, width, columnCount, gap]);\n\nexport const useVirtualGrid = ({\n items,\n height,\n width,\n columnCount,\n rowHeight,\n columnWidth,\n gap,\n overscan,\n onScroll,\n scrollContainerRef,\n}: GridArgs) => {\n const rowCount = Math.ceil(items.length / columnCount);\n const totalHeight = rowCount * (rowHeight + gap) - gap;\n const computedColumnWidth = useColumnWidth(columnWidth, width, columnCount, gap);\n\n const report = useCallback(\n (top: number, left: number) => onScroll?.(top, left),\n [onScroll],\n );\n const { scrollTop, handleScroll } = useScrollTop(scrollContainerRef, report);\n\n const visibleItems = useMemo(() => {\n const pitch = rowHeight + gap;\n const startRow = Math.max(0, Math.floor(scrollTop / pitch) - overscan);\n const endRow = Math.min(rowCount - 1, Math.ceil((scrollTop + height) / pitch) + overscan);\n\n // Rows are contiguous in `items`, so the visible block is one index range\n // rather than a row loop wrapping a column loop.\n const firstIndex = startRow * columnCount;\n const lastIndex = Math.min((endRow + 1) * columnCount - 1, items.length - 1);\n const result = [];\n\n for (let index = firstIndex; index <= lastIndex; index++) {\n const item = items[index];\n if (!item) continue;\n\n const rowIndex = Math.floor(index / columnCount);\n const columnIndex = index % columnCount;\n\n result.push({\n item,\n index,\n columnIndex,\n rowIndex,\n style: {\n position: 'absolute' as const,\n top: rowIndex * pitch,\n left: columnIndex * (computedColumnWidth + gap),\n width: computedColumnWidth,\n height: rowHeight,\n },\n });\n }\n\n return result;\n }, [items, scrollTop, height, overscan, rowCount, columnCount, rowHeight, gap, computedColumnWidth]);\n\n return { totalHeight, visibleItems, handleScroll };\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/utility/InfiniteScroll/InfiniteScroll.tsx"],"sourcesContent":["import Box from '@mui/material/Box/index.js';\nimport React from 'react';\n\nimport { useLoadMore, useSentinel } from './InfiniteScroll.hooks';\nimport {\n containerStyles,\n DefaultEndMessage,\n DefaultError,\n DefaultLoader,\n} from './InfiniteScroll.parts';\nimport type { InfiniteScrollProps } from './InfiniteScroll.types';\n\nexport const InfiniteScroll: React.FC<InfiniteScrollProps> = ({\n children,\n variant = 'default',\n hasMore,\n loading,\n threshold = 150,\n loadMore,\n loader,\n loadingText,\n endText,\n endMessage,\n error,\n errorComponent,\n onError,\n className,\n style,\n width,\n scrollableTarget,\n testMode = false,\n testTriggerRef,\n}) => {\n const { sentinelRef, isIntersecting } = useSentinel({ testMode, threshold, scrollableTarget });\n\n useLoadMore({\n hasMore,\n loading,\n error,\n loadMore,\n onError,\n isIntersecting,\n testMode,\n testTriggerRef,\n });\n\n // The tail of the list is one of four things: the end message, an error, a\n // spinner, or the sentinel that asks for the next page.\n const renderSentinel = () => {\n if (!hasMore) return endMessage || <DefaultEndMessage endText={endText} />;\n if (error) return errorComponent || <DefaultError error={error} />;\n if (loading) return loader || <DefaultLoader loadingText={loadingText} />;\n\n return (\n <div\n ref={sentinelRef}\n data-testid=\"infinite-scroll-sentinel\"\n style={{\n height: variant === 'horizontal' ? '100%' : '1px',\n width: variant === 'horizontal' ? '1px' : '100%',\n }}\n />\n );\n };\n\n return (\n <Box\n className={className}\n sx={{\n ...containerStyles(variant, width),\n ...style,\n }}\n >\n {variant === 'reverse' && renderSentinel()}\n\n {variant === 'horizontal' ? (\n <Box sx={{ display: 'flex', flexDirection: 'row' }}>{children}</Box>\n ) : (\n children\n )}\n\n {variant !== 'reverse' && renderSentinel()}\n\n {variant === 'horizontal' && renderSentinel()}\n </Box>\n );\n};\n"],"mappings":";;;;;;;;;;;;AAAA,OAAO,SAAS;AAiDuB,cAiBnC,YAjBmC;AArChC,IAAM,iBAAgD,CAAC;AAAA,EAC5D;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AACF,MAAM;AACJ,QAAM,EAAE,aAAa,eAAe,IAAI,YAAY,EAAE,UAAU,WAAW,iBAAiB,CAAC;AAE7F,cAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAID,QAAM,iBAAiB,MAAM;AAC3B,QAAI,CAAC,QAAS,QAAO,cAAc,oBAAC,qBAAkB,SAAkB;AACxE,QAAI,MAAO,QAAO,kBAAkB,oBAAC,gBAAa,OAAc;AAChE,QAAI,QAAS,QAAO,UAAU,oBAAC,iBAAc,aAA0B;AAEvE,WACE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,eAAY;AAAA,QACZ,OAAO;AAAA,UACL,QAAQ,YAAY,eAAe,SAAS;AAAA,UAC5C,OAAO,YAAY,eAAe,QAAQ;AAAA,QAC5C;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,IAAI;AAAA,QACF,GAAG,gBAAgB,SAAS,KAAK;AAAA,QACjC,GAAG;AAAA,MACL;AAAA,MAEC;AAAA,oBAAY,aAAa,eAAe;AAAA,QAExC,YAAY,eACX,oBAAC,OAAI,IAAI,EAAE,SAAS,QAAQ,eAAe,MAAM,GAAI,UAAS,IAE9D;AAAA,QAGD,YAAY,aAAa,eAAe;AAAA,QAExC,YAAY,gBAAgB,eAAe;AAAA;AAAA;AAAA,EAC9C;AAEJ;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/MapPreview/MapTiles.tsx"],"sourcesContent":["import { alpha, useTheme } from '@mui/material/styles/index.js';\nimport type { FC } from 'react';\nimport React from 'react';\n\nimport { TILE_SIZE } from './mapProjection';\nimport { tileBackground } from './mapSurface';\nimport type { MapType } from './MapPreview.types';\n\n// Two extra rows and columns so panning does not expose an edge.\nconst VISIBLE_TILES = Math.ceil(800 / TILE_SIZE) + 2;\n// Tile coordinates are only legible once the grid is reasonably fine.\nconst LABEL_MIN_ZOOM = 10;\n\nexport interface MapTilesProps {\n origin: { x: number; y: number } | null;\n zoom: number;\n mapType: MapType;\n panOffset: { x: number; y: number };\n}\n\nexport const MapTiles: FC<MapTilesProps> = ({ origin, zoom, mapType, panOffset }) => {\n const theme = useTheme();\n const borderOpacity = theme.palette.mode === 'dark' ? 0.15 : 0.1;\n const background = tileBackground(mapType, theme);\n const half = Math.floor(VISIBLE_TILES / 2);\n\n return (\n <div\n style={{\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: `translate(calc(-50% + ${panOffset.x}px), calc(-50% + ${panOffset.y}px))`,\n width: TILE_SIZE * VISIBLE_TILES,\n height: TILE_SIZE * VISIBLE_TILES,\n display: 'grid',\n gridTemplateColumns: `repeat(${VISIBLE_TILES}, ${TILE_SIZE}px)`,\n gridTemplateRows: `repeat(${VISIBLE_TILES}, ${TILE_SIZE}px)`,\n transition: 'transform 0.1s ease-out',\n }}\n >\n {Array.from({ length: VISIBLE_TILES * VISIBLE_TILES }).map((_, index) => {\n // The grid is centred on the origin tile, so indices run from -half.\n const tileX = (origin?.x || 0) + (index % VISIBLE_TILES) - half;\n const tileY = (origin?.y || 0) + Math.floor(index / VISIBLE_TILES) - half;\n\n return (\n <div\n key={`tile-${tileX}-${tileY}`}\n style={{\n width: TILE_SIZE,\n height: TILE_SIZE,\n border: `1px solid ${alpha(theme.palette.divider, borderOpacity)}`,\n background,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '10px',\n color: alpha(theme.palette.text.secondary, 0.3),\n fontFamily: 'monospace',\n userSelect: 'none',\n }}\n >\n {zoom > LABEL_MIN_ZOOM && `${tileX},${tileY}`}\n </div>\n );\n })}\n </div>\n );\n};\n"],"mappings":";;;;;;;;AAAA,SAAS,OAAO,gBAAgB;AA+CtB;AAtCV,IAAM,gBAAgB,KAAK,KAAK,MAAM,SAAS,IAAI;AAEnD,IAAM,iBAAiB;AAShB,IAAM,WAA8B,CAAC,EAAE,QAAQ,MAAM,SAAS,UAAU,MAAM;AACnF,QAAM,QAAQ,SAAS;AACvB,QAAM,gBAAgB,MAAM,QAAQ,SAAS,SAAS,OAAO;AAC7D,QAAM,aAAa,eAAe,SAAS,KAAK;AAChD,QAAM,OAAO,KAAK,MAAM,gBAAgB,CAAC;AAEzC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,UAAU;AAAA,QACV,KAAK;AAAA,QACL,MAAM;AAAA,QACN,WAAW,yBAAyB,UAAU,CAAC,oBAAoB,UAAU,CAAC;AAAA,QAC9E,OAAO,YAAY;AAAA,QACnB,QAAQ,YAAY;AAAA,QACpB,SAAS;AAAA,QACT,qBAAqB,UAAU,aAAa,KAAK,SAAS;AAAA,QAC1D,kBAAkB,UAAU,aAAa,KAAK,SAAS;AAAA,QACvD,YAAY;AAAA,MACd;AAAA,MAEC,gBAAM,KAAK,EAAE,QAAQ,gBAAgB,cAAc,CAAC,EAAE,IAAI,CAAC,GAAG,UAAU;AAEvE,cAAM,SAAS,QAAQ,KAAK,KAAM,QAAQ,gBAAiB;AAC3D,cAAM,SAAS,QAAQ,KAAK,KAAK,KAAK,MAAM,QAAQ,aAAa,IAAI;AAErE,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,OAAO;AAAA,cACL,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,QAAQ,aAAa,MAAM,MAAM,QAAQ,SAAS,aAAa,CAAC;AAAA,cAChE;AAAA,cACA,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,gBAAgB;AAAA,cAChB,UAAU;AAAA,cACV,OAAO,MAAM,MAAM,QAAQ,KAAK,WAAW,GAAG;AAAA,cAC9C,YAAY;AAAA,cACZ,YAAY;AAAA,YACd;AAAA,YAEC,iBAAO,kBAAkB,GAAG,KAAK,IAAI,KAAK;AAAA;AAAA,UAftC,QAAQ,KAAK,IAAI,KAAK;AAAA,QAgB7B;AAAA,MAEJ,CAAC;AAAA;AAAA,EACH;AAEJ;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/DataGrid/DataGrid.body.tsx"],"sourcesContent":["/**\n * The DataGrid's `<thead>` and `<tbody>`.\n *\n * Split from the shell so each stays inside the size budget and so the\n * virtualization spacers — which are pure layout, not data — sit next to the\n * rows they pad rather than in the middle of the component that owns the paper.\n */\nimport Checkbox from '@mui/material/Checkbox/index.js';\nimport TableBody from '@mui/material/TableBody/index.js';\nimport TableCell from '@mui/material/TableCell/index.js';\nimport TableHead from '@mui/material/TableHead/index.js';\nimport TableRow from '@mui/material/TableRow/index.js';\nimport { useTheme } from '@mui/material/styles/index.js';\nimport type React from 'react';\n\nimport { GridRow, HeaderCell } from './DataGrid.cells';\nimport type { DataGridModel } from './DataGrid.model';\nimport type { DataGridProps } from './DataGrid.types';\n\nexport interface GridSectionProps<T extends Record<string, unknown>> {\n model: DataGridModel<T>;\n props: DataGridProps<T>;\n totalColumns: number;\n}\n\n/** The leading header cells for the selection / expansion columns. */\nfunction HeaderControls<T extends Record<string, unknown>>({\n model,\n props,\n}: GridSectionProps<T>): React.JSX.Element {\n const theme = useTheme();\n const { selection = { mode: 'none' }, expansion, stickyHeader = true } = props;\n const sticky = {\n position: stickyHeader ? ('sticky' as const) : ('static' as const),\n top: 0,\n zIndex: 1,\n backgroundColor: theme.palette.background.paper,\n };\n const total = model.processedRows.length;\n const picked = model.selectedRowIds.length;\n return (\n <>\n {selection.mode !== 'none' && (\n <TableCell padding=\"checkbox\" sx={sticky}>\n {selection.mode === 'multi' && (\n <Checkbox\n indeterminate={picked > 0 && picked < total}\n checked={total > 0 && picked === total}\n onChange={(event) =>\n model.setSelectedRowIds(\n event.target.checked\n ? model.processedRows.map((row, index) => rowIdOf(props, row, index))\n : [],\n )\n }\n inputProps={{ 'aria-label': 'Select all rows' }}\n />\n )}\n </TableCell>\n )}\n {expansion && <TableCell padding=\"checkbox\" sx={sticky} />}\n </>\n );\n}\n\n/** The caller's `getRowId`, or the row's own `id`, or its index. */\nexport function rowIdOf<T extends Record<string, unknown>>(\n props: DataGridProps<T>,\n row: T,\n index: number,\n): string | number {\n if (props.getRowId) return props.getRowId(row, index);\n const candidate = (row as { id?: string | number }).id;\n return candidate ?? index;\n}\n\nexport function GridHeader<T extends Record<string, unknown>>(\n section: GridSectionProps<T>,\n): React.JSX.Element {\n const { model, props } = section;\n const { sorting = {}, stickyHeader = true, headerHeight = 56 } = props;\n const sortable = sorting.mode === 'client' || sorting.mode === 'server';\n return (\n <TableHead data-slot=\"header\">\n <TableRow data-slot=\"header-row\" role=\"row\">\n <HeaderControls {...section} />\n {model.visibleColumns.map((column) => (\n <HeaderCell\n key={column.id}\n column={column}\n sort={model.sortBy.find((entry) => entry.id === column.id)}\n sortable={column.enableSort !== false && sortable}\n stickyHeader={stickyHeader}\n headerHeight={headerHeight}\n onSort={model.onSort}\n />\n ))}\n </TableRow>\n </TableHead>\n );\n}\n\n/** An invisible row standing in for the rows the window is not rendering. */\nfunction Spacer({ height, colSpan }: { height: number; colSpan: number }): React.JSX.Element | null {\n if (height <= 0) return null;\n return (\n <TableRow>\n <TableCell colSpan={colSpan} sx={{ height, border: 'none', p: 0 }} />\n </TableRow>\n );\n}\n\nexport function GridBody<T extends Record<string, unknown>>(\n section: GridSectionProps<T>,\n): React.JSX.Element {\n const { model, props, totalColumns } = section;\n const { start, end } = model.visibleRange;\n const trailing = model.virtualized ? model.processedRows.length - end : 0;\n return (\n <TableBody data-slot=\"body\">\n {model.virtualized ? (\n <Spacer height={start * model.rowHeight} colSpan={totalColumns} />\n ) : null}\n {model.visibleRows.map((row, offset) => {\n const index = model.virtualized ? start + offset : offset;\n const rowId = rowIdOf(props, row, index);\n return (\n <GridRow\n key={rowId}\n row={row}\n index={index}\n rowId={rowId}\n isSelected={model.selectedRowIdsSet.has(rowId)}\n isExpanded={model.expandedRowIdsSet.has(rowId)}\n totalColumns={totalColumns}\n model={model}\n props={props}\n />\n );\n })}\n {model.virtualized ? (\n <Spacer height={trailing * model.rowHeight} colSpan={totalColumns} />\n ) : null}\n </TableBody>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/DataViews/data-views-overflow-costs.ts"],"sourcesContent":["/**\n * WHAT EACH THING ON THE TOOLBAR COSTS, IN PIXELS.\n *\n * The pricing half of the collapse ladder, split from `data-views-overflow` at\n * the file-size gate. Pure arithmetic and constants: no React, no measurement,\n * no decisions. `data-views-overflow` measures the row and spends what this\n * says it has.\n *\n * Every number here is either MEASURED in a browser (and says so) or\n * deliberately generous. Over-pricing sheds one control too early, which the\n * \"Mais\" button absorbs invisibly; under-pricing breaks the line.\n */\nimport type { OverflowField } from \"./data-views-overflow\";\nimport type { RangeValue } from \"./data-views-types\";\n\n/**\n * Rough rendered width of a control, in px.\n *\n * An ESTIMATE from the label text rather than a real measurement, deliberately:\n * measuring the true width needs every control mounted first, and mounting them\n * to decide whether to mount them is the layout thrash this hook exists to\n * avoid. The estimate only has to rank controls and find the cut point — being\n * a few px out moves the cut by at most one control, and the overflow catches it.\n */\nexport function estimateWidth(text: string, extra: number): number {\n /**\n * ~7.6px per character at the toolbar's font size, plus 76px of chrome:\n * horizontal padding, the border, and the dropdown chevron. The chrome used\n * to be 52, which under-priced every control by roughly a chevron's width —\n * six of them then \"fitted\" a row they overflowed, and because they are flex\n * children the row paid for it by squeezing labels to \"D…\" and \"V…\" rather\n * than by shedding a control into the overflow.\n *\n * Deliberately generous: over-pricing sheds one control too early, which the\n * \"Mais\" button absorbs invisibly. Under-pricing breaks the line.\n *\n * The chrome was 76, and generous had turned into wrong. MEASURED on the\n * Pedidos bar: \"Pagamento\" renders at 123px against an estimate of 144, and\n * \"Situação\" at 107 against 137 — every pill over-priced by ~22%, which on a\n * phone is the whole difference between one pill on the bar and none. 56 is\n * still above the ~50 measured, so the slack the comment above asks for is\n * intact; it is just slack rather than a second control's worth of budget.\n */\n return Math.round(text.length * 7.6) + 56 + extra;\n}\n\n/** Is a range bounded at either end? */\nexport function isRangeSet(range: RangeValue | undefined): boolean {\n return Boolean(range && (range.min !== undefined || range.max !== undefined));\n}\n\n/** The label a pill actually renders, which is what decides its width. */\nexport function pillText<T extends Record<string, unknown>>(field: OverflowField<T>, values: string[]): string {\n if (values.length === 0) return field.label;\n if (values.length === 1) {\n const option = field.pill?.options.find((entry) => entry.value === values[0]);\n return `${field.label}: ${option?.label ?? values[0]}`;\n }\n return `${field.label}: ${values.length}`;\n}\n\n/** Fixed toolbar furniture the filters have to fit around, in px. */\nexport const RESERVED = {\n /** The search box never shrinks below this. */\n search: 200,\n /**\n * The \"N de N\" counter.\n *\n * MEASURED at 35px, plus its divider and gap. The old 96 was priced for a\n * counter reading \"1.234 de 5.678\"; a phone shows \"3 de 3\", and charging\n * nearly triple its rendered width came straight out of the filter budget.\n */\n counter: 56,\n /**\n * ONE right-hand control (Exibir, or Exportar) WITH its text label.\n *\n * Priced per control rather than for the pair, because the pair is not what\n * every page renders: \"Exportar\" exists only when the host passes an\n * `exportConfig`, and several pages (Pedidos among them) put their export in\n * the PAGE HEADER instead. Charging 216 there billed the filters for a button\n * that was never on the bar — ~108px of budget spent on nothing, which on a\n * phone is the difference between one filter pill and none.\n */\n displayControl: 108,\n /**\n * The same control as an icon only — step 2 of the ladder.\n *\n * MEASURED at 133px for the PAIR (66 each: a Button's minimum tap target is\n * a good deal wider than the 20px glyph inside it); 70 keeps that total's\n * slack at one control's granularity.\n */\n displayControlCompact: 70,\n /**\n * What step 4 leaves behind: the search as a bare magnifier.\n *\n * MEASURED at 30px on the Pedidos bar (`…-search-all-collapsed`); 38 keeps a\n * tap target's worth of slack over it.\n */\n searchIcon: 38,\n /**\n * The narrowest keyword box still worth typing into — below it the operator\n * cannot read back what they wrote, and the box takes over the cluster\n * instead of sharing it (see `searchTakeover`).\n *\n * 120 rather than 140 because this is compared against the ESTIMATE, which\n * over-prices on purpose (see `estimateWidth`). At 140 a large phone took the\n * whole cluster to produce a box barely wider than the one it could have had\n * while keeping its filters — paying for nothing.\n */\n usableSearch: 120,\n /**\n * The \"Mais\" button, only charged when there IS an overflow — and priced by\n * the state it is actually in, like the right-hand cluster beside it.\n *\n * MEASURED: 128px with its label, badge and chevron; 69px once the ladder has\n * it down to icon + badge. One number for both was wrong in BOTH directions —\n * it under-priced the wide bar (the row's own failure mode) and over-priced\n * the narrow one by a whole pill.\n */\n overflowButton: 136,\n overflowButtonCompact: 80,\n /**\n * \"Limpar\", only charged when there IS something to clear.\n *\n * It appears exactly when the row is at its widest — every applied filter\n * has a longer label than the idle one it replaced — so leaving it unpriced\n * would break the line at the one moment the operator most needs it.\n * Measured at 64 as an icon; 72 with slack.\n */\n clearAll: 72,\n /**\n * The row's own padding, plus the gaps BETWEEN the fixed furniture.\n *\n * Not the per-control gaps — `splitFilters` already adds a `GAP` for every\n * filter it keeps, so counting a fourth one here charged one gap twice.\n * MEASURED: 32px of padding (16 each side) + three 8px gaps between the\n * search, the counter and the right cluster.\n */\n chrome: 56,\n} as const;\n\n/** The gap between two controls. */\nexport const GAP = 8;\n\n/** What the right-hand cluster costs, given what the host actually renders. */\nexport function rightClusterCost(hasExport: boolean, compact: boolean): number {\n const one = compact ? RESERVED.displayControlCompact : RESERVED.displayControl;\n return hasExport ? one * 2 : one;\n}\n\n/**\n * What the toolbar furniture costs at a given rung of the ladder — the budget\n * the filter controls have to fit AROUND.\n *\n * This exists because the two halves used to disagree. `splitFilters` priced\n * the furniture at its widest (search 200 + counter 96 + right 216) and shed\n * every filter to make room; the ladder then collapsed those very controls to\n * 44 + 0 + 140 and nobody handed the ~330px back. On a 428px phone that showed\n * as a bar carrying a magnifier, a \"Mais 5\" pill, and a band of nothing.\n */\nexport function furnitureCost(\n flags: { searchCollapsed: boolean; counterHidden: boolean; compactControls: boolean },\n hasExport: boolean,\n): number {\n return (\n (flags.searchCollapsed ? RESERVED.searchIcon : RESERVED.search) +\n (flags.counterHidden ? 0 : RESERVED.counter) +\n rightClusterCost(hasExport, flags.compactControls) +\n RESERVED.chrome\n );\n}\n"],"mappings":";AAwBO,SAAS,cAAc,MAAc,OAAuB;AAmBjE,SAAO,KAAK,MAAM,KAAK,SAAS,GAAG,IAAI,KAAK;AAC9C;AAGO,SAAS,WAAW,OAAwC;AACjE,SAAO,QAAQ,UAAU,MAAM,QAAQ,UAAa,MAAM,QAAQ,OAAU;AAC9E;AAGO,SAAS,SAA4C,OAAyB,QAA0B;AAC7G,MAAI,OAAO,WAAW,EAAG,QAAO,MAAM;AACtC,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,SAAS,MAAM,MAAM,QAAQ,KAAK,CAAC,UAAU,MAAM,UAAU,OAAO,CAAC,CAAC;AAC5E,WAAO,GAAG,MAAM,KAAK,KAAK,QAAQ,SAAS,OAAO,CAAC,CAAC;AAAA,EACtD;AACA,SAAO,GAAG,MAAM,KAAK,KAAK,OAAO,MAAM;AACzC;AAGO,IAAM,WAAW;AAAA;AAAA,EAEtB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQR,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWT,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhB,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOvB,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWZ,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUd,gBAAgB;AAAA,EAChB,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASvB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASV,QAAQ;AACV;AAGO,IAAM,MAAM;AAGZ,SAAS,iBAAiB,WAAoB,SAA0B;AAC7E,QAAM,MAAM,UAAU,SAAS,wBAAwB,SAAS;AAChE,SAAO,YAAY,MAAM,IAAI;AAC/B;AAYO,SAAS,cACd,OACA,WACQ;AACR,UACG,MAAM,kBAAkB,SAAS,aAAa,SAAS,WACvD,MAAM,gBAAgB,IAAI,SAAS,WACpC,iBAAiB,WAAW,MAAM,eAAe,IACjD,SAAS;AAEb;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/utility/VirtualList/VirtualList.tsx"],"sourcesContent":["import Box from '@mui/material/Box/index.js';\nimport React, { useRef } from 'react';\n\nimport { useVirtualGrid, useVirtualList } from './VirtualList.hooks';\nimport type { VirtualGridProps, VirtualListProps } from './VirtualList.types';\n\ninterface ContainerProps {\n children: React.ReactNode;\n role: 'list' | 'grid';\n totalHeight: number;\n height: number;\n width: number | string;\n disableInternalScroll: boolean;\n onScroll: (event: React.UIEvent<HTMLDivElement>) => void;\n className?: string;\n style?: React.CSSProperties;\n dataTestId?: string;\n ariaLabel?: string;\n}\n\n/**\n * Two shapes, shared by the list and the grid: when the caller owns the scroll\n * container we render only the full-height content, so their element does the\n * scrolling; otherwise we render our own viewport around it.\n */\nconst VirtualContainer: React.FC<ContainerProps> = ({\n children,\n role,\n totalHeight,\n height,\n width,\n disableInternalScroll,\n onScroll,\n className,\n style,\n dataTestId,\n ariaLabel,\n}) => {\n const internalContainerRef = useRef<HTMLDivElement>(null);\n const identity = {\n className,\n 'data-testid': dataTestId,\n role,\n 'aria-label': ariaLabel,\n };\n\n if (disableInternalScroll) {\n return (\n <Box {...identity} sx={{ height: totalHeight, width, position: 'relative', ...style }}>\n {children}\n </Box>\n );\n }\n\n return (\n <Box\n ref={internalContainerRef}\n {...identity}\n sx={{ height, width, overflow: 'auto', position: 'relative', ...style }}\n onScroll={onScroll}\n >\n <Box sx={{ height: totalHeight, position: 'relative' }}>{children}</Box>\n </Box>\n );\n};\n\nexport const VirtualList: React.FC<VirtualListProps> = ({\n items,\n variant = 'fixed',\n height,\n width = '100%',\n itemHeight = 40,\n estimatedItemHeight = 40,\n overscan = 5,\n renderItem,\n onScroll,\n className,\n style,\n 'data-testid': dataTestId,\n 'aria-label': ariaLabel,\n scrollContainerRef,\n disableInternalScroll = false,\n}) => {\n const { totalHeight, visibleItems, handleScroll } = useVirtualList({\n items,\n variant,\n height,\n itemHeight,\n estimatedItemHeight,\n overscan,\n onScroll,\n scrollContainerRef,\n });\n\n return (\n <VirtualContainer\n role=\"list\"\n totalHeight={totalHeight}\n height={height}\n width={width}\n disableInternalScroll={disableInternalScroll}\n onScroll={handleScroll}\n className={className}\n style={style}\n dataTestId={dataTestId}\n ariaLabel={ariaLabel}\n >\n {visibleItems.map(({ item, index, style: itemStyle }) =>\n renderItem({ item, index, style: itemStyle }),\n )}\n </VirtualContainer>\n );\n};\n\nexport const VirtualGrid: React.FC<VirtualGridProps> = ({\n items,\n height,\n width = '100%',\n columnCount,\n rowHeight,\n columnWidth,\n gap = 0,\n overscan = 5,\n renderItem,\n onScroll,\n className,\n style,\n 'data-testid': dataTestId,\n 'aria-label': ariaLabel,\n scrollContainerRef,\n disableInternalScroll = false,\n}) => {\n const { totalHeight, visibleItems, handleScroll } = useVirtualGrid({\n items,\n height,\n width,\n columnCount,\n rowHeight,\n columnWidth,\n gap,\n overscan,\n onScroll,\n scrollContainerRef,\n });\n\n return (\n <VirtualContainer\n role=\"grid\"\n totalHeight={totalHeight}\n height={height}\n width={width}\n disableInternalScroll={disableInternalScroll}\n onScroll={handleScroll}\n className={className}\n style={style}\n dataTestId={dataTestId}\n ariaLabel={ariaLabel}\n >\n {visibleItems.map(({ item, index, columnIndex, rowIndex, style: itemStyle }) =>\n renderItem({ item, index, columnIndex, rowIndex, style: itemStyle }),\n )}\n </VirtualContainer>\n );\n};\n"],"mappings":";;;;;;AAAA,OAAO,SAAS;AAChB,SAAgB,cAAc;AA+CxB;AAvBN,IAAM,mBAA6C,CAAC;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,uBAAuB,OAAuB,IAAI;AACxD,QAAM,WAAW;AAAA,IACf;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA,cAAc;AAAA,EAChB;AAEA,MAAI,uBAAuB;AACzB,WACE,oBAAC,OAAK,GAAG,UAAU,IAAI,EAAE,QAAQ,aAAa,OAAO,UAAU,YAAY,GAAG,MAAM,GACjF,UACH;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACJ,GAAG;AAAA,MACJ,IAAI,EAAE,QAAQ,OAAO,UAAU,QAAQ,UAAU,YAAY,GAAG,MAAM;AAAA,MACtE;AAAA,MAEA,8BAAC,OAAI,IAAI,EAAE,QAAQ,aAAa,UAAU,WAAW,GAAI,UAAS;AAAA;AAAA,EACpE;AAEJ;AAEO,IAAM,cAA0C,CAAC;AAAA,EACtD;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,sBAAsB;AAAA,EACtB,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,cAAc;AAAA,EACd;AAAA,EACA,wBAAwB;AAC1B,MAAM;AACJ,QAAM,EAAE,aAAa,cAAc,aAAa,IAAI,eAAe;AAAA,IACjE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAEC,uBAAa;AAAA,QAAI,CAAC,EAAE,MAAM,OAAO,OAAO,UAAU,MACjD,WAAW,EAAE,MAAM,OAAO,OAAO,UAAU,CAAC;AAAA,MAC9C;AAAA;AAAA,EACF;AAEJ;AAEO,IAAM,cAA0C,CAAC;AAAA,EACtD;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,cAAc;AAAA,EACd;AAAA,EACA,wBAAwB;AAC1B,MAAM;AACJ,QAAM,EAAE,aAAa,cAAc,aAAa,IAAI,eAAe;AAAA,IACjE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAEC,uBAAa;AAAA,QAAI,CAAC,EAAE,MAAM,OAAO,aAAa,UAAU,OAAO,UAAU,MACxE,WAAW,EAAE,MAAM,OAAO,aAAa,UAAU,OAAO,UAAU,CAAC;AAAA,MACrE;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/Table/Table.helpers.ts"],"sourcesContent":["import type { TableProps } from './Table.types';\n\nexport const TABLE_DEFAULTS: Partial<TableProps> = {\n variant: 'default',\n stripeColor: 'neutral',\n glow: false,\n pulse: false,\n hoverable: false,\n loading: false,\n density: 'normal',\n stickyHeader: false,\n selectable: false,\n selectedRows: [],\n sortable: false,\n virtualScrolling: false,\n rowHeight: 52,\n overscan: 5,\n responsive: false,\n showColumnToggle: true,\n};\n\n// Strips explicitly-undefined props before the merge, so `prop={undefined}` still\n// falls back to the default as a destructuring default would. Eighteen separate\n// destructuring defaults were most of this component's branch count.\nexport const definedProps = (props: TableProps): Partial<TableProps> =>\n Object.fromEntries(\n Object.entries(props).filter(([, value]) => value !== undefined),\n ) as Partial<TableProps>;\n\n// The container + styled table + optional header, shared by the loading, empty\n// and populated renders.\n"],"mappings":";AAEO,IAAM,iBAAsC;AAAA,EACjD,SAAS;AAAA,EACT,aAAa;AAAA,EACb,MAAM;AAAA,EACN,OAAO;AAAA,EACP,WAAW;AAAA,EACX,SAAS;AAAA,EACT,SAAS;AAAA,EACT,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,cAAc,CAAC;AAAA,EACf,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,WAAW;AAAA,EACX,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,kBAAkB;AACpB;AAKO,IAAM,eAAe,CAAC,UAC3B,OAAO;AAAA,EACL,OAAO,QAAQ,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,MAAS;AACjE;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/layout/Resizable/Resizable.hooks.ts"],"sourcesContent":["import React, { useCallback, useRef, useState } from 'react';\n\nimport type { Bounds } from './Resizable.helpers';\nimport { resizedTo } from './Resizable.helpers';\nimport type { ResizeHandle } from './Resizable.types';\n\ninterface ResizeArgs {\n width: number;\n height: number;\n bounds: Bounds;\n disabled: boolean;\n onResize?: (width: number, height: number) => void;\n}\n\n/**\n * Tracks the box's size across a drag. The listeners live on the document rather\n * than the handle, so the pointer can leave the handle — or the component — mid\n * drag without the resize sticking.\n */\nexport const useResize = ({ width, height, bounds, disabled, onResize }: ResizeArgs) => {\n const [size, setSize] = useState({ width, height });\n const [isResizing, setIsResizing] = useState(false);\n const startPos = useRef({ x: 0, y: 0 });\n const startSize = useRef({ width: 0, height: 0 });\n const activeHandle = useRef<ResizeHandle | null>(null);\n\n React.useEffect(() => {\n setSize({ width, height });\n }, [width, height]);\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent, handle: ResizeHandle) => {\n if (disabled) return;\n\n e.preventDefault();\n e.stopPropagation();\n\n setIsResizing(true);\n activeHandle.current = handle;\n startPos.current = { x: e.clientX, y: e.clientY };\n startSize.current = { width: size.width, height: size.height };\n\n const handleMouseMove = (move: globalThis.MouseEvent) => {\n const delta = {\n x: move.clientX - startPos.current.x,\n y: move.clientY - startPos.current.y,\n };\n const next = resizedTo(handle, delta, startSize.current, bounds);\n\n setSize(next);\n onResize?.(next.width, next.height);\n };\n\n const handleMouseUp = () => {\n setIsResizing(false);\n activeHandle.current = null;\n document.removeEventListener('mousemove', handleMouseMove);\n document.removeEventListener('mouseup', handleMouseUp);\n };\n\n document.addEventListener('mousemove', handleMouseMove);\n document.addEventListener('mouseup', handleMouseUp);\n },\n [disabled, size, bounds, onResize],\n );\n\n return { size, isResizing, activeHandle, handleMouseDown };\n};\n"],"mappings":";;;;;AAAA,OAAO,SAAS,aAAa,QAAQ,gBAAgB;AAmB9C,IAAM,YAAY,CAAC,EAAE,OAAO,QAAQ,QAAQ,UAAU,SAAS,MAAkB;AACtF,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,EAAE,OAAO,OAAO,CAAC;AAClD,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAClD,QAAM,WAAW,OAAO,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC;AACtC,QAAM,YAAY,OAAO,EAAE,OAAO,GAAG,QAAQ,EAAE,CAAC;AAChD,QAAM,eAAe,OAA4B,IAAI;AAErD,QAAM,UAAU,MAAM;AACpB,YAAQ,EAAE,OAAO,OAAO,CAAC;AAAA,EAC3B,GAAG,CAAC,OAAO,MAAM,CAAC;AAElB,QAAM,kBAAkB;AAAA,IACtB,CAAC,GAAqB,WAAyB;AAC7C,UAAI,SAAU;AAEd,QAAE,eAAe;AACjB,QAAE,gBAAgB;AAElB,oBAAc,IAAI;AAClB,mBAAa,UAAU;AACvB,eAAS,UAAU,EAAE,GAAG,EAAE,SAAS,GAAG,EAAE,QAAQ;AAChD,gBAAU,UAAU,EAAE,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO;AAE7D,YAAM,kBAAkB,CAAC,SAAgC;AACvD,cAAM,QAAQ;AAAA,UACZ,GAAG,KAAK,UAAU,SAAS,QAAQ;AAAA,UACnC,GAAG,KAAK,UAAU,SAAS,QAAQ;AAAA,QACrC;AACA,cAAM,OAAO,UAAU,QAAQ,OAAO,UAAU,SAAS,MAAM;AAE/D,gBAAQ,IAAI;AACZ,mBAAW,KAAK,OAAO,KAAK,MAAM;AAAA,MACpC;AAEA,YAAM,gBAAgB,MAAM;AAC1B,sBAAc,KAAK;AACnB,qBAAa,UAAU;AACvB,iBAAS,oBAAoB,aAAa,eAAe;AACzD,iBAAS,oBAAoB,WAAW,aAAa;AAAA,MACvD;AAEA,eAAS,iBAAiB,aAAa,eAAe;AACtD,eAAS,iBAAiB,WAAW,aAAa;AAAA,IACpD;AAAA,IACA,CAAC,UAAU,MAAM,QAAQ,QAAQ;AAAA,EACnC;AAEA,SAAO,EAAE,MAAM,YAAY,cAAc,gBAAgB;AAC3D;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/DataViews/data-views-layout-context.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from \"react\";\n\nimport GridViewOutlinedIcon from \"@mui/icons-material/GridViewOutlined\";\n\nimport { Slider } from \"../../form/Slider\";\nimport { Box } from \"../../../mui/Box\";\n\nimport { useDataViewsCopy } from \"./data-views-copy-context\";\nimport { DATA_VIEWS_LAYOUTS, type DataViewsLayout } from \"./data-views-types\";\n\n/**\n * The DataViews layout (view type): the dense \"Tabela\" grid, the \"Grade\" of\n * cards, the \"Lista\" of full-width rows, or the \"Quadro\" board of state columns.\n * Shared across the toolbar (the toggle) and the body (the selector) via context\n * so a single source of truth drives what renders — each layout only appears\n * when the table opts into it (`renderCard` for the grade, `renderListRow` for\n * the lista, `board` + `renderCard` for the quadro).\n */\nexport type { DataViewsLayout };\n\ninterface DataViewsLayoutValue {\n layout: DataViewsLayout;\n setLayout: (layout: DataViewsLayout) => void;\n /** How much air each record gets — see {@link DataViewsDensity}. */\n density: DataViewsDensity;\n setDensity: (density: DataViewsDensity) => void;\n /** Whether the cards layout is available (a `renderCard` was supplied). */\n canUseCards: boolean;\n /** Whether the list layout is available (a `renderListRow` was supplied). */\n canUseList: boolean;\n /** Whether the board layout is available (a `board` config AND a `renderCard`). */\n canUseBoard: boolean;\n /** Card-size zoom (0–100); drives the card grid's min column width. */\n zoom: number;\n setZoom: (zoom: number) => void;\n}\n\nconst DataViewsLayoutContext = createContext<DataViewsLayoutValue | null>(null);\n\n/** Default card zoom (0–100). */\nconst DEFAULT_ZOOM = 35;\n/** The card's width in px at scale 1 — the zoom slider multiplies this. */\nconst BASE_CARD_WIDTH = 180;\n/** The size multiplier the zoom slider spans (0.75× to 2×). */\nconst CARD_SCALE_RANGE = { min: 0.75, max: 2 } as const;\n\n/**\n * Where the user's layout preference is remembered. ONE key for every DataViews\n * table in the app, on purpose: picking \"Grade\" on Produtos is a statement about\n * how this operator likes to read lists, not about that one screen. Every other\n * screen that CAN render cards then opens in cards, and one that cannot falls\n * back without forgetting the preference.\n */\nconst LAYOUT_STORAGE_KEY = \"dataviews:layout\";\n\n/**\n * The density preference, remembered app-wide for the same reason as the layout:\n * an operator who wants tight rows wants them on every list, not on one.\n */\nconst DENSITY_STORAGE_KEY = \"dataviews:density\";\n\n/**\n * How much room each record gets. It means different things per layout, and\n * that is the point — one control, phrased in the terms of what is on screen:\n *\n * - table / list → row height (\"Baixa / Média / Alta\")\n * - cards → how many fit per row (\"Muitos / Médio / Poucos\")\n *\n * The board is unaffected: its cards are already sized by the zoom slider.\n */\nexport type DataViewsDensity = \"compact\" | \"cozy\" | \"comfortable\";\n\n/** Every density this build knows — the guard's single source. */\nconst DENSITIES: readonly DataViewsDensity[] = [\"compact\", \"cozy\", \"comfortable\"];\n\n/** Vertical padding (theme spacing units) per density, for a table or list row. */\nexport const DENSITY_ROW_PADDING: Record<DataViewsDensity, number> = {\n compact: 0.25,\n cozy: 0.75,\n comfortable: 1.5,\n};\n\n/**\n * The card WIDTH each density aims for, as a multiple of the base card width.\n *\n * Density used to cap the column COUNT, with a track floor of\n * `max(baseWidth, 100% / count)`. That base is a constant, so wherever it won\n * the arithmetic every density produced an identical track — \"Muitos\" and\n * \"Medio\" both drew 3 cards of 279px at md — and where the percentage won\n * instead, on a wide screen, the count was pinned and each card grew to a share\n * of the viewport: ~430px of card holding one chip and two lines of text.\n *\n * One width per density fixes both, because the number `auto-fill` divides by\n * now differs per density at every size. The spread is chosen so the three land\n * on DIFFERENT column counts across the range rather than by eye — 4/3/2 at md,\n * 6/4/3 at lg, 7/5/4 at xl, 13/9/8 at 2560.\n */\nexport const DENSITY_CARD_SCALE: Record<DataViewsDensity, number> = {\n compact: 0.84,\n cozy: 1.15,\n comfortable: 1.4,\n};\n\n/** The width a card aims for: the base width, scaled by zoom, then by density. */\nexport function cardTargetWidthFor(zoom: number, density: DataViewsDensity): number {\n return Math.round(cardMinWidthForZoom(zoom) * DENSITY_CARD_SCALE[density]);\n}\n\n/**\n * The BOARD's column-width multiplier per density.\n *\n * Density means \"how much air a record gets\", and on a board that is the column\n * width — narrow columns fit more etapas on screen, wide ones give each card\n * room to be read. Without this the board was the one layout the Exibição tab\n * offered nothing for: the format tile switched to Quadro and the whole density\n * section vanished, which reads as a control that broke rather than one that\n * does not apply.\n *\n * The spread is deliberately narrower than the card grid's. A board column has\n * a hard floor (`MIN_COLUMN_WIDTH` — a card below it stops being readable), so\n * a multiplier that undershoots it buys nothing and makes \"Estreita\" a tile\n * that does nothing on a phone.\n */\nexport const DENSITY_BOARD_SCALE: Record<DataViewsDensity, number> = {\n compact: 0.95,\n cozy: 1,\n comfortable: 1.25,\n};\n\n/**\n * Map the 0–100 zoom to the card SIZE multiplier. This is the single knob: the\n * card's width is {@link BASE_CARD_WIDTH} × scale and its padding + typography\n * scale by the same factor, so the whole card grows together (scale 2 → twice\n * the size, proportion preserved by the aspect ratio). Passed to a card via\n * `DataViewCardSelection.scale`.\n */\nexport function cardScaleForZoom(zoom: number): number {\n const clamped = Math.max(0, Math.min(100, zoom));\n return CARD_SCALE_RANGE.min + (clamped / 100) * (CARD_SCALE_RANGE.max - CARD_SCALE_RANGE.min);\n}\n\n/** The card grid's min column width in px = base width × the zoom size multiplier. */\nexport function cardMinWidthForZoom(zoom: number): number {\n return Math.round(BASE_CARD_WIDTH * cardScaleForZoom(zoom));\n}\n\n/** Which layouts this table can actually render. */\ninterface LayoutAvailability {\n canUseCards: boolean;\n canUseList: boolean;\n canUseBoard: boolean;\n}\n\n/** Is this a layout string this build knows? Guards whatever is in storage. */\nfunction isLayout(value: unknown): value is DataViewsLayout {\n return DATA_VIEWS_LAYOUTS.includes(value as DataViewsLayout);\n}\n\n/** Is this a density this build knows? Guards whatever is in storage. */\nfunction isDensity(value: unknown): value is DataViewsDensity {\n return DENSITIES.includes(value as DataViewsDensity);\n}\n\n/** The remembered density, or undefined (no window, no value, junk). */\nfunction readStoredDensity(): DataViewsDensity | undefined {\n try {\n if (typeof window === \"undefined\") return undefined;\n const stored = window.localStorage.getItem(DENSITY_STORAGE_KEY);\n return isDensity(stored) ? stored : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Pin a layout to one this table can render. \"Tabela\" is always available, so it\n * is the floor: a page with no `renderCard` never renders a cards body, one with\n * no `renderListRow` never renders a list, and one with no `board` config never\n * renders a board — whatever is stored, saved in a view, or requested.\n */\nfunction pinLayout(layout: DataViewsLayout, available: LayoutAvailability): DataViewsLayout {\n if (layout === \"cards\") return available.canUseCards ? \"cards\" : \"table\";\n if (layout === \"list\") return available.canUseList ? \"list\" : \"table\";\n if (layout === \"board\") return available.canUseBoard ? \"board\" : \"table\";\n return \"table\";\n}\n\n/** The stored cross-screen preference, or undefined (no window, no value, junk). */\nfunction readStoredLayout(): DataViewsLayout | undefined {\n // Guarded rather than assumed: this module is also imported in Node (tests,\n // any SSR host), and a `localStorage` access can throw outright under a\n // restrictive privacy setting — a thrown read must not take the grid with it.\n try {\n if (typeof window === \"undefined\") return undefined;\n const stored = window.localStorage.getItem(LAYOUT_STORAGE_KEY);\n return isLayout(stored) ? stored : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Remember a preference for every other screen. A failed write is not an error. */\nfunction writeStored(key: string, value: string): void {\n try {\n if (typeof window === \"undefined\") return;\n window.localStorage.setItem(key, value);\n } catch {\n // Private mode / quota / disabled storage: the preference simply does not\n // survive the session. Nothing about the current view depends on it.\n }\n}\n\ninterface LayoutProviderProps extends Partial<LayoutAvailability> {\n /** Which layout to show first when the user has expressed no preference. */\n defaultLayout?: DataViewsLayout;\n /**\n * The layout an APPLIED SAVED VIEW pins, when it stored one. It wins over the\n * remembered preference for as long as that view is applied — the view is a\n * snapshot someone chose to keep — but it does NOT overwrite the preference:\n * only the toggle does that, because only the toggle is the user saying so.\n */\n viewLayout?: DataViewsLayout;\n /**\n * Ignore — and stop writing — the remembered cross-screen preference, making\n * `defaultLayout` authoritative for this table.\n *\n * For a table that exists to SHOW a particular layout rather than to be\n * browsed: a Storybook story called \"Board\", a docs example, a screenshot\n * harness. Without it the remembered preference wins, so opening \"Board\"\n * after having clicked Tabela anywhere renders a table — the demonstration\n * silently showing the wrong thing, and a shared link doing it for everyone\n * whose preference differs.\n *\n * A real screen leaves this off: remembering how someone likes to read\n * lists is the point.\n */\n ignoreStoredLayout?: boolean;\n children: ReactNode;\n}\n\n/**\n * Provides the view-type state, seeded from (in order) the applied saved view's\n * layout, the user's remembered cross-screen preference, then `defaultLayout` —\n * each pinned to what this table can actually render.\n */\nexport function DataViewsLayoutProvider({\n canUseCards = false,\n canUseList = false,\n canUseBoard = false,\n defaultLayout = \"table\",\n viewLayout,\n ignoreStoredLayout = false,\n children,\n}: LayoutProviderProps): React.JSX.Element {\n const availability = { canUseCards, canUseList, canUseBoard };\n const [layout, setLayoutState] = useState<DataViewsLayout>(() =>\n pinLayout(\n viewLayout ?? (ignoreStoredLayout ? undefined : readStoredLayout()) ?? defaultLayout,\n availability,\n ),\n );\n const [density, setDensityState] = useState<DataViewsDensity>(\n () => (ignoreStoredLayout ? undefined : readStoredDensity()) ?? \"cozy\",\n );\n const [zoom, setZoom] = useState(DEFAULT_ZOOM);\n // A newly applied view carrying a layout switches to it (its reference-change\n // is the signal, exactly as `appliedState` works for the filters).\n useEffect(() => {\n if (viewLayout) setLayoutState(pinLayout(viewLayout, availability));\n // Availability is derived from props that do not change for a mounted table.\n }, [viewLayout]);\n // Pin again on read: `canUseCards`/`canUseBoard` can flip for a mounted table\n // (a page that supplies `renderCard` only once its card data has loaded), and\n // a stale \"cards\" would otherwise render a cards body with no renderer.\n const effective = pinLayout(layout, availability);\n\n const value = useMemo<DataViewsLayoutValue>(\n () => ({\n layout: effective,\n setLayout: (next: DataViewsLayout) => {\n const pinned = pinLayout(next, availability);\n setLayoutState(pinned);\n // Remember the user's own choice across every screen — see LAYOUT_STORAGE_KEY.\n // A table pinned to a layout does not write: it would teach the\n // preference a value the operator never chose.\n if (!ignoreStoredLayout) writeStored(LAYOUT_STORAGE_KEY, pinned);\n },\n density,\n setDensity: (next: DataViewsDensity) => {\n setDensityState(next);\n if (!ignoreStoredLayout) writeStored(DENSITY_STORAGE_KEY, next);\n },\n canUseCards,\n canUseList,\n canUseBoard,\n zoom,\n setZoom,\n }),\n [effective, density, canUseCards, canUseList, canUseBoard, zoom],\n );\n return <DataViewsLayoutContext.Provider value={value}>{children}</DataViewsLayoutContext.Provider>;\n}\n\n/** Read the current DataViews layout. Throws outside a provider. */\nexport function useDataViewsLayout(): DataViewsLayoutValue {\n const ctx = useContext(DataViewsLayoutContext);\n if (!ctx) {\n throw new Error(\"useDataViewsLayout must be used within a DataViewsLayoutProvider\");\n }\n return ctx;\n}\n\n/**\n * Card-size slider for the toolbar — shown in the CARD-BASED layouts (\"Grade\"\n * and \"Quadro\"), mirroring the tabwoah view-selector's zoom. The board reuses\n * the same `renderCard`, so the same knob scales both.\n *\n * Deliberately ABSENT in \"Lista\" and \"Tabela\" (FUT-733): a list row is\n * full-width and sized by its content, so a card-size multiplier has nothing to\n * act on — a slider that moved and changed nothing would be worse than none.\n */\nexport function DataViewsZoomSlider({ testIdPrefix }: { testIdPrefix: string }): React.JSX.Element | null {\n const { layout, zoom, setZoom } = useDataViewsLayout();\n const copy = useDataViewsCopy();\n if (layout !== \"cards\" && layout !== \"board\") return null;\n return (\n <Box\n sx={{\n display: { xs: \"none\", sm: \"flex\" },\n alignItems: \"center\",\n gap: 1,\n color: \"text.secondary\",\n }}\n >\n <GridViewOutlinedIcon sx={{ fontSize: 14 }} />\n <Box sx={{ width: 88, display: \"flex\", alignItems: \"center\" }}>\n <Slider\n size=\"sm\"\n showValue={false}\n value={zoom}\n min={0}\n max={100}\n step={5}\n onChange={(_event, next) => setZoom(Array.isArray(next) ? (next[0] ?? 0) : next)}\n aria-label={copy.display.cardZoom}\n data-testid={`${testIdPrefix}-card-zoom`}\n />\n </Box>\n <GridViewOutlinedIcon sx={{ fontSize: 20 }} />\n </Box>\n );\n}\n"],"mappings":"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","names":["default"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/data-display/DataViews/data-views-grid-helpers.tsx"],"sourcesContent":["\"use client\";\n\nimport type { Theme } from \"@mui/material/styles/index.js\";\n\nimport { useDataViewsCopy } from \"./data-views-copy-context\";\nimport { type GridColumn } from \"../DataGrid\";\nimport { type SortFieldDefinition } from \"../../layout/ContentToolbar\";\nimport { Box } from \"../../../mui/Box\";\nimport { rem, sxRem } from \"../../../tokens/relative\";\nimport { Button } from \"../../form/Button\";\nimport { DropdownMenu, type DropdownMenuItem } from \"../../navigation/DropdownMenu\";\n\nimport type {\n DataViewColumn,\n DataViewState,\n FilterFieldConfig,\n RangeFieldConfig,\n RowAction,\n} from \"./data-views-types\";\n\n/** Is this the non-clickable actions column? */\nexport function isActionsColumn<T extends Record<string, unknown>>(col: GridColumn<T>): boolean {\n return col.type === \"actions\" || col.id === \"actions\";\n}\n\n/**\n * Map the DataView columns to grid columns, applying visibility and — when a row\n * click handler is present — wrapping each non-actions cell so clicking opens the row.\n */\nexport function buildGridColumns<T extends Record<string, unknown>>(\n columns: DataViewColumn<T>[],\n visibleColumns: string[],\n onRowClick: ((row: T) => void) | undefined,\n): GridColumn<T>[] {\n return columns.map((col) => {\n const hidden = col.hideable !== false && !visibleColumns.includes(col.id);\n if (!onRowClick || isActionsColumn(col)) return { ...col, hidden };\n return {\n ...col,\n hidden,\n cell: (ctx) => {\n const content = col.cell ? col.cell(ctx) : ctx.value == null ? \"\" : String(ctx.value);\n return (\n <Box\n onClick={() => onRowClick(ctx.row)}\n sx={{ cursor: \"pointer\", width: \"100%\", height: \"100%\", display: \"flex\", alignItems: \"center\" }}\n >\n {content}\n </Box>\n );\n },\n };\n });\n}\n\ninterface ActionsColumnConfig<T extends Record<string, unknown>> {\n /** Actions that build the auto \"⋮\" kebab. Ignored when `renderRowMenu` is set. */\n rowActions: RowAction<T>[];\n /** Optional leading slot (e.g. a favourite star) rendered before the kebab. */\n leading?: (row: T) => React.ReactNode;\n testIdPrefix: string;\n getRowId: (row: T) => string | number;\n /**\n * Escape hatch: render a bespoke per-row menu (e.g. an entity's self-contained\n * 3-dots menu that owns its own popups) INSTEAD of the auto kebab built from\n * `rowActions`. This is how the table row and the card share ONE menu component.\n * `rowActions`/`bulkActions` still drive the multi-row bulk menu, which a\n * single-row menu intentionally does not replace.\n */\n renderRowMenu?: (row: T) => React.ReactNode;\n}\n\n/**\n * The auto \"⋮\" kebab actions column built from the reusable `rowActions` — the\n * SAME definitions that feed the bulk menu, so the two never drift. Each item\n * acts on just this row; `rowLabel` provides a per-row label when set. An\n * optional `leading` slot (e.g. a favourite star) renders before the kebab.\n * When `renderRowMenu` is supplied, the cell renders that bespoke menu instead.\n */\nexport function buildRowActionsColumn<T extends Record<string, unknown>>(\n config: ActionsColumnConfig<T>,\n): DataViewColumn<T> {\n const { rowActions, leading, testIdPrefix, getRowId, renderRowMenu } = config;\n const kebabActions = rowActions.filter((action) => action.row !== false);\n return {\n id: \"actions\",\n header: \"\",\n type: \"actions\",\n enableSort: false,\n hideable: false,\n // Narrow: the column only holds the \"⋮\" kebab (plus an optional leading icon),\n // so it needs room for just one or two icons.\n width: leading ? 72 : 44,\n cell: ({ row }) => (\n <Box component=\"span\" sx={{ display: \"inline-flex\", alignItems: \"center\", gap: sxRem(2), justifyContent: \"flex-end\" }}>\n {leading?.(row)}\n {renderRowMenu\n ? renderRowMenu(row)\n : renderAutoKebab(kebabActions, row, testIdPrefix, getRowId)}\n </Box>\n ),\n };\n}\n\n/** The built-in kebab menu for one row, derived from `rowActions`. */\nfunction renderAutoKebab<T extends Record<string, unknown>>(\n kebabActions: RowAction<T>[],\n row: T,\n testIdPrefix: string,\n getRowId: (row: T) => string | number,\n): React.ReactNode {\n const copy = useDataViewsCopy();\n const items: DropdownMenuItem[] = kebabActions\n .filter((action) => action.isVisible?.(row) ?? true)\n .map((action) => ({\n id: action.id,\n label: action.rowLabel ? action.rowLabel(row) : action.label,\n color: action.color,\n onClick: () => void action.onSelect([row]),\n }));\n if (items.length === 0) return null;\n return (\n <DropdownMenu\n size=\"sm\"\n items={items}\n trigger={\n <Button variant=\"text\" size=\"sm\" dataTestId={`${testIdPrefix}-actions-${getRowId(row)}`} aria-label={copy.grid.rowActions}>\n ⋮\n </Button>\n }\n />\n );\n}\n\n/** Sort options derived from the sortable columns when a page supplies none. */\nexport function defaultSortFields<T extends Record<string, unknown>>(\n columns: DataViewColumn<T>[],\n): SortFieldDefinition[] {\n return columns\n .filter(\n (col) =>\n col.enableSort !== false &&\n col.type !== \"actions\" &&\n col.id !== \"actions\" &&\n typeof col.header === \"string\" &&\n col.header !== \"\",\n )\n .map((col) => ({\n value: col.id,\n label: col.header as string,\n orderOptions: [\n { value: \"asc\", label: \"Crescente\" },\n { value: \"desc\", label: \"Decrescente\" },\n ],\n }));\n}\n\n/** Count active filters (search + selected pills + bounded ranges) for the badge. */\nexport function computeActiveFilterCount<T extends Record<string, unknown>>(\n state: DataViewState,\n fields: FilterFieldConfig<T>[],\n rangeFields: RangeFieldConfig<T>[],\n): number {\n const ranges = state.ranges ?? {};\n const pillCount = fields.reduce((n, field) => n + ((state.pills[field.id]?.length ?? 0) > 0 ? 1 : 0), 0);\n const rangeCount = rangeFields.reduce((n, field) => {\n const range = ranges[field.id];\n return n + (range && (range.min != null || range.max != null) ? 1 : 0);\n }, 0);\n return (state.search.trim() ? 1 : 0) + pillCount + rangeCount;\n}\n\nfunction bulkMenuItems<T extends Record<string, unknown>>(\n rowActions: RowAction<T>[],\n selectedRows: T[],\n clearSelection: () => void,\n): DropdownMenuItem[] {\n return rowActions\n .filter((action) => action.bulk !== false)\n .map((action) => {\n // State-machine guards: the action runs only on the rows it applies to,\n // and disappears from the menu when none of the selection qualifies.\n const targets = action.isVisible ? selectedRows.filter(action.isVisible) : selectedRows;\n return { action, targets };\n })\n .filter(({ targets }) => targets.length > 0)\n .map(({ action, targets }) => ({\n id: action.id,\n label: action.label,\n color: action.color,\n onClick: () => {\n // Run the (possibly async) handler on the captured selection, then clear\n // it — but only once the work settles. On failure keep the selection so\n // the user can see which rows still need action and retry.\n const result = action.onSelect(targets);\n if (result instanceof Promise) {\n void result.then(\n () => clearSelection(),\n () => {\n /* keep the selection on failure so the user can retry */\n },\n );\n } else {\n clearSelection();\n }\n },\n }));\n}\n\ninterface RenderBulkArgs<T extends Record<string, unknown>> {\n rowActions: RowAction<T>[] | undefined;\n bulkActions: ((selectedRows: T[], clearSelection: () => void) => React.ReactNode) | undefined;\n selectedRows: T[];\n clearSelection: () => void;\n testIdPrefix: string;\n}\n\n/**\n * The selection bulk control shown in the toolbar. Prefers the reusable\n * `rowActions` (an \"Ações\" dropdown mirroring the row kebab); falls back to the\n * low-level `bulkActions` render prop. Renders nothing with no selection.\n */\nexport function renderBulkActions<T extends Record<string, unknown>>({\n rowActions,\n bulkActions,\n selectedRows,\n clearSelection,\n testIdPrefix,\n}: RenderBulkArgs<T>): React.ReactNode {\n const copy = useDataViewsCopy();\n if (selectedRows.length === 0) return undefined;\n if (rowActions) {\n const items = bulkMenuItems(rowActions, selectedRows, clearSelection);\n if (items.length === 0) return undefined;\n return (\n <DropdownMenu\n size=\"sm\"\n items={items}\n trigger={\n <Button variant=\"outline\" size=\"sm\" dataTestId={`${testIdPrefix}-bulk-actions`}>\n {copy.grid.bulkActions(selectedRows.length)}\n </Button>\n }\n />\n );\n }\n return bulkActions ? bulkActions(selectedRows, clearSelection) : undefined;\n}\n\n/** Toggle a single value in a pill's selected-list (returns the next list). */\nexport function togglePillValues(current: string[] | undefined, value: string, checked: boolean): string[] {\n const list = current ?? [];\n return checked ? [...list, value] : list.filter((v) => v !== value);\n}\n\n/**\n * The card grid's `grid-template-columns`, as an sx fragment.\n *\n * One rule at every width: each card asks for `targetWidth` and `auto-fill`\n * decides how many fit. Density moves the target, so it changes the count at\n * every size — which the previous column-count cap could not do, because its\n * track floor bottomed out at a constant shared by all three densities.\n *\n * Below `sm` this is a single column, and no target changes that. That is why\n * the density control hides itself there rather than offering three settings\n * that all draw the same thing.\n */\nexport function cardGridTracks(targetWidth: number) {\n return {\n gridTemplateColumns: (theme: Theme) => ({\n xs: \"1fr\",\n sm: `repeat(auto-fill, minmax(${rem(theme, targetWidth)}, 1fr))`,\n }),\n };\n}\n"],"mappings":"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","names":["default"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/form/Calendar/CalendarMonth.tsx"],"sourcesContent":["import ChevronLeft from '@mui/icons-material/ChevronLeft';\nimport ChevronRight from '@mui/icons-material/ChevronRight';\nimport Box from '@mui/material/Box/index.js';\nimport IconButton from '@mui/material/IconButton/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport type { FC } from 'react';\nimport React from 'react';\n\nimport { getMonthName } from './Calendar.dates';\nimport type { CalendarProps, MonthMatrix } from './Calendar.types';\nimport type { DayCellContext } from './CalendarDayCell';\nimport { CalendarDayCell } from './CalendarDayCell';\n\nconst SPACER_WIDTH = 32;\n\nconst GRID_SX = { display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 0.5 } as const;\n\n// Only the outermost months carry arrows; the ones between get a spacer so their\n// titles stay centred.\nconst MonthNavHeader: FC<{\n title: React.ReactNode;\n showPrevious: boolean;\n showNext: boolean;\n onPreviousMonth: () => void;\n onNextMonth: () => void;\n}> = ({ title, showPrevious, showNext, onPreviousMonth, onNextMonth }) => (\n <Box\n sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}\n data-testid=\"calendar-header\"\n >\n {showPrevious && (\n <IconButton onClick={onPreviousMonth} size=\"small\" data-testid=\"calendar-prev-month\">\n <ChevronLeft />\n </IconButton>\n )}\n\n <Typography\n variant=\"h6\"\n component=\"h2\"\n sx={{ fontWeight: 'bold', flex: 1, textAlign: 'center' }}\n >\n {title}\n </Typography>\n\n {showNext && (\n <IconButton onClick={onNextMonth} size=\"small\" data-testid=\"calendar-next-month\">\n <ChevronRight />\n </IconButton>\n )}\n\n {!showPrevious && !showNext && <Box sx={{ width: SPACER_WIDTH }} />}\n </Box>\n);\n\nconst WeekdayHeader: FC<{ weekdayNames: string[] }> = ({ weekdayNames }) => (\n <Box sx={{ ...GRID_SX, mb: 1 }}>\n {weekdayNames.map((weekday, index) => (\n <Box\n // Narrow weekday names repeat within a week ('S', 'T'), so position is\n // the only stable key here.\n key={`weekday-${index}`}\n role=\"columnheader\"\n data-testid={`calendar-weekday-${index}`}\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: SPACER_WIDTH,\n fontSize: '0.875rem',\n fontWeight: 'bold',\n color: 'text.secondary',\n }}\n >\n {weekday}\n </Box>\n ))}\n </Box>\n);\n\nexport interface CalendarMonthProps {\n matrix: MonthMatrix;\n monthIndex: number;\n monthsToShow: number;\n locale: string;\n weekdayNames: string[];\n renderHeader?: CalendarProps['renderHeader'];\n onPreviousMonth: () => void;\n onNextMonth: () => void;\n dayContext: DayCellContext;\n}\n\nexport const CalendarMonth: FC<CalendarMonthProps> = ({\n matrix,\n monthIndex,\n monthsToShow,\n locale,\n weekdayNames,\n renderHeader,\n onPreviousMonth,\n onNextMonth,\n dayContext,\n}) => {\n const monthName = getMonthName(matrix.month, matrix.year, locale);\n const title = renderHeader ? renderHeader({ month: matrix.month, year: matrix.year }) : monthName;\n\n return (\n /* The month is addressable by its position, because in a multi-month\n calendar every day number appears once PER MONTH — `calendar-date-5` is\n January's 5th and February's. Without a per-month hook a test can only\n reach a day positionally, which is exactly what the flakiness gate\n refuses. Additive: `calendar-grid` below is unchanged. */\n <Box sx={{ minWidth: 280 }} data-testid={`calendar-month-${monthIndex}`}>\n <MonthNavHeader\n title={title}\n showPrevious={monthIndex === 0}\n showNext={monthIndex === monthsToShow - 1}\n onPreviousMonth={onPreviousMonth}\n onNextMonth={onNextMonth}\n />\n\n <WeekdayHeader weekdayNames={weekdayNames} />\n\n <Box\n role=\"grid\"\n aria-labelledby={`month-${monthIndex}`}\n data-testid=\"calendar-grid\"\n sx={GRID_SX}\n >\n {matrix.weeks.flat().map((day) => (\n <CalendarDayCell key={day.key} day={day} {...dayContext} />\n ))}\n </Box>\n </Box>\n );\n};\n"],"mappings":";;;;;;;;AAAA,OAAO,iBAAiB;AACxB,OAAO,kBAAkB;AACzB,OAAO,SAAS;AAChB,OAAO,gBAAgB;AACvB,OAAO,gBAAgB;AAsBrB,SAMM,KANN;AAbF,IAAM,eAAe;AAErB,IAAM,UAAU,EAAE,SAAS,QAAQ,qBAAqB,kBAAkB,KAAK,IAAI;AAInF,IAAM,iBAMD,CAAC,EAAE,OAAO,cAAc,UAAU,iBAAiB,YAAY,MAClE;AAAA,EAAC;AAAA;AAAA,IACC,IAAI,EAAE,SAAS,QAAQ,YAAY,UAAU,gBAAgB,iBAAiB,IAAI,EAAE;AAAA,IACpF,eAAY;AAAA,IAEX;AAAA,sBACC,oBAAC,cAAW,SAAS,iBAAiB,MAAK,SAAQ,eAAY,uBAC7D,8BAAC,eAAY,GACf;AAAA,MAGF;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,WAAU;AAAA,UACV,IAAI,EAAE,YAAY,QAAQ,MAAM,GAAG,WAAW,SAAS;AAAA,UAEtD;AAAA;AAAA,MACH;AAAA,MAEC,YACC,oBAAC,cAAW,SAAS,aAAa,MAAK,SAAQ,eAAY,uBACzD,8BAAC,gBAAa,GAChB;AAAA,MAGD,CAAC,gBAAgB,CAAC,YAAY,oBAAC,OAAI,IAAI,EAAE,OAAO,aAAa,GAAG;AAAA;AAAA;AACnE;AAGF,IAAM,gBAAgD,CAAC,EAAE,aAAa,MACpE,oBAAC,OAAI,IAAI,EAAE,GAAG,SAAS,IAAI,EAAE,GAC1B,uBAAa,IAAI,CAAC,SAAS,UAC1B;AAAA,EAAC;AAAA;AAAA,IAIC,MAAK;AAAA,IACL,eAAa,oBAAoB,KAAK;AAAA,IACtC,IAAI;AAAA,MACF,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,OAAO;AAAA,IACT;AAAA,IAEC;AAAA;AAAA,EAbI,WAAW,KAAK;AAcvB,CACD,GACH;AAeK,IAAM,gBAAwC,CAAC;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,YAAY,aAAa,OAAO,OAAO,OAAO,MAAM,MAAM;AAChE,QAAM,QAAQ,eAAe,aAAa,EAAE,OAAO,OAAO,OAAO,MAAM,OAAO,KAAK,CAAC,IAAI;AAExF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAME,qBAAC,OAAI,IAAI,EAAE,UAAU,IAAI,GAAG,eAAa,kBAAkB,UAAU,IACnE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,cAAc,eAAe;AAAA,UAC7B,UAAU,eAAe,eAAe;AAAA,UACxC;AAAA,UACA;AAAA;AAAA,MACF;AAAA,MAEA,oBAAC,iBAAc,cAA4B;AAAA,MAE3C;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,mBAAiB,SAAS,UAAU;AAAA,UACpC,eAAY;AAAA,UACZ,IAAI;AAAA,UAEH,iBAAO,MAAM,KAAK,EAAE,IAAI,CAAC,QACxB,oBAAC,mBAA8B,KAAW,GAAG,cAAvB,IAAI,GAA+B,CAC1D;AAAA;AAAA,MACH;AAAA,OACF;AAAA;AAEJ;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/utility/InfiniteScroll/InfiniteScroll.hooks.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport type { InfiniteScrollProps } from './InfiniteScroll.types';\n\ntype ScrollableTarget = InfiniteScrollProps['scrollableTarget'];\n\n/** A string target is looked up by id first, then as a selector. */\nconst resolveScrollable = (scrollableTarget: ScrollableTarget): Element | null => {\n if (!scrollableTarget) return null;\n\n if (typeof scrollableTarget === 'string') {\n return (\n document.getElementById(scrollableTarget) || document.querySelector(scrollableTarget)\n );\n }\n\n return scrollableTarget;\n};\n\ninterface ObserverArgs {\n testMode: boolean;\n threshold: number;\n scrollableTarget: ScrollableTarget;\n}\n\n/**\n * Watches a zero-size sentinel at the end of the list. `rootMargin` is what makes\n * it fire before the sentinel is actually on screen, so the next page is already\n * loading by the time the user reaches the bottom.\n */\nexport const useSentinel = ({ testMode, threshold, scrollableTarget }: ObserverArgs) => {\n const sentinelRef = useRef<HTMLDivElement>(null);\n const [isIntersecting, setIsIntersecting] = useState(false);\n\n useEffect(() => {\n if (testMode || !sentinelRef.current) return;\n\n const observer = new window.IntersectionObserver(\n ([entry]) => {\n if (entry) {\n setIsIntersecting(entry.isIntersecting);\n }\n },\n {\n root: resolveScrollable(scrollableTarget) || undefined,\n rootMargin: `${threshold}px`,\n threshold: 0,\n },\n );\n\n observer.observe(sentinelRef.current);\n\n return () => observer.disconnect();\n }, [testMode, threshold, scrollableTarget]);\n\n return { sentinelRef, isIntersecting };\n};\n\ntype LoadArgs = Pick<\n InfiniteScrollProps,\n 'hasMore' | 'loading' | 'error' | 'loadMore' | 'onError' | 'testTriggerRef'\n> & {\n isIntersecting: boolean;\n testMode: boolean;\n};\n\n/**\n * A ref rather than state guards re-entry, so a second intersection landing while\n * the first `loadMore` is still in flight is dropped rather than queued.\n */\nexport const useLoadMore = ({\n hasMore,\n loading,\n error,\n loadMore,\n onError,\n isIntersecting,\n testMode,\n testTriggerRef,\n}: LoadArgs) => {\n const loadingRef = useRef(false);\n\n const handleLoadMore = useCallback(async () => {\n if (loadingRef.current || !hasMore || error) {\n return;\n }\n\n loadingRef.current = true;\n\n try {\n await loadMore();\n } catch (err) {\n const errorObj = err instanceof Error ? err : new Error('Unknown error');\n onError?.(errorObj);\n } finally {\n loadingRef.current = false;\n }\n }, [hasMore, error, loadMore, onError]);\n\n // Expose test trigger for test mode\n useEffect(() => {\n if (testMode && testTriggerRef) {\n testTriggerRef.current = handleLoadMore;\n }\n\n return () => {\n if (testMode && testTriggerRef) {\n testTriggerRef.current = undefined;\n }\n };\n }, [testMode, testTriggerRef, handleLoadMore]);\n\n useEffect(() => {\n if (isIntersecting && hasMore && !loading && !error) {\n handleLoadMore();\n }\n }, [isIntersecting, hasMore, loading, error, handleLoadMore]);\n};\n"],"mappings":";AAAA,SAAS,aAAa,WAAW,QAAQ,gBAAgB;AAOzD,IAAM,oBAAoB,CAAC,qBAAuD;AAChF,MAAI,CAAC,iBAAkB,QAAO;AAE9B,MAAI,OAAO,qBAAqB,UAAU;AACxC,WACE,SAAS,eAAe,gBAAgB,KAAK,SAAS,cAAc,gBAAgB;AAAA,EAExF;AAEA,SAAO;AACT;AAaO,IAAM,cAAc,CAAC,EAAE,UAAU,WAAW,iBAAiB,MAAoB;AACtF,QAAM,cAAc,OAAuB,IAAI;AAC/C,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,KAAK;AAE1D,YAAU,MAAM;AACd,QAAI,YAAY,CAAC,YAAY,QAAS;AAEtC,UAAM,WAAW,IAAI,OAAO;AAAA,MAC1B,CAAC,CAAC,KAAK,MAAM;AACX,YAAI,OAAO;AACT,4BAAkB,MAAM,cAAc;AAAA,QACxC;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM,kBAAkB,gBAAgB,KAAK;AAAA,QAC7C,YAAY,GAAG,SAAS;AAAA,QACxB,WAAW;AAAA,MACb;AAAA,IACF;AAEA,aAAS,QAAQ,YAAY,OAAO;AAEpC,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,UAAU,WAAW,gBAAgB,CAAC;AAE1C,SAAO,EAAE,aAAa,eAAe;AACvC;AAcO,IAAM,cAAc,CAAC;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAgB;AACd,QAAM,aAAa,OAAO,KAAK;AAE/B,QAAM,iBAAiB,YAAY,YAAY;AAC7C,QAAI,WAAW,WAAW,CAAC,WAAW,OAAO;AAC3C;AAAA,IACF;AAEA,eAAW,UAAU;AAErB,QAAI;AACF,YAAM,SAAS;AAAA,IACjB,SAAS,KAAK;AACZ,YAAM,WAAW,eAAe,QAAQ,MAAM,IAAI,MAAM,eAAe;AACvE,gBAAU,QAAQ;AAAA,IACpB,UAAE;AACA,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,SAAS,OAAO,UAAU,OAAO,CAAC;AAGtC,YAAU,MAAM;AACd,QAAI,YAAY,gBAAgB;AAC9B,qBAAe,UAAU;AAAA,IAC3B;AAEA,WAAO,MAAM;AACX,UAAI,YAAY,gBAAgB;AAC9B,uBAAe,UAAU;AAAA,MAC3B;AAAA,IACF;AAAA,EACF,GAAG,CAAC,UAAU,gBAAgB,cAAc,CAAC;AAE7C,YAAU,MAAM;AACd,QAAI,kBAAkB,WAAW,CAAC,WAAW,CAAC,OAAO;AACnD,qBAAe;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,gBAAgB,SAAS,SAAS,OAAO,cAAc,CAAC;AAC9D;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/layout/ScrollArea/ScrollArea.helpers.ts"],"sourcesContent":["import type { ScrollAreaProps } from './ScrollArea.types';\n\ntype ScrollAreaDefaultedKeys =\n | 'width'\n | 'height'\n | 'orientation'\n | 'scrollbarSize'\n | 'autoHide'\n | 'autoHideDelay'\n | 'smoothScroll'\n | 'variant'\n | 'scrollToTopButton'\n | 'scrollToTopThreshold'\n | 'contentPadding'\n | 'alwaysShowScrollbar'\n | 'disabled'\n | 'loading'\n | 'testId';\n\nexport type ResolvedScrollAreaProps = ScrollAreaProps &\n Required<Pick<ScrollAreaProps, ScrollAreaDefaultedKeys>>;\n\nconst SCROLL_AREA_DEFAULTS: Pick<ScrollAreaProps, ScrollAreaDefaultedKeys> = {\n width: '100%',\n height: '100%',\n orientation: 'vertical',\n scrollbarSize: 'medium',\n autoHide: true,\n autoHideDelay: 1000,\n smoothScroll: true,\n variant: 'default',\n scrollToTopButton: false,\n scrollToTopThreshold: 100,\n contentPadding: 0,\n alwaysShowScrollbar: false,\n disabled: false,\n loading: false,\n testId: 'scroll-area',\n};\n\n// Strips explicitly-undefined props before the merge, so `prop={undefined}` still\n// falls back to the default exactly as a destructuring default would. Applied as\n// a merge rather than destructuring defaults, which would otherwise put fifteen\n// branches into the component's own complexity budget.\nexport const resolveScrollAreaProps = (props: ScrollAreaProps): ResolvedScrollAreaProps =>\n ({\n ...SCROLL_AREA_DEFAULTS,\n ...(Object.fromEntries(\n Object.entries(props).filter(([, value]) => value !== undefined),\n ) as Partial<ScrollAreaProps>),\n }) as ResolvedScrollAreaProps;\n"],"mappings":";AAsBA,IAAM,uBAAuE;AAAA,EAC3E,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,eAAe;AAAA,EACf,UAAU;AAAA,EACV,eAAe;AAAA,EACf,cAAc;AAAA,EACd,SAAS;AAAA,EACT,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,UAAU;AAAA,EACV,SAAS;AAAA,EACT,QAAQ;AACV;AAMO,IAAM,yBAAyB,CAAC,WACpC;AAAA,EACC,GAAG;AAAA,EACH,GAAI,OAAO;AAAA,IACT,OAAO,QAAQ,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,MAAS;AAAA,EACjE;AACF;","names":[]}
|