orn-ui 0.2.9 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +67 -52
- package/README.md +5 -9
- package/lib/commonjs/atoms/Avatar.js +77 -5
- package/lib/commonjs/atoms/Avatar.js.map +1 -1
- package/lib/commonjs/atoms/Badge.js +17 -8
- package/lib/commonjs/atoms/Badge.js.map +1 -1
- package/lib/commonjs/atoms/Button.js +108 -39
- package/lib/commonjs/atoms/Button.js.map +1 -1
- package/lib/commonjs/atoms/Card.js +24 -2
- package/lib/commonjs/atoms/Card.js.map +1 -1
- package/lib/commonjs/atoms/Checkbox.js +41 -10
- package/lib/commonjs/atoms/Checkbox.js.map +1 -1
- package/lib/commonjs/atoms/Divider.js +30 -5
- package/lib/commonjs/atoms/Divider.js.map +1 -1
- package/lib/commonjs/atoms/EmptyState.js +58 -20
- package/lib/commonjs/atoms/EmptyState.js.map +1 -1
- package/lib/commonjs/atoms/Fab.js +32 -12
- package/lib/commonjs/atoms/Fab.js.map +1 -1
- package/lib/commonjs/atoms/Gradient.js +102 -36
- package/lib/commonjs/atoms/Gradient.js.map +1 -1
- package/lib/commonjs/atoms/IconButton.js +25 -4
- package/lib/commonjs/atoms/IconButton.js.map +1 -1
- package/lib/commonjs/atoms/Image.js +61 -25
- package/lib/commonjs/atoms/Image.js.map +1 -1
- package/lib/commonjs/atoms/Input.js +105 -17
- package/lib/commonjs/atoms/Input.js.map +1 -1
- package/lib/commonjs/atoms/KeyValueRow.js +37 -9
- package/lib/commonjs/atoms/KeyValueRow.js.map +1 -1
- package/lib/commonjs/atoms/PressableScale.js +25 -5
- package/lib/commonjs/atoms/PressableScale.js.map +1 -1
- package/lib/commonjs/atoms/ShinyText.js +29 -29
- package/lib/commonjs/atoms/Skeleton.js +28 -13
- package/lib/commonjs/atoms/Skeleton.js.map +1 -1
- package/lib/commonjs/atoms/Spinner.js +81 -22
- package/lib/commonjs/atoms/Spinner.js.map +1 -1
- package/lib/commonjs/atoms/Text.js +56 -5
- package/lib/commonjs/atoms/Text.js.map +1 -1
- package/lib/commonjs/atoms/Transition.js +46 -43
- package/lib/commonjs/atoms/Transition.js.map +1 -1
- package/lib/commonjs/atoms/index.js +6 -0
- package/lib/commonjs/atoms/index.js.map +1 -1
- package/lib/commonjs/atoms/inputValidation.js +56 -0
- package/lib/commonjs/atoms/inputValidation.js.map +1 -0
- package/lib/commonjs/icons/Icon.js +4 -4
- package/lib/commonjs/icons/defaultIcons.js +576 -24
- package/lib/commonjs/icons/defaultIcons.js.map +1 -1
- package/lib/commonjs/icons/index.js +6 -0
- package/lib/commonjs/icons/index.js.map +1 -1
- package/lib/commonjs/molecules/AvatarHeader.js +47 -14
- package/lib/commonjs/molecules/AvatarHeader.js.map +1 -1
- package/lib/commonjs/molecules/FormActions.js +25 -9
- package/lib/commonjs/molecules/FormActions.js.map +1 -1
- package/lib/commonjs/molecules/InfoRow.js +30 -14
- package/lib/commonjs/molecules/InfoRow.js.map +1 -1
- package/lib/commonjs/molecules/OptionCard.js +37 -22
- package/lib/commonjs/molecules/OptionCard.js.map +1 -1
- package/lib/commonjs/molecules/SegmentedControl.js +103 -14
- package/lib/commonjs/molecules/SegmentedControl.js.map +1 -1
- package/lib/commonjs/molecules/Stepper.js +61 -16
- package/lib/commonjs/molecules/Stepper.js.map +1 -1
- package/lib/commonjs/molecules/Steps.js +105 -41
- package/lib/commonjs/molecules/Steps.js.map +1 -1
- package/lib/commonjs/molecules/SymmetricGrid.js +26 -18
- package/lib/commonjs/molecules/SymmetricGrid.js.map +1 -1
- package/lib/commonjs/organisms/Alert.js +49 -35
- package/lib/commonjs/organisms/Alert.js.map +1 -1
- package/lib/commonjs/organisms/AlertProvider.js +10 -10
- package/lib/commonjs/organisms/BottomSheet.js +137 -85
- package/lib/commonjs/organisms/BottomSheet.js.map +1 -1
- package/lib/commonjs/organisms/Chart.js +197 -156
- package/lib/commonjs/organisms/Chart.js.map +1 -1
- package/lib/commonjs/organisms/DateField.js +36 -20
- package/lib/commonjs/organisms/DateField.js.map +1 -1
- package/lib/commonjs/organisms/DatePicker.js +56 -33
- package/lib/commonjs/organisms/DatePicker.js.map +1 -1
- package/lib/commonjs/organisms/List.js +62 -34
- package/lib/commonjs/organisms/List.js.map +1 -1
- package/lib/commonjs/organisms/Modal.js +120 -82
- package/lib/commonjs/organisms/Modal.js.map +1 -1
- package/lib/commonjs/organisms/NavigationBar.js +63 -24
- package/lib/commonjs/organisms/NavigationBar.js.map +1 -1
- package/lib/commonjs/organisms/OptionWheel.js +64 -64
- package/lib/commonjs/organisms/OptionWheel.js.map +1 -1
- package/lib/commonjs/organisms/ReorderableList.js +48 -27
- package/lib/commonjs/organisms/ReorderableList.js.map +1 -1
- package/lib/commonjs/organisms/Screen.js +68 -35
- package/lib/commonjs/organisms/Screen.js.map +1 -1
- package/lib/commonjs/organisms/SearchList.js +56 -26
- package/lib/commonjs/organisms/SearchList.js.map +1 -1
- package/lib/commonjs/organisms/Select.js +45 -24
- package/lib/commonjs/organisms/Select.js.map +1 -1
- package/lib/commonjs/organisms/Slides.js +36 -23
- package/lib/commonjs/organisms/Slides.js.map +1 -1
- package/lib/commonjs/organisms/ThemeToggle.js +10 -9
- package/lib/commonjs/organisms/ThemeToggle.js.map +1 -1
- package/lib/commonjs/organisms/Timeline.js +73 -56
- package/lib/commonjs/organisms/Timeline.js.map +1 -1
- package/lib/commonjs/organisms/Toast.js +46 -15
- package/lib/commonjs/organisms/Toast.js.map +1 -1
- package/lib/commonjs/organisms/ToastProvider.js +14 -10
- package/lib/commonjs/organisms/ToastProvider.js.map +1 -1
- package/lib/commonjs/organisms/Wizard.js +40 -15
- package/lib/commonjs/organisms/Wizard.js.map +1 -1
- package/lib/commonjs/organisms/chart/frame.js +25 -25
- package/lib/commonjs/organisms/chart/frame.js.map +1 -1
- package/lib/commonjs/organisms/chart/marks.js +42 -42
- package/lib/commonjs/organisms/chart/math.js +84 -85
- package/lib/commonjs/organisms/chart/math.js.map +1 -1
- package/lib/commonjs/organisms/chart/palette.js +28 -28
- package/lib/commonjs/organisms/imperativeBridge.js +5 -5
- package/lib/commonjs/organisms/imperativeBridge.js.map +1 -1
- package/lib/commonjs/organisms/useSlides.js +53 -21
- package/lib/commonjs/organisms/useSlides.js.map +1 -1
- package/lib/commonjs/safe-area/SafeAreaUIProvider.js +9 -66
- package/lib/commonjs/safe-area/SafeAreaUIProvider.js.map +1 -1
- package/lib/commonjs/safe-area/index.js.map +1 -1
- package/lib/commonjs/theme/KeyboardAvoidance.js +206 -0
- package/lib/commonjs/theme/KeyboardAvoidance.js.map +1 -0
- package/lib/commonjs/theme/NativeOverlay.js +263 -0
- package/lib/commonjs/theme/NativeOverlay.js.map +1 -0
- package/lib/commonjs/theme/UIProvider.js +86 -33
- package/lib/commonjs/theme/UIProvider.js.map +1 -1
- package/lib/commonjs/theme/colors.js +17 -17
- package/lib/commonjs/theme/colors.js.map +1 -1
- package/lib/commonjs/theme/createStyles.js +19 -16
- package/lib/commonjs/theme/createStyles.js.map +1 -1
- package/lib/commonjs/theme/createTheme.js +6 -6
- package/lib/commonjs/theme/index.js +6 -0
- package/lib/commonjs/theme/index.js.map +1 -1
- package/lib/commonjs/theme/insets.js +1 -1
- package/lib/commonjs/theme/labels.js +29 -1
- package/lib/commonjs/theme/labels.js.map +1 -1
- package/lib/commonjs/theme/palettes.js +25 -23
- package/lib/commonjs/theme/palettes.js.map +1 -1
- package/lib/commonjs/theme/tokens.js +28 -14
- package/lib/commonjs/theme/tokens.js.map +1 -1
- package/lib/commonjs/theme/useKeyboardField.js +36 -0
- package/lib/commonjs/theme/useKeyboardField.js.map +1 -0
- package/lib/commonjs/theme/useReduceMotion.js +31 -0
- package/lib/commonjs/theme/useReduceMotion.js.map +1 -0
- package/lib/module/atoms/Avatar.js +79 -8
- package/lib/module/atoms/Avatar.js.map +1 -1
- package/lib/module/atoms/Badge.js +17 -8
- package/lib/module/atoms/Badge.js.map +1 -1
- package/lib/module/atoms/Button.js +110 -41
- package/lib/module/atoms/Button.js.map +1 -1
- package/lib/module/atoms/Card.js +24 -2
- package/lib/module/atoms/Card.js.map +1 -1
- package/lib/module/atoms/Checkbox.js +42 -11
- package/lib/module/atoms/Checkbox.js.map +1 -1
- package/lib/module/atoms/Divider.js +31 -6
- package/lib/module/atoms/Divider.js.map +1 -1
- package/lib/module/atoms/EmptyState.js +58 -20
- package/lib/module/atoms/EmptyState.js.map +1 -1
- package/lib/module/atoms/Fab.js +33 -13
- package/lib/module/atoms/Fab.js.map +1 -1
- package/lib/module/atoms/Gradient.js +103 -37
- package/lib/module/atoms/Gradient.js.map +1 -1
- package/lib/module/atoms/IconButton.js +25 -4
- package/lib/module/atoms/IconButton.js.map +1 -1
- package/lib/module/atoms/Image.js +61 -25
- package/lib/module/atoms/Image.js.map +1 -1
- package/lib/module/atoms/Input.js +108 -20
- package/lib/module/atoms/Input.js.map +1 -1
- package/lib/module/atoms/KeyValueRow.js +37 -9
- package/lib/module/atoms/KeyValueRow.js.map +1 -1
- package/lib/module/atoms/PressableScale.js +25 -5
- package/lib/module/atoms/PressableScale.js.map +1 -1
- package/lib/module/atoms/ShinyText.js +29 -29
- package/lib/module/atoms/Skeleton.js +30 -13
- package/lib/module/atoms/Skeleton.js.map +1 -1
- package/lib/module/atoms/Spinner.js +82 -23
- package/lib/module/atoms/Spinner.js.map +1 -1
- package/lib/module/atoms/Text.js +56 -5
- package/lib/module/atoms/Text.js.map +1 -1
- package/lib/module/atoms/Transition.js +41 -42
- package/lib/module/atoms/Transition.js.map +1 -1
- package/lib/module/atoms/index.js +1 -1
- package/lib/module/atoms/index.js.map +1 -1
- package/lib/module/atoms/inputValidation.js +52 -0
- package/lib/module/atoms/inputValidation.js.map +1 -0
- package/lib/module/icons/Icon.js +4 -4
- package/lib/module/icons/defaultIcons.js +574 -24
- package/lib/module/icons/defaultIcons.js.map +1 -1
- package/lib/module/icons/index.js +1 -1
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/molecules/AvatarHeader.js +47 -14
- package/lib/module/molecules/AvatarHeader.js.map +1 -1
- package/lib/module/molecules/FormActions.js +25 -9
- package/lib/module/molecules/FormActions.js.map +1 -1
- package/lib/module/molecules/InfoRow.js +30 -14
- package/lib/module/molecules/InfoRow.js.map +1 -1
- package/lib/module/molecules/OptionCard.js +37 -22
- package/lib/module/molecules/OptionCard.js.map +1 -1
- package/lib/module/molecules/SegmentedControl.js +107 -18
- package/lib/module/molecules/SegmentedControl.js.map +1 -1
- package/lib/module/molecules/Stepper.js +63 -18
- package/lib/module/molecules/Stepper.js.map +1 -1
- package/lib/module/molecules/Steps.js +107 -43
- package/lib/module/molecules/Steps.js.map +1 -1
- package/lib/module/molecules/SymmetricGrid.js +26 -18
- package/lib/module/molecules/SymmetricGrid.js.map +1 -1
- package/lib/module/organisms/Alert.js +51 -37
- package/lib/module/organisms/Alert.js.map +1 -1
- package/lib/module/organisms/AlertProvider.js +10 -10
- package/lib/module/organisms/BottomSheet.js +142 -88
- package/lib/module/organisms/BottomSheet.js.map +1 -1
- package/lib/module/organisms/Chart.js +199 -158
- package/lib/module/organisms/Chart.js.map +1 -1
- package/lib/module/organisms/DateField.js +36 -20
- package/lib/module/organisms/DateField.js.map +1 -1
- package/lib/module/organisms/DatePicker.js +56 -33
- package/lib/module/organisms/DatePicker.js.map +1 -1
- package/lib/module/organisms/List.js +62 -34
- package/lib/module/organisms/List.js.map +1 -1
- package/lib/module/organisms/Modal.js +122 -84
- package/lib/module/organisms/Modal.js.map +1 -1
- package/lib/module/organisms/NavigationBar.js +64 -25
- package/lib/module/organisms/NavigationBar.js.map +1 -1
- package/lib/module/organisms/OptionWheel.js +64 -64
- package/lib/module/organisms/OptionWheel.js.map +1 -1
- package/lib/module/organisms/ReorderableList.js +48 -27
- package/lib/module/organisms/ReorderableList.js.map +1 -1
- package/lib/module/organisms/Screen.js +70 -37
- package/lib/module/organisms/Screen.js.map +1 -1
- package/lib/module/organisms/SearchList.js +56 -26
- package/lib/module/organisms/SearchList.js.map +1 -1
- package/lib/module/organisms/Select.js +46 -25
- package/lib/module/organisms/Select.js.map +1 -1
- package/lib/module/organisms/Slides.js +37 -24
- package/lib/module/organisms/Slides.js.map +1 -1
- package/lib/module/organisms/ThemeToggle.js +11 -10
- package/lib/module/organisms/ThemeToggle.js.map +1 -1
- package/lib/module/organisms/Timeline.js +73 -56
- package/lib/module/organisms/Timeline.js.map +1 -1
- package/lib/module/organisms/Toast.js +47 -16
- package/lib/module/organisms/Toast.js.map +1 -1
- package/lib/module/organisms/ToastProvider.js +15 -11
- package/lib/module/organisms/ToastProvider.js.map +1 -1
- package/lib/module/organisms/Wizard.js +41 -16
- package/lib/module/organisms/Wizard.js.map +1 -1
- package/lib/module/organisms/chart/frame.js +25 -25
- package/lib/module/organisms/chart/frame.js.map +1 -1
- package/lib/module/organisms/chart/marks.js +42 -42
- package/lib/module/organisms/chart/math.js +84 -85
- package/lib/module/organisms/chart/math.js.map +1 -1
- package/lib/module/organisms/chart/palette.js +28 -28
- package/lib/module/organisms/imperativeBridge.js +5 -5
- package/lib/module/organisms/imperativeBridge.js.map +1 -1
- package/lib/module/organisms/useSlides.js +53 -21
- package/lib/module/organisms/useSlides.js.map +1 -1
- package/lib/module/safe-area/SafeAreaUIProvider.js +10 -65
- package/lib/module/safe-area/SafeAreaUIProvider.js.map +1 -1
- package/lib/module/safe-area/index.js +1 -0
- package/lib/module/safe-area/index.js.map +1 -1
- package/lib/module/theme/KeyboardAvoidance.js +198 -0
- package/lib/module/theme/KeyboardAvoidance.js.map +1 -0
- package/lib/module/theme/NativeOverlay.js +257 -0
- package/lib/module/theme/NativeOverlay.js.map +1 -0
- package/lib/module/theme/UIProvider.js +88 -35
- package/lib/module/theme/UIProvider.js.map +1 -1
- package/lib/module/theme/colors.js +17 -17
- package/lib/module/theme/colors.js.map +1 -1
- package/lib/module/theme/createStyles.js +20 -16
- package/lib/module/theme/createStyles.js.map +1 -1
- package/lib/module/theme/createTheme.js +6 -6
- package/lib/module/theme/index.js +1 -1
- package/lib/module/theme/index.js.map +1 -1
- package/lib/module/theme/insets.js +1 -1
- package/lib/module/theme/labels.js +29 -1
- package/lib/module/theme/labels.js.map +1 -1
- package/lib/module/theme/palettes.js +25 -23
- package/lib/module/theme/palettes.js.map +1 -1
- package/lib/module/theme/tokens.js +27 -13
- package/lib/module/theme/tokens.js.map +1 -1
- package/lib/module/theme/useKeyboardField.js +33 -0
- package/lib/module/theme/useKeyboardField.js.map +1 -0
- package/lib/module/theme/useReduceMotion.js +28 -0
- package/lib/module/theme/useReduceMotion.js.map +1 -0
- package/lib/typescript/atoms/Avatar.d.ts +35 -5
- package/lib/typescript/atoms/Avatar.d.ts.map +1 -1
- package/lib/typescript/atoms/Badge.d.ts +14 -3
- package/lib/typescript/atoms/Badge.d.ts.map +1 -1
- package/lib/typescript/atoms/Button.d.ts +34 -3
- package/lib/typescript/atoms/Button.d.ts.map +1 -1
- package/lib/typescript/atoms/Card.d.ts +13 -2
- package/lib/typescript/atoms/Card.d.ts.map +1 -1
- package/lib/typescript/atoms/Checkbox.d.ts +26 -1
- package/lib/typescript/atoms/Checkbox.d.ts.map +1 -1
- package/lib/typescript/atoms/Divider.d.ts +18 -1
- package/lib/typescript/atoms/Divider.d.ts.map +1 -1
- package/lib/typescript/atoms/EmptyState.d.ts +30 -3
- package/lib/typescript/atoms/EmptyState.d.ts.map +1 -1
- package/lib/typescript/atoms/Fab.d.ts +24 -4
- package/lib/typescript/atoms/Fab.d.ts.map +1 -1
- package/lib/typescript/atoms/Gradient.d.ts +21 -15
- package/lib/typescript/atoms/Gradient.d.ts.map +1 -1
- package/lib/typescript/atoms/IconButton.d.ts +18 -4
- package/lib/typescript/atoms/IconButton.d.ts.map +1 -1
- package/lib/typescript/atoms/Image.d.ts +39 -17
- package/lib/typescript/atoms/Image.d.ts.map +1 -1
- package/lib/typescript/atoms/Input.d.ts +57 -7
- package/lib/typescript/atoms/Input.d.ts.map +1 -1
- package/lib/typescript/atoms/KeyValueRow.d.ts +16 -4
- package/lib/typescript/atoms/KeyValueRow.d.ts.map +1 -1
- package/lib/typescript/atoms/PressableScale.d.ts +12 -5
- package/lib/typescript/atoms/PressableScale.d.ts.map +1 -1
- package/lib/typescript/atoms/ShinyText.d.ts +17 -17
- package/lib/typescript/atoms/ShinyText.d.ts.map +1 -1
- package/lib/typescript/atoms/Skeleton.d.ts +12 -7
- package/lib/typescript/atoms/Skeleton.d.ts.map +1 -1
- package/lib/typescript/atoms/Spinner.d.ts +29 -1
- package/lib/typescript/atoms/Spinner.d.ts.map +1 -1
- package/lib/typescript/atoms/Text.d.ts +46 -0
- package/lib/typescript/atoms/Text.d.ts.map +1 -1
- package/lib/typescript/atoms/Transition.d.ts +19 -15
- package/lib/typescript/atoms/Transition.d.ts.map +1 -1
- package/lib/typescript/atoms/index.d.ts +3 -3
- package/lib/typescript/atoms/index.d.ts.map +1 -1
- package/lib/typescript/atoms/inputValidation.d.ts +29 -0
- package/lib/typescript/atoms/inputValidation.d.ts.map +1 -0
- package/lib/typescript/icons/Icon.d.ts +4 -4
- package/lib/typescript/icons/defaultIcons.d.ts +19 -2
- package/lib/typescript/icons/defaultIcons.d.ts.map +1 -1
- package/lib/typescript/icons/index.d.ts +2 -2
- package/lib/typescript/icons/index.d.ts.map +1 -1
- package/lib/typescript/icons/types.d.ts +13 -3
- package/lib/typescript/icons/types.d.ts.map +1 -1
- package/lib/typescript/molecules/AvatarHeader.d.ts +23 -4
- package/lib/typescript/molecules/AvatarHeader.d.ts.map +1 -1
- package/lib/typescript/molecules/FormActions.d.ts +21 -4
- package/lib/typescript/molecules/FormActions.d.ts.map +1 -1
- package/lib/typescript/molecules/InfoRow.d.ts +17 -3
- package/lib/typescript/molecules/InfoRow.d.ts.map +1 -1
- package/lib/typescript/molecules/OptionCard.d.ts +20 -5
- package/lib/typescript/molecules/OptionCard.d.ts.map +1 -1
- package/lib/typescript/molecules/SegmentedControl.d.ts +18 -2
- package/lib/typescript/molecules/SegmentedControl.d.ts.map +1 -1
- package/lib/typescript/molecules/Stepper.d.ts +23 -7
- package/lib/typescript/molecules/Stepper.d.ts.map +1 -1
- package/lib/typescript/molecules/Steps.d.ts +18 -4
- package/lib/typescript/molecules/Steps.d.ts.map +1 -1
- package/lib/typescript/molecules/SymmetricGrid.d.ts +15 -5
- package/lib/typescript/molecules/SymmetricGrid.d.ts.map +1 -1
- package/lib/typescript/organisms/Alert.d.ts +28 -2
- package/lib/typescript/organisms/Alert.d.ts.map +1 -1
- package/lib/typescript/organisms/AlertProvider.d.ts +10 -10
- package/lib/typescript/organisms/AlertProvider.d.ts.map +1 -1
- package/lib/typescript/organisms/BottomSheet.d.ts +20 -5
- package/lib/typescript/organisms/BottomSheet.d.ts.map +1 -1
- package/lib/typescript/organisms/Chart.d.ts +86 -75
- package/lib/typescript/organisms/Chart.d.ts.map +1 -1
- package/lib/typescript/organisms/DateField.d.ts +17 -3
- package/lib/typescript/organisms/DateField.d.ts.map +1 -1
- package/lib/typescript/organisms/DatePicker.d.ts +7 -11
- package/lib/typescript/organisms/DatePicker.d.ts.map +1 -1
- package/lib/typescript/organisms/List.d.ts +30 -3
- package/lib/typescript/organisms/List.d.ts.map +1 -1
- package/lib/typescript/organisms/Modal.d.ts +30 -3
- package/lib/typescript/organisms/Modal.d.ts.map +1 -1
- package/lib/typescript/organisms/NavigationBar.d.ts +26 -7
- package/lib/typescript/organisms/NavigationBar.d.ts.map +1 -1
- package/lib/typescript/organisms/OptionWheel.d.ts +20 -16
- package/lib/typescript/organisms/OptionWheel.d.ts.map +1 -1
- package/lib/typescript/organisms/ReorderableList.d.ts +20 -11
- package/lib/typescript/organisms/ReorderableList.d.ts.map +1 -1
- package/lib/typescript/organisms/Screen.d.ts +27 -8
- package/lib/typescript/organisms/Screen.d.ts.map +1 -1
- package/lib/typescript/organisms/SearchList.d.ts +46 -3
- package/lib/typescript/organisms/SearchList.d.ts.map +1 -1
- package/lib/typescript/organisms/Select.d.ts +26 -6
- package/lib/typescript/organisms/Select.d.ts.map +1 -1
- package/lib/typescript/organisms/Slides.d.ts +44 -26
- package/lib/typescript/organisms/Slides.d.ts.map +1 -1
- package/lib/typescript/organisms/ThemeToggle.d.ts +6 -2
- package/lib/typescript/organisms/ThemeToggle.d.ts.map +1 -1
- package/lib/typescript/organisms/Timeline.d.ts +26 -9
- package/lib/typescript/organisms/Timeline.d.ts.map +1 -1
- package/lib/typescript/organisms/Toast.d.ts +19 -4
- package/lib/typescript/organisms/Toast.d.ts.map +1 -1
- package/lib/typescript/organisms/ToastProvider.d.ts +8 -8
- package/lib/typescript/organisms/ToastProvider.d.ts.map +1 -1
- package/lib/typescript/organisms/Wizard.d.ts +24 -6
- package/lib/typescript/organisms/Wizard.d.ts.map +1 -1
- package/lib/typescript/organisms/chart/frame.d.ts +21 -21
- package/lib/typescript/organisms/chart/frame.d.ts.map +1 -1
- package/lib/typescript/organisms/chart/marks.d.ts +28 -28
- package/lib/typescript/organisms/chart/marks.d.ts.map +1 -1
- package/lib/typescript/organisms/chart/math.d.ts +69 -70
- package/lib/typescript/organisms/chart/math.d.ts.map +1 -1
- package/lib/typescript/organisms/chart/palette.d.ts +2 -2
- package/lib/typescript/organisms/chart/palette.d.ts.map +1 -1
- package/lib/typescript/organisms/imperativeBridge.d.ts +4 -4
- package/lib/typescript/organisms/useSlides.d.ts +8 -16
- package/lib/typescript/organisms/useSlides.d.ts.map +1 -1
- package/lib/typescript/safe-area/SafeAreaUIProvider.d.ts +9 -7
- package/lib/typescript/safe-area/SafeAreaUIProvider.d.ts.map +1 -1
- package/lib/typescript/safe-area/index.d.ts.map +1 -1
- package/lib/typescript/theme/KeyboardAvoidance.d.ts +62 -0
- package/lib/typescript/theme/KeyboardAvoidance.d.ts.map +1 -0
- package/lib/typescript/theme/NativeOverlay.d.ts +43 -0
- package/lib/typescript/theme/NativeOverlay.d.ts.map +1 -0
- package/lib/typescript/theme/UIProvider.d.ts +38 -20
- package/lib/typescript/theme/UIProvider.d.ts.map +1 -1
- package/lib/typescript/theme/colors.d.ts +13 -13
- package/lib/typescript/theme/colors.d.ts.map +1 -1
- package/lib/typescript/theme/createStyles.d.ts +20 -14
- package/lib/typescript/theme/createStyles.d.ts.map +1 -1
- package/lib/typescript/theme/createTheme.d.ts +5 -5
- package/lib/typescript/theme/index.d.ts +1 -1
- package/lib/typescript/theme/index.d.ts.map +1 -1
- package/lib/typescript/theme/insets.d.ts +1 -1
- package/lib/typescript/theme/insets.d.ts.map +1 -1
- package/lib/typescript/theme/labels.d.ts +57 -2
- package/lib/typescript/theme/labels.d.ts.map +1 -1
- package/lib/typescript/theme/palettes.d.ts +25 -19
- package/lib/typescript/theme/palettes.d.ts.map +1 -1
- package/lib/typescript/theme/tokens.d.ts +15 -8
- package/lib/typescript/theme/tokens.d.ts.map +1 -1
- package/lib/typescript/theme/types.d.ts +7 -7
- package/lib/typescript/theme/types.d.ts.map +1 -1
- package/lib/typescript/theme/useKeyboardField.d.ts +17 -0
- package/lib/typescript/theme/useKeyboardField.d.ts.map +1 -0
- package/lib/typescript/theme/useReduceMotion.d.ts +7 -0
- package/lib/typescript/theme/useReduceMotion.d.ts.map +1 -0
- package/llms.txt +4 -4
- package/package.json +15 -14
- package/registry/alert-provider.json +4 -3
- package/registry/alert.json +3 -2
- package/registry/avatar-header.json +1 -1
- package/registry/avatar.json +3 -2
- package/registry/badge.json +1 -1
- package/registry/bottom-sheet.json +1 -1
- package/registry/button.json +3 -2
- package/registry/card.json +1 -1
- package/registry/chart.json +5 -5
- package/registry/checkbox.json +3 -2
- package/registry/core.json +31 -15
- package/registry/date-field.json +1 -1
- package/registry/date-picker.json +3 -2
- package/registry/divider.json +1 -1
- package/registry/empty-state.json +4 -2
- package/registry/fab.json +3 -2
- package/registry/form-actions.json +3 -2
- package/registry/gradient.json +1 -1
- package/registry/icon-button.json +3 -2
- package/registry/image.json +1 -1
- package/registry/index.json +79 -61
- package/registry/info-row.json +1 -1
- package/registry/input.json +5 -1
- package/registry/key-value-row.json +1 -1
- package/registry/list.json +3 -1
- package/registry/manifest.json +3 -1
- package/registry/modal.json +1 -1
- package/registry/navigation-bar.json +1 -1
- package/registry/option-card.json +3 -2
- package/registry/option-wheel.json +1 -1
- package/registry/pressable-scale.json +3 -2
- package/registry/reorderable-list.json +1 -1
- package/registry/screen.json +1 -1
- package/registry/search-list.json +7 -1
- package/registry/segmented-control.json +1 -1
- package/registry/select.json +1 -1
- package/registry/shiny-text.json +1 -1
- package/registry/skeleton.json +3 -2
- package/registry/slides.json +2 -2
- package/registry/spinner.json +1 -1
- package/registry/stepper.json +1 -1
- package/registry/steps.json +1 -1
- package/registry/symmetric-grid.json +1 -1
- package/registry/theme-toggle.json +1 -1
- package/registry/timeline.json +1 -1
- package/registry/title.json +1 -1
- package/registry/toast-provider.json +2 -2
- package/registry/toast.json +1 -1
- package/registry/transition.json +1 -1
- package/registry/wizard.json +1 -1
- package/src/atoms/Avatar.tsx +117 -26
- package/src/atoms/Badge.tsx +20 -9
- package/src/atoms/Button.tsx +102 -30
- package/src/atoms/Card.tsx +23 -3
- package/src/atoms/Checkbox.tsx +49 -12
- package/src/atoms/Divider.tsx +34 -4
- package/src/atoms/EmptyState.tsx +63 -16
- package/src/atoms/Fab.tsx +56 -9
- package/src/atoms/Gradient.tsx +92 -41
- package/src/atoms/IconButton.tsx +27 -4
- package/src/atoms/Image.tsx +74 -28
- package/src/atoms/Input.tsx +129 -19
- package/src/atoms/KeyValueRow.tsx +72 -28
- package/src/atoms/PressableScale.tsx +31 -7
- package/src/atoms/ShinyText.tsx +31 -31
- package/src/atoms/Skeleton.tsx +37 -17
- package/src/atoms/Spinner.tsx +87 -24
- package/src/atoms/Text.tsx +66 -6
- package/src/atoms/Transition.tsx +40 -44
- package/src/atoms/index.ts +3 -3
- package/src/atoms/inputValidation.ts +59 -0
- package/src/icons/Icon.tsx +4 -4
- package/src/icons/defaultIcons.tsx +445 -22
- package/src/icons/index.ts +2 -2
- package/src/icons/types.ts +26 -4
- package/src/molecules/AvatarHeader.tsx +88 -34
- package/src/molecules/FormActions.tsx +36 -6
- package/src/molecules/InfoRow.tsx +39 -12
- package/src/molecules/OptionCard.tsx +55 -20
- package/src/molecules/SegmentedControl.tsx +135 -15
- package/src/molecules/Stepper.tsx +73 -19
- package/src/molecules/Steps.tsx +121 -39
- package/src/molecules/SymmetricGrid.tsx +28 -12
- package/src/organisms/Alert.tsx +97 -26
- package/src/organisms/AlertProvider.tsx +13 -13
- package/src/organisms/BottomSheet.tsx +115 -43
- package/src/organisms/Chart.tsx +223 -165
- package/src/organisms/DateField.tsx +40 -15
- package/src/organisms/DatePicker.tsx +53 -32
- package/src/organisms/List.tsx +64 -15
- package/src/organisms/Modal.tsx +122 -63
- package/src/organisms/NavigationBar.tsx +73 -23
- package/src/organisms/OptionWheel.tsx +70 -66
- package/src/organisms/ReorderableList.tsx +49 -27
- package/src/organisms/Screen.tsx +79 -42
- package/src/organisms/SearchList.tsx +84 -20
- package/src/organisms/Select.tsx +63 -29
- package/src/organisms/Slides.tsx +63 -44
- package/src/organisms/ThemeToggle.tsx +15 -6
- package/src/organisms/Timeline.tsx +79 -62
- package/src/organisms/Toast.tsx +50 -15
- package/src/organisms/ToastProvider.tsx +17 -13
- package/src/organisms/Wizard.tsx +58 -21
- package/src/organisms/chart/frame.tsx +35 -35
- package/src/organisms/chart/marks.tsx +53 -53
- package/src/organisms/chart/math.ts +93 -94
- package/src/organisms/chart/palette.ts +28 -28
- package/src/organisms/imperativeBridge.ts +5 -5
- package/src/organisms/useSlides.ts +66 -31
- package/src/safe-area/SafeAreaUIProvider.tsx +9 -70
- package/src/safe-area/index.ts +1 -0
- package/src/theme/KeyboardAvoidance.tsx +216 -0
- package/src/theme/NativeOverlay.tsx +269 -0
- package/src/theme/UIProvider.tsx +109 -46
- package/src/theme/colors.ts +21 -21
- package/src/theme/createStyles.ts +23 -19
- package/src/theme/createTheme.ts +6 -6
- package/src/theme/index.ts +1 -1
- package/src/theme/insets.ts +1 -1
- package/src/theme/labels.ts +85 -2
- package/src/theme/palettes.ts +33 -25
- package/src/theme/tokens.ts +27 -13
- package/src/theme/types.ts +7 -7
- package/src/theme/useKeyboardField.ts +33 -0
- package/src/theme/useReduceMotion.ts +27 -0
package/src/organisms/Chart.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { memo, useCallback, useMemo, useRef, useState } from 'react';
|
|
1
|
+
import React, { createContext, memo, useCallback, useContext, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Pressable,
|
|
4
4
|
Text,
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { contrast } from '../theme/colors';
|
|
12
12
|
import { createStyles } from '../theme/createStyles';
|
|
13
13
|
import { useAllowFontScaling, useLabels, useTheme } from '../theme/UIProvider';
|
|
14
|
+
import { useReduceMotion } from '../theme/useReduceMotion';
|
|
14
15
|
import { SegmentedControl } from '../molecules/SegmentedControl';
|
|
15
16
|
import { Bar, Dot, Polyline, Wedge } from './chart/marks';
|
|
16
17
|
import { AxisLabels, CartesianGrid, Legend, RadarGrid, Tooltip, type LegendItem, type TooltipRow } from './chart/frame';
|
|
@@ -43,11 +44,11 @@ export type { ChartRow } from './chart/math';
|
|
|
43
44
|
export type ChartType = 'bar' | 'line' | 'area' | 'pie' | 'donut' | 'radar';
|
|
44
45
|
|
|
45
46
|
export interface ChartSeries {
|
|
46
|
-
/**
|
|
47
|
+
/** Column of `data` this series reads. */
|
|
47
48
|
key: string;
|
|
48
|
-
/**
|
|
49
|
+
/** Text shown in the legend and tooltip. Defaults to `key`. */
|
|
49
50
|
label?: string;
|
|
50
|
-
/**
|
|
51
|
+
/** Overrides the color derived from the theme. */
|
|
51
52
|
color?: string;
|
|
52
53
|
}
|
|
53
54
|
|
|
@@ -57,9 +58,9 @@ export interface ChartFilterOption {
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
61
|
+
* A filter in the top bar. Chart doesn't filter anything on its own: it shows
|
|
62
|
+
* the control and reports. Whoever has the data decides what "last 7 days"
|
|
63
|
+
* means, and that can't be guessed from here.
|
|
63
64
|
*/
|
|
64
65
|
export interface ChartFilter {
|
|
65
66
|
key: string;
|
|
@@ -70,130 +71,147 @@ export interface ChartFilter {
|
|
|
70
71
|
|
|
71
72
|
export interface ChartSelection {
|
|
72
73
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
74
|
+
* Row identity, stable across a `window` or decimation. Comes from
|
|
75
|
+
* `selectBy`; without it, it is the index, which does not survive the data
|
|
76
|
+
* shifting.
|
|
76
77
|
*/
|
|
77
78
|
id: string;
|
|
78
79
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
80
|
+
* Index within the **drawn** rows, not `data`: with `window` or decimation
|
|
81
|
+
* they are not the same list. Use `row` to get back to the datum.
|
|
81
82
|
*/
|
|
82
83
|
index: number;
|
|
83
|
-
/**
|
|
84
|
+
/** The whole row, without resolving the index against anything. */
|
|
84
85
|
row: ChartRow;
|
|
85
|
-
/**
|
|
86
|
+
/** Value of `xKey` in that row. */
|
|
86
87
|
label: string;
|
|
87
|
-
/**
|
|
88
|
+
/** Series that was touched. In a pie it is the row, which is the category there. */
|
|
88
89
|
seriesKey: string;
|
|
89
90
|
value: number;
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
interface ChartBaseProps {
|
|
94
|
+
/** Rows: one per category, with the label in `xKey` and one column per series. */
|
|
93
95
|
data: ChartRow[];
|
|
94
96
|
/**
|
|
95
|
-
* Series
|
|
96
|
-
*
|
|
97
|
+
* Series to draw. 'pie'/'donut' only use the first one: a pie's categories
|
|
98
|
+
* are the rows, not the columns.
|
|
97
99
|
*/
|
|
98
100
|
series: ChartSeries[];
|
|
99
|
-
/**
|
|
101
|
+
/** Column holding each row's label. @default 'x' */
|
|
100
102
|
xKey?: string;
|
|
101
103
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
104
|
+
* Stable identity of a row. Without it the selection is stored by index,
|
|
105
|
+
* and in a sliding window the index shifts: the highlighted point ends up
|
|
106
|
+
* pointing at another datum without anyone touching it. With it the
|
|
107
|
+
* highlight follows the datum and disappears only when it leaves the window.
|
|
106
108
|
*/
|
|
107
109
|
selectBy?: (row: ChartRow, index: number) => string;
|
|
108
110
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
+
* Draws only the last N rows. It is the sliding window of a live chart: the
|
|
112
|
+
* code pushing data doesn't have to trim it on every tick.
|
|
111
113
|
*/
|
|
112
114
|
window?: number;
|
|
113
|
-
/**
|
|
115
|
+
/** Height of the plot area, excluding filters and legend. @default 220 */
|
|
114
116
|
height?: number;
|
|
115
117
|
/**
|
|
116
|
-
* 'toggle'
|
|
117
|
-
*
|
|
118
|
+
* 'toggle' turns the legend into the cheapest filter a chart has: tapping a
|
|
119
|
+
* series hides it. @default 'auto' (toggle with 2+ series, none with one)
|
|
118
120
|
*/
|
|
119
121
|
legend?: 'auto' | 'none' | 'static' | 'toggle';
|
|
120
|
-
/**
|
|
122
|
+
/** Hidden series (controlled). Without it, Chart tracks them itself. */
|
|
121
123
|
hiddenKeys?: string[];
|
|
122
|
-
/** @default [] */
|
|
124
|
+
/** Series hidden at first (uncontrolled). @default [] */
|
|
123
125
|
defaultHiddenKeys?: string[];
|
|
126
|
+
/** Called when the legend shows or hides a series. */
|
|
124
127
|
onHiddenKeysChange?: (keys: string[]) => void;
|
|
125
|
-
/**
|
|
128
|
+
/** Controls above the chart, one per filter. */
|
|
126
129
|
filters?: ChartFilter[];
|
|
127
|
-
/**
|
|
130
|
+
/** Highlighted point (controlled). `null` means none. */
|
|
128
131
|
selected?: ChartSelection | null;
|
|
132
|
+
/** Called when a category is tapped, with `null` when it is released. */
|
|
129
133
|
onSelect?: (selection: ChartSelection | null) => void;
|
|
130
|
-
/**
|
|
134
|
+
/** Bubble with the values of the touched category. @default true */
|
|
131
135
|
tooltip?: boolean;
|
|
132
|
-
/** @default
|
|
136
|
+
/** Formats values on the axis, tooltip and slices. @default compact format: 1.2k, 3.4M */
|
|
133
137
|
formatValue?: (value: number) => string;
|
|
134
|
-
/** @default true */
|
|
138
|
+
/** Marks grow in on mount and morph on data changes (off with Reduce Motion). @default true */
|
|
135
139
|
animate?: boolean;
|
|
136
|
-
/**
|
|
140
|
+
/** Duration in ms of the marks' animation. @default tokens.duration.slow * 2 */
|
|
137
141
|
duration?: number;
|
|
138
|
-
/**
|
|
142
|
+
/** Text shown when there is nothing left to draw. */
|
|
139
143
|
emptyText?: string;
|
|
140
|
-
/**
|
|
144
|
+
/** Required: a chart has no text that describes it. */
|
|
141
145
|
accessibilityLabel: string;
|
|
146
|
+
/**
|
|
147
|
+
* Color behind the chart. The donut hole and the ring around points are
|
|
148
|
+
* painted with it, so they must match whatever the chart sits on.
|
|
149
|
+
* @default colors.surfaceRaised (a Chart usually lives in a Card)
|
|
150
|
+
*/
|
|
151
|
+
surfaceColor?: string;
|
|
142
152
|
style?: StyleProp<ViewStyle>;
|
|
143
153
|
testID?: string;
|
|
144
154
|
}
|
|
145
155
|
|
|
156
|
+
/** Background the marks paint "holes" with (donut center, point rings). */
|
|
157
|
+
const ChartSurfaceContext = createContext<string | undefined>(undefined);
|
|
158
|
+
function useChartSurface(): string {
|
|
159
|
+
const theme = useTheme();
|
|
160
|
+
return useContext(ChartSurfaceContext) ?? theme.colors.surfaceRaised;
|
|
161
|
+
}
|
|
162
|
+
|
|
146
163
|
interface CartesianProps {
|
|
147
164
|
/**
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
165
|
+
* Fixes the value axis. By default it is recomputed with every datum, which
|
|
166
|
+
* is right for a static chart and worst for a live one: a higher value
|
|
167
|
+
* arrives, the whole scale shifts and the line jumps even though the data
|
|
168
|
+
* didn't move.
|
|
152
169
|
*
|
|
153
|
-
* - `[min, max]` —
|
|
154
|
-
* - `'sticky'` —
|
|
155
|
-
*
|
|
170
|
+
* - `[min, max]` — exact, not rounded to nice numbers.
|
|
171
|
+
* - `'sticky'` — starts from the data and grows when something doesn't fit,
|
|
172
|
+
* but never shrinks back.
|
|
156
173
|
*/
|
|
157
174
|
domain?: [number, number] | 'sticky';
|
|
158
|
-
/**
|
|
175
|
+
/** Reference lines on the value axis. @default true */
|
|
159
176
|
grid?: boolean;
|
|
160
|
-
/**
|
|
177
|
+
/** Target tick count on the value axis; rounding may yield one more or one fewer. @default 4 */
|
|
161
178
|
ticks?: number;
|
|
162
|
-
/**
|
|
179
|
+
/** Labels on the horizontal axis. @default true */
|
|
163
180
|
xAxis?: boolean;
|
|
164
|
-
/**
|
|
181
|
+
/** Labels on the vertical axis. @default true */
|
|
165
182
|
yAxis?: boolean;
|
|
166
183
|
}
|
|
167
184
|
|
|
168
185
|
interface BarChartProps extends CartesianProps {
|
|
186
|
+
/** Kind of chart. Props marked "Only with type" depend on it. */
|
|
169
187
|
type: 'bar';
|
|
170
|
-
/** 'horizontal'
|
|
188
|
+
/** 'horizontal' puts the categories on the vertical axis. @default 'vertical' */
|
|
171
189
|
orientation?: 'vertical' | 'horizontal';
|
|
172
|
-
/**
|
|
190
|
+
/** Stacks the series instead of placing them side by side. @default false */
|
|
173
191
|
stacked?: boolean;
|
|
174
|
-
/**
|
|
192
|
+
/** Radius of each bar's free end. @default radius.xs */
|
|
175
193
|
barRadius?: number;
|
|
176
194
|
}
|
|
177
195
|
|
|
178
196
|
interface LineChartProps extends CartesianProps {
|
|
179
197
|
type: 'line';
|
|
180
198
|
/**
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
* `false`
|
|
199
|
+
* Maximum number of points to draw, picked with LTTB. Defaults to a value
|
|
200
|
+
* derived from the measured width: more than one point every two pixels
|
|
201
|
+
* isn't visible but still costs. `false` draws them all.
|
|
184
202
|
*/
|
|
185
203
|
decimate?: number | false;
|
|
186
|
-
/** Catmull-Rom
|
|
204
|
+
/** Catmull-Rom curves instead of straight segments. @default false */
|
|
187
205
|
smooth?: boolean;
|
|
188
|
-
/** @default 2 */
|
|
206
|
+
/** Line width in pt. @default 2 */
|
|
189
207
|
thickness?: number;
|
|
190
|
-
/**
|
|
208
|
+
/** A dot on each datum. @default true */
|
|
191
209
|
dots?: boolean;
|
|
192
210
|
}
|
|
193
211
|
|
|
194
212
|
interface AreaChartProps extends CartesianProps {
|
|
195
213
|
type: 'area';
|
|
196
|
-
/**
|
|
214
|
+
/** Same as in 'line'. */
|
|
197
215
|
decimate?: number | false;
|
|
198
216
|
smooth?: boolean;
|
|
199
217
|
thickness?: number;
|
|
@@ -201,20 +219,21 @@ interface AreaChartProps extends CartesianProps {
|
|
|
201
219
|
dots?: boolean;
|
|
202
220
|
/** @default false */
|
|
203
221
|
stacked?: boolean;
|
|
204
|
-
/**
|
|
222
|
+
/** Opacity of the fill under the line. @default 0.22 */
|
|
205
223
|
fillOpacity?: number;
|
|
206
224
|
}
|
|
207
225
|
|
|
208
226
|
interface PieBaseProps {
|
|
209
|
-
/**
|
|
227
|
+
/** Hole as a fraction of the radius, 0–0.9. @default 0 for 'pie', 0.6 for 'donut' */
|
|
210
228
|
innerRadius?: number;
|
|
211
|
-
/**
|
|
229
|
+
/** What to write on each slice. @default 'percent' */
|
|
212
230
|
sliceLabels?: 'none' | 'percent' | 'value';
|
|
213
231
|
}
|
|
214
232
|
|
|
215
|
-
// 'pie'
|
|
216
|
-
//
|
|
217
|
-
//
|
|
233
|
+
// 'pie' and 'donut' are kept separate even though they share everything: with
|
|
234
|
+
// a single member whose `type` were `'pie' | 'donut'`, TypeScript doesn't drop
|
|
235
|
+
// that member from the union when ruling it out, and the rest of the component
|
|
236
|
+
// stops narrowing.
|
|
218
237
|
interface PieChartProps extends PieBaseProps {
|
|
219
238
|
type: 'pie';
|
|
220
239
|
}
|
|
@@ -226,13 +245,13 @@ interface DonutChartProps extends PieBaseProps {
|
|
|
226
245
|
interface RadarChartProps {
|
|
227
246
|
type: 'radar';
|
|
228
247
|
/**
|
|
229
|
-
*
|
|
230
|
-
*
|
|
248
|
+
* Fixes the axes' range. A radar measures from the center, so the minimum is
|
|
249
|
+
* always 0 and only `max` of `[min, max]` is used.
|
|
231
250
|
*/
|
|
232
251
|
domain?: [number, number] | 'sticky';
|
|
233
|
-
/**
|
|
252
|
+
/** Rings of the web. @default 4 */
|
|
234
253
|
levels?: number;
|
|
235
|
-
/**
|
|
254
|
+
/** Fills the polygon in addition to drawing its outline. @default true */
|
|
236
255
|
fill?: boolean;
|
|
237
256
|
thickness?: number;
|
|
238
257
|
/** @default true */
|
|
@@ -244,15 +263,24 @@ export type ChartProps = ChartBaseProps &
|
|
|
244
263
|
|
|
245
264
|
const DEFAULT_HEIGHT = 220;
|
|
246
265
|
const DEFAULT_TICKS = 4;
|
|
247
|
-
/**
|
|
266
|
+
/** Floor of the value-label gutter, on the left. */
|
|
248
267
|
const VALUE_GUTTER = 38;
|
|
249
|
-
/**
|
|
268
|
+
/**
|
|
269
|
+
* Estimated width of a label character. React Native doesn't measure text
|
|
270
|
+
* without rendering it, and measuring to decide the layout would make the
|
|
271
|
+
* chart show up shifted for a frame; at `fontSize.xs` a digit is around
|
|
272
|
+
* 0.6em, and too much is better than too little — extra room, no clipped number.
|
|
273
|
+
*/
|
|
274
|
+
const VALUE_CHAR = 6.5;
|
|
275
|
+
/** Gutter cap: a wide axis can't eat the plot. */
|
|
276
|
+
const VALUE_GUTTER_MAX = 0.3;
|
|
277
|
+
/** Category gutter when they go on the left (horizontal bars). */
|
|
250
278
|
const CATEGORY_GUTTER = 64;
|
|
251
|
-
/**
|
|
279
|
+
/** Gutter for the bottom labels. */
|
|
252
280
|
const BOTTOM_GUTTER = 16;
|
|
253
|
-
/**
|
|
281
|
+
/** Fraction of the band width taken by the bars; the rest is room. */
|
|
254
282
|
const BAND_FILL = 0.7;
|
|
255
|
-
/**
|
|
283
|
+
/** Room around the radar so the axis labels fit. */
|
|
256
284
|
const RADAR_INSET = 26;
|
|
257
285
|
const DIM_OPACITY = 0.3;
|
|
258
286
|
|
|
@@ -284,7 +312,7 @@ const useStyles = createStyles((theme) => ({
|
|
|
284
312
|
},
|
|
285
313
|
}));
|
|
286
314
|
|
|
287
|
-
/**
|
|
315
|
+
/** Controlled or own state, with the same contract in both cases. */
|
|
288
316
|
function useControlled<T>(controlled: T | undefined, fallback: T): [T, (next: T) => void, boolean] {
|
|
289
317
|
const [own, setOwn] = useState(fallback);
|
|
290
318
|
const isControlled = controlled !== undefined;
|
|
@@ -292,10 +320,10 @@ function useControlled<T>(controlled: T | undefined, fallback: T): [T, (next: T)
|
|
|
292
320
|
}
|
|
293
321
|
|
|
294
322
|
/**
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
323
|
+
* Resolves the value axis domain from what the consumer asked for. In
|
|
324
|
+
* 'sticky' the reference lives in a ref: what matters isn't this render's
|
|
325
|
+
* domain but the widest one seen so far, and keeping it in state would fire
|
|
326
|
+
* an extra render for every tick that widens the axis.
|
|
299
327
|
*/
|
|
300
328
|
function useDomain(measured: [number, number], domain: [number, number] | 'sticky' | undefined): [number, number] {
|
|
301
329
|
const widest = useRef<[number, number] | null>(null);
|
|
@@ -309,19 +337,20 @@ function useDomain(measured: [number, number], domain: [number, number] | 'stick
|
|
|
309
337
|
|
|
310
338
|
/**
|
|
311
339
|
* Chart
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
340
|
+
* Bars (vertical, horizontal, grouped, stacked), line, area, pie, donut and
|
|
341
|
+
* radar in a single component, because what changes between them is the mark
|
|
342
|
+
* being drawn and not the rest: data, scale, axes, legend, tooltip, selection
|
|
343
|
+
* and filters are the same six mechanisms in all of them.
|
|
316
344
|
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
345
|
+
* It is drawn with `View`: React Native ships no vector canvas and the library
|
|
346
|
+
* can't add one. The three primitives are in `chart/marks.tsx` and the whole
|
|
347
|
+
* geometry, without React, in `chart/math.ts`.
|
|
320
348
|
*
|
|
321
|
-
* Gestalt:
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
349
|
+
* Gestalt: common fate — when you tap a category, everything that isn't it
|
|
350
|
+
* drops to {@link DIM_OPACITY} at once, so what is highlighted reads as a group
|
|
351
|
+
* and not as a loose mark. The legend uses similarity: the same color as the
|
|
352
|
+
* series, which is why it can turn it off without having to explain what it
|
|
353
|
+
* turns off.
|
|
325
354
|
*/
|
|
326
355
|
export function Chart(props: ChartProps) {
|
|
327
356
|
const {
|
|
@@ -340,10 +369,11 @@ export function Chart(props: ChartProps) {
|
|
|
340
369
|
onSelect,
|
|
341
370
|
tooltip = true,
|
|
342
371
|
formatValue = formatNumber,
|
|
343
|
-
animate = true,
|
|
372
|
+
animate: animateProp = true,
|
|
344
373
|
duration,
|
|
345
374
|
emptyText,
|
|
346
375
|
accessibilityLabel,
|
|
376
|
+
surfaceColor,
|
|
347
377
|
style,
|
|
348
378
|
testID,
|
|
349
379
|
} = props;
|
|
@@ -352,6 +382,9 @@ export function Chart(props: ChartProps) {
|
|
|
352
382
|
const styles = useStyles();
|
|
353
383
|
const allowFontScaling = useAllowFontScaling();
|
|
354
384
|
const uiLabels = useLabels();
|
|
385
|
+
// Reduce Motion: the marks appear in their final shape instead of growing.
|
|
386
|
+
const reduceMotion = useReduceMotion();
|
|
387
|
+
const animate = animateProp && !reduceMotion;
|
|
355
388
|
const [width, setWidth] = useState(0);
|
|
356
389
|
|
|
357
390
|
const [hidden, setHidden, hiddenIsControlled] = useControlled(hiddenKeys, defaultHiddenKeys ?? []);
|
|
@@ -362,15 +395,15 @@ export function Chart(props: ChartProps) {
|
|
|
362
395
|
const decimate = polyline ? props.decimate : false;
|
|
363
396
|
|
|
364
397
|
/**
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
398
|
+
* What gets drawn: the window of `data`, and from that the points that fit.
|
|
399
|
+
* Decimation runs over the whole row, chosen with the first visible series:
|
|
400
|
+
* the series share the x axis, so keeping different indexes per series would
|
|
401
|
+
* break the alignment, the touch layer and the tooltip.
|
|
369
402
|
*/
|
|
370
403
|
const rows = useMemo(() => {
|
|
371
404
|
const windowed = windowSize && windowSize > 0 ? data.slice(-windowSize) : data;
|
|
372
405
|
if (!polyline || decimate === false || width === 0) return windowed;
|
|
373
|
-
//
|
|
406
|
+
// One point every two pixels: more can't be seen but still has to be paid for.
|
|
374
407
|
const target = typeof decimate === 'number' ? decimate : Math.floor(width / 2);
|
|
375
408
|
if (windowed.length <= target) return windowed;
|
|
376
409
|
const lead = series.find((item) => !hidden.includes(item.key))?.key ?? series[0]?.key;
|
|
@@ -385,10 +418,10 @@ export function Chart(props: ChartProps) {
|
|
|
385
418
|
);
|
|
386
419
|
|
|
387
420
|
/**
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
421
|
+
* The selection is stored by `id` and resolved against the current rows:
|
|
422
|
+
* if the datum shifted, the highlight follows it; if it left the window, it
|
|
423
|
+
* disappears. Blindly reusing the index would point at the datum that ended
|
|
424
|
+
* up in that spot, which isn't the one anyone picked.
|
|
392
425
|
*/
|
|
393
426
|
const selection = useMemo(() => {
|
|
394
427
|
if (!pick) return null;
|
|
@@ -404,8 +437,8 @@ export function Chart(props: ChartProps) {
|
|
|
404
437
|
};
|
|
405
438
|
}, [pick, ids, rows, labels]);
|
|
406
439
|
|
|
407
|
-
//
|
|
408
|
-
//
|
|
440
|
+
// In a pie the categories are the rows; in the rest, the columns. The
|
|
441
|
+
// color, the legend and what a tap on it turns off depend on that.
|
|
409
442
|
const palette = seriesPalette(theme, Math.max(1, isPie ? rows.length : series.length));
|
|
410
443
|
const entries: LegendItem[] = useMemo(
|
|
411
444
|
() =>
|
|
@@ -432,9 +465,9 @@ export function Chart(props: ChartProps) {
|
|
|
432
465
|
);
|
|
433
466
|
|
|
434
467
|
/**
|
|
435
|
-
*
|
|
436
|
-
*
|
|
437
|
-
*
|
|
468
|
+
* The plots report what was tapped —row and series— and the whole selection
|
|
469
|
+
* is built here: it is the only place that knows `selectBy`, the labels and
|
|
470
|
+
* the actual rows, so the three don't repeat the building.
|
|
438
471
|
*/
|
|
439
472
|
const applySelection = useCallback(
|
|
440
473
|
(hit: { index: number; seriesKey: string } | null) => {
|
|
@@ -450,9 +483,9 @@ export function Chart(props: ChartProps) {
|
|
|
450
483
|
value: toNumber(row[hit.seriesKey]) ?? 0,
|
|
451
484
|
}
|
|
452
485
|
: null;
|
|
453
|
-
//
|
|
454
|
-
//
|
|
455
|
-
//
|
|
486
|
+
// Tapping what is already selected releases it: without that there would
|
|
487
|
+
// be no way back to the whole chart without tapping outside, and
|
|
488
|
+
// "outside" doesn't always exist on a scrolling screen.
|
|
456
489
|
const same = next && selection && next.id === selection.id && next.seriesKey === selection.seriesKey;
|
|
457
490
|
const value = same ? null : next;
|
|
458
491
|
if (!selectionIsControlled) setPick(value);
|
|
@@ -484,6 +517,7 @@ export function Chart(props: ChartProps) {
|
|
|
484
517
|
};
|
|
485
518
|
|
|
486
519
|
return (
|
|
520
|
+
<ChartSurfaceContext.Provider value={surfaceColor ?? theme.colors.surfaceRaised}>
|
|
487
521
|
<View style={[styles.root, style]} testID={testID} accessible={false}>
|
|
488
522
|
{filters && filters.length > 0 ? (
|
|
489
523
|
<View style={styles.filters}>
|
|
@@ -556,19 +590,20 @@ export function Chart(props: ChartProps) {
|
|
|
556
590
|
<Legend items={entries} hidden={hidden} onToggle={toggleable ? applyHidden : undefined} testID={testID && `${testID}-legend`} />
|
|
557
591
|
) : null}
|
|
558
592
|
</View>
|
|
593
|
+
</ChartSurfaceContext.Provider>
|
|
559
594
|
);
|
|
560
595
|
}
|
|
561
596
|
|
|
562
597
|
Chart.displayName = 'Chart';
|
|
563
598
|
|
|
564
|
-
// ──
|
|
599
|
+
// ── what the three plots share ─────────────────────────────────────────────
|
|
565
600
|
|
|
566
601
|
interface PlotProps {
|
|
567
602
|
rows: ChartRow[];
|
|
568
603
|
labels: string[];
|
|
569
|
-
/**
|
|
604
|
+
/** All categories, with their color: the color doesn't change when one is turned off. */
|
|
570
605
|
entries: LegendItem[];
|
|
571
|
-
/**
|
|
606
|
+
/** The ones still turned on. */
|
|
572
607
|
visible: LegendItem[];
|
|
573
608
|
width: number;
|
|
574
609
|
height: number;
|
|
@@ -576,13 +611,13 @@ interface PlotProps {
|
|
|
576
611
|
animate: boolean;
|
|
577
612
|
duration: number;
|
|
578
613
|
selection: ChartSelection | null;
|
|
579
|
-
/**
|
|
614
|
+
/** Reports what was tapped; Chart builds the selection. `null` releases it. */
|
|
580
615
|
onPick: (hit: { index: number; seriesKey: string } | null) => void;
|
|
581
616
|
tooltip: boolean;
|
|
582
617
|
testID?: string;
|
|
583
618
|
}
|
|
584
619
|
|
|
585
|
-
/**
|
|
620
|
+
/** Tooltip rows for a category on the x axis. */
|
|
586
621
|
function tooltipRowsAt(rows: ChartRow[], index: number, visible: LegendItem[], format: (value: number) => string): TooltipRow[] {
|
|
587
622
|
const row = rows[index];
|
|
588
623
|
if (!row) return [];
|
|
@@ -594,7 +629,7 @@ function tooltipRowsAt(rows: ChartRow[], index: number, visible: LegendItem[], f
|
|
|
594
629
|
.filter((item): item is TooltipRow => item !== null);
|
|
595
630
|
}
|
|
596
631
|
|
|
597
|
-
// ──
|
|
632
|
+
// ── bars, line and area ────────────────────────────────────────────────────
|
|
598
633
|
|
|
599
634
|
interface CartesianPlotProps extends PlotProps {
|
|
600
635
|
type: 'bar' | 'line' | 'area';
|
|
@@ -612,10 +647,10 @@ interface CartesianPlotProps extends PlotProps {
|
|
|
612
647
|
yAxis: boolean;
|
|
613
648
|
}
|
|
614
649
|
|
|
615
|
-
/**
|
|
650
|
+
/** Width of one strip of the area fill, in pixels. Thinner = more views. */
|
|
616
651
|
const STRIP_WIDTH = 4;
|
|
617
652
|
const MAX_STRIPS = 140;
|
|
618
|
-
/**
|
|
653
|
+
/** Room between two bars of the same group. */
|
|
619
654
|
const GROUP_GAP = 2;
|
|
620
655
|
|
|
621
656
|
const CartesianPlot = memo((props: CartesianPlotProps) => {
|
|
@@ -648,31 +683,52 @@ const CartesianPlot = memo((props: CartesianPlotProps) => {
|
|
|
648
683
|
} = props;
|
|
649
684
|
|
|
650
685
|
const theme = useTheme();
|
|
686
|
+
const surface = useChartSurface();
|
|
651
687
|
const horizontal = type === 'bar' && orientation === 'horizontal';
|
|
652
688
|
const keys = useMemo(() => visible.map((entry) => entry.key), [visible]);
|
|
653
689
|
|
|
654
|
-
const leftGutter = yAxis ? (horizontal ? CATEGORY_GUTTER : VALUE_GUTTER) : 0;
|
|
655
690
|
const bottomGutter = xAxis ? BOTTOM_GUTTER : 0;
|
|
656
|
-
const plotW = Math.max(1, width - leftGutter);
|
|
657
|
-
const plotH = Math.max(1, height - bottomGutter);
|
|
658
691
|
|
|
659
|
-
//
|
|
660
|
-
//
|
|
692
|
+
// The line may not touch zero (a temperature, a ranking); a bar does have
|
|
693
|
+
// to, because its length is what states the value.
|
|
661
694
|
const measured = useMemo(
|
|
662
695
|
() => extent(rows, keys, { stacked, includeZero: type !== 'line' }),
|
|
663
696
|
[rows, keys, stacked, type]
|
|
664
697
|
);
|
|
665
698
|
const [low, high] = useDomain(measured, domain);
|
|
666
699
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
700
|
+
// A hand-set domain is respected as is; a measured one (or 'sticky') is
|
|
701
|
+
// rounded, which is what makes the axis legible.
|
|
702
|
+
const nice = useMemo(
|
|
703
|
+
() => (Array.isArray(domain) ? exactTicks(low, high, tickCount) : niceScale(low, high, tickCount)),
|
|
704
|
+
[domain, low, high, tickCount]
|
|
705
|
+
);
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* The gutter comes from the longest label, not from a constant: with a
|
|
709
|
+
* custom `formatValue` ("$3000", "1.250 ms") a fixed width clips the number
|
|
710
|
+
* and the axis ends up saying "$30…". The ticks don't depend on the plot's
|
|
711
|
+
* width, so they can be measured before splitting it up.
|
|
712
|
+
*/
|
|
713
|
+
const leftGutter = useMemo(() => {
|
|
714
|
+
if (!yAxis) return 0;
|
|
715
|
+
if (horizontal) return CATEGORY_GUTTER;
|
|
716
|
+
const longest = nice.values.reduce((widest, value) => Math.max(widest, formatValue(value).length), 0);
|
|
717
|
+
const wanted = Math.ceil(longest * VALUE_CHAR) + theme.tokens.spacing.sm;
|
|
718
|
+
return Math.max(VALUE_GUTTER, Math.min(wanted, Math.floor(width * VALUE_GUTTER_MAX)));
|
|
719
|
+
}, [yAxis, horizontal, nice, formatValue, width, theme.tokens.spacing.sm]);
|
|
720
|
+
|
|
721
|
+
const plotW = Math.max(1, width - leftGutter);
|
|
722
|
+
const plotH = Math.max(1, height - bottomGutter);
|
|
723
|
+
|
|
724
|
+
const toPixel = useMemo(
|
|
725
|
+
() =>
|
|
726
|
+
horizontal
|
|
727
|
+
? linearScale([nice.min, nice.max], [0, plotW])
|
|
728
|
+
: linearScale([nice.min, nice.max], [plotH, 0]),
|
|
729
|
+
[horizontal, nice, plotW, plotH]
|
|
730
|
+
);
|
|
731
|
+
const scale = useMemo(() => ({ nice, toPixel }), [nice, toPixel]);
|
|
676
732
|
|
|
677
733
|
const band = (horizontal ? plotH : plotW) / Math.max(1, rows.length);
|
|
678
734
|
const centerOf = useCallback((index: number) => (index + 0.5) * band, [band]);
|
|
@@ -680,7 +736,7 @@ const CartesianPlot = memo((props: CartesianPlotProps) => {
|
|
|
680
736
|
|
|
681
737
|
const stacks = useMemo(() => (stacked ? rows.map((row) => stackRow(row, keys)) : null), [stacked, rows, keys]);
|
|
682
738
|
|
|
683
|
-
/**
|
|
739
|
+
/** A series' points: `to` is the value, `from` the floor it is filled from. */
|
|
684
740
|
const pointsFor = useCallback(
|
|
685
741
|
(key: string, edge: 'to' | 'from'): Point[] => {
|
|
686
742
|
const out: Point[] = [];
|
|
@@ -702,8 +758,8 @@ const CartesianPlot = memo((props: CartesianPlotProps) => {
|
|
|
702
758
|
|
|
703
759
|
const pickAt = useCallback(
|
|
704
760
|
(index: number, event: GestureResponderEvent) => {
|
|
705
|
-
//
|
|
706
|
-
//
|
|
761
|
+
// Which series the finger landed on: the one whose mark is closest to
|
|
762
|
+
// the touch on the value axis. With a single series it is always that one.
|
|
707
763
|
const touch = (horizontal ? event?.nativeEvent?.locationX : event?.nativeEvent?.locationY) ?? 0;
|
|
708
764
|
let bestKey = keys[0] ?? '';
|
|
709
765
|
let bestDistance = Infinity;
|
|
@@ -739,7 +795,7 @@ const CartesianPlot = memo((props: CartesianPlotProps) => {
|
|
|
739
795
|
|
|
740
796
|
return (
|
|
741
797
|
<>
|
|
742
|
-
{/*
|
|
798
|
+
{/* Frame: grid and labels, beneath the marks. */}
|
|
743
799
|
<View style={{ position: 'absolute', left: leftGutter, top: 0, width: plotW, height: plotH }}>
|
|
744
800
|
{grid ? (
|
|
745
801
|
<CartesianGrid
|
|
@@ -818,14 +874,14 @@ const CartesianPlot = memo((props: CartesianPlotProps) => {
|
|
|
818
874
|
|
|
819
875
|
return (
|
|
820
876
|
<View key={entry.key} style={{ position: 'absolute', left: 0, top: 0, width: plotW, height: plotH }}>
|
|
821
|
-
{/*
|
|
822
|
-
|
|
823
|
-
|
|
877
|
+
{/* Area: without `path` there is no fill under a curve, so it
|
|
878
|
+
is cut into vertical strips and each one asks the polyline
|
|
879
|
+
for its height. At 4px per strip the edge already reads as continuous. */}
|
|
824
880
|
{type === 'area' ? (
|
|
825
|
-
//
|
|
826
|
-
//
|
|
827
|
-
//
|
|
828
|
-
//
|
|
881
|
+
// Opacity goes on the group, not on each strip: the half
|
|
882
|
+
// pixel of overlap that hides the antialias seam is
|
|
883
|
+
// composited twice and leaves a vertical stripe every four
|
|
884
|
+
// pixels. Dimming the whole group, it is painted only once.
|
|
829
885
|
<View
|
|
830
886
|
pointerEvents="none"
|
|
831
887
|
style={{ position: 'absolute', left: 0, top: 0, width: plotW, height: plotH, opacity: fillOpacity }}
|
|
@@ -860,7 +916,7 @@ const CartesianPlot = memo((props: CartesianPlotProps) => {
|
|
|
860
916
|
key={index}
|
|
861
917
|
point={point}
|
|
862
918
|
color={entry.color}
|
|
863
|
-
ringColor={
|
|
919
|
+
ringColor={surface}
|
|
864
920
|
size={selection?.index === index ? 8 : 6}
|
|
865
921
|
testID={testID && `${testID}-dot-${entry.key}-${index}`}
|
|
866
922
|
/>
|
|
@@ -870,8 +926,8 @@ const CartesianPlot = memo((props: CartesianPlotProps) => {
|
|
|
870
926
|
);
|
|
871
927
|
})}
|
|
872
928
|
|
|
873
|
-
{/*
|
|
874
|
-
|
|
929
|
+
{/* Touch layer: a whole band per category. Tapping a 2px line is
|
|
930
|
+
impossible; tapping its column isn't. */}
|
|
875
931
|
{rows.map((row, index) => (
|
|
876
932
|
<Pressable
|
|
877
933
|
key={index}
|
|
@@ -935,7 +991,7 @@ const CartesianPlot = memo((props: CartesianPlotProps) => {
|
|
|
935
991
|
});
|
|
936
992
|
CartesianPlot.displayName = 'CartesianPlot';
|
|
937
993
|
|
|
938
|
-
// ──
|
|
994
|
+
// ── pie and donut ──────────────────────────────────────────────────────────
|
|
939
995
|
|
|
940
996
|
interface PiePlotProps extends PlotProps {
|
|
941
997
|
donut: boolean;
|
|
@@ -945,12 +1001,12 @@ interface PiePlotProps extends PlotProps {
|
|
|
945
1001
|
}
|
|
946
1002
|
|
|
947
1003
|
const DONUT_RADIUS = 0.6;
|
|
948
|
-
/**
|
|
1004
|
+
/** How far the selected slice pops out, in pixels. */
|
|
949
1005
|
const EXPLODE = 8;
|
|
950
|
-
/**
|
|
1006
|
+
/** Where the label falls, as a fraction between the hole and the edge. */
|
|
951
1007
|
const LABEL_AT = 0.62;
|
|
952
1008
|
|
|
953
|
-
/**
|
|
1009
|
+
/** White or black, whichever reads over the color. An odd color doesn't break: it falls back to `text`. */
|
|
954
1010
|
function inkOn(background: string, theme: { colors: { white: string; black: string; text: string } }): string {
|
|
955
1011
|
try {
|
|
956
1012
|
return contrast(background, theme.colors.white) >= contrast(background, theme.colors.black)
|
|
@@ -964,6 +1020,7 @@ function inkOn(background: string, theme: { colors: { white: string; black: stri
|
|
|
964
1020
|
const PiePlot = memo((props: PiePlotProps) => {
|
|
965
1021
|
const { rows, labels, entries, visible, width, height, formatValue, selection, onPick, tooltip, testID, donut, innerRadius, sliceLabels, valueKey } = props;
|
|
966
1022
|
const theme = useTheme();
|
|
1023
|
+
const surface = useChartSurface();
|
|
967
1024
|
const styles = useStyles();
|
|
968
1025
|
const allowFontScaling = useAllowFontScaling();
|
|
969
1026
|
|
|
@@ -972,8 +1029,8 @@ const PiePlot = memo((props: PiePlotProps) => {
|
|
|
972
1029
|
const hole = clamp(innerRadius ?? (donut ? DONUT_RADIUS : 0), 0, 0.9) * radius;
|
|
973
1030
|
|
|
974
1031
|
const arcs = useMemo(() => {
|
|
975
|
-
//
|
|
976
|
-
// 100%,
|
|
1032
|
+
// A turned-off category is worth 0: it leaves the pie and the rest share
|
|
1033
|
+
// the 100%, which is what whoever turned it off from the legend expects.
|
|
977
1034
|
const values = rows.map((row, index) =>
|
|
978
1035
|
visible.some((entry) => entry.key === labels[index]) ? (toNumber(row[valueKey]) ?? 0) : 0
|
|
979
1036
|
);
|
|
@@ -984,8 +1041,8 @@ const PiePlot = memo((props: PiePlotProps) => {
|
|
|
984
1041
|
(event: GestureResponderEvent) => {
|
|
985
1042
|
const point = { x: event?.nativeEvent?.locationX ?? 0, y: event?.nativeEvent?.locationY ?? 0 };
|
|
986
1043
|
const distance = Math.hypot(point.x - center.x, point.y - center.y);
|
|
987
|
-
//
|
|
988
|
-
//
|
|
1044
|
+
// A donut's hole isn't part of any slice, and neither is the area
|
|
1045
|
+
// outside the circle: both release the selection.
|
|
989
1046
|
if (distance > radius || distance < hole) return onPick(null);
|
|
990
1047
|
const index = arcAt(arcs, angleOf(center, point));
|
|
991
1048
|
if (index === -1) return onPick(null);
|
|
@@ -1025,7 +1082,7 @@ const PiePlot = memo((props: PiePlotProps) => {
|
|
|
1025
1082
|
width: hole * 2,
|
|
1026
1083
|
height: hole * 2,
|
|
1027
1084
|
borderRadius: hole,
|
|
1028
|
-
backgroundColor:
|
|
1085
|
+
backgroundColor: surface,
|
|
1029
1086
|
}}
|
|
1030
1087
|
/>
|
|
1031
1088
|
) : null}
|
|
@@ -1033,8 +1090,8 @@ const PiePlot = memo((props: PiePlotProps) => {
|
|
|
1033
1090
|
{sliceLabels === 'none'
|
|
1034
1091
|
? null
|
|
1035
1092
|
: arcs.map((arc) => {
|
|
1036
|
-
//
|
|
1037
|
-
//
|
|
1093
|
+
// A very thin slice has nowhere to write: the label would spill
|
|
1094
|
+
// over its neighbors and none would be readable.
|
|
1038
1095
|
if (arc.sweep < 18) return null;
|
|
1039
1096
|
const at = polar(center, hole + (radius - hole) * LABEL_AT, arc.start + arc.sweep / 2);
|
|
1040
1097
|
const color = entries[arc.index]?.color ?? theme.colors.primary;
|
|
@@ -1089,7 +1146,7 @@ interface RadarPlotProps extends PlotProps {
|
|
|
1089
1146
|
dots: boolean;
|
|
1090
1147
|
}
|
|
1091
1148
|
|
|
1092
|
-
/**
|
|
1149
|
+
/** Strips per side of the polygon when it is filled. More = cleaner edge, more views. */
|
|
1093
1150
|
const RADAR_STEPS = 5;
|
|
1094
1151
|
const RADAR_FILL_OPACITY = 0.18;
|
|
1095
1152
|
const RADAR_LABEL_WIDTH = 56;
|
|
@@ -1097,6 +1154,7 @@ const RADAR_LABEL_WIDTH = 56;
|
|
|
1097
1154
|
const RadarPlot = memo((props: RadarPlotProps) => {
|
|
1098
1155
|
const { rows, labels, visible, width, height, formatValue, selection, onPick, tooltip, testID, domain, levels, fill, thickness, dots } = props;
|
|
1099
1156
|
const theme = useTheme();
|
|
1157
|
+
const surface = useChartSurface();
|
|
1100
1158
|
const styles = useStyles();
|
|
1101
1159
|
const allowFontScaling = useAllowFontScaling();
|
|
1102
1160
|
|
|
@@ -1105,8 +1163,8 @@ const RadarPlot = memo((props: RadarPlotProps) => {
|
|
|
1105
1163
|
const angles = useMemo(() => radarAngles(rows.length), [rows.length]);
|
|
1106
1164
|
const keys = useMemo(() => visible.map((entry) => entry.key), [visible]);
|
|
1107
1165
|
|
|
1108
|
-
//
|
|
1109
|
-
//
|
|
1166
|
+
// The radar measures from the center, and the center is 0: a minimum other
|
|
1167
|
+
// than zero would make two similar values look miles apart.
|
|
1110
1168
|
const measured = useMemo(() => [0, extent(rows, keys, { includeZero: true })[1]] as [number, number], [rows, keys]);
|
|
1111
1169
|
const [, top] = useDomain(measured, domain);
|
|
1112
1170
|
|
|
@@ -1140,14 +1198,14 @@ const RadarPlot = memo((props: RadarPlotProps) => {
|
|
|
1140
1198
|
const points = pointsOf(entry.key);
|
|
1141
1199
|
return (
|
|
1142
1200
|
<View key={entry.key} style={{ position: 'absolute', left: 0, top: 0, width, height }}>
|
|
1143
|
-
{/*
|
|
1144
|
-
|
|
1201
|
+
{/* Fill: the same sector a pie draws, one per strip of the
|
|
1202
|
+
polygon, with the radius that strip gets. */}
|
|
1145
1203
|
{fill ? (
|
|
1146
|
-
//
|
|
1147
|
-
//
|
|
1148
|
-
//
|
|
1149
|
-
//
|
|
1150
|
-
//
|
|
1204
|
+
// Opacity goes on the group, not on each strip. Per strip, the
|
|
1205
|
+
// 0.4° overlap that hides the antialias seam is composited
|
|
1206
|
+
// twice and leaves a darker radius at each cut: the fill ends
|
|
1207
|
+
// up looking like a spider web. Applied to the group, the strips
|
|
1208
|
+
// paint opaque against each other and the whole is dimmed once.
|
|
1151
1209
|
<View
|
|
1152
1210
|
pointerEvents="none"
|
|
1153
1211
|
style={{ position: 'absolute', left: 0, top: 0, width, height, opacity: RADAR_FILL_OPACITY }}
|
|
@@ -1172,7 +1230,7 @@ const RadarPlot = memo((props: RadarPlotProps) => {
|
|
|
1172
1230
|
key={index}
|
|
1173
1231
|
point={point}
|
|
1174
1232
|
color={entry.color}
|
|
1175
|
-
ringColor={
|
|
1233
|
+
ringColor={surface}
|
|
1176
1234
|
size={selection?.index === index ? 8 : 6}
|
|
1177
1235
|
/>
|
|
1178
1236
|
))
|