@12-apps/ui 1.0.0 → 1.3.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 +14 -0
- package/package.json +42 -27
- package/src/__tests__/data-grid.test.tsx +125 -0
- package/src/__tests__/package-wiring.test.ts +12 -8
- package/src/__tests__/social-login-button.test.tsx +5 -5
- package/src/__tests__/viewport.test.ts +50 -0
- package/src/charts/index.ts +8 -0
- package/src/components/data-display/Alert/Alert.md +1 -1
- package/src/components/data-display/Alert/Alert.stories.tsx +5 -7
- package/src/components/data-display/Alert/Alert.styles.tsx +255 -0
- package/src/components/data-display/Alert/Alert.test.stories.tsx +11 -13
- package/src/components/data-display/Alert/Alert.tsx +135 -328
- package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +3 -1
- package/src/components/data-display/AlertDialog/AlertDialog.tsx +191 -78
- package/src/components/data-display/AlertDialog/AlertDialog.types.ts +8 -1
- package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +5 -5
- package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.tsx +44 -35
- package/src/components/data-display/Avatar/Avatar.stories.tsx +4 -1
- package/src/components/data-display/Avatar/Avatar.test.stories.tsx +5 -3
- package/src/components/data-display/Avatar/Avatar.tsx +154 -450
- package/src/components/data-display/Avatar/Avatar.view.tsx +396 -0
- package/src/components/data-display/Badge/Badge.animations.ts +67 -0
- package/src/components/data-display/Badge/Badge.helpers.ts +74 -0
- package/src/components/data-display/Badge/Badge.stories.tsx +14 -16
- package/src/components/data-display/Badge/Badge.styles.ts +261 -0
- package/src/components/data-display/Badge/Badge.test.stories.tsx +32 -31
- package/src/components/data-display/Badge/Badge.tsx +151 -557
- package/src/components/data-display/Badge/Badge.variants.ts +106 -0
- package/src/components/data-display/Badge/BadgeContent.tsx +107 -0
- package/src/components/data-display/Banner/Banner.stories.tsx +5 -1
- package/src/components/data-display/Banner/Banner.styles.ts +120 -0
- package/src/components/data-display/Banner/Banner.tsx +179 -224
- package/src/components/data-display/Chart/Chart.md +48 -1
- package/src/components/data-display/Chart/Chart.tsx +82 -500
- package/src/components/data-display/Chart/Chart.types.ts +2 -0
- package/src/components/data-display/Chart/ChartComposables.tsx +121 -0
- package/src/components/data-display/Chart/ChartSpec.types.ts +70 -0
- package/src/components/data-display/Chart/SpecChart.stories.tsx +150 -0
- package/src/components/data-display/Chart/SpecChart.test.stories.tsx +56 -0
- package/src/components/data-display/Chart/SpecChart.tsx +53 -0
- package/src/components/data-display/Chart/__tests__/SpecChart.test.tsx +60 -0
- package/src/components/data-display/Chart/__tests__/chart-format.test.ts +43 -0
- package/src/components/data-display/Chart/__tests__/chart-spec.test.ts +119 -0
- package/src/components/data-display/Chart/chart-format.ts +26 -0
- package/src/components/data-display/Chart/chart-internals.ts +148 -0
- package/src/components/data-display/Chart/chart-renderers.tsx +338 -0
- package/src/components/data-display/Chart/chart-spec-registry.ts +74 -0
- package/src/components/data-display/Chart/chart-spec.ts +171 -0
- package/src/components/data-display/Chart/index.ts +30 -0
- package/src/components/data-display/Chip/Chip.helpers.tsx +131 -0
- package/src/components/data-display/Chip/Chip.stories.tsx +2 -1
- package/src/components/data-display/Chip/Chip.test.stories.tsx +11 -8
- package/src/components/data-display/Chip/Chip.tsx +31 -94
- package/src/components/data-display/DataGrid/DataGrid.body.tsx +141 -0
- package/src/components/data-display/DataGrid/DataGrid.cells.tsx +238 -0
- package/src/components/data-display/DataGrid/DataGrid.model.ts +315 -0
- package/src/components/data-display/DataGrid/DataGrid.rows.ts +112 -0
- package/src/components/data-display/DataGrid/DataGrid.states.tsx +102 -0
- package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +6 -12
- package/src/components/data-display/DataGrid/DataGrid.tsx +129 -725
- package/src/components/data-display/DataViews/DataViewsGrid.tsx +187 -0
- package/src/components/data-display/DataViews/DataViewsTableBase.tsx +400 -0
- package/src/components/data-display/DataViews/ManageViewsDialog.tsx +140 -0
- package/src/components/data-display/DataViews/SaveViewModal.tsx +289 -0
- package/src/components/data-display/DataViews/__tests__/DataViewsGrid.test.tsx +271 -0
- package/src/components/data-display/DataViews/__tests__/DataViewsTableBase.test.tsx +134 -0
- package/src/components/data-display/DataViews/__tests__/SaveViewModal.test.tsx +83 -0
- package/src/components/data-display/DataViews/__tests__/data-views-filter.test.ts +115 -0
- package/src/components/data-display/DataViews/__tests__/data-views-preview.test.ts +53 -0
- package/src/components/data-display/DataViews/__tests__/range-pill.test.tsx +114 -0
- package/src/components/data-display/DataViews/base-card.stories.tsx +136 -0
- package/src/components/data-display/DataViews/base-card.tsx +278 -0
- package/src/components/data-display/DataViews/data-views-filter-panel.tsx +184 -0
- package/src/components/data-display/DataViews/data-views-filter.ts +138 -0
- package/src/components/data-display/DataViews/data-views-grid-helpers.tsx +248 -0
- package/src/components/data-display/DataViews/data-views-grid-parts.tsx +400 -0
- package/src/components/data-display/DataViews/data-views-inline-bar.tsx +257 -0
- package/src/components/data-display/DataViews/data-views-layout-context.tsx +176 -0
- package/src/components/data-display/DataViews/data-views-pagination.tsx +31 -0
- package/src/components/data-display/DataViews/data-views-preview.ts +53 -0
- package/src/components/data-display/DataViews/data-views-range-pill.tsx +277 -0
- package/src/components/data-display/DataViews/data-views-table-parts.tsx +150 -0
- package/src/components/data-display/DataViews/data-views-toolbar.tsx +149 -0
- package/src/components/data-display/DataViews/data-views-types.ts +312 -0
- package/src/components/data-display/DataViews/data-views-view-mutations.ts +68 -0
- package/src/components/data-display/DataViews/index.ts +33 -0
- package/src/components/data-display/DataViews/use-data-views-state.ts +349 -0
- package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.hooks.ts +104 -0
- package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +68 -118
- package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +1 -1
- package/src/components/data-display/DescriptionItem/DescriptionItem.tsx +52 -34
- package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +6 -6
- package/src/components/data-display/EmptyState/EmptyState.tsx +218 -135
- package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +2 -2
- package/src/components/data-display/ErrorState/ErrorState.tsx +83 -55
- package/src/components/data-display/HoverCard/HoverCard.stories.tsx +3 -1
- package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +5 -5
- package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.hooks.ts +99 -0
- package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.styles.ts +87 -0
- package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.tsx +28 -155
- package/src/components/data-display/LazyImage/LazyImage.hooks.ts +203 -0
- package/src/components/data-display/LazyImage/LazyImage.md +1 -1
- package/src/components/data-display/LazyImage/LazyImage.stories.tsx +3 -3
- package/src/components/data-display/LazyImage/LazyImage.tsx +144 -243
- package/src/components/data-display/Lightbox/Lightbox.constants.ts +53 -0
- package/src/components/data-display/Lightbox/Lightbox.helpers.ts +39 -0
- package/src/components/data-display/Lightbox/Lightbox.hooks.ts +259 -0
- package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +28 -35
- package/src/components/data-display/Lightbox/Lightbox.tsx +98 -658
- package/src/components/data-display/Lightbox/LightboxControls.tsx +152 -0
- package/src/components/data-display/Lightbox/LightboxCurrentMedia.tsx +50 -0
- package/src/components/data-display/Lightbox/LightboxMedia.tsx +76 -0
- package/src/components/data-display/Lightbox/LightboxOverlay.tsx +83 -0
- package/src/components/data-display/Lightbox/LightboxStage.tsx +97 -0
- package/src/components/data-display/Lightbox/LightboxThumbnails.tsx +83 -0
- package/src/components/data-display/Lightbox/useLightbox.ts +80 -0
- package/src/components/data-display/LoadingState/LoadingState.helpers.ts +52 -0
- package/src/components/data-display/LoadingState/LoadingState.tsx +117 -87
- package/src/components/data-display/MapPreview/MapControlBar.tsx +116 -0
- package/src/components/data-display/MapPreview/MapDecorations.tsx +155 -0
- package/src/components/data-display/MapPreview/MapLayers.tsx +70 -0
- package/src/components/data-display/MapPreview/MapMarkers.tsx +84 -0
- package/src/components/data-display/MapPreview/MapOverlays.tsx +68 -0
- package/src/components/data-display/MapPreview/MapPreview.constants.ts +19 -0
- package/src/components/data-display/MapPreview/MapPreview.helpers.ts +63 -0
- package/src/components/data-display/MapPreview/MapPreview.hooks.ts +265 -0
- package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +14 -10
- package/src/components/data-display/MapPreview/MapPreview.tsx +52 -882
- package/src/components/data-display/MapPreview/MapPreview.types.ts +8 -1
- package/src/components/data-display/MapPreview/MapSearchBar.tsx +64 -0
- package/src/components/data-display/MapPreview/MapTiles.tsx +70 -0
- package/src/components/data-display/MapPreview/StaticMapView.tsx +63 -0
- package/src/components/data-display/MapPreview/mapProjection.ts +52 -0
- package/src/components/data-display/MapPreview/mapSurface.ts +37 -0
- package/src/components/data-display/MapPreview/useMapPreview.ts +62 -0
- package/src/components/data-display/Popover/Popover.test.stories.tsx +13 -19
- package/src/components/data-display/Progress/Progress.helpers.ts +37 -0
- package/src/components/data-display/Progress/Progress.styles.ts +101 -0
- package/src/components/data-display/Progress/Progress.tsx +185 -213
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +1 -1
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.tsx +1 -1
- package/src/components/data-display/StatCard/StatCard.md +117 -0
- package/src/components/data-display/StatCard/StatCard.stories.tsx +167 -0
- package/src/components/data-display/StatCard/StatCard.test.stories.tsx +240 -0
- package/src/components/data-display/StatCard/StatCard.tsx +236 -0
- package/src/components/data-display/StatCard/StatCard.types.ts +62 -0
- package/src/components/data-display/StatCard/index.ts +7 -0
- package/src/components/data-display/Stepper/Stepper.test.stories.tsx +12 -19
- package/src/components/data-display/Stepper/Stepper.tsx +1 -1
- package/src/components/data-display/Table/Table.helpers.ts +31 -0
- package/src/components/data-display/Table/Table.hooks.ts +161 -0
- package/src/components/data-display/Table/Table.stories.tsx +3 -1
- package/src/components/data-display/Table/Table.styles.ts +223 -0
- package/src/components/data-display/Table/Table.test.stories.tsx +4 -4
- package/src/components/data-display/Table/Table.tsx +291 -748
- package/src/components/data-display/Table/TableParts.hooks.tsx +112 -0
- package/src/components/data-display/Table/TableParts.tsx +298 -0
- package/src/components/data-display/Table/TableStates.tsx +21 -0
- package/src/components/data-display/Timeline/Timeline.stories.tsx +10 -12
- package/src/components/data-display/Timeline/Timeline.test.stories.tsx +30 -44
- package/src/components/data-display/Timeline/Timeline.tsx +23 -284
- package/src/components/data-display/Timeline/TimelineRow.tsx +346 -0
- package/src/components/data-display/TimingDiagram/TimingDiagram.tsx +38 -311
- package/src/components/data-display/TimingDiagram/TimingDiagram.views.tsx +346 -0
- package/src/components/data-display/Tooltip/Tooltip.stories.tsx +4 -1
- package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +44 -58
- package/src/components/data-display/Tooltip/Tooltip.tsx +67 -62
- package/src/components/data-display/index.ts +1 -0
- package/src/components/feedback/ConfirmAction/ConfirmAction.hooks.ts +96 -0
- package/src/components/feedback/ConfirmAction/ConfirmAction.md +140 -0
- package/src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx +154 -0
- package/src/components/feedback/ConfirmAction/ConfirmAction.stories.tsx +146 -0
- package/src/components/feedback/ConfirmAction/ConfirmAction.test.stories.tsx +114 -0
- package/src/components/feedback/ConfirmAction/ConfirmAction.tsx +46 -0
- package/src/components/feedback/ConfirmAction/ConfirmAction.types.ts +111 -0
- package/src/components/feedback/ConfirmAction/ConfirmButton.tsx +18 -0
- package/src/components/feedback/ConfirmAction/__tests__/confirm-action.test.tsx +288 -0
- package/src/components/feedback/ConfirmAction/index.ts +16 -0
- package/src/components/feedback/ConfirmAction/with-confirmation.tsx +112 -0
- package/src/components/feedback/Dialog/Dialog.styles.ts +4 -2
- package/src/components/feedback/Dialog/Dialog.tsx +26 -1
- package/src/components/feedback/Dialog/__tests__/dialog-content-spacing.test.tsx +66 -0
- package/src/components/feedback/Modal/Modal.md +1 -1
- package/src/components/feedback/Modal/Modal.stories.tsx +2 -2
- package/src/components/feedback/Sonner/Sonner.tsx +104 -288
- package/src/components/feedback/Sonner/Sonner.types.ts +7 -0
- package/src/components/feedback/Sonner/SonnerToast.tsx +216 -0
- package/src/components/feedback/StackedModal/StackedModal.hooks.ts +226 -0
- package/src/components/feedback/StackedModal/StackedModal.parts.tsx +311 -0
- package/src/components/feedback/StackedModal/StackedModal.stories.tsx +13 -15
- package/src/components/feedback/StackedModal/StackedModal.styles.ts +193 -0
- package/src/components/feedback/StackedModal/StackedModal.tsx +100 -619
- package/src/components/feedback/StackedModal/StackedModal.types.ts +17 -3
- package/src/components/feedback/StackedModal/__tests__/stacked-modal-viewport.test.tsx +104 -0
- package/src/components/feedback/StackedModal/modal-stack.tsx +119 -0
- package/src/components/feedback/Toast/Toast.tsx +92 -81
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.geometry.ts +65 -0
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.hooks.ts +185 -0
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +2 -2
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.tsx +156 -414
- package/src/components/feedback/TutorialOverlay/TutorialStepBody.tsx +255 -0
- package/src/components/feedback/index.ts +1 -0
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.helpers.ts +58 -0
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.hooks.ts +93 -0
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.mapper.ts +57 -0
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +4 -2
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +20 -16
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.tsx +26 -829
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.types.ts +11 -0
- package/src/components/form/AddressAutocomplete/AddressAutocompleteField.tsx +86 -0
- package/src/components/form/AddressAutocomplete/AddressFallbackField.tsx +64 -0
- package/src/components/form/AddressAutocomplete/AddressInputField.tsx +80 -0
- package/src/components/form/AddressAutocomplete/AddressOption.tsx +83 -0
- package/src/components/form/AddressAutocomplete/AddressSuggestionsPaper.tsx +24 -0
- package/src/components/form/AddressAutocomplete/AddressTextField.tsx +43 -0
- package/src/components/form/AddressAutocomplete/mockPlaces.ts +208 -0
- package/src/components/form/AddressAutocomplete/useAddressPredictions.ts +136 -0
- package/src/components/form/AddressAutocomplete/useAddressSelection.ts +113 -0
- package/src/components/form/AddressAutocomplete/useCurrentLocation.ts +116 -0
- package/src/components/form/AddressAutocomplete/useGoogleMapsAPI.ts +75 -0
- package/src/components/form/Button/Button.helpers.ts +36 -0
- package/src/components/form/Button/Button.stories.tsx +4 -1
- package/src/components/form/Button/Button.styles.ts +225 -0
- package/src/components/form/Button/Button.test.stories.tsx +25 -21
- package/src/components/form/Button/Button.tsx +45 -252
- package/src/components/form/Calendar/Calendar.dates.ts +100 -0
- package/src/components/form/Calendar/Calendar.helpers.ts +32 -0
- package/src/components/form/Calendar/Calendar.hooks.ts +278 -0
- package/src/components/form/Calendar/Calendar.keyboard.ts +32 -0
- package/src/components/form/Calendar/Calendar.selection.ts +156 -0
- package/src/components/form/Calendar/Calendar.test.stories.tsx +33 -34
- package/src/components/form/Calendar/Calendar.tsx +63 -551
- package/src/components/form/Calendar/Calendar.types.ts +16 -0
- package/src/components/form/Calendar/CalendarDay.tsx +127 -0
- package/src/components/form/Calendar/CalendarDayCell.tsx +52 -0
- package/src/components/form/Calendar/CalendarMonth.tsx +128 -0
- package/src/components/form/CepField/CepField.md +138 -0
- package/src/components/form/CepField/CepField.stories.tsx +138 -0
- package/src/components/form/CepField/CepField.test.stories.tsx +281 -0
- package/src/components/form/CepField/CepField.tsx +211 -0
- package/src/components/form/CepField/CepField.types.ts +73 -0
- package/src/components/form/CepField/index.ts +2 -0
- package/src/components/form/Checkbox/Checkbox.helpers.ts +28 -0
- package/src/components/form/Checkbox/Checkbox.tsx +19 -16
- package/src/components/form/CodeEditor/CodeEditor.helpers.ts +45 -0
- package/src/components/form/CodeEditor/CodeEditor.hooks.ts +104 -0
- package/src/components/form/CodeEditor/CodeEditor.monaco.ts +109 -0
- package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +17 -18
- package/src/components/form/CodeEditor/CodeEditor.tsx +81 -330
- package/src/components/form/CodeEditor/CodeEditorToolbar.tsx +168 -0
- package/src/components/form/Command/Command.hooks.ts +207 -0
- package/src/components/form/Command/Command.parts.tsx +58 -0
- package/src/components/form/Command/Command.styles.ts +83 -0
- package/src/components/form/Command/Command.tsx +61 -270
- package/src/components/form/CreatableSelect/CreatableSelect.md +1 -1
- package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +1 -1
- package/src/components/form/CreatableSelect/CreatableSelect.tsx +152 -71
- package/src/components/form/CreatableSelect/CreatableSelect.types.ts +13 -0
- package/src/components/form/HeaderButton/HeaderButton.tsx +80 -0
- package/src/components/form/HeaderButton/index.ts +2 -0
- package/src/components/form/Input/Input.stories.tsx +5 -1
- package/src/components/form/Input/Input.styles.ts +176 -0
- package/src/components/form/Input/Input.test.stories.tsx +30 -23
- package/src/components/form/Input/Input.tsx +71 -211
- package/src/components/form/Input/Input.types.ts +11 -0
- package/src/components/form/InputOTP/InputOTP.test.stories.tsx +9 -17
- package/src/components/form/Menubar/Menubar.test.stories.tsx +4 -8
- package/src/components/form/PasswordStrength/PasswordStrength.helpers.tsx +117 -0
- package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +3 -3
- package/src/components/form/PasswordStrength/PasswordStrength.tsx +202 -255
- package/src/components/form/PhoneInput/PhoneInput.hooks.ts +134 -0
- package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +4 -4
- package/src/components/form/PhoneInput/PhoneInput.tsx +279 -292
- package/src/components/form/PhoneInput/countries.ts +54 -0
- package/src/components/form/PhoneInput/phone.ts +47 -0
- package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +9 -9
- package/src/components/form/RichTextEditor/RichTextEditor.dom.ts +124 -0
- package/src/components/form/RichTextEditor/RichTextEditor.format.ts +61 -0
- package/src/components/form/RichTextEditor/RichTextEditor.hooks.ts +142 -0
- package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +5 -12
- package/src/components/form/RichTextEditor/RichTextEditor.tsx +98 -410
- package/src/components/form/RichTextEditor/RichTextEditorToolbar.tsx +187 -0
- package/src/components/form/SearchPalette/SearchPalette.parts.tsx +22 -0
- package/src/components/form/SearchPalette/SearchPalette.tsx +13 -9
- package/src/components/form/Select/Select.test.stories.tsx +35 -27
- package/src/components/form/Slider/Slider.test.stories.tsx +9 -11
- package/src/components/form/Switch/Switch.md +2 -1
- package/src/components/form/Switch/Switch.test.stories.tsx +6 -6
- package/src/components/form/Textarea/Textarea.styles.ts +143 -0
- package/src/components/form/Textarea/Textarea.test.stories.tsx +20 -26
- package/src/components/form/Textarea/Textarea.tsx +114 -535
- package/src/components/form/Textarea/TextareaRichEditor.tsx +377 -0
- package/src/components/form/Toggle/Toggle.styles.ts +211 -0
- package/src/components/form/Toggle/Toggle.test.stories.tsx +19 -27
- package/src/components/form/Toggle/Toggle.tsx +10 -185
- package/src/components/form/UploadButton/UploadButton.hooks.ts +323 -0
- package/src/components/form/UploadButton/UploadButton.parts.tsx +210 -0
- package/src/components/form/UploadButton/UploadButton.stories.tsx +2 -1
- package/src/components/form/UploadButton/UploadButton.test.stories.tsx +123 -4
- package/src/components/form/UploadButton/UploadButton.tsx +76 -305
- package/src/components/form/UploadButton/UploadButton.types.ts +16 -0
- package/src/components/form/index.ts +1 -0
- package/src/components/form/total-form/Fields/CepField.tsx +143 -0
- package/src/components/form/total-form/Fields/ToggleField.tsx +61 -0
- package/src/components/form/total-form/Fields/index.ts +4 -0
- package/src/components/form/total-form/FormContainer.tsx +3 -3
- package/src/components/form/total-form/SubmitButton.tsx +25 -2
- package/src/components/form/total-form/total-form.test.tsx +118 -1
- package/src/components/layout/Accordion/Accordion.md +1 -1
- package/src/components/layout/Accordion/Accordion.stories.tsx +5 -1
- package/src/components/layout/Accordion/Accordion.styles.ts +80 -0
- package/src/components/layout/Accordion/Accordion.test.stories.tsx +32 -50
- package/src/components/layout/Accordion/Accordion.tsx +2 -75
- package/src/components/layout/Card/Card.helpers.ts +30 -0
- package/src/components/layout/Card/Card.stories.tsx +9 -11
- package/src/components/layout/Card/Card.styles.ts +182 -0
- package/src/components/layout/Card/Card.test.stories.tsx +46 -46
- package/src/components/layout/Card/Card.tsx +24 -241
- package/src/components/layout/CardGrid/CardGrid.md +96 -0
- package/src/components/layout/CardGrid/CardGrid.tsx +140 -0
- package/src/components/layout/CardGrid/__tests__/CardGrid.test.tsx +92 -0
- package/src/components/layout/CardGrid/index.ts +2 -0
- package/src/components/layout/Collapsible/Collapsible.helpers.ts +83 -0
- package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +7 -3
- package/src/components/layout/Collapsible/Collapsible.tsx +111 -107
- package/src/components/layout/Container/Container.test.stories.tsx +11 -16
- package/src/components/layout/ContentToolbar/ColumnsMenu.tsx +1 -1
- package/src/components/layout/ContentToolbar/ContentToolbar.tsx +120 -44
- package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +9 -0
- package/src/components/layout/ContentToolbar/FilterTrigger.tsx +1 -1
- package/src/components/layout/ContentToolbar/MultiSelectDropdown.tsx +58 -43
- package/src/components/layout/ContentToolbar/MultiSelectTriggers.tsx +139 -0
- package/src/components/layout/ContentToolbar/SavedViewsMenu.tsx +10 -3
- package/src/components/layout/ContentToolbar/SortByDropdown.tsx +35 -11
- package/src/components/layout/ContentToolbar/ViewSelector.tsx +5 -6
- package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +21 -0
- package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +27 -1
- package/src/components/layout/Dashboard/Dashboard.tsx +27 -8
- package/src/components/layout/Dashboard/DashboardParts.tsx +12 -19
- package/src/components/layout/Dashboard/index.ts +2 -1
- package/src/components/layout/Drawer/Drawer.stories.tsx +8 -10
- package/src/components/layout/Drawer/Drawer.test.stories.tsx +18 -14
- package/src/components/layout/Drawer/Drawer.tsx +67 -53
- package/src/components/layout/Resizable/Resizable.helpers.ts +133 -0
- package/src/components/layout/Resizable/Resizable.hooks.ts +68 -0
- package/src/components/layout/Resizable/Resizable.tsx +38 -153
- package/src/components/layout/ScrollArea/ScrollArea.helpers.ts +51 -0
- package/src/components/layout/ScrollArea/ScrollArea.styles.ts +248 -0
- package/src/components/layout/ScrollArea/ScrollArea.tsx +183 -374
- package/src/components/layout/ScrollArea/ScrollAreaContent.tsx +70 -0
- package/src/components/layout/ScrollArea/ScrollViewport.tsx +90 -0
- package/src/components/layout/Separator/Separator.styles.ts +128 -0
- package/src/components/layout/Separator/Separator.test.stories.tsx +3 -12
- package/src/components/layout/Separator/Separator.tsx +6 -132
- package/src/components/layout/SettingsLayout/SettingsLayout.parts.tsx +2 -1
- package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +6 -8
- package/src/components/layout/Sidebar/Sidebar.stories.tsx +10 -12
- package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +35 -37
- package/src/components/layout/Skeleton/Skeleton.helpers.ts +33 -0
- package/src/components/layout/Skeleton/Skeleton.styles.ts +114 -0
- package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +3 -3
- package/src/components/layout/Skeleton/Skeleton.tsx +67 -155
- package/src/components/layout/TableFilter/TableFilter.tsx +2 -1
- package/src/components/navigation/Breadcrumbs/BreadcrumbEntry.tsx +305 -0
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.md +2 -1
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +12 -14
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.styles.tsx +212 -0
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +62 -61
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +116 -429
- package/src/components/navigation/CommandPalette/CommandPalette.helpers.ts +82 -0
- package/src/components/navigation/CommandPalette/CommandPalette.hooks.ts +202 -0
- package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +3 -1
- package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +3 -5
- package/src/components/navigation/CommandPalette/CommandPalette.tsx +108 -341
- package/src/components/navigation/CommandPalette/CommandPaletteResults.tsx +182 -0
- package/src/components/navigation/CommandPalette/ShortcutChip.tsx +18 -0
- package/src/components/navigation/ContextMenu/ContextMenu.md +3 -1
- package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +4 -1
- package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +19 -24
- package/src/components/navigation/ContextMenu/ContextMenu.tsx +70 -54
- package/src/components/navigation/DropdownMenu/DropdownMenu.md +3 -1
- package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +17 -19
- package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +26 -26
- package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +189 -111
- package/src/components/navigation/NavigationMenu/NavigationMegaSection.tsx +66 -0
- package/src/components/navigation/NavigationMenu/NavigationMenu.md +7 -2
- package/src/components/navigation/NavigationMenu/NavigationMenu.shell.tsx +218 -0
- package/src/components/navigation/NavigationMenu/NavigationMenu.styles.ts +223 -0
- package/src/components/navigation/NavigationMenu/NavigationMenu.tsx +119 -808
- package/src/components/navigation/NavigationMenu/NavigationMenuItem.hooks.ts +126 -0
- package/src/components/navigation/NavigationMenu/NavigationMenuItem.tsx +352 -0
- package/src/components/navigation/NavigationMenu/NavigationStandardBody.tsx +148 -0
- package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +15 -17
- package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +27 -23
- package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +11 -13
- package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +9 -11
- package/src/components/navigation/Pagination/Pagination.helpers.tsx +85 -0
- package/src/components/navigation/Pagination/Pagination.md +2 -1
- package/src/components/navigation/Pagination/Pagination.stories.tsx +4 -6
- package/src/components/navigation/Pagination/Pagination.styles.ts +135 -0
- package/src/components/navigation/Pagination/Pagination.tsx +178 -313
- package/src/components/navigation/Pagination/PaginationParts.tsx +81 -0
- package/src/components/navigation/Tabs/Tabs.md +3 -1
- package/src/components/navigation/Tabs/Tabs.stories.tsx +21 -23
- package/src/components/navigation/Tabs/Tabs.styles.ts +163 -0
- package/src/components/navigation/Tabs/Tabs.test.stories.tsx +37 -37
- package/src/components/navigation/Tabs/Tabs.tsx +192 -361
- package/src/components/navigation/Tabs/TabsPanel.tsx +100 -0
- package/src/components/typography/Blockquote/Blockquote.tsx +1 -1
- package/src/components/typography/Code/Code.test.stories.tsx +5 -5
- package/src/components/typography/Code/Code.tsx +74 -49
- package/src/components/typography/Heading/Heading.test.stories.tsx +8 -8
- package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +5 -12
- package/src/components/typography/Text/Text.tsx +84 -77
- package/src/components/utility/AnimatedIcon/AnimatedIcon.md +4 -4
- package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +19 -21
- package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +19 -12
- package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +9 -9
- package/src/components/utility/InfiniteScroll/InfiniteScroll.hooks.ts +118 -0
- package/src/components/utility/InfiniteScroll/InfiniteScroll.parts.tsx +54 -0
- package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +12 -9
- package/src/components/utility/InfiniteScroll/InfiniteScroll.tsx +29 -148
- package/src/components/utility/InstallPrompt/InstallPrompt.helpers.ts +124 -0
- package/src/components/utility/InstallPrompt/InstallPrompt.md +113 -0
- package/src/components/utility/InstallPrompt/InstallPrompt.stories.tsx +118 -0
- package/src/components/utility/InstallPrompt/InstallPrompt.styles.ts +50 -0
- package/src/components/utility/InstallPrompt/InstallPrompt.test.stories.tsx +83 -0
- package/src/components/utility/InstallPrompt/InstallPrompt.tsx +192 -0
- package/src/components/utility/InstallPrompt/InstallPrompt.types.ts +78 -0
- package/src/components/utility/InstallPrompt/__tests__/InstallPrompt.ios.test.tsx +65 -0
- package/src/components/utility/InstallPrompt/__tests__/usePwaInstall.test.tsx +271 -0
- package/src/components/utility/InstallPrompt/index.ts +10 -0
- package/src/components/utility/InstallPrompt/usePwaInstall.ts +171 -0
- package/src/components/utility/Transition/Transition.helpers.ts +40 -0
- package/src/components/utility/Transition/Transition.tsx +17 -68
- package/src/components/utility/VirtualList/VirtualList.hooks.ts +319 -0
- package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +49 -38
- package/src/components/utility/VirtualList/VirtualList.tsx +110 -315
- package/src/components/utility/WorkflowStep/WorkflowStep.helpers.ts +151 -0
- package/src/components/utility/WorkflowStep/WorkflowStep.parts.tsx +371 -0
- package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +9 -11
- package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +7 -7
- package/src/components/utility/WorkflowStep/WorkflowStep.tsx +51 -449
- package/src/components/utility/WorkflowStep/WorkflowStepRow.tsx +96 -0
- package/src/components/utility/index.ts +1 -0
- package/src/mui/Link.ts +2 -0
- package/src/utils/index.ts +2 -1
- package/src/utils/viewport.ts +65 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import SearchIcon from '@mui/icons-material/Search';
|
|
4
4
|
import {
|
|
5
5
|
Box,
|
|
6
6
|
Button,
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
Menu,
|
|
12
12
|
MenuItem,
|
|
13
13
|
TextField,
|
|
14
|
-
Typography,
|
|
15
14
|
} from '@mui/material';
|
|
16
15
|
import React, { useMemo, useState } from 'react';
|
|
17
16
|
|
|
@@ -20,25 +19,7 @@ import type {
|
|
|
20
19
|
MultiSelectExtraOption,
|
|
21
20
|
MultiSelectOption,
|
|
22
21
|
} from './ContentToolbar.types';
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Trigger label from the current selection: `allLabel` when none/all are
|
|
26
|
-
* selected, the single label when one, else "first (+N)". Uses Set iteration
|
|
27
|
-
* order so the label reflects the first-clicked option.
|
|
28
|
-
*/
|
|
29
|
-
function buildTriggerLabel<TValue extends string>(
|
|
30
|
-
selected: ReadonlySet<TValue>,
|
|
31
|
-
options: MultiSelectOption<TValue>[],
|
|
32
|
-
allLabel: string,
|
|
33
|
-
): string {
|
|
34
|
-
const size = selected.size;
|
|
35
|
-
if (size === 0 || size === options.length) return allLabel;
|
|
36
|
-
const labelMap = new Map(options.map((option) => [option.value, option.label]));
|
|
37
|
-
const firstValue = selected.values().next().value as TValue;
|
|
38
|
-
const firstLabel = labelMap.get(firstValue) ?? allLabel;
|
|
39
|
-
if (size === 1) return firstLabel;
|
|
40
|
-
return `${firstLabel} (+${size - 1})`;
|
|
41
|
-
}
|
|
22
|
+
import { buildTriggerLabel, InlineTrigger, PillTrigger, StackedTrigger } from './MultiSelectTriggers';
|
|
42
23
|
|
|
43
24
|
/** One checkbox menu row with an optional trailing count. */
|
|
44
25
|
function CheckboxRow({
|
|
@@ -84,11 +65,13 @@ export function MultiSelectDropdown<TValue extends string = string>({
|
|
|
84
65
|
searchable,
|
|
85
66
|
searchPlaceholder = 'Search…',
|
|
86
67
|
noResultsLabel = 'No results',
|
|
68
|
+
layout = 'inline',
|
|
87
69
|
'data-testid': testId,
|
|
88
70
|
}: MultiSelectDropdownProps<TValue>): React.JSX.Element {
|
|
89
71
|
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
|
|
90
72
|
const [query, setQuery] = useState('');
|
|
91
73
|
const open = Boolean(anchorEl);
|
|
74
|
+
const stacked = layout === 'stacked';
|
|
92
75
|
// Reset the query each time the menu closes so it reopens showing everything.
|
|
93
76
|
const close = (): void => {
|
|
94
77
|
setAnchorEl(null);
|
|
@@ -100,24 +83,18 @@ export function MultiSelectDropdown<TValue extends string = string>({
|
|
|
100
83
|
const anyExtraChecked = extraOptions?.some((option) => option.checked) ?? false;
|
|
101
84
|
const clearDisabled = selected.size === 0 && !anyExtraChecked;
|
|
102
85
|
|
|
86
|
+
const openMenu = (event: React.MouseEvent<HTMLElement>): void => setAnchorEl(event.currentTarget);
|
|
87
|
+
const triggerProps = { triggerLabel, open, onOpen: openMenu, testId };
|
|
88
|
+
|
|
89
|
+
const renderTrigger = (): React.JSX.Element => {
|
|
90
|
+
if (stacked) return <StackedTrigger label={label} {...triggerProps} />;
|
|
91
|
+
if (layout === 'pill') return <PillTrigger label={label} selectedCount={selected.size} {...triggerProps} />;
|
|
92
|
+
return <InlineTrigger label={label} {...triggerProps} />;
|
|
93
|
+
};
|
|
94
|
+
|
|
103
95
|
return (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
{label}:
|
|
107
|
-
</Typography>
|
|
108
|
-
<Button
|
|
109
|
-
variant="text"
|
|
110
|
-
size="small"
|
|
111
|
-
color="inherit"
|
|
112
|
-
data-testid={testId}
|
|
113
|
-
aria-haspopup="menu"
|
|
114
|
-
aria-expanded={open}
|
|
115
|
-
onClick={(event) => setAnchorEl(event.currentTarget)}
|
|
116
|
-
sx={{ minWidth: 0, height: 32, px: 1, gap: 0.5, color: 'text.primary', textTransform: 'none', fontWeight: 600 }}
|
|
117
|
-
>
|
|
118
|
-
{triggerLabel}
|
|
119
|
-
<ChevronDownIcon sx={{ fontSize: 14 }} />
|
|
120
|
-
</Button>
|
|
96
|
+
<>
|
|
97
|
+
{renderTrigger()}
|
|
121
98
|
<MultiSelectMenu
|
|
122
99
|
anchorEl={anchorEl}
|
|
123
100
|
open={open}
|
|
@@ -133,9 +110,10 @@ export function MultiSelectDropdown<TValue extends string = string>({
|
|
|
133
110
|
onQueryChange={setQuery}
|
|
134
111
|
searchPlaceholder={searchPlaceholder}
|
|
135
112
|
noResultsLabel={noResultsLabel}
|
|
113
|
+
matchAnchorWidth={stacked}
|
|
136
114
|
testId={testId}
|
|
137
115
|
/>
|
|
138
|
-
|
|
116
|
+
</>
|
|
139
117
|
);
|
|
140
118
|
}
|
|
141
119
|
|
|
@@ -191,9 +169,24 @@ interface MultiSelectMenuProps<TValue extends string> {
|
|
|
191
169
|
onQueryChange: (value: string) => void;
|
|
192
170
|
searchPlaceholder: string;
|
|
193
171
|
noResultsLabel: string;
|
|
172
|
+
/** Match the menu width to the trigger and left-align it (stacked select). */
|
|
173
|
+
matchAnchorWidth?: boolean;
|
|
194
174
|
testId?: string;
|
|
195
175
|
}
|
|
196
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Menu placement. Default: anchored to the trigger's right (toolbar). When
|
|
179
|
+
* `matchAnchorWidth` (stacked select), match the trigger width and left-align so
|
|
180
|
+
* the menu sits flush under the full-width control.
|
|
181
|
+
*/
|
|
182
|
+
function resolveMenuPlacement(
|
|
183
|
+
matchAnchorWidth: boolean | undefined,
|
|
184
|
+
anchorEl: HTMLElement | null,
|
|
185
|
+
): { anchorWidth: number | undefined; align: 'left' | 'right' } {
|
|
186
|
+
if (!matchAnchorWidth) return { anchorWidth: undefined, align: 'right' };
|
|
187
|
+
return { anchorWidth: anchorEl?.offsetWidth, align: 'left' };
|
|
188
|
+
}
|
|
189
|
+
|
|
197
190
|
/** The (optional) search box + checkbox list + optional "Options" section + a "Clear" footer. */
|
|
198
191
|
function MultiSelectMenu<TValue extends string>({
|
|
199
192
|
anchorEl,
|
|
@@ -210,6 +203,7 @@ function MultiSelectMenu<TValue extends string>({
|
|
|
210
203
|
onQueryChange,
|
|
211
204
|
searchPlaceholder,
|
|
212
205
|
noResultsLabel,
|
|
206
|
+
matchAnchorWidth,
|
|
213
207
|
testId,
|
|
214
208
|
}: MultiSelectMenuProps<TValue>): React.JSX.Element {
|
|
215
209
|
const trimmed = query.trim().toLowerCase();
|
|
@@ -217,18 +211,24 @@ function MultiSelectMenu<TValue extends string>({
|
|
|
217
211
|
() => (trimmed ? options.filter((option) => option.label.toLowerCase().includes(trimmed)) : options),
|
|
218
212
|
[options, trimmed],
|
|
219
213
|
);
|
|
214
|
+
const { anchorWidth, align } = resolveMenuPlacement(matchAnchorWidth, anchorEl);
|
|
220
215
|
return (
|
|
221
216
|
<Menu
|
|
222
217
|
anchorEl={anchorEl}
|
|
223
218
|
open={open}
|
|
224
219
|
onClose={close}
|
|
225
|
-
anchorOrigin={{ vertical: 'bottom', horizontal:
|
|
226
|
-
transformOrigin={{ vertical: 'top', horizontal:
|
|
220
|
+
anchorOrigin={{ vertical: 'bottom', horizontal: align }}
|
|
221
|
+
transformOrigin={{ vertical: 'top', horizontal: align }}
|
|
227
222
|
// Keep focus on the search box (don't let the Menu grab the first item),
|
|
228
223
|
// and stop MUI's typeahead from swallowing keystrokes meant for the input.
|
|
229
224
|
autoFocus={!showSearch}
|
|
230
225
|
disableAutoFocusItem
|
|
231
|
-
slotProps={{
|
|
226
|
+
slotProps={{
|
|
227
|
+
// Cap the height so a long list (e.g. many categories) scrolls instead
|
|
228
|
+
// of running off-screen; the sticky search box stays pinned on top.
|
|
229
|
+
paper: { sx: { minWidth: anchorWidth ?? 180, width: anchorWidth, maxHeight: 360 } },
|
|
230
|
+
list: { sx: { pt: showSearch ? 0 : undefined, pb: 0 } },
|
|
231
|
+
}}
|
|
232
232
|
>
|
|
233
233
|
{showSearch && (
|
|
234
234
|
<MenuSearchField query={query} onQueryChange={onQueryChange} placeholder={searchPlaceholder} testId={testId} />
|
|
@@ -277,7 +277,22 @@ function MenuClearFooter({
|
|
|
277
277
|
testId?: string;
|
|
278
278
|
}): React.JSX.Element {
|
|
279
279
|
return (
|
|
280
|
-
<Box
|
|
280
|
+
<Box
|
|
281
|
+
sx={{
|
|
282
|
+
// Pin to the bottom of the scroll viewport so it stays visible while the
|
|
283
|
+
// options list scrolls (mirrors the sticky search box on top).
|
|
284
|
+
position: 'sticky',
|
|
285
|
+
bottom: 0,
|
|
286
|
+
zIndex: 1,
|
|
287
|
+
display: 'flex',
|
|
288
|
+
justifyContent: 'flex-end',
|
|
289
|
+
borderTop: 1,
|
|
290
|
+
borderColor: 'divider',
|
|
291
|
+
bgcolor: 'background.paper',
|
|
292
|
+
px: 1,
|
|
293
|
+
py: 0.75,
|
|
294
|
+
}}
|
|
295
|
+
>
|
|
281
296
|
<Button
|
|
282
297
|
variant="text"
|
|
283
298
|
size="small"
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import ChevronDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
|
4
|
+
import { Box, Button, Typography } from '@mui/material';
|
|
5
|
+
import React, { useId } from 'react';
|
|
6
|
+
|
|
7
|
+
import type { MultiSelectOption } from './ContentToolbar.types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Trigger label from the current selection: `allLabel` when none/all are
|
|
11
|
+
* selected, the single label when one, else "first (+N)". Uses Set iteration
|
|
12
|
+
* order so the label reflects the first-clicked option.
|
|
13
|
+
*/
|
|
14
|
+
export function buildTriggerLabel<TValue extends string>(
|
|
15
|
+
selected: ReadonlySet<TValue>,
|
|
16
|
+
options: MultiSelectOption<TValue>[],
|
|
17
|
+
allLabel: string,
|
|
18
|
+
): string {
|
|
19
|
+
const size = selected.size;
|
|
20
|
+
if (size === 0 || size === options.length) return allLabel;
|
|
21
|
+
const labelMap = new Map(options.map((option) => [option.value, option.label]));
|
|
22
|
+
const firstValue = selected.values().next().value as TValue;
|
|
23
|
+
const firstLabel = labelMap.get(firstValue) ?? allLabel;
|
|
24
|
+
if (size === 1) return firstLabel;
|
|
25
|
+
return `${firstLabel} (+${size - 1})`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface TriggerProps {
|
|
29
|
+
label: string;
|
|
30
|
+
triggerLabel: string;
|
|
31
|
+
open: boolean;
|
|
32
|
+
onOpen: (event: React.MouseEvent<HTMLElement>) => void;
|
|
33
|
+
testId?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Compact `Label:` text button for a horizontal toolbar (the default layout). */
|
|
37
|
+
export function InlineTrigger({ label, triggerLabel, open, onOpen, testId }: TriggerProps): React.JSX.Element {
|
|
38
|
+
return (
|
|
39
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, fontSize: '0.875rem' }}>
|
|
40
|
+
<Typography component="span" sx={{ color: 'text.secondary', fontSize: '0.875rem' }}>
|
|
41
|
+
{label}:
|
|
42
|
+
</Typography>
|
|
43
|
+
<Button
|
|
44
|
+
variant="text"
|
|
45
|
+
size="small"
|
|
46
|
+
color="inherit"
|
|
47
|
+
data-testid={testId}
|
|
48
|
+
aria-haspopup="menu"
|
|
49
|
+
aria-expanded={open}
|
|
50
|
+
onClick={onOpen}
|
|
51
|
+
sx={{ minWidth: 0, height: 32, px: 1, gap: 0.5, color: 'text.primary', textTransform: 'none', fontWeight: 600 }}
|
|
52
|
+
>
|
|
53
|
+
{triggerLabel}
|
|
54
|
+
<ChevronDownIcon sx={{ fontSize: 14 }} />
|
|
55
|
+
</Button>
|
|
56
|
+
</Box>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Full-width, outlined select-style control with the label above (stacked layout). */
|
|
61
|
+
export function StackedTrigger({ label, triggerLabel, open, onOpen, testId }: TriggerProps): React.JSX.Element {
|
|
62
|
+
// Name the button by label + value (aria-labelledby): a <button> isn't labelable.
|
|
63
|
+
const baseId = useId();
|
|
64
|
+
return (
|
|
65
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
|
66
|
+
<Typography id={`${baseId}-label`} component="label" sx={{ fontSize: '0.75rem', fontWeight: 500, color: 'text.secondary' }}>
|
|
67
|
+
{label}
|
|
68
|
+
</Typography>
|
|
69
|
+
<Button
|
|
70
|
+
variant="outlined"
|
|
71
|
+
color="inherit"
|
|
72
|
+
fullWidth
|
|
73
|
+
data-testid={testId}
|
|
74
|
+
aria-haspopup="menu"
|
|
75
|
+
aria-expanded={open}
|
|
76
|
+
aria-labelledby={`${baseId}-label ${baseId}-value`}
|
|
77
|
+
onClick={onOpen}
|
|
78
|
+
endIcon={<ChevronDownIcon sx={{ fontSize: 18, color: 'text.secondary' }} />}
|
|
79
|
+
sx={{
|
|
80
|
+
justifyContent: 'space-between',
|
|
81
|
+
height: 40,
|
|
82
|
+
px: 1.5,
|
|
83
|
+
color: 'text.primary',
|
|
84
|
+
textTransform: 'none',
|
|
85
|
+
fontWeight: 400,
|
|
86
|
+
fontSize: '0.875rem',
|
|
87
|
+
borderColor: 'divider',
|
|
88
|
+
bgcolor: 'background.paper',
|
|
89
|
+
'&:hover': { borderColor: 'text.primary', bgcolor: 'background.paper' },
|
|
90
|
+
}}
|
|
91
|
+
>
|
|
92
|
+
<Box
|
|
93
|
+
component="span" id={`${baseId}-value`}
|
|
94
|
+
sx={{ flex: 1, minWidth: 0, textAlign: 'left', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}
|
|
95
|
+
>
|
|
96
|
+
{triggerLabel}
|
|
97
|
+
</Box>
|
|
98
|
+
</Button>
|
|
99
|
+
</Box>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Rounded outlined chip (`Label ▾`, `Label (N) ▾` when selected) for a filter row. */
|
|
104
|
+
export function PillTrigger({
|
|
105
|
+
label,
|
|
106
|
+
open,
|
|
107
|
+
onOpen,
|
|
108
|
+
testId,
|
|
109
|
+
selectedCount,
|
|
110
|
+
}: TriggerProps & { selectedCount: number }): React.JSX.Element {
|
|
111
|
+
const active = selectedCount > 0;
|
|
112
|
+
return (
|
|
113
|
+
<Button
|
|
114
|
+
variant="outlined"
|
|
115
|
+
color="inherit"
|
|
116
|
+
size="small"
|
|
117
|
+
data-testid={testId}
|
|
118
|
+
aria-haspopup="menu"
|
|
119
|
+
aria-expanded={open}
|
|
120
|
+
onClick={onOpen}
|
|
121
|
+
endIcon={<ChevronDownIcon sx={{ fontSize: 16 }} />}
|
|
122
|
+
sx={{
|
|
123
|
+
borderRadius: 999,
|
|
124
|
+
height: 34,
|
|
125
|
+
px: 1.5,
|
|
126
|
+
color: 'text.primary',
|
|
127
|
+
fontWeight: 600,
|
|
128
|
+
fontSize: '0.8125rem',
|
|
129
|
+
textTransform: 'none',
|
|
130
|
+
borderColor: active ? 'primary.main' : 'divider',
|
|
131
|
+
bgcolor: active ? 'action.selected' : 'background.paper',
|
|
132
|
+
'&:hover': { borderColor: active ? 'primary.main' : 'text.primary', bgcolor: active ? 'action.selected' : 'action.hover' },
|
|
133
|
+
}}
|
|
134
|
+
>
|
|
135
|
+
{label}
|
|
136
|
+
{active ? ` (${selectedCount})` : ''}
|
|
137
|
+
</Button>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import CheckIcon from '@mui/icons-material/Check';
|
|
4
|
+
import ChevronDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
|
5
|
+
import KebabIcon from '@mui/icons-material/MoreVert';
|
|
6
|
+
import ViewIcon from '@mui/icons-material/Visibility';
|
|
4
7
|
import { Box, Button, IconButton, Menu, MenuItem, Popover, Stack, Typography } from '@mui/material';
|
|
5
8
|
import React, { useState } from 'react';
|
|
6
9
|
|
|
@@ -278,7 +281,6 @@ export function SavedViewsMenu<V extends SavedViewLike = SavedViewLike>({
|
|
|
278
281
|
close();
|
|
279
282
|
};
|
|
280
283
|
const labels = { ...DEFAULT_LABELS, ...labelOverrides };
|
|
281
|
-
|
|
282
284
|
const pinned = views.filter((view) => view.pinned);
|
|
283
285
|
const recent = views.filter((view) => !view.pinned).slice(0, RECENT_LIMIT);
|
|
284
286
|
|
|
@@ -304,9 +306,14 @@ export function SavedViewsMenu<V extends SavedViewLike = SavedViewLike>({
|
|
|
304
306
|
data-testid={`${testIdPrefix}-button`}
|
|
305
307
|
aria-haspopup="menu"
|
|
306
308
|
aria-expanded={Boolean(anchorEl)}
|
|
309
|
+
aria-label={activeViewName ?? labels.mainView}
|
|
307
310
|
sx={{ minWidth: 0, height: 32, px: 1, gap: 0.5, color: 'text.primary', textTransform: 'none', fontWeight: 600 }}
|
|
308
311
|
>
|
|
309
|
-
{
|
|
312
|
+
{/* Mobile: an eye icon stands in for the view name to keep the toolbar one line. */}
|
|
313
|
+
<ViewIcon sx={{ fontSize: 18, display: { xs: 'inline-flex', md: 'none' } }} />
|
|
314
|
+
<Box component="span" sx={{ display: { xs: 'none', md: 'inline' } }}>
|
|
315
|
+
{activeViewName ?? labels.mainView}
|
|
316
|
+
</Box>
|
|
310
317
|
<ChevronDownIcon sx={{ fontSize: 14 }} />
|
|
311
318
|
</Button>
|
|
312
319
|
<Popover
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import CheckIcon from '@mui/icons-material/Check';
|
|
4
|
+
import ChevronDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
|
4
5
|
import { Box, Button, Divider, ListSubheader, Menu, MenuItem, Typography } from '@mui/material';
|
|
5
6
|
import React, { useState } from 'react';
|
|
6
7
|
|
|
@@ -45,6 +46,20 @@ function buildTriggerLabel(
|
|
|
45
46
|
return `${fieldDef.label} (${orderOption.label.toLowerCase()})`;
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
/** The trigger's full label (md+), short label (mobile), and direction arrow. */
|
|
50
|
+
function resolveTriggerParts(
|
|
51
|
+
fieldDef: SortFieldDefinition | undefined,
|
|
52
|
+
orderOption: SortOrderOption | undefined,
|
|
53
|
+
orderOptions: SortOrderOption[],
|
|
54
|
+
): { full: string; short: string; arrowSuffix: string } {
|
|
55
|
+
const useRangeLabel = fieldDef?.triggerLabelStyle === 'range' && orderOptions.length === 2;
|
|
56
|
+
const orderIndex = orderOptions.findIndex((option) => option.value === orderOption?.value);
|
|
57
|
+
const arrow = resolveArrowDirection(orderOption, orderIndex);
|
|
58
|
+
const arrowSuffix = orderOptions.length > 0 && !useRangeLabel ? ` ${arrow === 'down' ? '↓' : '↑'}` : '';
|
|
59
|
+
const full = buildTriggerLabel(fieldDef, orderOption);
|
|
60
|
+
return { full, short: fieldDef?.label ?? full, arrowSuffix };
|
|
61
|
+
}
|
|
62
|
+
|
|
48
63
|
const sectionLabelSx = { px: 1, py: 0.75, fontSize: '0.75rem', fontWeight: 600, color: 'text.primary', lineHeight: 1.5 } as const;
|
|
49
64
|
|
|
50
65
|
/** A fixed-width check slot (empty when unchecked) so labels align. */
|
|
@@ -162,22 +177,24 @@ export function SortByDropdown<TField extends string = string>({
|
|
|
162
177
|
const activeFieldDef = findActiveField(fields, activeField);
|
|
163
178
|
const orderOptions = activeFieldDef?.orderOptions ?? [];
|
|
164
179
|
const activeOrderOption = findActiveOrder(activeFieldDef, activeOrder);
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
const orderIndex = orderOptions.findIndex((option) => option.value === activeOrderOption?.value);
|
|
168
|
-
const arrow = resolveArrowDirection(activeOrderOption, orderIndex);
|
|
169
|
-
const arrowSuffix = orderOptions.length > 0 && !useRangeLabel ? ` ${arrow === 'down' ? '↓' : '↑'}` : '';
|
|
180
|
+
const trigger = resolveTriggerParts(activeFieldDef, activeOrderOption, orderOptions);
|
|
170
181
|
|
|
171
182
|
function handleFieldChange(field: TField): void {
|
|
183
|
+
// Switch field in ONE callback. Previously this also fired `onOrderChange`
|
|
184
|
+
// to reset the order, but a consumer whose `onOrderChange` derives the field
|
|
185
|
+
// from its own (now-stale) prop would re-apply the OLD field — silently
|
|
186
|
+
// reverting the field change (e.g. picking "E-mail" snapped back to "Nome").
|
|
187
|
+
// The field-change consumer owns the resulting order.
|
|
172
188
|
onFieldChange(field);
|
|
173
|
-
const nextOrder = safeFields.find((candidate) => candidate.value === field)?.orderOptions?.[0]?.value;
|
|
174
|
-
if (nextOrder && onOrderChange) onOrderChange(nextOrder);
|
|
175
189
|
close();
|
|
176
190
|
}
|
|
177
191
|
|
|
178
192
|
return (
|
|
179
193
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, fontSize: '0.875rem' }}>
|
|
180
|
-
<Typography
|
|
194
|
+
<Typography
|
|
195
|
+
component="span"
|
|
196
|
+
sx={{ display: { xs: 'none', md: 'inline' }, color: 'text.secondary', fontSize: '0.875rem' }}
|
|
197
|
+
>
|
|
181
198
|
Sort By:
|
|
182
199
|
</Typography>
|
|
183
200
|
<Button
|
|
@@ -190,8 +207,15 @@ export function SortByDropdown<TField extends string = string>({
|
|
|
190
207
|
onClick={(event) => setAnchorEl(event.currentTarget)}
|
|
191
208
|
sx={{ minWidth: 0, height: 32, px: 1, gap: 0.5, color: 'text.primary', textTransform: 'none', fontWeight: 600 }}
|
|
192
209
|
>
|
|
193
|
-
{
|
|
194
|
-
|
|
210
|
+
{/* Full "Nome (crescente)" on md+; just the field name on mobile — the
|
|
211
|
+
arrow already conveys the direction, so the parenthetical is dropped. */}
|
|
212
|
+
<Box component="span" sx={{ display: { xs: 'none', md: 'inline' } }}>
|
|
213
|
+
{trigger.full}
|
|
214
|
+
</Box>
|
|
215
|
+
<Box component="span" sx={{ display: { xs: 'inline', md: 'none' } }}>
|
|
216
|
+
{trigger.short}
|
|
217
|
+
</Box>
|
|
218
|
+
{trigger.arrowSuffix}
|
|
195
219
|
<ChevronDownIcon sx={{ fontSize: 14 }} />
|
|
196
220
|
</Button>
|
|
197
221
|
<SortMenu
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
FormatListBulletedRounded as ListIcon,
|
|
8
|
-
} from '@mui/icons-material';
|
|
3
|
+
import CheckIcon from '@mui/icons-material/Check';
|
|
4
|
+
import ChevronDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
|
5
|
+
import GridIcon from '@mui/icons-material/GridViewOutlined';
|
|
6
|
+
import ListIcon from '@mui/icons-material/FormatListBulletedRounded';
|
|
9
7
|
import { Box, Button, ListItemIcon, ListItemText, Menu, MenuItem, Slider } from '@mui/material';
|
|
8
|
+
// Type-only, so it is erased at build time and costs no barrel transform.
|
|
10
9
|
import type { SvgIconComponent } from '@mui/icons-material';
|
|
11
10
|
import React, { useState } from 'react';
|
|
12
11
|
|
|
@@ -108,3 +108,24 @@ describe('MultiSelectDropdown search (FUT-169)', () => {
|
|
|
108
108
|
expect(screen.getByTestId('cat-search')).toBeInTheDocument();
|
|
109
109
|
});
|
|
110
110
|
});
|
|
111
|
+
|
|
112
|
+
describe('MultiSelectDropdown stacked trigger accessibility', () => {
|
|
113
|
+
it("names the trigger by the field label AND value so it isn't announced as just its value", () => {
|
|
114
|
+
render(
|
|
115
|
+
<MultiSelectDropdown
|
|
116
|
+
label="Papéis"
|
|
117
|
+
layout="stacked"
|
|
118
|
+
options={MANY_OPTIONS}
|
|
119
|
+
selected={new Set<string>()}
|
|
120
|
+
onToggle={vi.fn()}
|
|
121
|
+
onClear={vi.fn()}
|
|
122
|
+
allLabel="Todas"
|
|
123
|
+
data-testid="roles"
|
|
124
|
+
/>,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// The accessible name resolves aria-labelledby to "<label> <value>", so the
|
|
128
|
+
// field name (not just "Todas") distinguishes this trigger from a sibling.
|
|
129
|
+
expect(screen.getByRole('button', { name: 'Papéis Todas' })).toBe(screen.getByTestId('roles'));
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -2,7 +2,7 @@ import { Box, Button, TextField, Typography } from '@mui/material';
|
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
3
|
import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
|
|
4
4
|
|
|
5
|
-
import { Dashboard } from './Dashboard';
|
|
5
|
+
import { Dashboard, markDashboardSlot } from './Dashboard';
|
|
6
6
|
|
|
7
7
|
const meta: Meta<typeof Dashboard> = {
|
|
8
8
|
title: 'Layout/Dashboard/Tests',
|
|
@@ -162,3 +162,29 @@ export const OrderIndependentRendering: Story = {
|
|
|
162
162
|
});
|
|
163
163
|
},
|
|
164
164
|
};
|
|
165
|
+
|
|
166
|
+
/** A page-owned wrapper around `<Dashboard.Header>`, tagged with its slot. */
|
|
167
|
+
const WrappedHeader = markDashboardSlot(
|
|
168
|
+
({ title }: { title: string }) => <Dashboard.Header title={title} />,
|
|
169
|
+
'header',
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
export const MarkedWrapperKeepsHeaderAboveBody: Story = {
|
|
173
|
+
name: '🧪 A slot-marked header wrapper still renders above the body',
|
|
174
|
+
render: () => (
|
|
175
|
+
<Dashboard>
|
|
176
|
+
<Dashboard.Breadcrumb items={[{ label: 'Admin', href: '#' }, { label: 'Wrapped' }]} />
|
|
177
|
+
<WrappedHeader title="Wrapped" />
|
|
178
|
+
<Dashboard.Body>{body}</Dashboard.Body>
|
|
179
|
+
</Dashboard>
|
|
180
|
+
),
|
|
181
|
+
play: async ({ canvasElement, step }) => {
|
|
182
|
+
const canvas = within(canvasElement);
|
|
183
|
+
await step('Wrapped header sits above the body, not below it', async () => {
|
|
184
|
+
const header = canvas.getByTestId('dashboard-header');
|
|
185
|
+
const content = canvas.getByTestId('dashboard-body');
|
|
186
|
+
const headerBeforeBody = header.compareDocumentPosition(content) & Node.DOCUMENT_POSITION_FOLLOWING;
|
|
187
|
+
await expect(Boolean(headerBeforeBody)).toBe(true);
|
|
188
|
+
});
|
|
189
|
+
},
|
|
190
|
+
};
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
NavigateNext as NavigateNextIcon,
|
|
8
|
-
} from '@mui/icons-material';
|
|
3
|
+
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
|
4
|
+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
5
|
+
import FilterIcon from '@mui/icons-material/FilterListRounded';
|
|
6
|
+
import NavigateNextIcon from '@mui/icons-material/NavigateNext';
|
|
9
7
|
import {
|
|
10
8
|
Box,
|
|
11
9
|
Breadcrumbs as MuiBreadcrumbs,
|
|
@@ -41,10 +39,31 @@ import type {
|
|
|
41
39
|
* a `<Dashboard.Header>` still renders below it.
|
|
42
40
|
*/
|
|
43
41
|
const SLOT_ORDER = ['breadcrumb', 'header', 'filters', 'body'] as const;
|
|
44
|
-
|
|
42
|
+
/** A slot a component can occupy in the canonical Dashboard order. */
|
|
43
|
+
export type DashboardSlot = (typeof SLOT_ORDER)[number];
|
|
45
44
|
|
|
46
45
|
/** Marker attached to each sub-component so the root can rank it by slot. */
|
|
47
|
-
type SlottedComponent = { dashboardSlot?:
|
|
46
|
+
type SlottedComponent = { dashboardSlot?: DashboardSlot };
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Tag a component with the Dashboard slot it occupies so the root ranks it in
|
|
50
|
+
* canonical order. The root inspects only its DIRECT children's `type`, so a
|
|
51
|
+
* page that wraps a `<Dashboard.Header>` (or any part) in its own component MUST
|
|
52
|
+
* mark that wrapper — otherwise it counts as an unrecognised child and sinks
|
|
53
|
+
* below the body. Returns the component for convenient inline use.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```tsx
|
|
57
|
+
* function ProductsHeader(props) {
|
|
58
|
+
* return <Dashboard.Header title="Products">{/* … *\/}</Dashboard.Header>;
|
|
59
|
+
* }
|
|
60
|
+
* markDashboardSlot(ProductsHeader, 'header');
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export function markDashboardSlot<T>(component: T, slot: DashboardSlot): T {
|
|
64
|
+
(component as SlottedComponent).dashboardSlot = slot;
|
|
65
|
+
return component;
|
|
66
|
+
}
|
|
48
67
|
|
|
49
68
|
const Root = styled(Box)(({ theme }) => ({
|
|
50
69
|
display: 'flex',
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
SettingsOutlined as SettingsIcon,
|
|
10
|
-
} from '@mui/icons-material';
|
|
3
|
+
import CloseIcon from '@mui/icons-material/Close';
|
|
4
|
+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
5
|
+
import ExportIcon from '@mui/icons-material/FileDownloadOutlined';
|
|
6
|
+
import FilterIcon from '@mui/icons-material/FilterListRounded';
|
|
7
|
+
import InfoIcon from '@mui/icons-material/InfoOutlined';
|
|
8
|
+
import SettingsIcon from '@mui/icons-material/SettingsOutlined';
|
|
11
9
|
import {
|
|
12
10
|
Badge,
|
|
13
11
|
Box,
|
|
14
|
-
Button,
|
|
15
12
|
Dialog,
|
|
16
13
|
DialogContent,
|
|
17
14
|
DialogTitle,
|
|
@@ -24,6 +21,7 @@ import {
|
|
|
24
21
|
} from '@mui/material';
|
|
25
22
|
import React, { useState } from 'react';
|
|
26
23
|
|
|
24
|
+
import { HeaderButton } from '../../form/HeaderButton';
|
|
27
25
|
import { useDashboardContext } from './DashboardContext';
|
|
28
26
|
import type {
|
|
29
27
|
DashboardActionProps,
|
|
@@ -175,22 +173,17 @@ export const DashboardExport = ({
|
|
|
175
173
|
const open = Boolean(anchorEl);
|
|
176
174
|
return (
|
|
177
175
|
<>
|
|
178
|
-
<
|
|
176
|
+
<HeaderButton
|
|
179
177
|
variant="outlined"
|
|
180
|
-
size="medium"
|
|
181
178
|
color="inherit"
|
|
182
|
-
|
|
179
|
+
text={label}
|
|
180
|
+
icon={<ExportIcon fontSize="small" />}
|
|
183
181
|
endIcon={<ExpandMoreIcon fontSize="small" />}
|
|
184
182
|
onClick={(e) => setAnchorEl(e.currentTarget)}
|
|
185
183
|
aria-haspopup="menu"
|
|
186
184
|
aria-expanded={open}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
// padding/height and a 1rem non-uppercased label.
|
|
190
|
-
sx={{ py: 1, px: 2, fontSize: '1rem', textTransform: 'none' }}
|
|
191
|
-
>
|
|
192
|
-
{label}
|
|
193
|
-
</Button>
|
|
185
|
+
dataTestId={`${testIdPrefix}-export-trigger`}
|
|
186
|
+
/>
|
|
194
187
|
<Menu anchorEl={anchorEl} open={open} onClose={() => setAnchorEl(null)} data-testid={`${testIdPrefix}-export-menu`}>
|
|
195
188
|
{formats.map((format) => (
|
|
196
189
|
<MenuItem
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { Dashboard } from './Dashboard';
|
|
1
|
+
export { Dashboard, markDashboardSlot } from './Dashboard';
|
|
2
|
+
export type { DashboardSlot } from './Dashboard';
|
|
2
3
|
export { DashboardContext, useDashboardContext } from './DashboardContext';
|
|
3
4
|
export type { DashboardContextValue } from './DashboardContext';
|
|
4
5
|
export type {
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Settings,
|
|
10
|
-
} from '@mui/icons-material';
|
|
1
|
+
import Analytics from '@mui/icons-material/Analytics';
|
|
2
|
+
import Dashboard from '@mui/icons-material/Dashboard';
|
|
3
|
+
import Help from '@mui/icons-material/Help';
|
|
4
|
+
import Home from '@mui/icons-material/Home';
|
|
5
|
+
import MenuIcon from '@mui/icons-material/Menu';
|
|
6
|
+
import Notifications from '@mui/icons-material/Notifications';
|
|
7
|
+
import Person from '@mui/icons-material/Person';
|
|
8
|
+
import Settings from '@mui/icons-material/Settings';
|
|
11
9
|
import {
|
|
12
10
|
Box,
|
|
13
11
|
Button,
|