@coinbase/cds-mobile 8.59.0 → 8.61.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dts/buttons/Button.d.ts +8 -0
  3. package/dts/buttons/Button.d.ts.map +1 -1
  4. package/dts/buttons/DefaultSlideButtonHandle.d.ts.map +1 -1
  5. package/dts/buttons/IconButton.d.ts +12 -7
  6. package/dts/buttons/IconButton.d.ts.map +1 -1
  7. package/dts/cards/Card.d.ts +4 -0
  8. package/dts/cards/Card.d.ts.map +1 -1
  9. package/dts/cards/CardBody.d.ts +4 -0
  10. package/dts/cards/CardBody.d.ts.map +1 -1
  11. package/dts/cards/CardFooter.d.ts +4 -0
  12. package/dts/cards/CardFooter.d.ts.map +1 -1
  13. package/dts/cards/CardGroup.d.ts +12 -0
  14. package/dts/cards/CardGroup.d.ts.map +1 -1
  15. package/dts/cards/CardHeader.d.ts +8 -0
  16. package/dts/cards/CardHeader.d.ts.map +1 -1
  17. package/dts/cards/CardMedia.d.ts +8 -0
  18. package/dts/cards/CardMedia.d.ts.map +1 -1
  19. package/dts/controls/InputIconButton.d.ts +1 -1
  20. package/dts/loaders/Spinner.d.ts +4 -0
  21. package/dts/loaders/Spinner.d.ts.map +1 -1
  22. package/dts/visualizations/ProgressBar.d.ts +2 -2
  23. package/dts/visualizations/ProgressBar.d.ts.map +1 -1
  24. package/dts/visualizations/ProgressBarWithFloatLabel.d.ts.map +1 -1
  25. package/dts/visualizations/ProgressCircle.d.ts +9 -1
  26. package/dts/visualizations/ProgressCircle.d.ts.map +1 -1
  27. package/esm/alpha/select/__stories__/AlphaSelect.stories.js +13 -9
  28. package/esm/buttons/Button.js +28 -10
  29. package/esm/buttons/DefaultSlideButtonHandle.js +7 -6
  30. package/esm/buttons/IconButton.js +23 -12
  31. package/esm/buttons/__stories__/Button.stories.js +60 -0
  32. package/esm/buttons/__stories__/IconButton.stories.js +148 -1
  33. package/esm/cards/Card.js +5 -0
  34. package/esm/cards/CardBody.js +5 -0
  35. package/esm/cards/CardFooter.js +4 -0
  36. package/esm/cards/CardGroup.js +14 -0
  37. package/esm/cards/CardHeader.js +9 -0
  38. package/esm/cards/CardMedia.js +10 -0
  39. package/esm/loaders/Spinner.js +5 -0
  40. package/esm/overlays/__stories__/AlertBasic.stories.js +2 -2
  41. package/esm/overlays/__stories__/AlertLongTitle.stories.js +2 -2
  42. package/esm/overlays/__stories__/AlertOverModal.stories.js +2 -10
  43. package/esm/overlays/__stories__/AlertPortal.stories.js +2 -6
  44. package/esm/overlays/__stories__/AlertSingleAction.stories.js +2 -2
  45. package/esm/overlays/__stories__/AlertVerticalActions.stories.js +2 -2
  46. package/esm/overlays/__stories__/DrawerFallback.stories.js +20 -13
  47. package/esm/overlays/__stories__/DrawerScrollable.stories.js +8 -1
  48. package/esm/overlays/__stories__/Drawers.js +4 -4
  49. package/esm/overlays/__stories__/ModalBackButton.stories.js +2 -2
  50. package/esm/overlays/__stories__/ModalBasic.stories.js +2 -2
  51. package/esm/overlays/__stories__/ModalCustomPadding.stories.js +2 -2
  52. package/esm/overlays/__stories__/ModalLong.stories.js +2 -2
  53. package/esm/overlays/__stories__/ModalPortal.stories.js +2 -6
  54. package/esm/overlays/__stories__/Overlay.stories.js +2 -6
  55. package/esm/overlays/__stories__/TrayNavigation.stories.js +6 -2
  56. package/esm/overlays/__stories__/Trays.js +20 -11
  57. package/esm/sticky-footer/__stories__/StickyFooter.stories.js +2 -2
  58. package/esm/sticky-footer/__stories__/StickyFooterWithTray.stories.js +3 -3
  59. package/esm/visualizations/DefaultProgressCircleContent.js +1 -1
  60. package/esm/visualizations/ProgressBar.js +3 -3
  61. package/esm/visualizations/ProgressBarWithFloatLabel.js +19 -28
  62. package/esm/visualizations/ProgressCircle.js +80 -60
  63. package/esm/visualizations/__stories__/ProgressCircle.stories.js +63 -11
  64. package/package.json +2 -2
