@12-apps/ui 1.0.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 +806 -0
- package/components-guidelines.md +347 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/eslint.config.js +77 -0
- package/package.json +247 -0
- package/src/__tests__/package-wiring.test.ts +37 -0
- package/src/__tests__/setup.ts +1 -0
- package/src/__tests__/social-login-button.test.tsx +186 -0
- package/src/__tests__/user-avatar.test.tsx +195 -0
- package/src/button.tsx +22 -0
- package/src/components/command/__tests__/command.test.tsx +112 -0
- package/src/components/data-display/Alert/Alert.md +209 -0
- package/src/components/data-display/Alert/Alert.stories.tsx +561 -0
- package/src/components/data-display/Alert/Alert.test.stories.tsx +709 -0
- package/src/components/data-display/Alert/Alert.tsx +449 -0
- package/src/components/data-display/Alert/Alert.types.ts +79 -0
- package/src/components/data-display/Alert/index.ts +2 -0
- package/src/components/data-display/AlertDialog/AlertDialog.md +408 -0
- package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +360 -0
- package/src/components/data-display/AlertDialog/AlertDialog.test.stories.tsx +753 -0
- package/src/components/data-display/AlertDialog/AlertDialog.tsx +273 -0
- package/src/components/data-display/AlertDialog/AlertDialog.types.ts +74 -0
- package/src/components/data-display/AlertDialog/index.ts +2 -0
- package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.stories.tsx +230 -0
- package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +270 -0
- package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.tsx +116 -0
- package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.types.ts +70 -0
- package/src/components/data-display/AsyncStateContainer/index.ts +2 -0
- package/src/components/data-display/Avatar/Avatar.md +568 -0
- package/src/components/data-display/Avatar/Avatar.stories.tsx +718 -0
- package/src/components/data-display/Avatar/Avatar.test.stories.tsx +820 -0
- package/src/components/data-display/Avatar/Avatar.tsx +507 -0
- package/src/components/data-display/Avatar/Avatar.types.ts +88 -0
- package/src/components/data-display/Avatar/index.ts +2 -0
- package/src/components/data-display/Badge/Badge.md +469 -0
- package/src/components/data-display/Badge/Badge.stories.tsx +1136 -0
- package/src/components/data-display/Badge/Badge.test.stories.tsx +1193 -0
- package/src/components/data-display/Badge/Badge.tsx +606 -0
- package/src/components/data-display/Badge/Badge.types.ts +118 -0
- package/src/components/data-display/Badge/index.ts +2 -0
- package/src/components/data-display/Banner/Banner.stories.tsx +524 -0
- package/src/components/data-display/Banner/Banner.test.stories.tsx +503 -0
- package/src/components/data-display/Banner/Banner.tsx +350 -0
- package/src/components/data-display/Banner/Banner.types.ts +41 -0
- package/src/components/data-display/Banner/banner.md +141 -0
- package/src/components/data-display/Banner/index.ts +2 -0
- package/src/components/data-display/Carousel/Carousel.md +815 -0
- package/src/components/data-display/Carousel/Carousel.stories.tsx +607 -0
- package/src/components/data-display/Carousel/Carousel.test.stories.tsx +691 -0
- package/src/components/data-display/Carousel/Carousel.tsx +765 -0
- package/src/components/data-display/Carousel/Carousel.types.ts +79 -0
- package/src/components/data-display/Carousel/index.ts +8 -0
- package/src/components/data-display/Chart/Chart.md +352 -0
- package/src/components/data-display/Chart/Chart.stories.tsx +568 -0
- package/src/components/data-display/Chart/Chart.test.stories.tsx +174 -0
- package/src/components/data-display/Chart/Chart.tsx +520 -0
- package/src/components/data-display/Chart/Chart.types.ts +65 -0
- package/src/components/data-display/Chart/index.ts +2 -0
- package/src/components/data-display/Chip/Chip.stories.tsx +251 -0
- package/src/components/data-display/Chip/Chip.test.stories.tsx +263 -0
- package/src/components/data-display/Chip/Chip.tsx +134 -0
- package/src/components/data-display/Chip/Chip.types.ts +51 -0
- package/src/components/data-display/Chip/chip.md +395 -0
- package/src/components/data-display/Chip/index.ts +2 -0
- package/src/components/data-display/DataGrid/DataGrid.md +602 -0
- package/src/components/data-display/DataGrid/DataGrid.stories.tsx +515 -0
- package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +659 -0
- package/src/components/data-display/DataGrid/DataGrid.tsx +743 -0
- package/src/components/data-display/DataGrid/DataGrid.types.ts +171 -0
- package/src/components/data-display/DataGrid/index.ts +21 -0
- package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +197 -0
- package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.types.ts +46 -0
- package/src/components/data-display/DateTimeDisplay/index.ts +2 -0
- package/src/components/data-display/DescriptionItem/DescriptionItem.md +226 -0
- package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +254 -0
- package/src/components/data-display/DescriptionItem/DescriptionItem.tsx +100 -0
- package/src/components/data-display/DescriptionItem/DescriptionItem.types.ts +1 -0
- package/src/components/data-display/DescriptionItem/index.ts +2 -0
- package/src/components/data-display/EmptyState/EmptyState.md +265 -0
- package/src/components/data-display/EmptyState/EmptyState.stories.tsx +282 -0
- package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +441 -0
- package/src/components/data-display/EmptyState/EmptyState.tsx +180 -0
- package/src/components/data-display/EmptyState/EmptyState.types.ts +31 -0
- package/src/components/data-display/EmptyState/index.ts +2 -0
- package/src/components/data-display/ErrorState/ErrorState.stories.tsx +110 -0
- package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +133 -0
- package/src/components/data-display/ErrorState/ErrorState.tsx +118 -0
- package/src/components/data-display/ErrorState/ErrorState.types.ts +45 -0
- package/src/components/data-display/ErrorState/index.ts +2 -0
- package/src/components/data-display/HoverCard/HoverCard.md +389 -0
- package/src/components/data-display/HoverCard/HoverCard.stories.tsx +648 -0
- package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +929 -0
- package/src/components/data-display/HoverCard/HoverCard.tsx +657 -0
- package/src/components/data-display/HoverCard/HoverCard.types.ts +116 -0
- package/src/components/data-display/HoverCard/index.ts +2 -0
- package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.md +532 -0
- package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.stories.tsx +411 -0
- package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.tsx +245 -0
- package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.types.ts +64 -0
- package/src/components/data-display/InteractiveTooltip/index.ts +2 -0
- package/src/components/data-display/LazyImage/LazyImage.md +356 -0
- package/src/components/data-display/LazyImage/LazyImage.stories.tsx +387 -0
- package/src/components/data-display/LazyImage/LazyImage.tsx +323 -0
- package/src/components/data-display/LazyImage/LazyImage.types.ts +205 -0
- package/src/components/data-display/LazyImage/index.ts +2 -0
- package/src/components/data-display/Lightbox/Lightbox.stories.tsx +315 -0
- package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +605 -0
- package/src/components/data-display/Lightbox/Lightbox.tsx +666 -0
- package/src/components/data-display/Lightbox/Lightbox.types.ts +49 -0
- package/src/components/data-display/Lightbox/index.ts +2 -0
- package/src/components/data-display/Lightbox/lightbox.md +298 -0
- package/src/components/data-display/LoadingState/LoadingState.stories.tsx +124 -0
- package/src/components/data-display/LoadingState/LoadingState.test.stories.tsx +99 -0
- package/src/components/data-display/LoadingState/LoadingState.tsx +103 -0
- package/src/components/data-display/LoadingState/LoadingState.types.ts +37 -0
- package/src/components/data-display/LoadingState/index.ts +2 -0
- package/src/components/data-display/MapPreview/MapPreview.md +154 -0
- package/src/components/data-display/MapPreview/MapPreview.stories.tsx +458 -0
- package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +390 -0
- package/src/components/data-display/MapPreview/MapPreview.tsx +922 -0
- package/src/components/data-display/MapPreview/MapPreview.types.ts +56 -0
- package/src/components/data-display/MapPreview/index.ts +2 -0
- package/src/components/data-display/Popover/Popover.md +245 -0
- package/src/components/data-display/Popover/Popover.stories.tsx +295 -0
- package/src/components/data-display/Popover/Popover.test.stories.tsx +1168 -0
- package/src/components/data-display/Popover/Popover.tsx +132 -0
- package/src/components/data-display/Popover/Popover.types.ts +33 -0
- package/src/components/data-display/Popover/index.ts +2 -0
- package/src/components/data-display/Progress/Progress.md +450 -0
- package/src/components/data-display/Progress/Progress.stories.tsx +481 -0
- package/src/components/data-display/Progress/Progress.test.stories.tsx +2070 -0
- package/src/components/data-display/Progress/Progress.tsx +332 -0
- package/src/components/data-display/Progress/Progress.types.ts +61 -0
- package/src/components/data-display/Progress/index.ts +2 -0
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.md +108 -0
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +160 -0
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.test.stories.tsx +190 -0
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.tsx +224 -0
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.types.ts +101 -0
- package/src/components/data-display/SectionOnboarding/index.ts +7 -0
- package/src/components/data-display/Sheet/Sheet.md +475 -0
- package/src/components/data-display/Sheet/Sheet.stories.tsx +883 -0
- package/src/components/data-display/Sheet/Sheet.test.stories.tsx +1101 -0
- package/src/components/data-display/Sheet/Sheet.tsx +978 -0
- package/src/components/data-display/Sheet/Sheet.types.ts +93 -0
- package/src/components/data-display/Sheet/index.ts +8 -0
- package/src/components/data-display/Stepper/Stepper.md +542 -0
- package/src/components/data-display/Stepper/Stepper.stories.tsx +540 -0
- package/src/components/data-display/Stepper/Stepper.test.stories.tsx +607 -0
- package/src/components/data-display/Stepper/Stepper.tsx +328 -0
- package/src/components/data-display/Stepper/Stepper.types.ts +97 -0
- package/src/components/data-display/Stepper/index.ts +2 -0
- package/src/components/data-display/Table/Table.md +243 -0
- package/src/components/data-display/Table/Table.stories.tsx +801 -0
- package/src/components/data-display/Table/Table.test.stories.tsx +369 -0
- package/src/components/data-display/Table/Table.tsx +831 -0
- package/src/components/data-display/Table/Table.types.ts +335 -0
- package/src/components/data-display/Table/index.ts +2 -0
- package/src/components/data-display/Timeline/Timeline.md +201 -0
- package/src/components/data-display/Timeline/Timeline.stories.tsx +444 -0
- package/src/components/data-display/Timeline/Timeline.test.stories.tsx +944 -0
- package/src/components/data-display/Timeline/Timeline.tsx +348 -0
- package/src/components/data-display/Timeline/Timeline.types.ts +26 -0
- package/src/components/data-display/Timeline/index.ts +2 -0
- package/src/components/data-display/TimingDiagram/TimingDiagram.md +162 -0
- package/src/components/data-display/TimingDiagram/TimingDiagram.stories.tsx +475 -0
- package/src/components/data-display/TimingDiagram/TimingDiagram.test.stories.tsx +734 -0
- package/src/components/data-display/TimingDiagram/TimingDiagram.tsx +399 -0
- package/src/components/data-display/TimingDiagram/TimingDiagram.types.ts +19 -0
- package/src/components/data-display/TimingDiagram/index.ts +2 -0
- package/src/components/data-display/Tooltip/Tooltip.md +397 -0
- package/src/components/data-display/Tooltip/Tooltip.stories.tsx +465 -0
- package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +1168 -0
- package/src/components/data-display/Tooltip/Tooltip.tsx +161 -0
- package/src/components/data-display/Tooltip/Tooltip.types.ts +33 -0
- package/src/components/data-display/Tooltip/index.ts +2 -0
- package/src/components/data-display/index.ts +29 -0
- package/src/components/feedback/Dialog/Dialog.md +527 -0
- package/src/components/feedback/Dialog/Dialog.stories.tsx +833 -0
- package/src/components/feedback/Dialog/Dialog.styles.ts +171 -0
- package/src/components/feedback/Dialog/Dialog.test.stories.tsx +955 -0
- package/src/components/feedback/Dialog/Dialog.tsx +256 -0
- package/src/components/feedback/Dialog/Dialog.types.ts +46 -0
- package/src/components/feedback/Dialog/index.ts +9 -0
- package/src/components/feedback/Modal/Modal.md +629 -0
- package/src/components/feedback/Modal/Modal.stories.tsx +765 -0
- package/src/components/feedback/Modal/Modal.test.stories.tsx +251 -0
- package/src/components/feedback/Modal/Modal.tsx +279 -0
- package/src/components/feedback/Modal/Modal.types.ts +26 -0
- package/src/components/feedback/Modal/index.ts +7 -0
- package/src/components/feedback/Sonner/Sonner.stories.tsx +698 -0
- package/src/components/feedback/Sonner/Sonner.test.stories.tsx +896 -0
- package/src/components/feedback/Sonner/Sonner.tsx +493 -0
- package/src/components/feedback/Sonner/Sonner.types.ts +65 -0
- package/src/components/feedback/Sonner/index.ts +8 -0
- package/src/components/feedback/StackedModal/StackedModal.md +273 -0
- package/src/components/feedback/StackedModal/StackedModal.stories.tsx +1785 -0
- package/src/components/feedback/StackedModal/StackedModal.test.stories.tsx +975 -0
- package/src/components/feedback/StackedModal/StackedModal.tsx +664 -0
- package/src/components/feedback/StackedModal/StackedModal.types.ts +70 -0
- package/src/components/feedback/StackedModal/index.ts +11 -0
- package/src/components/feedback/Toast/Toast.md +547 -0
- package/src/components/feedback/Toast/Toast.stories.tsx +548 -0
- package/src/components/feedback/Toast/Toast.test.stories.tsx +834 -0
- package/src/components/feedback/Toast/Toast.tsx +279 -0
- package/src/components/feedback/Toast/Toast.types.ts +59 -0
- package/src/components/feedback/Toast/index.ts +8 -0
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.md +610 -0
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.stories.tsx +691 -0
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +634 -0
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.tsx +554 -0
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.types.ts +30 -0
- package/src/components/feedback/TutorialOverlay/index.ts +2 -0
- package/src/components/feedback/index.ts +6 -0
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.md +633 -0
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +663 -0
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +723 -0
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.tsx +836 -0
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.types.ts +37 -0
- package/src/components/form/AddressAutocomplete/index.ts +2 -0
- package/src/components/form/Autocomplete/Autocomplete.helpers.ts +115 -0
- package/src/components/form/Autocomplete/Autocomplete.keys.ts +134 -0
- package/src/components/form/Autocomplete/Autocomplete.parts.tsx +337 -0
- package/src/components/form/Autocomplete/Autocomplete.stories.tsx +715 -0
- package/src/components/form/Autocomplete/Autocomplete.test.stories.tsx +825 -0
- package/src/components/form/Autocomplete/Autocomplete.tsx +166 -0
- package/src/components/form/Autocomplete/Autocomplete.types.ts +116 -0
- package/src/components/form/Autocomplete/autocomplete.md +789 -0
- package/src/components/form/Autocomplete/index.ts +8 -0
- package/src/components/form/Autocomplete/useAutocomplete.ts +311 -0
- package/src/components/form/Button/Button.md +411 -0
- package/src/components/form/Button/Button.stories.tsx +362 -0
- package/src/components/form/Button/Button.test.stories.tsx +603 -0
- package/src/components/form/Button/Button.tsx +326 -0
- package/src/components/form/Button/Button.types.ts +74 -0
- package/src/components/form/Button/index.ts +2 -0
- package/src/components/form/Calendar/Calendar.md +807 -0
- package/src/components/form/Calendar/Calendar.stories.tsx +349 -0
- package/src/components/form/Calendar/Calendar.test.stories.tsx +465 -0
- package/src/components/form/Calendar/Calendar.tsx +571 -0
- package/src/components/form/Calendar/Calendar.types.ts +81 -0
- package/src/components/form/Calendar/index.ts +11 -0
- package/src/components/form/Checkbox/Checkbox.md +200 -0
- package/src/components/form/Checkbox/Checkbox.stories.tsx +265 -0
- package/src/components/form/Checkbox/Checkbox.test.stories.tsx +181 -0
- package/src/components/form/Checkbox/Checkbox.tsx +170 -0
- package/src/components/form/Checkbox/Checkbox.types.ts +20 -0
- package/src/components/form/Checkbox/index.ts +2 -0
- package/src/components/form/CodeEditor/CodeEditor.md +350 -0
- package/src/components/form/CodeEditor/CodeEditor.stories.tsx +871 -0
- package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +575 -0
- package/src/components/form/CodeEditor/CodeEditor.tsx +415 -0
- package/src/components/form/CodeEditor/CodeEditor.types.ts +38 -0
- package/src/components/form/CodeEditor/index.ts +2 -0
- package/src/components/form/Command/Command.md +468 -0
- package/src/components/form/Command/Command.stories.tsx +580 -0
- package/src/components/form/Command/Command.test.stories.tsx +215 -0
- package/src/components/form/Command/Command.tsx +545 -0
- package/src/components/form/Command/Command.types.ts +116 -0
- package/src/components/form/Command/index.ts +12 -0
- package/src/components/form/CreatableSelect/CreatableSelect.md +114 -0
- package/src/components/form/CreatableSelect/CreatableSelect.stories.tsx +112 -0
- package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +134 -0
- package/src/components/form/CreatableSelect/CreatableSelect.tsx +149 -0
- package/src/components/form/CreatableSelect/CreatableSelect.types.ts +37 -0
- package/src/components/form/CreatableSelect/index.ts +2 -0
- package/src/components/form/Form/Form.md +325 -0
- package/src/components/form/Form/Form.stories.tsx +687 -0
- package/src/components/form/Form/Form.test.stories.tsx +601 -0
- package/src/components/form/Form/Form.tsx +136 -0
- package/src/components/form/Form/Form.types.ts +42 -0
- package/src/components/form/Form/index.ts +8 -0
- package/src/components/form/Input/Input.md +252 -0
- package/src/components/form/Input/Input.stories.tsx +256 -0
- package/src/components/form/Input/Input.test.stories.tsx +1184 -0
- package/src/components/form/Input/Input.tsx +263 -0
- package/src/components/form/Input/Input.types.ts +24 -0
- package/src/components/form/Input/index.ts +2 -0
- package/src/components/form/InputOTP/InputOTP.md +419 -0
- package/src/components/form/InputOTP/InputOTP.stories.tsx +774 -0
- package/src/components/form/InputOTP/InputOTP.test.stories.tsx +596 -0
- package/src/components/form/InputOTP/InputOTP.tsx +231 -0
- package/src/components/form/InputOTP/InputOTP.types.ts +68 -0
- package/src/components/form/InputOTP/index.ts +2 -0
- package/src/components/form/Label/Label.md +426 -0
- package/src/components/form/Label/Label.stories.tsx +473 -0
- package/src/components/form/Label/Label.test.stories.tsx +909 -0
- package/src/components/form/Label/Label.tsx +367 -0
- package/src/components/form/Label/Label.types.ts +35 -0
- package/src/components/form/Label/index.ts +2 -0
- package/src/components/form/Menubar/Menubar.md +275 -0
- package/src/components/form/Menubar/Menubar.stories.tsx +472 -0
- package/src/components/form/Menubar/Menubar.test.stories.tsx +588 -0
- package/src/components/form/Menubar/Menubar.tsx +467 -0
- package/src/components/form/Menubar/Menubar.types.ts +71 -0
- package/src/components/form/Menubar/index.ts +8 -0
- package/src/components/form/PasswordStrength/PasswordStrength.md +139 -0
- package/src/components/form/PasswordStrength/PasswordStrength.stories.tsx +562 -0
- package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +327 -0
- package/src/components/form/PasswordStrength/PasswordStrength.tsx +419 -0
- package/src/components/form/PasswordStrength/PasswordStrength.types.ts +18 -0
- package/src/components/form/PasswordStrength/index.ts +2 -0
- package/src/components/form/PhoneInput/PhoneInput.md +578 -0
- package/src/components/form/PhoneInput/PhoneInput.stories.tsx +495 -0
- package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +666 -0
- package/src/components/form/PhoneInput/PhoneInput.tsx +376 -0
- package/src/components/form/PhoneInput/PhoneInput.types.ts +25 -0
- package/src/components/form/PhoneInput/index.ts +2 -0
- package/src/components/form/RadioGroup/RadioGroup.md +477 -0
- package/src/components/form/RadioGroup/RadioGroup.stories.tsx +518 -0
- package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +685 -0
- package/src/components/form/RadioGroup/RadioGroup.tsx +664 -0
- package/src/components/form/RadioGroup/RadioGroup.types.ts +82 -0
- package/src/components/form/RadioGroup/index.ts +2 -0
- package/src/components/form/RichTextEditor/RichTextEditor.md +710 -0
- package/src/components/form/RichTextEditor/RichTextEditor.stories.tsx +261 -0
- package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +498 -0
- package/src/components/form/RichTextEditor/RichTextEditor.tsx +468 -0
- package/src/components/form/RichTextEditor/RichTextEditor.types.ts +72 -0
- package/src/components/form/RichTextEditor/index.ts +2 -0
- package/src/components/form/SearchPalette/SearchPalette.md +69 -0
- package/src/components/form/SearchPalette/SearchPalette.parts.tsx +358 -0
- package/src/components/form/SearchPalette/SearchPalette.stories.tsx +135 -0
- package/src/components/form/SearchPalette/SearchPalette.tsx +141 -0
- package/src/components/form/SearchPalette/SearchPalette.types.ts +82 -0
- package/src/components/form/SearchPalette/index.ts +7 -0
- package/src/components/form/Select/Select.md +254 -0
- package/src/components/form/Select/Select.stories.tsx +364 -0
- package/src/components/form/Select/Select.test.stories.tsx +977 -0
- package/src/components/form/Select/Select.tsx +239 -0
- package/src/components/form/Select/Select.types.ts +57 -0
- package/src/components/form/Select/index.ts +2 -0
- package/src/components/form/Slider/Slider.md +326 -0
- package/src/components/form/Slider/Slider.stories.tsx +418 -0
- package/src/components/form/Slider/Slider.test.stories.tsx +1044 -0
- package/src/components/form/Slider/Slider.tsx +374 -0
- package/src/components/form/Slider/Slider.types.ts +113 -0
- package/src/components/form/Slider/index.ts +2 -0
- package/src/components/form/Switch/Switch.md +565 -0
- package/src/components/form/Switch/Switch.stories.tsx +697 -0
- package/src/components/form/Switch/Switch.test.stories.tsx +597 -0
- package/src/components/form/Switch/Switch.tsx +578 -0
- package/src/components/form/Switch/Switch.types.ts +130 -0
- package/src/components/form/Switch/index.ts +2 -0
- package/src/components/form/Textarea/Textarea.stories.tsx +473 -0
- package/src/components/form/Textarea/Textarea.test.stories.tsx +708 -0
- package/src/components/form/Textarea/Textarea.tsx +678 -0
- package/src/components/form/Textarea/Textarea.types.ts +84 -0
- package/src/components/form/Textarea/index.ts +2 -0
- package/src/components/form/Toggle/Toggle.md +234 -0
- package/src/components/form/Toggle/Toggle.stories.tsx +638 -0
- package/src/components/form/Toggle/Toggle.test.stories.tsx +1167 -0
- package/src/components/form/Toggle/Toggle.tsx +265 -0
- package/src/components/form/Toggle/Toggle.types.ts +79 -0
- package/src/components/form/Toggle/index.ts +2 -0
- package/src/components/form/ToggleGroup/ToggleGroup.md +329 -0
- package/src/components/form/ToggleGroup/ToggleGroup.stories.tsx +617 -0
- package/src/components/form/ToggleGroup/ToggleGroup.test.stories.tsx +918 -0
- package/src/components/form/ToggleGroup/ToggleGroup.tsx +129 -0
- package/src/components/form/ToggleGroup/ToggleGroup.types.ts +53 -0
- package/src/components/form/ToggleGroup/index.ts +2 -0
- package/src/components/form/UploadButton/UploadButton.md +44 -0
- package/src/components/form/UploadButton/UploadButton.stories.tsx +366 -0
- package/src/components/form/UploadButton/UploadButton.test.stories.tsx +454 -0
- package/src/components/form/UploadButton/UploadButton.tsx +312 -0
- package/src/components/form/UploadButton/UploadButton.types.ts +58 -0
- package/src/components/form/UploadButton/index.ts +2 -0
- package/src/components/form/index.ts +25 -0
- package/src/components/form/total-form/Fields/SelectField.tsx +57 -0
- package/src/components/form/total-form/Fields/TextField.tsx +58 -0
- package/src/components/form/total-form/Fields/index.ts +4 -0
- package/src/components/form/total-form/FormContainer.tsx +104 -0
- package/src/components/form/total-form/FormContext.tsx +38 -0
- package/src/components/form/total-form/FormErrorSnackbar.tsx +35 -0
- package/src/components/form/total-form/SubmitButton.tsx +27 -0
- package/src/components/form/total-form/index.ts +12 -0
- package/src/components/form/total-form/total-form.test.tsx +97 -0
- package/src/components/index.ts +7 -0
- package/src/components/layout/Accordion/Accordion.md +725 -0
- package/src/components/layout/Accordion/Accordion.stories.tsx +690 -0
- package/src/components/layout/Accordion/Accordion.test.stories.tsx +1362 -0
- package/src/components/layout/Accordion/Accordion.tsx +242 -0
- package/src/components/layout/Accordion/Accordion.types.ts +32 -0
- package/src/components/layout/Accordion/index.ts +8 -0
- package/src/components/layout/Card/Card.md +533 -0
- package/src/components/layout/Card/Card.stories.tsx +593 -0
- package/src/components/layout/Card/Card.test.stories.tsx +1134 -0
- package/src/components/layout/Card/Card.tsx +404 -0
- package/src/components/layout/Card/Card.types.ts +57 -0
- package/src/components/layout/Card/index.ts +8 -0
- package/src/components/layout/Collapsible/Collapsible.md +135 -0
- package/src/components/layout/Collapsible/Collapsible.stories.tsx +180 -0
- package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +304 -0
- package/src/components/layout/Collapsible/Collapsible.tsx +198 -0
- package/src/components/layout/Collapsible/Collapsible.types.ts +35 -0
- package/src/components/layout/Collapsible/index.ts +6 -0
- package/src/components/layout/Container/Container.md +420 -0
- package/src/components/layout/Container/Container.stories.tsx +557 -0
- package/src/components/layout/Container/Container.test.stories.tsx +750 -0
- package/src/components/layout/Container/Container.tsx +72 -0
- package/src/components/layout/Container/Container.types.ts +11 -0
- package/src/components/layout/Container/index.ts +2 -0
- package/src/components/layout/ContentToolbar/ColumnsMenu.tsx +99 -0
- package/src/components/layout/ContentToolbar/ContentToolbar.md +75 -0
- package/src/components/layout/ContentToolbar/ContentToolbar.stories.tsx +129 -0
- package/src/components/layout/ContentToolbar/ContentToolbar.test.stories.tsx +251 -0
- package/src/components/layout/ContentToolbar/ContentToolbar.tsx +108 -0
- package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +229 -0
- package/src/components/layout/ContentToolbar/FilterTrigger.tsx +71 -0
- package/src/components/layout/ContentToolbar/MultiSelectDropdown.tsx +297 -0
- package/src/components/layout/ContentToolbar/SavedViewsMenu.tsx +334 -0
- package/src/components/layout/ContentToolbar/SortByDropdown.tsx +213 -0
- package/src/components/layout/ContentToolbar/ViewSelector.tsx +98 -0
- package/src/components/layout/ContentToolbar/__tests__/ColumnsMenu.test.tsx +39 -0
- package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +110 -0
- package/src/components/layout/ContentToolbar/__tests__/SavedViewsMenu.test.tsx +99 -0
- package/src/components/layout/ContentToolbar/index.ts +24 -0
- package/src/components/layout/ContentToolbar/tests.md +42 -0
- package/src/components/layout/ContentToolbar/track.md +41 -0
- package/src/components/layout/Dashboard/Dashboard.md +71 -0
- package/src/components/layout/Dashboard/Dashboard.stories.tsx +104 -0
- package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +164 -0
- package/src/components/layout/Dashboard/Dashboard.tsx +297 -0
- package/src/components/layout/Dashboard/Dashboard.types.ts +157 -0
- package/src/components/layout/Dashboard/DashboardContext.tsx +47 -0
- package/src/components/layout/Dashboard/DashboardParts.tsx +216 -0
- package/src/components/layout/Dashboard/index.ts +18 -0
- package/src/components/layout/Dashboard/tests.md +46 -0
- package/src/components/layout/Dashboard/track.md +50 -0
- package/src/components/layout/Drawer/Drawer.md +479 -0
- package/src/components/layout/Drawer/Drawer.stories.tsx +660 -0
- package/src/components/layout/Drawer/Drawer.test.stories.tsx +1339 -0
- package/src/components/layout/Drawer/Drawer.tsx +150 -0
- package/src/components/layout/Drawer/Drawer.types.ts +34 -0
- package/src/components/layout/Drawer/index.ts +2 -0
- package/src/components/layout/Resizable/Resizable.md +308 -0
- package/src/components/layout/Resizable/Resizable.stories.tsx +1039 -0
- package/src/components/layout/Resizable/Resizable.test.stories.tsx +750 -0
- package/src/components/layout/Resizable/Resizable.tsx +190 -0
- package/src/components/layout/Resizable/Resizable.types.ts +34 -0
- package/src/components/layout/Resizable/index.ts +2 -0
- package/src/components/layout/ScrollArea/ScrollArea.md +122 -0
- package/src/components/layout/ScrollArea/ScrollArea.stories.tsx +651 -0
- package/src/components/layout/ScrollArea/ScrollArea.test.stories.tsx +619 -0
- package/src/components/layout/ScrollArea/ScrollArea.tsx +449 -0
- package/src/components/layout/ScrollArea/ScrollArea.types.ts +80 -0
- package/src/components/layout/ScrollArea/index.ts +7 -0
- package/src/components/layout/Separator/Separator.stories.tsx +563 -0
- package/src/components/layout/Separator/Separator.test.stories.tsx +527 -0
- package/src/components/layout/Separator/Separator.tsx +187 -0
- package/src/components/layout/Separator/Separator.types.ts +17 -0
- package/src/components/layout/Separator/index.ts +2 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.md +139 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.parts.tsx +357 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +194 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.test.stories.tsx +175 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.tsx +69 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.types.ts +61 -0
- package/src/components/layout/SettingsLayout/index.ts +6 -0
- package/src/components/layout/Sidebar/Sidebar.md +367 -0
- package/src/components/layout/Sidebar/Sidebar.stories.tsx +611 -0
- package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +1326 -0
- package/src/components/layout/Sidebar/Sidebar.tsx +131 -0
- package/src/components/layout/Sidebar/Sidebar.types.ts +30 -0
- package/src/components/layout/Sidebar/index.ts +7 -0
- package/src/components/layout/Skeleton/Skeleton.md +240 -0
- package/src/components/layout/Skeleton/Skeleton.stories.tsx +689 -0
- package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +521 -0
- package/src/components/layout/Skeleton/Skeleton.tsx +166 -0
- package/src/components/layout/Skeleton/Skeleton.types.ts +19 -0
- package/src/components/layout/Skeleton/index.ts +2 -0
- package/src/components/layout/Spacer/Spacer.md +84 -0
- package/src/components/layout/Spacer/Spacer.stories.tsx +502 -0
- package/src/components/layout/Spacer/Spacer.test.stories.tsx +472 -0
- package/src/components/layout/Spacer/Spacer.tsx +68 -0
- package/src/components/layout/Spacer/Spacer.types.ts +12 -0
- package/src/components/layout/Spacer/index.ts +2 -0
- package/src/components/layout/TableFilter/TableFilter.md +55 -0
- package/src/components/layout/TableFilter/TableFilter.stories.tsx +82 -0
- package/src/components/layout/TableFilter/TableFilter.test.stories.tsx +87 -0
- package/src/components/layout/TableFilter/TableFilter.tsx +383 -0
- package/src/components/layout/TableFilter/TableFilter.types.ts +87 -0
- package/src/components/layout/TableFilter/TableFilterContext.tsx +29 -0
- package/src/components/layout/TableFilter/index.ts +15 -0
- package/src/components/layout/TableFilter/tests.md +37 -0
- package/src/components/layout/TableFilter/track.md +36 -0
- package/src/components/layout/index.ts +14 -0
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.md +558 -0
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +640 -0
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +1007 -0
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +516 -0
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.types.ts +132 -0
- package/src/components/navigation/Breadcrumbs/index.ts +2 -0
- package/src/components/navigation/CommandPalette/CommandPalette.md +201 -0
- package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +384 -0
- package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +437 -0
- package/src/components/navigation/CommandPalette/CommandPalette.tsx +434 -0
- package/src/components/navigation/CommandPalette/CommandPalette.types.ts +25 -0
- package/src/components/navigation/CommandPalette/index.ts +2 -0
- package/src/components/navigation/ContextMenu/ContextMenu.md +535 -0
- package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +611 -0
- package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +850 -0
- package/src/components/navigation/ContextMenu/ContextMenu.tsx +254 -0
- package/src/components/navigation/ContextMenu/ContextMenu.types.ts +96 -0
- package/src/components/navigation/ContextMenu/index.ts +2 -0
- package/src/components/navigation/DropdownMenu/DropdownMenu.md +514 -0
- package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +580 -0
- package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +660 -0
- package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +305 -0
- package/src/components/navigation/DropdownMenu/DropdownMenu.types.ts +116 -0
- package/src/components/navigation/DropdownMenu/index.ts +2 -0
- package/src/components/navigation/NavigationMenu/NavigationMenu.md +580 -0
- package/src/components/navigation/NavigationMenu/NavigationMenu.tsx +874 -0
- package/src/components/navigation/NavigationMenu/NavigationMenu.types.ts +135 -0
- package/src/components/navigation/NavigationMenu/index.ts +2 -0
- package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +518 -0
- package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +931 -0
- package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +503 -0
- package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +455 -0
- package/src/components/navigation/Pagination/Pagination.md +699 -0
- package/src/components/navigation/Pagination/Pagination.stories.tsx +604 -0
- package/src/components/navigation/Pagination/Pagination.test.stories.tsx +520 -0
- package/src/components/navigation/Pagination/Pagination.tsx +356 -0
- package/src/components/navigation/Pagination/Pagination.types.ts +129 -0
- package/src/components/navigation/Pagination/index.ts +2 -0
- package/src/components/navigation/Tabs/Tabs.md +774 -0
- package/src/components/navigation/Tabs/Tabs.stories.tsx +1006 -0
- package/src/components/navigation/Tabs/Tabs.test.stories.tsx +1225 -0
- package/src/components/navigation/Tabs/Tabs.tsx +433 -0
- package/src/components/navigation/Tabs/Tabs.types.ts +239 -0
- package/src/components/navigation/Tabs/index.ts +2 -0
- package/src/components/navigation/index.ts +7 -0
- package/src/components/typography/Blockquote/Blockquote.md +130 -0
- package/src/components/typography/Blockquote/Blockquote.stories.tsx +359 -0
- package/src/components/typography/Blockquote/Blockquote.test.stories.tsx +432 -0
- package/src/components/typography/Blockquote/Blockquote.tsx +166 -0
- package/src/components/typography/Blockquote/Blockquote.types.ts +11 -0
- package/src/components/typography/Blockquote/index.ts +2 -0
- package/src/components/typography/Code/Code.md +182 -0
- package/src/components/typography/Code/Code.stories.tsx +686 -0
- package/src/components/typography/Code/Code.test.stories.tsx +703 -0
- package/src/components/typography/Code/Code.tsx +228 -0
- package/src/components/typography/Code/Code.types.ts +12 -0
- package/src/components/typography/Code/index.ts +2 -0
- package/src/components/typography/Heading/Heading.md +143 -0
- package/src/components/typography/Heading/Heading.stories.tsx +451 -0
- package/src/components/typography/Heading/Heading.test.stories.tsx +830 -0
- package/src/components/typography/Heading/Heading.tsx +178 -0
- package/src/components/typography/Heading/Heading.types.ts +11 -0
- package/src/components/typography/Heading/index.ts +2 -0
- package/src/components/typography/Paragraph/Paragraph.md +80 -0
- package/src/components/typography/Paragraph/Paragraph.stories.tsx +280 -0
- package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +238 -0
- package/src/components/typography/Paragraph/Paragraph.tsx +99 -0
- package/src/components/typography/Paragraph/Paragraph.types.ts +10 -0
- package/src/components/typography/Paragraph/index.ts +2 -0
- package/src/components/typography/Text/Text.md +129 -0
- package/src/components/typography/Text/Text.stories.tsx +359 -0
- package/src/components/typography/Text/Text.test.stories.tsx +762 -0
- package/src/components/typography/Text/Text.tsx +159 -0
- package/src/components/typography/Text/Text.types.ts +15 -0
- package/src/components/typography/Text/index.ts +2 -0
- package/src/components/typography/index.ts +5 -0
- package/src/components/utility/AnimatedIcon/AnimatedIcon.md +359 -0
- package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +947 -0
- package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +596 -0
- package/src/components/utility/AnimatedIcon/AnimatedIcon.tsx +595 -0
- package/src/components/utility/AnimatedIcon/AnimatedIcon.types.ts +98 -0
- package/src/components/utility/AnimatedIcon/index.ts +2 -0
- package/src/components/utility/AspectRatio/AspectRatio.md +200 -0
- package/src/components/utility/AspectRatio/AspectRatio.stories.tsx +414 -0
- package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +859 -0
- package/src/components/utility/AspectRatio/AspectRatio.tsx +76 -0
- package/src/components/utility/AspectRatio/AspectRatio.types.ts +13 -0
- package/src/components/utility/AspectRatio/index.ts +2 -0
- package/src/components/utility/InfiniteScroll/InfiniteScroll.md +531 -0
- package/src/components/utility/InfiniteScroll/InfiniteScroll.stories.tsx +620 -0
- package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +358 -0
- package/src/components/utility/InfiniteScroll/InfiniteScroll.tsx +204 -0
- package/src/components/utility/InfiniteScroll/InfiniteScroll.types.ts +39 -0
- package/src/components/utility/InfiniteScroll/index.ts +6 -0
- package/src/components/utility/Portal/Portal.button-container.example.tsx +99 -0
- package/src/components/utility/Portal/Portal.md +593 -0
- package/src/components/utility/Portal/Portal.stories.tsx +340 -0
- package/src/components/utility/Portal/Portal.test.stories.tsx +2086 -0
- package/src/components/utility/Portal/Portal.tsx +39 -0
- package/src/components/utility/Portal/Portal.types.ts +7 -0
- package/src/components/utility/Portal/index.ts +2 -0
- package/src/components/utility/Transition/Transition.md +684 -0
- package/src/components/utility/Transition/Transition.stories.tsx +493 -0
- package/src/components/utility/Transition/Transition.test.stories.tsx +854 -0
- package/src/components/utility/Transition/Transition.tsx +140 -0
- package/src/components/utility/Transition/Transition.types.ts +14 -0
- package/src/components/utility/Transition/index.ts +6 -0
- package/src/components/utility/VirtualList/VirtualList.md +520 -0
- package/src/components/utility/VirtualList/VirtualList.stories.tsx +1073 -0
- package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +1074 -0
- package/src/components/utility/VirtualList/VirtualList.tsx +369 -0
- package/src/components/utility/VirtualList/VirtualList.types.ts +56 -0
- package/src/components/utility/VirtualList/index.ts +7 -0
- package/src/components/utility/WorkflowStep/WorkflowStep.md +187 -0
- package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +433 -0
- package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +364 -0
- package/src/components/utility/WorkflowStep/WorkflowStep.tsx +506 -0
- package/src/components/utility/WorkflowStep/WorkflowStep.types.ts +133 -0
- package/src/components/utility/WorkflowStep/index.ts +13 -0
- package/src/components/utility/index.ts +7 -0
- package/src/index.ts +17 -0
- package/src/mui/AppBar.ts +2 -0
- package/src/mui/Box.ts +2 -0
- package/src/mui/CssBaseline.ts +2 -0
- package/src/mui/FormControl.ts +2 -0
- package/src/mui/FormControlLabel.ts +2 -0
- package/src/mui/Grid2.ts +2 -0
- package/src/mui/InputLabel.ts +2 -0
- package/src/mui/List.ts +2 -0
- package/src/mui/ListItem.ts +2 -0
- package/src/mui/ListItemButton.ts +2 -0
- package/src/mui/ListItemText.ts +2 -0
- package/src/mui/Stack.ts +2 -0
- package/src/mui/SvgIcon.ts +2 -0
- package/src/mui/Toolbar.ts +2 -0
- package/src/mui/styles.ts +2 -0
- package/src/mui/useMediaQuery.ts +1 -0
- package/src/social-login-button.tsx +199 -0
- package/src/user-avatar.tsx +102 -0
- package/src/utils/cn.ts +9 -0
- package/src/utils/index.ts +1 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
Got it — I’ll merge those **advanced features** directly into the master description so your AI has a single, complete spec for building the `Lightbox` component.
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Lightbox Component – AI Implementation Description (Extended)
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
A **Lightbox** is a modal overlay to showcase media (images, videos, or custom content) in a distraction-free way. It emphasizes the active item, dims the background, and provides intuitive navigation and controls.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Core Features
|
|
14
|
+
|
|
15
|
+
1. **Overlay & Focus**
|
|
16
|
+
- Semi-transparent backdrop covering viewport.
|
|
17
|
+
- Content centered with scroll lock while active.
|
|
18
|
+
|
|
19
|
+
2. **Media Support**
|
|
20
|
+
- Images, videos, and arbitrary children.
|
|
21
|
+
- Mixed galleries (image + video).
|
|
22
|
+
|
|
23
|
+
3. **Navigation**
|
|
24
|
+
- Previous/Next controls.
|
|
25
|
+
- Keyboard (`←`, `→`, `Esc`) and swipe support.
|
|
26
|
+
- Optional loop at edges.
|
|
27
|
+
|
|
28
|
+
4. **Controls**
|
|
29
|
+
- Always-visible close button.
|
|
30
|
+
- Optional captions, share, and download.
|
|
31
|
+
- Configurable via props.
|
|
32
|
+
|
|
33
|
+
5. **Accessibility**
|
|
34
|
+
- Focus trap, `aria-modal="true"`, `role="dialog"`.
|
|
35
|
+
- Screen reader announcement of current item (“Image 2 of 5”).
|
|
36
|
+
- Escape closes by default.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Advanced Features
|
|
41
|
+
|
|
42
|
+
- **Thumbnails / Filmstrip**: optional preview strip for quick navigation.
|
|
43
|
+
- **Zoom & Pan**: pinch/scroll zoom, drag pan, double-tap reset.
|
|
44
|
+
- **Slideshow / Autoplay**: auto-advance with start/stop.
|
|
45
|
+
- **Lazy Load & Preload**: load current, preload prev/next.
|
|
46
|
+
- **Multi-Item Layout**: switch between single and grid view.
|
|
47
|
+
- **Gestures**: swipe left/right to change, swipe down to close (mobile).
|
|
48
|
+
- **Share & Download**: Web Share API, link copy, download with watermark support.
|
|
49
|
+
- **Animations**: morph from thumbnail to fullscreen, crossfade or slide transitions.
|
|
50
|
+
- **Multiple Instances**: independent galleries on one page.
|
|
51
|
+
- **Programmatic API**: expose `open(index)`, `close()`, `next()`, `prev()`.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Props
|
|
56
|
+
|
|
57
|
+
- `isOpen: boolean` – controls visibility.
|
|
58
|
+
- `onClose: () => void` – close handler.
|
|
59
|
+
- `items?: Array<{ src: string; alt?: string; caption?: string; type?: "image" | "video" }>` – gallery items.
|
|
60
|
+
- `startIndex?: number` – initial item index.
|
|
61
|
+
- `showControls?: boolean` – toggle controls.
|
|
62
|
+
- `showCaptions?: boolean` – toggle captions.
|
|
63
|
+
- `loop?: boolean` – loop gallery navigation.
|
|
64
|
+
- `autoplay?: boolean` – enable auto slideshow.
|
|
65
|
+
- `thumbnails?: boolean` – show filmstrip navigation.
|
|
66
|
+
- `zoomable?: boolean` – enable zoom/pan.
|
|
67
|
+
- `className?: string` – extend styling.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Visual & Motion Guidelines
|
|
72
|
+
|
|
73
|
+
- **Backdrop:** 60–80% black opacity.
|
|
74
|
+
- **Animation:** fade backdrop, scale/slide media (200–300ms).
|
|
75
|
+
- **Transitions:** configurable easing/duration.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Variants
|
|
80
|
+
|
|
81
|
+
- **Default:** Image viewer with captions.
|
|
82
|
+
- **Minimal:** Only close button.
|
|
83
|
+
- **Media-Rich:** Mixed gallery.
|
|
84
|
+
- **Fullscreen:** 100% viewport expansion.
|
|
85
|
+
- **Filmstrip Mode:** with thumbnails.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Testing
|
|
90
|
+
|
|
91
|
+
### Test IDs
|
|
92
|
+
|
|
93
|
+
The Lightbox component provides comprehensive test IDs for automated testing. All test IDs can be customized via the `dataTestId` prop.
|
|
94
|
+
|
|
95
|
+
| Element | Default Test ID | Custom Test ID Pattern |
|
|
96
|
+
|---------|----------------|----------------------|
|
|
97
|
+
| Overlay/Dialog | `lightbox` | `{dataTestId}` |
|
|
98
|
+
| Close Button | `lightbox-close` | `{dataTestId}-close` |
|
|
99
|
+
| Previous Button | `lightbox-prev` | `{dataTestId}-prev` |
|
|
100
|
+
| Next Button | `lightbox-next` | `{dataTestId}-next` |
|
|
101
|
+
| Zoom Controls Container | `lightbox-zoom-controls` | `{dataTestId}-zoom-controls` |
|
|
102
|
+
| Zoom In Button | `lightbox-zoom-in` | `{dataTestId}-zoom-in` |
|
|
103
|
+
| Zoom Out Button | `lightbox-zoom-out` | `{dataTestId}-zoom-out` |
|
|
104
|
+
| Zoom Reset Button | `lightbox-zoom-reset` | `{dataTestId}-zoom-reset` |
|
|
105
|
+
| Autoplay Button | `lightbox-autoplay` | `{dataTestId}-autoplay` |
|
|
106
|
+
| Content Container | `lightbox-content` | `{dataTestId}-content` |
|
|
107
|
+
| Image Container | `lightbox-image-container` | `{dataTestId}-image-container` |
|
|
108
|
+
| Image Element | `lightbox-image` | `{dataTestId}-image` |
|
|
109
|
+
| Video Element | `lightbox-video` | `{dataTestId}-video` |
|
|
110
|
+
| Loading Indicator | `lightbox-loading` | `{dataTestId}-loading` |
|
|
111
|
+
| Caption | `lightbox-caption` | `{dataTestId}-caption` |
|
|
112
|
+
| Item Counter | `lightbox-counter` | `{dataTestId}-counter` |
|
|
113
|
+
| Thumbnails Container | `lightbox-thumbnails` | `{dataTestId}-thumbnails` |
|
|
114
|
+
| Individual Thumbnail | `lightbox-thumbnail-{index}` | `{dataTestId}-thumbnail-{index}` |
|
|
115
|
+
|
|
116
|
+
### Testing Best Practices
|
|
117
|
+
|
|
118
|
+
1. **Custom Test IDs**: Always provide a `dataTestId` prop when testing multiple lightbox instances on the same page.
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
<Lightbox dataTestId="product-gallery" isOpen={isOpen} onClose={handleClose} items={items} />
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
2. **Wait for Visibility**: Use proper waiting strategies for the overlay to appear/disappear.
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
await waitFor(() => {
|
|
128
|
+
expect(screen.getByTestId('lightbox')).toBeInTheDocument();
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
3. **Test User Interactions**: Verify all interactive elements respond correctly.
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
const closeButton = screen.getByTestId('lightbox-close');
|
|
136
|
+
await userEvent.click(closeButton);
|
|
137
|
+
expect(onCloseMock).toHaveBeenCalled();
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
4. **Test Keyboard Navigation**: Ensure keyboard controls work as expected.
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
await userEvent.keyboard('{Escape}');
|
|
144
|
+
expect(onCloseMock).toHaveBeenCalled();
|
|
145
|
+
|
|
146
|
+
await userEvent.keyboard('{ArrowRight}');
|
|
147
|
+
// Verify next image is displayed
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
5. **Accessibility Testing**: Validate ARIA attributes and focus management.
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
const dialog = screen.getByRole('dialog');
|
|
154
|
+
expect(dialog).toHaveAttribute('aria-modal', 'true');
|
|
155
|
+
expect(dialog).toHaveAttribute('aria-labelledby', 'lightbox-title');
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Common Test Scenarios
|
|
159
|
+
|
|
160
|
+
#### 1. Opening and Closing
|
|
161
|
+
- Click close button
|
|
162
|
+
- Click backdrop (if enabled)
|
|
163
|
+
- Press Escape key
|
|
164
|
+
- Swipe down on mobile
|
|
165
|
+
|
|
166
|
+
#### 2. Navigation
|
|
167
|
+
- Click previous/next buttons
|
|
168
|
+
- Use keyboard arrows (←, →)
|
|
169
|
+
- Swipe left/right on mobile
|
|
170
|
+
- Click thumbnails to navigate
|
|
171
|
+
- Verify disabled state at boundaries (when loop is off)
|
|
172
|
+
|
|
173
|
+
#### 3. Loop Behavior
|
|
174
|
+
- Test navigation wraps at edges when `loop={true}`
|
|
175
|
+
- Test navigation stops at edges when `loop={false}`
|
|
176
|
+
|
|
177
|
+
#### 4. Zoom and Pan
|
|
178
|
+
- Mouse wheel zoom
|
|
179
|
+
- Double-click to zoom in
|
|
180
|
+
- Double-click to zoom out (when zoomed)
|
|
181
|
+
- Drag to pan when zoomed
|
|
182
|
+
- Zoom controls (+, -, reset)
|
|
183
|
+
- Verify zoom only works on images, not videos
|
|
184
|
+
|
|
185
|
+
#### 5. Autoplay
|
|
186
|
+
- Start/stop slideshow
|
|
187
|
+
- Verify auto-advance timing
|
|
188
|
+
- Pause on hover/focus (if implemented)
|
|
189
|
+
- Spacebar toggle (if enabled)
|
|
190
|
+
|
|
191
|
+
#### 6. Media Loading
|
|
192
|
+
- Loading indicator appears for slow images
|
|
193
|
+
- Loading indicator disappears when image loads
|
|
194
|
+
- Video controls are visible
|
|
195
|
+
- Mixed image/video galleries work correctly
|
|
196
|
+
|
|
197
|
+
#### 7. Captions
|
|
198
|
+
- Caption displays when `showCaptions={true}`
|
|
199
|
+
- Caption is hidden when `showCaptions={false}`
|
|
200
|
+
- Caption content matches item caption
|
|
201
|
+
|
|
202
|
+
#### 8. Thumbnails
|
|
203
|
+
- Thumbnail strip appears when `thumbnails={true}`
|
|
204
|
+
- Current thumbnail is highlighted
|
|
205
|
+
- Clicking thumbnail navigates to that item
|
|
206
|
+
- Video thumbnails show play icon
|
|
207
|
+
|
|
208
|
+
#### 9. Accessibility
|
|
209
|
+
- Focus trap keeps focus within lightbox
|
|
210
|
+
- Screen reader announces current item ("Image 2 of 5")
|
|
211
|
+
- All interactive elements have aria-labels
|
|
212
|
+
- Dialog has proper ARIA roles and attributes
|
|
213
|
+
|
|
214
|
+
#### 10. Responsiveness
|
|
215
|
+
- Test at viewport widths: 320px, 768px, 1200px, 3200px
|
|
216
|
+
- Touch gestures work on mobile devices
|
|
217
|
+
- Controls are properly positioned at all sizes
|
|
218
|
+
|
|
219
|
+
### Example Test Suite
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
223
|
+
import userEvent from '@testing-library/user-event';
|
|
224
|
+
import { Lightbox } from './Lightbox';
|
|
225
|
+
|
|
226
|
+
describe('Lightbox', () => {
|
|
227
|
+
const mockItems = [
|
|
228
|
+
{ src: '/image1.jpg', alt: 'Image 1', caption: 'First image' },
|
|
229
|
+
{ src: '/image2.jpg', alt: 'Image 2', caption: 'Second image' },
|
|
230
|
+
{ src: '/video1.mp4', alt: 'Video 1', type: 'video' as const },
|
|
231
|
+
];
|
|
232
|
+
|
|
233
|
+
it('should open and display the lightbox', async () => {
|
|
234
|
+
const onClose = vi.fn();
|
|
235
|
+
render(<Lightbox isOpen={true} onClose={onClose} items={mockItems} />);
|
|
236
|
+
|
|
237
|
+
await waitFor(() => {
|
|
238
|
+
expect(screen.getByTestId('lightbox')).toBeInTheDocument();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
expect(screen.getByTestId('lightbox-image')).toHaveAttribute('src', '/image1.jpg');
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('should navigate to next item', async () => {
|
|
245
|
+
const onClose = vi.fn();
|
|
246
|
+
render(<Lightbox isOpen={true} onClose={onClose} items={mockItems} showControls={true} />);
|
|
247
|
+
|
|
248
|
+
const nextButton = screen.getByTestId('lightbox-next');
|
|
249
|
+
await userEvent.click(nextButton);
|
|
250
|
+
|
|
251
|
+
await waitFor(() => {
|
|
252
|
+
expect(screen.getByTestId('lightbox-image')).toHaveAttribute('src', '/image2.jpg');
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('should close on Escape key', async () => {
|
|
257
|
+
const onClose = vi.fn();
|
|
258
|
+
render(<Lightbox isOpen={true} onClose={onClose} items={mockItems} />);
|
|
259
|
+
|
|
260
|
+
await userEvent.keyboard('{Escape}');
|
|
261
|
+
|
|
262
|
+
expect(onClose).toHaveBeenCalled();
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('should display thumbnails when enabled', async () => {
|
|
266
|
+
const onClose = vi.fn();
|
|
267
|
+
render(<Lightbox isOpen={true} onClose={onClose} items={mockItems} thumbnails={true} />);
|
|
268
|
+
|
|
269
|
+
await waitFor(() => {
|
|
270
|
+
expect(screen.getByTestId('lightbox-thumbnails')).toBeInTheDocument();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
expect(screen.getByTestId('lightbox-thumbnail-0')).toBeInTheDocument();
|
|
274
|
+
expect(screen.getByTestId('lightbox-thumbnail-1')).toBeInTheDocument();
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('should zoom in and out', async () => {
|
|
278
|
+
const onClose = vi.fn();
|
|
279
|
+
render(<Lightbox isOpen={true} onClose={onClose} items={mockItems} zoomable={true} />);
|
|
280
|
+
|
|
281
|
+
const zoomInButton = screen.getByTestId('lightbox-zoom-in');
|
|
282
|
+
const zoomOutButton = screen.getByTestId('lightbox-zoom-out');
|
|
283
|
+
|
|
284
|
+
await userEvent.click(zoomInButton);
|
|
285
|
+
// Verify zoom level increased
|
|
286
|
+
|
|
287
|
+
await userEvent.click(zoomOutButton);
|
|
288
|
+
// Verify zoom level decreased
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Storybook Tests
|
|
294
|
+
|
|
295
|
+
- **Visual regression**: Overlay appearance, transitions, zoom states
|
|
296
|
+
- **Interaction**: Navigation buttons, keyboard controls, autoplay, gestures
|
|
297
|
+
- **Accessibility**: Roles, ARIA attributes, focus management, announcements
|
|
298
|
+
- **Responsive**: Layout at various viewport sizes
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
import { LoadingState } from './LoadingState';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof LoadingState> = {
|
|
6
|
+
title: 'DataDisplay/AsyncStates/LoadingState',
|
|
7
|
+
component: LoadingState,
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'centered',
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'A loading state component that displays a spinner or skeleton placeholder while content is being loaded.',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
tags: ['autodocs', 'component:LoadingState'],
|
|
18
|
+
argTypes: {
|
|
19
|
+
variant: {
|
|
20
|
+
control: 'radio',
|
|
21
|
+
options: ['spinner', 'skeleton'],
|
|
22
|
+
description: 'The visual style of the loading indicator',
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
control: 'radio',
|
|
26
|
+
options: ['sm', 'md', 'lg'],
|
|
27
|
+
description: 'Size of the loading indicator',
|
|
28
|
+
},
|
|
29
|
+
message: {
|
|
30
|
+
control: 'text',
|
|
31
|
+
description: 'Optional message to display below the loading indicator',
|
|
32
|
+
},
|
|
33
|
+
skeletonRows: {
|
|
34
|
+
control: { type: 'number', min: 1, max: 10 },
|
|
35
|
+
description: 'Number of skeleton rows (only for skeleton variant)',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default meta;
|
|
41
|
+
type Story = StoryObj<typeof meta>;
|
|
42
|
+
|
|
43
|
+
export const Default: Story = {
|
|
44
|
+
args: {},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const SpinnerSmall: Story = {
|
|
48
|
+
name: 'Spinner - Small',
|
|
49
|
+
args: {
|
|
50
|
+
variant: 'spinner',
|
|
51
|
+
size: 'sm',
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const SpinnerMedium: Story = {
|
|
56
|
+
name: 'Spinner - Medium',
|
|
57
|
+
args: {
|
|
58
|
+
variant: 'spinner',
|
|
59
|
+
size: 'md',
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const SpinnerLarge: Story = {
|
|
64
|
+
name: 'Spinner - Large',
|
|
65
|
+
args: {
|
|
66
|
+
variant: 'spinner',
|
|
67
|
+
size: 'lg',
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const SpinnerWithMessage: Story = {
|
|
72
|
+
name: 'Spinner with Message',
|
|
73
|
+
args: {
|
|
74
|
+
variant: 'spinner',
|
|
75
|
+
size: 'md',
|
|
76
|
+
message: 'Loading your data...',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const SkeletonDefault: Story = {
|
|
81
|
+
name: 'Skeleton - Default',
|
|
82
|
+
args: {
|
|
83
|
+
variant: 'skeleton',
|
|
84
|
+
},
|
|
85
|
+
parameters: {
|
|
86
|
+
layout: 'padded',
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const SkeletonWithMessage: Story = {
|
|
91
|
+
name: 'Skeleton with Message',
|
|
92
|
+
args: {
|
|
93
|
+
variant: 'skeleton',
|
|
94
|
+
message: 'Preparing content...',
|
|
95
|
+
skeletonRows: 4,
|
|
96
|
+
},
|
|
97
|
+
parameters: {
|
|
98
|
+
layout: 'padded',
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const SkeletonSmall: Story = {
|
|
103
|
+
name: 'Skeleton - Small',
|
|
104
|
+
args: {
|
|
105
|
+
variant: 'skeleton',
|
|
106
|
+
size: 'sm',
|
|
107
|
+
skeletonRows: 5,
|
|
108
|
+
},
|
|
109
|
+
parameters: {
|
|
110
|
+
layout: 'padded',
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export const SkeletonLarge: Story = {
|
|
115
|
+
name: 'Skeleton - Large',
|
|
116
|
+
args: {
|
|
117
|
+
variant: 'skeleton',
|
|
118
|
+
size: 'lg',
|
|
119
|
+
skeletonRows: 3,
|
|
120
|
+
},
|
|
121
|
+
parameters: {
|
|
122
|
+
layout: 'padded',
|
|
123
|
+
},
|
|
124
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { expect, within } from 'storybook/test';
|
|
3
|
+
|
|
4
|
+
import { LoadingState } from './LoadingState';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof LoadingState> = {
|
|
7
|
+
title: 'DataDisplay/AsyncStates/LoadingState/Tests',
|
|
8
|
+
component: LoadingState,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'padded',
|
|
11
|
+
chromatic: { disableSnapshot: false },
|
|
12
|
+
},
|
|
13
|
+
tags: ['autodocs', 'test', 'component:LoadingState'],
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default meta;
|
|
17
|
+
type Story = StoryObj<typeof meta>;
|
|
18
|
+
|
|
19
|
+
export const SpinnerAccessibility: Story = {
|
|
20
|
+
name: '🧪 Spinner Accessibility',
|
|
21
|
+
args: {
|
|
22
|
+
variant: 'spinner',
|
|
23
|
+
message: 'Loading data...',
|
|
24
|
+
},
|
|
25
|
+
play: async ({ canvasElement, step }) => {
|
|
26
|
+
const canvas = within(canvasElement);
|
|
27
|
+
|
|
28
|
+
await step('Verify loading state container exists', async () => {
|
|
29
|
+
const container = canvas.getByTestId('loading-state');
|
|
30
|
+
await expect(container).toBeInTheDocument();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await step('Verify ARIA attributes', async () => {
|
|
34
|
+
const container = canvas.getByTestId('loading-state');
|
|
35
|
+
await expect(container).toHaveAttribute('role', 'status');
|
|
36
|
+
await expect(container).toHaveAttribute('aria-busy', 'true');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
await step('Verify message is displayed', async () => {
|
|
40
|
+
const message = canvas.getByTestId('loading-state-message');
|
|
41
|
+
await expect(message).toHaveTextContent('Loading data...');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await step('Verify spinner is present', async () => {
|
|
45
|
+
const spinner = canvas.getByTestId('loading-state-spinner');
|
|
46
|
+
await expect(spinner).toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const SkeletonAccessibility: Story = {
|
|
52
|
+
name: '🧪 Skeleton Accessibility',
|
|
53
|
+
args: {
|
|
54
|
+
variant: 'skeleton',
|
|
55
|
+
skeletonRows: 3,
|
|
56
|
+
dataTestId: 'skeleton-test',
|
|
57
|
+
},
|
|
58
|
+
play: async ({ canvasElement, step }) => {
|
|
59
|
+
const canvas = within(canvasElement);
|
|
60
|
+
|
|
61
|
+
await step('Verify loading state container exists', async () => {
|
|
62
|
+
const container = canvas.getByTestId('skeleton-test');
|
|
63
|
+
await expect(container).toBeInTheDocument();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
await step('Verify ARIA attributes', async () => {
|
|
67
|
+
const container = canvas.getByTestId('skeleton-test');
|
|
68
|
+
await expect(container).toHaveAttribute('role', 'status');
|
|
69
|
+
await expect(container).toHaveAttribute('aria-busy', 'true');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await step('Verify skeleton rows are rendered', async () => {
|
|
73
|
+
const skeletons = canvasElement.querySelectorAll('[class*="MuiSkeleton"]');
|
|
74
|
+
await expect(skeletons.length).toBeGreaterThanOrEqual(3);
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const SizeVariations: Story = {
|
|
80
|
+
name: '🧪 Size Variations',
|
|
81
|
+
args: {
|
|
82
|
+
variant: 'spinner',
|
|
83
|
+
size: 'lg',
|
|
84
|
+
message: 'Large spinner',
|
|
85
|
+
},
|
|
86
|
+
play: async ({ canvasElement, step }) => {
|
|
87
|
+
const canvas = within(canvasElement);
|
|
88
|
+
|
|
89
|
+
await step('Verify large spinner renders', async () => {
|
|
90
|
+
const spinner = canvas.getByTestId('loading-state-spinner');
|
|
91
|
+
await expect(spinner).toBeInTheDocument();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
await step('Verify message with correct typography', async () => {
|
|
95
|
+
const message = canvas.getByTestId('loading-state-message');
|
|
96
|
+
await expect(message).toBeInTheDocument();
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Box, CircularProgress, Stack, Typography, useTheme } from '@mui/material';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { Skeleton } from '../../layout/Skeleton/Skeleton';
|
|
5
|
+
|
|
6
|
+
import type { LoadingStateProps, LoadingStateSize } from './LoadingState.types';
|
|
7
|
+
|
|
8
|
+
const sizeMap: Record<LoadingStateSize, { spinner: number; text: 'body2' | 'body1' | 'h6' }> = {
|
|
9
|
+
sm: { spinner: 24, text: 'body2' },
|
|
10
|
+
md: { spinner: 40, text: 'body1' },
|
|
11
|
+
lg: { spinner: 56, text: 'h6' },
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const LoadingState: React.FC<LoadingStateProps> = React.memo(
|
|
15
|
+
({
|
|
16
|
+
variant = 'spinner',
|
|
17
|
+
message,
|
|
18
|
+
size = 'md',
|
|
19
|
+
skeletonRows = 3,
|
|
20
|
+
className,
|
|
21
|
+
dataTestId,
|
|
22
|
+
}) => {
|
|
23
|
+
const theme = useTheme();
|
|
24
|
+
const sizeConfig = sizeMap[size];
|
|
25
|
+
|
|
26
|
+
if (variant === 'skeleton') {
|
|
27
|
+
return (
|
|
28
|
+
<Box
|
|
29
|
+
role="status"
|
|
30
|
+
aria-busy="true"
|
|
31
|
+
aria-label={message || 'Loading content'}
|
|
32
|
+
className={className}
|
|
33
|
+
data-testid={dataTestId || 'loading-state'}
|
|
34
|
+
sx={{
|
|
35
|
+
width: '100%',
|
|
36
|
+
padding: theme.spacing(3),
|
|
37
|
+
}}
|
|
38
|
+
>
|
|
39
|
+
<Stack spacing={2}>
|
|
40
|
+
{Array.from({ length: skeletonRows }).map((_, index) => (
|
|
41
|
+
<Skeleton
|
|
42
|
+
key={`skeleton-row-${index}`}
|
|
43
|
+
variant="rectangular"
|
|
44
|
+
animation="wave"
|
|
45
|
+
height={size === 'sm' ? 20 : size === 'md' ? 28 : 36}
|
|
46
|
+
width={index === skeletonRows - 1 ? '60%' : '100%'}
|
|
47
|
+
borderRadius={4}
|
|
48
|
+
data-testid={dataTestId ? `${dataTestId}-skeleton-${index}` : undefined}
|
|
49
|
+
/>
|
|
50
|
+
))}
|
|
51
|
+
</Stack>
|
|
52
|
+
{message && (
|
|
53
|
+
<Typography
|
|
54
|
+
variant={sizeConfig.text}
|
|
55
|
+
color="text.secondary"
|
|
56
|
+
sx={{ mt: 2, textAlign: 'center' }}
|
|
57
|
+
data-testid={dataTestId ? `${dataTestId}-message` : 'loading-state-message'}
|
|
58
|
+
>
|
|
59
|
+
{message}
|
|
60
|
+
</Typography>
|
|
61
|
+
)}
|
|
62
|
+
</Box>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<Box
|
|
68
|
+
role="status"
|
|
69
|
+
aria-busy="true"
|
|
70
|
+
aria-label={message || 'Loading'}
|
|
71
|
+
className={className}
|
|
72
|
+
data-testid={dataTestId || 'loading-state'}
|
|
73
|
+
sx={{
|
|
74
|
+
display: 'flex',
|
|
75
|
+
flexDirection: 'column',
|
|
76
|
+
alignItems: 'center',
|
|
77
|
+
justifyContent: 'center',
|
|
78
|
+
padding: theme.spacing(6),
|
|
79
|
+
minHeight: 200,
|
|
80
|
+
gap: theme.spacing(2),
|
|
81
|
+
}}
|
|
82
|
+
>
|
|
83
|
+
<CircularProgress
|
|
84
|
+
size={sizeConfig.spinner}
|
|
85
|
+
data-testid={dataTestId ? `${dataTestId}-spinner` : 'loading-state-spinner'}
|
|
86
|
+
/>
|
|
87
|
+
{message && (
|
|
88
|
+
<Typography
|
|
89
|
+
variant={sizeConfig.text}
|
|
90
|
+
color="text.secondary"
|
|
91
|
+
data-testid={dataTestId ? `${dataTestId}-message` : 'loading-state-message'}
|
|
92
|
+
>
|
|
93
|
+
{message}
|
|
94
|
+
</Typography>
|
|
95
|
+
)}
|
|
96
|
+
</Box>
|
|
97
|
+
);
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
LoadingState.displayName = 'LoadingState';
|
|
102
|
+
|
|
103
|
+
export default LoadingState;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type LoadingStateVariant = 'spinner' | 'skeleton';
|
|
2
|
+
export type LoadingStateSize = 'sm' | 'md' | 'lg';
|
|
3
|
+
|
|
4
|
+
export interface LoadingStateProps {
|
|
5
|
+
/**
|
|
6
|
+
* The visual style of the loading indicator
|
|
7
|
+
* @default 'spinner'
|
|
8
|
+
*/
|
|
9
|
+
variant?: LoadingStateVariant;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Optional message to display below the loading indicator
|
|
13
|
+
*/
|
|
14
|
+
message?: string;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Size of the loading indicator
|
|
18
|
+
* @default 'md'
|
|
19
|
+
*/
|
|
20
|
+
size?: LoadingStateSize;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Number of skeleton rows to display (only for skeleton variant)
|
|
24
|
+
* @default 3
|
|
25
|
+
*/
|
|
26
|
+
skeletonRows?: number;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Custom className for the container
|
|
30
|
+
*/
|
|
31
|
+
className?: string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Test ID for component testing
|
|
35
|
+
*/
|
|
36
|
+
dataTestId?: string;
|
|
37
|
+
}
|