@utilitywarehouse/hearth-react-native 0.1.0 → 0.2.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/.storybook/preview.tsx +5 -0
- package/.storybook/prism-setup.ts +104 -0
- package/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-lint.log +1 -1
- package/CHANGELOG.md +20 -0
- package/build/components/Accordion/Accordion.d.ts +1 -1
- package/build/components/Accordion/Accordion.js +7 -7
- package/build/components/Accordion/Accordion.props.d.ts +2 -2
- package/build/components/Accordion/AccordionIcon.js +2 -2
- package/build/components/Accordion/AccordionItemRoot.js +2 -2
- package/build/components/Accordion/AccordionTrigger.js +4 -4
- package/build/components/Accordion/index.d.ts +1 -2
- package/build/components/Accordion/index.js +1 -2
- package/build/components/Alert/Alert.js +21 -21
- package/build/components/Alert/Alert.props.d.ts +3 -3
- package/build/components/Alert/AlertCloseButton.js +2 -2
- package/build/components/Alert/AlertIcon.js +5 -5
- package/build/components/Badge/Badge.context.d.ts +4 -0
- package/build/components/Badge/Badge.js +86 -27
- package/build/components/Badge/Badge.props.d.ts +2 -1
- package/build/components/Badge/BadgeIcon.js +102 -18
- package/build/components/Badge/BadgeText.js +102 -17
- package/build/components/BodyText/BodyText.js +2 -2
- package/build/components/BottomSheet/BottomSheet.d.ts +1 -1
- package/build/components/BottomSheet/BottomSheet.js +3 -3
- package/build/components/BottomSheet/BottomSheetHandle.js +1 -1
- package/build/components/BottomSheet/BottomSheetModal.js +1 -1
- package/build/components/BottomSheet/BottomSheetScrollView.js +3 -1
- package/build/components/BottomSheet/BottomSheetView.js +1 -1
- package/build/components/Button/Button.props.d.ts +7 -7
- package/build/components/Button/ButtonIcon.js +29 -29
- package/build/components/Button/ButtonRoot.js +79 -88
- package/build/components/Button/ButtonSpinner.js +28 -31
- package/build/components/Button/ButtonText.js +40 -26
- package/build/components/Card/Card.props.d.ts +1 -1
- package/build/components/Card/CardRoot.js +56 -56
- package/build/components/Checkbox/CheckboxIcon.js +3 -3
- package/build/components/Checkbox/CheckboxIndicator.js +3 -3
- package/build/components/Checkbox/CheckboxTileRoot.js +3 -3
- package/build/components/DetailText/DetailText.js +2 -2
- package/build/components/Divider/Divider.js +1 -1
- package/build/components/Heading/Heading.js +2 -2
- package/build/components/Heading/Heading.props.d.ts +3 -1
- package/build/components/Helper/HelperIcon.js +3 -3
- package/build/components/Helper/HelperText.js +4 -4
- package/build/components/IconButton/IconButtonIcon.js +29 -29
- package/build/components/IconButton/IconButtonRoot.js +94 -88
- package/build/components/IconButton/IconButtonSpinner.js +27 -30
- package/build/components/InlineLink/InlineLinkRoot.js +2 -2
- package/build/components/Input/Input.d.ts +9 -3
- package/build/components/Input/Input.js +13 -13
- package/build/components/Input/Input.props.d.ts +1 -0
- package/build/components/Input/InputField.d.ts +3 -1
- package/build/components/Input/InputField.js +9 -39
- package/build/components/Input/InputIcon.js +1 -1
- package/build/components/Input/InputRoot.js +9 -9
- package/build/components/Label/Label.js +1 -1
- package/build/components/Link/LinkRoot.js +2 -2
- package/build/components/List/List.d.ts +1 -1
- package/build/components/List/List.js +6 -4
- package/build/components/List/List.props.d.ts +9 -10
- package/build/components/List/ListItem/ListItemHelperText.js +1 -1
- package/build/components/List/ListItem/ListItemIcon.js +1 -1
- package/build/components/List/ListItem/ListItemRoot.js +15 -6
- package/build/components/List/ListItem/ListItemTrailingIcon.js +1 -1
- package/build/components/List/index.d.ts +0 -1
- package/build/components/List/index.js +0 -1
- package/build/components/Modal/Modal.d.ts +7 -0
- package/build/components/Modal/Modal.js +164 -0
- package/build/components/Modal/Modal.props.d.ts +24 -0
- package/build/components/Modal/Modal.web.d.ts +7 -0
- package/build/components/Modal/Modal.web.js +164 -0
- package/build/components/Modal/index.d.ts +2 -0
- package/build/components/Modal/index.js +1 -0
- package/build/components/Radio/RadioIndicator.js +2 -2
- package/build/components/Radio/RadioTileRoot.js +3 -3
- package/build/components/RadioCard/RadioCardIndicator.js +2 -2
- package/build/components/RadioCard/RadioCardRoot.js +3 -3
- package/build/components/SectionHeader/SectionHeader.d.ts +6 -0
- package/build/components/SectionHeader/SectionHeader.js +19 -0
- package/build/components/{List/ListHeading/ListHeading.props.d.ts → SectionHeader/SectionHeader.props.d.ts} +7 -9
- package/build/components/SectionHeader/SectionHeaderHeading.d.ts +6 -0
- package/build/components/SectionHeader/SectionHeaderHeading.js +7 -0
- package/build/components/SectionHeader/SectionHeaderHelperText.d.ts +6 -0
- package/build/components/{List/ListHeading/ListHeadingHelperText.js → SectionHeader/SectionHeaderHelperText.js} +5 -5
- package/build/components/{List/ListHeading/ListHeadingTextContent.d.ts → SectionHeader/SectionHeaderTextContent.d.ts} +2 -2
- package/build/components/{List/ListHeading/ListHeadingTextContent.js → SectionHeader/SectionHeaderTextContent.js} +4 -4
- package/build/components/SectionHeader/index.d.ts +4 -0
- package/build/components/SectionHeader/index.js +4 -0
- package/build/components/Select/Select.js +10 -10
- package/build/components/Select/SelectOption.js +6 -6
- package/build/components/Spinner/Spinner.web.js +3 -3
- package/build/components/Switch/Switch.js +10 -7
- package/build/components/Switch/Switch.web.js +10 -8
- package/build/components/Textarea/TextareaField.js +5 -5
- package/build/components/Textarea/TextareaRoot.js +9 -9
- package/build/components/ToggleButton/ToggleButtonIcon.js +3 -3
- package/build/components/ToggleButton/ToggleButtonRoot.js +9 -9
- package/build/components/ToggleButton/ToggleButtonText.js +2 -2
- package/build/components/ToggleButtonCard/ToggleButtonCardRoot.js +3 -3
- package/build/components/index.d.ts +5 -3
- package/build/components/index.js +5 -3
- package/build/core/themes.d.ts +1094 -178
- package/build/core/themes.js +2 -2
- package/build/tokens/color.d.ts +1002 -86
- package/build/tokens/color.js +501 -43
- package/build/tokens/components/dark/accordion.d.ts +0 -2
- package/build/tokens/components/dark/accordion.js +0 -2
- package/build/tokens/components/dark/alert.d.ts +0 -16
- package/build/tokens/components/dark/alert.js +0 -16
- package/build/tokens/components/dark/avatar.d.ts +19 -0
- package/build/tokens/components/dark/avatar.js +18 -0
- package/build/tokens/components/dark/badge.d.ts +7 -34
- package/build/tokens/components/dark/badge.js +7 -34
- package/build/tokens/components/dark/banner.d.ts +1 -10
- package/build/tokens/components/dark/banner.js +1 -10
- package/build/tokens/components/dark/bottom-navigation.d.ts +2 -7
- package/build/tokens/components/dark/bottom-navigation.js +2 -7
- package/build/tokens/components/dark/bottom-sheet.d.ts +1 -2
- package/build/tokens/components/dark/bottom-sheet.js +1 -2
- package/build/tokens/components/dark/breadcrumb.d.ts +0 -1
- package/build/tokens/components/dark/breadcrumb.js +0 -1
- package/build/tokens/components/dark/button.d.ts +0 -86
- package/build/tokens/components/dark/button.js +0 -86
- package/build/tokens/components/dark/card.d.ts +0 -28
- package/build/tokens/components/dark/card.js +0 -28
- package/build/tokens/components/dark/carousel-control.d.ts +0 -8
- package/build/tokens/components/dark/carousel-control.js +0 -8
- package/build/tokens/components/dark/checkbox.d.ts +1 -10
- package/build/tokens/components/dark/checkbox.js +1 -10
- package/build/tokens/components/dark/date-picker.d.ts +0 -12
- package/build/tokens/components/dark/date-picker.js +0 -12
- package/build/tokens/components/dark/description-list.d.ts +20 -0
- package/build/tokens/components/dark/description-list.js +19 -0
- package/build/tokens/components/dark/dialog.d.ts +0 -1
- package/build/tokens/components/dark/dialog.js +0 -1
- package/build/tokens/components/dark/divider.d.ts +4 -1
- package/build/tokens/components/dark/divider.js +4 -1
- package/build/tokens/components/dark/expandable-card.d.ts +11 -0
- package/build/tokens/components/dark/expandable-card.js +10 -0
- package/build/tokens/components/dark/icon-button.d.ts +5 -5
- package/build/tokens/components/dark/icon-button.js +5 -5
- package/build/tokens/components/dark/icon-container.d.ts +0 -17
- package/build/tokens/components/dark/icon-container.js +0 -17
- package/build/tokens/components/dark/index.d.ts +10 -4
- package/build/tokens/components/dark/index.js +10 -4
- package/build/tokens/components/dark/indicator-icon-button.d.ts +11 -0
- package/build/tokens/components/dark/indicator-icon-button.js +10 -0
- package/build/tokens/components/dark/inline-link.d.ts +1 -1
- package/build/tokens/components/dark/inline-link.js +1 -1
- package/build/tokens/components/dark/input.d.ts +1 -9
- package/build/tokens/components/dark/input.js +1 -9
- package/build/tokens/components/dark/link.d.ts +2 -2
- package/build/tokens/components/dark/link.js +2 -2
- package/build/tokens/components/dark/list.d.ts +20 -20
- package/build/tokens/components/dark/list.js +20 -20
- package/build/tokens/components/dark/menu.d.ts +0 -12
- package/build/tokens/components/dark/menu.js +0 -12
- package/build/tokens/components/dark/modal.d.ts +0 -1
- package/build/tokens/components/dark/modal.js +0 -1
- package/build/tokens/components/dark/navigation.d.ts +1 -6
- package/build/tokens/components/dark/navigation.js +1 -6
- package/build/tokens/components/dark/pagination.d.ts +12 -0
- package/build/tokens/components/dark/pagination.js +11 -0
- package/build/tokens/components/dark/parts.d.ts +14 -4
- package/build/tokens/components/dark/parts.js +14 -4
- package/build/tokens/components/dark/pill.d.ts +0 -10
- package/build/tokens/components/dark/pill.js +0 -10
- package/build/tokens/components/dark/progress-stepper.d.ts +0 -8
- package/build/tokens/components/dark/progress-stepper.js +0 -8
- package/build/tokens/components/dark/radio.d.ts +1 -8
- package/build/tokens/components/dark/radio.js +1 -8
- package/build/tokens/components/dark/{focus.d.ts → section-header.d.ts} +4 -2
- package/build/tokens/components/dark/{focus.js → section-header.js} +4 -2
- package/build/tokens/components/dark/segmented-control.d.ts +0 -8
- package/build/tokens/components/dark/segmented-control.js +0 -8
- package/build/tokens/components/dark/select.d.ts +0 -10
- package/build/tokens/components/dark/select.js +0 -10
- package/build/tokens/components/dark/spinner.d.ts +1 -1
- package/build/tokens/components/dark/spinner.js +1 -1
- package/build/tokens/components/dark/switch.d.ts +1 -11
- package/build/tokens/components/dark/switch.js +1 -11
- package/build/tokens/components/dark/table.d.ts +23 -0
- package/build/tokens/components/dark/table.js +22 -0
- package/build/tokens/components/dark/tabs.d.ts +24 -0
- package/build/tokens/components/dark/tabs.js +23 -0
- package/build/tokens/components/dark/toast.d.ts +10 -0
- package/build/tokens/components/dark/toast.js +9 -0
- package/build/tokens/components/dark/toggle-button.d.ts +0 -11
- package/build/tokens/components/dark/toggle-button.js +0 -11
- package/build/tokens/components/dark/tooltip.d.ts +12 -0
- package/build/tokens/components/dark/tooltip.js +11 -0
- package/build/tokens/components/dark/top-navigation.d.ts +0 -8
- package/build/tokens/components/dark/top-navigation.js +0 -8
- package/build/tokens/components/light/accordion.d.ts +0 -2
- package/build/tokens/components/light/accordion.js +0 -2
- package/build/tokens/components/light/alert.d.ts +0 -16
- package/build/tokens/components/light/alert.js +0 -16
- package/build/tokens/components/light/avatar.d.ts +19 -0
- package/build/tokens/components/light/avatar.js +18 -0
- package/build/tokens/components/light/badge.d.ts +7 -34
- package/build/tokens/components/light/badge.js +7 -34
- package/build/tokens/components/light/banner.d.ts +2 -11
- package/build/tokens/components/light/banner.js +2 -11
- package/build/tokens/components/light/bottom-navigation.d.ts +0 -5
- package/build/tokens/components/light/bottom-navigation.js +0 -5
- package/build/tokens/components/light/bottom-sheet.d.ts +1 -2
- package/build/tokens/components/light/bottom-sheet.js +1 -2
- package/build/tokens/components/light/breadcrumb.d.ts +0 -1
- package/build/tokens/components/light/breadcrumb.js +0 -1
- package/build/tokens/components/light/button.d.ts +0 -86
- package/build/tokens/components/light/button.js +0 -86
- package/build/tokens/components/light/card.d.ts +0 -28
- package/build/tokens/components/light/card.js +0 -28
- package/build/tokens/components/light/carousel-control.d.ts +0 -8
- package/build/tokens/components/light/carousel-control.js +0 -8
- package/build/tokens/components/light/checkbox.d.ts +0 -9
- package/build/tokens/components/light/checkbox.js +0 -9
- package/build/tokens/components/light/date-picker.d.ts +0 -12
- package/build/tokens/components/light/date-picker.js +0 -12
- package/build/tokens/components/light/description-list.d.ts +20 -0
- package/build/tokens/components/light/description-list.js +19 -0
- package/build/tokens/components/light/dialog.d.ts +0 -1
- package/build/tokens/components/light/dialog.js +0 -1
- package/build/tokens/components/light/divider.d.ts +4 -1
- package/build/tokens/components/light/divider.js +4 -1
- package/build/tokens/components/light/expandable-card.d.ts +11 -0
- package/build/tokens/components/light/expandable-card.js +10 -0
- package/build/tokens/components/light/icon-button.d.ts +5 -5
- package/build/tokens/components/light/icon-button.js +5 -5
- package/build/tokens/components/light/icon-container.d.ts +0 -17
- package/build/tokens/components/light/icon-container.js +0 -17
- package/build/tokens/components/light/index.d.ts +10 -4
- package/build/tokens/components/light/index.js +10 -4
- package/build/tokens/components/light/indicator-icon-button.d.ts +11 -0
- package/build/tokens/components/light/indicator-icon-button.js +10 -0
- package/build/tokens/components/light/input.d.ts +1 -9
- package/build/tokens/components/light/input.js +1 -9
- package/build/tokens/components/light/link.d.ts +2 -2
- package/build/tokens/components/light/link.js +2 -2
- package/build/tokens/components/light/list.d.ts +20 -20
- package/build/tokens/components/light/list.js +20 -20
- package/build/tokens/components/light/menu.d.ts +0 -12
- package/build/tokens/components/light/menu.js +0 -12
- package/build/tokens/components/light/modal.d.ts +0 -1
- package/build/tokens/components/light/modal.js +0 -1
- package/build/tokens/components/light/navigation.d.ts +1 -6
- package/build/tokens/components/light/navigation.js +1 -6
- package/build/tokens/components/light/pagination.d.ts +12 -0
- package/build/tokens/components/light/pagination.js +11 -0
- package/build/tokens/components/light/parts.d.ts +11 -1
- package/build/tokens/components/light/parts.js +11 -1
- package/build/tokens/components/light/pill.d.ts +0 -10
- package/build/tokens/components/light/pill.js +0 -10
- package/build/tokens/components/light/progress-stepper.d.ts +0 -8
- package/build/tokens/components/light/progress-stepper.js +0 -8
- package/build/tokens/components/light/radio.d.ts +0 -7
- package/build/tokens/components/light/radio.js +0 -7
- package/build/tokens/components/light/section-header.d.ts +10 -0
- package/build/tokens/components/light/section-header.js +9 -0
- package/build/tokens/components/light/segmented-control.d.ts +0 -8
- package/build/tokens/components/light/segmented-control.js +0 -8
- package/build/tokens/components/light/select.d.ts +0 -10
- package/build/tokens/components/light/select.js +0 -10
- package/build/tokens/components/light/switch.d.ts +1 -11
- package/build/tokens/components/light/switch.js +1 -11
- package/build/tokens/components/light/table.d.ts +23 -0
- package/build/tokens/components/light/table.js +22 -0
- package/build/tokens/components/light/tabs.d.ts +24 -0
- package/build/tokens/components/light/tabs.js +23 -0
- package/build/tokens/components/light/toast.d.ts +10 -0
- package/build/tokens/components/light/toast.js +9 -0
- package/build/tokens/components/light/toggle-button.d.ts +0 -11
- package/build/tokens/components/light/toggle-button.js +0 -11
- package/build/tokens/components/light/tooltip.d.ts +12 -0
- package/build/tokens/components/light/tooltip.js +11 -0
- package/build/tokens/components/light/top-navigation.d.ts +0 -8
- package/build/tokens/components/light/top-navigation.js +0 -8
- package/build/tokens/index.d.ts +1 -0
- package/build/tokens/index.js +1 -0
- package/build/tokens/semantic-dark.d.ts +240 -13
- package/build/tokens/semantic-dark.js +240 -13
- package/build/tokens/semantic-light.d.ts +240 -13
- package/build/tokens/semantic-light.js +240 -13
- package/build/tokens/{components/light/focus.d.ts → semantic.d.ts} +3 -2
- package/build/tokens/{components/light/focus.js → semantic.js} +3 -2
- package/build/types/values.d.ts +10 -6
- package/build/utils/coloursAsArray.d.ts +8 -0
- package/build/utils/coloursAsArray.js +37 -2
- package/build/utils/getFlattenedColorValue.d.ts +3 -1
- package/build/utils/hexWithOpacity.d.ts +2 -0
- package/build/utils/hexWithOpacity.js +15 -0
- package/build/utils/index.d.ts +2 -1
- package/build/utils/index.js +2 -1
- package/build/utils/styleUtils.js +33 -1
- package/docs/assets/modal-android.mp4 +0 -0
- package/docs/assets/modal-ios.mp4 +0 -0
- package/docs/assets/pigs.png +0 -0
- package/docs/components/AllComponents.web.tsx +39 -2
- package/docs/components/BadgeList.tsx +8 -8
- package/docs/components/ViewFigmaButton.tsx +3 -3
- package/docs/introduction.mdx +2 -2
- package/docs/llm-docs/unistyles-llms-full.txt +1 -1
- package/docs/theme-tokens.mdx +49 -26
- package/package.json +20 -17
- package/src/components/Accordion/Accordion.docs.mdx +25 -39
- package/src/components/Accordion/Accordion.props.ts +2 -2
- package/src/components/Accordion/Accordion.stories.tsx +10 -10
- package/src/components/Accordion/Accordion.tsx +14 -14
- package/src/components/Accordion/AccordionIcon.tsx +2 -2
- package/src/components/Accordion/AccordionItemRoot.tsx +3 -3
- package/src/components/Accordion/AccordionTrigger.tsx +4 -4
- package/src/components/Accordion/index.ts +3 -4
- package/src/components/Alert/Alert.docs.mdx +25 -25
- package/src/components/Alert/Alert.props.ts +3 -3
- package/src/components/Alert/Alert.stories.tsx +11 -11
- package/src/components/Alert/Alert.tsx +22 -22
- package/src/components/Alert/AlertCloseButton.tsx +3 -3
- package/src/components/Alert/AlertIcon.tsx +7 -7
- package/src/components/Badge/Badge.context.ts +2 -0
- package/src/components/Badge/Badge.docs.mdx +16 -15
- package/src/components/Badge/Badge.props.ts +13 -1
- package/src/components/Badge/Badge.stories.tsx +106 -48
- package/src/components/Badge/Badge.tsx +96 -29
- package/src/components/Badge/BadgeIcon.tsx +102 -18
- package/src/components/Badge/BadgeText.tsx +102 -17
- package/src/components/BodyText/BodyText.tsx +4 -4
- package/src/components/BottomSheet/BottomSheet.docs.mdx +23 -5
- package/src/components/BottomSheet/BottomSheet.stories.tsx +9 -9
- package/src/components/BottomSheet/BottomSheet.tsx +5 -5
- package/src/components/BottomSheet/BottomSheetHandle.tsx +1 -1
- package/src/components/BottomSheet/BottomSheetModal.tsx +1 -1
- package/src/components/BottomSheet/BottomSheetScrollView.tsx +4 -2
- package/src/components/BottomSheet/BottomSheetView.tsx +1 -1
- package/src/components/Box/Box.stories.tsx +3 -3
- package/src/components/Button/Button.docs.mdx +35 -35
- package/src/components/Button/Button.props.tsx +7 -7
- package/src/components/Button/Button.stories.tsx +16 -16
- package/src/components/Button/ButtonIcon.tsx +29 -29
- package/src/components/Button/ButtonRoot.tsx +79 -89
- package/src/components/Button/ButtonSpinner.tsx +30 -33
- package/src/components/Button/ButtonText.tsx +40 -26
- package/src/components/Card/Card.docs.mdx +22 -22
- package/src/components/Card/Card.props.ts +9 -9
- package/src/components/Card/Card.stories.tsx +34 -34
- package/src/components/Card/CardRoot.tsx +56 -56
- package/src/components/Checkbox/CheckboxIcon.tsx +4 -4
- package/src/components/Checkbox/CheckboxIndicator.tsx +3 -3
- package/src/components/Checkbox/CheckboxTileRoot.tsx +3 -3
- package/src/components/DetailText/DetailText.tsx +3 -3
- package/src/components/Divider/Divider.tsx +1 -1
- package/src/components/Heading/Heading.props.ts +3 -1
- package/src/components/Heading/Heading.tsx +2 -2
- package/src/components/Helper/HelperIcon.tsx +3 -3
- package/src/components/Helper/HelperText.tsx +4 -4
- package/src/components/Icon/Icon.stories.tsx +2 -2
- package/src/components/IconButton/IconButton.docs.mdx +21 -16
- package/src/components/IconButton/IconButton.figma.tsx +1 -1
- package/src/components/IconButton/IconButton.stories.tsx +14 -14
- package/src/components/IconButton/IconButtonIcon.tsx +29 -29
- package/src/components/IconButton/IconButtonRoot.tsx +94 -88
- package/src/components/IconButton/IconButtonSpinner.tsx +27 -30
- package/src/components/InlineLink/InlineLinkRoot.tsx +2 -2
- package/src/components/Input/Input.docs.mdx +16 -14
- package/src/components/Input/Input.props.ts +1 -0
- package/src/components/Input/Input.stories.tsx +5 -4
- package/src/components/Input/Input.tsx +15 -13
- package/src/components/Input/InputField.tsx +25 -52
- package/src/components/Input/InputIcon.tsx +1 -1
- package/src/components/Input/InputRoot.tsx +10 -10
- package/src/components/Label/Label.tsx +2 -2
- package/src/components/Link/LinkRoot.tsx +2 -2
- package/src/components/List/List.docs.mdx +35 -56
- package/src/components/List/List.props.ts +9 -10
- package/src/components/List/List.stories.tsx +8 -8
- package/src/components/List/List.tsx +25 -25
- package/src/components/List/ListItem/ListItemHelperText.tsx +1 -1
- package/src/components/List/ListItem/ListItemIcon.tsx +1 -1
- package/src/components/List/ListItem/ListItemRoot.tsx +15 -6
- package/src/components/List/ListItem/ListItemTrailingIcon.tsx +1 -1
- package/src/components/List/index.ts +0 -1
- package/src/components/Modal/Modal.docs.mdx +547 -0
- package/src/components/Modal/Modal.props.ts +26 -0
- package/src/components/Modal/Modal.stories.tsx +222 -0
- package/src/components/Modal/Modal.tsx +333 -0
- package/src/components/Modal/Modal.web.tsx +333 -0
- package/src/components/Modal/index.ts +2 -0
- package/src/components/Radio/RadioIndicator.tsx +2 -2
- package/src/components/Radio/RadioTileRoot.tsx +3 -3
- package/src/components/RadioCard/RadioCardIndicator.tsx +2 -2
- package/src/components/RadioCard/RadioCardRoot.tsx +3 -3
- package/src/components/{List/ListHeading/ListHeading.figma.tsx → SectionHeader/SectionHeader.figma.tsx} +3 -3
- package/src/components/{List/ListHeading/ListHeading.props.ts → SectionHeader/SectionHeader.props.ts} +7 -9
- package/src/components/SectionHeader/SectionHeader.stories.tsx +76 -0
- package/src/components/{List/ListHeading/ListHeading.tsx → SectionHeader/SectionHeader.tsx} +16 -19
- package/src/components/SectionHeader/SectionHeaderHeading.tsx +14 -0
- package/src/components/SectionHeader/SectionHeaderHelperText.tsx +21 -0
- package/src/components/{List/ListHeading/ListHeadingTextContent.tsx → SectionHeader/SectionHeaderTextContent.tsx} +4 -4
- package/src/components/SectionHeader/Sectionheader.docs.mdx +83 -0
- package/src/components/SectionHeader/index.ts +4 -0
- package/src/components/Select/Select.tsx +10 -10
- package/src/components/Select/SelectOption.tsx +7 -7
- package/src/components/Spinner/Spinner.tsx +3 -3
- package/src/components/Spinner/Spinner.web.tsx +12 -12
- package/src/components/Switch/Switch.tsx +10 -7
- package/src/components/Switch/Switch.web.tsx +10 -12
- package/src/components/Textarea/TextareaField.tsx +5 -5
- package/src/components/Textarea/TextareaRoot.tsx +10 -10
- package/src/components/ToggleButton/ToggleButtonIcon.tsx +3 -3
- package/src/components/ToggleButton/ToggleButtonRoot.tsx +11 -11
- package/src/components/ToggleButton/ToggleButtonText.tsx +2 -2
- package/src/components/ToggleButtonCard/ToggleButtonCardRoot.tsx +3 -3
- package/src/components/index.ts +7 -5
- package/src/core/themes.ts +2 -2
- package/src/tokens/color.ts +501 -43
- package/src/tokens/components/dark/accordion.ts +0 -2
- package/src/tokens/components/dark/alert.ts +0 -16
- package/src/tokens/components/dark/avatar.ts +19 -0
- package/src/tokens/components/dark/badge.ts +7 -34
- package/src/tokens/components/dark/banner.ts +1 -10
- package/src/tokens/components/dark/bottom-navigation.ts +2 -7
- package/src/tokens/components/dark/bottom-sheet.ts +1 -2
- package/src/tokens/components/dark/breadcrumb.ts +0 -1
- package/src/tokens/components/dark/button.ts +0 -86
- package/src/tokens/components/dark/card.ts +0 -28
- package/src/tokens/components/dark/carousel-control.ts +0 -8
- package/src/tokens/components/dark/checkbox.ts +1 -10
- package/src/tokens/components/dark/date-picker.ts +0 -12
- package/src/tokens/components/dark/description-list.ts +20 -0
- package/src/tokens/components/dark/dialog.ts +0 -1
- package/src/tokens/components/dark/divider.ts +4 -1
- package/src/tokens/components/{light/footer.ts → dark/expandable-card.ts} +4 -5
- package/src/tokens/components/dark/icon-button.ts +5 -5
- package/src/tokens/components/dark/icon-container.ts +0 -17
- package/src/tokens/components/dark/index.ts +10 -4
- package/src/tokens/components/dark/{footer.ts → indicator-icon-button.ts} +4 -5
- package/src/tokens/components/dark/inline-link.ts +1 -1
- package/src/tokens/components/dark/input.ts +1 -9
- package/src/tokens/components/dark/link.ts +2 -2
- package/src/tokens/components/dark/list.ts +20 -20
- package/src/tokens/components/dark/menu.ts +0 -12
- package/src/tokens/components/dark/modal.ts +0 -1
- package/src/tokens/components/dark/navigation.ts +1 -6
- package/src/tokens/components/dark/pagination.ts +12 -0
- package/src/tokens/components/dark/parts.ts +14 -4
- package/src/tokens/components/dark/pill.ts +0 -10
- package/src/tokens/components/dark/progress-stepper.ts +0 -8
- package/src/tokens/components/dark/radio.ts +1 -8
- package/src/tokens/components/dark/{focus.ts → section-header.ts} +4 -2
- package/src/tokens/components/dark/segmented-control.ts +0 -8
- package/src/tokens/components/dark/select.ts +0 -10
- package/src/tokens/components/dark/spinner.ts +1 -1
- package/src/tokens/components/dark/switch.ts +1 -11
- package/src/tokens/components/dark/table.ts +23 -0
- package/src/tokens/components/dark/tabs.ts +24 -0
- package/src/tokens/components/dark/toast.ts +10 -0
- package/src/tokens/components/dark/toggle-button.ts +0 -11
- package/src/tokens/components/dark/tooltip.ts +12 -0
- package/src/tokens/components/dark/top-navigation.ts +0 -8
- package/src/tokens/components/light/accordion.ts +0 -2
- package/src/tokens/components/light/alert.ts +0 -16
- package/src/tokens/components/light/avatar.ts +19 -0
- package/src/tokens/components/light/badge.ts +7 -34
- package/src/tokens/components/light/banner.ts +2 -11
- package/src/tokens/components/light/bottom-navigation.ts +0 -5
- package/src/tokens/components/light/bottom-sheet.ts +1 -2
- package/src/tokens/components/light/breadcrumb.ts +0 -1
- package/src/tokens/components/light/button.ts +0 -86
- package/src/tokens/components/light/card.ts +0 -28
- package/src/tokens/components/light/carousel-control.ts +0 -8
- package/src/tokens/components/light/checkbox.ts +0 -9
- package/src/tokens/components/light/date-picker.ts +0 -12
- package/src/tokens/components/light/description-list.ts +20 -0
- package/src/tokens/components/light/dialog.ts +0 -1
- package/src/tokens/components/light/divider.ts +4 -1
- package/src/tokens/components/light/expandable-card.ts +11 -0
- package/src/tokens/components/light/icon-button.ts +5 -5
- package/src/tokens/components/light/icon-container.ts +0 -17
- package/src/tokens/components/light/index.ts +10 -4
- package/src/tokens/components/light/indicator-icon-button.ts +11 -0
- package/src/tokens/components/light/input.ts +1 -9
- package/src/tokens/components/light/link.ts +2 -2
- package/src/tokens/components/light/list.ts +20 -20
- package/src/tokens/components/light/menu.ts +0 -12
- package/src/tokens/components/light/modal.ts +0 -1
- package/src/tokens/components/light/navigation.ts +1 -6
- package/src/tokens/components/light/pagination.ts +12 -0
- package/src/tokens/components/light/parts.ts +11 -1
- package/src/tokens/components/light/pill.ts +0 -10
- package/src/tokens/components/light/progress-stepper.ts +0 -8
- package/src/tokens/components/light/radio.ts +0 -7
- package/src/tokens/components/light/{focus.ts → section-header.ts} +4 -2
- package/src/tokens/components/light/segmented-control.ts +0 -8
- package/src/tokens/components/light/select.ts +0 -10
- package/src/tokens/components/light/switch.ts +1 -11
- package/src/tokens/components/light/table.ts +23 -0
- package/src/tokens/components/light/tabs.ts +24 -0
- package/src/tokens/components/light/toast.ts +10 -0
- package/src/tokens/components/light/toggle-button.ts +0 -11
- package/src/tokens/components/light/tooltip.ts +12 -0
- package/src/tokens/components/light/top-navigation.ts +0 -8
- package/src/tokens/index.ts +1 -0
- package/src/tokens/semantic-dark.ts +240 -13
- package/src/tokens/semantic-light.ts +240 -13
- package/src/tokens/semantic.ts +9 -0
- package/src/types/values.ts +28 -6
- package/src/utils/coloursAsArray.ts +44 -2
- package/src/utils/getFlattenedColorValue.ts +1 -1
- package/src/utils/hexWithOpacity.ts +19 -0
- package/src/utils/index.ts +2 -1
- package/src/utils/styleUtils.ts +39 -1
- package/src/vite-env.d.ts +5 -0
- package/build/components/Accordion/AccordionHeading/AccordionHeading.d.ts +0 -6
- package/build/components/Accordion/AccordionHeading/AccordionHeading.js +0 -16
- package/build/components/Accordion/AccordionHeading/AccordionHeading.props.d.ts +0 -14
- package/build/components/Accordion/AccordionHeading/AccordionHeadingHelperText.d.ts +0 -6
- package/build/components/Accordion/AccordionHeading/AccordionHeadingHelperText.js +0 -13
- package/build/components/Accordion/AccordionHeading/AccordionHeadingTextContent.d.ts +0 -6
- package/build/components/Accordion/AccordionHeading/AccordionHeadingTextContent.js +0 -14
- package/build/components/Accordion/AccordionHeading/AccordionHeadingTitle.d.ts +0 -6
- package/build/components/Accordion/AccordionHeading/AccordionHeadingTitle.js +0 -7
- package/build/components/Accordion/AccordionHeading/index.d.ts +0 -4
- package/build/components/Accordion/AccordionHeading/index.js +0 -4
- package/build/components/List/ListHeading/ListHeading.d.ts +0 -6
- package/build/components/List/ListHeading/ListHeading.js +0 -20
- package/build/components/List/ListHeading/ListHeadingHelperText.d.ts +0 -6
- package/build/components/List/ListHeading/ListHeadingTitle.d.ts +0 -6
- package/build/components/List/ListHeading/ListHeadingTitle.js +0 -7
- package/build/components/List/ListHeading/index.d.ts +0 -4
- package/build/components/List/ListHeading/index.js +0 -4
- package/build/tokens/components/dark/footer.d.ts +0 -12
- package/build/tokens/components/dark/footer.js +0 -11
- package/build/tokens/components/dark/icon.d.ts +0 -15
- package/build/tokens/components/dark/icon.js +0 -14
- package/build/tokens/components/dark/text.d.ts +0 -11
- package/build/tokens/components/dark/text.js +0 -10
- package/build/tokens/components/light/footer.d.ts +0 -12
- package/build/tokens/components/light/footer.js +0 -11
- package/build/tokens/components/light/icon.d.ts +0 -15
- package/build/tokens/components/light/icon.js +0 -14
- package/build/tokens/components/light/text.d.ts +0 -11
- package/build/tokens/components/light/text.js +0 -10
- package/src/components/Accordion/AccordionHeading/AccordionHeading.props.ts +0 -19
- package/src/components/Accordion/AccordionHeading/AccordionHeading.tsx +0 -38
- package/src/components/Accordion/AccordionHeading/AccordionHeadingHelperText.tsx +0 -22
- package/src/components/Accordion/AccordionHeading/AccordionHeadingTextContent.tsx +0 -21
- package/src/components/Accordion/AccordionHeading/AccordionHeadingTitle.tsx +0 -14
- package/src/components/Accordion/AccordionHeading/index.ts +0 -4
- package/src/components/List/ListHeading/ListHeadingHelperText.tsx +0 -21
- package/src/components/List/ListHeading/ListHeadingTitle.tsx +0 -14
- package/src/components/List/ListHeading/index.ts +0 -4
- package/src/tokens/components/dark/icon.ts +0 -15
- package/src/tokens/components/dark/text.ts +0 -11
- package/src/tokens/components/light/icon.ts +0 -15
- package/src/tokens/components/light/text.ts +0 -11
- /package/build/components/{Accordion/AccordionHeading/AccordionHeading.props.js → Modal/Modal.props.js} +0 -0
- /package/build/components/{List/ListHeading/ListHeading.props.js → SectionHeader/SectionHeader.props.js} +0 -0
|
@@ -125,8 +125,8 @@ ListItemRoot.displayName = 'ListItemRoot';
|
|
|
125
125
|
|
|
126
126
|
const styles = StyleSheet.create(theme => ({
|
|
127
127
|
container: {
|
|
128
|
-
paddingVertical: theme.components.list.item.padding,
|
|
129
|
-
paddingHorizontal: theme.components.list.item.padding,
|
|
128
|
+
paddingVertical: theme.components.list.item.functional.padding,
|
|
129
|
+
paddingHorizontal: theme.components.list.item.functional.padding,
|
|
130
130
|
flexDirection: 'row',
|
|
131
131
|
gap: theme.components.list.item.gap,
|
|
132
132
|
variants: {
|
|
@@ -143,10 +143,10 @@ const styles = StyleSheet.create(theme => ({
|
|
|
143
143
|
},
|
|
144
144
|
variant: {
|
|
145
145
|
subtle: {
|
|
146
|
-
borderTopColor: theme.
|
|
146
|
+
borderTopColor: theme.color.border.subtle,
|
|
147
147
|
},
|
|
148
148
|
emphasis: {
|
|
149
|
-
borderTopColor: theme.
|
|
149
|
+
borderTopColor: theme.color.border.strong,
|
|
150
150
|
},
|
|
151
151
|
},
|
|
152
152
|
disabled: {
|
|
@@ -160,7 +160,16 @@ const styles = StyleSheet.create(theme => ({
|
|
|
160
160
|
},
|
|
161
161
|
},
|
|
162
162
|
showPressed: {
|
|
163
|
-
true: {
|
|
163
|
+
true: {
|
|
164
|
+
_web: {
|
|
165
|
+
_hover: {
|
|
166
|
+
backgroundColor: theme.color.interactive.neutral.surface.subtle.hover,
|
|
167
|
+
},
|
|
168
|
+
_active: {
|
|
169
|
+
backgroundColor: theme.color.interactive.neutral.surface.subtle.active,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
164
173
|
false: {
|
|
165
174
|
cursor: 'auto',
|
|
166
175
|
},
|
|
@@ -183,7 +192,7 @@ const styles = StyleSheet.create(theme => ({
|
|
|
183
192
|
showPressed: true,
|
|
184
193
|
active: true,
|
|
185
194
|
styles: {
|
|
186
|
-
backgroundColor: theme.
|
|
195
|
+
backgroundColor: theme.color.interactive.neutral.surface.subtle.active,
|
|
187
196
|
},
|
|
188
197
|
},
|
|
189
198
|
],
|
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
import { Canvas, Controls, Meta, Story } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import { BodyText, BottomSheetModal, Box, Button, Center, Heading, Modal } from '../../';
|
|
3
|
+
import modalAndroidVideo from '../../../docs/assets/modal-android.mp4';
|
|
4
|
+
import modaliOSVideo from '../../../docs/assets/modal-ios.mp4';
|
|
5
|
+
import { BackToTopButton, UsageWrap, ViewFigmaButton } from '../../../docs/components';
|
|
6
|
+
import * as Stories from './Modal.stories';
|
|
7
|
+
|
|
8
|
+
<Meta title="Components / Modal" />
|
|
9
|
+
|
|
10
|
+
<ViewFigmaButton url="https://www.figma.com/design/6NKZXZhFSExXrcbBgc6zTR/Hearth-Components---Tokens?node-id=6300-2825&t=JmfcCbdIvO3jcjc3-4" />
|
|
11
|
+
|
|
12
|
+
<BackToTopButton />
|
|
13
|
+
|
|
14
|
+
# Modal
|
|
15
|
+
|
|
16
|
+
The `Modal` component provides a versatile dialog interface that slides up from the bottom of the screen. It's built on top of the `BottomSheetModal` component and includes pre-configured layouts for common modal patterns including headers, content areas, and action buttons.
|
|
17
|
+
|
|
18
|
+
The Modal component is ideal for displaying important information, collecting user input, or presenting choices that require user attention without navigating away from the current screen.
|
|
19
|
+
|
|
20
|
+
- [Playground](#playground)
|
|
21
|
+
- [Usage](#usage)
|
|
22
|
+
- [Props](#props)
|
|
23
|
+
- [Features](#features)
|
|
24
|
+
- [Accessibility](#accessibility)
|
|
25
|
+
- [Examples](#examples)
|
|
26
|
+
- [Basic Modal](#basic-modal)
|
|
27
|
+
- [Modal with Image](#modal-with-image)
|
|
28
|
+
- [Modal with Custom Content](#modal-with-custom-content)
|
|
29
|
+
- [Loading State](#loading-state)
|
|
30
|
+
- [Without Close Button](#without-close-button)
|
|
31
|
+
- [Single Action Modal](#single-action-modal)
|
|
32
|
+
- [Fullscreen Modal (Usage with navigation modal)](#fullscreen-modal-usage-with-navigation-modal)
|
|
33
|
+
- [Integration Notes](#integration-notes)
|
|
34
|
+
- [External Resources](#external-resources)
|
|
35
|
+
|
|
36
|
+
## Playground
|
|
37
|
+
|
|
38
|
+
<Canvas of={Stories.Playground} />
|
|
39
|
+
|
|
40
|
+
<Controls of={Stories.Playground} />
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
### Basic Usage
|
|
45
|
+
|
|
46
|
+
<UsageWrap>
|
|
47
|
+
<Center>
|
|
48
|
+
<Button onPress={() => {}}>Open Modal</Button>
|
|
49
|
+
</Center>
|
|
50
|
+
</UsageWrap>
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { useRef, useCallback } from 'react';
|
|
54
|
+
import { Modal, Button, BottomSheetModal } from '@utilitywarehouse/hearth-react-native';
|
|
55
|
+
|
|
56
|
+
const MyComponent = () => {
|
|
57
|
+
const modalRef = useRef<BottomSheetModal>(null);
|
|
58
|
+
|
|
59
|
+
const handleOpenModal = useCallback(() => {
|
|
60
|
+
modalRef.current?.present();
|
|
61
|
+
}, []);
|
|
62
|
+
|
|
63
|
+
const handleCloseModal = useCallback(() => {
|
|
64
|
+
modalRef.current?.dismiss();
|
|
65
|
+
}, []);
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<>
|
|
69
|
+
<Button onPress={handleOpenModal}>Open Modal</Button>
|
|
70
|
+
|
|
71
|
+
<Modal
|
|
72
|
+
ref={modalRef}
|
|
73
|
+
heading="Confirm Action"
|
|
74
|
+
description="Are you sure you want to proceed with this action?"
|
|
75
|
+
primaryButtonText="Confirm"
|
|
76
|
+
secondaryButtonText="Cancel"
|
|
77
|
+
onPressPrimaryButton={handleCloseModal}
|
|
78
|
+
onPressSecondaryButton={handleCloseModal}
|
|
79
|
+
/>
|
|
80
|
+
</>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Props
|
|
86
|
+
|
|
87
|
+
The Modal component extends the `BottomSheetModal` component and accepts all of its props, plus the following additional props:
|
|
88
|
+
|
|
89
|
+
| Property | Type | Description | Default |
|
|
90
|
+
| ----------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------- |
|
|
91
|
+
| `heading` | `string` | The heading text displayed at the top of the modal | - |
|
|
92
|
+
| `description` | `string` | The description text displayed below the heading | - |
|
|
93
|
+
| `showCloseButton` | `boolean` | Whether to show the close button in the top-right corner | `true` |
|
|
94
|
+
| `primaryButtonText` | `string` | Text for the primary action button | - |
|
|
95
|
+
| `secondaryButtonText` | `string` | Text for the secondary action button | - |
|
|
96
|
+
| `onPressPrimaryButton` | `() => void` | Callback function called when the primary button is pressed | - |
|
|
97
|
+
| `onPressSecondaryButton` | `() => void` | Callback function called when the secondary button is pressed | - |
|
|
98
|
+
| `onPressCloseButton` | `() => void` | Callback function called when the close button is pressed | - |
|
|
99
|
+
| `closeOnPrimaryButtonPress` | `boolean` | Whether to automatically close the modal when the primary button is pressed | `true` |
|
|
100
|
+
| `closeOnSecondaryButtonPress` | `boolean` | Whether to automatically close the modal when the secondary button is pressed | `true` |
|
|
101
|
+
| `loading` | `boolean` | Whether to show a loading state with spinner | `false` |
|
|
102
|
+
| `image` | `ImageProps` | Image to display in the modal (shows as centered content with text below) | - |
|
|
103
|
+
| `children` | `ReactNode` | Custom content to display in the modal body | - |
|
|
104
|
+
| `primaryButtonProps` | `Omit<ButtonWithoutChildrenProps, 'children'>` | Additional props to pass to the primary button (colorScheme defaults to 'highlight', variant to 'solid') | - |
|
|
105
|
+
| `secondaryButtonProps` | `Omit<ButtonWithoutChildrenProps, 'children'>` | Additional props to pass to the secondary button (colorScheme defaults to 'functional', variant to 'outline') | - |
|
|
106
|
+
| `closeButtonProps` | `Omit<UnstyledIconButtonProps, 'children'>` | Additional props to pass to the close button | - |
|
|
107
|
+
| `fullscreen` | `boolean` | Whether the modal should take up the full screen height (useful for navigation modals) | `false` |
|
|
108
|
+
|
|
109
|
+
## Features
|
|
110
|
+
|
|
111
|
+
### Automatic Layout Management
|
|
112
|
+
|
|
113
|
+
- **Header Section**: Displays heading, description, and close button in a flexible layout
|
|
114
|
+
- **Content Area**: Supports custom children or image content with automatic centering
|
|
115
|
+
- **Footer Section**: Action buttons with consistent spacing and styling
|
|
116
|
+
- **Loading State**: Built-in spinner and loading text with proper layout
|
|
117
|
+
|
|
118
|
+
### Responsive Behavior
|
|
119
|
+
|
|
120
|
+
- **Dynamic Sizing**: Automatically adjusts height based on content when `enableDynamicSizing` is enabled
|
|
121
|
+
- **Image Modals**: Automatically sets snapPoints to `['90%']` when an image is provided
|
|
122
|
+
- **Handle Management**: Automatically hides the drag handle during loading states
|
|
123
|
+
|
|
124
|
+
### Accessibility & UX
|
|
125
|
+
|
|
126
|
+
- **Auto-close**: Configurable auto-close behavior for action buttons
|
|
127
|
+
- **Backdrop**: Inherits backdrop behavior from BottomSheetModal
|
|
128
|
+
- **Scrollable Content**: Uses BottomSheetScrollView for content that may overflow
|
|
129
|
+
- **Screen Reader Support**: Automatically announces modal state changes and manages focus
|
|
130
|
+
- **Focus Management**: Sets accessibility focus to modal content when opened
|
|
131
|
+
- **Keyboard Navigation**: Full keyboard support for interactive elements
|
|
132
|
+
- **ARIA Labels**: Proper labeling for all interactive components
|
|
133
|
+
- **Loading States**: Accessible loading indicators with appropriate announcements
|
|
134
|
+
|
|
135
|
+
## Accessibility
|
|
136
|
+
|
|
137
|
+
The Modal component is built with comprehensive accessibility support to ensure a great experience for all users, including those using screen readers and other assistive technologies.
|
|
138
|
+
|
|
139
|
+
### Screen Reader Support
|
|
140
|
+
|
|
141
|
+
- **Automatic Announcements**: When the modal opens, screen readers automatically announce "Modal opened"
|
|
142
|
+
- **Content Focus**: Focus is automatically set to the modal content area for immediate access
|
|
143
|
+
- **Loading State Announcements**: Loading states are properly announced with "Loading..." text
|
|
144
|
+
- **Button Labels**: All interactive elements have descriptive accessibility labels
|
|
145
|
+
|
|
146
|
+
### Focus Management
|
|
147
|
+
|
|
148
|
+
The Modal component automatically manages focus to provide a seamless experience:
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
// Focus is automatically set when modal opens
|
|
152
|
+
const MyModal = () => {
|
|
153
|
+
const modalRef = useRef<BottomSheetModal>(null);
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<Modal
|
|
157
|
+
ref={modalRef}
|
|
158
|
+
heading="Accessible Modal" // Automatically becomes accessible heading
|
|
159
|
+
description="This description is accessible to screen readers"
|
|
160
|
+
primaryButtonText="Confirm" // Button is automatically labeled
|
|
161
|
+
secondaryButtonText="Cancel"
|
|
162
|
+
// Focus management is handled automatically
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Custom Accessibility Labels
|
|
169
|
+
|
|
170
|
+
You can enhance accessibility by providing custom labels for buttons and close actions:
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
<Modal
|
|
174
|
+
ref={modalRef}
|
|
175
|
+
heading="Delete Item"
|
|
176
|
+
description="This action cannot be undone"
|
|
177
|
+
primaryButtonText="Delete"
|
|
178
|
+
secondaryButtonText="Cancel"
|
|
179
|
+
// Custom accessibility labels
|
|
180
|
+
closeButtonProps={{
|
|
181
|
+
accessibilityLabel: 'Close delete confirmation dialog',
|
|
182
|
+
}}
|
|
183
|
+
primaryButtonProps={{
|
|
184
|
+
accessibilityLabel: 'Confirm deletion of item',
|
|
185
|
+
}}
|
|
186
|
+
secondaryButtonProps={{
|
|
187
|
+
accessibilityLabel: 'Cancel deletion and return to previous screen',
|
|
188
|
+
}}
|
|
189
|
+
/>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Loading State Accessibility
|
|
193
|
+
|
|
194
|
+
Loading states are fully accessible with proper announcements:
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
<Modal
|
|
198
|
+
ref={modalRef}
|
|
199
|
+
heading="Processing Payment"
|
|
200
|
+
description="Please wait while we process your payment"
|
|
201
|
+
loading={isProcessing}
|
|
202
|
+
// Loading spinner and "Loading..." text are automatically accessible
|
|
203
|
+
primaryButtonText="Process Payment"
|
|
204
|
+
onPressPrimaryButton={handlePayment}
|
|
205
|
+
/>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Best Practices
|
|
209
|
+
|
|
210
|
+
1. **Descriptive Headings**: Use clear, descriptive headings that explain the modal's purpose
|
|
211
|
+
2. **Actionable Button Text**: Use specific button text that describes the action (e.g., "Save Changes" vs "OK")
|
|
212
|
+
3. **Meaningful Descriptions**: Provide context in the description to help users understand the consequences
|
|
213
|
+
4. **Custom Labels**: Add custom accessibility labels for complex interactions
|
|
214
|
+
5. **Loading Feedback**: Always provide accessible feedback during loading states
|
|
215
|
+
|
|
216
|
+
### Testing Accessibility
|
|
217
|
+
|
|
218
|
+
To test accessibility in your Modal implementation:
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
import { AccessibilityInfo } from 'react-native';
|
|
222
|
+
|
|
223
|
+
const TestableModal = () => {
|
|
224
|
+
const modalRef = useRef<BottomSheetModal>(null);
|
|
225
|
+
|
|
226
|
+
const handleOpenModal = () => {
|
|
227
|
+
modalRef.current?.present();
|
|
228
|
+
|
|
229
|
+
// Test: Verify screen reader announcement
|
|
230
|
+
AccessibilityInfo.announceForAccessibility('Opening confirmation dialog');
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
<Modal
|
|
235
|
+
ref={modalRef}
|
|
236
|
+
heading="Test Modal"
|
|
237
|
+
description="This modal demonstrates accessibility features"
|
|
238
|
+
primaryButtonText="Test Action"
|
|
239
|
+
// Verify these labels work with your screen reader
|
|
240
|
+
closeButtonProps={{
|
|
241
|
+
accessibilityLabel: 'Close test modal',
|
|
242
|
+
accessibilityHint: 'Dismisses the modal without saving changes',
|
|
243
|
+
}}
|
|
244
|
+
/>
|
|
245
|
+
);
|
|
246
|
+
};
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Platform Considerations
|
|
250
|
+
|
|
251
|
+
The Modal component handles platform-specific accessibility differences:
|
|
252
|
+
|
|
253
|
+
- **iOS**: Uses VoiceOver optimizations for focus management
|
|
254
|
+
- **Android**: Implements TalkBack-specific accessibility patterns
|
|
255
|
+
- **Cross-platform**: Consistent behavior across both platforms
|
|
256
|
+
|
|
257
|
+
## Examples
|
|
258
|
+
|
|
259
|
+
### Basic Modal
|
|
260
|
+
|
|
261
|
+
<Canvas of={Stories.Playground} />
|
|
262
|
+
|
|
263
|
+
### Modal with Image
|
|
264
|
+
|
|
265
|
+
Use the `image` prop to display an image-centric modal with centered content:
|
|
266
|
+
|
|
267
|
+
<Canvas of={Stories.WithImage} />
|
|
268
|
+
|
|
269
|
+
```tsx
|
|
270
|
+
const ImageModal = () => {
|
|
271
|
+
const modalRef = useRef<BottomSheetModal>(null);
|
|
272
|
+
|
|
273
|
+
return (
|
|
274
|
+
<>
|
|
275
|
+
<Button onPress={() => modalRef.current?.present()}>Show Image Modal</Button>
|
|
276
|
+
|
|
277
|
+
<Modal
|
|
278
|
+
ref={modalRef}
|
|
279
|
+
heading="Welcome!"
|
|
280
|
+
description="Thanks for joining our community"
|
|
281
|
+
primaryButtonText="Get Started"
|
|
282
|
+
secondaryButtonText="Maybe Later"
|
|
283
|
+
image={{
|
|
284
|
+
source: require('./path/to/image.png'),
|
|
285
|
+
resizeMode: 'contain',
|
|
286
|
+
}}
|
|
287
|
+
onPressPrimaryButton={() => modalRef.current?.dismiss()}
|
|
288
|
+
onPressSecondaryButton={() => modalRef.current?.dismiss()}
|
|
289
|
+
/>
|
|
290
|
+
</>
|
|
291
|
+
);
|
|
292
|
+
};
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Modal with Custom Content
|
|
296
|
+
|
|
297
|
+
Add custom content between the header and footer sections:
|
|
298
|
+
|
|
299
|
+
<Canvas of={Stories.WithCustomContent} />
|
|
300
|
+
|
|
301
|
+
```tsx
|
|
302
|
+
const CustomContentModal = () => {
|
|
303
|
+
const modalRef = useRef<BottomSheetModal>(null);
|
|
304
|
+
|
|
305
|
+
return (
|
|
306
|
+
<>
|
|
307
|
+
<Button onPress={() => modalRef.current?.present()}>Show Custom Modal</Button>
|
|
308
|
+
|
|
309
|
+
<Modal
|
|
310
|
+
ref={modalRef}
|
|
311
|
+
heading="Settings"
|
|
312
|
+
description="Configure your preferences"
|
|
313
|
+
primaryButtonText="Save"
|
|
314
|
+
secondaryButtonText="Cancel"
|
|
315
|
+
onPressPrimaryButton={() => modalRef.current?.dismiss()}
|
|
316
|
+
onPressSecondaryButton={() => modalRef.current?.dismiss()}
|
|
317
|
+
>
|
|
318
|
+
<Box gap="200">
|
|
319
|
+
<BodyText>Enable notifications</BodyText>
|
|
320
|
+
<BodyText>Allow location access</BodyText>
|
|
321
|
+
<BodyText>Share usage data</BodyText>
|
|
322
|
+
</Box>
|
|
323
|
+
</Modal>
|
|
324
|
+
</>
|
|
325
|
+
);
|
|
326
|
+
};
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Loading State
|
|
330
|
+
|
|
331
|
+
Show a loading spinner while processing:
|
|
332
|
+
|
|
333
|
+
<Canvas of={Stories.Loading} />
|
|
334
|
+
|
|
335
|
+
```tsx
|
|
336
|
+
const LoadingModal = () => {
|
|
337
|
+
const modalRef = useRef<BottomSheetModal>(null);
|
|
338
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
339
|
+
|
|
340
|
+
const handleSubmit = async () => {
|
|
341
|
+
setIsLoading(true);
|
|
342
|
+
// Simulate API call
|
|
343
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
344
|
+
setIsLoading(false);
|
|
345
|
+
modalRef.current?.dismiss();
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
return (
|
|
349
|
+
<>
|
|
350
|
+
<Button onPress={() => modalRef.current?.present()}>Show Loading Modal</Button>
|
|
351
|
+
|
|
352
|
+
<Modal
|
|
353
|
+
ref={modalRef}
|
|
354
|
+
heading="Processing"
|
|
355
|
+
description="Please wait while we process your request"
|
|
356
|
+
loading={isLoading}
|
|
357
|
+
primaryButtonText="Submit"
|
|
358
|
+
onPressPrimaryButton={handleSubmit}
|
|
359
|
+
closeOnPrimaryButtonPress={false}
|
|
360
|
+
/>
|
|
361
|
+
</>
|
|
362
|
+
);
|
|
363
|
+
};
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Without Close Button
|
|
367
|
+
|
|
368
|
+
Remove the close button for critical actions:
|
|
369
|
+
|
|
370
|
+
```tsx
|
|
371
|
+
const CriticalModal = () => {
|
|
372
|
+
const modalRef = useRef<BottomSheetModal>(null);
|
|
373
|
+
|
|
374
|
+
return (
|
|
375
|
+
<>
|
|
376
|
+
<Button onPress={() => modalRef.current?.present()}>Show Critical Modal</Button>
|
|
377
|
+
|
|
378
|
+
<Modal
|
|
379
|
+
ref={modalRef}
|
|
380
|
+
heading="Critical Action Required"
|
|
381
|
+
description="This action cannot be undone"
|
|
382
|
+
showCloseButton={false}
|
|
383
|
+
primaryButtonText="Continue"
|
|
384
|
+
secondaryButtonText="Cancel"
|
|
385
|
+
onPressPrimaryButton={() => modalRef.current?.dismiss()}
|
|
386
|
+
onPressSecondaryButton={() => modalRef.current?.dismiss()}
|
|
387
|
+
/>
|
|
388
|
+
</>
|
|
389
|
+
);
|
|
390
|
+
};
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Single Action Modal
|
|
394
|
+
|
|
395
|
+
Create a modal with only one action button:
|
|
396
|
+
|
|
397
|
+
```tsx
|
|
398
|
+
const AlertModal = () => {
|
|
399
|
+
const modalRef = useRef<BottomSheetModal>(null);
|
|
400
|
+
|
|
401
|
+
return (
|
|
402
|
+
<>
|
|
403
|
+
<Button onPress={() => modalRef.current?.present()}>Show Alert</Button>
|
|
404
|
+
|
|
405
|
+
<Modal
|
|
406
|
+
ref={modalRef}
|
|
407
|
+
heading="Success!"
|
|
408
|
+
description="Your action was completed successfully"
|
|
409
|
+
primaryButtonText="OK"
|
|
410
|
+
onPressPrimaryButton={() => modalRef.current?.dismiss()}
|
|
411
|
+
/>
|
|
412
|
+
</>
|
|
413
|
+
);
|
|
414
|
+
};
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Fullscreen Modal (Usage with navigation modal)
|
|
418
|
+
|
|
419
|
+
When using the Modal component in a navigation context, you can set it to fullscreen mode, this will make it behave like a standard modal screen.
|
|
420
|
+
Here's an example of how to implement this with custom close animations for Android:
|
|
421
|
+
|
|
422
|
+
```tsx
|
|
423
|
+
import { useNavigation } from 'react-navigation/native';
|
|
424
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
425
|
+
import { Platform, StyleSheet, View } from 'react-native';
|
|
426
|
+
|
|
427
|
+
import { BodyText, Heading, InlineLink, Modal } from '@utilitywarehouse/hearth-react-native';
|
|
428
|
+
|
|
429
|
+
export default function ModalScreen() {
|
|
430
|
+
const modalRef = useRef<Modal>(null);
|
|
431
|
+
const navigation = useNavigation();
|
|
432
|
+
const isClosingRef = useRef(false);
|
|
433
|
+
|
|
434
|
+
const handleClose = useCallback(() => {
|
|
435
|
+
if (Platform.OS === 'ios') {
|
|
436
|
+
navigation.goBack();
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
if (isClosingRef.current) return;
|
|
440
|
+
|
|
441
|
+
isClosingRef.current = true;
|
|
442
|
+
// Trigger our custom animation first
|
|
443
|
+
modalRef.current?.triggerCloseAnimation?.();
|
|
444
|
+
|
|
445
|
+
// Delay the actual navigation to allow our animation to play
|
|
446
|
+
setTimeout(() => {
|
|
447
|
+
navigation.goBack();
|
|
448
|
+
}, 100); // Match Modal animation duration
|
|
449
|
+
}, [navigation]);
|
|
450
|
+
|
|
451
|
+
useEffect(() => {
|
|
452
|
+
if (Platform.OS === 'android') {
|
|
453
|
+
const unsubscribe = navigation.addListener('beforeRemove', e => {
|
|
454
|
+
if (!isClosingRef.current) {
|
|
455
|
+
// Prevent default behavior
|
|
456
|
+
e.preventDefault();
|
|
457
|
+
handleClose();
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
return unsubscribe;
|
|
462
|
+
}
|
|
463
|
+
}, [navigation, handleClose]);
|
|
464
|
+
|
|
465
|
+
return (
|
|
466
|
+
<Modal
|
|
467
|
+
ref={modalRef}
|
|
468
|
+
fullscreen
|
|
469
|
+
onPressCloseButton={handleClose}
|
|
470
|
+
primaryButtonText="Action"
|
|
471
|
+
onPressPrimaryButton={handleClose}
|
|
472
|
+
secondaryButtonText="Cancel"
|
|
473
|
+
onPressSecondaryButton={handleClose}
|
|
474
|
+
>
|
|
475
|
+
<View style={styles.container}>
|
|
476
|
+
<Heading size="xl">This is a modal</Heading>
|
|
477
|
+
<BodyText>
|
|
478
|
+
<InlineLink onPress={handleClose} style={styles.link}>
|
|
479
|
+
Go to home screen
|
|
480
|
+
</InlineLink>
|
|
481
|
+
</BodyText>
|
|
482
|
+
</View>
|
|
483
|
+
</Modal>
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const styles = StyleSheet.create({
|
|
488
|
+
container: {
|
|
489
|
+
flex: 1,
|
|
490
|
+
alignItems: 'center',
|
|
491
|
+
justifyContent: 'center',
|
|
492
|
+
padding: 20,
|
|
493
|
+
},
|
|
494
|
+
link: {
|
|
495
|
+
marginTop: 15,
|
|
496
|
+
paddingVertical: 15,
|
|
497
|
+
},
|
|
498
|
+
});
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
The above example demonstrates how to create a fullscreen modal that integrates with navigation.
|
|
502
|
+
It includes custom close animations for Android to enhance the user experience. See the videos below for platform-specific behavior:
|
|
503
|
+
|
|
504
|
+
| ios | android |
|
|
505
|
+
| ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
|
|
506
|
+
| <video src={modaliOSVideo} width={300} height="auto" controls loop autoPlay /> | <video src={modalAndroidVideo} width={300} height="auto" controls loop autoPlay /> |
|
|
507
|
+
|
|
508
|
+
## Integration Notes
|
|
509
|
+
|
|
510
|
+
### BottomSheetModalProvider
|
|
511
|
+
|
|
512
|
+
When using the Modal component, ensure your app is wrapped with `BottomSheetModalProvider`:
|
|
513
|
+
|
|
514
|
+
```tsx
|
|
515
|
+
import { BottomSheetModalProvider } from '@utilitywarehouse/hearth-react-native';
|
|
516
|
+
|
|
517
|
+
const App = () => {
|
|
518
|
+
return <BottomSheetModalProvider>{/* Your app content */}</BottomSheetModalProvider>;
|
|
519
|
+
};
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### Ref Usage
|
|
523
|
+
|
|
524
|
+
The Modal component forwards its ref to the underlying `BottomSheetModal`, giving you access to methods like:
|
|
525
|
+
|
|
526
|
+
- `present()` - Opens the modal
|
|
527
|
+
- `dismiss()` - Closes the modal
|
|
528
|
+
- `close()` - Alternative to dismiss
|
|
529
|
+
- `snapToIndex(index)` - Snap to a specific index
|
|
530
|
+
- `snapToPosition(position)` - Snap to a specific position
|
|
531
|
+
|
|
532
|
+
```tsx
|
|
533
|
+
const modalRef = useRef<BottomSheetModal>(null);
|
|
534
|
+
|
|
535
|
+
// Open modal
|
|
536
|
+
modalRef.current?.present();
|
|
537
|
+
|
|
538
|
+
// Close modal
|
|
539
|
+
modalRef.current?.dismiss();
|
|
540
|
+
|
|
541
|
+
// Snap to specific position
|
|
542
|
+
modalRef.current?.snapToIndex(1);
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
## External Resources
|
|
546
|
+
|
|
547
|
+
This component is built on top of [@gorhom/bottom-sheet](https://gorhom.github.io/react-native-bottom-sheet/) (v5). For more information about the underlying BottomSheet functionality, please refer to the [BottomSheet documentation](./BottomSheet.docs.mdx) and the [official documentation](https://gorhom.dev/react-native-bottom-sheet/).
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ImageProps, ViewProps } from 'react-native';
|
|
2
|
+
import { BottomSheetProps } from '../BottomSheet';
|
|
3
|
+
import { ButtonWithoutChildrenProps } from '../Button/Button.props';
|
|
4
|
+
import { UnstyledIconButtonProps } from '../UnstyledIconButton';
|
|
5
|
+
|
|
6
|
+
interface ModalProps extends Omit<BottomSheetProps, 'children'> {
|
|
7
|
+
loading?: boolean;
|
|
8
|
+
image?: ImageProps;
|
|
9
|
+
showCloseButton?: boolean;
|
|
10
|
+
heading?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
fullscreen?: boolean;
|
|
13
|
+
children?: ViewProps['children'];
|
|
14
|
+
onPressPrimaryButton?: () => void;
|
|
15
|
+
primaryButtonText?: string;
|
|
16
|
+
onPressSecondaryButton?: () => void;
|
|
17
|
+
closeOnPrimaryButtonPress?: boolean;
|
|
18
|
+
secondaryButtonText?: string;
|
|
19
|
+
onPressCloseButton?: () => void;
|
|
20
|
+
closeOnSecondaryButtonPress?: boolean;
|
|
21
|
+
primaryButtonProps?: Omit<ButtonWithoutChildrenProps, 'children'>;
|
|
22
|
+
secondaryButtonProps?: Omit<ButtonWithoutChildrenProps, 'children'>;
|
|
23
|
+
closeButtonProps?: Omit<UnstyledIconButtonProps, 'children'>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default ModalProps;
|