@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
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import Code from '@mui/icons-material/Code';
|
|
2
|
+
import FormatBold from '@mui/icons-material/FormatBold';
|
|
3
|
+
import FormatItalic from '@mui/icons-material/FormatItalic';
|
|
4
|
+
import FormatListBulleted from '@mui/icons-material/FormatListBulleted';
|
|
5
|
+
import FormatListNumbered from '@mui/icons-material/FormatListNumbered';
|
|
6
|
+
import FormatQuote from '@mui/icons-material/FormatQuote';
|
|
7
|
+
import FormatStrikethrough from '@mui/icons-material/FormatStrikethrough';
|
|
8
|
+
import FormatUnderlined from '@mui/icons-material/FormatUnderlined';
|
|
9
|
+
import Image from '@mui/icons-material/Image';
|
|
10
|
+
import Link from '@mui/icons-material/Link';
|
|
11
|
+
import { alpha, Box, Divider, IconButton, Toolbar, Tooltip, Typography } from '@mui/material';
|
|
12
|
+
import type { FC, ReactElement } from 'react';
|
|
13
|
+
import React from 'react';
|
|
14
|
+
|
|
15
|
+
import type { ToolbarConfig } from './RichTextEditor.types';
|
|
16
|
+
|
|
17
|
+
type ResolvedToolbar = Required<Omit<ToolbarConfig, 'customItems'>> &
|
|
18
|
+
Pick<ToolbarConfig, 'customItems'>;
|
|
19
|
+
|
|
20
|
+
// The button groups, in render order. A separator is drawn between two groups
|
|
21
|
+
// only when both actually have something switched on.
|
|
22
|
+
const GROUPS: Array<Array<{ key: keyof ResolvedToolbar; icon: ReactElement; tooltip: string; command: string; commandValue?: string }>> = [
|
|
23
|
+
[
|
|
24
|
+
{ key: 'bold', icon: <FormatBold />, tooltip: 'Bold', command: 'bold' },
|
|
25
|
+
{ key: 'italic', icon: <FormatItalic />, tooltip: 'Italic', command: 'italic' },
|
|
26
|
+
{ key: 'underline', icon: <FormatUnderlined />, tooltip: 'Underline', command: 'underline' },
|
|
27
|
+
{
|
|
28
|
+
key: 'strikethrough',
|
|
29
|
+
icon: <FormatStrikethrough />,
|
|
30
|
+
tooltip: 'Strikethrough',
|
|
31
|
+
command: 'strikethrough',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
[
|
|
35
|
+
{
|
|
36
|
+
key: 'orderedList',
|
|
37
|
+
icon: <FormatListNumbered />,
|
|
38
|
+
tooltip: 'Numbered List',
|
|
39
|
+
command: 'insertOrderedList',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: 'unorderedList',
|
|
43
|
+
icon: <FormatListBulleted />,
|
|
44
|
+
tooltip: 'Bulleted List',
|
|
45
|
+
command: 'insertUnorderedList',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
[
|
|
49
|
+
{ key: 'link', icon: <Link />, tooltip: 'Insert Link', command: 'createLink' },
|
|
50
|
+
{ key: 'image', icon: <Image />, tooltip: 'Insert Image', command: 'insertImage' },
|
|
51
|
+
{
|
|
52
|
+
key: 'codeBlock',
|
|
53
|
+
icon: <Code />,
|
|
54
|
+
tooltip: 'Code Block',
|
|
55
|
+
command: 'formatBlock',
|
|
56
|
+
commandValue: 'pre',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
key: 'quote',
|
|
60
|
+
icon: <FormatQuote />,
|
|
61
|
+
tooltip: 'Quote',
|
|
62
|
+
command: 'formatBlock',
|
|
63
|
+
commandValue: 'blockquote',
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
// Link and image need a target before they can run.
|
|
69
|
+
const PROMPTS: Record<string, { message: string; initial?: string }> = {
|
|
70
|
+
createLink: { message: 'Enter URL:', initial: 'https://' },
|
|
71
|
+
insertImage: { message: 'Enter image URL:' },
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const Separator: FC = () => <Divider orientation="vertical" flexItem sx={{ mx: 0.5 }} />;
|
|
75
|
+
|
|
76
|
+
export interface RichTextEditorToolbarProps {
|
|
77
|
+
config: ResolvedToolbar;
|
|
78
|
+
disabled: boolean;
|
|
79
|
+
readOnly: boolean;
|
|
80
|
+
maxLength?: number;
|
|
81
|
+
characterCount: number;
|
|
82
|
+
editorRef: React.RefObject<HTMLDivElement | null>;
|
|
83
|
+
onFormat: (command: string, value?: string) => void;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const ToolbarGroups: FC<{
|
|
87
|
+
config: ResolvedToolbar;
|
|
88
|
+
disabled: boolean;
|
|
89
|
+
readOnly: boolean;
|
|
90
|
+
onRun: (command: string, commandValue?: string) => void;
|
|
91
|
+
}> = ({ config, disabled, readOnly, onRun }) => {
|
|
92
|
+
const groupIsActive = (group: (typeof GROUPS)[number]) => group.some((item) => config[item.key]);
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<>
|
|
96
|
+
{GROUPS.map((group, groupIndex) => (
|
|
97
|
+
<React.Fragment key={group[0]?.key ?? groupIndex}>
|
|
98
|
+
{groupIsActive(group) && GROUPS.slice(0, groupIndex).some(groupIsActive) && <Separator />}
|
|
99
|
+
{group
|
|
100
|
+
.filter((item) => config[item.key])
|
|
101
|
+
.map((item) => (
|
|
102
|
+
<Tooltip key={item.key} title={item.tooltip}>
|
|
103
|
+
<IconButton
|
|
104
|
+
size="small"
|
|
105
|
+
onClick={() => onRun(item.command, item.commandValue)}
|
|
106
|
+
disabled={disabled || readOnly}
|
|
107
|
+
aria-label={item.tooltip}
|
|
108
|
+
data-testid={`toolbar-${item.key}`}
|
|
109
|
+
>
|
|
110
|
+
{item.icon}
|
|
111
|
+
</IconButton>
|
|
112
|
+
</Tooltip>
|
|
113
|
+
))}
|
|
114
|
+
</React.Fragment>
|
|
115
|
+
))}
|
|
116
|
+
</>
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export const RichTextEditorToolbar: FC<RichTextEditorToolbarProps> = ({
|
|
121
|
+
config,
|
|
122
|
+
disabled,
|
|
123
|
+
readOnly,
|
|
124
|
+
maxLength,
|
|
125
|
+
characterCount,
|
|
126
|
+
editorRef,
|
|
127
|
+
onFormat,
|
|
128
|
+
}) => {
|
|
129
|
+
const run = (command: string, commandValue?: string) => {
|
|
130
|
+
const prompt = PROMPTS[command];
|
|
131
|
+
if (!prompt) {
|
|
132
|
+
onFormat(command, commandValue);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const answer = window.prompt(prompt.message, prompt.initial);
|
|
137
|
+
if (answer) onFormat(command, answer);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<Toolbar
|
|
142
|
+
variant="dense"
|
|
143
|
+
data-testid="editor-toolbar"
|
|
144
|
+
sx={{
|
|
145
|
+
minHeight: 48,
|
|
146
|
+
px: 1,
|
|
147
|
+
borderBottom: (theme) => `1px solid ${theme.palette.divider}`,
|
|
148
|
+
backgroundColor: (theme) => alpha(theme.palette.background.paper, 0.8),
|
|
149
|
+
}}
|
|
150
|
+
>
|
|
151
|
+
<ToolbarGroups config={config} disabled={disabled} readOnly={readOnly} onRun={run} />
|
|
152
|
+
|
|
153
|
+
{config.customItems && config.customItems.length > 0 && (
|
|
154
|
+
<>
|
|
155
|
+
<Separator />
|
|
156
|
+
{config.customItems.map((item) => (
|
|
157
|
+
<Tooltip key={item.id} title={item.label}>
|
|
158
|
+
<IconButton
|
|
159
|
+
size="small"
|
|
160
|
+
onClick={() => item.action(editorRef.current)}
|
|
161
|
+
disabled={item.disabled || disabled || readOnly}
|
|
162
|
+
aria-label={item.label}
|
|
163
|
+
data-testid={`toolbar-custom-${item.id}`}
|
|
164
|
+
>
|
|
165
|
+
{item.icon}
|
|
166
|
+
</IconButton>
|
|
167
|
+
</Tooltip>
|
|
168
|
+
))}
|
|
169
|
+
</>
|
|
170
|
+
)}
|
|
171
|
+
|
|
172
|
+
<Box sx={{ flexGrow: 1 }} />
|
|
173
|
+
|
|
174
|
+
{maxLength && (
|
|
175
|
+
<Typography
|
|
176
|
+
variant="caption"
|
|
177
|
+
// Turns red in the last fifth of the allowance.
|
|
178
|
+
color={characterCount > maxLength * 0.8 ? 'error' : 'text.secondary'}
|
|
179
|
+
sx={{ mr: 1 }}
|
|
180
|
+
data-testid="editor-counter"
|
|
181
|
+
>
|
|
182
|
+
{characterCount}/{maxLength}
|
|
183
|
+
</Typography>
|
|
184
|
+
)}
|
|
185
|
+
</Toolbar>
|
|
186
|
+
);
|
|
187
|
+
};
|
|
@@ -302,6 +302,28 @@ export function PaletteBody<T>(view: BodyView<T>): React.JSX.Element | null {
|
|
|
302
302
|
);
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
+
/**
|
|
306
|
+
* The palette card: a flex column capped at the height its container allows, so
|
|
307
|
+
* the input and the filter chips stay pinned while only the results scroll and a
|
|
308
|
+
* long result set can never push the palette past the bottom of the viewport.
|
|
309
|
+
*/
|
|
310
|
+
export const PALETTE_CARD_SX = {
|
|
311
|
+
width: '100%',
|
|
312
|
+
maxWidth: 640,
|
|
313
|
+
maxHeight: '100%',
|
|
314
|
+
borderRadius: 2,
|
|
315
|
+
overflow: 'hidden',
|
|
316
|
+
display: 'flex',
|
|
317
|
+
flexDirection: 'column',
|
|
318
|
+
} as const;
|
|
319
|
+
|
|
320
|
+
/** The scrolling region of the card — the results, and nothing above them. */
|
|
321
|
+
export function PaletteScrollArea({ children }: { children: React.ReactNode }): React.JSX.Element {
|
|
322
|
+
return (
|
|
323
|
+
<Box sx={{ minHeight: 0, overflowY: 'auto', overscrollBehavior: 'contain' }}>{children}</Box>
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
305
327
|
export { Paper };
|
|
306
328
|
|
|
307
329
|
/** Context for the keydown handler builder. */
|
|
@@ -4,8 +4,10 @@ import {
|
|
|
4
4
|
createKeyDownHandler,
|
|
5
5
|
FilterChips,
|
|
6
6
|
ghostRemainder,
|
|
7
|
+
PALETTE_CARD_SX,
|
|
7
8
|
PaletteBody,
|
|
8
9
|
PaletteInput,
|
|
10
|
+
PaletteScrollArea,
|
|
9
11
|
Paper,
|
|
10
12
|
} from './SearchPalette.parts';
|
|
11
13
|
import type { SearchPaletteProps } from './SearchPalette.types';
|
|
@@ -104,7 +106,7 @@ export function SearchPalette<T>(props: SearchPaletteProps<T>): React.JSX.Elemen
|
|
|
104
106
|
elevation={8}
|
|
105
107
|
className={props.className}
|
|
106
108
|
data-testid={text.dataTestId}
|
|
107
|
-
sx={
|
|
109
|
+
sx={PALETTE_CARD_SX}
|
|
108
110
|
>
|
|
109
111
|
<PaletteInput
|
|
110
112
|
value={props.value}
|
|
@@ -124,14 +126,16 @@ export function SearchPalette<T>(props: SearchPaletteProps<T>): React.JSX.Elemen
|
|
|
124
126
|
onToggleFilter={props.onToggleFilter}
|
|
125
127
|
/>
|
|
126
128
|
)}
|
|
127
|
-
<
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
129
|
+
<PaletteScrollArea>
|
|
130
|
+
<PaletteBody<T>
|
|
131
|
+
hasQuery={hasQuery} emptyQueryContent={props.emptyQueryContent} visible={visible}
|
|
132
|
+
isLoading={opts.isLoading} noResultsLabel={text.noResultsLabel} showFooter={showFooter}
|
|
133
|
+
footerIndex={footerIndex} activeIndex={activeIndex} trimmed={trimmed}
|
|
134
|
+
submitAllLabel={text.submitAllLabel} getKey={props.getKey} getPrimary={props.getPrimary}
|
|
135
|
+
getSecondary={props.getSecondary} getLead={props.getLead} getTrailing={props.getTrailing}
|
|
136
|
+
onSelect={props.onSelect} onSubmitAll={props.onSubmitAll} setActiveIndex={setActiveIndex}
|
|
137
|
+
/>
|
|
138
|
+
</PaletteScrollArea>
|
|
135
139
|
</Paper>
|
|
136
140
|
);
|
|
137
141
|
}
|
|
@@ -128,7 +128,10 @@ export const FormInteraction: Story = {
|
|
|
128
128
|
{ timeout: 3000 },
|
|
129
129
|
);
|
|
130
130
|
|
|
131
|
-
await
|
|
131
|
+
await waitFor(() => {
|
|
132
|
+
// TODO: Add assertion or condition
|
|
133
|
+
expect(true).toBe(true);
|
|
134
|
+
});
|
|
132
135
|
|
|
133
136
|
const option1 = await waitFor(
|
|
134
137
|
() => {
|
|
@@ -162,7 +165,10 @@ export const FormInteraction: Story = {
|
|
|
162
165
|
{ timeout: 3000 },
|
|
163
166
|
);
|
|
164
167
|
|
|
165
|
-
await
|
|
168
|
+
await waitFor(() => {
|
|
169
|
+
// TODO: Add assertion or condition
|
|
170
|
+
expect(true).toBe(true);
|
|
171
|
+
});
|
|
166
172
|
|
|
167
173
|
const option2 = await waitFor(
|
|
168
174
|
() => {
|
|
@@ -249,7 +255,10 @@ export const StateChangeTest: Story = {
|
|
|
249
255
|
{ timeout: 3000 },
|
|
250
256
|
);
|
|
251
257
|
|
|
252
|
-
await
|
|
258
|
+
await waitFor(() => {
|
|
259
|
+
// TODO: Add assertion or condition
|
|
260
|
+
expect(true).toBe(true);
|
|
261
|
+
});
|
|
253
262
|
|
|
254
263
|
const option1 = await waitFor(
|
|
255
264
|
() => {
|
|
@@ -330,15 +339,15 @@ export const KeyboardNavigation: Story = {
|
|
|
330
339
|
const selectContainer = canvas.getByTestId('keyboard-select');
|
|
331
340
|
const selectElement = selectContainer.querySelector('[role="combobox"]') as HTMLElement;
|
|
332
341
|
await expect(selectElement).toBeInTheDocument();
|
|
333
|
-
|
|
334
|
-
await expect(selectElement).toHaveFocus();
|
|
342
|
+
await userEvent.click(selectElement);
|
|
343
|
+
await waitFor(() => expect(selectElement).toHaveFocus());
|
|
335
344
|
});
|
|
336
345
|
|
|
337
346
|
await step('Open dropdown with Enter key', async () => {
|
|
338
347
|
// MUI Select renders as a combobox role - find it using container first
|
|
339
348
|
const selectContainer = canvas.getByTestId('keyboard-select');
|
|
340
349
|
const selectElement = selectContainer.querySelector('[role="combobox"]') as HTMLElement;
|
|
341
|
-
|
|
350
|
+
await userEvent.click(selectElement);
|
|
342
351
|
|
|
343
352
|
// Use click instead of Enter for more reliable dropdown opening
|
|
344
353
|
await userEvent.click(selectElement);
|
|
@@ -481,34 +490,34 @@ export const FocusManagement: Story = {
|
|
|
481
490
|
|
|
482
491
|
await step('Tab navigation forward', async () => {
|
|
483
492
|
const beforeButton = canvas.getByTestId('before-select');
|
|
484
|
-
|
|
485
|
-
await expect(beforeButton).toHaveFocus();
|
|
493
|
+
await userEvent.click(beforeButton);
|
|
494
|
+
await waitFor(() => expect(beforeButton).toHaveFocus());
|
|
486
495
|
|
|
487
496
|
await userEvent.tab();
|
|
488
497
|
// MUI Select renders as a combobox role
|
|
489
498
|
const selectElement = canvas.getByRole('combobox');
|
|
490
|
-
await expect(selectElement).toHaveFocus();
|
|
499
|
+
await waitFor(() => expect(selectElement).toHaveFocus());
|
|
491
500
|
|
|
492
501
|
await userEvent.tab();
|
|
493
502
|
const afterButton = canvas.getByTestId('after-select');
|
|
494
|
-
await expect(afterButton).toHaveFocus();
|
|
503
|
+
await waitFor(() => expect(afterButton).toHaveFocus());
|
|
495
504
|
});
|
|
496
505
|
|
|
497
506
|
await step('Tab navigation backward', async () => {
|
|
498
507
|
await userEvent.tab({ shift: true });
|
|
499
508
|
// MUI Select renders as a combobox role
|
|
500
509
|
const selectElement = canvas.getByRole('combobox');
|
|
501
|
-
await expect(selectElement).toHaveFocus();
|
|
510
|
+
await waitFor(() => expect(selectElement).toHaveFocus());
|
|
502
511
|
|
|
503
512
|
await userEvent.tab({ shift: true });
|
|
504
513
|
const beforeButton = canvas.getByTestId('before-select');
|
|
505
|
-
await expect(beforeButton).toHaveFocus();
|
|
514
|
+
await waitFor(() => expect(beforeButton).toHaveFocus());
|
|
506
515
|
});
|
|
507
516
|
|
|
508
517
|
await step('Focus returns to select after dropdown interaction', async () => {
|
|
509
518
|
// MUI Select renders as a combobox role
|
|
510
519
|
const selectElement = canvas.getByRole('combobox');
|
|
511
|
-
|
|
520
|
+
await userEvent.click(selectElement);
|
|
512
521
|
|
|
513
522
|
// Open dropdown and select option
|
|
514
523
|
await userEvent.keyboard('{Enter}');
|
|
@@ -687,10 +696,12 @@ export const VisualStates: Story = {
|
|
|
687
696
|
await expect(helperText).toBeInTheDocument();
|
|
688
697
|
|
|
689
698
|
// Check if error styling is applied - look for the error class anywhere in the component tree
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
699
|
+
await waitFor(() => {
|
|
700
|
+
const hasErrorClass =
|
|
701
|
+
errorSelect.classList.contains('Mui-error') ||
|
|
702
|
+
Boolean(errorSelect.querySelector('.Mui-error'));
|
|
703
|
+
expect(hasErrorClass).toBe(true);
|
|
704
|
+
});
|
|
694
705
|
});
|
|
695
706
|
|
|
696
707
|
await step('Verify disabled state', async () => {
|
|
@@ -737,8 +748,9 @@ export const Performance: Story = {
|
|
|
737
748
|
play: async ({ canvasElement, step }) => {
|
|
738
749
|
const canvas = within(canvasElement);
|
|
739
750
|
|
|
740
|
-
|
|
741
|
-
|
|
751
|
+
// This bracketed the interaction below with Date.now() and asserted a
|
|
752
|
+
// wall-clock budget, which measured the machine rather than the component.
|
|
753
|
+
await step('Open a select with many options', async () => {
|
|
742
754
|
const selectContainer = canvas.getByTestId('performance-select');
|
|
743
755
|
const selectElement = selectContainer.querySelector('[role="combobox"]') as HTMLElement;
|
|
744
756
|
await userEvent.click(selectElement);
|
|
@@ -748,15 +760,8 @@ export const Performance: Story = {
|
|
|
748
760
|
expect(options.length).toBeGreaterThan(0);
|
|
749
761
|
});
|
|
750
762
|
|
|
751
|
-
const endTime = Date.now();
|
|
752
|
-
const renderTime = endTime - startTime;
|
|
753
763
|
|
|
754
|
-
// Log render time for debugging (allow console in tests)
|
|
755
|
-
// eslint-disable-next-line no-console
|
|
756
|
-
console.log(`Render time for ${manyOptions.length} options: ${renderTime}ms`);
|
|
757
764
|
|
|
758
|
-
// Assert reasonable render time
|
|
759
|
-
await expect(renderTime).toBeLessThan(2000);
|
|
760
765
|
});
|
|
761
766
|
|
|
762
767
|
await step('Test scroll performance in dropdown', async () => {
|
|
@@ -893,7 +898,10 @@ export const EdgeCases: Story = {
|
|
|
893
898
|
await userEvent.click(selectElement);
|
|
894
899
|
await userEvent.keyboard('{Escape}');
|
|
895
900
|
// Small delay to ensure state change
|
|
896
|
-
await
|
|
901
|
+
await waitFor(() => {
|
|
902
|
+
// TODO: Add assertion or condition
|
|
903
|
+
expect(true).toBe(true);
|
|
904
|
+
});
|
|
897
905
|
}
|
|
898
906
|
|
|
899
907
|
// Select should still be functional
|
|
@@ -88,8 +88,8 @@ export const BasicInteraction: Story = {
|
|
|
88
88
|
expect(slider).toHaveAttribute('aria-valuenow', '50');
|
|
89
89
|
|
|
90
90
|
// Verify slider is focusable
|
|
91
|
-
|
|
92
|
-
expect(slider).toHaveFocus();
|
|
91
|
+
await userEvent.click(slider);
|
|
92
|
+
await waitFor(() => expect(slider).toHaveFocus());
|
|
93
93
|
|
|
94
94
|
// Verify slider ARIA label or accessible name
|
|
95
95
|
expect(slider).toHaveAttribute('aria-orientation', 'horizontal');
|
|
@@ -273,8 +273,8 @@ export const KeyboardNavigation: Story = {
|
|
|
273
273
|
const slider = sliders[0] as HTMLElement; // First slider is the single-slider
|
|
274
274
|
expect(slider).toBeInTheDocument();
|
|
275
275
|
|
|
276
|
-
|
|
277
|
-
await expect(slider).toHaveFocus();
|
|
276
|
+
await userEvent.click(slider);
|
|
277
|
+
await waitFor(() => expect(slider).toHaveFocus());
|
|
278
278
|
|
|
279
279
|
// Verify keyboard accessibility attributes are present
|
|
280
280
|
expect(slider).toHaveAttribute('aria-valuenow', '50');
|
|
@@ -405,17 +405,17 @@ export const FocusManagement: Story = {
|
|
|
405
405
|
const toggleButton = canvas.getByTestId('toggle-button');
|
|
406
406
|
const afterButton = canvas.getByTestId('after-button');
|
|
407
407
|
|
|
408
|
-
|
|
409
|
-
await expect(toggleButton).toHaveFocus();
|
|
408
|
+
await userEvent.click(toggleButton);
|
|
409
|
+
await waitFor(() => expect(toggleButton).toHaveFocus());
|
|
410
410
|
|
|
411
411
|
await userEvent.tab();
|
|
412
412
|
// Find the slider directly by role
|
|
413
413
|
const slider = canvas.getByRole('slider') as HTMLElement;
|
|
414
414
|
expect(slider).toBeInTheDocument();
|
|
415
|
-
await expect(slider).toHaveFocus();
|
|
415
|
+
await waitFor(() => expect(slider).toHaveFocus());
|
|
416
416
|
|
|
417
417
|
await userEvent.tab();
|
|
418
|
-
await expect(afterButton).toHaveFocus();
|
|
418
|
+
await waitFor(() => expect(afterButton).toHaveFocus());
|
|
419
419
|
});
|
|
420
420
|
},
|
|
421
421
|
};
|
|
@@ -505,7 +505,7 @@ export const ThemeVariations: Story = {
|
|
|
505
505
|
label={`${color.charAt(0).toUpperCase() + color.slice(1)} Slider`}
|
|
506
506
|
showValue
|
|
507
507
|
unit="%"
|
|
508
|
-
defaultValue={
|
|
508
|
+
defaultValue={42}
|
|
509
509
|
/>
|
|
510
510
|
</Box>
|
|
511
511
|
),
|
|
@@ -707,8 +707,6 @@ export const Performance: Story = {
|
|
|
707
707
|
const endTime = window.performance.now();
|
|
708
708
|
const renderTime = endTime - startTime;
|
|
709
709
|
|
|
710
|
-
// eslint-disable-next-line no-console
|
|
711
|
-
console.log(`Render time for 5 sliders: ${renderTime}ms`);
|
|
712
710
|
expect(renderTime).toBeLessThan(2000);
|
|
713
711
|
});
|
|
714
712
|
},
|
|
@@ -259,7 +259,8 @@ Control the position of the label relative to the switch:
|
|
|
259
259
|
Add custom icons that transition based on the switch state:
|
|
260
260
|
|
|
261
261
|
```tsx
|
|
262
|
-
import
|
|
262
|
+
import Check from '@mui/icons-material/Check';
|
|
263
|
+
import Close from '@mui/icons-material/Close';
|
|
263
264
|
|
|
264
265
|
<Switch
|
|
265
266
|
onIcon={<Check />}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
2
|
import { Moon, Sun, Volume2, VolumeX } from 'lucide-react';
|
|
3
3
|
import React from 'react';
|
|
4
|
-
import { expect, fn,userEvent, waitFor, within } from 'storybook/test';
|
|
4
|
+
import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
|
|
5
5
|
|
|
6
6
|
import { Switch } from './Switch';
|
|
7
7
|
|
|
@@ -70,7 +70,7 @@ export const KeyboardInteraction: Story = {
|
|
|
70
70
|
await step('Focus with Tab key', async () => {
|
|
71
71
|
const switchElement = canvas.getByRole('checkbox');
|
|
72
72
|
await userEvent.tab();
|
|
73
|
-
await expect(switchElement).toHaveFocus();
|
|
73
|
+
await waitFor(() => expect(switchElement).toHaveFocus());
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
await step('Toggle with Space key', async () => {
|
|
@@ -213,15 +213,15 @@ export const FocusManagement: Story = {
|
|
|
213
213
|
|
|
214
214
|
// Focus first switch
|
|
215
215
|
await userEvent.tab();
|
|
216
|
-
await expect(firstSwitch).toHaveFocus();
|
|
216
|
+
await waitFor(() => expect(firstSwitch).toHaveFocus());
|
|
217
217
|
|
|
218
218
|
// Tab to second switch
|
|
219
219
|
await userEvent.tab();
|
|
220
|
-
await expect(secondSwitch).toHaveFocus();
|
|
220
|
+
await waitFor(() => expect(secondSwitch).toHaveFocus());
|
|
221
221
|
|
|
222
222
|
// Tab to third switch
|
|
223
223
|
await userEvent.tab();
|
|
224
|
-
await expect(thirdSwitch).toHaveFocus();
|
|
224
|
+
await waitFor(() => expect(thirdSwitch).toHaveFocus());
|
|
225
225
|
});
|
|
226
226
|
|
|
227
227
|
await step('Tab navigation backward', async () => {
|
|
@@ -230,7 +230,7 @@ export const FocusManagement: Story = {
|
|
|
230
230
|
.querySelector('input[type="checkbox"]');
|
|
231
231
|
|
|
232
232
|
await userEvent.tab({ shift: true });
|
|
233
|
-
await expect(secondSwitch).toHaveFocus();
|
|
233
|
+
await waitFor(() => expect(secondSwitch).toHaveFocus());
|
|
234
234
|
});
|
|
235
235
|
},
|
|
236
236
|
};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { alpha, keyframes } from '@mui/material';
|
|
2
|
+
import type { CSSObject, Theme } from '@mui/material/styles';
|
|
3
|
+
|
|
4
|
+
const glowAnimation = keyframes`
|
|
5
|
+
0% {
|
|
6
|
+
box-shadow: 0 0 5px currentColor;
|
|
7
|
+
}
|
|
8
|
+
50% {
|
|
9
|
+
box-shadow: 0 0 20px currentColor, 0 0 30px currentColor;
|
|
10
|
+
}
|
|
11
|
+
100% {
|
|
12
|
+
box-shadow: 0 0 5px currentColor;
|
|
13
|
+
}
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
// Ripple animation for buttons (commented out - not currently used)
|
|
17
|
+
// const rippleAnimation = keyframes`
|
|
18
|
+
// 0% {
|
|
19
|
+
// transform: scale(0);
|
|
20
|
+
// opacity: 1;
|
|
21
|
+
// }
|
|
22
|
+
// 100% {
|
|
23
|
+
// transform: scale(4);
|
|
24
|
+
// opacity: 0;
|
|
25
|
+
// }
|
|
26
|
+
// `;
|
|
27
|
+
|
|
28
|
+
// Float animation for rich text toolbar
|
|
29
|
+
export const floatAnimation = keyframes`
|
|
30
|
+
0% {
|
|
31
|
+
transform: translateY(0px);
|
|
32
|
+
}
|
|
33
|
+
50% {
|
|
34
|
+
transform: translateY(-3px);
|
|
35
|
+
}
|
|
36
|
+
100% {
|
|
37
|
+
transform: translateY(0px);
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
type ResolvedPalette = {
|
|
42
|
+
main: string;
|
|
43
|
+
dark: string;
|
|
44
|
+
light: string;
|
|
45
|
+
contrastText: string;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
type PartialPalette = { main: string; dark?: string; light?: string; contrastText?: string };
|
|
49
|
+
|
|
50
|
+
// grey is indexed by weight rather than main/dark/light, so neutral is built by
|
|
51
|
+
// hand. The literals are the MUI grey values, used if the theme omits a weight.
|
|
52
|
+
const neutralPalette = (theme: Theme): ResolvedPalette => {
|
|
53
|
+
const grey = theme.palette.grey as unknown as Record<number, string>;
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
main: grey?.[700] || '#616161',
|
|
57
|
+
dark: grey?.[800] || '#424242',
|
|
58
|
+
light: grey?.[500] || '#9e9e9e',
|
|
59
|
+
contrastText: '#fff',
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Each slot falls back to the palette's own main, then to primary — a custom
|
|
64
|
+
// theme can define main without dark or light.
|
|
65
|
+
const pick = (...candidates: Array<string | undefined>): string =>
|
|
66
|
+
candidates.find(Boolean) ?? '';
|
|
67
|
+
|
|
68
|
+
const withFallbacks = (theme: Theme, palette: PartialPalette): ResolvedPalette => ({
|
|
69
|
+
main: pick(palette?.main, theme.palette.primary.main),
|
|
70
|
+
dark: pick(palette?.dark, palette?.main, theme.palette.primary.dark),
|
|
71
|
+
light: pick(palette?.light, palette?.main, theme.palette.primary.light),
|
|
72
|
+
contrastText: pick(palette?.contrastText, '#fff'),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
export const getColorFromTheme = (theme: Theme, color: string): ResolvedPalette => {
|
|
76
|
+
if (color === 'neutral') return neutralPalette(theme);
|
|
77
|
+
|
|
78
|
+
const colorMap: Record<string, PartialPalette> = {
|
|
79
|
+
primary: theme.palette.primary,
|
|
80
|
+
secondary: theme.palette.secondary,
|
|
81
|
+
success: theme.palette.success,
|
|
82
|
+
warning: theme.palette.warning,
|
|
83
|
+
danger: theme.palette.error,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return withFallbacks(theme, colorMap[color] || theme.palette.primary);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// glass, gradient and glow are independent flags that each layer styles onto the
|
|
90
|
+
// base. Spelled out here rather than inline so the styled() callback keeps one
|
|
91
|
+
// branch instead of three.
|
|
92
|
+
export const textareaEmphasisStyles = ({
|
|
93
|
+
theme,
|
|
94
|
+
colorPalette,
|
|
95
|
+
glass,
|
|
96
|
+
gradient,
|
|
97
|
+
glow,
|
|
98
|
+
}: {
|
|
99
|
+
theme: Theme;
|
|
100
|
+
colorPalette: { main: string; light?: string; dark?: string };
|
|
101
|
+
glass?: boolean;
|
|
102
|
+
gradient?: boolean;
|
|
103
|
+
glow?: boolean;
|
|
104
|
+
}): CSSObject => {
|
|
105
|
+
const glassStyles = glass
|
|
106
|
+
? {
|
|
107
|
+
backgroundColor: alpha(theme.palette.background.paper, 0.1),
|
|
108
|
+
backdropFilter: 'blur(20px)',
|
|
109
|
+
border: `1px solid ${alpha(theme.palette.divider, 0.2)}`,
|
|
110
|
+
'&:hover': {
|
|
111
|
+
backgroundColor: alpha(theme.palette.background.paper, 0.15),
|
|
112
|
+
backdropFilter: 'blur(25px)',
|
|
113
|
+
},
|
|
114
|
+
'&:focus': {
|
|
115
|
+
backgroundColor: alpha(theme.palette.background.paper, 0.2),
|
|
116
|
+
backdropFilter: 'blur(30px)',
|
|
117
|
+
},
|
|
118
|
+
}
|
|
119
|
+
: {};
|
|
120
|
+
|
|
121
|
+
// Gradient border effect
|
|
122
|
+
const gradientStyles = gradient
|
|
123
|
+
? {
|
|
124
|
+
background: `linear-gradient(${theme.palette.background.paper}, ${theme.palette.background.paper}) padding-box,
|
|
125
|
+
linear-gradient(135deg, ${colorPalette.main}, ${colorPalette.light}) border-box`,
|
|
126
|
+
border: '2px solid transparent',
|
|
127
|
+
'&:focus': {
|
|
128
|
+
background: `linear-gradient(${theme.palette.background.paper}, ${theme.palette.background.paper}) padding-box,
|
|
129
|
+
linear-gradient(135deg, ${colorPalette.main}, ${colorPalette.dark}) border-box`,
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
: {};
|
|
133
|
+
|
|
134
|
+
// Glow effect
|
|
135
|
+
const glowStyles = glow
|
|
136
|
+
? {
|
|
137
|
+
animation: `${glowAnimation} 2s ease-in-out infinite`,
|
|
138
|
+
boxShadow: `0 0 10px ${alpha(colorPalette.main, 0.3)}`,
|
|
139
|
+
}
|
|
140
|
+
: {};
|
|
141
|
+
|
|
142
|
+
return { ...glassStyles, ...gradientStyles, ...glowStyles };
|
|
143
|
+
};
|