orn-ui 0.2.9 → 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 +67 -52
- package/README.md +5 -9
- 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 +197 -156
- 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 +199 -158
- 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 +223 -165
- 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/atoms/Input.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import React, { memo, useRef, useState } from 'react';
|
|
1
|
+
import React, { forwardRef, memo, useEffect, useImperativeHandle, useRef, useState, type ComponentRef } from 'react';
|
|
2
2
|
import {
|
|
3
|
+
AccessibilityInfo,
|
|
3
4
|
ActivityIndicator,
|
|
4
5
|
Animated,
|
|
5
6
|
Text,
|
|
@@ -11,21 +12,51 @@ import {
|
|
|
11
12
|
type ViewStyle,
|
|
12
13
|
} from 'react-native';
|
|
13
14
|
import { createStyles } from '../theme/createStyles';
|
|
14
|
-
import { useAllowFontScaling, useColors } from '../theme/UIProvider';
|
|
15
|
+
import { useAllowFontScaling, useColors, useLabels, useTheme } from '../theme/UIProvider';
|
|
15
16
|
import { Icon } from '../icons/Icon';
|
|
16
17
|
import type { IconName } from '../icons/types';
|
|
18
|
+
import { useKeyboardField } from '../theme/useKeyboardField';
|
|
19
|
+
import { validateInputValue, type InputRules } from './inputValidation';
|
|
20
|
+
|
|
21
|
+
export type { InputRules, InputRuleValue } from './inputValidation';
|
|
22
|
+
|
|
23
|
+
/** The TextInput instance, plus `validate()` to check the field on demand (e.g. on submit). */
|
|
24
|
+
export type InputHandle = ComponentRef<typeof TextInput> & {
|
|
25
|
+
/** Runs the rules, shows the error (if any) and returns it. */
|
|
26
|
+
validate: () => string | undefined;
|
|
27
|
+
};
|
|
17
28
|
|
|
18
29
|
export interface InputProps extends Omit<TextInputProps, 'style'> {
|
|
30
|
+
/** Text above the field; also its accessible name (falls back to `placeholder`). */
|
|
19
31
|
label?: string;
|
|
20
|
-
/** Shows an asterisk next to the label
|
|
32
|
+
/** Shows an asterisk next to the label, and an empty value fails validation (`labels.requiredError`). */
|
|
21
33
|
required?: boolean;
|
|
34
|
+
/** Error shown under the field. Takes precedence over the built-in validation. */
|
|
22
35
|
error?: string;
|
|
36
|
+
/** Built-in validation: length limits, a pattern and/or a custom check. */
|
|
37
|
+
rules?: InputRules;
|
|
38
|
+
/**
|
|
39
|
+
* When the rules run: on leaving the field, on every change, or only through
|
|
40
|
+
* `ref.validate()`. Once an error shows, it re-checks on every change so it
|
|
41
|
+
* clears as soon as the value is fixed. @default 'blur'
|
|
42
|
+
*/
|
|
43
|
+
validateOn?: 'blur' | 'change' | 'submit';
|
|
44
|
+
/** Called with the error (or undefined) every time the rules run. */
|
|
45
|
+
onValidate?: (error: string | undefined) => void;
|
|
46
|
+
/** Style of the outer wrapper (label, field and error). */
|
|
23
47
|
containerStyle?: StyleProp<ViewStyle>;
|
|
24
48
|
style?: TextInputProps['style'];
|
|
49
|
+
/** Icon shown inside the field, to the left of the text. */
|
|
25
50
|
leftIconName?: IconName;
|
|
51
|
+
/** Icon button inside the field, on the right. Ignored with `isPassword` or `isLoading`. */
|
|
26
52
|
rightIconName?: IconName;
|
|
53
|
+
/** Called when the `rightIconName` button is pressed. Without it the button is disabled. */
|
|
27
54
|
onRightIconPress?: () => void;
|
|
55
|
+
/** Accessible name of the `rightIconName` button. @default labels.clear */
|
|
56
|
+
rightIconAccessibilityLabel?: string;
|
|
57
|
+
/** Hides the text and adds an eye button to show or hide it. @default false */
|
|
28
58
|
isPassword?: boolean;
|
|
59
|
+
/** Shows a small spinner on the right, in place of the right icon. @default false */
|
|
29
60
|
isLoading?: boolean;
|
|
30
61
|
}
|
|
31
62
|
|
|
@@ -54,25 +85,57 @@ const useStyles = createStyles((theme) => ({
|
|
|
54
85
|
color: theme.colors.text,
|
|
55
86
|
},
|
|
56
87
|
leftIcon: { marginLeft: theme.tokens.spacing.lg, marginRight: -theme.tokens.spacing.xs },
|
|
57
|
-
|
|
88
|
+
// 20 icon + md padding (12) per side = 44pt touch area (Fitts).
|
|
89
|
+
rightIcon: { padding: theme.tokens.spacing.md, marginRight: theme.tokens.spacing.xxs },
|
|
90
|
+
// Read-only: no fill, so it doesn't look like a field you can tap
|
|
91
|
+
// (affordance), but the text keeps its contrast to stay readable.
|
|
92
|
+
readOnly: { backgroundColor: 'transparent' },
|
|
58
93
|
errorText: { marginTop: theme.tokens.spacing.xs, fontSize: theme.tokens.fontSize.sm, color: theme.colors.errorText },
|
|
59
94
|
}));
|
|
60
95
|
|
|
61
96
|
/**
|
|
62
97
|
* Input
|
|
63
|
-
*
|
|
64
|
-
* useNativeDriver:
|
|
65
|
-
*
|
|
98
|
+
* The border animates its color between border/primary/error with Animated
|
|
99
|
+
* (no useNativeDriver: color drivers in RN without Fabric are only reliable
|
|
100
|
+
* on the JS thread; the cost is negligible, it animates one border).
|
|
101
|
+
*
|
|
102
|
+
* Gestalt:
|
|
103
|
+
* - Proximity: label (`spacing.sm` above) and error (`spacing.xs` below) sit
|
|
104
|
+
* right next to the field and the next field is `spacing.lg` away: each
|
|
105
|
+
* label and its error read with their field, not with the neighbor.
|
|
106
|
+
* - Common region: left icon, text and right action share the same border
|
|
107
|
+
* and background, so they read as a single control.
|
|
108
|
+
* - Focal point: the border turns `primary` on focus and `error` on error;
|
|
109
|
+
* the error is also written out (not just color).
|
|
110
|
+
*
|
|
111
|
+
* Accessibility: the accessible name includes "required" when applicable, the
|
|
112
|
+
* error is announced as a hint, and the eye and right-action buttons have a
|
|
113
|
+
* 44pt touch area and texts from `labels` (translatable).
|
|
114
|
+
*
|
|
115
|
+
* Keyboard: on focus it registers with the root UIProvider's host, which
|
|
116
|
+
* lifts the app just enough for the whole field (label, field and error) to
|
|
117
|
+
* sit above the keyboard — without depending on Screen or a ScrollView. What
|
|
118
|
+
* you type is always visible.
|
|
119
|
+
*
|
|
120
|
+
* Validation: `required` and `rules` run when leaving the field (`validateOn`),
|
|
121
|
+
* the error appears in writing, is announced to the screen reader and, once
|
|
122
|
+
* visible, is revalidated on every change so it disappears as soon as it is
|
|
123
|
+
* fixed. An `error` passed by hand overrides the internal validation.
|
|
66
124
|
*/
|
|
67
125
|
export const Input = memo(
|
|
68
|
-
({
|
|
126
|
+
forwardRef<InputHandle, InputProps>(({
|
|
69
127
|
label,
|
|
70
128
|
required = false,
|
|
71
|
-
error,
|
|
129
|
+
error: errorProp,
|
|
130
|
+
rules,
|
|
131
|
+
validateOn = 'blur',
|
|
132
|
+
onValidate,
|
|
133
|
+
onChangeText,
|
|
72
134
|
containerStyle,
|
|
73
135
|
leftIconName,
|
|
74
136
|
rightIconName,
|
|
75
137
|
onRightIconPress,
|
|
138
|
+
rightIconAccessibilityLabel,
|
|
76
139
|
isPassword = false,
|
|
77
140
|
isLoading = false,
|
|
78
141
|
style,
|
|
@@ -80,43 +143,85 @@ export const Input = memo(
|
|
|
80
143
|
onBlur,
|
|
81
144
|
testID,
|
|
82
145
|
...props
|
|
83
|
-
}
|
|
146
|
+
}, ref) => {
|
|
84
147
|
const colors = useColors();
|
|
85
148
|
const styles = useStyles();
|
|
86
149
|
const allowFontScaling = useAllowFontScaling();
|
|
150
|
+
const labels = useLabels();
|
|
151
|
+
const theme = useTheme();
|
|
152
|
+
const readOnly = props.editable === false;
|
|
87
153
|
const [isFocused, setIsFocused] = useState(false);
|
|
88
154
|
const [showPassword, setShowPassword] = useState(false);
|
|
89
155
|
const focusProgress = useRef(new Animated.Value(0)).current;
|
|
156
|
+
const inputRef = useRef<ComponentRef<typeof TextInput>>(null);
|
|
157
|
+
const containerRef = useRef<ComponentRef<typeof View>>(null);
|
|
158
|
+
const [internalError, setInternalError] = useState<string | undefined>(undefined);
|
|
159
|
+
// Last known value: the controlled one (`value`) or what was typed (uncontrolled).
|
|
160
|
+
const valueRef = useRef(props.value ?? props.defaultValue ?? '');
|
|
161
|
+
if (props.value !== undefined) valueRef.current = props.value;
|
|
162
|
+
const error = errorProp ?? internalError;
|
|
163
|
+
|
|
164
|
+
const runValidation = () => {
|
|
165
|
+
const next = validateInputValue(valueRef.current, { required, rules }, labels);
|
|
166
|
+
setInternalError(next);
|
|
167
|
+
onValidate?.(next);
|
|
168
|
+
return next;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
useImperativeHandle(ref, () => Object.assign(inputRef.current as ComponentRef<typeof TextInput>, { validate: runValidation }));
|
|
172
|
+
|
|
173
|
+
// The new error is announced right away, not only as a hint when returning to the field.
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
if (internalError && errorProp === undefined) AccessibilityInfo.announceForAccessibility(internalError);
|
|
176
|
+
}, [internalError, errorProp]);
|
|
177
|
+
|
|
178
|
+
const keyboard = useKeyboardField(containerRef);
|
|
179
|
+
|
|
180
|
+
// If the error appears or changes while the field is focused, the block grows:
|
|
181
|
+
// a readjustment is requested so the error line isn't covered either.
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
if (isFocused) keyboard.focus();
|
|
184
|
+
}, [error, isFocused, keyboard]);
|
|
90
185
|
|
|
91
186
|
const handleFocus: TextInputProps['onFocus'] = (e) => {
|
|
92
187
|
setIsFocused(true);
|
|
93
|
-
|
|
188
|
+
keyboard.focus();
|
|
189
|
+
Animated.timing(focusProgress, { toValue: 1, duration: theme.tokens.duration.base, useNativeDriver: false }).start();
|
|
94
190
|
onFocus?.(e);
|
|
95
191
|
};
|
|
96
192
|
|
|
97
193
|
const handleBlur: TextInputProps['onBlur'] = (e) => {
|
|
98
194
|
setIsFocused(false);
|
|
99
|
-
|
|
195
|
+
keyboard.blur();
|
|
196
|
+
if (validateOn === 'blur') runValidation();
|
|
197
|
+
Animated.timing(focusProgress, { toValue: 0, duration: theme.tokens.duration.base, useNativeDriver: false }).start();
|
|
100
198
|
onBlur?.(e);
|
|
101
199
|
};
|
|
102
200
|
|
|
201
|
+
const handleChangeText = (text: string) => {
|
|
202
|
+
valueRef.current = text;
|
|
203
|
+
onChangeText?.(text);
|
|
204
|
+
if (validateOn === 'change' || internalError) runValidation();
|
|
205
|
+
};
|
|
206
|
+
|
|
103
207
|
const borderColor = error
|
|
104
208
|
? colors.error
|
|
105
209
|
: focusProgress.interpolate({ outputRange: [colors.border, colors.primary], inputRange: [0, 1] });
|
|
106
210
|
|
|
107
211
|
return (
|
|
108
|
-
<View style={[styles.container, containerStyle]} testID={testID}>
|
|
109
|
-
{label && (
|
|
212
|
+
<View ref={containerRef} style={[styles.container, containerStyle]} testID={testID}>
|
|
213
|
+
{!!label && (
|
|
110
214
|
<Text allowFontScaling={allowFontScaling} style={styles.label}>
|
|
111
215
|
{label}
|
|
112
216
|
{required && <Text style={styles.required}> *</Text>}
|
|
113
217
|
</Text>
|
|
114
218
|
)}
|
|
115
219
|
|
|
116
|
-
<Animated.View style={[styles.inputWrapper, { borderColor }]}>
|
|
220
|
+
<Animated.View style={[styles.inputWrapper, readOnly && styles.readOnly, { borderColor }]}>
|
|
117
221
|
{leftIconName && <Icon name={leftIconName} size={20} color={colors.textLight} style={styles.leftIcon} />}
|
|
118
222
|
|
|
119
223
|
<TextInput
|
|
224
|
+
ref={inputRef}
|
|
120
225
|
style={[styles.input, style]}
|
|
121
226
|
placeholderTextColor={colors.textLight}
|
|
122
227
|
onFocus={handleFocus}
|
|
@@ -124,8 +229,13 @@ export const Input = memo(
|
|
|
124
229
|
secureTextEntry={isPassword && !showPassword}
|
|
125
230
|
allowFontScaling={allowFontScaling}
|
|
126
231
|
textAlignVertical="center"
|
|
127
|
-
accessibilityLabel={
|
|
232
|
+
accessibilityLabel={
|
|
233
|
+
label || props.placeholder ? `${label ?? props.placeholder}${required ? `, ${labels.required}` : ''}` : undefined
|
|
234
|
+
}
|
|
235
|
+
accessibilityHint={error || undefined}
|
|
236
|
+
accessibilityState={{ disabled: readOnly, busy: isLoading }}
|
|
128
237
|
{...props}
|
|
238
|
+
onChangeText={handleChangeText}
|
|
129
239
|
/>
|
|
130
240
|
|
|
131
241
|
{isLoading ? (
|
|
@@ -137,7 +247,7 @@ export const Input = memo(
|
|
|
137
247
|
onPress={() => setShowPassword((v) => !v)}
|
|
138
248
|
style={styles.rightIcon}
|
|
139
249
|
accessibilityRole="button"
|
|
140
|
-
accessibilityLabel={showPassword ?
|
|
250
|
+
accessibilityLabel={showPassword ? labels.hidePassword : labels.showPassword}
|
|
141
251
|
>
|
|
142
252
|
<Icon name={showPassword ? 'eye-off' : 'eye'} size={20} color={colors.textLight} />
|
|
143
253
|
</TouchableOpacity>
|
|
@@ -147,7 +257,7 @@ export const Input = memo(
|
|
|
147
257
|
style={styles.rightIcon}
|
|
148
258
|
disabled={!onRightIconPress}
|
|
149
259
|
accessibilityRole="button"
|
|
150
|
-
accessibilityLabel=
|
|
260
|
+
accessibilityLabel={rightIconAccessibilityLabel ?? labels.clear}
|
|
151
261
|
>
|
|
152
262
|
<Icon name={rightIconName} size={20} color={colors.textLight} />
|
|
153
263
|
</TouchableOpacity>
|
|
@@ -161,6 +271,6 @@ export const Input = memo(
|
|
|
161
271
|
)}
|
|
162
272
|
</View>
|
|
163
273
|
);
|
|
164
|
-
}
|
|
274
|
+
})
|
|
165
275
|
);
|
|
166
276
|
Input.displayName = 'Input';
|
|
@@ -4,45 +4,89 @@ import { createStyles } from '../theme/createStyles';
|
|
|
4
4
|
import { useAllowFontScaling } from '../theme/UIProvider';
|
|
5
5
|
|
|
6
6
|
export interface KeyValueRowProps {
|
|
7
|
+
/** Left side. A string or number gets the default label style; any other node renders as is. */
|
|
7
8
|
label: React.ReactNode;
|
|
9
|
+
/** Right side. A string or number gets the default value style (tabular digits); any other node renders as is. */
|
|
8
10
|
value: React.ReactNode;
|
|
9
11
|
style?: StyleProp<ViewStyle>;
|
|
12
|
+
/** Only applies when `label` is a string or number. */
|
|
10
13
|
labelStyle?: StyleProp<TextStyle>;
|
|
14
|
+
/** Only applies when `value` is a string or number. */
|
|
11
15
|
valueStyle?: StyleProp<TextStyle>;
|
|
16
|
+
testID?: string;
|
|
12
17
|
}
|
|
13
18
|
|
|
14
19
|
const useStyles = createStyles((theme) => ({
|
|
15
|
-
row: {
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
row: {
|
|
21
|
+
flexDirection: 'row',
|
|
22
|
+
justifyContent: 'space-between',
|
|
23
|
+
alignItems: 'center',
|
|
24
|
+
gap: theme.tokens.spacing.md,
|
|
25
|
+
},
|
|
26
|
+
// Two texts: aligned on the first line, so a value that wraps onto
|
|
27
|
+
// several lines still reads next to its label.
|
|
28
|
+
rowText: { alignItems: 'baseline' },
|
|
29
|
+
// The label keeps its natural width up to half the row; the value
|
|
30
|
+
// shrinks and wraps instead of pushing the row off the screen.
|
|
31
|
+
label: {
|
|
32
|
+
flexShrink: 0,
|
|
33
|
+
maxWidth: '50%',
|
|
34
|
+
fontSize: theme.tokens.fontSize.sm,
|
|
35
|
+
lineHeight: theme.tokens.lineHeight.sm,
|
|
36
|
+
fontWeight: theme.tokens.fontWeight.semibold,
|
|
37
|
+
color: theme.colors.textLight,
|
|
38
|
+
},
|
|
39
|
+
value: {
|
|
40
|
+
flexShrink: 1,
|
|
41
|
+
fontSize: theme.tokens.fontSize.sm,
|
|
42
|
+
lineHeight: theme.tokens.lineHeight.sm,
|
|
43
|
+
textAlign: 'right',
|
|
44
|
+
color: theme.colors.text,
|
|
45
|
+
// Fixed-width digits: in a column of amounts the figures line up
|
|
46
|
+
// across rows.
|
|
47
|
+
fontVariant: ['tabular-nums'],
|
|
48
|
+
},
|
|
18
49
|
}));
|
|
19
50
|
|
|
51
|
+
const isPrimitive = (node: React.ReactNode): node is string | number =>
|
|
52
|
+
typeof node === 'string' || typeof node === 'number';
|
|
53
|
+
|
|
20
54
|
/**
|
|
21
55
|
* KeyValueRow
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
56
|
+
* Label (left) / value (right) row. If label/value are a string or number,
|
|
57
|
+
* they render with the default style; if they already come wrapped in a
|
|
58
|
+
* custom component, they are kept as is.
|
|
59
|
+
*
|
|
60
|
+
* Gestalt, alignment and similarity: labels share color and weight and values
|
|
61
|
+
* align to the right edge with tabular digits, so a stack of rows reads as
|
|
62
|
+
* two columns — what on the left, how much on the right.
|
|
63
|
+
* With a text label and value, the row is a single accessibility node
|
|
64
|
+
* ("Subtotal, $300.00"); if either is a custom node (a Badge, a button) it
|
|
65
|
+
* isn't merged, so as not to hide what that node announces or lets you tap.
|
|
25
66
|
*/
|
|
26
|
-
export const KeyValueRow = memo(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
67
|
+
export const KeyValueRow = memo(
|
|
68
|
+
({ label, value, style, labelStyle, valueStyle, testID }: KeyValueRowProps) => {
|
|
69
|
+
const styles = useStyles();
|
|
70
|
+
const allowFontScaling = useAllowFontScaling();
|
|
71
|
+
const merge = isPrimitive(label) && isPrimitive(value);
|
|
72
|
+
return (
|
|
73
|
+
<View style={[styles.row, merge && styles.rowText, style]} accessible={merge || undefined} testID={testID}>
|
|
74
|
+
{isPrimitive(label) ? (
|
|
75
|
+
<Text allowFontScaling={allowFontScaling} style={[styles.label, labelStyle]}>
|
|
76
|
+
{label}
|
|
77
|
+
</Text>
|
|
78
|
+
) : (
|
|
79
|
+
label
|
|
80
|
+
)}
|
|
81
|
+
{isPrimitive(value) ? (
|
|
82
|
+
<Text allowFontScaling={allowFontScaling} style={[styles.value, valueStyle]}>
|
|
83
|
+
{value}
|
|
84
|
+
</Text>
|
|
85
|
+
) : (
|
|
86
|
+
value
|
|
87
|
+
)}
|
|
88
|
+
</View>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
);
|
|
48
92
|
KeyValueRow.displayName = 'KeyValueRow';
|
|
@@ -7,32 +7,54 @@ import {
|
|
|
7
7
|
type StyleProp,
|
|
8
8
|
type ViewStyle,
|
|
9
9
|
} from 'react-native';
|
|
10
|
+
import { useReduceMotion } from './Transition';
|
|
10
11
|
|
|
11
|
-
export interface PressableScaleProps extends Omit<PressableProps, 'style'> {
|
|
12
|
+
export interface PressableScaleProps extends Omit<PressableProps, 'style' | 'children'> {
|
|
12
13
|
/** Target scale when pressed. @default 0.96 */
|
|
13
14
|
scaleTo?: number;
|
|
14
15
|
style?: StyleProp<ViewStyle>;
|
|
16
|
+
/** Pressable content. */
|
|
15
17
|
children: React.ReactNode;
|
|
16
18
|
}
|
|
17
19
|
|
|
20
|
+
/** Short spring with almost no bounce: feedback arrives in ~100 ms (Doherty). */
|
|
21
|
+
const PRESS_SPRING = { speed: 50, bounciness: 6 } as const;
|
|
22
|
+
|
|
18
23
|
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
|
|
19
24
|
|
|
20
25
|
/**
|
|
21
26
|
* PressableScale
|
|
22
|
-
*
|
|
23
|
-
* (useNativeDriver: true —
|
|
24
|
-
*
|
|
27
|
+
* Tactile "shrink" feedback on press, with RN's Animated.spring
|
|
28
|
+
* (useNativeDriver: true — runs on the native thread, no JS cost per frame).
|
|
29
|
+
* Doesn't depend on reanimated: the whole library is zero-dependency.
|
|
30
|
+
*
|
|
31
|
+
* Gestalt, figure/ground: as it sinks, the pressed element separates for an
|
|
32
|
+
* instant from the rest and confirms what was touched (Doherty: immediate
|
|
33
|
+
* response). Announces itself as a button by default (`accessibilityRole` can
|
|
34
|
+
* be changed) and, when disabled, exposes `disabled` to the screen reader.
|
|
35
|
+
* With Reduce Motion it doesn't scale.
|
|
25
36
|
*/
|
|
26
37
|
export const PressableScale = memo(
|
|
27
|
-
({
|
|
38
|
+
({
|
|
39
|
+
scaleTo = 0.96,
|
|
40
|
+
style,
|
|
41
|
+
children,
|
|
42
|
+
onPressIn,
|
|
43
|
+
onPressOut,
|
|
44
|
+
disabled,
|
|
45
|
+
accessibilityRole = 'button',
|
|
46
|
+
accessibilityState,
|
|
47
|
+
...props
|
|
48
|
+
}: PressableScaleProps) => {
|
|
28
49
|
const scale = useRef(new Animated.Value(1)).current;
|
|
50
|
+
const reduceMotion = useReduceMotion();
|
|
29
51
|
|
|
30
52
|
const animateTo = (value: number) => {
|
|
53
|
+
if (reduceMotion) return;
|
|
31
54
|
Animated.spring(scale, {
|
|
32
55
|
toValue: value,
|
|
33
56
|
useNativeDriver: true,
|
|
34
|
-
|
|
35
|
-
bounciness: 6,
|
|
57
|
+
...PRESS_SPRING,
|
|
36
58
|
}).start();
|
|
37
59
|
};
|
|
38
60
|
|
|
@@ -49,6 +71,8 @@ export const PressableScale = memo(
|
|
|
49
71
|
return (
|
|
50
72
|
<AnimatedPressable
|
|
51
73
|
{...props}
|
|
74
|
+
accessibilityRole={accessibilityRole}
|
|
75
|
+
accessibilityState={{ ...accessibilityState, disabled: !!disabled }}
|
|
52
76
|
disabled={disabled}
|
|
53
77
|
onPressIn={handlePressIn}
|
|
54
78
|
onPressOut={handlePressOut}
|
package/src/atoms/ShinyText.tsx
CHANGED
|
@@ -26,11 +26,11 @@ export interface ShinyTextProps {
|
|
|
26
26
|
spread?: number;
|
|
27
27
|
/** When false it renders plain text in `shineColor`. @default true */
|
|
28
28
|
animated?: boolean;
|
|
29
|
-
/** Resting color of the characters. @default theme.colors.textLight */
|
|
29
|
+
/** Resting color of the characters. Keep it readable on its own (WCAG AA): the shine is decorative. @default theme.colors.textLight */
|
|
30
30
|
color?: string;
|
|
31
31
|
/** Color of the band that travels across. @default theme.colors.primary */
|
|
32
32
|
shineColor?: string;
|
|
33
|
-
/** @default 'left' */
|
|
33
|
+
/** Horizontal alignment of the line. @default 'left' */
|
|
34
34
|
align?: 'left' | 'center' | 'right';
|
|
35
35
|
/** Typography only: `color` and `shineColor` win over any color set here. */
|
|
36
36
|
style?: StyleProp<TextStyle>;
|
|
@@ -49,11 +49,11 @@ const useStyles = createStyles((theme) => ({
|
|
|
49
49
|
color: theme.colors.text,
|
|
50
50
|
},
|
|
51
51
|
row: { flexDirection: 'row', flexWrap: 'wrap' },
|
|
52
|
-
//
|
|
53
|
-
//
|
|
52
|
+
// Only top/left: an absoluteFill would stretch the letter to the group's width
|
|
53
|
+
// and realign it. Anchored to the corner it lands exactly on the one below.
|
|
54
54
|
overlay: { position: 'absolute', top: 0, left: 0 },
|
|
55
|
-
//
|
|
56
|
-
//
|
|
55
|
+
// A word and the spaces that follow it: line breaks happen between
|
|
56
|
+
// groups, never between the letters of a word.
|
|
57
57
|
group: { flexDirection: 'row' },
|
|
58
58
|
}));
|
|
59
59
|
|
|
@@ -63,7 +63,7 @@ const ALIGN: Record<'left' | 'center' | 'right', ViewStyle['justifyContent']> =
|
|
|
63
63
|
right: 'flex-end',
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
-
/**
|
|
66
|
+
/** A word with the spaces that follow it, and the index of its first letter. */
|
|
67
67
|
interface Group {
|
|
68
68
|
start: number;
|
|
69
69
|
chars: string[];
|
|
@@ -79,8 +79,8 @@ function toGroups(text: string): Group[] {
|
|
|
79
79
|
if (current.length === 0) start = index;
|
|
80
80
|
current.push(char);
|
|
81
81
|
const next = chars[index + 1];
|
|
82
|
-
//
|
|
83
|
-
//
|
|
82
|
+
// Closes the group when the run of spaces following the word ends:
|
|
83
|
+
// that way the space travels with it and never starts a line on its own.
|
|
84
84
|
const isSpace = /\s/.test(char);
|
|
85
85
|
if (isSpace && next !== undefined && !/\s/.test(next)) {
|
|
86
86
|
groups.push({ start, chars: current });
|
|
@@ -94,23 +94,23 @@ function toGroups(text: string): Group[] {
|
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
96
|
* ShinyText
|
|
97
|
-
*
|
|
98
|
-
* `background-clip: text`
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
97
|
+
* A band of light sweeps across the text from left to right. Without
|
|
98
|
+
* `background-clip: text` or masks —which React Native lacks in the supported
|
|
99
|
+
* range— the shine is composed letter by letter: each one carries its resting
|
|
100
|
+
* color and, overlaid on top, the same letter in the shine color with animated
|
|
101
|
+
* opacity. The band is a moving interpolation window: the only thing that
|
|
102
|
+
* changes per frame is `opacity`, which means the whole animation runs on the
|
|
103
|
+
* native thread and JS takes part in no frame.
|
|
104
104
|
*
|
|
105
|
-
* Gestalt,
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
105
|
+
* Gestalt, common fate: the letters light up in sequence and at the same
|
|
106
|
+
* rhythm, so they read as one moving thing —a word lighting up— and not as N
|
|
107
|
+
* letters blinking on their own. That is why the band width is relative to
|
|
108
|
+
* the text and not a fixed number of pixels: a long title and a short one take
|
|
109
|
+
* the same time and are perceived the same.
|
|
110
110
|
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
111
|
+
* With "reduce motion" on, or with `animated={false}`, the text renders flat
|
|
112
|
+
* in `shineColor` —legible, a single node and selectable— because the effect
|
|
113
|
+
* is decorative and nothing it communicates lives in the shine.
|
|
114
114
|
*/
|
|
115
115
|
export const ShinyText = memo(
|
|
116
116
|
({
|
|
@@ -132,9 +132,9 @@ export const ShinyText = memo(
|
|
|
132
132
|
const progress = useRef(new Animated.Value(0)).current;
|
|
133
133
|
|
|
134
134
|
const base = color ?? theme.colors.textLight;
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
135
|
+
// The accent, not `text`: against `textLight` the difference is only in
|
|
136
|
+
// luminance and the sweep is barely visible. The shine changes hue as well
|
|
137
|
+
// as lightness, which is what makes the motion readable.
|
|
138
138
|
const shine = shineColor ?? theme.colors.primary;
|
|
139
139
|
const running = animated && !reduceMotion && text.length > 0;
|
|
140
140
|
|
|
@@ -170,9 +170,9 @@ export const ShinyText = memo(
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
const total = Array.from(text).length;
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
173
|
+
// The band enters on the left and exits on the right, so the normalized
|
|
174
|
+
// path measures 1 + 2·spread. `half` is half a band on that scale: the
|
|
175
|
+
// stretch of progress a letter takes to light up.
|
|
176
176
|
const half = spread / (1 + 2 * spread);
|
|
177
177
|
|
|
178
178
|
return (
|
|
@@ -188,7 +188,7 @@ export const ShinyText = memo(
|
|
|
188
188
|
{group.chars.map((char, offset) => {
|
|
189
189
|
const index = group.start + offset;
|
|
190
190
|
const position = total === 1 ? 0.5 : index / (total - 1);
|
|
191
|
-
//
|
|
191
|
+
// Progress at which the center of the band falls on this letter.
|
|
192
192
|
const peak = (position + spread) / (1 + 2 * spread);
|
|
193
193
|
const charStyle: StyleProp<TextStyle> = [styles.text, style];
|
|
194
194
|
|