@rific/timer 0.1.3 → 0.2.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/README.md +2 -2
- package/dist/index.js +6 -2
- package/dist/index.mjs +6 -2
- package/package.json +9 -5
- package/src/Timer.tsx +101 -0
- package/src/index.ts +2 -0
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -35,9 +35,10 @@ __export(index_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
37
|
// src/Timer.tsx
|
|
38
|
-
var import_react =
|
|
38
|
+
var import_react = require("react");
|
|
39
39
|
var import_react_native = require("react-native");
|
|
40
40
|
var import_react_native_svg = __toESM(require("react-native-svg"));
|
|
41
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
41
42
|
var AnimatedCircle = import_react_native.Animated.createAnimatedComponent(import_react_native_svg.Circle);
|
|
42
43
|
var useNativeDriver = true;
|
|
43
44
|
var Timer = ({ children, color, duration, onStart, onStop, radius, startProgress = 0, started, style, width = 6 }) => {
|
|
@@ -97,7 +98,10 @@ var Timer = ({ children, color, duration, onStart, onStop, radius, startProgress
|
|
|
97
98
|
progressRef.current = startProgress;
|
|
98
99
|
startedRef.current = started;
|
|
99
100
|
}, [animation, duration, startProgress, started, startTimer, stopTimer]);
|
|
100
|
-
return /* @__PURE__ */
|
|
101
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: [style, styles.root], children: [
|
|
102
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.default, { width: radius * 2 + width, height: radius * 2 + width, viewBox: `0 0 ${radius * 2 + width} ${radius * 2 + width}`, style: styles.svg, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_svg.G, { rotation: "-90", origin: `${radius + width / 2}, ${radius + width / 2}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnimatedCircle, { cx: radius + width / 2, cy: radius + width / 2, r: radius, stroke: color, strokeWidth: width, fill: "none", strokeDasharray: circumference, ...animatedProps }) }) }),
|
|
103
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: styles.children, children })
|
|
104
|
+
] });
|
|
101
105
|
};
|
|
102
106
|
var styles = import_react_native.StyleSheet.create({
|
|
103
107
|
children: {
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// src/Timer.tsx
|
|
2
|
-
import
|
|
2
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
3
3
|
import { Animated, Easing, StyleSheet, View } from "react-native";
|
|
4
4
|
import Svg, { Circle, G } from "react-native-svg";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
6
|
var AnimatedCircle = Animated.createAnimatedComponent(Circle);
|
|
6
7
|
var useNativeDriver = true;
|
|
7
8
|
var Timer = ({ children, color, duration, onStart, onStop, radius, startProgress = 0, started, style, width = 6 }) => {
|
|
@@ -61,7 +62,10 @@ var Timer = ({ children, color, duration, onStart, onStop, radius, startProgress
|
|
|
61
62
|
progressRef.current = startProgress;
|
|
62
63
|
startedRef.current = started;
|
|
63
64
|
}, [animation, duration, startProgress, started, startTimer, stopTimer]);
|
|
64
|
-
return /* @__PURE__ */
|
|
65
|
+
return /* @__PURE__ */ jsxs(View, { style: [style, styles.root], children: [
|
|
66
|
+
/* @__PURE__ */ jsx(Svg, { width: radius * 2 + width, height: radius * 2 + width, viewBox: `0 0 ${radius * 2 + width} ${radius * 2 + width}`, style: styles.svg, children: /* @__PURE__ */ jsx(G, { rotation: "-90", origin: `${radius + width / 2}, ${radius + width / 2}`, children: /* @__PURE__ */ jsx(AnimatedCircle, { cx: radius + width / 2, cy: radius + width / 2, r: radius, stroke: color, strokeWidth: width, fill: "none", strokeDasharray: circumference, ...animatedProps }) }) }),
|
|
67
|
+
/* @__PURE__ */ jsx(View, { style: styles.children, children })
|
|
68
|
+
] });
|
|
65
69
|
};
|
|
66
70
|
var styles = StyleSheet.create({
|
|
67
71
|
children: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rific/timer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Animated SVG progress ring timer for React Native",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"type": "commonjs",
|
|
27
27
|
"exports": {
|
|
28
28
|
".": {
|
|
29
|
+
"react-native": "./src/index.ts",
|
|
29
30
|
"types": "./dist/index.d.ts",
|
|
30
31
|
"import": "./dist/index.mjs",
|
|
31
32
|
"require": "./dist/index.js"
|
|
@@ -35,7 +36,10 @@
|
|
|
35
36
|
"module": "dist/index.mjs",
|
|
36
37
|
"types": "dist/index.d.ts",
|
|
37
38
|
"files": [
|
|
38
|
-
"dist"
|
|
39
|
+
"dist",
|
|
40
|
+
"src",
|
|
41
|
+
"!src/__tests__",
|
|
42
|
+
"!src/__mocks__"
|
|
39
43
|
],
|
|
40
44
|
"scripts": {
|
|
41
45
|
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
@@ -49,7 +53,7 @@
|
|
|
49
53
|
"test": "jest",
|
|
50
54
|
"test:watch": "jest --watchAll",
|
|
51
55
|
"typecheck": "tsc --noEmit",
|
|
52
|
-
"preversion": "npm run lint && npm test"
|
|
56
|
+
"preversion": "npm run lint && npm test && npm run build"
|
|
53
57
|
},
|
|
54
58
|
"devDependencies": {
|
|
55
59
|
"@testing-library/dom": "^10.4.1",
|
|
@@ -77,8 +81,8 @@
|
|
|
77
81
|
"typescript-eslint": "^8.59.3"
|
|
78
82
|
},
|
|
79
83
|
"peerDependencies": {
|
|
80
|
-
"react": ">=
|
|
81
|
-
"react-native": ">=0.
|
|
84
|
+
"react": ">=18.0.0",
|
|
85
|
+
"react-native": ">=0.76.0",
|
|
82
86
|
"react-native-svg": ">=13.0.0"
|
|
83
87
|
},
|
|
84
88
|
"publishConfig": {
|
package/src/Timer.tsx
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import React, { type ReactNode, useCallback, useEffect, useRef } from 'react'
|
|
2
|
+
import { Animated, Easing, StyleSheet, View, ViewStyle } from 'react-native'
|
|
3
|
+
import Svg, { Circle, G } from 'react-native-svg'
|
|
4
|
+
|
|
5
|
+
const AnimatedCircle = Animated.createAnimatedComponent(Circle)
|
|
6
|
+
|
|
7
|
+
const useNativeDriver = true
|
|
8
|
+
|
|
9
|
+
export type TimerProps = {
|
|
10
|
+
children?: ReactNode
|
|
11
|
+
color: string
|
|
12
|
+
duration: number
|
|
13
|
+
onStart?: () => void
|
|
14
|
+
onStop?: () => void
|
|
15
|
+
radius: number
|
|
16
|
+
startProgress?: number
|
|
17
|
+
started: string | null
|
|
18
|
+
style?: ViewStyle
|
|
19
|
+
width?: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const Timer = ({ children, color, duration, onStart, onStop, radius, startProgress = 0, started, style, width = 6 }: TimerProps) => {
|
|
23
|
+
const durationRef = useRef(duration)
|
|
24
|
+
const progressRef = useRef(startProgress)
|
|
25
|
+
const startedRef = useRef<string | null>(null)
|
|
26
|
+
const circumference = 2 * Math.PI * radius
|
|
27
|
+
const animation = useRef(new Animated.Value(0)).current
|
|
28
|
+
const animatedProps = {
|
|
29
|
+
strokeDashoffset: animation.interpolate({
|
|
30
|
+
inputRange: [0, 1],
|
|
31
|
+
outputRange: [circumference, 0]
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
const startTimer = useCallback(
|
|
35
|
+
(callback?: () => void) => {
|
|
36
|
+
const clampedProgress = Math.max(0, Math.min(1, startProgress))
|
|
37
|
+
const remainingDurationMs = Math.max(0, duration * 1000 * (1 - clampedProgress))
|
|
38
|
+
animation.setValue(clampedProgress)
|
|
39
|
+
if (onStart) onStart()
|
|
40
|
+
Animated.timing(animation, {
|
|
41
|
+
toValue: 1,
|
|
42
|
+
duration: remainingDurationMs,
|
|
43
|
+
easing: Easing.linear,
|
|
44
|
+
useNativeDriver
|
|
45
|
+
}).start(({ finished }) => {
|
|
46
|
+
if (finished && onStop) onStop()
|
|
47
|
+
if (callback) callback()
|
|
48
|
+
})
|
|
49
|
+
},
|
|
50
|
+
[animation, duration, onStart, onStop, startProgress]
|
|
51
|
+
)
|
|
52
|
+
const stopTimer = useCallback(
|
|
53
|
+
(callback?: () => void) => {
|
|
54
|
+
animation.stopAnimation()
|
|
55
|
+
Animated.spring(animation, {
|
|
56
|
+
toValue: 0,
|
|
57
|
+
useNativeDriver
|
|
58
|
+
}).start(callback)
|
|
59
|
+
},
|
|
60
|
+
[animation]
|
|
61
|
+
)
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
const startedChanged = started !== startedRef.current
|
|
64
|
+
const durationChanged = duration !== durationRef.current
|
|
65
|
+
const progressChanged = startProgress !== progressRef.current
|
|
66
|
+
|
|
67
|
+
if (duration === 0) {
|
|
68
|
+
stopTimer()
|
|
69
|
+
} else if (started) {
|
|
70
|
+
if (startedChanged || durationChanged || progressChanged) {
|
|
71
|
+
animation.stopAnimation(() => startTimer())
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
stopTimer()
|
|
75
|
+
}
|
|
76
|
+
durationRef.current = duration
|
|
77
|
+
progressRef.current = startProgress
|
|
78
|
+
startedRef.current = started
|
|
79
|
+
}, [animation, duration, startProgress, started, startTimer, stopTimer])
|
|
80
|
+
return (
|
|
81
|
+
<View style={[style, styles.root]}>
|
|
82
|
+
<Svg width={radius * 2 + width} height={radius * 2 + width} viewBox={`0 0 ${radius * 2 + width} ${radius * 2 + width}`} style={styles.svg}>
|
|
83
|
+
<G rotation='-90' origin={`${radius + width / 2}, ${radius + width / 2}`}>
|
|
84
|
+
<AnimatedCircle cx={radius + width / 2} cy={radius + width / 2} r={radius} stroke={color} strokeWidth={width} fill='none' strokeDasharray={circumference} {...animatedProps} />
|
|
85
|
+
</G>
|
|
86
|
+
</Svg>
|
|
87
|
+
<View style={styles.children}>{children}</View>
|
|
88
|
+
</View>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const styles = StyleSheet.create({
|
|
93
|
+
children: {
|
|
94
|
+
position: 'absolute'
|
|
95
|
+
},
|
|
96
|
+
root: {
|
|
97
|
+
alignItems: 'center',
|
|
98
|
+
justifyContent: 'center'
|
|
99
|
+
},
|
|
100
|
+
svg: {}
|
|
101
|
+
})
|
package/src/index.ts
ADDED