@12-apps/ui 6.13.2 → 6.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components-catalog.md +8 -1
- package/dist/_internal/components/data-display/AsyncStateContainer/AsyncStateContainer.js +4 -4
- package/dist/_internal/components/data-display/Badge/Badge.js +2 -2
- package/dist/_internal/components/data-display/CardKit/use-remove-confirm.js +5 -5
- package/dist/_internal/components/data-display/CardKit/use-row-confirm.js +5 -5
- package/dist/_internal/components/data-display/Carousel/Carousel.js +3 -3
- package/dist/_internal/components/data-display/Chart/Chart.js +4 -4
- package/dist/_internal/components/data-display/Chart/SpecChart.js +8 -8
- package/dist/_internal/components/data-display/Chart/chart-context.js +2 -2
- package/dist/_internal/components/data-display/Chart/chart-renderers.js +3 -3
- package/dist/_internal/components/data-display/Chart/chart-spec.js +2 -2
- package/dist/_internal/components/data-display/DataGrid/DataGrid.js +3 -3
- package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +44 -42
- package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +60 -58
- package/dist/_internal/components/data-display/DataViews/ManageViewsDialog.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 +7 -7
- package/dist/_internal/components/data-display/DataViews/data-views-category-pill.js +13 -13
- package/dist/_internal/components/data-display/DataViews/data-views-display-panel.js +1 -1
- package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +20 -20
- package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +7 -7
- package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +39 -37
- package/dist/_internal/components/data-display/DataViews/data-views-header-row.js +12 -0
- package/dist/_internal/components/data-display/DataViews/data-views-header-row.js.map +1 -0
- package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +20 -20
- package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +7 -7
- package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +8 -8
- package/dist/_internal/components/data-display/DataViews/data-views-range-pill.js +3 -3
- package/dist/_internal/components/data-display/DataViews/data-views-scope-tabs.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-selection-extra.js +8 -0
- package/dist/_internal/components/data-display/DataViews/data-views-selection-extra.js.map +1 -0
- package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +7 -7
- package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +9 -9
- package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +6 -6
- 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 +4 -4
- package/dist/_internal/components/data-display/DataViews/use-saved-views-controller.js +2 -2
- package/dist/_internal/components/data-display/HoverCard/HoverCard.js +2 -2
- package/dist/_internal/components/data-display/LazyImage/LazyImage.js +3 -3
- package/dist/_internal/components/data-display/Lightbox/Lightbox.js +6 -6
- package/dist/_internal/components/data-display/LoadingState/LoadingState.js +3 -3
- package/dist/_internal/components/data-display/MapPreview/MapDecorations.js +2 -2
- package/dist/_internal/components/data-display/MapPreview/MapLayers.js +3 -3
- package/dist/_internal/components/data-display/MapPreview/MapPreview.hooks.js +2 -2
- package/dist/_internal/components/data-display/MapPreview/MapPreview.js +11 -11
- 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/useMapPreview.js +3 -3
- package/dist/_internal/components/data-display/StatCard/StatCard.js +3 -3
- package/dist/_internal/components/data-display/Table/Table.js +2 -2
- package/dist/_internal/components/data-display/index.js +52 -52
- package/dist/_internal/components/feedback/ConfirmAction/ConfirmAction.js +2 -2
- package/dist/_internal/components/feedback/ConfirmAction/ConfirmButton.js +3 -3
- package/dist/_internal/components/feedback/ConfirmAction/with-confirmation.js +2 -2
- package/dist/_internal/components/feedback/StackedModal/StackedModal.js +6 -6
- package/dist/_internal/components/feedback/TutorialOverlay/TutorialOverlay.js +2 -2
- package/dist/_internal/components/feedback/index.js +15 -15
- package/dist/_internal/components/form/AddressAutocomplete/AddressAutocomplete.hooks.js +4 -4
- package/dist/_internal/components/form/AddressAutocomplete/AddressAutocomplete.js +7 -7
- package/dist/_internal/components/form/AddressAutocomplete/AddressAutocompleteField.js +2 -2
- package/dist/_internal/components/form/Autocomplete/Autocomplete.js +2 -2
- package/dist/_internal/components/form/CategorySelect/CategoryPanel.js +4 -4
- package/dist/_internal/components/form/CategorySelect/CategoryPanelList.js +3 -3
- package/dist/_internal/components/form/CategorySelect/CategoryRows.js +2 -2
- package/dist/_internal/components/form/CategorySelect/CategorySelect.js +9 -9
- package/dist/_internal/components/form/CodeEditor/CodeEditor.js +3 -3
- package/dist/_internal/components/form/DateRangePicker/DateRangePicker.js +3 -3
- package/dist/_internal/components/form/HeaderActions/HeaderActions.js +11 -0
- package/dist/_internal/components/form/HeaderActions/HeaderActions.js.map +1 -0
- package/dist/_internal/components/form/HeaderActions/HeaderActions.types.js +1 -0
- package/dist/_internal/components/form/HeaderActions/HeaderActions.types.js.map +1 -0
- package/dist/_internal/components/form/Label/Label.js +2 -2
- package/dist/_internal/components/form/PhoneInput/PhoneInput.hooks.js +2 -2
- package/dist/_internal/components/form/PhoneInput/PhoneInput.js +3 -3
- package/dist/_internal/components/form/index.js +38 -38
- package/dist/_internal/components/form/total-form/Fields/CategoryField.js +10 -10
- package/dist/_internal/components/form/total-form/Fields/index.js +13 -13
- package/dist/_internal/components/index.js +143 -141
- package/dist/_internal/components/layout/ContentToolbar/ContentToolbar.js +1 -1
- package/dist/_internal/components/layout/Dashboard/Dashboard.js +4 -2
- package/dist/_internal/components/layout/Dashboard/DashboardParts.js +5 -1
- package/dist/_internal/components/layout/ScrollArea/ScrollArea.js +3 -3
- package/dist/_internal/components/layout/Skeleton/Skeleton.js +2 -2
- package/dist/_internal/components/layout/index.js +22 -20
- package/dist/_internal/components/navigation/CommandPalette/CommandPalette.js +2 -2
- package/dist/_internal/components/navigation/NavigationMenu/NavigationMegaSection.js +3 -3
- package/dist/_internal/components/navigation/NavigationMenu/NavigationMenu.js +5 -5
- package/dist/_internal/components/navigation/NavigationMenu/NavigationMenuItem.js +2 -2
- package/dist/_internal/components/navigation/NavigationMenu/NavigationStandardBody.js +3 -3
- package/dist/_internal/components/navigation/index.js +11 -11
- package/dist/_internal/components/typography/index.js +3 -3
- package/dist/_internal/components/utility/InstallPrompt/InstallPrompt.js +2 -2
- package/dist/_internal/components/utility/index.js +7 -7
- package/dist/_internal/en-US.data-display.js +2 -2
- package/dist/charts.js +17 -17
- package/dist/{chunk-WQSL6MCA.js → chunk-23FCBIUN.js} +4 -4
- package/dist/{chunk-6PFBYCBU.js → chunk-24LW52EU.js} +2 -2
- package/dist/{chunk-HR7YTBR7.js → chunk-3AOOI2NR.js} +4 -4
- package/dist/{chunk-EIGELK2H.js → chunk-3P4THDBM.js} +4 -4
- package/dist/{chunk-SJIBPRPB.js → chunk-3T2I6BYA.js} +4 -4
- package/dist/{chunk-5ZZPQ3MT.js → chunk-434EDUHY.js} +5 -5
- package/dist/{chunk-4ETQRBZC.js → chunk-46UPILLK.js} +4 -4
- package/dist/{chunk-CKZFYGBY.js → chunk-47DCYF4G.js} +6 -6
- package/dist/{chunk-B2324WXJ.js → chunk-4KNJQFDJ.js} +4 -4
- package/dist/{chunk-V44U7H4M.js → chunk-5KZESOK6.js} +8 -8
- package/dist/{chunk-JE6RZ5L6.js → chunk-5ZOJLYD2.js} +4 -4
- package/dist/{chunk-AVGTTWTE.js → chunk-65DLYC4S.js} +4 -4
- package/dist/{chunk-HRJ27X5B.js → chunk-6HNEEJES.js} +7 -7
- package/dist/{chunk-4VNUOSTQ.js → chunk-6YFMGNSA.js} +4 -4
- package/dist/{chunk-R7MX5KPJ.js → chunk-6YLAVHV4.js} +4 -4
- package/dist/{chunk-56SMIHWE.js → chunk-747HBFGH.js} +4 -4
- package/dist/{chunk-A43SJQYE.js → chunk-74LYLKO2.js} +4 -2
- package/dist/chunk-74LYLKO2.js.map +1 -0
- package/dist/{chunk-RXSGHPCR.js → chunk-7FOOLP5H.js} +4 -4
- package/dist/{chunk-EICVL6GS.js → chunk-7HPPUO2A.js} +2 -2
- package/dist/chunk-A4YWFX5C.js +39 -0
- package/dist/chunk-A4YWFX5C.js.map +1 -0
- package/dist/{chunk-VJFH2AXT.js → chunk-ARI5ZU75.js} +7 -7
- package/dist/{chunk-7QVYJQN4.js → chunk-B5LNUTGZ.js} +2 -2
- package/dist/{chunk-75KRWRJA.js → chunk-BQYIJOKS.js} +6 -6
- package/dist/{chunk-72NOM3O2.js → chunk-C34GFGA5.js} +2 -2
- package/dist/{chunk-4KSOSI3U.js → chunk-CRHQN42I.js} +5 -5
- package/dist/{chunk-LQR2IVSL.js → chunk-DWUMMMLR.js} +4 -4
- package/dist/{chunk-SHDIZSN5.js → chunk-EGRFMPGD.js} +6 -6
- package/dist/{chunk-XFUNJYFT.js → chunk-EPNUVSNK.js} +7 -7
- package/dist/{chunk-FLSSV4TH.js → chunk-EWGVRRUF.js} +23 -2
- package/dist/chunk-EWGVRRUF.js.map +1 -0
- package/dist/{chunk-L6KEVPXN.js → chunk-FH4VARZ7.js} +7 -7
- package/dist/{chunk-N6JGYVRY.js → chunk-GDUIT5I6.js} +2 -2
- package/dist/{chunk-R6SBP5M5.js → chunk-GOWBYHYW.js} +4 -4
- package/dist/{chunk-HDNK7BAX.js → chunk-GT7C6TSM.js} +3 -3
- package/dist/{chunk-X5MPHXG5.js → chunk-HEG7JIBM.js} +4 -4
- package/dist/{chunk-RDYBS45D.js → chunk-HIZCBYEP.js} +7 -7
- package/dist/{chunk-AZUFGKMQ.js → chunk-HJOABXKN.js} +4 -4
- package/dist/{chunk-ZOUWHGV3.js → chunk-HOJL2GKW.js} +7 -7
- package/dist/{chunk-AZSFIQIA.js → chunk-I2S2GHEG.js} +12 -12
- package/dist/{chunk-RRO2EOJB.js → chunk-JB67KPGM.js} +4 -4
- package/dist/{chunk-MNJVOU7T.js → chunk-K2T2CQSZ.js} +4 -4
- package/dist/chunk-KX75HM5U.js +20 -0
- package/dist/chunk-KX75HM5U.js.map +1 -0
- package/dist/{chunk-AWTERXCW.js → chunk-LDMXHDZ5.js} +4 -2
- package/dist/chunk-LDMXHDZ5.js.map +1 -0
- package/dist/{chunk-IIUB4IOH.js → chunk-LKF5KQ2Q.js} +4 -4
- package/dist/{chunk-A2WJMZX5.js → chunk-LNQ6QMKG.js} +2 -2
- package/dist/{chunk-ECIGNYSI.js → chunk-LR2ECQSZ.js} +2 -2
- package/dist/{chunk-SFAP5EH5.js → chunk-LUMF63BM.js} +4 -4
- package/dist/{chunk-CZPU5TW3.js → chunk-LYSSO6WC.js} +4 -4
- package/dist/{chunk-XSKVBGCZ.js → chunk-MHJ52VJE.js} +5 -5
- package/dist/{chunk-WXBBWSNU.js → chunk-MJOXIENM.js} +3 -2
- package/dist/chunk-MJOXIENM.js.map +1 -0
- package/dist/chunk-N4JEQJBL.js +93 -0
- package/dist/chunk-N4JEQJBL.js.map +1 -0
- package/dist/{chunk-HNDUCGM3.js → chunk-NI2ISQZI.js} +3 -3
- package/dist/chunk-NI2ISQZI.js.map +1 -0
- package/dist/{chunk-Q4ITS2EP.js → chunk-NJS4WCHA.js} +21 -45
- package/dist/chunk-NJS4WCHA.js.map +1 -0
- package/dist/{chunk-RUO4D4N6.js → chunk-NKCKIGRL.js} +6 -6
- package/dist/{chunk-IRDGC7FK.js → chunk-NVOQLMYF.js} +4 -4
- package/dist/{chunk-AGYGNNOM.js → chunk-PQECNGDE.js} +2 -2
- package/dist/{chunk-LPYB4Y7C.js → chunk-PRAGFBHW.js} +4 -4
- package/dist/{chunk-7DNQHMDO.js → chunk-PXH24VIP.js} +4 -4
- package/dist/{chunk-AP3PVR3T.js → chunk-Q6KXTTC4.js} +2 -2
- package/dist/{chunk-CDJPDZCA.js → chunk-QISJKBCM.js} +2 -2
- package/dist/{chunk-WBKWIFXA.js → chunk-QYNCPS5W.js} +6 -6
- package/dist/{chunk-XEE7PLDR.js → chunk-QZBUGUOY.js} +6 -6
- package/dist/{chunk-BLT5ZBVL.js → chunk-RRX6ZTNX.js} +2 -2
- package/dist/{chunk-QQE2PVLO.js → chunk-RXYSP56G.js} +6 -6
- package/dist/{chunk-BVGR7OYA.js → chunk-SE4Z3P6D.js} +4 -4
- package/dist/chunk-SIZOJNB2.js +1 -0
- package/dist/chunk-SIZOJNB2.js.map +1 -0
- package/dist/{chunk-2WWKBD4D.js → chunk-TSPHRZ4U.js} +5 -1
- package/dist/chunk-TSPHRZ4U.js.map +1 -0
- package/dist/{chunk-BGYLL467.js → chunk-TXHJX2NG.js} +4 -4
- package/dist/{chunk-KEDI6IRA.js → chunk-UN5D73A4.js} +2 -2
- package/dist/{chunk-PKJKA4CU.js → chunk-UPR7F3ML.js} +2 -2
- package/dist/{chunk-4ZEU22L2.js → chunk-VLNM4BTH.js} +4 -4
- package/dist/{chunk-2SWQ6HIK.js → chunk-W3FAKT3D.js} +4 -4
- package/dist/{chunk-UHXNEXOC.js → chunk-WWNXJMBX.js} +2 -2
- package/dist/{chunk-V5P5Q6HM.js → chunk-X24P3ZYW.js} +10 -10
- package/dist/{chunk-PMS3H3OO.js → chunk-XSJWN3WH.js} +10 -10
- package/dist/{chunk-OGGHD64H.js → chunk-Y5UCOBQN.js} +4 -4
- package/dist/{chunk-O6J4CKS5.js → chunk-YROTCW42.js} +2 -2
- package/dist/{chunk-2A3OMYCB.js → chunk-YRUCIKPO.js} +4 -4
- package/dist/{chunk-PDGAFQ6Z.js → chunk-YVX7GGS4.js} +3 -3
- package/dist/{chunk-G5ZVD5IJ.js → chunk-ZDWU52DJ.js} +2 -2
- package/dist/{chunk-2UCJJACD.js → chunk-ZLNKBKUB.js} +11 -11
- package/dist/{chunk-RRYQG5Y6.js → chunk-ZPIFVTJA.js} +6 -6
- package/dist/chunk-ZPIFVTJA.js.map +1 -0
- package/dist/data-display/AsyncStateContainer.js +4 -4
- package/dist/data-display/Badge.js +2 -2
- package/dist/data-display/CardKit.js +11 -11
- package/dist/data-display/Carousel.js +3 -3
- package/dist/data-display/Chart.js +17 -17
- package/dist/data-display/DataGrid.js +3 -3
- package/dist/data-display/DataViews.js +77 -75
- package/dist/data-display/HoverCard.js +2 -2
- package/dist/data-display/LazyImage.js +3 -3
- package/dist/data-display/Lightbox.js +6 -6
- package/dist/data-display/LoadingState.js +3 -3
- package/dist/data-display/MapPreview.js +11 -11
- package/dist/data-display/StatCard.js +3 -3
- package/dist/data-display/Table.js +2 -2
- package/dist/en-US.js +8 -8
- package/dist/feedback/ConfirmAction.js +7 -7
- package/dist/feedback/StackedModal.js +6 -6
- package/dist/feedback/TutorialOverlay.js +2 -2
- package/dist/form/AddressAutocomplete.js +7 -7
- package/dist/form/Autocomplete.js +2 -2
- package/dist/form/CategorySelect.js +9 -9
- package/dist/form/CodeEditor.js +3 -3
- package/dist/form/DateRangePicker.js +3 -3
- package/dist/form/HeaderActions.js +11 -0
- package/dist/form/HeaderActions.js.map +1 -0
- package/dist/form/Label.js +2 -2
- package/dist/form/PhoneInput.js +3 -3
- package/dist/form/total-form.js +16 -16
- package/dist/layout/ContentToolbar.js +7 -7
- package/dist/layout/Dashboard.js +4 -2
- package/dist/layout/ScrollArea.js +3 -3
- package/dist/layout/Skeleton.js +2 -2
- package/dist/locales.js +11 -11
- package/dist/navigation/CommandPalette.js +2 -2
- package/dist/navigation/NavigationMenu.js +5 -5
- package/dist/pt-BR.js +4 -4
- package/dist/types/components/data-display/DataViews/DataViewsGrid.d.ts +12 -0
- package/dist/types/components/data-display/DataViews/DataViewsGrid.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/DataViewsTableBase.d.ts +3 -0
- package/dist/types/components/data-display/DataViews/DataViewsTableBase.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-grid-parts.d.ts +3 -0
- package/dist/types/components/data-display/DataViews/data-views-grid-parts.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-header-row.d.ts +18 -0
- package/dist/types/components/data-display/DataViews/data-views-header-row.d.ts.map +1 -0
- package/dist/types/components/data-display/DataViews/data-views-selection-extra.d.ts +50 -0
- package/dist/types/components/data-display/DataViews/data-views-selection-extra.d.ts.map +1 -0
- package/dist/types/components/data-display/DataViews/data-views-shell-toolbar.d.ts +3 -1
- package/dist/types/components/data-display/DataViews/data-views-shell-toolbar.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-toolbar.d.ts +2 -0
- package/dist/types/components/data-display/DataViews/data-views-toolbar.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/index.d.ts +1 -0
- package/dist/types/components/data-display/DataViews/index.d.ts.map +1 -1
- package/dist/types/components/form/HeaderActions/HeaderActions.d.ts +48 -0
- package/dist/types/components/form/HeaderActions/HeaderActions.d.ts.map +1 -0
- package/dist/types/components/form/HeaderActions/HeaderActions.types.d.ts +62 -0
- package/dist/types/components/form/HeaderActions/HeaderActions.types.d.ts.map +1 -0
- package/dist/types/components/form/HeaderActions/index.d.ts +3 -0
- package/dist/types/components/form/HeaderActions/index.d.ts.map +1 -0
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.d.ts +1 -1
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.d.ts.map +1 -1
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.types.d.ts +15 -0
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.types.d.ts.map +1 -1
- package/dist/types/components/layout/Dashboard/Dashboard.d.ts +4 -0
- package/dist/types/components/layout/Dashboard/Dashboard.d.ts.map +1 -1
- package/dist/types/components/layout/Dashboard/Dashboard.types.d.ts +10 -0
- package/dist/types/components/layout/Dashboard/Dashboard.types.d.ts.map +1 -1
- package/dist/types/components/layout/Dashboard/DashboardParts.d.ts +22 -1
- package/dist/types/components/layout/Dashboard/DashboardParts.d.ts.map +1 -1
- package/dist/types/components/layout/Dashboard/index.d.ts +1 -1
- package/dist/types/components/layout/Dashboard/index.d.ts.map +1 -1
- package/dist/utility/InstallPrompt.js +2 -2
- package/package.json +5 -1
- package/src/components/data-display/DataViews/DataViewsGrid.tsx +12 -0
- package/src/components/data-display/DataViews/DataViewsTableBase.tsx +3 -0
- package/src/components/data-display/DataViews/data-views-grid-parts.tsx +5 -50
- package/src/components/data-display/DataViews/data-views-header-row.tsx +52 -0
- package/src/components/data-display/DataViews/data-views-selection-extra.ts +67 -0
- package/src/components/data-display/DataViews/data-views-shell-toolbar.tsx +4 -0
- package/src/components/data-display/DataViews/data-views-toolbar.tsx +3 -0
- package/src/components/data-display/DataViews/index.ts +1 -0
- package/src/components/form/HeaderActions/HeaderActions.md +72 -0
- package/src/components/form/HeaderActions/HeaderActions.tsx +134 -0
- package/src/components/form/HeaderActions/HeaderActions.types.ts +64 -0
- package/src/components/form/HeaderActions/index.ts +2 -0
- package/src/components/layout/ContentToolbar/ContentToolbar.md +10 -3
- package/src/components/layout/ContentToolbar/ContentToolbar.tsx +5 -0
- package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +15 -0
- package/src/components/layout/Dashboard/Dashboard.md +9 -2
- package/src/components/layout/Dashboard/Dashboard.tsx +2 -0
- package/src/components/layout/Dashboard/Dashboard.types.ts +12 -0
- package/src/components/layout/Dashboard/DashboardParts.tsx +36 -0
- package/src/components/layout/Dashboard/index.ts +1 -0
- package/dist/chunk-2WWKBD4D.js.map +0 -1
- package/dist/chunk-A43SJQYE.js.map +0 -1
- package/dist/chunk-AWTERXCW.js.map +0 -1
- package/dist/chunk-FLSSV4TH.js.map +0 -1
- package/dist/chunk-HNDUCGM3.js.map +0 -1
- package/dist/chunk-Q4ITS2EP.js.map +0 -1
- package/dist/chunk-RRYQG5Y6.js.map +0 -1
- package/dist/chunk-WXBBWSNU.js.map +0 -1
- /package/dist/{chunk-WQSL6MCA.js.map → chunk-23FCBIUN.js.map} +0 -0
- /package/dist/{chunk-6PFBYCBU.js.map → chunk-24LW52EU.js.map} +0 -0
- /package/dist/{chunk-HR7YTBR7.js.map → chunk-3AOOI2NR.js.map} +0 -0
- /package/dist/{chunk-EIGELK2H.js.map → chunk-3P4THDBM.js.map} +0 -0
- /package/dist/{chunk-SJIBPRPB.js.map → chunk-3T2I6BYA.js.map} +0 -0
- /package/dist/{chunk-5ZZPQ3MT.js.map → chunk-434EDUHY.js.map} +0 -0
- /package/dist/{chunk-4ETQRBZC.js.map → chunk-46UPILLK.js.map} +0 -0
- /package/dist/{chunk-CKZFYGBY.js.map → chunk-47DCYF4G.js.map} +0 -0
- /package/dist/{chunk-B2324WXJ.js.map → chunk-4KNJQFDJ.js.map} +0 -0
- /package/dist/{chunk-V44U7H4M.js.map → chunk-5KZESOK6.js.map} +0 -0
- /package/dist/{chunk-JE6RZ5L6.js.map → chunk-5ZOJLYD2.js.map} +0 -0
- /package/dist/{chunk-AVGTTWTE.js.map → chunk-65DLYC4S.js.map} +0 -0
- /package/dist/{chunk-HRJ27X5B.js.map → chunk-6HNEEJES.js.map} +0 -0
- /package/dist/{chunk-4VNUOSTQ.js.map → chunk-6YFMGNSA.js.map} +0 -0
- /package/dist/{chunk-R7MX5KPJ.js.map → chunk-6YLAVHV4.js.map} +0 -0
- /package/dist/{chunk-56SMIHWE.js.map → chunk-747HBFGH.js.map} +0 -0
- /package/dist/{chunk-RXSGHPCR.js.map → chunk-7FOOLP5H.js.map} +0 -0
- /package/dist/{chunk-EICVL6GS.js.map → chunk-7HPPUO2A.js.map} +0 -0
- /package/dist/{chunk-VJFH2AXT.js.map → chunk-ARI5ZU75.js.map} +0 -0
- /package/dist/{chunk-7QVYJQN4.js.map → chunk-B5LNUTGZ.js.map} +0 -0
- /package/dist/{chunk-75KRWRJA.js.map → chunk-BQYIJOKS.js.map} +0 -0
- /package/dist/{chunk-72NOM3O2.js.map → chunk-C34GFGA5.js.map} +0 -0
- /package/dist/{chunk-4KSOSI3U.js.map → chunk-CRHQN42I.js.map} +0 -0
- /package/dist/{chunk-LQR2IVSL.js.map → chunk-DWUMMMLR.js.map} +0 -0
- /package/dist/{chunk-SHDIZSN5.js.map → chunk-EGRFMPGD.js.map} +0 -0
- /package/dist/{chunk-XFUNJYFT.js.map → chunk-EPNUVSNK.js.map} +0 -0
- /package/dist/{chunk-L6KEVPXN.js.map → chunk-FH4VARZ7.js.map} +0 -0
- /package/dist/{chunk-N6JGYVRY.js.map → chunk-GDUIT5I6.js.map} +0 -0
- /package/dist/{chunk-R6SBP5M5.js.map → chunk-GOWBYHYW.js.map} +0 -0
- /package/dist/{chunk-HDNK7BAX.js.map → chunk-GT7C6TSM.js.map} +0 -0
- /package/dist/{chunk-X5MPHXG5.js.map → chunk-HEG7JIBM.js.map} +0 -0
- /package/dist/{chunk-RDYBS45D.js.map → chunk-HIZCBYEP.js.map} +0 -0
- /package/dist/{chunk-AZUFGKMQ.js.map → chunk-HJOABXKN.js.map} +0 -0
- /package/dist/{chunk-ZOUWHGV3.js.map → chunk-HOJL2GKW.js.map} +0 -0
- /package/dist/{chunk-AZSFIQIA.js.map → chunk-I2S2GHEG.js.map} +0 -0
- /package/dist/{chunk-RRO2EOJB.js.map → chunk-JB67KPGM.js.map} +0 -0
- /package/dist/{chunk-MNJVOU7T.js.map → chunk-K2T2CQSZ.js.map} +0 -0
- /package/dist/{chunk-IIUB4IOH.js.map → chunk-LKF5KQ2Q.js.map} +0 -0
- /package/dist/{chunk-A2WJMZX5.js.map → chunk-LNQ6QMKG.js.map} +0 -0
- /package/dist/{chunk-ECIGNYSI.js.map → chunk-LR2ECQSZ.js.map} +0 -0
- /package/dist/{chunk-SFAP5EH5.js.map → chunk-LUMF63BM.js.map} +0 -0
- /package/dist/{chunk-CZPU5TW3.js.map → chunk-LYSSO6WC.js.map} +0 -0
- /package/dist/{chunk-XSKVBGCZ.js.map → chunk-MHJ52VJE.js.map} +0 -0
- /package/dist/{chunk-RUO4D4N6.js.map → chunk-NKCKIGRL.js.map} +0 -0
- /package/dist/{chunk-IRDGC7FK.js.map → chunk-NVOQLMYF.js.map} +0 -0
- /package/dist/{chunk-AGYGNNOM.js.map → chunk-PQECNGDE.js.map} +0 -0
- /package/dist/{chunk-LPYB4Y7C.js.map → chunk-PRAGFBHW.js.map} +0 -0
- /package/dist/{chunk-7DNQHMDO.js.map → chunk-PXH24VIP.js.map} +0 -0
- /package/dist/{chunk-AP3PVR3T.js.map → chunk-Q6KXTTC4.js.map} +0 -0
- /package/dist/{chunk-CDJPDZCA.js.map → chunk-QISJKBCM.js.map} +0 -0
- /package/dist/{chunk-WBKWIFXA.js.map → chunk-QYNCPS5W.js.map} +0 -0
- /package/dist/{chunk-XEE7PLDR.js.map → chunk-QZBUGUOY.js.map} +0 -0
- /package/dist/{chunk-BLT5ZBVL.js.map → chunk-RRX6ZTNX.js.map} +0 -0
- /package/dist/{chunk-QQE2PVLO.js.map → chunk-RXYSP56G.js.map} +0 -0
- /package/dist/{chunk-BVGR7OYA.js.map → chunk-SE4Z3P6D.js.map} +0 -0
- /package/dist/{chunk-BGYLL467.js.map → chunk-TXHJX2NG.js.map} +0 -0
- /package/dist/{chunk-KEDI6IRA.js.map → chunk-UN5D73A4.js.map} +0 -0
- /package/dist/{chunk-PKJKA4CU.js.map → chunk-UPR7F3ML.js.map} +0 -0
- /package/dist/{chunk-4ZEU22L2.js.map → chunk-VLNM4BTH.js.map} +0 -0
- /package/dist/{chunk-2SWQ6HIK.js.map → chunk-W3FAKT3D.js.map} +0 -0
- /package/dist/{chunk-UHXNEXOC.js.map → chunk-WWNXJMBX.js.map} +0 -0
- /package/dist/{chunk-V5P5Q6HM.js.map → chunk-X24P3ZYW.js.map} +0 -0
- /package/dist/{chunk-PMS3H3OO.js.map → chunk-XSJWN3WH.js.map} +0 -0
- /package/dist/{chunk-OGGHD64H.js.map → chunk-Y5UCOBQN.js.map} +0 -0
- /package/dist/{chunk-O6J4CKS5.js.map → chunk-YROTCW42.js.map} +0 -0
- /package/dist/{chunk-2A3OMYCB.js.map → chunk-YRUCIKPO.js.map} +0 -0
- /package/dist/{chunk-PDGAFQ6Z.js.map → chunk-YVX7GGS4.js.map} +0 -0
- /package/dist/{chunk-G5ZVD5IJ.js.map → chunk-ZDWU52DJ.js.map} +0 -0
- /package/dist/{chunk-2UCJJACD.js.map → chunk-ZLNKBKUB.js.map} +0 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The selection-WIDENING slot: what a paginated grid needs so an operator can
|
|
3
|
+
* act on "everything matching the filter" rather than on the page in front of
|
|
4
|
+
* them.
|
|
5
|
+
*
|
|
6
|
+
* It is a slot of its own rather than a share of the bulk-actions menu because
|
|
7
|
+
* the two answer different questions — `actions` is what HAPPENS to the
|
|
8
|
+
* selection, this is what the selection IS. Folding a widening into the actions
|
|
9
|
+
* menu files "change what I picked" under "do this to what I picked", where
|
|
10
|
+
* every entry is expected to write something.
|
|
11
|
+
*/
|
|
12
|
+
import type { DataViewsController } from "./use-data-views-state";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* What a widening control gets to decide with.
|
|
16
|
+
*
|
|
17
|
+
* `allOnPageSelected` is the one thing a host cannot compute for itself, and
|
|
18
|
+
* the whole reason this is a context rather than a bare node: the grid owns
|
|
19
|
+
* which rows the page is currently rendering — server mode pages at the
|
|
20
|
+
* backend, so the host's `rows` prop and the page can differ mid-fetch — and
|
|
21
|
+
* "every row here is ticked" is the trigger a select-all-matching control
|
|
22
|
+
* hangs on. Deriving it host-side would be a second, slightly different answer
|
|
23
|
+
* to the question the grid already answers to draw its own header checkbox.
|
|
24
|
+
*/
|
|
25
|
+
export interface SelectionExtraContext<T extends Record<string, unknown>> {
|
|
26
|
+
/** The selected rows, off-page ones included. */
|
|
27
|
+
selectedRows: T[];
|
|
28
|
+
/** Drop the whole selection. */
|
|
29
|
+
clearSelection: () => void;
|
|
30
|
+
/** Every row the page is rendering is selected — and the page is not empty. */
|
|
31
|
+
allOnPageSelected: boolean;
|
|
32
|
+
/** How many rows the page is rendering. */
|
|
33
|
+
pageRowCount: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** The host's widening control, called only while something is selected. */
|
|
37
|
+
export type SelectionExtraRender<T extends Record<string, unknown>> = (
|
|
38
|
+
context: SelectionExtraContext<T>,
|
|
39
|
+
) => React.ReactNode;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the host's control against the page on screen.
|
|
43
|
+
*
|
|
44
|
+
* Measured against `c.matched` — which in server mode IS the page — rather than
|
|
45
|
+
* the `rows` prop, so the answer cannot lag a page change.
|
|
46
|
+
*
|
|
47
|
+
* Returns `undefined` with nothing selected, so the toolbar renders no empty
|
|
48
|
+
* slot: a widening with nothing to widen is not a control.
|
|
49
|
+
*/
|
|
50
|
+
export function resolveSelectionExtra<T extends Record<string, unknown>>({
|
|
51
|
+
c,
|
|
52
|
+
getRowId,
|
|
53
|
+
selectionExtra,
|
|
54
|
+
}: {
|
|
55
|
+
c: DataViewsController<T>;
|
|
56
|
+
getRowId: (row: T) => string | number;
|
|
57
|
+
selectionExtra?: SelectionExtraRender<T>;
|
|
58
|
+
}): React.ReactNode {
|
|
59
|
+
if (selectionExtra === undefined || c.selectedRows.length === 0) return undefined;
|
|
60
|
+
const page = c.matched;
|
|
61
|
+
return selectionExtra({
|
|
62
|
+
selectedRows: c.selectedRows,
|
|
63
|
+
clearSelection: c.clearSelection,
|
|
64
|
+
allOnPageSelected: page.length > 0 && page.every((row) => c.selectedIds.has(getRowId(row))),
|
|
65
|
+
pageRowCount: page.length,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
@@ -22,6 +22,7 @@ export function ShellToolbar<T extends Record<string, unknown>>({
|
|
|
22
22
|
testIdPrefix,
|
|
23
23
|
rowActions,
|
|
24
24
|
bulkActions,
|
|
25
|
+
selectionExtra,
|
|
25
26
|
toolbarRightSlot,
|
|
26
27
|
showInline,
|
|
27
28
|
compactControls,
|
|
@@ -40,6 +41,8 @@ export function ShellToolbar<T extends Record<string, unknown>>({
|
|
|
40
41
|
exportConfig?: DataViewExport;
|
|
41
42
|
rowActions?: RowAction<T>[];
|
|
42
43
|
bulkActions?: (selectedRows: T[], clearSelection: () => void) => React.ReactNode;
|
|
44
|
+
/** Already resolved by the shell, which is the party that knows the page. */
|
|
45
|
+
selectionExtra?: React.ReactNode;
|
|
43
46
|
toolbarRightSlot?: React.ReactNode;
|
|
44
47
|
/** Search + filters, rendered on the toolbar line (see `GridToolbar`). */
|
|
45
48
|
filterControls?: React.ReactNode;
|
|
@@ -71,6 +74,7 @@ export function ShellToolbar<T extends Record<string, unknown>>({
|
|
|
71
74
|
clearSelection={c.clearSelection}
|
|
72
75
|
rowActions={rowActions}
|
|
73
76
|
bulkActions={bulkActions}
|
|
77
|
+
selectionExtra={selectionExtra}
|
|
74
78
|
sortFields={c.resolvedSortFields}
|
|
75
79
|
activeSortField={c.activeSortField}
|
|
76
80
|
activeSortOrder={c.activeSortOrder}
|
|
@@ -25,6 +25,8 @@ export interface GridToolbarProps<T extends Record<string, unknown>> {
|
|
|
25
25
|
clearSelection: () => void;
|
|
26
26
|
rowActions?: RowAction<T>[];
|
|
27
27
|
bulkActions?: (selectedRows: T[], clearSelection: () => void) => React.ReactNode;
|
|
28
|
+
/** A control between the count and the actions menu — see `selectionExtra`. */
|
|
29
|
+
selectionExtra?: React.ReactNode;
|
|
28
30
|
sortFields: SortFieldDefinition[];
|
|
29
31
|
activeSortField: string;
|
|
30
32
|
activeSortOrder: "asc" | "desc";
|
|
@@ -161,6 +163,7 @@ export function GridToolbar<T extends Record<string, unknown>>(props: GridToolba
|
|
|
161
163
|
clearSelection={props.clearSelection}
|
|
162
164
|
selectAllTestId={`${testIdPrefix}-select-all`}
|
|
163
165
|
clearAllTestId={`${testIdPrefix}-clear-all`}
|
|
166
|
+
selectionExtra={props.selectionExtra}
|
|
164
167
|
actions={renderBulkActions({
|
|
165
168
|
rowActions: props.rowActions,
|
|
166
169
|
bulkActions: props.bulkActions,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# HeaderActions
|
|
2
|
+
|
|
3
|
+
The page header's actions as ONE control, sized to how many there are.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { HeaderActions } from '@12-apps/ui/form/HeaderActions';
|
|
7
|
+
|
|
8
|
+
<HeaderActions
|
|
9
|
+
moreLabel={copy.moreActions}
|
|
10
|
+
actions={[
|
|
11
|
+
{ id: 'new-product', text: 'Novo produto', icon: <AddIcon fontSize="small" />, onClick: onCreate },
|
|
12
|
+
{ id: 'order-highlights', text: 'Ordenar destaques', icon: <ListIcon fontSize="small" />, onClick: onOrder },
|
|
13
|
+
{ id: 'export-sheet', text: 'Exportar planilha', icon: <DownloadIcon fontSize="small" />, onClick: onExport },
|
|
14
|
+
canImport && { id: 'import-sheet', text: 'Importar planilha', icon: <UploadIcon fontSize="small" />, onClick: onImport },
|
|
15
|
+
]}
|
|
16
|
+
/>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| actions | renders |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| 0 | nothing at all — not an empty box, and not a menu with no items |
|
|
22
|
+
| 1 | that action, as an ordinary `HeaderButton` |
|
|
23
|
+
| n | the FIRST as a button; the other n−1 inside one dropdown |
|
|
24
|
+
|
|
25
|
+
## The array is in priority order
|
|
26
|
+
|
|
27
|
+
Index 0 is the action that keeps its button, so the order you declare is the
|
|
28
|
+
ranking you get. Put the thing the page is FOR first — "Novo produto" on a
|
|
29
|
+
catalog — and everything the merchant reaches for monthly after it.
|
|
30
|
+
|
|
31
|
+
## Falsy entries are dropped
|
|
32
|
+
|
|
33
|
+
`[edit, canDelete && del]` is a legal array, and so is
|
|
34
|
+
`{ …, visible: false }`. Both mean the same thing and both keep the gate at the
|
|
35
|
+
call site, where a reader can see WHY an action is missing, instead of in an
|
|
36
|
+
array built somewhere above.
|
|
37
|
+
|
|
38
|
+
## Test ids survive the overflow
|
|
39
|
+
|
|
40
|
+
An action that moves into the menu keeps its `dataTestId` (falling back to its
|
|
41
|
+
`id`) on the `MenuItem`. Adding a fifth action to a header must not silently
|
|
42
|
+
break the suite of the action it pushed out.
|
|
43
|
+
|
|
44
|
+
The overflow trigger and its menu take their ids from `testIdPrefix`
|
|
45
|
+
(`header-actions` by default): `…-more-trigger` and `…-more-menu`.
|
|
46
|
+
|
|
47
|
+
## It brings its own spacing
|
|
48
|
+
|
|
49
|
+
The component renders one `inline-flex` box, not a fragment. A fragment inherits
|
|
50
|
+
whatever gap its parent sets, and the two mounts set different ones — a
|
|
51
|
+
`Dashboard.Header` spaces its children, a `Dashboard.Action` slot does not.
|
|
52
|
+
|
|
53
|
+
## Copy
|
|
54
|
+
|
|
55
|
+
`moreLabel` is REQUIRED and has no default. This package ships no words of its
|
|
56
|
+
own, in any language — the label is also the trigger's accessible name, so a
|
|
57
|
+
default would be read out to a screen-reader user in the wrong language.
|
|
58
|
+
|
|
59
|
+
## Inside a Dashboard
|
|
60
|
+
|
|
61
|
+
`<Dashboard.Actions>` is the same component wired to the Dashboard's own
|
|
62
|
+
`testIdPrefix`; prefer it when the header is a `<Dashboard.Header>`.
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
<Dashboard.Header title="Produtos">
|
|
66
|
+
<Dashboard.Spacer />
|
|
67
|
+
<Dashboard.Actions moreLabel={copy.moreActions} actions={actions} />
|
|
68
|
+
</Dashboard.Header>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`<Dashboard.Action>` (singular) stays for the one header control that is not an
|
|
72
|
+
action at all — a link, a toggle, a status pill.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
4
|
+
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
|
|
5
|
+
import Box from '@mui/material/Box/index.js';
|
|
6
|
+
import ListItemIcon from '@mui/material/ListItemIcon/index.js';
|
|
7
|
+
import ListItemText from '@mui/material/ListItemText/index.js';
|
|
8
|
+
import Menu from '@mui/material/Menu/index.js';
|
|
9
|
+
import MenuItem from '@mui/material/MenuItem/index.js';
|
|
10
|
+
import React, { useState } from 'react';
|
|
11
|
+
|
|
12
|
+
import { HeaderButton } from '../HeaderButton';
|
|
13
|
+
import type { HeaderActionItem, HeaderActionsProps } from './HeaderActions.types';
|
|
14
|
+
|
|
15
|
+
/** Drop the gated-away entries, so everything below can count what is left. */
|
|
16
|
+
function present(
|
|
17
|
+
actions: HeaderActionsProps['actions'],
|
|
18
|
+
): HeaderActionItem[] {
|
|
19
|
+
return actions.filter(
|
|
20
|
+
(action): action is HeaderActionItem => Boolean(action) && (action as HeaderActionItem).visible !== false,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The page header's actions, as ONE control that scales with how many there
|
|
26
|
+
* are: nothing, a button, or a button plus an overflow menu.
|
|
27
|
+
*
|
|
28
|
+
* | actions | renders |
|
|
29
|
+
* |---|---|
|
|
30
|
+
* | 0 | nothing at all — not an empty box, and not a menu with no items |
|
|
31
|
+
* | 1 | that action, as an ordinary `HeaderButton` |
|
|
32
|
+
* | n | the FIRST as a button; the other n−1 inside one dropdown |
|
|
33
|
+
*
|
|
34
|
+
* ## Why the first one stays a button
|
|
35
|
+
*
|
|
36
|
+
* A header whose every action lives behind a menu costs two clicks for the
|
|
37
|
+
* thing the page is FOR — "Novo produto" on a catalog, "Nova categoria" on the
|
|
38
|
+
* categories list. Folding it in with the exports and the reorder screens
|
|
39
|
+
* would treat a merchant's daily action as equal to the one they use monthly.
|
|
40
|
+
* So the array is in PRIORITY order and index 0 keeps its button; everything
|
|
41
|
+
* after it is secondary by the caller's own declaration.
|
|
42
|
+
*
|
|
43
|
+
* ## Why this takes a list and not children
|
|
44
|
+
*
|
|
45
|
+
* The 0/1/n decision is only decidable over data. A component handed JSX can
|
|
46
|
+
* count `React.Children`, but it cannot tell a gated-away action from an
|
|
47
|
+
* absent one, cannot read a label to put in a menu row, and cannot re-render
|
|
48
|
+
* a `<Button>` as a `<MenuItem>` without reaching into its props. Every
|
|
49
|
+
* caller in the estate had therefore hand-written the row, which is how four
|
|
50
|
+
* equally-weighted buttons ended up wrapping the line on a catalog page.
|
|
51
|
+
*
|
|
52
|
+
* ## One element, so the spacing is the component's and not the mount's
|
|
53
|
+
*
|
|
54
|
+
* It renders an `inline-flex` box rather than a fragment. A fragment inherits
|
|
55
|
+
* whatever gap its parent happens to set, and the two mounts here set
|
|
56
|
+
* different ones — a `Dashboard.Header` spaces its children, a
|
|
57
|
+
* `Dashboard.Action` slot does not, which is why the pair of buttons in that
|
|
58
|
+
* slot sat flush against each other. The gap belongs to the control.
|
|
59
|
+
*
|
|
60
|
+
* ## The ids survive the move
|
|
61
|
+
*
|
|
62
|
+
* An action that overflows keeps its `dataTestId` on its `MenuItem`. It is a
|
|
63
|
+
* different element in a different place, and it must still answer to the same
|
|
64
|
+
* selector: otherwise adding a fifth action to a header silently breaks the
|
|
65
|
+
* suite of the action that got pushed out, which is the last place anyone
|
|
66
|
+
* would look.
|
|
67
|
+
*/
|
|
68
|
+
export function HeaderActions({
|
|
69
|
+
actions,
|
|
70
|
+
moreLabel,
|
|
71
|
+
collapseBelow = 'md',
|
|
72
|
+
testIdPrefix = 'header-actions',
|
|
73
|
+
}: HeaderActionsProps): React.JSX.Element | null {
|
|
74
|
+
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
|
|
75
|
+
const items = present(actions);
|
|
76
|
+
const open = Boolean(anchorEl);
|
|
77
|
+
|
|
78
|
+
// Before the early return would be a conditional hook; after it is the only
|
|
79
|
+
// legal place. Nothing below runs for an empty list anyway.
|
|
80
|
+
const [primary, ...overflow] = items;
|
|
81
|
+
if (!primary) return null;
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<Box sx={{ display: 'inline-flex', alignItems: 'center', gap: 1 }}>
|
|
85
|
+
<HeaderButton
|
|
86
|
+
text={primary.text}
|
|
87
|
+
icon={primary.icon}
|
|
88
|
+
onClick={primary.onClick}
|
|
89
|
+
disabled={primary.disabled}
|
|
90
|
+
variant={primary.variant}
|
|
91
|
+
color={primary.color}
|
|
92
|
+
collapseBelow={collapseBelow}
|
|
93
|
+
dataTestId={primary.dataTestId ?? primary.id}
|
|
94
|
+
/>
|
|
95
|
+
{overflow.length > 0 && (
|
|
96
|
+
<>
|
|
97
|
+
<HeaderButton
|
|
98
|
+
text={moreLabel}
|
|
99
|
+
icon={<MoreHorizIcon fontSize="small" />}
|
|
100
|
+
endIcon={<ExpandMoreIcon fontSize="small" />}
|
|
101
|
+
onClick={(event) => setAnchorEl(event.currentTarget)}
|
|
102
|
+
collapseBelow={collapseBelow}
|
|
103
|
+
aria-haspopup="menu"
|
|
104
|
+
aria-expanded={open}
|
|
105
|
+
dataTestId={`${testIdPrefix}-more-trigger`}
|
|
106
|
+
/>
|
|
107
|
+
<Menu
|
|
108
|
+
anchorEl={anchorEl}
|
|
109
|
+
open={open}
|
|
110
|
+
onClose={() => setAnchorEl(null)}
|
|
111
|
+
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
|
112
|
+
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
|
|
113
|
+
data-testid={`${testIdPrefix}-more-menu`}
|
|
114
|
+
>
|
|
115
|
+
{overflow.map((action) => (
|
|
116
|
+
<MenuItem
|
|
117
|
+
key={action.id}
|
|
118
|
+
disabled={action.disabled}
|
|
119
|
+
onClick={() => {
|
|
120
|
+
setAnchorEl(null);
|
|
121
|
+
action.onClick?.();
|
|
122
|
+
}}
|
|
123
|
+
data-testid={action.dataTestId ?? action.id}
|
|
124
|
+
>
|
|
125
|
+
<ListItemIcon sx={{ minWidth: 32 }}>{action.icon}</ListItemIcon>
|
|
126
|
+
<ListItemText>{action.text}</ListItemText>
|
|
127
|
+
</MenuItem>
|
|
128
|
+
))}
|
|
129
|
+
</Menu>
|
|
130
|
+
</>
|
|
131
|
+
)}
|
|
132
|
+
</Box>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { HeaderButtonProps } from '../HeaderButton';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* One page-header action, declared as DATA rather than composed as an element.
|
|
7
|
+
*
|
|
8
|
+
* That is the whole point of the type. A header that composes its buttons as
|
|
9
|
+
* JSX can only ever render all of them, because nothing can count a fragment's
|
|
10
|
+
* children without walking React internals — so "three actions" and "seven
|
|
11
|
+
* actions" produce the same row, and the seventh button is what wraps the line
|
|
12
|
+
* on a laptop. A list can be measured, so the component can decide.
|
|
13
|
+
*/
|
|
14
|
+
export interface HeaderActionItem {
|
|
15
|
+
/**
|
|
16
|
+
* Stable identity. Used as the React key, and as the `data-testid` fallback
|
|
17
|
+
* so an action that MOVES into the overflow menu keeps the selector it had
|
|
18
|
+
* as a button — a suite driving it by id must not care where it ended up.
|
|
19
|
+
*/
|
|
20
|
+
id: string;
|
|
21
|
+
/** The label. Shown beside the icon as a button; alone in the menu row. */
|
|
22
|
+
text: ReactNode;
|
|
23
|
+
/** Leading icon. Always visible as a button, and in the menu row. */
|
|
24
|
+
icon: ReactNode;
|
|
25
|
+
onClick?: () => void;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Drop this action entirely when false. Present so a caller can declare a
|
|
29
|
+
* permission- or plan-gated action inline, instead of building the array
|
|
30
|
+
* conditionally and losing the reason it is missing.
|
|
31
|
+
*
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
34
|
+
visible?: boolean;
|
|
35
|
+
/** Overrides the `data-testid`, which otherwise falls back to {@link id}. */
|
|
36
|
+
dataTestId?: string;
|
|
37
|
+
/** MUI variant for the PRIMARY rendering. Ignored inside the menu. */
|
|
38
|
+
variant?: HeaderButtonProps['variant'];
|
|
39
|
+
/** MUI color for the PRIMARY rendering. Ignored inside the menu. */
|
|
40
|
+
color?: HeaderButtonProps['color'];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Props for {@link HeaderActions}. */
|
|
44
|
+
export interface HeaderActionsProps {
|
|
45
|
+
/**
|
|
46
|
+
* The actions, in priority order — the first is the one that stays a button.
|
|
47
|
+
*
|
|
48
|
+
* `false`/`null`/`undefined` entries are dropped, so a caller can write
|
|
49
|
+
* `[edit, canDelete && del]` without pre-filtering.
|
|
50
|
+
*/
|
|
51
|
+
actions: Array<HeaderActionItem | false | null | undefined>;
|
|
52
|
+
/**
|
|
53
|
+
* The overflow trigger's label, which is also its accessible name. REQUIRED:
|
|
54
|
+
* this package ships no copy of its own, in any language.
|
|
55
|
+
*/
|
|
56
|
+
moreLabel: string;
|
|
57
|
+
/** Width below which every button collapses to icon-only. @default 'md' */
|
|
58
|
+
collapseBelow?: HeaderButtonProps['collapseBelow'];
|
|
59
|
+
/**
|
|
60
|
+
* Prefix for the overflow trigger's and menu's own test ids. The ACTIONS
|
|
61
|
+
* keep their own ids either way. @default 'header-actions'
|
|
62
|
+
*/
|
|
63
|
+
testIdPrefix?: string;
|
|
64
|
+
}
|
|
@@ -8,12 +8,19 @@ pages and projects.
|
|
|
8
8
|
## Anatomy
|
|
9
9
|
|
|
10
10
|
```
|
|
11
|
-
[Select All] [Clear All] | N
|
|
12
|
-
|
|
11
|
+
[Select All] [Clear All] | N selected <selectionExtra> <actions> (o)══ ▦▾ Sort By: … ▾ ⨏
|
|
12
|
+
└─────────────────── left cluster (selection chrome) ──────────────┘ └───── rightControls slot ─────┘
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
- **Left cluster** — always shows **Select All**. Once `hasSelection` is true it
|
|
16
|
-
adds **Clear All**, an "N items selected" count, and
|
|
16
|
+
adds **Clear All**, an "N items selected" count, and two optional slots:
|
|
17
|
+
`selectionExtra` then `actions`.
|
|
18
|
+
- **`selectionExtra` vs `actions`** — `actions` is what HAPPENS to the selection
|
|
19
|
+
(delete, export, send). `selectionExtra` is what the selection IS: the
|
|
20
|
+
"select all N matching the filter" widening a paginated list needs once its
|
|
21
|
+
whole page is ticked. They are separate slots because an operator reasonably
|
|
22
|
+
expects every entry in an actions menu to write something, and a widening
|
|
23
|
+
writes nothing.
|
|
17
24
|
- **Right cluster** — a free `rightControls` node. Compose it from the shipped
|
|
18
25
|
controls below (or anything else).
|
|
19
26
|
|
|
@@ -28,6 +28,7 @@ type SelectionClusterProps = Pick<
|
|
|
28
28
|
| 'selectAll'
|
|
29
29
|
| 'clearSelection'
|
|
30
30
|
| 'actions'
|
|
31
|
+
| 'selectionExtra'
|
|
31
32
|
| 'selectAllTestId'
|
|
32
33
|
| 'clearAllTestId'
|
|
33
34
|
| 'edgeAlign'
|
|
@@ -43,6 +44,7 @@ function SelectionCluster({
|
|
|
43
44
|
selectAll,
|
|
44
45
|
clearSelection,
|
|
45
46
|
actions,
|
|
47
|
+
selectionExtra,
|
|
46
48
|
selectAllTestId,
|
|
47
49
|
clearAllTestId,
|
|
48
50
|
edgeAlign = false,
|
|
@@ -106,6 +108,7 @@ function SelectionCluster({
|
|
|
106
108
|
>
|
|
107
109
|
{selectedCount} {selectedCount === 1 ? 'item' : 'items'} selected
|
|
108
110
|
</Typography>
|
|
111
|
+
{selectionExtra}
|
|
109
112
|
{actionsSlot}
|
|
110
113
|
</>
|
|
111
114
|
) : (
|
|
@@ -219,6 +222,7 @@ export function ContentToolbar({
|
|
|
219
222
|
rightControls,
|
|
220
223
|
leadingControls,
|
|
221
224
|
actions,
|
|
225
|
+
selectionExtra,
|
|
222
226
|
selectAllTestId,
|
|
223
227
|
clearAllTestId,
|
|
224
228
|
edgeAlign = false,
|
|
@@ -258,6 +262,7 @@ export function ContentToolbar({
|
|
|
258
262
|
selectAll={selectAll}
|
|
259
263
|
clearSelection={clearSelection}
|
|
260
264
|
actions={actions}
|
|
265
|
+
selectionExtra={selectionExtra}
|
|
261
266
|
selectAllTestId={selectAllTestId}
|
|
262
267
|
clearAllTestId={clearAllTestId}
|
|
263
268
|
selectAllLabel={selectAllLabel}
|
|
@@ -45,6 +45,21 @@ export interface ContentToolbarProps {
|
|
|
45
45
|
* what the action does.
|
|
46
46
|
*/
|
|
47
47
|
actions?: ReactNode;
|
|
48
|
+
/**
|
|
49
|
+
* A control rendered between the count and {@link actions}, and ONLY while
|
|
50
|
+
* something is selected.
|
|
51
|
+
*
|
|
52
|
+
* It is a second slot rather than more room in `actions` because the two
|
|
53
|
+
* answer different questions. `actions` is what HAPPENS to the selection;
|
|
54
|
+
* this is what the selection IS — the "select all 143 matching" widening
|
|
55
|
+
* that a paginated grid needs once its whole page is ticked. Folding a
|
|
56
|
+
* widening control into the actions menu would file "change what I picked"
|
|
57
|
+
* under "do this to what I picked", where an operator reasonably expects
|
|
58
|
+
* every entry to write something.
|
|
59
|
+
*
|
|
60
|
+
* Ignored when nothing is selected: a widening has nothing to widen.
|
|
61
|
+
*/
|
|
62
|
+
selectionExtra?: ReactNode;
|
|
48
63
|
/** Test id for the Select All button. */
|
|
49
64
|
selectAllTestId?: string;
|
|
50
65
|
/** Test id for the Clear All button. */
|
|
@@ -27,7 +27,13 @@ import { Dashboard } from '@12-apps/ui/layout/Dashboard';
|
|
|
27
27
|
<Dashboard.Settings title="Product settings">In development</Dashboard.Settings>
|
|
28
28
|
<Dashboard.Spacer />
|
|
29
29
|
<Dashboard.Export onExport={(id) => exportAs(id)} />
|
|
30
|
-
<Dashboard.
|
|
30
|
+
<Dashboard.Actions
|
|
31
|
+
moreLabel={copy.moreActions}
|
|
32
|
+
actions={[
|
|
33
|
+
{ id: 'new-product', text: 'New product', icon: <AddIcon fontSize="small" />, onClick: onCreate },
|
|
34
|
+
{ id: 'import', text: 'Import sheet', icon: <UploadIcon fontSize="small" />, onClick: onImport },
|
|
35
|
+
]}
|
|
36
|
+
/>
|
|
31
37
|
</Dashboard.Header>
|
|
32
38
|
<Dashboard.Filters>
|
|
33
39
|
<SearchInput />
|
|
@@ -51,7 +57,8 @@ import { Dashboard } from '@12-apps/ui/layout/Dashboard';
|
|
|
51
57
|
| `Dashboard.Settings` | (in header) | Gear icon. Default: opens a dialog with `children`. With `href` (+ optional `linkComponent`): renders as a link to a settings route (e.g. the page's Configuração section) — no dialog. |
|
|
52
58
|
| `Dashboard.Export` | (in header) | Export dropdown (CSV/Excel/JSON by default); calls `onExport(id)`. |
|
|
53
59
|
| `Dashboard.Spacer` | (in header) | Pushes following controls to the right edge. |
|
|
54
|
-
| `Dashboard.Action` | (in header) | Slot for a
|
|
60
|
+
| `Dashboard.Action` | (in header) | Slot for ONE header control that is not an action — a link, a toggle, a status pill. |
|
|
61
|
+
| `Dashboard.Actions` | (in header) | The header's actions declared as a list. 0 renders nothing, 1 renders a button, n renders the first as a button and the other n−1 in a dropdown. See [HeaderActions](../../form/HeaderActions/HeaderActions.md). |
|
|
55
62
|
| `Dashboard.Filters` | filters | Collapsible search/filter region; visibility driven by `FilterToggle`. |
|
|
56
63
|
| `Dashboard.MoreFilters` | (in filters) | Expandable advanced panel for ranges/dates. |
|
|
57
64
|
| `Dashboard.Body` | body | Main content area (the table/grid). |
|
|
@@ -16,6 +16,7 @@ import React, { useMemo, useState } from 'react';
|
|
|
16
16
|
import { DashboardContext, useDashboardContext } from './DashboardContext';
|
|
17
17
|
import {
|
|
18
18
|
DashboardAction,
|
|
19
|
+
DashboardActions,
|
|
19
20
|
DashboardExport,
|
|
20
21
|
DashboardFilterToggle,
|
|
21
22
|
DashboardInfo,
|
|
@@ -309,6 +310,7 @@ Dashboard.FilterToggle = DashboardFilterToggle;
|
|
|
309
310
|
Dashboard.Settings = DashboardSettings;
|
|
310
311
|
Dashboard.Export = DashboardExport;
|
|
311
312
|
Dashboard.Action = DashboardAction;
|
|
313
|
+
Dashboard.Actions = DashboardActions;
|
|
312
314
|
Dashboard.Filters = DashboardFilters;
|
|
313
315
|
Dashboard.MoreFilters = DashboardMoreFilters;
|
|
314
316
|
Dashboard.Body = DashboardBody;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ElementType, ReactNode } from 'react';
|
|
2
2
|
|
|
3
|
+
import type { HeaderActionsProps } from '../../form/HeaderActions';
|
|
4
|
+
|
|
3
5
|
/** A single breadcrumb entry for `<Dashboard.Breadcrumb>`. */
|
|
4
6
|
export interface DashboardBreadcrumbItem {
|
|
5
7
|
/** Visible label. */
|
|
@@ -139,6 +141,16 @@ export interface DashboardActionProps {
|
|
|
139
141
|
children: ReactNode;
|
|
140
142
|
}
|
|
141
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Props for `<Dashboard.Actions>` — the header's actions DECLARED, rather than
|
|
146
|
+
* composed one `<Dashboard.Action>` at a time.
|
|
147
|
+
*
|
|
148
|
+
* `testIdPrefix` is not among them: the Dashboard already has one, from its
|
|
149
|
+
* root, and letting the part carry a second would give one page two answers to
|
|
150
|
+
* "what is this header called".
|
|
151
|
+
*/
|
|
152
|
+
export type DashboardActionsProps = Omit<HeaderActionsProps, 'testIdPrefix'>;
|
|
153
|
+
|
|
142
154
|
/** Props for `<Dashboard.Filters>` — the collapsible search/filter region. */
|
|
143
155
|
export interface DashboardFiltersProps {
|
|
144
156
|
/** Filter controls (search input, pills, `<Dashboard.MoreFilters>`, …). */
|
|
@@ -19,10 +19,12 @@ import Tooltip from '@mui/material/Tooltip/index.js';
|
|
|
19
19
|
import Typography from '@mui/material/Typography/index.js';
|
|
20
20
|
import React, { useState } from 'react';
|
|
21
21
|
|
|
22
|
+
import { HeaderActions } from '../../form/HeaderActions';
|
|
22
23
|
import { HeaderButton } from '../../form/HeaderButton';
|
|
23
24
|
import { useDashboardContext } from './DashboardContext';
|
|
24
25
|
import type {
|
|
25
26
|
DashboardActionProps,
|
|
27
|
+
DashboardActionsProps,
|
|
26
28
|
DashboardExportFormat,
|
|
27
29
|
DashboardExportProps,
|
|
28
30
|
DashboardFilterToggleProps,
|
|
@@ -206,3 +208,37 @@ export const DashboardAction = ({ children }: DashboardActionProps): React.JSX.E
|
|
|
206
208
|
<Box sx={{ display: 'inline-flex' }}>{children}</Box>
|
|
207
209
|
);
|
|
208
210
|
DashboardAction.displayName = 'Dashboard.Action';
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The header's actions, declared as a LIST — `<Dashboard.Action>`'s plural.
|
|
214
|
+
*
|
|
215
|
+
* `<Dashboard.Action>` is a slot: it renders whatever you hand it, once per
|
|
216
|
+
* action, and a page with five of them draws five equally-loud buttons. That is
|
|
217
|
+
* the right primitive for one button and the wrong one for five, and the pages
|
|
218
|
+
* here that grew a fifth action all grew it the same way — by adding a fifth
|
|
219
|
+
* slot, because the slot was the only thing on offer.
|
|
220
|
+
*
|
|
221
|
+
* This part answers the question the slot cannot: given N actions, how many
|
|
222
|
+
* belong on the bar? See {@link HeaderActions} for the rule (0 ⇒ nothing,
|
|
223
|
+
* 1 ⇒ a button, n ⇒ a button and a menu of the rest).
|
|
224
|
+
*
|
|
225
|
+
* Both stay. A header still composes `<Dashboard.Action>` for the one control
|
|
226
|
+
* that is not an action at all — a link, a toggle, a status pill — and reaches
|
|
227
|
+
* for this when it has actions to rank.
|
|
228
|
+
*/
|
|
229
|
+
export const DashboardActions = ({
|
|
230
|
+
actions,
|
|
231
|
+
moreLabel,
|
|
232
|
+
collapseBelow,
|
|
233
|
+
}: DashboardActionsProps): React.JSX.Element => {
|
|
234
|
+
const { testIdPrefix } = useDashboardContext();
|
|
235
|
+
return (
|
|
236
|
+
<HeaderActions
|
|
237
|
+
actions={actions}
|
|
238
|
+
moreLabel={moreLabel}
|
|
239
|
+
collapseBelow={collapseBelow}
|
|
240
|
+
testIdPrefix={`${testIdPrefix}-actions`}
|
|
241
|
+
/>
|
|
242
|
+
);
|
|
243
|
+
};
|
|
244
|
+
DashboardActions.displayName = 'Dashboard.Actions';
|
|
@@ -4,6 +4,7 @@ export { DashboardContext, useDashboardContext } from './DashboardContext';
|
|
|
4
4
|
export type { DashboardContextValue } from './DashboardContext';
|
|
5
5
|
export type {
|
|
6
6
|
DashboardActionProps,
|
|
7
|
+
DashboardActionsProps,
|
|
7
8
|
DashboardBodyProps,
|
|
8
9
|
DashboardBreadcrumbItem,
|
|
9
10
|
DashboardBreadcrumbProps,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/layout/ContentToolbar/ContentToolbar.tsx"],"sourcesContent":["'use client';\n\nimport Box from '@mui/material/Box/index.js';\nimport Button from '@mui/material/Button/index.js';\nimport Checkbox from '@mui/material/Checkbox/index.js';\nimport Divider from '@mui/material/Divider/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport React from 'react';\n\nimport type { ContentToolbarProps } from './ContentToolbar.types';\n\nconst selectionButtonSx = {\n minWidth: 0,\n height: 'auto',\n borderRadius: 0.5,\n fontWeight: 600,\n py: 0.5,\n px: 1.5,\n fontSize: '0.75rem',\n textTransform: 'none',\n color: 'text.primary',\n} as const;\n\ntype SelectionClusterProps = Pick<\n ContentToolbarProps,\n | 'hasSelection'\n | 'selectedCount'\n | 'selectAll'\n | 'clearSelection'\n | 'actions'\n | 'selectAllTestId'\n | 'clearAllTestId'\n | 'edgeAlign'\n | 'selectAllLabel'\n | 'selectAllText'\n | 'clearAllText'\n>;\n\n/** The left cluster: Select All + (when selecting) Clear All / count / actions. */\nfunction SelectionCluster({\n hasSelection,\n selectedCount,\n selectAll,\n clearSelection,\n actions,\n selectAllTestId,\n clearAllTestId,\n edgeAlign = false,\n selectAllLabel,\n selectAllText,\n clearAllText,\n}: SelectionClusterProps): React.JSX.Element {\n const actionsSlot = actions !== undefined && (\n <Box sx={{ ml: 0.5, display: 'flex', flexShrink: 0, alignItems: 'center' }}>{actions}</Box>\n );\n return (\n <Box\n sx={{\n display: 'flex',\n minWidth: 0,\n // Mobile: don't grow, so the controls sit on the SAME line as the checkbox\n // (no orphaned selection row). Desktop: grow to push controls right.\n flex: { xs: '0 0 auto', md: 1 },\n alignItems: 'center',\n gap: 1.5,\n ml: edgeAlign ? -1.5 : 0,\n }}\n >\n {/* Desktop: a \"Select All\" text button (md+). Mobile: a compact checkbox\n that toggles select-all/clear — the text would eat the tight row. */}\n <Button\n variant=\"text\"\n size=\"small\"\n color=\"inherit\"\n onClick={selectAll}\n data-testid={selectAllTestId}\n sx={{ ...selectionButtonSx, display: { xs: 'none', md: 'inline-flex' } }}\n >\n {selectAllText}\n </Button>\n <Checkbox\n size=\"small\"\n checked={hasSelection}\n onChange={(event) => (event.target.checked ? selectAll() : clearSelection())}\n data-testid={`${selectAllTestId}-checkbox`}\n inputProps={{ 'aria-label': selectAllLabel }}\n sx={{ p: 0.5, display: { xs: 'inline-flex', md: 'none' } }}\n />\n {hasSelection ? (\n <>\n <Button\n variant=\"text\"\n size=\"small\"\n color=\"inherit\"\n onClick={clearSelection}\n data-testid={clearAllTestId}\n sx={selectionButtonSx}\n >\n {clearAllText}\n </Button>\n <Divider orientation=\"vertical\" flexItem sx={{ height: 16, alignSelf: 'center' }} />\n <Typography\n component=\"span\"\n data-testid=\"selected-count-indicator\"\n sx={{ fontSize: '0.875rem', color: 'text.secondary', whiteSpace: 'nowrap', flexShrink: 0 }}\n >\n {selectedCount} {selectedCount === 1 ? 'item' : 'items'} selected\n </Typography>\n {actionsSlot}\n </>\n ) : (\n actionsSlot\n )}\n </Box>\n );\n}\n\n/**\n * The BROWSING half of the toolbar: search + filters on the left, the page's\n * own controls on the right. Split out of {@link ContentToolbar} so that\n * function stays inside the complexity gate — it is layout only, and the\n * decision of whether to show it at all is made by the caller.\n */\nfunction BrowsingClusters({\n leadingControls,\n rightControls,\n hasSelection,\n edgeAlign,\n}: {\n leadingControls?: React.ReactNode;\n rightControls: React.ReactNode;\n hasSelection: boolean;\n edgeAlign: boolean;\n}): React.JSX.Element {\n return (\n <>\n {/* minWidth:0 lets this cluster be the one that gives up width as the row\n * tightens, which is what the filter overflow measures against. */}\n {leadingControls !== undefined && (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n flexGrow: 1,\n minWidth: 0,\n // The collapse ladder has a FLOOR — below roughly 400px even the\n // fully-collapsed row does not fit, and its controls cannot shrink\n // (they are flexShrink:0 so an over-packed row sheds instead of\n // squeezing). Past that point this scrolls rather than letting them\n // paint outside the toolbar, which is what a narrow phone did.\n overflowX: 'auto',\n // No scrollbar gutter stealing height on the common case.\n scrollbarWidth: 'thin',\n }}\n >\n {leadingControls}\n </Box>\n )}\n {/* ml:auto keeps the controls right-aligned even when the cluster wraps to\n * its own row (where justify-content:space-between would otherwise snap a\n * lone item to the left); it's a no-op on a shared row. */}\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n // Same single-line rule as the row itself: this cluster wrapping\n // INTERNALLY buys a second line just as surely as the row wrapping\n // does. It bit at exactly 900px, the `md` breakpoint where the \"N de\n // N\" counter appears and pushes Exibir/Exportar over the edge.\n flexWrap: leadingControls === undefined ? 'wrap' : 'nowrap',\n // Tight (5px) when browsing so the controls fit one line beside the\n // checkbox; roomier (14px) in selection mode where they get their own row.\n gap: hasSelection ? '14px' : '5px',\n ml: 'auto',\n mr: edgeAlign ? -1.5 : 0,\n '& > *': { flexShrink: 0 },\n }}\n >\n {rightControls}\n </Box>\n </>\n );\n}\n\n/**\n * Shared toolbar for content pages (Favorites, Personal Space, Recents, …). The\n * left cluster owns selection chrome — **Select All**, and once items are\n * selected, **Clear All** + an \"N items selected\" count + an optional `actions`\n * slot. The right cluster is a free `rightControls` slot for page-specific\n * controls (ViewSelector, SortByDropdown, MultiSelectDropdown, FilterTrigger).\n *\n * Faithful, generic MUI port of the reference `ContentPageToolbar` — the\n * domain-specific default actions are intentionally left to the consumer via\n * the `actions` slot so this stays agnostic and reusable across projects.\n *\n * @example\n * ```tsx\n * <ContentToolbar\n * hasSelection={selected.size > 0}\n * selectedCount={selected.size}\n * selectAll={selectAll}\n * clearSelection={clear}\n * rightControls={\n * <>\n * <ViewSelector viewMode={view} onViewModeChange={setView} zoom={zoom} onZoomChange={setZoom} />\n * <SortByDropdown fields={FIELDS} activeField={field} onFieldChange={setField} />\n * <MultiSelectDropdown label=\"Content Type\" options={types} selected={typeSet} onToggle={toggle} onClear={clear} />\n * <FilterTrigger open={panelOpen} onOpenChange={setPanelOpen} hasActiveFilters={hasFilters} />\n * </>\n * }\n * />\n * ```\n */\nexport function ContentToolbar({\n hasSelection,\n selectedCount,\n selectAll,\n clearSelection,\n rightControls,\n leadingControls,\n actions,\n selectAllTestId,\n clearAllTestId,\n edgeAlign = false,\n exclusiveSelection = false,\n selectAllLabel,\n selectAllText,\n clearAllText,\n}: ContentToolbarProps): React.JSX.Element {\n // Under `exclusiveSelection` the two states are alternatives, not neighbours:\n // browsing shows the controls and no checkbox, selecting shows the checkbox\n // and no controls. Anything else double-books the row.\n const showSelection = !exclusiveSelection || hasSelection;\n const showControls = !exclusiveSelection || !hasSelection;\n return (\n // Two clusters on one line. They may wrap onto separate rows ONLY for a\n // toolbar without `leadingControls` — one carrying search + filters is\n // driven by a measured collapse ladder (see `useFilterOverflow`), and a\n // wrap there is the ladder having failed: it would silently buy a second\n // row instead of shedding a control into \"Mais\", which is the one outcome\n // the ladder exists to prevent.\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 2,\n flexWrap: leadingControls === undefined ? 'wrap' : 'nowrap',\n rowGap: 1,\n }}\n >\n {showSelection && (\n <SelectionCluster\n selectAllText={selectAllText}\n clearAllText={clearAllText}\n hasSelection={hasSelection}\n selectedCount={selectedCount}\n selectAll={selectAll}\n clearSelection={clearSelection}\n actions={actions}\n selectAllTestId={selectAllTestId}\n clearAllTestId={clearAllTestId}\n selectAllLabel={selectAllLabel}\n edgeAlign={edgeAlign}\n />\n )}\n\n {showControls && (\n <BrowsingClusters\n leadingControls={leadingControls}\n rightControls={rightControls}\n hasSelection={hasSelection}\n edgeAlign={edgeAlign}\n />\n )}\n </Box>\n );\n}\n"],"mappings":"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","names":[]}
|