Skip to content

Commit 23d0dfd

Browse files
Karthik-B-06kodiakhq[bot]
authored andcommitted
refactor(circular-progress): ✨ wrap circular progress component
- change svg circle with fixed value of radius - update theme to actual circular progress dimensions - improve circular progress animation - change hint as user controlled prop
1 parent c03f223 commit 23d0dfd

File tree

2 files changed

+88
-66
lines changed

2 files changed

+88
-66
lines changed

src/components/circular-progress/CircularProgress.tsx

Lines changed: 80 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import React, { forwardRef } from "react";
2-
import { StyleSheet, TextInput, TextInputProps } from "react-native";
2+
import { StyleSheet } from "react-native";
33
import Animated, {
44
Easing,
55
interpolate,
66
useAnimatedProps,
7+
useAnimatedStyle,
78
useDerivedValue,
89
useSharedValue,
910
withRepeat,
@@ -12,16 +13,13 @@ import Animated, {
1213
} from "react-native-reanimated";
1314
import Svg, { Circle, G } from "react-native-svg";
1415

15-
import { Box, BoxProps } from "../../primitives";
16+
import { AnimatedBox, Box, BoxProps, Text } from "../../primitives";
1617
import { useTheme } from "../../theme";
17-
import { createComponent, cx } from "../../utils";
18+
import { createComponent, cx, styleAdapter } from "../../utils";
1819

1920
Animated.addWhitelistedNativeProps({ text: true });
2021

2122
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
22-
const AnimatedG = Animated.createAnimatedComponent(G);
23-
24-
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
2523

2624
export type CircularProgressSizes = "sm" | "md" | "lg" | "xl";
2725
export type CircularProgressTheme = "base" | "primary";
@@ -35,10 +33,6 @@ export interface CircularProgressProps extends BoxProps {
3533
* The size of the Circle
3634
*/
3735
themeColor: CircularProgressTheme;
38-
/**
39-
* Stroke Width of the Circle Border
40-
*/
41-
strokeWidth: number;
4236
/**
4337
* Color of Progress value
4438
*/
@@ -64,10 +58,9 @@ export interface CircularProgressProps extends BoxProps {
6458
*/
6559
max: number;
6660
/**
67-
* Should show progress value
68-
* @default false
61+
* Hint for the Meter
6962
*/
70-
hint: boolean;
63+
hint: string;
7164
}
7265

7366
const SPRING_CONFIG = {
@@ -87,13 +80,13 @@ const RNCircularProgress: React.FC<Partial<CircularProgressProps>> = forwardRef<
8780
{
8881
size = "md",
8982
themeColor = "base",
90-
strokeWidth = 2,
9183
progressTrackColor,
9284
trackColor,
9385
value,
9486
min = 0,
9587
max = 100,
9688
hint = false,
89+
style,
9790
...otherProps
9891
},
9992
ref,
@@ -107,13 +100,10 @@ const RNCircularProgress: React.FC<Partial<CircularProgressProps>> = forwardRef<
107100
[value],
108101
);
109102

103+
const strokeWidth = hint ? 5 : 10;
104+
110105
// Circle parameters
111-
const radius = isIndeterminate
112-
? circularProgressTheme.size[size]?.default
113-
: hint
114-
? circularProgressTheme.size[size]?.withHintSize
115-
: circularProgressTheme.size[size]?.default;
116-
const halfCircle = radius + strokeWidth;
106+
const radius = 44;
117107
const circleCircumference = 2 * Math.PI * radius;
118108

119109
// Animation for value based progress
@@ -137,40 +127,68 @@ const RNCircularProgress: React.FC<Partial<CircularProgressProps>> = forwardRef<
137127
});
138128

139129
// Indeterminate Progress
140-
const progress = useSharedValue(-1);
141-
130+
const progress = useSharedValue(0);
131+
const rotate = useSharedValue(0);
132+
const animatedSvgStyle = useAnimatedStyle(() => {
133+
const rotateValue = interpolate(rotate.value, [0, 1], [0, 360]);
134+
return {
135+
transform: [
136+
{
137+
rotate: `${rotateValue}deg`,
138+
},
139+
],
140+
};
141+
});
142142
const indeterminateAnimatedCircularProgress = useAnimatedProps(() => {
143143
return {
144144
strokeDashoffset: interpolate(
145145
progress.value,
146-
[-1, 1],
147-
[circleCircumference, -circleCircumference],
146+
[0, 0.5, 1],
147+
[0, -276, -(276 * 2)],
148148
),
149149
};
150150
});
151151

