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
|
@@ -5,10 +5,13 @@ import { useAllowFontScaling, useColors, useLabels } from '../theme/UIProvider';
|
|
|
5
5
|
import { Modal } from './Modal';
|
|
6
6
|
import { DatePicker, type DatePickerProps, type DateRange } from './DatePicker';
|
|
7
7
|
import { Button } from '../atoms/Button';
|
|
8
|
+
import { Icon } from '../icons/Icon';
|
|
8
9
|
|
|
9
10
|
export interface DateFieldProps
|
|
10
11
|
extends Pick<DatePickerProps, 'minDate' | 'maxDate' | 'monthNames' | 'weekdayNames' | 'firstDayOfWeek'> {
|
|
12
|
+
/** Text above the field; also its accessible name. */
|
|
11
13
|
label?: string;
|
|
14
|
+
/** Shows an asterisk and says "required" to screen readers. @default false */
|
|
12
15
|
required?: boolean;
|
|
13
16
|
/**
|
|
14
17
|
* 'single' picks one date; 'range' picks an interval with two taps.
|
|
@@ -23,8 +26,11 @@ export interface DateFieldProps
|
|
|
23
26
|
range?: DateRange;
|
|
24
27
|
/** Called in mode="range", both when setting the start and when closing the range. */
|
|
25
28
|
onRangeChange?: (range: DateRange) => void;
|
|
29
|
+
/** Text while empty. @default labels.selectDate */
|
|
26
30
|
placeholder?: string;
|
|
31
|
+
/** Error under the field (red border); announced to screen readers. */
|
|
27
32
|
error?: string;
|
|
33
|
+
/** Dims the field and ignores taps. @default false */
|
|
28
34
|
disabled?: boolean;
|
|
29
35
|
/** Formats the date in the field. @default "Month D, YYYY" */
|
|
30
36
|
format?: (date: Date) => string;
|
|
@@ -37,6 +43,7 @@ export interface DateFieldProps
|
|
|
37
43
|
onClear?: () => void;
|
|
38
44
|
/** Text for that button. @default the `clear` from `useLabels()` */
|
|
39
45
|
clearLabel?: string;
|
|
46
|
+
/** Style of the outer wrapper (label, field and error). */
|
|
40
47
|
containerStyle?: StyleProp<ViewStyle>;
|
|
41
48
|
testID?: string;
|
|
42
49
|
}
|
|
@@ -45,6 +52,13 @@ function defaultFormat(date: Date, monthNames: string[]): string {
|
|
|
45
52
|
return `${monthNames[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;
|
|
46
53
|
}
|
|
47
54
|
|
|
55
|
+
const DISABLED_OPACITY = 0.5;
|
|
56
|
+
const PRESSED_OPACITY = 0.7;
|
|
57
|
+
/** Same box as Input, so a form reads as one column of identical fields. */
|
|
58
|
+
const FIELD_MIN_HEIGHT = 50;
|
|
59
|
+
const FIELD_BORDER = 2;
|
|
60
|
+
const CHEVRON_SIZE = 20;
|
|
61
|
+
|
|
48
62
|
const useStyles = createStyles((theme) => ({
|
|
49
63
|
container: { marginBottom: theme.tokens.spacing.lg, width: '100%', gap: theme.tokens.spacing.sm },
|
|
50
64
|
label: { fontSize: theme.tokens.fontSize.md, fontWeight: theme.tokens.fontWeight.medium, color: theme.colors.text },
|
|
@@ -55,12 +69,13 @@ const useStyles = createStyles((theme) => ({
|
|
|
55
69
|
justifyContent: 'space-between',
|
|
56
70
|
backgroundColor: theme.colors.inputBackground,
|
|
57
71
|
borderRadius: theme.tokens.radius.lg,
|
|
58
|
-
borderWidth:
|
|
72
|
+
borderWidth: FIELD_BORDER,
|
|
59
73
|
borderColor: theme.colors.border,
|
|
60
|
-
minHeight:
|
|
74
|
+
minHeight: FIELD_MIN_HEIGHT,
|
|
61
75
|
paddingHorizontal: theme.tokens.spacing.lg,
|
|
62
76
|
},
|
|
63
77
|
fieldError: { borderColor: theme.colors.error },
|
|
78
|
+
fieldDisabled: { opacity: DISABLED_OPACITY },
|
|
64
79
|
fieldText: { fontSize: theme.tokens.fontSize.lg, color: theme.colors.text },
|
|
65
80
|
placeholder: { color: theme.colors.textLight },
|
|
66
81
|
errorText: { fontSize: theme.tokens.fontSize.sm, color: theme.colors.errorText },
|
|
@@ -68,9 +83,17 @@ const useStyles = createStyles((theme) => ({
|
|
|
68
83
|
|
|
69
84
|
/**
|
|
70
85
|
* DateField
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
86
|
+
* Date field: looks like an Input, opens a `DatePicker` in a Modal when
|
|
87
|
+
* tapped. No native system picker, so it looks and behaves the same on iOS
|
|
88
|
+
* and Android.
|
|
89
|
+
*
|
|
90
|
+
* Gestalt, similarity (and Jakob's law): same box, border, height and label
|
|
91
|
+
* as Input, and the same chevron as Select, so in a form it reads as one more
|
|
92
|
+
* field; only the chevron says it opens something. Proximity: label, field
|
|
93
|
+
* and error stack tight, as one unit.
|
|
94
|
+
*
|
|
95
|
+
* Accessibility: the name includes the label, "required" and the chosen date;
|
|
96
|
+
* the error is a hint; `expanded` tells whether the calendar is open.
|
|
74
97
|
*/
|
|
75
98
|
export const DateField = memo(
|
|
76
99
|
({
|
|
@@ -81,7 +104,7 @@ export const DateField = memo(
|
|
|
81
104
|
onChange,
|
|
82
105
|
range,
|
|
83
106
|
onRangeChange,
|
|
84
|
-
placeholder
|
|
107
|
+
placeholder,
|
|
85
108
|
error,
|
|
86
109
|
disabled = false,
|
|
87
110
|
format,
|
|
@@ -100,12 +123,13 @@ export const DateField = memo(
|
|
|
100
123
|
const [open, setOpen] = useState(false);
|
|
101
124
|
|
|
102
125
|
const months = monthNames ?? labels.months;
|
|
126
|
+
const emptyText = placeholder ?? labels.selectDate;
|
|
103
127
|
const isRange = mode === 'range';
|
|
104
128
|
|
|
105
129
|
const formatDate = (date: Date) => (format ? format(date) : defaultFormat(date, months));
|
|
106
130
|
|
|
107
|
-
//
|
|
108
|
-
//
|
|
131
|
+
// The calendar closes on its own only once there is nothing left to pick:
|
|
132
|
+
// in range mode, only when the second tap closes the interval.
|
|
109
133
|
const handleChange = useCallback(
|
|
110
134
|
(date: Date) => {
|
|
111
135
|
onChange?.(date);
|
|
@@ -128,7 +152,7 @@ export const DateField = memo(
|
|
|
128
152
|
}, [onClear]);
|
|
129
153
|
|
|
130
154
|
const hasValue = isRange ? !!range?.start : !!value;
|
|
131
|
-
let display =
|
|
155
|
+
let display = emptyText;
|
|
132
156
|
if (isRange && range?.start) {
|
|
133
157
|
display = range.end ? `${formatDate(range.start)} — ${formatDate(range.end)}` : formatDate(range.start);
|
|
134
158
|
} else if (!isRange && value) {
|
|
@@ -145,20 +169,21 @@ export const DateField = memo(
|
|
|
145
169
|
)}
|
|
146
170
|
|
|
147
171
|
<TouchableOpacity
|
|
148
|
-
style={[styles.field, !!error && styles.fieldError, disabled &&
|
|
172
|
+
style={[styles.field, !!error && styles.fieldError, disabled && styles.fieldDisabled]}
|
|
149
173
|
onPress={() => setOpen(true)}
|
|
150
174
|
disabled={disabled}
|
|
151
|
-
activeOpacity={
|
|
175
|
+
activeOpacity={PRESSED_OPACITY}
|
|
152
176
|
accessibilityRole="button"
|
|
153
|
-
accessibilityLabel={
|
|
177
|
+
accessibilityLabel={[label ?? emptyText, required ? labels.required : null, hasValue ? display : null]
|
|
178
|
+
.filter(Boolean)
|
|
179
|
+
.join(', ')}
|
|
180
|
+
accessibilityHint={error || undefined}
|
|
154
181
|
accessibilityState={{ disabled, expanded: open }}
|
|
155
182
|
>
|
|
156
183
|
<Text allowFontScaling={allowFontScaling} style={[styles.fieldText, !hasValue && styles.placeholder]}>
|
|
157
184
|
{display}
|
|
158
185
|
</Text>
|
|
159
|
-
<
|
|
160
|
-
{'▾'}
|
|
161
|
-
</Text>
|
|
186
|
+
<Icon name="chevron-down" size={CHEVRON_SIZE} color={colors.textLight} />
|
|
162
187
|
</TouchableOpacity>
|
|
163
188
|
|
|
164
189
|
{!!error && (
|
|
@@ -9,12 +9,12 @@ export const DEFAULT_MONTH_NAMES = [
|
|
|
9
9
|
'July', 'August', 'September', 'October', 'November', 'December',
|
|
10
10
|
];
|
|
11
11
|
|
|
12
|
-
/**
|
|
12
|
+
/** Index 0 = Sunday, to line up with Date.getDay(). */
|
|
13
13
|
export const DEFAULT_WEEKDAY_NAMES = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
|
|
14
14
|
|
|
15
15
|
export interface DateRange {
|
|
16
16
|
start: Date;
|
|
17
|
-
/**
|
|
17
|
+
/** Missing while the range is half-picked (only the start was tapped). */
|
|
18
18
|
end?: Date;
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -32,7 +32,9 @@ export interface DatePickerProps {
|
|
|
32
32
|
range?: DateRange;
|
|
33
33
|
/** Called in mode="range", both when setting the start and when closing the range. */
|
|
34
34
|
onRangeChange?: (range: DateRange) => void;
|
|
35
|
+
/** Earliest selectable day; earlier days are dimmed and the back arrow stops there. */
|
|
35
36
|
minDate?: Date;
|
|
37
|
+
/** Latest selectable day; later days are dimmed and the forward arrow stops there. */
|
|
36
38
|
maxDate?: Date;
|
|
37
39
|
/** Month shown on open if there's no `value`. @default today */
|
|
38
40
|
defaultMonth?: Date;
|
|
@@ -52,7 +54,7 @@ function startOfDay(d: Date): Date {
|
|
|
52
54
|
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
/**
|
|
57
|
+
/** The day's timestamp, to compare without creating a Date again in each cell. */
|
|
56
58
|
function dayTime(d: Date): number {
|
|
57
59
|
return startOfDay(d).getTime();
|
|
58
60
|
}
|
|
@@ -61,21 +63,21 @@ function dayTimeOf(d: Date | undefined): number | undefined {
|
|
|
61
63
|
return d ? dayTime(d) : undefined;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
/**
|
|
66
|
+
/** Milliseconds left until the next local midnight. */
|
|
65
67
|
function msUntilNextMidnight(from: Date): number {
|
|
66
68
|
const next = new Date(from.getFullYear(), from.getMonth(), from.getDate() + 1);
|
|
67
69
|
return next.getTime() - from.getTime();
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
/**
|
|
72
|
+
/** Absolute month number (year * 12 + month), to compare months with a `<`. */
|
|
71
73
|
function monthIndex(d: Date): number {
|
|
72
74
|
return d.getFullYear() * 12 + d.getMonth();
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
78
|
+
* Returns the month grid: 6 rows of 7 cells. Cells outside the month are
|
|
79
|
+
* null, so the layout doesn't jump in height between months (a month can
|
|
80
|
+
* need 4, 5 or 6 rows depending on which day the 1st falls on).
|
|
79
81
|
*/
|
|
80
82
|
export function buildMonthGrid(year: number, month: number, firstDayOfWeek: 0 | 1): (Date | null)[][] {
|
|
81
83
|
const first = new Date(year, month, 1);
|
|
@@ -92,9 +94,16 @@ export function buildMonthGrid(year: number, month: number, firstDayOfWeek: 0 |
|
|
|
92
94
|
return rows;
|
|
93
95
|
}
|
|
94
96
|
|
|
97
|
+
/** Drawn size of a day; hitSlop takes the touch target to 44pt (Fitts). */
|
|
98
|
+
const DAY_SIZE = 36;
|
|
99
|
+
const MIN_TOUCH = 44;
|
|
100
|
+
const DAY_HIT_SLOP = (MIN_TOUCH - DAY_SIZE) / 2;
|
|
101
|
+
const DAY_HIT = { top: DAY_HIT_SLOP, bottom: DAY_HIT_SLOP, left: DAY_HIT_SLOP, right: DAY_HIT_SLOP };
|
|
102
|
+
|
|
95
103
|
const useStyles = createStyles((theme) => ({
|
|
96
104
|
container: {
|
|
97
|
-
|
|
105
|
+
// Raised, like Card: in dark the calendar reads as a panel, not only as a border.
|
|
106
|
+
backgroundColor: theme.colors.surfaceRaised,
|
|
98
107
|
borderRadius: theme.tokens.radius.lg,
|
|
99
108
|
borderWidth: 1,
|
|
100
109
|
borderColor: theme.colors.border,
|
|
@@ -113,12 +122,12 @@ const useStyles = createStyles((theme) => ({
|
|
|
113
122
|
},
|
|
114
123
|
row: { flexDirection: 'row' },
|
|
115
124
|
cell: { flex: 1, aspectRatio: 1, alignItems: 'center', justifyContent: 'center' },
|
|
116
|
-
dayButton: { width:
|
|
125
|
+
dayButton: { width: DAY_SIZE, height: DAY_SIZE, borderRadius: DAY_SIZE / 2, alignItems: 'center', justifyContent: 'center' },
|
|
117
126
|
dayText: { fontSize: theme.tokens.fontSize.md, color: theme.colors.text },
|
|
118
127
|
daySelected: { backgroundColor: theme.colors.primary },
|
|
119
128
|
dayTextSelected: { color: theme.colors.onPrimary, fontWeight: theme.tokens.fontWeight.bold },
|
|
120
|
-
//
|
|
121
|
-
//
|
|
129
|
+
// The highlight of the in-between stretch goes on the cell (square, no gaps)
|
|
130
|
+
// and not on the round button, so the range bar looks continuous.
|
|
122
131
|
cellInRange: { backgroundColor: theme.colors.primarySoft },
|
|
123
132
|
cellRangeStart: { borderTopLeftRadius: 18, borderBottomLeftRadius: 18 },
|
|
124
133
|
cellRangeEnd: { borderTopRightRadius: 18, borderBottomRightRadius: 18 },
|
|
@@ -144,8 +153,8 @@ interface DayCellProps {
|
|
|
144
153
|
}
|
|
145
154
|
|
|
146
155
|
/**
|
|
147
|
-
*
|
|
148
|
-
*
|
|
156
|
+
* A calendar cell. It is memoized separately because the whole month is 42
|
|
157
|
+
* cells: without this, any parent render reconciles all 42.
|
|
149
158
|
*/
|
|
150
159
|
const DayCell = memo(
|
|
151
160
|
({
|
|
@@ -173,7 +182,8 @@ const DayCell = memo(
|
|
|
173
182
|
style={[styles.dayButton, selected && styles.daySelected, !selected && isToday && styles.dayToday]}
|
|
174
183
|
onPress={() => onPress(day)}
|
|
175
184
|
disabled={disabled}
|
|
176
|
-
activeOpacity={
|
|
185
|
+
activeOpacity={PRESSED_OPACITY}
|
|
186
|
+
hitSlop={DAY_HIT}
|
|
177
187
|
accessibilityRole="button"
|
|
178
188
|
accessibilityLabel={label}
|
|
179
189
|
accessibilityState={{ selected, disabled }}
|
|
@@ -197,10 +207,21 @@ DayCell.displayName = 'DayCell';
|
|
|
197
207
|
|
|
198
208
|
/**
|
|
199
209
|
* DatePicker
|
|
200
|
-
*
|
|
201
|
-
* @react-native-community/datetimepicker
|
|
202
|
-
*
|
|
210
|
+
* Monthly calendar drawn with plain View/Text — without
|
|
211
|
+
* @react-native-community/datetimepicker or any native picker, to keep the
|
|
212
|
+
* library at zero dependencies and look the same on iOS and Android.
|
|
213
|
+
*
|
|
214
|
+
* Gestalt, common region and alignment: 6 rows of 7 cells always (the grid
|
|
215
|
+
* never jumps between months), weekdays aligned over their column. Similarity:
|
|
216
|
+
* every day is the same circle; state changes only fill and color (selected
|
|
217
|
+
* filled, today outlined, out of range dimmed). Continuity: a range is one
|
|
218
|
+
* band from start to end, not separate dots. Fitts: each day reaches a 44pt touch target (36pt circle + hitSlop).
|
|
219
|
+
*
|
|
220
|
+
* Accessibility: the month is a header, each day reads its full date, and the
|
|
221
|
+
* arrows' names come from `labels` (`previousMonth`, `nextMonth`).
|
|
203
222
|
*/
|
|
223
|
+
const PRESSED_OPACITY = 0.7;
|
|
224
|
+
|
|
204
225
|
export const DatePicker = memo(
|
|
205
226
|
({
|
|
206
227
|
mode = 'single',
|
|
@@ -232,8 +253,8 @@ export const DatePicker = memo(
|
|
|
232
253
|
onChange?.(day);
|
|
233
254
|
return;
|
|
234
255
|
}
|
|
235
|
-
//
|
|
236
|
-
//
|
|
256
|
+
// First tap (or range already closed, or a tap before the start): starts
|
|
257
|
+
// a new range. Second tap onward: closes it.
|
|
237
258
|
if (!range?.start || range.end || dayTime(day) < dayTime(range.start)) {
|
|
238
259
|
onRangeChange?.({ start: day });
|
|
239
260
|
} else {
|
|
@@ -248,8 +269,8 @@ export const DatePicker = memo(
|
|
|
248
269
|
() => new Date((anchor ?? new Date()).getFullYear(), (anchor ?? new Date()).getMonth(), 1)
|
|
249
270
|
);
|
|
250
271
|
|
|
251
|
-
//
|
|
252
|
-
//
|
|
272
|
+
// The selected date can change from outside (controlled use): without this,
|
|
273
|
+
// the calendar stayed stuck on the month it mounted with.
|
|
253
274
|
const anchorMonth = anchor ? monthIndex(anchor) : undefined;
|
|
254
275
|
const lastAnchorMonth = useRef(anchorMonth);
|
|
255
276
|
useEffect(() => {
|
|
@@ -258,8 +279,8 @@ export const DatePicker = memo(
|
|
|
258
279
|
setVisibleMonth(new Date(Math.floor(anchorMonth / 12), anchorMonth % 12, 1));
|
|
259
280
|
}, [anchorMonth]);
|
|
260
281
|
|
|
261
|
-
// "
|
|
262
|
-
//
|
|
282
|
+
// "Today" is recalculated at the next midnight: an app left open all
|
|
283
|
+
// night marked the previous day.
|
|
263
284
|
const [todayTs, setTodayTs] = useState(() => dayTime(new Date()));
|
|
264
285
|
useEffect(() => {
|
|
265
286
|
const timer = setTimeout(() => setTodayTs(dayTime(new Date())), msUntilNextMidnight(new Date()));
|
|
@@ -276,8 +297,8 @@ export const DatePicker = memo(
|
|
|
276
297
|
[weekdays, firstDayOfWeek]
|
|
277
298
|
);
|
|
278
299
|
|
|
279
|
-
//
|
|
280
|
-
// timestamps
|
|
300
|
+
// The limits are resolved once and not 42 times per render: comparing
|
|
301
|
+
// timestamps is free, creating a Date per cell isn't.
|
|
281
302
|
const bounds = useMemo(
|
|
282
303
|
() => ({
|
|
283
304
|
min: dayTimeOf(minDate),
|
|
@@ -296,8 +317,8 @@ export const DatePicker = memo(
|
|
|
296
317
|
return next;
|
|
297
318
|
});
|
|
298
319
|
|
|
299
|
-
//
|
|
300
|
-
//
|
|
320
|
+
// A month entirely outside the limits has nothing to pick: the arrow
|
|
321
|
+
// leading there turns off instead of letting you navigate into the void.
|
|
301
322
|
const visibleIndex = monthIndex(visibleMonth);
|
|
302
323
|
const canGoBack = !minDate || visibleIndex > monthIndex(minDate);
|
|
303
324
|
const canGoForward = !maxDate || visibleIndex < monthIndex(maxDate);
|
|
@@ -309,7 +330,7 @@ export const DatePicker = memo(
|
|
|
309
330
|
<View style={styles.header}>
|
|
310
331
|
<IconButton
|
|
311
332
|
iconName="chevron-left"
|
|
312
|
-
accessibilityLabel=
|
|
333
|
+
accessibilityLabel={labels.previousMonth}
|
|
313
334
|
disabled={!canGoBack}
|
|
314
335
|
onPress={() => shiftMonth(-1)}
|
|
315
336
|
/>
|
|
@@ -318,7 +339,7 @@ export const DatePicker = memo(
|
|
|
318
339
|
</Text>
|
|
319
340
|
<IconButton
|
|
320
341
|
iconName="chevron-right"
|
|
321
|
-
accessibilityLabel=
|
|
342
|
+
accessibilityLabel={labels.nextMonth}
|
|
322
343
|
disabled={!canGoForward}
|
|
323
344
|
onPress={() => shiftMonth(1)}
|
|
324
345
|
/>
|
|
@@ -351,8 +372,8 @@ export const DatePicker = memo(
|
|
|
351
372
|
day={day}
|
|
352
373
|
label={`${months[day.getMonth()]} ${day.getDate()}, ${day.getFullYear()}`}
|
|
353
374
|
selected={selected}
|
|
354
|
-
//
|
|
355
|
-
//
|
|
375
|
+
// A day outside the limits isn't painted as part of the
|
|
376
|
+
// range: it looks disabled, and that is what it is.
|
|
356
377
|
inRange={between && !disabled}
|
|
357
378
|
isRangeStart={!!closed && isStart && !disabled}
|
|
358
379
|
isRangeEnd={isEnd && !disabled}
|
package/src/organisms/List.tsx
CHANGED
|
@@ -8,18 +8,24 @@ import { Spinner } from '../atoms/Spinner';
|
|
|
8
8
|
import type { IconName } from '../icons/types';
|
|
9
9
|
|
|
10
10
|
export interface ListProps<T> {
|
|
11
|
+
/** Items to render. */
|
|
11
12
|
data: T[];
|
|
13
|
+
/** Stable key per item. */
|
|
12
14
|
keyExtractor: (item: T, index: number) => string;
|
|
15
|
+
/** Renders each row (same as FlatList's `renderItem`). */
|
|
13
16
|
renderItem: FlatListProps<T>['renderItem'];
|
|
14
17
|
|
|
15
18
|
/** Initial load: while true and there's no data, placeholders are shown. */
|
|
16
19
|
isLoading: boolean;
|
|
17
20
|
/** Reload with data already on screen (pull-to-refresh). @default false */
|
|
18
21
|
isRefreshing?: boolean;
|
|
22
|
+
/** Shows a spinner in the footer while the next page loads. @default false */
|
|
19
23
|
isLoadingMore?: boolean;
|
|
20
24
|
/** Controlled by the consumer: while false, a fullscreen spinner is shown. @default true */
|
|
21
25
|
isReady?: boolean;
|
|
26
|
+
/** Text of the fullscreen spinner shown while `isReady` is false. @default labels.loading */
|
|
22
27
|
loadingText?: string;
|
|
28
|
+
/** Text of the footer spinner shown with `isLoadingMore`. @default labels.loadingMore */
|
|
23
29
|
loadingMoreText?: string;
|
|
24
30
|
|
|
25
31
|
/** Ghost rows for the initial load. @default 6 */
|
|
@@ -27,22 +33,33 @@ export interface ListProps<T> {
|
|
|
27
33
|
/** Custom placeholder, to match the real shape of the item. */
|
|
28
34
|
renderSkeletonItem?: () => React.ReactElement;
|
|
29
35
|
|
|
36
|
+
/** Called when scrolling gets close to the end (to load the next page). */
|
|
30
37
|
onEndReached?: () => void;
|
|
38
|
+
/** How close to the end `onEndReached` fires, in visible lengths of the list. @default 0.3 */
|
|
31
39
|
onEndReachedThreshold?: number;
|
|
40
|
+
/** Enables pull-to-refresh and is called when the user pulls. */
|
|
32
41
|
onRefresh?: () => void;
|
|
33
42
|
|
|
43
|
+
/** Title of the empty state. @default labels.noResultsTitle */
|
|
34
44
|
emptyTitle?: string;
|
|
45
|
+
/** Supporting line of the empty state. @default labels.noResultsDescription */
|
|
35
46
|
emptyDescription?: string;
|
|
47
|
+
/** Icon of the empty state. @default 'search' */
|
|
36
48
|
emptyIconName?: IconName;
|
|
37
49
|
|
|
50
|
+
/** Rendered above the items, inside the scroll. */
|
|
38
51
|
ListHeaderComponent?: FlatListProps<T>['ListHeaderComponent'];
|
|
52
|
+
/** Rendered below the items, before the pagination loader. */
|
|
39
53
|
ListFooterComponent?: FlatListProps<T>['ListFooterComponent'];
|
|
40
54
|
|
|
55
|
+
/** Style of the list's content container (also used by the skeleton). */
|
|
41
56
|
contentContainerStyle?: ViewStyle;
|
|
57
|
+
/** Style of the outer wrapper. */
|
|
42
58
|
containerStyle?: ViewStyle;
|
|
43
59
|
|
|
44
60
|
/** List component to use (FlashList, etc). @default FlatList */
|
|
45
61
|
ListComponent?: React.ComponentType<any>;
|
|
62
|
+
/** Extra props passed to `ListComponent`; they override the ones set here. */
|
|
46
63
|
listProps?: Record<string, unknown>;
|
|
47
64
|
}
|
|
48
65
|
|
|
@@ -56,14 +73,33 @@ const useStyles = createStyles((theme) => ({
|
|
|
56
73
|
gap: theme.tokens.spacing.md,
|
|
57
74
|
padding: theme.tokens.spacing.md,
|
|
58
75
|
},
|
|
59
|
-
skeletonText: { flex: 1
|
|
76
|
+
skeletonText: { flex: 1 },
|
|
77
|
+
empty: { marginTop: theme.tokens.spacing.xxxl },
|
|
60
78
|
}));
|
|
61
79
|
|
|
80
|
+
/** Same as Avatar's default size: the placeholder row matches a typical avatar row. */
|
|
81
|
+
const SKELETON_AVATAR = 44;
|
|
82
|
+
|
|
83
|
+
function renderHeader(Header: ListProps<unknown>['ListHeaderComponent']) {
|
|
84
|
+
if (!Header) return null;
|
|
85
|
+
return typeof Header === 'function' ? <Header /> : (Header as React.ReactElement);
|
|
86
|
+
}
|
|
87
|
+
|
|
62
88
|
/**
|
|
63
89
|
* List
|
|
64
|
-
*
|
|
65
|
-
* expo-router
|
|
66
|
-
* (
|
|
90
|
+
* List with loading/pagination/empty states handled, without being tied to
|
|
91
|
+
* expo-router or FlashList: `ListComponent` lets you inject any of them
|
|
92
|
+
* (React Native's own FlatList by default).
|
|
93
|
+
*
|
|
94
|
+
* Design:
|
|
95
|
+
* - Continuity (Gestalt): the first load shows placeholders shaped like the
|
|
96
|
+
* rows and keeps `ListHeaderComponent` in place, so nothing jumps when the
|
|
97
|
+
* data arrives.
|
|
98
|
+
* - Doherty threshold: every wait has immediate feedback (placeholders,
|
|
99
|
+
* pull-to-refresh spinner, footer loader while paging), and "no results"
|
|
100
|
+
* only appears once it is known there is nothing.
|
|
101
|
+
* - Jakob's law: the native pull-to-refresh and infinite scroll people
|
|
102
|
+
* already know from other apps.
|
|
67
103
|
*/
|
|
68
104
|
export function List<T>({
|
|
69
105
|
data,
|
|
@@ -98,8 +134,8 @@ export function List<T>({
|
|
|
98
134
|
|
|
99
135
|
const isInitialLoading = isLoading && data.length === 0;
|
|
100
136
|
|
|
101
|
-
//
|
|
102
|
-
//
|
|
137
|
+
// The custom footer and the pagination loader coexist: previously the first
|
|
138
|
+
// covered the second and the list stopped signaling it was fetching more.
|
|
103
139
|
const renderFooter = useCallback(() => {
|
|
104
140
|
const custom =
|
|
105
141
|
typeof ListFooterComponent === 'function' ? (
|
|
@@ -120,16 +156,16 @@ export function List<T>({
|
|
|
120
156
|
);
|
|
121
157
|
}, [isLoadingMore, resolvedLoadingMoreText, ListFooterComponent, styles.footerLoader]);
|
|
122
158
|
|
|
123
|
-
//
|
|
124
|
-
//
|
|
159
|
+
// Empty only once it is known there is nothing: during the initial load
|
|
160
|
+
// placeholders are shown, not "no results".
|
|
125
161
|
const renderEmpty = useCallback(() => {
|
|
126
162
|
if (isLoading || isRefreshing) return null;
|
|
127
|
-
return <EmptyState title={emptyTitle} description={emptyDescription} iconName={emptyIconName} style={
|
|
128
|
-
}, [isLoading, isRefreshing, emptyTitle, emptyDescription, emptyIconName]);
|
|
163
|
+
return <EmptyState title={emptyTitle} description={emptyDescription} iconName={emptyIconName} style={styles.empty} />;
|
|
164
|
+
}, [isLoading, isRefreshing, emptyTitle, emptyDescription, emptyIconName, styles.empty]);
|
|
129
165
|
|
|
130
166
|
if (!isReady) {
|
|
131
167
|
return (
|
|
132
|
-
<View style={styles.container}>
|
|
168
|
+
<View style={[styles.container, containerStyle]}>
|
|
133
169
|
<Spinner text={resolvedLoadingText} />
|
|
134
170
|
</View>
|
|
135
171
|
);
|
|
@@ -137,22 +173,35 @@ export function List<T>({
|
|
|
137
173
|
|
|
138
174
|
if (isInitialLoading) {
|
|
139
175
|
return (
|
|
140
|
-
<View style={[styles.container, containerStyle]}
|
|
176
|
+
<View style={[styles.container, containerStyle]}>
|
|
141
177
|
<View style={[styles.listContent, contentContainerStyle]}>
|
|
178
|
+
{/* Same padding as the loaded list, and outside the group below so it
|
|
179
|
+
stays reachable (a search field above the list, say). */}
|
|
180
|
+
{renderHeader(ListHeaderComponent as ListProps<unknown>['ListHeaderComponent'])}
|
|
181
|
+
<View
|
|
182
|
+
testID="list-skeleton"
|
|
183
|
+
// The placeholders themselves are hidden from screen readers: the
|
|
184
|
+
// group announces that the list is loading instead of silence.
|
|
185
|
+
accessible
|
|
186
|
+
accessibilityRole="progressbar"
|
|
187
|
+
accessibilityLabel={resolvedLoadingText}
|
|
188
|
+
accessibilityState={{ busy: true }}
|
|
189
|
+
>
|
|
142
190
|
{Array.from({ length: skeletonCount }, (_, i) => (
|
|
143
191
|
<React.Fragment key={i}>
|
|
144
192
|
{renderSkeletonItem?.() ?? (
|
|
145
193
|
<View style={styles.skeletonRow}>
|
|
146
|
-
<Skeleton variant="circle" width={
|
|
194
|
+
<Skeleton variant="circle" width={SKELETON_AVATAR} />
|
|
147
195
|
<View style={styles.skeletonText}>
|
|
148
|
-
<Skeleton width="60%"
|
|
149
|
-
<Skeleton width="35%"
|
|
196
|
+
<Skeleton variant="text" width="60%" />
|
|
197
|
+
<Skeleton variant="text" width="35%" />
|
|
150
198
|
</View>
|
|
151
199
|
</View>
|
|
152
200
|
)}
|
|
153
201
|
</React.Fragment>
|
|
154
202
|
))}
|
|
155
203
|
</View>
|
|
204
|
+
</View>
|
|
156
205
|
</View>
|
|
157
206
|
);
|
|
158
207
|
}
|