@@ -13,7 +13,7 @@ export const DefaultDrawer = _ref => {
13
13
  pin = 'left',
14
14
  reduceMotion
15
15
  } = _ref;
16
- const [isVisible, setIsVisible] = useState(true);
16
+ const [isVisible, setIsVisible] = useState(false);
17
17
  const setIsVisibleOff = useCallback(() => setIsVisible(false), [setIsVisible]);
18
18
  const setIsVisibleOn = useCallback(() => setIsVisible(true), [setIsVisible]);
19
19
  return /*#__PURE__*/_jsxs(_Fragment, {
@@ -33,7 +33,7 @@ export const DefaultDrawer = _ref => {
33
33
  children: [/*#__PURE__*/_jsx(LoremIpsum, {}), /*#__PURE__*/_jsx(Button, {
34
34
  onPress: handleClose,
35
35
  variant: "secondary",
36
- children: "Close Drawer"
36
+ children: "Cancel"
37
37
  })]
38
38
  });
39
39
  }
@@ -109,7 +109,7 @@ export const SideDrawerContent = _ref3 => {
109
109
  compact: true,
110
110
  onPress: handleClose,
111
111
  variant: "secondary",
112
- children: "Sign out"
112
+ children: "Cancel"
113
113
  })]
114
114
  });
115
115
  };