152152
React.useEffect(() => {
153153
progress.value = withRepeat(
154154
withTiming(1, {
155-
duration: 1750,
155+
duration: 1500,
156+
easing: Easing.linear,
157+
}),
158+
-1,
159+
false,
160+
);
161+
rotate.value = withRepeat(
162+
withTiming(1, {
163+
duration: 1000,
156164
easing: Easing.bezier(0.4, 0, 0.2, 1),
157165
}),
158166
-1,
159167
false,
160168
);
161-
}, [progress]);
162-
const animatedTextProps = useAnimatedProps(() => {
163-
return { text: `${progressValue.value}%` } as unknown as TextInputProps;
164-
});
169+
}, [progress, rotate]);
170+
171+
const circularProgressBoxDimensions = {
172+
width: hint
173+
? circularProgressTheme.size[size]?.withHintSize
174+
: circularProgressTheme.size[size]?.default,
175+
height: hint
176+
? circularProgressTheme.size[size]?.withHintSize
177+
: circularProgressTheme.size[size]?.default,
178+
};
165179

166180
return (
167-
<Box ref={ref} {...otherProps}>
168-
<Svg
169-
width={radius * 2}
170-
height={radius * 2}
171-
viewBox={`0 0 ${halfCircle * 2} ${halfCircle * 2}`}
172-
>
173-
<AnimatedG rotation={"-90"} origin={`${halfCircle}, ${halfCircle}`}>
181+
<AnimatedBox
182+
ref={ref}
183+
style={[
184+
circularProgressBoxDimensions,
185+
styleAdapter(style, { pressed: false }, false),
186+
isIndeterminate && animatedSvgStyle,
187+
]}
188+
{...otherProps}
189+
>
190+
<Svg width="100%" height="100%" viewBox={"0 0 100 100"}>
191+
<G rotation={"-90"} origin="50, 50">
174192
<Circle
175193
stroke={
176194
trackColor
@@ -185,8 +203,8 @@ const RNCircularProgress: React.FC<Partial<CircularProgressProps>> = forwardRef<
185203
strokeWidth={strokeWidth}
186204
fill="transparent"
187205
r={radius}
188-
cx="50%"
189-
cy="50%"
206+
cx={50}
207+
cy={50}
190208
/>
191209
{isIndeterminate && (
192210
<AnimatedCircle
@@ -203,10 +221,10 @@ const RNCircularProgress: React.FC<Partial<CircularProgressProps>> = forwardRef<
203221
strokeWidth={strokeWidth}
204222
fill="transparent"
205223
r={radius}
206-
cx="50%"
207-
cy="50%"
224+
cx={50}
225+
cy={50}
208226
strokeLinecap="round"
209-
strokeDasharray={`${circleCircumference} ${circleCircumference}`}
227+
strokeDasharray="276 276"
210228
animatedProps={indeterminateAnimatedCircularProgress}
211229
/>
212230
)}
@@ -225,33 +243,37 @@ const RNCircularProgress: React.FC<Partial<CircularProgressProps>> = forwardRef<
225243
strokeWidth={strokeWidth}
226244
fill="transparent"
227245
r={radius}
228-
cx="50%"
229-
cy="50%"
230-
strokeDasharray={circleCircumference}
246+
cx={50}
247+
cy={50}
231248
strokeLinecap="round"
249+
strokeDasharray={circleCircumference}
232250
animatedProps={animatedCircleProps}
233251
/>
234252
)}
235-
</AnimatedG>
253+
</G>
236254
</Svg>
237255
{!isIndeterminate && hint && (
238-
<AnimatedTextInput
239-
underlineColorAndroid="transparent"
240-
editable={false}
241-
defaultValue={`${progressValue.value}`}
256+
<Box
242257
style={[
243258
StyleSheet.absoluteFillObject,
244-
tailwind.style(
245-
cx(
246-
circularProgressTheme.text,
247-
circularProgressTheme.size[size]?.text,
248-
),
249-
),
259+
tailwind.style("justify-center items-center bg-transparent"),
250260
]}
251-
animatedProps={animatedTextProps}
252-
/>
261+
>
262+
<Text
263+
style={[
264+
tailwind.style(
265+
cx(
266+
circularProgressTheme.text,
267+
circularProgressTheme.size[size]?.text,
268+
),
269+
),
270+
]}
271+
>
272+
{hint}
273+
</Text>
274+
</Box>
253275
)}
254-
</Box>
276+
</AnimatedBox>
255277
);
256278
},
257279
);

src/theme/defaultTheme/circularProgress.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,23 @@ export const circularProgress = {
1111
},
1212
size: {
1313
sm: {
14-
default: 7,
15-
withHintSize: 22,
14+
default: 14,
15+
withHintSize: 44,
1616
text: "text-xs",
1717
},
1818
md: {
19-
default: 8,
20-
withHintSize: 28,
19+
default: 16,
20+
withHintSize: 56,
2121
text: "text-sm",
2222
},
2323
lg: {
24-
default: 10,
25-
withHintSize: 32,
24+
default: 20,
25+
withHintSize: 64,
2626
text: "text-base",
2727
},
2828
xl: {
29-
default: 14,
30-
withHintSize: 40,
29+
default: 28,
30+
withHintSize: 80,
3131
text: "text-xl",
3232
},
3333
},

0 commit comments

Comments
 (0)