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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useRef, type ComponentRef } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Animated,
|
|
4
4
|
ScrollView,
|
|
@@ -24,8 +24,11 @@ export interface OptionWheelOption<T> {
|
|
|
24
24
|
export type OptionWheelVariant = 'window' | 'spotlight';
|
|
25
25
|
|
|
26
26
|
export interface OptionWheelProps<T> {
|
|
27
|
+
/** The range, in order. Each option has a label, its value, and may be disabled. */
|
|
27
28
|
options: OptionWheelOption<T>[];
|
|
29
|
+
/** Value of the option in the centre row (controlled). */
|
|
28
30
|
selectedValue: T | undefined;
|
|
31
|
+
/** Called with the value of the option the wheel settles on. */
|
|
29
32
|
onSelect: (value: T) => void;
|
|
30
33
|
/** Title above the wheel. */
|
|
31
34
|
label?: string;
|
|
@@ -64,26 +67,27 @@ export interface OptionWheelProps<T> {
|
|
|
64
67
|
curveRadius?: number;
|
|
65
68
|
/** Which side the wheel's centre is on. @default 'left' */
|
|
66
69
|
curveFrom?: 'left' | 'right';
|
|
70
|
+
/** Dims the wheel and stops it from turning. @default false */
|
|
67
71
|
disabled?: boolean;
|
|
68
72
|
style?: StyleProp<ViewStyle>;
|
|
69
73
|
testID?: string;
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
const DEFAULT_VISIBLE_COUNT = 5;
|
|
73
|
-
/** 44pt:
|
|
77
|
+
/** 44pt: iOS's touch minimum, and enough for an `lg` line with room to spare. */
|
|
74
78
|
const DEFAULT_ITEM_HEIGHT = 44;
|
|
75
79
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
+
* Rows toward each side that the interpolation distinguishes; further out,
|
|
81
|
+
* all the same (`extrapolate: 'clamp'`). The three ranges are symmetric
|
|
82
|
+
* around the center: the row above and the row below look the same, except
|
|
83
|
+
* the one above tilts backward and the one below forward.
|
|
80
84
|
*/
|
|
81
85
|
const FALLOFF = 2;
|
|
82
86
|
|
|
83
87
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
88
|
+
* Each variant is a set of ranges. 'spotlight' falls off much faster and
|
|
89
|
+
* tilts more because it has no band marking the center: all the work of
|
|
90
|
+
* saying which one is selected is done by contrast and sharpness.
|
|
87
91
|
*/
|
|
88
92
|
const RANGES: Record<OptionWheelVariant, { opacity: number[]; scale: number[]; rotation: string[] }> = {
|
|
89
93
|
window: {
|
|
@@ -99,28 +103,28 @@ const RANGES: Record<OptionWheelVariant, { opacity: number[]; scale: number[]; r
|
|
|
99
103
|
};
|
|
100
104
|
|
|
101
105
|
/**
|
|
102
|
-
* React Native no
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* `
|
|
106
|
+
* React Native has no blur without a native dependency, so in 'spotlight'
|
|
107
|
+
* each row that isn't in the center is also drawn twice, offset and at half
|
|
108
|
+
* ink. The overlap smears the stroke: it isn't a gaussian blur, but at that
|
|
109
|
+
* size and opacity it reads the same, and it is still `opacity` and
|
|
110
|
+
* `transform` over the same scroll, i.e. the native thread.
|
|
107
111
|
*/
|
|
108
112
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
+
* Where each point of the `inputRange` falls on the arc. `Animated` can't
|
|
114
|
+
* compute roots or arcsines, but it doesn't need to: the five distances to
|
|
115
|
+
* the center are fixed per row, so the arc's sagitta and the tangent's angle
|
|
116
|
+
* are resolved once here and go in as `outputRange`.
|
|
113
117
|
*/
|
|
114
118
|
function arcOffsets(radius: number, itemHeight: number, sign: number) {
|
|
115
119
|
const shift: number[] = [];
|
|
116
120
|
const angle: string[] = [];
|
|
117
121
|
for (let step = -FALLOFF; step <= FALLOFF; step += 1) {
|
|
118
|
-
//
|
|
119
|
-
//
|
|
122
|
+
// Beyond the radius the row has already turned over: cut it off there
|
|
123
|
+
// instead of taking the root of a negative.
|
|
120
124
|
const dy = Math.min(Math.abs(step * itemHeight), radius);
|
|
121
|
-
//
|
|
125
|
+
// Arc sagitta: how far the row moves in toward the center of the wheel.
|
|
122
126
|
shift.push(sign * (radius - Math.sqrt(radius * radius - dy * dy)));
|
|
123
|
-
//
|
|
127
|
+
// The arc's tangent, so the row follows the curve instead of crossing it.
|
|
124
128
|
const degrees = Math.asin(dy / radius) * (180 / Math.PI);
|
|
125
129
|
angle.push(`${-sign * Math.sign(step) * degrees}deg`);
|
|
126
130
|
}
|
|
@@ -140,7 +144,7 @@ const useStyles = createStyles((theme) => ({
|
|
|
140
144
|
},
|
|
141
145
|
viewport: { overflow: 'hidden' },
|
|
142
146
|
disabled: { opacity: 0.5 },
|
|
143
|
-
//
|
|
147
|
+
// The center window: figure against the ground of options passing by.
|
|
144
148
|
window: {
|
|
145
149
|
position: 'absolute',
|
|
146
150
|
left: 0,
|
|
@@ -166,7 +170,7 @@ const useStyles = createStyles((theme) => ({
|
|
|
166
170
|
unit: { fontSize: theme.tokens.fontSize.sm, color: theme.colors.textLight },
|
|
167
171
|
}));
|
|
168
172
|
|
|
169
|
-
/**
|
|
173
|
+
/** The enabled index closest to `index`, or -1 if there is none. */
|
|
170
174
|
function nearestEnabled<T>(options: OptionWheelOption<T>[], index: number): number {
|
|
171
175
|
if (options.length === 0) return -1;
|
|
172
176
|
for (let step = 0; step < options.length; step += 1) {
|
|
@@ -180,25 +184,25 @@ function nearestEnabled<T>(options: OptionWheelOption<T>[], index: number): numb
|
|
|
180
184
|
|
|
181
185
|
/**
|
|
182
186
|
* OptionWheel
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
187
|
+
* Wheel picker: the options pass through a fixed window and the one left in
|
|
188
|
+
* the center is the selected one. The scroll snaps to the row height, so
|
|
189
|
+
* lifting the finger anywhere always leaves one option centered, never half.
|
|
186
190
|
*
|
|
187
|
-
* Gestalt,
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
191
|
+
* Gestalt, figure and ground: what marks the selection isn't a style on the
|
|
192
|
+
* row —which would travel with it— but a still window on top of the list. The
|
|
193
|
+
* figure stays, the ground moves, and that is why the wheel reads without
|
|
194
|
+
* reading: the place signals, not the color. And common fate: all rows shrink
|
|
195
|
+
* and tilt by the same law relative to the center, so they are perceived as a
|
|
196
|
+
* rigid surface that turns and not as N rows animating on their own.
|
|
193
197
|
*
|
|
194
|
-
*
|
|
195
|
-
* `contentOffset
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
198
|
+
* Scale, opacity and tilt come from interpolating the scroll's
|
|
199
|
+
* `contentOffset`, not from React state: they are computed on the native
|
|
200
|
+
* thread (`useNativeDriver`) and the JS thread only takes part once the wheel
|
|
201
|
+
* has stopped, to report what was selected. With "reduce motion" on, the tilt
|
|
202
|
+
* is turned off and the size stays, since it is information, not decoration.
|
|
199
203
|
*
|
|
200
|
-
* `disabled`
|
|
201
|
-
*
|
|
204
|
+
* `disabled` on an option can't keep the snap from centering it, so the
|
|
205
|
+
* wheel centers it and moves on its own to the nearest enabled one.
|
|
202
206
|
*/
|
|
203
207
|
export function OptionWheel<T extends string | number>({
|
|
204
208
|
options,
|
|
@@ -223,14 +227,14 @@ export function OptionWheel<T extends string | number>({
|
|
|
223
227
|
const allowFontScaling = useAllowFontScaling();
|
|
224
228
|
const reduceMotion = useReduceMotion();
|
|
225
229
|
|
|
226
|
-
const scrollRef = useRef<ScrollView
|
|
230
|
+
const scrollRef = useRef<ComponentRef<typeof ScrollView>>(null);
|
|
227
231
|
const scrollY = useRef(new Animated.Value(0)).current;
|
|
228
|
-
//
|
|
229
|
-
//
|
|
232
|
+
// The first positioning isn't animated: the wheel has to appear already
|
|
233
|
+
// set at its value, not traveling to it.
|
|
230
234
|
const settled = useRef(false);
|
|
231
235
|
|
|
232
|
-
//
|
|
233
|
-
//
|
|
236
|
+
// Always odd: with an even number there is no center row to line up with
|
|
237
|
+
// the window, and the snap would leave the selection between two rows.
|
|
234
238
|
const rows = visibleCount % 2 === 0 ? visibleCount + 1 : visibleCount;
|
|
235
239
|
const padding = ((rows - 1) / 2) * itemHeight;
|
|
236
240
|
const height = rows * itemHeight;
|
|
@@ -244,11 +248,11 @@ export function OptionWheel<T extends string | number>({
|
|
|
244
248
|
(index: number, animated: boolean) => {
|
|
245
249
|
const y = index * itemHeight;
|
|
246
250
|
scrollRef.current?.scrollTo({ y, animated });
|
|
247
|
-
// `scrollY`
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
//
|
|
251
|
+
// `scrollY` is only fed by `onScroll`, and an unanimated jump doesn't
|
|
252
|
+
// always emit it: without this the value stays at 0, the interpolation
|
|
253
|
+
// thinks the centered row is the first one and dims the one that is
|
|
254
|
+
// really in the window. The animated scroll does emit along the whole
|
|
255
|
+
// path, so forcing it there would fight the animation.
|
|
252
256
|
if (!animated) scrollY.setValue(y);
|
|
253
257
|
},
|
|
254
258
|
[itemHeight, scrollY]
|
|
@@ -261,10 +265,10 @@ export function OptionWheel<T extends string | number>({
|
|
|
261
265
|
}, [selectedIndex, scrollToIndex, reduceMotion]);
|
|
262
266
|
|
|
263
267
|
/**
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
+
* Runs both at the end of the drag and at the end of momentum: on Android
|
|
269
|
+
* a short drag with no momentum doesn't fire `onMomentumScrollEnd`, and the
|
|
270
|
+
* wheel would keep the old selection. Re-entering with the same index is
|
|
271
|
+
* harmless because it only reports when it changes.
|
|
268
272
|
*/
|
|
269
273
|
const commit = useCallback(
|
|
270
274
|
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
@@ -274,8 +278,8 @@ export function OptionWheel<T extends string | number>({
|
|
|
274
278
|
if (!landed) return;
|
|
275
279
|
const target = landed.disabled ? nearestEnabled(options, clamped) : clamped;
|
|
276
280
|
const option = options[target];
|
|
277
|
-
//
|
|
278
|
-
//
|
|
281
|
+
// With no enabled options there is nowhere to stop: the wheel stays where
|
|
282
|
+
// it was left and reports nothing.
|
|
279
283
|
if (!option) return;
|
|
280
284
|
if (target !== clamped) scrollToIndex(target, true);
|
|
281
285
|
if (option.value !== selectedValue) onSelect(option.value);
|
|
@@ -283,13 +287,13 @@ export function OptionWheel<T extends string | number>({
|
|
|
283
287
|
[options, itemHeight, selectedValue, onSelect, scrollToIndex]
|
|
284
288
|
);
|
|
285
289
|
|
|
286
|
-
/** VoiceOver/TalkBack
|
|
290
|
+
/** VoiceOver/TalkBack go through the wheel with increment/decrement, not the finger. */
|
|
287
291
|
const step = useCallback(
|
|
288
292
|
(delta: number) => {
|
|
289
293
|
if (disabled || selectedIndex < 0) return;
|
|
290
294
|
const next = nearestEnabled(options, selectedIndex + delta);
|
|
291
295
|
const option = options[next];
|
|
292
|
-
//
|
|
296
|
+
// At the edge, `nearestEnabled` returns the row we are already on.
|
|
293
297
|
if (!option || next === selectedIndex) return;
|
|
294
298
|
onSelect(option.value);
|
|
295
299
|
},
|
|
@@ -305,9 +309,9 @@ export function OptionWheel<T extends string | number>({
|
|
|
305
309
|
|
|
306
310
|
const selected = selectedIndex >= 0 ? options[selectedIndex] : undefined;
|
|
307
311
|
const ranges = RANGES[variant];
|
|
308
|
-
//
|
|
309
|
-
//
|
|
310
|
-
//
|
|
312
|
+
// The simulated blur triples the text nodes: it only goes where it helps,
|
|
313
|
+
// and not with "reduce motion", because there sharpness is the only thing
|
|
314
|
+
// left to tell the selected row apart.
|
|
311
315
|
const smeared = variant === 'spotlight' && !reduceMotion;
|
|
312
316
|
const arc = useMemo(
|
|
313
317
|
() =>
|
|
@@ -379,8 +383,8 @@ export function OptionWheel<T extends string | number>({
|
|
|
379
383
|
{ scale: scrollY.interpolate({ inputRange, outputRange: ranges.scale, extrapolate: 'clamp' }) },
|
|
380
384
|
];
|
|
381
385
|
if (perspective && !reduceMotion) {
|
|
382
|
-
//
|
|
383
|
-
//
|
|
386
|
+
// perspective goes first: applied after the rotation it doesn't
|
|
387
|
+
// distort anything and the row looks flat even though it's rotated.
|
|
384
388
|
transform.unshift({ perspective: height * 2 });
|
|
385
389
|
transform.push({
|
|
386
390
|
rotateX: scrollY.interpolate({ inputRange, outputRange: ranges.rotation, extrapolate: 'clamp' }),
|
|
@@ -425,9 +429,9 @@ export function OptionWheel<T extends string | number>({
|
|
|
425
429
|
<Animated.View
|
|
426
430
|
key={direction}
|
|
427
431
|
pointerEvents="none"
|
|
428
|
-
// `accessibilityElementsHidden`
|
|
429
|
-
//
|
|
430
|
-
//
|
|
432
|
+
// `accessibilityElementsHidden` isn't enough: the reader
|
|
433
|
+
// would read the row three times over, because the whole
|
|
434
|
+
// wheel is already a single element and this lives inside it.
|
|
431
435
|
style={[
|
|
432
436
|
styles.ghost,
|
|
433
437
|
{
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import React, { useRef, useState } from 'react';
|
|
2
2
|
import { Animated, PanResponder, View, type StyleProp, type ViewStyle } from 'react-native';
|
|
3
3
|
import { createStyles } from '../theme/createStyles';
|
|
4
|
+
import { useLabels } from '../theme/UIProvider';
|
|
4
5
|
|
|
5
6
|
export interface ReorderableListProps<T> {
|
|
7
|
+
/** Items, in their current order. */
|
|
6
8
|
data: T[];
|
|
9
|
+
/** Stable key per item. */
|
|
7
10
|
keyExtractor: (item: T, index: number) => string;
|
|
8
11
|
/** Fixed height of each row: needed to calculate the target index without measuring layout async. */
|
|
9
12
|
itemHeight: number;
|
|
13
|
+
/** Renders each row; the third argument is true while that row is being dragged. */
|
|
10
14
|
renderItem: (item: T, index: number, dragging: boolean) => React.ReactElement;
|
|
11
15
|
/** Called on release, with the array already reordered. Does not mutate `data`. */
|
|
12
16
|
onReorder: (data: T[]) => void;
|
|
@@ -19,11 +23,12 @@ export interface ReorderableListProps<T> {
|
|
|
19
23
|
onDragStart?: (index: number) => void;
|
|
20
24
|
/** Ends the drag — on release or cancellation. Always runs if `onDragStart` ran. */
|
|
21
25
|
onDragEnd?: () => void;
|
|
26
|
+
/** Turns off dragging. @default false */
|
|
22
27
|
disabled?: boolean;
|
|
23
28
|
style?: StyleProp<ViewStyle>;
|
|
24
29
|
}
|
|
25
30
|
|
|
26
|
-
/**
|
|
31
|
+
/** Reorders by moving the item from `from` to `to`, without mutating `data`. Exported separately so it can be tested without simulating gestures. */
|
|
27
32
|
export function move<T>(data: T[], from: number, to: number): T[] {
|
|
28
33
|
const next = data.slice();
|
|
29
34
|
const [item] = next.splice(from, 1) as [T];
|
|
@@ -37,18 +42,23 @@ const useStyles = createStyles(() => ({
|
|
|
37
42
|
|
|
38
43
|
/**
|
|
39
44
|
* ReorderableList
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
45
|
+
* Law of common fate: when dragging a row, the rows it has to cross shift
|
|
46
|
+
* together in the same direction — that is what communicates "they are
|
|
47
|
+
* going to swap places" before the finger lifts, not a simple highlight of
|
|
48
|
+
* the active item.
|
|
44
49
|
*
|
|
45
|
-
*
|
|
46
|
-
* PanResponder + Animated
|
|
47
|
-
*
|
|
48
|
-
*
|
|
50
|
+
* No external gesture/animation dependencies (reanimated, gesture-handler):
|
|
51
|
+
* PanResponder + Animated are enough because computing the target index
|
|
52
|
+
* needs the drag value in JS on every move (not something useNativeDriver
|
|
53
|
+
* can resolve on its own).
|
|
49
54
|
*
|
|
50
|
-
*
|
|
51
|
-
* `scrollEnabled`,
|
|
55
|
+
* Inside a vertical scroll you have to wire `onDragStart`/`onDragEnd` to
|
|
56
|
+
* `scrollEnabled`, or on iOS the drag never gets to start:
|
|
57
|
+
*
|
|
58
|
+
* Screen readers can't drag: each row is one accessible element with two
|
|
59
|
+
* actions, "Move up" and "Move down" (`labels.moveUp` / `labels.moveDown`),
|
|
60
|
+
* that call `onReorder` the same way a drop does. The row's content is read
|
|
61
|
+
* as its label, so keep interactive controls out of reorderable rows.
|
|
52
62
|
*
|
|
53
63
|
* ```tsx
|
|
54
64
|
* const [dragging, setDragging] = useState(false);
|
|
@@ -69,24 +79,25 @@ export function ReorderableList<T>({
|
|
|
69
79
|
style,
|
|
70
80
|
}: ReorderableListProps<T>) {
|
|
71
81
|
const styles = useStyles();
|
|
82
|
+
const labels = useLabels();
|
|
72
83
|
const [activeIndex, setActiveIndex] = useState<number | null>(null);
|
|
73
84
|
const [targetIndex, setTargetIndex] = useState<number | null>(null);
|
|
74
85
|
const dy = useRef(new Animated.Value(0)).current;
|
|
75
86
|
const activeIndexRef = useRef<number | null>(null);
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
87
|
+
// Each row's PanResponder is created only once (cached in the Map below)
|
|
88
|
+
// and its closure stays fixed to that first render: reading `targetIndex`
|
|
89
|
+
// (state) directly there would always give the value from mount. A ref
|
|
90
|
+
// does reflect the latest write no matter when the closure reading it was
|
|
91
|
+
// created.
|
|
81
92
|
const targetIndexRef = useRef<number | null>(null);
|
|
82
93
|
const dataRef = useRef(data);
|
|
83
94
|
dataRef.current = data;
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
95
|
+
// Same reason as targetIndexRef: each row's responder is created only
|
|
96
|
+
// once, so reading `disabled` straight from the closure would freeze the
|
|
97
|
+
// value from when that row was created.
|
|
87
98
|
const disabledRef = useRef(disabled);
|
|
88
99
|
disabledRef.current = disabled;
|
|
89
|
-
//
|
|
100
|
+
// Same reason: the callbacks are read from closures created only once.
|
|
90
101
|
const onReorderRef = useRef(onReorder);
|
|
91
102
|
onReorderRef.current = onReorder;
|
|
92
103
|
const onDragStartRef = useRef(onDragStart);
|
|
@@ -95,8 +106,8 @@ export function ReorderableList<T>({
|
|
|
95
106
|
onDragEndRef.current = onDragEnd;
|
|
96
107
|
|
|
97
108
|
const panResponders = useRef(new Map<number, ReturnType<typeof PanResponder.create>>()).current;
|
|
98
|
-
//
|
|
99
|
-
//
|
|
109
|
+
// If `data` shrinks, the responders for indexes that no longer exist stay
|
|
110
|
+
// stuck in the Map forever: they are pruned on every render.
|
|
100
111
|
for (const index of panResponders.keys()) {
|
|
101
112
|
if (index >= data.length) panResponders.delete(index);
|
|
102
113
|
}
|
|
@@ -117,9 +128,9 @@ export function ReorderableList<T>({
|
|
|
117
128
|
responder = PanResponder.create({
|
|
118
129
|
onStartShouldSetPanResponder: () => !disabledRef.current,
|
|
119
130
|
onMoveShouldSetPanResponder: (_, gesture) => !disabledRef.current && Math.abs(gesture.dy) > 2,
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
//
|
|
131
|
+
// A parent scroll requests the responder as soon as its vertical gesture
|
|
132
|
+
// starts — the same axis as the drag. Yielding it would cancel the drag
|
|
133
|
+
// midway, so the row keeps it until release.
|
|
123
134
|
onPanResponderTerminationRequest: () => false,
|
|
124
135
|
onPanResponderGrant: () => {
|
|
125
136
|
activeIndexRef.current = index;
|
|
@@ -155,8 +166,8 @@ export function ReorderableList<T>({
|
|
|
155
166
|
<View style={style}>
|
|
156
167
|
{data.map((item, index) => {
|
|
157
168
|
const isActive = activeIndex === index;
|
|
158
|
-
//
|
|
159
|
-
//
|
|
169
|
+
// Rows between the origin and the target shift one full place in the
|
|
170
|
+
// drag direction: it is the "group moving together" effect.
|
|
160
171
|
let shift = 0;
|
|
161
172
|
if (activeIndex !== null && targetIndex !== null && !isActive) {
|
|
162
173
|
if (activeIndex < targetIndex && index > activeIndex && index <= targetIndex) shift = -itemHeight;
|
|
@@ -173,6 +184,17 @@ export function ReorderableList<T>({
|
|
|
173
184
|
: { transform: [{ translateY: shift }] },
|
|
174
185
|
]}
|
|
175
186
|
{...panResponderFor(index).panHandlers}
|
|
187
|
+
accessible
|
|
188
|
+
accessibilityActions={[
|
|
189
|
+
...(index > 0 ? [{ name: 'moveUp', label: labels.moveUp }] : []),
|
|
190
|
+
...(index < data.length - 1 ? [{ name: 'moveDown', label: labels.moveDown }] : []),
|
|
191
|
+
]}
|
|
192
|
+
onAccessibilityAction={(event) => {
|
|
193
|
+
if (disabled) return;
|
|
194
|
+
const to = event.nativeEvent.actionName === 'moveUp' ? index - 1 : index + 1;
|
|
195
|
+
if (to < 0 || to >= data.length) return;
|
|
196
|
+
onReorder(move(data, index, to));
|
|
197
|
+
}}
|
|
176
198
|
>
|
|
177
199
|
{renderItem(item, index, isActive)}
|
|
178
200
|
</Animated.View>
|
package/src/organisms/Screen.tsx
CHANGED
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
import React, { memo } from 'react';
|
|
2
2
|
import { KeyboardAvoidingView, Platform, ScrollView, View, type ViewStyle } from 'react-native';
|
|
3
3
|
import { createStyles } from '../theme/createStyles';
|
|
4
|
-
import { useInsets } from '../theme/UIProvider';
|
|
4
|
+
import { useInsets, useTheme } from '../theme/UIProvider';
|
|
5
|
+
import { KeyboardHandled, KeyboardPanArea, useKeyboardHost } from '../theme/KeyboardAvoidance';
|
|
5
6
|
|
|
6
7
|
export type ScreenEdge = 'top' | 'bottom';
|
|
7
8
|
|
|
8
9
|
export interface ScreenProps {
|
|
10
|
+
/** Content of the screen. */
|
|
9
11
|
children: React.ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* Fixed bar on top (back button, title, actions). It stays in place while
|
|
14
|
+
* the content scrolls or moves up for the keyboard. The top safe area goes
|
|
15
|
+
* above it.
|
|
16
|
+
*/
|
|
17
|
+
header?: React.ReactNode;
|
|
10
18
|
style?: ViewStyle;
|
|
19
|
+
/** Wraps the content in a ScrollView. @default true */
|
|
11
20
|
scrollable?: boolean;
|
|
21
|
+
/** Style of the ScrollView's content container. Only applies when `scrollable`. */
|
|
12
22
|
contentContainerStyle?: ViewStyle;
|
|
13
23
|
/** Which safe area insets to apply. @default ['top', 'bottom'] */
|
|
14
24
|
edges?: ScreenEdge[];
|
|
15
25
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* the
|
|
19
|
-
*
|
|
20
|
-
* ends up pushed off screen.
|
|
26
|
+
* Keeps the focused Input above the keyboard by moving only the content
|
|
27
|
+
* (the `header` and a tab bar outside the Screen stay put). On iOS with
|
|
28
|
+
* scroll, the ScrollView scrolls to it instead. Set to false when the
|
|
29
|
+
* content brings its own keyboard handling.
|
|
21
30
|
* @default true
|
|
22
31
|
*/
|
|
23
32
|
keyboardAvoiding?: boolean;
|
|
@@ -27,15 +36,28 @@ const useStyles = createStyles((theme) => ({
|
|
|
27
36
|
wrapper: { flex: 1, backgroundColor: theme.colors.background },
|
|
28
37
|
container: { flex: 1 },
|
|
29
38
|
contentContainer: { flexGrow: 1 },
|
|
39
|
+
header: { backgroundColor: theme.colors.background },
|
|
30
40
|
}));
|
|
31
41
|
|
|
32
42
|
/**
|
|
33
43
|
* Screen
|
|
34
|
-
*
|
|
35
|
-
*
|
|
44
|
+
* Root screen container: theme background, safe area (via the UIProvider's
|
|
45
|
+
* insets), keyboard and optional scroll handled consistently.
|
|
46
|
+
*
|
|
47
|
+
* Keyboard: with the UIProvider handling it (default), Screen shifts only its
|
|
48
|
+
* content — clipped below the `header` — to keep the focused Input above the
|
|
49
|
+
* keyboard. The header stays fixed and a tab bar outside the Screen stays
|
|
50
|
+
* behind the keyboard, as in a native app. On iOS with scroll, the ScrollView
|
|
51
|
+
* already brings the field into view (automaticallyAdjustKeyboardInsets) and
|
|
52
|
+
* nothing is added. Without a host (`keyboardAvoidance={false}` on the
|
|
53
|
+
* provider) the usual KeyboardAvoidingView remains.
|
|
54
|
+
*
|
|
55
|
+
* Gestalt, common region: the header shares the screen's background and stays
|
|
56
|
+
* fixed; only the content moves, so navigation isn't lost.
|
|
36
57
|
*/
|
|
37
58
|
export const Screen = memo(({
|
|
38
59
|
children,
|
|
60
|
+
header,
|
|
39
61
|
style,
|
|
40
62
|
scrollable = true,
|
|
41
63
|
contentContainerStyle,
|
|
@@ -44,47 +66,62 @@ export const Screen = memo(({
|
|
|
44
66
|
}: ScreenProps) => {
|
|
45
67
|
const insets = useInsets();
|
|
46
68
|
const styles = useStyles();
|
|
69
|
+
const theme = useTheme();
|
|
70
|
+
const host = useKeyboardHost();
|
|
47
71
|
const applyTop = edges.includes('top');
|
|
48
72
|
const applyBottom = edges.includes('bottom');
|
|
73
|
+
const topInset = applyTop ? insets.top : 0;
|
|
74
|
+
|
|
75
|
+
const scrollHandles = keyboardAvoiding && scrollable && Platform.OS === 'ios';
|
|
76
|
+
const panArea = keyboardAvoiding && !scrollHandles && !!host;
|
|
77
|
+
const avoidWithView = keyboardAvoiding && !scrollHandles && !host;
|
|
49
78
|
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
79
|
+
// With a header, the top inset goes above the header; the content starts
|
|
80
|
+
// right below it.
|
|
81
|
+
const contentTop = header ? 0 : topInset;
|
|
82
|
+
|
|
83
|
+
let content = scrollable ? (
|
|
84
|
+
<ScrollView
|
|
85
|
+
style={styles.container}
|
|
86
|
+
automaticallyAdjustKeyboardInsets={scrollHandles}
|
|
87
|
+
contentContainerStyle={[
|
|
88
|
+
styles.contentContainer,
|
|
89
|
+
{ paddingTop: contentTop },
|
|
90
|
+
applyBottom && { paddingBottom: insets.bottom },
|
|
91
|
+
contentContainerStyle,
|
|
92
|
+
]}
|
|
93
|
+
keyboardShouldPersistTaps="handled"
|
|
94
|
+
>
|
|
95
|
+
{scrollHandles ? <KeyboardHandled>{children}</KeyboardHandled> : children}
|
|
96
|
+
</ScrollView>
|
|
97
|
+
) : (
|
|
98
|
+
<View style={[styles.container, { paddingTop: contentTop, paddingBottom: applyBottom ? insets.bottom : 0 }]}>
|
|
99
|
+
{children}
|
|
100
|
+
</View>
|
|
101
|
+
);
|
|
56
102
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
103
|
+
if (panArea) {
|
|
104
|
+
content = (
|
|
105
|
+
<KeyboardPanArea margin={theme.tokens.spacing.md} topLimit={insets.top} clip>
|
|
106
|
+
{content}
|
|
107
|
+
</KeyboardPanArea>
|
|
108
|
+
);
|
|
109
|
+
} else if (avoidWithView) {
|
|
110
|
+
content = (
|
|
111
|
+
<KeyboardAvoidingView
|
|
112
|
+
style={styles.container}
|
|
113
|
+
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
|
114
|
+
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : theme.tokens.spacing.xl}
|
|
115
|
+
>
|
|
116
|
+
{content}
|
|
117
|
+
</KeyboardAvoidingView>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
64
120
|
|
|
65
121
|
return (
|
|
66
122
|
<View style={[styles.wrapper, style]}>
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
<ScrollView
|
|
70
|
-
style={styles.container}
|
|
71
|
-
automaticallyAdjustKeyboardInsets
|
|
72
|
-
contentContainerStyle={[
|
|
73
|
-
styles.contentContainer,
|
|
74
|
-
{ paddingTop: applyTop ? insets.top : 0 },
|
|
75
|
-
applyBottom && { paddingBottom: insets.bottom },
|
|
76
|
-
contentContainerStyle,
|
|
77
|
-
]}
|
|
78
|
-
keyboardShouldPersistTaps="handled"
|
|
79
|
-
>
|
|
80
|
-
{children}
|
|
81
|
-
</ScrollView>
|
|
82
|
-
) : (
|
|
83
|
-
<View style={[styles.container, { paddingTop: applyTop ? insets.top : 0, paddingBottom: applyBottom ? insets.bottom : 0 }]}>
|
|
84
|
-
{children}
|
|
85
|
-
</View>
|
|
86
|
-
)}
|
|
87
|
-
</KeyboardWrapper>
|
|
123
|
+
{header && <View style={[styles.header, { paddingTop: topInset }]}>{header}</View>}
|
|
124
|
+
{content}
|
|
88
125
|
</View>
|
|
89
126
|
);
|
|
90
127
|
});
|