@@ -117,7 +117,7 @@ export const SideDrawer = _ref5 => {
117
117
  let {
118
118
  pin = 'left'
119
119
  } = _ref5;
120
- const [isVisible, setIsVisible] = useState(true);
120
+ const [isVisible, setIsVisible] = useState(false);
121
121
  const setIsVisibleOff = useCallback(() => setIsVisible(false), [setIsVisible]);
122
122
  const setIsVisibleOn = useCallback(() => setIsVisible(true), [setIsVisible]);
123
123
  return /*#__PURE__*/_jsxs(_Fragment, {
@@ -8,7 +8,7 @@ import { ModalFooter } from '../modal/ModalFooter';
8
8
  import { ModalHeader } from '../modal/ModalHeader';
9
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
10
  const ModalBackButtonScreen = () => {
11
- const [visible, setVisible] = useState(true);
11
+ const [visible, setVisible] = useState(false);
12
12
  const handleClose = useCallback(() => setVisible(false), []);
13
13
  const handleOpen = useCallback(() => setVisible(true), []);
14
14
  return /*#__PURE__*/_jsx(ExampleScreen, {
@@ -16,7 +16,7 @@ const ModalBackButtonScreen = () => {
16
16
  title: "Back Button Modal",
17
17
  children: [/*#__PURE__*/_jsx(Button, {
18
18
  onPress: handleOpen,
19
- children: "Open Modal"
19
+ children: "Open"
20
20
  }), /*#__PURE__*/_jsxs(Modal, {
21
21
  onRequestClose: handleClose,
22
22
  visible: visible,
@@ -8,7 +8,7 @@ import { ModalFooter } from '../modal/ModalFooter';
8
8
  import { ModalHeader } from '../modal/ModalHeader';
9
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
10
  const ModalBasicScreen = () => {
11
- const [visible, setVisible] = useState(true);
11
+ const [visible, setVisible] = useState(false);
12
12
  const handleClose = useCallback(() => setVisible(false), []);
13
13
  const handleOpen = useCallback(() => setVisible(true), []);
14
14
  return /*#__PURE__*/_jsx(ExampleScreen, {
@@ -16,7 +16,7 @@ const ModalBasicScreen = () => {
16
16
  title: "Basic Modal",
17
17
  children: [/*#__PURE__*/_jsx(Button, {
18
18
  onPress: handleOpen,
19
- children: "Open Modal"
19
+ children: "Open"
20
20
  }), /*#__PURE__*/_jsxs(Modal, {
21
21
  onRequestClose: handleClose,
22
22
  visible: visible,
@@ -8,7 +8,7 @@ import { ModalFooter } from '../modal/ModalFooter';
8
8
  import { ModalHeader } from '../modal/ModalHeader';
9
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
10
  export default function ModalCustomPaddingScreen() {
11
- const [visible, setVisible] = useState(true);
11
+ const [visible, setVisible] = useState(false);
12
12
  const handleClose = useCallback(() => setVisible(false), []);
13
13
  const handleOpen = useCallback(() => setVisible(true), []);
14
14
  return /*#__PURE__*/_jsx(ExampleScreen, {
@@ -16,7 +16,7 @@ export default function ModalCustomPaddingScreen() {
16
16
  title: "Modal with custom padding",
17
17
  children: [/*#__PURE__*/_jsx(Button, {
18
18
  onPress: handleOpen,
19
- children: "Open Modal"
19
+ children: "Open"
20
20
  }), /*#__PURE__*/_jsxs(Modal, {
21
21
  onRequestClose: handleClose,
22
22
  visible: visible,
@@ -9,7 +9,7 @@ import { ModalFooter } from '../modal/ModalFooter';
9
9
  import { ModalHeader } from '../modal/ModalHeader';
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  const ModalLongScreen = () => {
12
- const [visible, setVisible] = useState(true);
12
+ const [visible, setVisible] = useState(false);
13
13
  const handleClose = useCallback(() => setVisible(false), []);
14
14
  const handleOpen = useCallback(() => setVisible(true), []);
15
15
  return /*#__PURE__*/_jsx(ExampleScreen, {
@@ -17,7 +17,7 @@ const ModalLongScreen = () => {
17
17
  title: "Long Modal",
18
18
  children: [/*#__PURE__*/_jsx(Button, {
19
19
  onPress: handleOpen,
20
- children: "Open Modal"
20
+ children: "Open"
21
21
  }), /*#__PURE__*/_jsxs(Modal, {
22
22
  onRequestClose: handleClose,
23
23
  visible: visible,
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect } from 'react';
1
+ import React, { useCallback } from 'react';
2
2
  import { useModal } from '@coinbase/cds-common/overlays/useModal';
3
3
  import { Button } from '../../buttons/Button';
4
4
  import { Example, ExampleScreen } from '../../examples/ExampleScreen';
@@ -33,16 +33,12 @@ const ModalPortalScreen = () => {
33
33
  })
34
34
  })]
35
35
  })), [openModal, closeModal]);
36
- useEffect(() => {
37
- handlePress();
38
- return () => closeModal();
39
- }, [closeModal, handlePress]);
40
36
  return /*#__PURE__*/_jsx(ExampleScreen, {
41
37
  children: /*#__PURE__*/_jsx(Example, {
42
38
  title: "Portal Modal",
43
39
  children: /*#__PURE__*/_jsx(Button, {
44
40
  onPress: handlePress,
45
- children: "Open Modal"
41
+ children: "Open"
46
42
  })
47
43
  })
48
44
  });
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect, useState } from 'react';
1
+ import React, { useCallback, useState } from 'react';
2
2
  import { Modal } from 'react-native';
3
3
  import { Button } from '../../buttons/Button';
4
4
  import { Example, ExampleScreen } from '../../examples/ExampleScreen';
@@ -22,15 +22,11 @@ const OverlayScreen = () => {
22
22
  if (finished) setVisibleToOff();
23
23
  });
24
24
  }, [animateOverlayOut, setVisibleToOff]);
25
- useEffect(() => {
26
- openModal();
27
- return () => closeModal();
28
- }, [closeModal, openModal]);
29
25
  return /*#__PURE__*/_jsx(ExampleScreen, {
30
26
  children: /*#__PURE__*/_jsxs(Example, {
31
27
  children: [/*#__PURE__*/_jsx(Button, {
32
28
  onPress: openModal,
33
- children: "Open Overlay"
29
+ children: "Open"
34
30
  }), /*#__PURE__*/_jsx(Modal, {
35
31
  hardwareAccelerated: true,
36
32
  statusBarTranslucent: true,
@@ -1,6 +1,7 @@
1
1
  import React, { useCallback, useRef, useState } from 'react';
2
2
  import { navigationOptions } from '@coinbase/cds-common/internal/data/navigation';
3
3
  import { NoopFn } from '@coinbase/cds-common/utils/mockUtils';
4
+ import { Button } from '../../buttons/Button';
4
5
  import { IconButton } from '../../buttons/IconButton';
5
6
  import { Menu } from '../../controls/Menu';
6
7
  import { SelectOption } from '../../controls/SelectOption';
@@ -10,7 +11,7 @@ import { HStack } from '../../layout';
10
11
  import { Tray } from '../tray/Tray';
11
12
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
12
13
  const NavigationTray = () => {
13
- const [isTrayVisible, setIsTrayVisible] = useState(true);
14
+ const [isTrayVisible, setIsTrayVisible] = useState(false);
14
15
  const setIsTrayVisibleToFalse = useCallback(() => setIsTrayVisible(false), []);
15
16
  const [value, setValue] = useState();
16
17
  const trayRef = useRef(null);
@@ -22,7 +23,10 @@ const NavigationTray = () => {
22
23
  setIsTrayVisible(true);
23
24
  }, []);
24
25
  return /*#__PURE__*/_jsxs(_Fragment, {
25
- children: [/*#__PURE__*/_jsxs(HStack, {
26
+ children: [/*#__PURE__*/_jsx(Button, {
27
+ onPress: handleAppSwitcherPress,
28
+ children: "Open"
29
+ }), /*#__PURE__*/_jsxs(HStack, {
26
30
  gap: 2,
27
31
  justifyContent: "flex-end",
28
32
  minHeight: 200,
@@ -6,14 +6,14 @@ import { Menu } from '../../controls/Menu';
6
6
  import { SelectOption } from '../../controls/SelectOption';
7
7
  import { Fallback, VStack } from '../../layout';
8
8
  import { Tray } from '../tray/Tray';
9
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
9
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
10
10
  export const options = prices.slice(0, 4);
11
11
  const lotsOfOptions = prices.slice(0, 30);
12
12
  export const DefaultTray = _ref => {
13
13
  let {
14
14
  title
15
15
  } = _ref;
16
- const [isTrayVisible, setIsTrayVisible] = useState(true);
16
+ const [isTrayVisible, setIsTrayVisible] = useState(false);
17
17
  const setIsTrayVisibleOff = useCallback(() => setIsTrayVisible(false), [setIsTrayVisible]);
18
18
  const setIsTrayVisibleOn = useCallback(() => setIsTrayVisible(true), [setIsTrayVisible]);
19
19
  const [value, setValue] = useState();
@@ -34,15 +34,24 @@ export const DefaultTray = _ref => {
34
34
  onCloseComplete: setIsTrayVisibleOff,
35
35
  onVisibilityChange: handleTrayVisibilityChange,
36
36
  title: title,
37
- children: /*#__PURE__*/_jsx(Menu, {
38
- onChange: setValue,
39
- value: value,
40
- children: options.map(option => /*#__PURE__*/_jsx(SelectOption, {
41
- description: "BTC",
37
+ children: /*#__PURE__*/_jsxs(VStack, {
38
+ gap: 2,
39
+ paddingX: 3,
40
+ children: [/*#__PURE__*/_jsx(Menu, {
41
+ onChange: setValue,
42
+ value: value,
43
+ children: options.map(option => /*#__PURE__*/_jsx(SelectOption, {
44
+ description: "BTC",
45
+ onPress: handleOptionPress,
46
+ title: option,
47
+ value: option
48
+ }, option))
49
+ }), /*#__PURE__*/_jsx(Button, {
50
+ block: true,
42
51
  onPress: handleOptionPress,
43
- title: option,
44
- value: option
45
- }, option))
52
+ variant: "secondary",
53
+ children: "Close"
54
+ })]
46
55
  })
47
56
  })]
48
57
  });
@@ -64,7 +73,7 @@ export const ScrollableTray = _ref2 => {
64
73
  fallbackEnabled,
65
74
  verticalDrawerPercentageOfView
66
75
  } = _ref2;
67
- const [isTrayVisible, setIsTrayVisible] = useState(true);
76
+ const [isTrayVisible, setIsTrayVisible] = useState(false);
68
77
  const setIsTrayVisibleOff = useCallback(() => setIsTrayVisible(false), [setIsTrayVisible]);
69
78
  const setIsTrayVisibleOn = useCallback(() => setIsTrayVisible(true), [setIsTrayVisible]);
70
79
  const [value, setValue] = useState();
@@ -7,7 +7,7 @@ import { VStack } from '../../layout';
7
7
  import { StickyFooter } from '../StickyFooter';
8
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
9
  const StickyFooterScreen = () => {
10
- const [showStickyFooter, setShowStickyFooter] = useState(true);
10
+ const [showStickyFooter, setShowStickyFooter] = useState(false);
11
11
  const handleButtonPress = useCallback(() => {
12
12
  setShowStickyFooter(!showStickyFooter);
13
13
  }, [showStickyFooter]);
@@ -17,7 +17,7 @@ const StickyFooterScreen = () => {
17
17
  title: "StickyFooter with Screen",
18
18
  children: /*#__PURE__*/_jsx(Button, {
19
19
  onPress: handleButtonPress,
20
- children: showStickyFooter ? 'Close' : 'Open'
20
+ children: showStickyFooter ? 'Cancel' : 'Open'
21
21
  })
22
22
  }), showStickyFooter && /*#__PURE__*/_jsx(View, {
23
23
  style: {
@@ -14,7 +14,7 @@ const StickyFooterWithTray = _ref => {
14
14
  let {
15
15
  title
16
16
  } = _ref;
17
- const [isTrayVisible, setIsTrayVisible] = useState(true);
17
+ const [isTrayVisible, setIsTrayVisible] = useState(false);
18
18
  const setIsTrayVisibleToFalse = useCallback(() => setIsTrayVisible(false), []);
19
19
  const setIsTrayVisibleToTrue = useCallback(() => setIsTrayVisible(true), []);
20
20
  const [value, setValue] = useState();
@@ -56,14 +56,14 @@ const StickyFooterWithTray = _ref => {
56
56
  flexGrow: 1,
57
57
  children: /*#__PURE__*/_jsx(Button, {
58
58
  block: true,
59
+ onPress: handleClose,
59
60
  variant: "secondary",
60
- children: "Secondary"
61
+ children: "Cancel"
61
62
  })
62
63
  }), /*#__PURE__*/_jsx(Box, {
63
64
  flexGrow: 1,
64
65
  children: /*#__PURE__*/_jsx(Button, {
65
66
  block: true,
66
- onPress: handleClose,
67
67
  children: "Primary"
68
68
  })
69
69
  })]
@@ -4,7 +4,7 @@ import { ProgressTextLabel } from './ProgressTextLabel';
4
4
  import { jsx as _jsx } from "react/jsx-runtime";
5
5
  export const DefaultProgressCircleContent = /*#__PURE__*/memo(_ref => {
6
6
  let {
7
- progress,
7
+ progress = 0,
8
8
  disableAnimateOnMount,
9
9
  disabled,
10
10
  color = 'fgMuted'
@@ -2,7 +2,7 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
2
2
  import React, { forwardRef, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { Animated, I18nManager } from 'react-native';
4
4
  import { animateProgressBaseSpec } from '@coinbase/cds-common/animation/progress';
5
- import { useProgressSize } from '@coinbase/cds-common/visualizations/useProgressSize';
5
+ import { getProgressSize } from '@coinbase/cds-common/visualizations/getProgressSize';
6
6
  import { convertMotionConfig } from '../animation/convertMotionConfig';
7
7
  import { useTheme } from '../hooks/useTheme';
8
8
  import { Box, HStack } from '../layout';
@@ -10,7 +10,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
10
10
  export const ProgressBar = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, forwardedRef) => {
11
11
  let {
12
12
  weight = 'normal',
13
- progress,
13
+ progress = 0,
14
14
  color = 'bgPrimary',
15
15
  disabled,
16
16
  disableAnimateOnMount,
@@ -22,7 +22,7 @@ export const ProgressBar = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, forw
22
22
  onAnimationStart
23
23
  } = _ref;
24
24
  const theme = useTheme();
25
- const height = useProgressSize(weight);
25
+ const height = getProgressSize(weight);
26
26
  const animatedProgress = useRef(new Animated.Value(disableAnimateOnMount ? progress : 0));
27
27
  const [trackWidth, setTrackWidth] = useState(-1);
28
28
  useEffect(() => {
@@ -1,64 +1,55 @@
1
1
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
- import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
2
+ import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { Animated, I18nManager } from 'react-native';
4
4
  import { animateProgressBaseSpec } from '@coinbase/cds-common/animation/progress';
5
- import { usePreviousValues } from '@coinbase/cds-common/hooks/usePreviousValues';
6
5
  import { convertMotionConfig } from '../animation/convertMotionConfig';
7
6
  import { useLayout } from '../hooks/useLayout';
8
7
  import { Box, VStack } from '../layout';
9
8
  import { getProgressBarLabelParts } from './getProgressBarLabelParts';
10
9
  import { ProgressTextLabel } from './ProgressTextLabel';
11
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ const getEndTranslateX = (containerWidth, textWidth, progress) => I18nManager.isRTL ? Math.min(containerWidth - textWidth, containerWidth - containerWidth * progress) : Math.max(0, containerWidth * progress - textWidth);
12
12
  const ProgressBarFloatLabel = /*#__PURE__*/memo(_ref => {
13
13
  let {
14
14
  label,
15
15
  disabled,
16
- progress,
16
+ progress = 0,
17
17
  disableAnimateOnMount,
18
18
  labelPlacement,
19
19
  styles
20
20
  } = _ref;
21
21
  const [textWidth, setTextWidth] = useState(-1);
22
- const {
23
- addPreviousValue: addPreviousPercent
24
- } = usePreviousValues([disableAnimateOnMount ? progress : 0]);
25
22
  const [size, onLayout] = useLayout();
26
23
  const containerWidth = size.width;
27
- const [hasAnimationMounted, setHasAnimationMounted] = useState(!disableAnimateOnMount);
28
- const animatedProgress = useMemo(() => new Animated.Value(0), []);
29
- addPreviousPercent(progress);
24
+ const animatedTranslateX = useRef(new Animated.Value(0));
30
25
  const {
31
26
  value: labelNum,
32
27
  render: renderLabel
33
28
  } = getProgressBarLabelParts(label);
34
29
  useEffect(() => {
35
- if (containerWidth > 0 && textWidth > -1) {
36
- if (!hasAnimationMounted && disableAnimateOnMount) {
37
- animatedProgress.setValue(progress);
38
- setHasAnimationMounted(true);
39
- } else {
40
- var _Animated$timing;
41
- (_Animated$timing = Animated.timing(animatedProgress, convertMotionConfig(_extends({
42
- toValue: progress
43
- }, animateProgressBaseSpec, {
44
- useNativeDriver: true
45
- })))) == null || _Animated$timing.start();
46
- }
30
+ if (containerWidth <= 0 || textWidth < 0) return;
31
+ const targetTranslateX = getEndTranslateX(containerWidth, textWidth, progress);
32
+ if (disableAnimateOnMount) {
33
+ animatedTranslateX.current.setValue(targetTranslateX);
34
+ } else {
35
+ Animated.timing(animatedTranslateX.current, convertMotionConfig(_extends({
36
+ toValue: targetTranslateX
37
+ }, animateProgressBaseSpec, {
38
+ useNativeDriver: true
39
+ }))).start();
47
40
  }
48
- }, [progress, containerWidth, textWidth, animatedProgress, disableAnimateOnMount, hasAnimationMounted]);
41
+ }, [progress, containerWidth, textWidth, disableAnimateOnMount]);
49
42
  const handleTextLayout = useCallback(event => {
50
43
  setTextWidth(event.nativeEvent.layout.width);
51
44
  }, []);
45
+ const hasDimensions = containerWidth > 0 && textWidth > -1;
52
46
  const containerStyle = useMemo(() => [styles == null ? void 0 : styles.labelContainer], [styles == null ? void 0 : styles.labelContainer]);
53
47
  const labelStyle = useMemo(() => [{
54
- opacity: hasAnimationMounted ? 1 : 0,
48
+ opacity: hasDimensions ? 1 : 0,
55
49
  transform: [{
56
- translateX: animatedProgress.interpolate({
57
- inputRange: [0, 1],
58
- outputRange: [I18nManager.isRTL ? containerWidth - textWidth : 0, I18nManager.isRTL ? 0 : containerWidth - textWidth]
59
- })
50
+ translateX: animatedTranslateX.current
60
51
  }]
61
- }], [containerWidth, textWidth, hasAnimationMounted, animatedProgress]);
52
+ }], [hasDimensions]);
62
53
  return /*#__PURE__*/_jsx(Box, {
63
54
  flexWrap: "nowrap",
64
55
  onLayout: onLayout,
@@ -1,11 +1,11 @@
1
1
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
2
  import React, { forwardRef, memo, useEffect, useMemo, useRef } from 'react';
3
- import { Animated } from 'react-native';
3
+ import { Animated, StyleSheet } from 'react-native';
4
4
  import { Circle, G, Svg } from 'react-native-svg';
5
5
  import { animateProgressBaseSpec } from '@coinbase/cds-common/animation/progress';
6
6
  import { getCircumference, getRadius } from '@coinbase/cds-common/utils/circle';
7
7
  import { getProgressCircleParams } from '@coinbase/cds-common/visualizations/getProgressCircleParams';
8
- import { useProgressSize } from '@coinbase/cds-common/visualizations/useProgressSize';
8
+ import { getProgressSize } from '@coinbase/cds-common/visualizations/getProgressSize';
9
9
  import { isTest } from '@coinbase/cds-utils';
10
10
  import { convertMotionConfig } from '../animation/convertMotionConfig';
11
11
  import { useTheme } from '../hooks/useTheme';
@@ -14,19 +14,19 @@ import { DefaultProgressCircleContent } from './DefaultProgressCircleContent';
14
14
  import { VisualizationContainer } from './VisualizationContainer';
15
15
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
16
  const AnimatedCircle = Animated.createAnimatedComponent(Circle);
17
+ const AnimatedSvg = Animated.createAnimatedComponent(Svg);
17
18
  const ProgressCircleInner = /*#__PURE__*/memo(_ref => {
18
19
  let {
19
20
  size,
20
- progress,
21
+ progress = 0,
21
22
  color,
22
- weight,
23
+ strokeWidth,
23
24
  visuallyDisabled,
24
25
  style,
25
26
  onAnimationEnd,
26
27
  onAnimationStart,
27
28
  disableAnimateOnMount
28
29
  } = _ref;
29
- const strokeWidth = useProgressSize(weight);
30
30
  const theme = useTheme();
31
31
  const circleRef = useRef(null);
32
32
  const circumference = getCircumference(getRadius(size, strokeWidth));
@@ -47,8 +47,7 @@ const ProgressCircleInner = /*#__PURE__*/memo(_ref => {
47
47
  });
48
48
  }, [circumference, progress, animatedStrokeDashOffset, onAnimationStart, onAnimationEnd]);
49
49
  return /*#__PURE__*/_jsx(AnimatedCircle, _extends({
50
- ref: !isTest() ? circleRef : undefined // This is required because Circle is mocked in the unit test to support testID. The mock does not support refs
51
- ,
50
+ ref: !isTest() ? circleRef : undefined,
52
51
  strokeDasharray: circumference,
53
52
  strokeDashoffset: animatedStrokeDashOffset.current,
54
53
  strokeLinecap: progress > 0 ? 'round' : 'butt',
@@ -61,14 +60,15 @@ const ProgressCircleInner = /*#__PURE__*/memo(_ref => {
61
60
  });
62
61
  export const ProgressCircle = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref3, forwardedRef) => {
63
62
  let {
63
+ indeterminate,
64
64
  weight = 'normal',
65
- progress,
65
+ progress = indeterminate ? 0.75 : 0,
66
66
  // Default is empty string due to iOS VoiceOver repeating percentage multiple times when
67
67
  // a11y label isn't specified
68
- accessibilityLabel = '',
69
- color = 'bgPrimary',
68
+ accessibilityLabel = indeterminate ? 'Loading' : '',
69
+ color = indeterminate ? 'fgMuted' : 'bgPrimary',
70
70
  disabled,
71
- disableAnimateOnMount,
71
+ disableAnimateOnMount = indeterminate ? true : false,
72
72
  testID,
73
73
  hideContent,
74
74
  hideText,
@@ -80,12 +80,25 @@ export const ProgressCircle = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref3,
80
80
  onAnimationStart
81
81
  } = _ref3;
82
82
  const theme = useTheme();
83
- const strokeWidth = useProgressSize(weight);
83
+ const strokeWidth = getProgressSize(weight);
84
84
  const visSize = size != null ? size : '100%';
85
85
  const rootStyle = useMemo(() => [style, styles == null ? void 0 : styles.root], [style, styles == null ? void 0 : styles.root]);
86
86
  const textContainerStyle = useMemo(() => [{
87
87
  padding: strokeWidth
88
88
  }, styles == null ? void 0 : styles.textContainer], [strokeWidth, styles == null ? void 0 : styles.textContainer]);
89
+ const animatedRotate = useRef(new Animated.Value(0));
90
+ useEffect(() => {
91
+ if (!indeterminate) return;
92
+ // if indeterminate, animate the rotation of the svg
93
+ const animation = Animated.loop(Animated.timing(animatedRotate.current, convertMotionConfig({
94
+ toValue: 1,
95
+ duration: 'slow4',
96
+ easing: 'linear',
97
+ fromValue: 0
98
+ })));
99
+ animation.start();
100
+ return () => animation.stop();
101
+ }, [indeterminate]);
89
102
  return /*#__PURE__*/_jsx(VisualizationContainer, {
90
103
  height: visSize,
91
104
  width: visSize,
@@ -95,12 +108,12 @@ export const ProgressCircle = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref3,
95
108
  height,
96
109
  circleSize
97
110
  } = _ref4;
98
- return /*#__PURE__*/_jsx(Box, {
111
+ return /*#__PURE__*/_jsxs(Box, {
99
112
  ref: forwardedRef,
100
113
  accessible: true,
101
114
  accessibilityLabel: accessibilityLabel,
102
115
  accessibilityRole: "progressbar",
103
- accessibilityValue: {
116
+ accessibilityValue: indeterminate ? undefined : {
104
117
  min: 0,
105
118
  max: 100,
106
119
  now: Math.round(progress * 100)
@@ -111,57 +124,64 @@ export const ProgressCircle = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref3,
111
124
  style: rootStyle,
112
125
  testID: testID,
113
126
  width: width,
114
- children: /*#__PURE__*/_jsxs(Box, {
115
- flexGrow: 0,
116
- flexShrink: 0,
127
+ children: [/*#__PURE__*/_jsx(AnimatedSvg, {
117
128
  height: circleSize,
118
- style: styles == null ? void 0 : styles.svgContainer,
129
+ style: [styles == null ? void 0 : styles.svg, styleSheet.svg, {
130
+ transform: [{
131
+ rotate: animatedRotate.current.interpolate({
132
+ inputRange: [0, 1],
133
+ outputRange: ['0deg', '360deg']
134
+ })
135
+ }]
136
+ }],
137
+ viewBox: "0 0 " + circleSize + " " + circleSize,
119
138
  width: circleSize,
120
- children: [/*#__PURE__*/_jsx(Svg, {
121
- height: circleSize,
122
- style: styles == null ? void 0 : styles.svg,
123
- viewBox: "0 0 " + circleSize + " " + circleSize,
124
- width: circleSize,
125
- children: /*#__PURE__*/_jsxs(G, {
126
- origin: circleSize / 2 + ", " + circleSize / 2,
127
- rotation: -90,
128
- children: [/*#__PURE__*/_jsx(Circle, _extends({}, getProgressCircleParams({
129
- size: circleSize,
130
- strokeWidth,
131
- stroke: theme.color.bgLine
132
- }), (styles == null ? void 0 : styles.circle) || {})), /*#__PURE__*/_jsx(ProgressCircleInner, {
133
- color: color,
134
- disableAnimateOnMount: disableAnimateOnMount,
135
- onAnimationEnd: onAnimationEnd,
136
- onAnimationStart: onAnimationStart,
137
- progress: progress,
138
- size: circleSize,
139
- style: styles == null ? void 0 : styles.progress,
140
- visuallyDisabled: disabled,
141
- weight: weight
142
- })]
143
- })
144
- }, circleSize), !hideText && !hideContent && /*#__PURE__*/_jsx(Box, {
139
+ children: /*#__PURE__*/_jsxs(G, {
140
+ origin: circleSize / 2 + ", " + circleSize / 2,
141
+ rotation: -90,
142
+ children: [/*#__PURE__*/_jsx(Circle, _extends({}, getProgressCircleParams({
143
+ size: circleSize,
144
+ strokeWidth,
145
+ stroke: theme.color.bgLine
146
+ }), (styles == null ? void 0 : styles.circle) || {})), /*#__PURE__*/_jsx(ProgressCircleInner, {
147
+ color: color,
148
+ disableAnimateOnMount: disableAnimateOnMount,
149
+ indeterminate: indeterminate,
150
+ onAnimationEnd: onAnimationEnd,
151
+ onAnimationStart: onAnimationStart,
152
+ progress: progress,
153
+ size: circleSize,
154
+ strokeWidth: strokeWidth,
155
+ style: styles == null ? void 0 : styles.progress,
156
+ visuallyDisabled: disabled
157
+ })]
158
+ })
159
+ }, circleSize), !hideText && !hideContent && /*#__PURE__*/_jsx(Box, {
160
+ height: "100%",
161
+ position: "absolute",
162
+ style: textContainerStyle,
163
+ width: "100%",
164
+ children: /*#__PURE__*/_jsx(Box, {
165
+ alignItems: "center",
166
+ borderRadius: 1000,
145
167
  height: "100%",
146
- position: "absolute",
147
- style: textContainerStyle,
168
+ justifyContent: "center",
169
+ overflow: "hidden",
148
170
  width: "100%",
149
- children: /*#__PURE__*/_jsx(Box, {
150
- alignItems: "center",
151
- borderRadius: 1000,
152
- height: "100%",
153
- justifyContent: "center",
154
- overflow: "hidden",
155
- width: "100%",
156
- children: contentNode != null ? contentNode : /*#__PURE__*/_jsx(DefaultProgressCircleContent, {
157
- disableAnimateOnMount: disableAnimateOnMount,
158
- disabled: disabled,
159
- progress: progress
160
- })
171
+ children: contentNode != null ? contentNode : !indeterminate && /*#__PURE__*/_jsx(DefaultProgressCircleContent, {
172
+ disableAnimateOnMount: disableAnimateOnMount,
173
+ disabled: disabled,
174
+ progress: progress
161
175
  })
162
- })]
163
- })
176
+ })
177
+ })]
164
178
  });
165
179
  }
166
180
  });
167
- }));
181
+ }));
182
+ const styleSheet = StyleSheet.create({
183
+ svg: {
184
+ flexGrow: 0,
185
+ flexShrink: 0
186
+ }
187
+ });