orn-ui 0.2.10 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +66 -51
- package/README.md +3 -7
- package/lib/commonjs/atoms/Avatar.js +77 -5
- package/lib/commonjs/atoms/Avatar.js.map +1 -1
- package/lib/commonjs/atoms/Badge.js +17 -8
- package/lib/commonjs/atoms/Badge.js.map +1 -1
- package/lib/commonjs/atoms/Button.js +108 -39
- package/lib/commonjs/atoms/Button.js.map +1 -1
- package/lib/commonjs/atoms/Card.js +24 -2
- package/lib/commonjs/atoms/Card.js.map +1 -1
- package/lib/commonjs/atoms/Checkbox.js +41 -10
- package/lib/commonjs/atoms/Checkbox.js.map +1 -1
- package/lib/commonjs/atoms/Divider.js +30 -5
- package/lib/commonjs/atoms/Divider.js.map +1 -1
- package/lib/commonjs/atoms/EmptyState.js +58 -20
- package/lib/commonjs/atoms/EmptyState.js.map +1 -1
- package/lib/commonjs/atoms/Fab.js +32 -12
- package/lib/commonjs/atoms/Fab.js.map +1 -1
- package/lib/commonjs/atoms/Gradient.js +102 -36
- package/lib/commonjs/atoms/Gradient.js.map +1 -1
- package/lib/commonjs/atoms/IconButton.js +25 -4
- package/lib/commonjs/atoms/IconButton.js.map +1 -1
- package/lib/commonjs/atoms/Image.js +61 -25
- package/lib/commonjs/atoms/Image.js.map +1 -1
- package/lib/commonjs/atoms/Input.js +105 -17
- package/lib/commonjs/atoms/Input.js.map +1 -1
- package/lib/commonjs/atoms/KeyValueRow.js +37 -9
- package/lib/commonjs/atoms/KeyValueRow.js.map +1 -1
- package/lib/commonjs/atoms/PressableScale.js +25 -5
- package/lib/commonjs/atoms/PressableScale.js.map +1 -1
- package/lib/commonjs/atoms/ShinyText.js +29 -29
- package/lib/commonjs/atoms/Skeleton.js +28 -13
- package/lib/commonjs/atoms/Skeleton.js.map +1 -1
- package/lib/commonjs/atoms/Spinner.js +81 -22
- package/lib/commonjs/atoms/Spinner.js.map +1 -1
- package/lib/commonjs/atoms/Text.js +56 -5
- package/lib/commonjs/atoms/Text.js.map +1 -1
- package/lib/commonjs/atoms/Transition.js +46 -43
- package/lib/commonjs/atoms/Transition.js.map +1 -1
- package/lib/commonjs/atoms/index.js +6 -0
- package/lib/commonjs/atoms/index.js.map +1 -1
- package/lib/commonjs/atoms/inputValidation.js +56 -0
- package/lib/commonjs/atoms/inputValidation.js.map +1 -0
- package/lib/commonjs/icons/Icon.js +4 -4
- package/lib/commonjs/icons/defaultIcons.js +576 -24
- package/lib/commonjs/icons/defaultIcons.js.map +1 -1
- package/lib/commonjs/icons/index.js +6 -0
- package/lib/commonjs/icons/index.js.map +1 -1
- package/lib/commonjs/molecules/AvatarHeader.js +47 -14
- package/lib/commonjs/molecules/AvatarHeader.js.map +1 -1
- package/lib/commonjs/molecules/FormActions.js +25 -9
- package/lib/commonjs/molecules/FormActions.js.map +1 -1
- package/lib/commonjs/molecules/InfoRow.js +30 -14
- package/lib/commonjs/molecules/InfoRow.js.map +1 -1
- package/lib/commonjs/molecules/OptionCard.js +37 -22
- package/lib/commonjs/molecules/OptionCard.js.map +1 -1
- package/lib/commonjs/molecules/SegmentedControl.js +103 -14
- package/lib/commonjs/molecules/SegmentedControl.js.map +1 -1
- package/lib/commonjs/molecules/Stepper.js +61 -16
- package/lib/commonjs/molecules/Stepper.js.map +1 -1
- package/lib/commonjs/molecules/Steps.js +105 -41
- package/lib/commonjs/molecules/Steps.js.map +1 -1
- package/lib/commonjs/molecules/SymmetricGrid.js +26 -18
- package/lib/commonjs/molecules/SymmetricGrid.js.map +1 -1
- package/lib/commonjs/organisms/Alert.js +49 -35
- package/lib/commonjs/organisms/Alert.js.map +1 -1
- package/lib/commonjs/organisms/AlertProvider.js +10 -10
- package/lib/commonjs/organisms/BottomSheet.js +137 -85
- package/lib/commonjs/organisms/BottomSheet.js.map +1 -1
- package/lib/commonjs/organisms/Chart.js +174 -154
- package/lib/commonjs/organisms/Chart.js.map +1 -1
- package/lib/commonjs/organisms/DateField.js +36 -20
- package/lib/commonjs/organisms/DateField.js.map +1 -1
- package/lib/commonjs/organisms/DatePicker.js +56 -33
- package/lib/commonjs/organisms/DatePicker.js.map +1 -1
- package/lib/commonjs/organisms/List.js +62 -34
- package/lib/commonjs/organisms/List.js.map +1 -1
- package/lib/commonjs/organisms/Modal.js +120 -82
- package/lib/commonjs/organisms/Modal.js.map +1 -1
- package/lib/commonjs/organisms/NavigationBar.js +63 -24
- package/lib/commonjs/organisms/NavigationBar.js.map +1 -1
- package/lib/commonjs/organisms/OptionWheel.js +64 -64
- package/lib/commonjs/organisms/OptionWheel.js.map +1 -1
- package/lib/commonjs/organisms/ReorderableList.js +48 -27
- package/lib/commonjs/organisms/ReorderableList.js.map +1 -1
- package/lib/commonjs/organisms/Screen.js +68 -35
- package/lib/commonjs/organisms/Screen.js.map +1 -1
- package/lib/commonjs/organisms/SearchList.js +56 -26
- package/lib/commonjs/organisms/SearchList.js.map +1 -1
- package/lib/commonjs/organisms/Select.js +45 -24
- package/lib/commonjs/organisms/Select.js.map +1 -1
- package/lib/commonjs/organisms/Slides.js +36 -23
- package/lib/commonjs/organisms/Slides.js.map +1 -1
- package/lib/commonjs/organisms/ThemeToggle.js +10 -9
- package/lib/commonjs/organisms/ThemeToggle.js.map +1 -1
- package/lib/commonjs/organisms/Timeline.js +73 -56
- package/lib/commonjs/organisms/Timeline.js.map +1 -1
- package/lib/commonjs/organisms/Toast.js +46 -15
- package/lib/commonjs/organisms/Toast.js.map +1 -1
- package/lib/commonjs/organisms/ToastProvider.js +14 -10
- package/lib/commonjs/organisms/ToastProvider.js.map +1 -1
- package/lib/commonjs/organisms/Wizard.js +40 -15
- package/lib/commonjs/organisms/Wizard.js.map +1 -1
- package/lib/commonjs/organisms/chart/frame.js +25 -25
- package/lib/commonjs/organisms/chart/frame.js.map +1 -1
- package/lib/commonjs/organisms/chart/marks.js +42 -42
- package/lib/commonjs/organisms/chart/math.js +84 -85
- package/lib/commonjs/organisms/chart/math.js.map +1 -1
- package/lib/commonjs/organisms/chart/palette.js +28 -28
- package/lib/commonjs/organisms/imperativeBridge.js +5 -5
- package/lib/commonjs/organisms/imperativeBridge.js.map +1 -1
- package/lib/commonjs/organisms/useSlides.js +53 -21
- package/lib/commonjs/organisms/useSlides.js.map +1 -1
- package/lib/commonjs/safe-area/SafeAreaUIProvider.js +9 -66
- package/lib/commonjs/safe-area/SafeAreaUIProvider.js.map +1 -1
- package/lib/commonjs/safe-area/index.js.map +1 -1
- package/lib/commonjs/theme/KeyboardAvoidance.js +206 -0
- package/lib/commonjs/theme/KeyboardAvoidance.js.map +1 -0
- package/lib/commonjs/theme/NativeOverlay.js +263 -0
- package/lib/commonjs/theme/NativeOverlay.js.map +1 -0
- package/lib/commonjs/theme/UIProvider.js +86 -33
- package/lib/commonjs/theme/UIProvider.js.map +1 -1
- package/lib/commonjs/theme/colors.js +17 -17
- package/lib/commonjs/theme/colors.js.map +1 -1
- package/lib/commonjs/theme/createStyles.js +19 -16
- package/lib/commonjs/theme/createStyles.js.map +1 -1
- package/lib/commonjs/theme/createTheme.js +6 -6
- package/lib/commonjs/theme/index.js +6 -0
- package/lib/commonjs/theme/index.js.map +1 -1
- package/lib/commonjs/theme/insets.js +1 -1
- package/lib/commonjs/theme/labels.js +29 -1
- package/lib/commonjs/theme/labels.js.map +1 -1
- package/lib/commonjs/theme/palettes.js +25 -23
- package/lib/commonjs/theme/palettes.js.map +1 -1
- package/lib/commonjs/theme/tokens.js +28 -14
- package/lib/commonjs/theme/tokens.js.map +1 -1
- package/lib/commonjs/theme/useKeyboardField.js +36 -0
- package/lib/commonjs/theme/useKeyboardField.js.map +1 -0
- package/lib/commonjs/theme/useReduceMotion.js +31 -0
- package/lib/commonjs/theme/useReduceMotion.js.map +1 -0
- package/lib/module/atoms/Avatar.js +79 -8
- package/lib/module/atoms/Avatar.js.map +1 -1
- package/lib/module/atoms/Badge.js +17 -8
- package/lib/module/atoms/Badge.js.map +1 -1
- package/lib/module/atoms/Button.js +110 -41
- package/lib/module/atoms/Button.js.map +1 -1
- package/lib/module/atoms/Card.js +24 -2
- package/lib/module/atoms/Card.js.map +1 -1
- package/lib/module/atoms/Checkbox.js +42 -11
- package/lib/module/atoms/Checkbox.js.map +1 -1
- package/lib/module/atoms/Divider.js +31 -6
- package/lib/module/atoms/Divider.js.map +1 -1
- package/lib/module/atoms/EmptyState.js +58 -20
- package/lib/module/atoms/EmptyState.js.map +1 -1
- package/lib/module/atoms/Fab.js +33 -13
- package/lib/module/atoms/Fab.js.map +1 -1
- package/lib/module/atoms/Gradient.js +103 -37
- package/lib/module/atoms/Gradient.js.map +1 -1
- package/lib/module/atoms/IconButton.js +25 -4
- package/lib/module/atoms/IconButton.js.map +1 -1
- package/lib/module/atoms/Image.js +61 -25
- package/lib/module/atoms/Image.js.map +1 -1
- package/lib/module/atoms/Input.js +108 -20
- package/lib/module/atoms/Input.js.map +1 -1
- package/lib/module/atoms/KeyValueRow.js +37 -9
- package/lib/module/atoms/KeyValueRow.js.map +1 -1
- package/lib/module/atoms/PressableScale.js +25 -5
- package/lib/module/atoms/PressableScale.js.map +1 -1
- package/lib/module/atoms/ShinyText.js +29 -29
- package/lib/module/atoms/Skeleton.js +30 -13
- package/lib/module/atoms/Skeleton.js.map +1 -1
- package/lib/module/atoms/Spinner.js +82 -23
- package/lib/module/atoms/Spinner.js.map +1 -1
- package/lib/module/atoms/Text.js +56 -5
- package/lib/module/atoms/Text.js.map +1 -1
- package/lib/module/atoms/Transition.js +41 -42
- package/lib/module/atoms/Transition.js.map +1 -1
- package/lib/module/atoms/index.js +1 -1
- package/lib/module/atoms/index.js.map +1 -1
- package/lib/module/atoms/inputValidation.js +52 -0
- package/lib/module/atoms/inputValidation.js.map +1 -0
- package/lib/module/icons/Icon.js +4 -4
- package/lib/module/icons/defaultIcons.js +574 -24
- package/lib/module/icons/defaultIcons.js.map +1 -1
- package/lib/module/icons/index.js +1 -1
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/molecules/AvatarHeader.js +47 -14
- package/lib/module/molecules/AvatarHeader.js.map +1 -1
- package/lib/module/molecules/FormActions.js +25 -9
- package/lib/module/molecules/FormActions.js.map +1 -1
- package/lib/module/molecules/InfoRow.js +30 -14
- package/lib/module/molecules/InfoRow.js.map +1 -1
- package/lib/module/molecules/OptionCard.js +37 -22
- package/lib/module/molecules/OptionCard.js.map +1 -1
- package/lib/module/molecules/SegmentedControl.js +107 -18
- package/lib/module/molecules/SegmentedControl.js.map +1 -1
- package/lib/module/molecules/Stepper.js +63 -18
- package/lib/module/molecules/Stepper.js.map +1 -1
- package/lib/module/molecules/Steps.js +107 -43
- package/lib/module/molecules/Steps.js.map +1 -1
- package/lib/module/molecules/SymmetricGrid.js +26 -18
- package/lib/module/molecules/SymmetricGrid.js.map +1 -1
- package/lib/module/organisms/Alert.js +51 -37
- package/lib/module/organisms/Alert.js.map +1 -1
- package/lib/module/organisms/AlertProvider.js +10 -10
- package/lib/module/organisms/BottomSheet.js +142 -88
- package/lib/module/organisms/BottomSheet.js.map +1 -1
- package/lib/module/organisms/Chart.js +176 -156
- package/lib/module/organisms/Chart.js.map +1 -1
- package/lib/module/organisms/DateField.js +36 -20
- package/lib/module/organisms/DateField.js.map +1 -1
- package/lib/module/organisms/DatePicker.js +56 -33
- package/lib/module/organisms/DatePicker.js.map +1 -1
- package/lib/module/organisms/List.js +62 -34
- package/lib/module/organisms/List.js.map +1 -1
- package/lib/module/organisms/Modal.js +122 -84
- package/lib/module/organisms/Modal.js.map +1 -1
- package/lib/module/organisms/NavigationBar.js +64 -25
- package/lib/module/organisms/NavigationBar.js.map +1 -1
- package/lib/module/organisms/OptionWheel.js +64 -64
- package/lib/module/organisms/OptionWheel.js.map +1 -1
- package/lib/module/organisms/ReorderableList.js +48 -27
- package/lib/module/organisms/ReorderableList.js.map +1 -1
- package/lib/module/organisms/Screen.js +70 -37
- package/lib/module/organisms/Screen.js.map +1 -1
- package/lib/module/organisms/SearchList.js +56 -26
- package/lib/module/organisms/SearchList.js.map +1 -1
- package/lib/module/organisms/Select.js +46 -25
- package/lib/module/organisms/Select.js.map +1 -1
- package/lib/module/organisms/Slides.js +37 -24
- package/lib/module/organisms/Slides.js.map +1 -1
- package/lib/module/organisms/ThemeToggle.js +11 -10
- package/lib/module/organisms/ThemeToggle.js.map +1 -1
- package/lib/module/organisms/Timeline.js +73 -56
- package/lib/module/organisms/Timeline.js.map +1 -1
- package/lib/module/organisms/Toast.js +47 -16
- package/lib/module/organisms/Toast.js.map +1 -1
- package/lib/module/organisms/ToastProvider.js +15 -11
- package/lib/module/organisms/ToastProvider.js.map +1 -1
- package/lib/module/organisms/Wizard.js +41 -16
- package/lib/module/organisms/Wizard.js.map +1 -1
- package/lib/module/organisms/chart/frame.js +25 -25
- package/lib/module/organisms/chart/frame.js.map +1 -1
- package/lib/module/organisms/chart/marks.js +42 -42
- package/lib/module/organisms/chart/math.js +84 -85
- package/lib/module/organisms/chart/math.js.map +1 -1
- package/lib/module/organisms/chart/palette.js +28 -28
- package/lib/module/organisms/imperativeBridge.js +5 -5
- package/lib/module/organisms/imperativeBridge.js.map +1 -1
- package/lib/module/organisms/useSlides.js +53 -21
- package/lib/module/organisms/useSlides.js.map +1 -1
- package/lib/module/safe-area/SafeAreaUIProvider.js +10 -65
- package/lib/module/safe-area/SafeAreaUIProvider.js.map +1 -1
- package/lib/module/safe-area/index.js +1 -0
- package/lib/module/safe-area/index.js.map +1 -1
- package/lib/module/theme/KeyboardAvoidance.js +198 -0
- package/lib/module/theme/KeyboardAvoidance.js.map +1 -0
- package/lib/module/theme/NativeOverlay.js +257 -0
- package/lib/module/theme/NativeOverlay.js.map +1 -0
- package/lib/module/theme/UIProvider.js +88 -35
- package/lib/module/theme/UIProvider.js.map +1 -1
- package/lib/module/theme/colors.js +17 -17
- package/lib/module/theme/colors.js.map +1 -1
- package/lib/module/theme/createStyles.js +20 -16
- package/lib/module/theme/createStyles.js.map +1 -1
- package/lib/module/theme/createTheme.js +6 -6
- package/lib/module/theme/index.js +1 -1
- package/lib/module/theme/index.js.map +1 -1
- package/lib/module/theme/insets.js +1 -1
- package/lib/module/theme/labels.js +29 -1
- package/lib/module/theme/labels.js.map +1 -1
- package/lib/module/theme/palettes.js +25 -23
- package/lib/module/theme/palettes.js.map +1 -1
- package/lib/module/theme/tokens.js +27 -13
- package/lib/module/theme/tokens.js.map +1 -1
- package/lib/module/theme/useKeyboardField.js +33 -0
- package/lib/module/theme/useKeyboardField.js.map +1 -0
- package/lib/module/theme/useReduceMotion.js +28 -0
- package/lib/module/theme/useReduceMotion.js.map +1 -0
- package/lib/typescript/atoms/Avatar.d.ts +35 -5
- package/lib/typescript/atoms/Avatar.d.ts.map +1 -1
- package/lib/typescript/atoms/Badge.d.ts +14 -3
- package/lib/typescript/atoms/Badge.d.ts.map +1 -1
- package/lib/typescript/atoms/Button.d.ts +34 -3
- package/lib/typescript/atoms/Button.d.ts.map +1 -1
- package/lib/typescript/atoms/Card.d.ts +13 -2
- package/lib/typescript/atoms/Card.d.ts.map +1 -1
- package/lib/typescript/atoms/Checkbox.d.ts +26 -1
- package/lib/typescript/atoms/Checkbox.d.ts.map +1 -1
- package/lib/typescript/atoms/Divider.d.ts +18 -1
- package/lib/typescript/atoms/Divider.d.ts.map +1 -1
- package/lib/typescript/atoms/EmptyState.d.ts +30 -3
- package/lib/typescript/atoms/EmptyState.d.ts.map +1 -1
- package/lib/typescript/atoms/Fab.d.ts +24 -4
- package/lib/typescript/atoms/Fab.d.ts.map +1 -1
- package/lib/typescript/atoms/Gradient.d.ts +21 -15
- package/lib/typescript/atoms/Gradient.d.ts.map +1 -1
- package/lib/typescript/atoms/IconButton.d.ts +18 -4
- package/lib/typescript/atoms/IconButton.d.ts.map +1 -1
- package/lib/typescript/atoms/Image.d.ts +39 -17
- package/lib/typescript/atoms/Image.d.ts.map +1 -1
- package/lib/typescript/atoms/Input.d.ts +57 -7
- package/lib/typescript/atoms/Input.d.ts.map +1 -1
- package/lib/typescript/atoms/KeyValueRow.d.ts +16 -4
- package/lib/typescript/atoms/KeyValueRow.d.ts.map +1 -1
- package/lib/typescript/atoms/PressableScale.d.ts +12 -5
- package/lib/typescript/atoms/PressableScale.d.ts.map +1 -1
- package/lib/typescript/atoms/ShinyText.d.ts +17 -17
- package/lib/typescript/atoms/ShinyText.d.ts.map +1 -1
- package/lib/typescript/atoms/Skeleton.d.ts +12 -7
- package/lib/typescript/atoms/Skeleton.d.ts.map +1 -1
- package/lib/typescript/atoms/Spinner.d.ts +29 -1
- package/lib/typescript/atoms/Spinner.d.ts.map +1 -1
- package/lib/typescript/atoms/Text.d.ts +46 -0
- package/lib/typescript/atoms/Text.d.ts.map +1 -1
- package/lib/typescript/atoms/Transition.d.ts +19 -15
- package/lib/typescript/atoms/Transition.d.ts.map +1 -1
- package/lib/typescript/atoms/index.d.ts +3 -3
- package/lib/typescript/atoms/index.d.ts.map +1 -1
- package/lib/typescript/atoms/inputValidation.d.ts +29 -0
- package/lib/typescript/atoms/inputValidation.d.ts.map +1 -0
- package/lib/typescript/icons/Icon.d.ts +4 -4
- package/lib/typescript/icons/defaultIcons.d.ts +19 -2
- package/lib/typescript/icons/defaultIcons.d.ts.map +1 -1
- package/lib/typescript/icons/index.d.ts +2 -2
- package/lib/typescript/icons/index.d.ts.map +1 -1
- package/lib/typescript/icons/types.d.ts +13 -3
- package/lib/typescript/icons/types.d.ts.map +1 -1
- package/lib/typescript/molecules/AvatarHeader.d.ts +23 -4
- package/lib/typescript/molecules/AvatarHeader.d.ts.map +1 -1
- package/lib/typescript/molecules/FormActions.d.ts +21 -4
- package/lib/typescript/molecules/FormActions.d.ts.map +1 -1
- package/lib/typescript/molecules/InfoRow.d.ts +17 -3
- package/lib/typescript/molecules/InfoRow.d.ts.map +1 -1
- package/lib/typescript/molecules/OptionCard.d.ts +20 -5
- package/lib/typescript/molecules/OptionCard.d.ts.map +1 -1
- package/lib/typescript/molecules/SegmentedControl.d.ts +18 -2
- package/lib/typescript/molecules/SegmentedControl.d.ts.map +1 -1
- package/lib/typescript/molecules/Stepper.d.ts +23 -7
- package/lib/typescript/molecules/Stepper.d.ts.map +1 -1
- package/lib/typescript/molecules/Steps.d.ts +18 -4
- package/lib/typescript/molecules/Steps.d.ts.map +1 -1
- package/lib/typescript/molecules/SymmetricGrid.d.ts +15 -5
- package/lib/typescript/molecules/SymmetricGrid.d.ts.map +1 -1
- package/lib/typescript/organisms/Alert.d.ts +28 -2
- package/lib/typescript/organisms/Alert.d.ts.map +1 -1
- package/lib/typescript/organisms/AlertProvider.d.ts +10 -10
- package/lib/typescript/organisms/AlertProvider.d.ts.map +1 -1
- package/lib/typescript/organisms/BottomSheet.d.ts +20 -5
- package/lib/typescript/organisms/BottomSheet.d.ts.map +1 -1
- package/lib/typescript/organisms/Chart.d.ts +86 -75
- package/lib/typescript/organisms/Chart.d.ts.map +1 -1
- package/lib/typescript/organisms/DateField.d.ts +17 -3
- package/lib/typescript/organisms/DateField.d.ts.map +1 -1
- package/lib/typescript/organisms/DatePicker.d.ts +7 -11
- package/lib/typescript/organisms/DatePicker.d.ts.map +1 -1
- package/lib/typescript/organisms/List.d.ts +30 -3
- package/lib/typescript/organisms/List.d.ts.map +1 -1
- package/lib/typescript/organisms/Modal.d.ts +30 -3
- package/lib/typescript/organisms/Modal.d.ts.map +1 -1
- package/lib/typescript/organisms/NavigationBar.d.ts +26 -7
- package/lib/typescript/organisms/NavigationBar.d.ts.map +1 -1
- package/lib/typescript/organisms/OptionWheel.d.ts +20 -16
- package/lib/typescript/organisms/OptionWheel.d.ts.map +1 -1
- package/lib/typescript/organisms/ReorderableList.d.ts +20 -11
- package/lib/typescript/organisms/ReorderableList.d.ts.map +1 -1
- package/lib/typescript/organisms/Screen.d.ts +27 -8
- package/lib/typescript/organisms/Screen.d.ts.map +1 -1
- package/lib/typescript/organisms/SearchList.d.ts +46 -3
- package/lib/typescript/organisms/SearchList.d.ts.map +1 -1
- package/lib/typescript/organisms/Select.d.ts +26 -6
- package/lib/typescript/organisms/Select.d.ts.map +1 -1
- package/lib/typescript/organisms/Slides.d.ts +44 -26
- package/lib/typescript/organisms/Slides.d.ts.map +1 -1
- package/lib/typescript/organisms/ThemeToggle.d.ts +6 -2
- package/lib/typescript/organisms/ThemeToggle.d.ts.map +1 -1
- package/lib/typescript/organisms/Timeline.d.ts +26 -9
- package/lib/typescript/organisms/Timeline.d.ts.map +1 -1
- package/lib/typescript/organisms/Toast.d.ts +19 -4
- package/lib/typescript/organisms/Toast.d.ts.map +1 -1
- package/lib/typescript/organisms/ToastProvider.d.ts +8 -8
- package/lib/typescript/organisms/ToastProvider.d.ts.map +1 -1
- package/lib/typescript/organisms/Wizard.d.ts +24 -6
- package/lib/typescript/organisms/Wizard.d.ts.map +1 -1
- package/lib/typescript/organisms/chart/frame.d.ts +21 -21
- package/lib/typescript/organisms/chart/frame.d.ts.map +1 -1
- package/lib/typescript/organisms/chart/marks.d.ts +28 -28
- package/lib/typescript/organisms/chart/marks.d.ts.map +1 -1
- package/lib/typescript/organisms/chart/math.d.ts +69 -70
- package/lib/typescript/organisms/chart/math.d.ts.map +1 -1
- package/lib/typescript/organisms/chart/palette.d.ts +2 -2
- package/lib/typescript/organisms/chart/palette.d.ts.map +1 -1
- package/lib/typescript/organisms/imperativeBridge.d.ts +4 -4
- package/lib/typescript/organisms/useSlides.d.ts +8 -16
- package/lib/typescript/organisms/useSlides.d.ts.map +1 -1
- package/lib/typescript/safe-area/SafeAreaUIProvider.d.ts +9 -7
- package/lib/typescript/safe-area/SafeAreaUIProvider.d.ts.map +1 -1
- package/lib/typescript/safe-area/index.d.ts.map +1 -1
- package/lib/typescript/theme/KeyboardAvoidance.d.ts +62 -0
- package/lib/typescript/theme/KeyboardAvoidance.d.ts.map +1 -0
- package/lib/typescript/theme/NativeOverlay.d.ts +43 -0
- package/lib/typescript/theme/NativeOverlay.d.ts.map +1 -0
- package/lib/typescript/theme/UIProvider.d.ts +38 -20
- package/lib/typescript/theme/UIProvider.d.ts.map +1 -1
- package/lib/typescript/theme/colors.d.ts +13 -13
- package/lib/typescript/theme/colors.d.ts.map +1 -1
- package/lib/typescript/theme/createStyles.d.ts +20 -14
- package/lib/typescript/theme/createStyles.d.ts.map +1 -1
- package/lib/typescript/theme/createTheme.d.ts +5 -5
- package/lib/typescript/theme/index.d.ts +1 -1
- package/lib/typescript/theme/index.d.ts.map +1 -1
- package/lib/typescript/theme/insets.d.ts +1 -1
- package/lib/typescript/theme/insets.d.ts.map +1 -1
- package/lib/typescript/theme/labels.d.ts +57 -2
- package/lib/typescript/theme/labels.d.ts.map +1 -1
- package/lib/typescript/theme/palettes.d.ts +25 -19
- package/lib/typescript/theme/palettes.d.ts.map +1 -1
- package/lib/typescript/theme/tokens.d.ts +15 -8
- package/lib/typescript/theme/tokens.d.ts.map +1 -1
- package/lib/typescript/theme/types.d.ts +7 -7
- package/lib/typescript/theme/types.d.ts.map +1 -1
- package/lib/typescript/theme/useKeyboardField.d.ts +17 -0
- package/lib/typescript/theme/useKeyboardField.d.ts.map +1 -0
- package/lib/typescript/theme/useReduceMotion.d.ts +7 -0
- package/lib/typescript/theme/useReduceMotion.d.ts.map +1 -0
- package/llms.txt +4 -4
- package/package.json +15 -14
- package/registry/alert-provider.json +4 -3
- package/registry/alert.json +3 -2
- package/registry/avatar-header.json +1 -1
- package/registry/avatar.json +3 -2
- package/registry/badge.json +1 -1
- package/registry/bottom-sheet.json +1 -1
- package/registry/button.json +3 -2
- package/registry/card.json +1 -1
- package/registry/chart.json +5 -5
- package/registry/checkbox.json +3 -2
- package/registry/core.json +31 -15
- package/registry/date-field.json +1 -1
- package/registry/date-picker.json +3 -2
- package/registry/divider.json +1 -1
- package/registry/empty-state.json +4 -2
- package/registry/fab.json +3 -2
- package/registry/form-actions.json +3 -2
- package/registry/gradient.json +1 -1
- package/registry/icon-button.json +3 -2
- package/registry/image.json +1 -1
- package/registry/index.json +79 -61
- package/registry/info-row.json +1 -1
- package/registry/input.json +5 -1
- package/registry/key-value-row.json +1 -1
- package/registry/list.json +3 -1
- package/registry/manifest.json +3 -1
- package/registry/modal.json +1 -1
- package/registry/navigation-bar.json +1 -1
- package/registry/option-card.json +3 -2
- package/registry/option-wheel.json +1 -1
- package/registry/pressable-scale.json +3 -2
- package/registry/reorderable-list.json +1 -1
- package/registry/screen.json +1 -1
- package/registry/search-list.json +7 -1
- package/registry/segmented-control.json +1 -1
- package/registry/select.json +1 -1
- package/registry/shiny-text.json +1 -1
- package/registry/skeleton.json +3 -2
- package/registry/slides.json +2 -2
- package/registry/spinner.json +1 -1
- package/registry/stepper.json +1 -1
- package/registry/steps.json +1 -1
- package/registry/symmetric-grid.json +1 -1
- package/registry/theme-toggle.json +1 -1
- package/registry/timeline.json +1 -1
- package/registry/title.json +1 -1
- package/registry/toast-provider.json +2 -2
- package/registry/toast.json +1 -1
- package/registry/transition.json +1 -1
- package/registry/wizard.json +1 -1
- package/src/atoms/Avatar.tsx +117 -26
- package/src/atoms/Badge.tsx +20 -9
- package/src/atoms/Button.tsx +102 -30
- package/src/atoms/Card.tsx +23 -3
- package/src/atoms/Checkbox.tsx +49 -12
- package/src/atoms/Divider.tsx +34 -4
- package/src/atoms/EmptyState.tsx +63 -16
- package/src/atoms/Fab.tsx +56 -9
- package/src/atoms/Gradient.tsx +92 -41
- package/src/atoms/IconButton.tsx +27 -4
- package/src/atoms/Image.tsx +74 -28
- package/src/atoms/Input.tsx +129 -19
- package/src/atoms/KeyValueRow.tsx +72 -28
- package/src/atoms/PressableScale.tsx +31 -7
- package/src/atoms/ShinyText.tsx +31 -31
- package/src/atoms/Skeleton.tsx +37 -17
- package/src/atoms/Spinner.tsx +87 -24
- package/src/atoms/Text.tsx +66 -6
- package/src/atoms/Transition.tsx +40 -44
- package/src/atoms/index.ts +3 -3
- package/src/atoms/inputValidation.ts +59 -0
- package/src/icons/Icon.tsx +4 -4
- package/src/icons/defaultIcons.tsx +445 -22
- package/src/icons/index.ts +2 -2
- package/src/icons/types.ts +26 -4
- package/src/molecules/AvatarHeader.tsx +88 -34
- package/src/molecules/FormActions.tsx +36 -6
- package/src/molecules/InfoRow.tsx +39 -12
- package/src/molecules/OptionCard.tsx +55 -20
- package/src/molecules/SegmentedControl.tsx +135 -15
- package/src/molecules/Stepper.tsx +73 -19
- package/src/molecules/Steps.tsx +121 -39
- package/src/molecules/SymmetricGrid.tsx +28 -12
- package/src/organisms/Alert.tsx +97 -26
- package/src/organisms/AlertProvider.tsx +13 -13
- package/src/organisms/BottomSheet.tsx +115 -43
- package/src/organisms/Chart.tsx +193 -164
- package/src/organisms/DateField.tsx +40 -15
- package/src/organisms/DatePicker.tsx +53 -32
- package/src/organisms/List.tsx +64 -15
- package/src/organisms/Modal.tsx +122 -63
- package/src/organisms/NavigationBar.tsx +73 -23
- package/src/organisms/OptionWheel.tsx +70 -66
- package/src/organisms/ReorderableList.tsx +49 -27
- package/src/organisms/Screen.tsx +79 -42
- package/src/organisms/SearchList.tsx +84 -20
- package/src/organisms/Select.tsx +63 -29
- package/src/organisms/Slides.tsx +63 -44
- package/src/organisms/ThemeToggle.tsx +15 -6
- package/src/organisms/Timeline.tsx +79 -62
- package/src/organisms/Toast.tsx +50 -15
- package/src/organisms/ToastProvider.tsx +17 -13
- package/src/organisms/Wizard.tsx +58 -21
- package/src/organisms/chart/frame.tsx +35 -35
- package/src/organisms/chart/marks.tsx +53 -53
- package/src/organisms/chart/math.ts +93 -94
- package/src/organisms/chart/palette.ts +28 -28
- package/src/organisms/imperativeBridge.ts +5 -5
- package/src/organisms/useSlides.ts +66 -31
- package/src/safe-area/SafeAreaUIProvider.tsx +9 -70
- package/src/safe-area/index.ts +1 -0
- package/src/theme/KeyboardAvoidance.tsx +216 -0
- package/src/theme/NativeOverlay.tsx +269 -0
- package/src/theme/UIProvider.tsx +109 -46
- package/src/theme/colors.ts +21 -21
- package/src/theme/createStyles.ts +23 -19
- package/src/theme/createTheme.ts +6 -6
- package/src/theme/index.ts +1 -1
- package/src/theme/insets.ts +1 -1
- package/src/theme/labels.ts +85 -2
- package/src/theme/palettes.ts +33 -25
- package/src/theme/tokens.ts +27 -13
- package/src/theme/types.ts +7 -7
- package/src/theme/useKeyboardField.ts +33 -0
- package/src/theme/useReduceMotion.ts +27 -0
package/src/organisms/Modal.tsx
CHANGED
|
@@ -1,49 +1,65 @@
|
|
|
1
1
|
import React, { memo, useEffect, useState } from 'react';
|
|
2
2
|
import {
|
|
3
|
-
Dimensions,
|
|
4
3
|
KeyboardAvoidingView,
|
|
5
|
-
Modal as RNModal,
|
|
6
4
|
Platform,
|
|
7
5
|
Pressable,
|
|
8
6
|
ScrollView,
|
|
9
7
|
View,
|
|
8
|
+
useWindowDimensions,
|
|
10
9
|
type ModalProps as RNModalProps,
|
|
11
10
|
type ViewStyle,
|
|
12
11
|
} from 'react-native';
|
|
13
12
|
import { createStyles } from '../theme/createStyles';
|
|
14
|
-
import {
|
|
13
|
+
import { useLabels, useModalSafeAreaBoundary, useTheme } from '../theme/UIProvider';
|
|
14
|
+
import { NativeOverlay } from '../theme/NativeOverlay';
|
|
15
|
+
import { KeyboardHandled } from '../theme/KeyboardAvoidance';
|
|
15
16
|
import type { EdgeInsets } from '../theme/insets';
|
|
16
17
|
import { Title } from '../atoms/Text';
|
|
17
18
|
import { IconButton } from '../atoms/IconButton';
|
|
18
19
|
import { Transition, type TransitionPreset } from '../atoms/Transition';
|
|
19
20
|
|
|
20
|
-
const { height: SCREEN_HEIGHT } = Dimensions.get('window');
|
|
21
|
-
|
|
22
21
|
export type ModalVariant = 'full' | 'overlay' | 'fullScreen';
|
|
23
22
|
|
|
24
23
|
export interface ModalProps
|
|
25
24
|
extends Pick<RNModalProps, 'statusBarTranslucent' | 'onRequestClose' | 'hardwareAccelerated'> {
|
|
25
|
+
/** Shows or hides the modal. The animated variants play their exit before unmounting. */
|
|
26
26
|
visible: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Shows the close button in the header and is called by it, by a tap on the backdrop (`overlay`) and
|
|
29
|
+
* by Android's back button.
|
|
30
|
+
*/
|
|
27
31
|
onClose?: () => void;
|
|
32
|
+
/** Header title, on a single line. */
|
|
28
33
|
title?: string;
|
|
34
|
+
/** Accessible name of the close button. @default labels.close */
|
|
29
35
|
closeAccessibilityLabel?: string;
|
|
36
|
+
/** Body of the modal. */
|
|
30
37
|
children: React.ReactNode;
|
|
38
|
+
/** Fixed area below the content (e.g. actions); it doesn't scroll. */
|
|
31
39
|
footer?: React.ReactNode;
|
|
40
|
+
/** Style of the card (`overlay`) or the full-screen wrapper. */
|
|
32
41
|
containerStyle?: ViewStyle;
|
|
42
|
+
/** Style of the content area (the scroll container when `scrollable`). */
|
|
33
43
|
contentStyle?: ViewStyle;
|
|
44
|
+
/**
|
|
45
|
+
* 'full' slides up a full page, 'overlay' a centered card over a dimmed backdrop, 'fullScreen' uses
|
|
46
|
+
* the native full-screen presentation. @default 'full'
|
|
47
|
+
*/
|
|
34
48
|
variant?: ModalVariant;
|
|
49
|
+
/** Wraps the content in a ScrollView. @default true */
|
|
35
50
|
scrollable?: boolean;
|
|
36
51
|
}
|
|
37
52
|
|
|
38
53
|
const useStyles = createStyles((theme) => ({
|
|
39
54
|
flex1: { flex: 1 },
|
|
40
|
-
fullWrapper: { flex: 1, backgroundColor: theme.colors.
|
|
41
|
-
overlayContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: theme.tokens.spacing.
|
|
55
|
+
fullWrapper: { flex: 1, backgroundColor: theme.colors.surface },
|
|
56
|
+
overlayContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: theme.tokens.spacing.xl },
|
|
42
57
|
backdrop: { backgroundColor: theme.colors.overlay },
|
|
43
58
|
overlayCard: {
|
|
44
59
|
width: '100%',
|
|
45
60
|
maxHeight: '85%',
|
|
46
|
-
|
|
61
|
+
// Raised: in dark mode the plain surface sank into the dimmed backdrop.
|
|
62
|
+
backgroundColor: theme.colors.surfaceRaised,
|
|
47
63
|
borderRadius: theme.tokens.radius.xxl,
|
|
48
64
|
overflow: 'hidden',
|
|
49
65
|
...theme.tokens.shadow.lg,
|
|
@@ -55,11 +71,11 @@ const useStyles = createStyles((theme) => ({
|
|
|
55
71
|
padding: theme.tokens.spacing.xl,
|
|
56
72
|
borderBottomWidth: 1,
|
|
57
73
|
borderBottomColor: theme.colors.border,
|
|
58
|
-
backgroundColor: theme.colors.surface,
|
|
59
74
|
},
|
|
60
75
|
title: { fontSize: theme.tokens.fontSize.xl, fontWeight: theme.tokens.fontWeight.bold, flex: 1 },
|
|
61
76
|
closeButton: { marginLeft: theme.tokens.spacing.md },
|
|
62
|
-
|
|
77
|
+
cardInner: { flexShrink: 1 },
|
|
78
|
+
contentWrapper: { flexShrink: 1 },
|
|
63
79
|
scrollWrapper: { flexShrink: 1 },
|
|
64
80
|
scrollContent: { padding: theme.tokens.spacing.xl, flexGrow: 1 },
|
|
65
81
|
scrollContentFull: { padding: 0, flexGrow: 1 },
|
|
@@ -67,22 +83,38 @@ const useStyles = createStyles((theme) => ({
|
|
|
67
83
|
padding: theme.tokens.spacing.xl,
|
|
68
84
|
borderTopWidth: 1,
|
|
69
85
|
borderTopColor: theme.colors.border,
|
|
70
|
-
backgroundColor: theme.colors.surface,
|
|
71
86
|
},
|
|
72
87
|
}));
|
|
73
88
|
|
|
89
|
+
/** Close glyph: the same size BottomSheet uses; IconButton pads it to 44pt. */
|
|
90
|
+
const CLOSE_ICON_SIZE = 24;
|
|
91
|
+
/** How far the `overlay` card drops in while it scales up. */
|
|
92
|
+
const OVERLAY_ENTER_DISTANCE = 40;
|
|
93
|
+
|
|
94
|
+
|
|
74
95
|
/**
|
|
75
96
|
* Modal
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* BottomSheet,
|
|
97
|
+
* A single component for all of the app's modals: handles scroll, keyboard,
|
|
98
|
+
* insets and layout according to `variant`. For a sheet from the bottom there
|
|
99
|
+
* is BottomSheet, which also comes with drag to close.
|
|
100
|
+
*
|
|
101
|
+
* Design:
|
|
102
|
+
* - Figure and ground (Gestalt): `overlay` dims the screen behind a raised
|
|
103
|
+
* card, so the task in front is the only figure.
|
|
104
|
+
* - Common region: header, content and footer share one surface, split by
|
|
105
|
+
* hairlines; the footer stays fixed so its actions are always in reach.
|
|
106
|
+
* - Jakob's law: title on the left, close at the top right, Android back and
|
|
107
|
+
* the VoiceOver escape gesture close it, like the system's own sheets.
|
|
108
|
+
* - Fitts's law: the close button is a 44pt target.
|
|
109
|
+
* - Screen readers stay inside the modal (`accessibilityViewIsModal`), which
|
|
110
|
+
* matters on iOS when it is drawn inside another open overlay.
|
|
79
111
|
*/
|
|
80
112
|
export const Modal = memo(
|
|
81
113
|
({
|
|
82
114
|
visible,
|
|
83
115
|
onClose,
|
|
84
116
|
title,
|
|
85
|
-
closeAccessibilityLabel
|
|
117
|
+
closeAccessibilityLabel,
|
|
86
118
|
children,
|
|
87
119
|
footer,
|
|
88
120
|
containerStyle,
|
|
@@ -98,8 +130,12 @@ export const Modal = memo(
|
|
|
98
130
|
const isFullScreen = variant === 'fullScreen';
|
|
99
131
|
const isAnimatedVariant = isOverlay || isFull;
|
|
100
132
|
const ModalSafeAreaBoundary = useModalSafeAreaBoundary();
|
|
101
|
-
const
|
|
133
|
+
const theme = useTheme();
|
|
134
|
+
const { colors } = theme;
|
|
102
135
|
const styles = useStyles();
|
|
136
|
+
const labels = useLabels();
|
|
137
|
+
const closeLabel = closeAccessibilityLabel ?? labels.close;
|
|
138
|
+
const { height: windowHeight } = useWindowDimensions();
|
|
103
139
|
|
|
104
140
|
const [mounted, setMounted] = useState(!isAnimatedVariant && visible);
|
|
105
141
|
|
|
@@ -108,10 +144,10 @@ export const Modal = memo(
|
|
|
108
144
|
else if (visible) setMounted(true);
|
|
109
145
|
}, [visible, isAnimatedVariant]);
|
|
110
146
|
|
|
111
|
-
//
|
|
112
|
-
//
|
|
147
|
+
// The card never animates opacity: doing so triggers an Android bug where
|
|
148
|
+
// children with elevation flicker. The semi-transparent backdrop does.
|
|
113
149
|
const cardPreset: TransitionPreset[] = isFull ? ['slide-up'] : ['slide-down', 'scale'];
|
|
114
|
-
const cardDistance = isFull ?
|
|
150
|
+
const cardDistance = isFull ? windowHeight : OVERLAY_ENTER_DISTANCE;
|
|
115
151
|
|
|
116
152
|
const behavior = Platform.OS === 'ios' ? (isFull ? undefined : 'padding') : 'height';
|
|
117
153
|
const keyboardOffset = Platform.OS === 'ios' ? 0 : 20;
|
|
@@ -127,7 +163,14 @@ export const Modal = memo(
|
|
|
127
163
|
)}
|
|
128
164
|
{!title && <View style={styles.flex1} />}
|
|
129
165
|
{!!onClose && (
|
|
130
|
-
<IconButton
|
|
166
|
+
<IconButton
|
|
167
|
+
iconName="close"
|
|
168
|
+
size={CLOSE_ICON_SIZE}
|
|
169
|
+
color={colors.text}
|
|
170
|
+
onPress={onClose}
|
|
171
|
+
accessibilityLabel={closeLabel}
|
|
172
|
+
style={styles.closeButton}
|
|
173
|
+
/>
|
|
131
174
|
)}
|
|
132
175
|
</View>
|
|
133
176
|
);
|
|
@@ -156,42 +199,17 @@ export const Modal = memo(
|
|
|
156
199
|
|
|
157
200
|
const renderFooter = () => (footer ? <View style={styles.footer}>{footer}</View> : null);
|
|
158
201
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return (
|
|
162
|
-
<RNModal
|
|
163
|
-
visible
|
|
164
|
-
onRequestClose={onRequestClose ?? onClose}
|
|
165
|
-
animationType={isAnimatedVariant ? 'none' : 'slide'}
|
|
166
|
-
// `full` anima su propia entrada (translateY) con animationType="none"
|
|
167
|
-
// y necesita `transparent` para que no se vea un fondo negro detrás
|
|
168
|
-
// mientras desliza. RN sólo admite `transparent` junto a
|
|
169
|
-
// 'overFullScreen' — con 'pageSheet' avisa que la combinación no está
|
|
170
|
-
// soportada. Por eso `full` usa overFullScreen: la presentación nativa
|
|
171
|
-
// de pageSheet sería redundante con nuestra animación de todos modos.
|
|
172
|
-
presentationStyle={
|
|
173
|
-
Platform.OS === 'ios' ? (isFullScreen ? 'fullScreen' : 'overFullScreen') : undefined
|
|
174
|
-
}
|
|
175
|
-
transparent={isOverlay || isFull}
|
|
176
|
-
statusBarTranslucent={statusBarTranslucent}
|
|
177
|
-
hardwareAccelerated={hardwareAccelerated}
|
|
178
|
-
>
|
|
179
|
-
<KeyboardAvoidingView behavior={behavior} keyboardVerticalOffset={keyboardOffset} style={styles.flex1}>
|
|
180
|
-
{/* Insets medidos dentro de esta ventana nativa del Modal, no los de
|
|
181
|
-
la raíz de la app — pueden diferir (Android siempre abre una
|
|
182
|
-
ventana propia; iOS según `presentationStyle`). */}
|
|
183
|
-
<ModalSafeAreaBoundary>
|
|
184
|
-
{(insets: EdgeInsets) =>
|
|
202
|
+
const renderBody = (insets: EdgeInsets) =>
|
|
185
203
|
isOverlay ? (
|
|
186
204
|
<View style={styles.overlayContainer}>
|
|
187
|
-
{/*
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
205
|
+
{/* No accessibilityLabel of its own: the header already exposes an
|
|
206
|
+
accessible "Close" button; duplicating the label here would create
|
|
207
|
+
two elements with the same name for screen readers. Tapping
|
|
208
|
+
outside is a purely tactile shortcut. */}
|
|
191
209
|
<Transition
|
|
192
210
|
visible={visible}
|
|
193
211
|
preset="fade"
|
|
194
|
-
duration={
|
|
212
|
+
duration={theme.tokens.duration.base}
|
|
195
213
|
keepMounted
|
|
196
214
|
style={[{ ...StyleSheetAbsoluteFill }, styles.backdrop]}
|
|
197
215
|
>
|
|
@@ -202,13 +220,15 @@ export const Modal = memo(
|
|
|
202
220
|
visible={visible}
|
|
203
221
|
preset={cardPreset}
|
|
204
222
|
distance={cardDistance}
|
|
205
|
-
duration={
|
|
223
|
+
duration={theme.tokens.duration.slow}
|
|
206
224
|
onExited={() => setMounted(false)}
|
|
207
225
|
style={[styles.overlayCard, containerStyle]}
|
|
208
226
|
>
|
|
209
|
-
{
|
|
210
|
-
|
|
211
|
-
|
|
227
|
+
<View style={styles.cardInner} accessibilityViewIsModal onAccessibilityEscape={onClose}>
|
|
228
|
+
{renderHeader()}
|
|
229
|
+
{renderMainContent()}
|
|
230
|
+
{renderFooter()}
|
|
231
|
+
</View>
|
|
212
232
|
</Transition>
|
|
213
233
|
</View>
|
|
214
234
|
) : isFull ? (
|
|
@@ -216,29 +236,68 @@ export const Modal = memo(
|
|
|
216
236
|
visible={visible}
|
|
217
237
|
preset={cardPreset}
|
|
218
238
|
distance={cardDistance}
|
|
219
|
-
duration={
|
|
239
|
+
duration={theme.tokens.duration.slow}
|
|
220
240
|
onExited={() => setMounted(false)}
|
|
221
241
|
style={[styles.fullWrapper, containerStyle]}
|
|
222
242
|
>
|
|
223
|
-
<View
|
|
243
|
+
<View
|
|
244
|
+
style={[styles.flex1, { paddingTop: insets.top, paddingBottom: insets.bottom }]}
|
|
245
|
+
accessibilityViewIsModal
|
|
246
|
+
onAccessibilityEscape={onClose}
|
|
247
|
+
>
|
|
224
248
|
{renderHeader()}
|
|
225
249
|
{renderMainContent()}
|
|
226
250
|
{renderFooter()}
|
|
227
251
|
</View>
|
|
228
252
|
</Transition>
|
|
229
253
|
) : (
|
|
230
|
-
<View
|
|
231
|
-
|
|
254
|
+
<View
|
|
255
|
+
style={[styles.fullWrapper, containerStyle]}
|
|
256
|
+
>
|
|
257
|
+
<View
|
|
258
|
+
style={[styles.flex1, { paddingTop: insets.top, paddingBottom: insets.bottom }]}
|
|
259
|
+
accessibilityViewIsModal
|
|
260
|
+
onAccessibilityEscape={onClose}
|
|
261
|
+
>
|
|
232
262
|
{renderHeader()}
|
|
233
263
|
{renderMainContent()}
|
|
234
264
|
{renderFooter()}
|
|
235
265
|
</View>
|
|
236
266
|
</View>
|
|
237
|
-
)
|
|
238
|
-
|
|
239
|
-
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
if (!mounted) return null;
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
return (
|
|
273
|
+
<NativeOverlay
|
|
274
|
+
// closing: while the exit animation plays, no other overlay layers into it.
|
|
275
|
+
closing={!visible}
|
|
276
|
+
onRequestClose={onRequestClose ?? onClose}
|
|
277
|
+
animationType={isAnimatedVariant ? 'none' : 'slide'}
|
|
278
|
+
// `full` animates its own entrance (translateY) with animationType="none"
|
|
279
|
+
// and needs `transparent` so no black background shows behind it
|
|
280
|
+
// while sliding. RN only allows `transparent` together with
|
|
281
|
+
// 'overFullScreen' — with 'pageSheet' it warns that the combination
|
|
282
|
+
// isn't supported. That's why `full` uses overFullScreen: pageSheet's
|
|
283
|
+
// native presentation would be redundant with our animation anyway.
|
|
284
|
+
presentationStyle={
|
|
285
|
+
Platform.OS === 'ios' ? (isFullScreen ? 'fullScreen' : 'overFullScreen') : undefined
|
|
286
|
+
}
|
|
287
|
+
transparent={isOverlay || isFull}
|
|
288
|
+
statusBarTranslucent={statusBarTranslucent}
|
|
289
|
+
hardwareAccelerated={hardwareAccelerated}
|
|
290
|
+
>
|
|
291
|
+
{/* Its own native window: its KeyboardAvoidingView compensates for it, not the root host. */}
|
|
292
|
+
<KeyboardHandled>
|
|
293
|
+
<KeyboardAvoidingView behavior={behavior} keyboardVerticalOffset={keyboardOffset} style={styles.flex1}>
|
|
294
|
+
{/* Insets measured inside this native Modal window, not the app
|
|
295
|
+
root's — they may differ (Android always opens its own window;
|
|
296
|
+
iOS depending on `presentationStyle`). */}
|
|
297
|
+
<ModalSafeAreaBoundary>{renderBody}</ModalSafeAreaBoundary>
|
|
240
298
|
</KeyboardAvoidingView>
|
|
241
|
-
|
|
299
|
+
</KeyboardHandled>
|
|
300
|
+
</NativeOverlay>
|
|
242
301
|
);
|
|
243
302
|
}
|
|
244
303
|
);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React, { memo, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Animated,
|
|
4
|
+
Keyboard,
|
|
5
|
+
Platform,
|
|
4
6
|
StyleSheet,
|
|
5
7
|
Text,
|
|
6
8
|
TouchableOpacity,
|
|
@@ -11,6 +13,7 @@ import {
|
|
|
11
13
|
} from 'react-native';
|
|
12
14
|
import { createStyles } from '../theme/createStyles';
|
|
13
15
|
import { useAllowFontScaling, useColors, useInsets, useTheme } from '../theme/UIProvider';
|
|
16
|
+
import { useReduceMotion } from '../theme/useReduceMotion';
|
|
14
17
|
import { Icon } from '../icons/Icon';
|
|
15
18
|
import type { IconName } from '../icons/types';
|
|
16
19
|
|
|
@@ -18,24 +21,40 @@ export interface NavigationBarItem {
|
|
|
18
21
|
key: string;
|
|
19
22
|
label: string;
|
|
20
23
|
iconName?: IconName;
|
|
21
|
-
/**
|
|
24
|
+
/** Counter over the icon, also read by screen readers. `true` shows only the dot. */
|
|
22
25
|
badge?: number | string | true;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
export interface NavigationBarProps {
|
|
29
|
+
/** The destinations: key, label, and optionally an icon and a badge. */
|
|
26
30
|
items: NavigationBarItem[];
|
|
31
|
+
/** Key of the selected item (controlled). */
|
|
27
32
|
activeKey: string;
|
|
33
|
+
/** Called with the key of the pressed item. */
|
|
28
34
|
onChange: (key: string) => void;
|
|
29
35
|
/** Screen edge where the bar lives. @default 'bottom' */
|
|
30
36
|
position?: 'bottom' | 'top';
|
|
31
|
-
/** @default true */
|
|
37
|
+
/** Shows the label under each icon. @default true */
|
|
32
38
|
showLabels?: boolean;
|
|
33
39
|
/** Adds the safe area inset for the edge where the bar lives. @default true */
|
|
34
40
|
safeArea?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Hides a bottom bar while the keyboard is open, like native tab bars, so
|
|
43
|
+
* it doesn't sit between the field and the keyboard. Only Android needs it:
|
|
44
|
+
* on iOS the keyboard already covers the bar. @default true
|
|
45
|
+
*/
|
|
46
|
+
hideOnKeyboard?: boolean;
|
|
35
47
|
style?: StyleProp<ViewStyle>;
|
|
36
48
|
testID?: string;
|
|
37
49
|
}
|
|
38
50
|
|
|
51
|
+
/** Counter badge: a pill that still fits two digits over a 22pt icon. */
|
|
52
|
+
const BADGE_SIZE = 16;
|
|
53
|
+
const BADGE_DOT_SIZE = 10;
|
|
54
|
+
const BADGE_FONT_SIZE = 10;
|
|
55
|
+
/** Indicator spring: settles fast without bouncing past the tab. */
|
|
56
|
+
const INDICATOR_SPRING = { friction: 9, tension: 90 };
|
|
57
|
+
|
|
39
58
|
const useStyles = createStyles((theme) => ({
|
|
40
59
|
bar: {
|
|
41
60
|
flexDirection: 'row',
|
|
@@ -50,32 +69,32 @@ const useStyles = createStyles((theme) => ({
|
|
|
50
69
|
position: 'absolute',
|
|
51
70
|
top: theme.tokens.spacing.xs,
|
|
52
71
|
bottom: theme.tokens.spacing.xs,
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
72
|
+
// The indicator is positioned against the bar's edge, not its inner box:
|
|
73
|
+
// the horizontal padding has to be added to `left` so it sits centered
|
|
74
|
+
// over the tab and not shifted to the left.
|
|
56
75
|
left: theme.tokens.spacing.xs + theme.tokens.spacing.sm,
|
|
57
76
|
borderRadius: theme.tokens.radius.lg,
|
|
58
77
|
backgroundColor: theme.colors.primarySoft,
|
|
59
78
|
},
|
|
60
79
|
item: { flex: 1, paddingVertical: theme.tokens.spacing.xs },
|
|
61
|
-
itemContent: { alignItems: 'center', justifyContent: 'center', gap:
|
|
80
|
+
itemContent: { alignItems: 'center', justifyContent: 'center', gap: theme.tokens.spacing.xxs },
|
|
62
81
|
label: { fontSize: theme.tokens.fontSize.xs, fontWeight: theme.tokens.fontWeight.medium },
|
|
63
82
|
badge: {
|
|
64
83
|
position: 'absolute',
|
|
65
|
-
top: -
|
|
84
|
+
top: -theme.tokens.spacing.xs,
|
|
66
85
|
left: '50%',
|
|
67
|
-
marginLeft:
|
|
68
|
-
minWidth:
|
|
69
|
-
height:
|
|
70
|
-
paddingHorizontal:
|
|
86
|
+
marginLeft: theme.tokens.spacing.xs,
|
|
87
|
+
minWidth: BADGE_SIZE,
|
|
88
|
+
height: BADGE_SIZE,
|
|
89
|
+
paddingHorizontal: theme.tokens.spacing.xs,
|
|
71
90
|
borderRadius: theme.tokens.radius.full,
|
|
72
91
|
backgroundColor: theme.colors.error,
|
|
73
92
|
alignItems: 'center',
|
|
74
93
|
justifyContent: 'center',
|
|
75
94
|
},
|
|
76
|
-
badgeDot: { minWidth:
|
|
95
|
+
badgeDot: { minWidth: BADGE_DOT_SIZE, height: BADGE_DOT_SIZE, top: -theme.tokens.spacing.xxs, paddingHorizontal: 0 },
|
|
77
96
|
badgeText: {
|
|
78
|
-
fontSize:
|
|
97
|
+
fontSize: BADGE_FONT_SIZE,
|
|
79
98
|
fontWeight: theme.tokens.fontWeight.bold,
|
|
80
99
|
color: theme.colors.onError,
|
|
81
100
|
},
|
|
@@ -85,10 +104,20 @@ const ICON_SIZE = 22;
|
|
|
85
104
|
|
|
86
105
|
/**
|
|
87
106
|
* NavigationBar
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
107
|
+
* Tab navigation bar with the same look and the same transitions on iOS and
|
|
108
|
+
* Android: the indicator slides to the active tab and its content grows and
|
|
109
|
+
* takes the accent color with a cross-fade.
|
|
110
|
+
* It doesn't navigate on its own — it reports the tapped tab and the consumer decides.
|
|
111
|
+
*
|
|
112
|
+
* Design:
|
|
113
|
+
* - Jakob's law: the tab bar people know from every app, at the bottom by
|
|
114
|
+
* default, icon over label.
|
|
115
|
+
* - Similarity + Von Restorff: every tab looks the same except the active
|
|
116
|
+
* one, which alone gets the accent and the indicator.
|
|
117
|
+
* - Continuity: the indicator slides from tab to tab instead of jumping
|
|
118
|
+
* (in place with Reduce Motion).
|
|
119
|
+
* - Fitts's law: the whole column is the target, not just the icon.
|
|
120
|
+
* - Hick's law: meant for 3–5 destinations.
|
|
92
121
|
*/
|
|
93
122
|
export const NavigationBar = memo(
|
|
94
123
|
({
|
|
@@ -98,6 +127,7 @@ export const NavigationBar = memo(
|
|
|
98
127
|
position = 'bottom',
|
|
99
128
|
showLabels = true,
|
|
100
129
|
safeArea = true,
|
|
130
|
+
hideOnKeyboard = true,
|
|
101
131
|
style,
|
|
102
132
|
testID,
|
|
103
133
|
}: NavigationBarProps) => {
|
|
@@ -106,8 +136,23 @@ export const NavigationBar = memo(
|
|
|
106
136
|
const styles = useStyles();
|
|
107
137
|
const insets = useInsets();
|
|
108
138
|
const allowFontScaling = useAllowFontScaling();
|
|
139
|
+
const reduceMotion = useReduceMotion();
|
|
109
140
|
|
|
110
141
|
const [barWidth, setBarWidth] = useState(0);
|
|
142
|
+
const [keyboardOpen, setKeyboardOpen] = useState(false);
|
|
143
|
+
|
|
144
|
+
// On Android the window shrinks with the keyboard and the bar would end up
|
|
145
|
+
// floating above it, between the field and the keys. On iOS the keyboard
|
|
146
|
+
// covers it: no need (and hiding it would move the layout midway through
|
|
147
|
+
// the keyboard animation).
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
if (!hideOnKeyboard || position !== 'bottom' || Platform.OS !== 'android') return;
|
|
150
|
+
const subs = [
|
|
151
|
+
Keyboard.addListener('keyboardDidShow', () => setKeyboardOpen(true)),
|
|
152
|
+
Keyboard.addListener('keyboardDidHide', () => setKeyboardOpen(false)),
|
|
153
|
+
];
|
|
154
|
+
return () => subs.forEach((sub) => sub.remove());
|
|
155
|
+
}, [hideOnKeyboard, position]);
|
|
111
156
|
const slide = useRef(new Animated.Value(0)).current;
|
|
112
157
|
const placed = useRef(false);
|
|
113
158
|
|
|
@@ -120,15 +165,16 @@ export const NavigationBar = memo(
|
|
|
120
165
|
useEffect(() => {
|
|
121
166
|
if (itemWidth <= 0) return;
|
|
122
167
|
const to = activeIndex * itemWidth;
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
|
|
168
|
+
// On the first layout the indicator appears in place; animating it from 0
|
|
169
|
+
// would be a slide the user didn't ask for.
|
|
170
|
+
// With Reduce Motion it moves without the slide, too.
|
|
171
|
+
if (!placed.current || reduceMotion) {
|
|
126
172
|
placed.current = true;
|
|
127
173
|
slide.setValue(to);
|
|
128
174
|
return;
|
|
129
175
|
}
|
|
130
|
-
Animated.spring(slide, { toValue: to, useNativeDriver: true,
|
|
131
|
-
}, [activeIndex, itemWidth, slide]);
|
|
176
|
+
Animated.spring(slide, { toValue: to, useNativeDriver: true, ...INDICATOR_SPRING }).start();
|
|
177
|
+
}, [activeIndex, itemWidth, slide, reduceMotion]);
|
|
132
178
|
|
|
133
179
|
const onLayout = (e: LayoutChangeEvent) => {
|
|
134
180
|
const next = e.nativeEvent.layout.width - theme.tokens.spacing.xs * 2;
|
|
@@ -146,6 +192,8 @@ export const NavigationBar = memo(
|
|
|
146
192
|
</>
|
|
147
193
|
);
|
|
148
194
|
|
|
195
|
+
if (keyboardOpen) return null;
|
|
196
|
+
|
|
149
197
|
return (
|
|
150
198
|
<View
|
|
151
199
|
testID={testID}
|
|
@@ -196,10 +244,12 @@ export const NavigationBar = memo(
|
|
|
196
244
|
accessibilityRole="tab"
|
|
197
245
|
accessibilityLabel={item.label}
|
|
198
246
|
accessibilityState={{ selected: active }}
|
|
247
|
+
// The badge is drawn, not text the reader reaches: its count goes in the value.
|
|
248
|
+
accessibilityValue={typeof item.badge === 'number' || typeof item.badge === 'string' ? { text: String(item.badge) } : undefined}
|
|
199
249
|
>
|
|
200
250
|
<Animated.View style={[styles.itemContent, { transform: [{ scale }] }]}>
|
|
201
251
|
{renderContent(item, colors.textLight)}
|
|
202
|
-
{/*
|
|
252
|
+
{/* Decorative copy: if it weren't hidden, the reader would read the label twice. */}
|
|
203
253
|
<Animated.View
|
|
204
254
|
pointerEvents="none"
|
|
205
255
|
accessibilityElementsHidden
|