45 | );
46 | };
47 |
48 | export default App;
49 |
--------------------------------------------------------------------------------
/src/helpers/useCounter.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import { BaseCounter, BaseCounterOptions } from "../interfaces";
3 | import { addLeadingZero } from ".";
4 |
5 | export const useCounter = (
6 | min: number,
7 | max: number,
8 | isCountingUp: boolean,
9 | options: BaseCounterOptions
10 | ): BaseCounter => {
11 | if (min >= max) {
12 | throw new Error("The min parameter has to be less than the max parameter.");
13 | }
14 |
15 | const { startPaused, onFinish } = options;
16 | const [count, setCount] = useState(isCountingUp ? min : max);
17 | const [paused, setPaused] = useState(startPaused ?? false);
18 | const [isOver, setIsOver] = useState(false);
19 |
20 | useEffect(() => {
21 | if (paused) {
22 | return;
23 | }
24 |
25 | const interval = setInterval(() => {
26 | setCount((prev) => {
27 | return isCountingUp ? prev + 1 : prev - 1;
28 | });
29 | }, 1000);
30 |
31 | if ((count <= min && !isCountingUp) || (count >= max && isCountingUp)) {
32 | setIsOver(true);
33 | clearInterval(interval);
34 | return;
35 | }
36 |
37 | return () => clearInterval(interval);
38 | }, [count, min, max, paused, isCountingUp]);
39 |
40 | useEffect(() => {
41 | isOver && onFinish && onFinish();
42 | }, [isOver]);
43 |
44 | return {
45 | current: {
46 | withLeadingZero: addLeadingZero(count),
47 | withoutLeadingZero: count.toString(),
48 | },
49 | isPaused: paused,
50 | isOver,
51 | pause: () => setPaused(true),
52 | play: () => setPaused(false),
53 | reset: () => {
54 | setIsOver(false);
55 | setCount(isCountingUp ? min : max);
56 | },
57 | togglePause: () => {
58 | setPaused(!paused);
59 | },
60 | };
61 | };
62 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "final-countdown-js",
3 | "description": "A library of React hooks to manage counters, timers and stopwatches",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/dlcastillop/final-countdown-js"
7 | },
8 | "keywords": [
9 | "timer",
10 | "timers",
11 | "stopwatch",
12 | "stopwatches",
13 | "counter",
14 | "counters"
15 | ],
16 | "author": "Daniel Castillo {
9 | const { days, hours, minutes, seconds } = parseTime(startTime);
10 | const { startPaused, separator, onFinish } = options;
11 | const [time, setTime] = useState({ days, hours, minutes, seconds });
12 | const [paused, setPaused] = useState(startPaused ?? false);
13 | const divider = separator ?? ":";
14 | const [isOver, setIsOver] = useState(false);
15 |
16 | useEffect(() => {
17 | if (paused) {
18 | return;
19 | }
20 |
21 | const interval = setInterval(() => {
22 | setTime((prev) => {
23 | let d = prev.days;
24 | let h = prev.hours;
25 | let m = prev.minutes;
26 | let s = prev.seconds;
27 |
28 | if (s - 1 < 0) {
29 | s = 59;
30 | if (m - 1 < 0) {
31 | m = 59;
32 | if (h - 1 < 0) {
33 | h = 23;
34 | if (d - 1 >= 0) {
35 | d--;
36 | }
37 | } else {
38 | h--;
39 | }
40 | } else {
41 | m--;
42 | }
43 | } else {
44 | s--;
45 | }
46 |
47 | return { days: d, hours: h, minutes: m, seconds: s };
48 | });
49 | }, 1000);
50 |
51 | if (
52 | time.seconds === 0 &&
53 | time.minutes === 0 &&
54 | time.hours === 0 &&
55 | time.days === 0
56 | ) {
57 | setIsOver(true);
58 | clearInterval(interval);
59 | return;
60 | }
61 |
62 | return () => clearInterval(interval);
63 | }, [days, hours, minutes, seconds, time, paused]);
64 |
65 | useEffect(() => {
66 | isOver && onFinish && onFinish();
67 | }, [isOver]);
68 |
69 | return {
70 | current: {
71 | withLeadingZero: `${addLeadingZero(time.days)}${divider}${addLeadingZero(
72 | time.hours
73 | )}${divider}${addLeadingZero(time.minutes)}${divider}${addLeadingZero(
74 | time.seconds
75 | )}`,
76 | withoutLeadingZero: `${time.days}${divider}${time.hours}${divider}${time.minutes}${divider}${time.seconds}`,
77 | },
78 | isPaused: paused,
79 | isOver,
80 | currentDays: time.days,
81 | currentHours: time.hours,
82 | currentMinutes: time.minutes,
83 | currentSeconds: time.seconds,
84 | elapsedSeconds:
85 | days * 86400 +
86 | hours * 3600 +
87 | minutes * 60 +
88 | seconds -
89 | (time.days * 86400 +
90 | time.hours * 3600 +
91 | time.minutes * 60 +
92 | time.seconds),
93 | remainingSeconds:
94 | time.days * 86400 + time.hours * 3600 + time.minutes * 60 + time.seconds,
95 | pause: () => setPaused(true),
96 | play: () => setPaused(false),
97 | reset: () => {
98 | setIsOver(false);
99 | setTime({ days, hours, minutes, seconds });
100 | },
101 | togglePause: () => {
102 | setPaused(!paused);
103 | },
104 | };
105 | };
106 |
--------------------------------------------------------------------------------
/src/helpers/useInternalStopwatch.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import { addLeadingZero, parseTime } from "../helpers";
3 | import { InternalCounter, StopwatchOptions } from "../interfaces";
4 |
5 | export const useInternalStopwatch = (
6 | options: StopwatchOptions
7 | ): InternalCounter => {
8 | const { startPaused, separator, onFinish, endTime } = options;
9 | const { days, hours, minutes, seconds } = parseTime(endTime ?? "0:0:0:0");
10 | const [time, setTime] = useState({
11 | days: 0,
12 | hours: 0,
13 | minutes: 0,
14 | seconds: 0,
15 | });
16 | const [paused, setPaused] = useState(startPaused ?? false);
17 | const divider = separator ?? ":";
18 | const [isOver, setIsOver] = useState(false);
19 |
20 | useEffect(() => {
21 | if (paused) {
22 | return;
23 | }
24 |
25 | const interval = setInterval(() => {
26 | setTime((prev) => {
27 | let d = prev.days;
28 | let h = prev.hours;
29 | let m = prev.minutes;
30 | let s = prev.seconds;
31 |
32 | if (s + 1 >= 60) {
33 | s = 0;
34 | if (m + 1 >= 60) {
35 | m = 0;
36 | if (h + 1 >= 24) {
37 | h = 0;
38 | d++;
39 | } else {
40 | h++;
41 | }
42 | } else {
43 | m++;
44 | }
45 | } else {
46 | s++;
47 | }
48 |
49 | return { days: d, hours: h, minutes: m, seconds: s };
50 | });
51 | }, 1000);
52 |
53 | if (
54 | endTime &&
55 | time.seconds === seconds &&
56 | time.minutes === minutes &&
57 | time.hours === hours &&
58 | time.days === days
59 | ) {
60 | setIsOver(true);
61 | clearInterval(interval);
62 | return;
63 | }
64 |
65 | return () => clearInterval(interval);
66 | }, [days, hours, minutes, seconds, time, paused]);
67 |
68 | useEffect(() => {
69 | isOver && onFinish && onFinish();
70 | }, [isOver]);
71 |
72 | return {
73 | current: {
74 | withLeadingZero: `${addLeadingZero(time.days)}${divider}${addLeadingZero(
75 | time.hours
76 | )}${divider}${addLeadingZero(time.minutes)}${divider}${addLeadingZero(
77 | time.seconds
78 | )}`,
79 | withoutLeadingZero: `${time.days}${divider}${time.hours}${divider}${time.minutes}${divider}${time.seconds}`,
80 | },
81 | isPaused: paused,
82 | isOver,
83 | currentDays: time.days,
84 | currentHours: time.hours,
85 | currentMinutes: time.minutes,
86 | currentSeconds: time.seconds,
87 | elapsedSeconds:
88 | time.days * 86400 + time.hours * 3600 + time.minutes * 60 + time.seconds,
89 | remainingSeconds: endTime
90 | ? days * 86400 +
91 | hours * 3600 +
92 | minutes * 60 +
93 | seconds -
94 | (time.days * 86400 +
95 | time.hours * 3600 +
96 | time.minutes * 60 +
97 | time.seconds)
98 | : 0,
99 | pause: () => setPaused(true),
100 | play: () => setPaused(false),
101 | reset: () => {
102 | setIsOver(false);
103 | setTime({ days: 0, hours: 0, minutes: 0, seconds: 0 });
104 | },
105 | togglePause: () => {
106 | setPaused(!paused);
107 | },
108 | };
109 | };
110 |
--------------------------------------------------------------------------------
/vite.config.ts.timestamp-1692018226773-58641b11ebb79.mjs:
--------------------------------------------------------------------------------
1 | // vite.config.ts
2 | import react from "file:///D:/Work/01.%20Proyectos/final-countdown-js/node_modules/@vitejs/plugin-react/dist/index.mjs";
3 | import path from "node:path";
4 | import { defineConfig } from "file:///D:/Work/01.%20Proyectos/final-countdown-js/node_modules/vite/dist/node/index.js";
5 | import dts from "file:///D:/Work/01.%20Proyectos/final-countdown-js/node_modules/vite-plugin-dts/dist/index.mjs";
6 | var __vite_injected_original_dirname = "D:\\Work\\01. Proyectos\\final-countdown-js";
7 | var vite_config_default = defineConfig({
8 | plugins: [
9 | react(),
10 | dts({
11 | insertTypesEntry: true
12 | })
13 | ],
14 | build: {
15 | lib: {
16 | entry: path.resolve(__vite_injected_original_dirname, "src/hooks/index.ts"),
17 | name: "final-countdown-js",
18 | formats: ["es", "umd"],
19 | fileName: (format) => `final-countdown-js.${format}.js`
20 | },
21 | rollupOptions: {
22 | external: ["react", "react-dom", "styled-components"],
23 | output: {
24 | globals: {
25 | react: "React",
26 | "react-dom": "ReactDOM",
27 | "styled-components": "styled"
28 | }
29 | }
30 | }
31 | }
32 | });
33 | export {
34 | vite_config_default as default
35 | };
36 | //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJEOlxcXFxXb3JrXFxcXDAxLiBQcm95ZWN0b3NcXFxcZmluYWwtY291bnRkb3duLWpzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCJEOlxcXFxXb3JrXFxcXDAxLiBQcm95ZWN0b3NcXFxcZmluYWwtY291bnRkb3duLWpzXFxcXHZpdGUuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9EOi9Xb3JrLzAxLiUyMFByb3llY3Rvcy9maW5hbC1jb3VudGRvd24tanMvdml0ZS5jb25maWcudHNcIjtpbXBvcnQgcmVhY3QgZnJvbSBcIkB2aXRlanMvcGx1Z2luLXJlYWN0XCI7XHJcbmltcG9ydCBwYXRoIGZyb20gXCJub2RlOnBhdGhcIjtcclxuaW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSBcInZpdGVcIjtcclxuaW1wb3J0IGR0cyBmcm9tIFwidml0ZS1wbHVnaW4tZHRzXCI7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoe1xyXG4gIHBsdWdpbnM6IFtcclxuICAgIHJlYWN0KCksXHJcbiAgICBkdHMoe1xyXG4gICAgICBpbnNlcnRUeXBlc0VudHJ5OiB0cnVlLFxyXG4gICAgfSksXHJcbiAgXSxcclxuICBidWlsZDoge1xyXG4gICAgbGliOiB7XHJcbiAgICAgIGVudHJ5OiBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCBcInNyYy9ob29rcy9pbmRleC50c1wiKSxcclxuICAgICAgbmFtZTogXCJmaW5hbC1jb3VudGRvd24tanNcIixcclxuICAgICAgZm9ybWF0czogW1wiZXNcIiwgXCJ1bWRcIl0sXHJcbiAgICAgIGZpbGVOYW1lOiAoZm9ybWF0KSA9PiBgZmluYWwtY291bnRkb3duLWpzLiR7Zm9ybWF0fS5qc2AsXHJcbiAgICB9LFxyXG4gICAgcm9sbHVwT3B0aW9uczoge1xyXG4gICAgICBleHRlcm5hbDogW1wicmVhY3RcIiwgXCJyZWFjdC1kb21cIiwgXCJzdHlsZWQtY29tcG9uZW50c1wiXSxcclxuICAgICAgb3V0cHV0OiB7XHJcbiAgICAgICAgZ2xvYmFsczoge1xyXG4gICAgICAgICAgcmVhY3Q6IFwiUmVhY3RcIixcclxuICAgICAgICAgIFwicmVhY3QtZG9tXCI6IFwiUmVhY3RET01cIixcclxuICAgICAgICAgIFwic3R5bGVkLWNvbXBvbmVudHNcIjogXCJzdHlsZWRcIixcclxuICAgICAgICB9LFxyXG4gICAgICB9LFxyXG4gICAgfSxcclxuICB9LFxyXG59KTtcclxuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUFvVCxPQUFPLFdBQVc7QUFDdFUsT0FBTyxVQUFVO0FBQ2pCLFNBQVMsb0JBQW9CO0FBQzdCLE9BQU8sU0FBUztBQUhoQixJQUFNLG1DQUFtQztBQUt6QyxJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixTQUFTO0FBQUEsSUFDUCxNQUFNO0FBQUEsSUFDTixJQUFJO0FBQUEsTUFDRixrQkFBa0I7QUFBQSxJQUNwQixDQUFDO0FBQUEsRUFDSDtBQUFBLEVBQ0EsT0FBTztBQUFBLElBQ0wsS0FBSztBQUFBLE1BQ0gsT0FBTyxLQUFLLFFBQVEsa0NBQVcsb0JBQW9CO0FBQUEsTUFDbkQsTUFBTTtBQUFBLE1BQ04sU0FBUyxDQUFDLE1BQU0sS0FBSztBQUFBLE1BQ3JCLFVBQVUsQ0FBQyxXQUFXLHNCQUFzQixNQUFNO0FBQUEsSUFDcEQ7QUFBQSxJQUNBLGVBQWU7QUFBQSxNQUNiLFVBQVUsQ0FBQyxTQUFTLGFBQWEsbUJBQW1CO0FBQUEsTUFDcEQsUUFBUTtBQUFBLFFBQ04sU0FBUztBQUFBLFVBQ1AsT0FBTztBQUFBLFVBQ1AsYUFBYTtBQUFBLFVBQ2IscUJBQXFCO0FBQUEsUUFDdkI7QUFBQSxNQUNGO0FBQUEsSUFDRjtBQUFBLEVBQ0Y7QUFDRixDQUFDOyIsCiAgIm5hbWVzIjogW10KfQo=
37 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | dlcastillo3015@gmail.com.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Final Countdown JS
2 |
3 | Final Countdown JS is a library of React hooks to manage counters, timers and stopwatches.
4 |
5 | ## Featured
6 |
7 |
8 |
9 | [Featured on DevHunt with 19 upvotes ending up in the 6th position of the week.](https://devhunt.org/tool/final-countdown-js)
10 |
11 | ## Installation
12 |
13 | You can use npm, yarn or pnpm to install Final Countdown JS.
14 |
15 | ```bash
16 | npm install final-countdown-js
17 | ```
18 |
19 | ```bash
20 | yarn add final-countdown-js
21 | ```
22 |
23 | ```bash
24 | pnpm install final-countdown-js
25 | ```
26 |
27 | ## Hooks
28 |
29 | > [!NOTE]
30 | > Do you want to use these hooks, but without installing an extra dependency? Try [Nova.js: a collection of dependency-free React hooks](https://novajs.co/).
31 |
32 | ### useCountDown
33 |
34 | The useCountDown hook provides a simple countdown timer functionality.
35 |
36 | It takes three arguments:
37 |
38 | - `min` (number): the initial value of the counter.
39 | - `max`(number): the final value of the counter. It has to be greater than `min`.
40 | - `options`(optional object): the options for the counter.
41 | - `startPaused` (optional boolean): determines whether the counter should start in a paused state. Defaults to false.
42 | - `onFinish` (optional function): a function that will be called when the counter reaches the final value.
43 |
44 | It returns an object with the following props:
45 |
46 | - `current`: an object holding the current time of the counter in both leading zero and non-leading zero formats. This object has two properties:
47 | - `withLeadingZero`: a string indicating the current time of the counter with leading zeroes where necessary.
48 | - `withoutLeadingZero`: a string indicating the current time of the counter without leading zeros.
49 | - `isPaused`: a boolean value indicating if the counter is currently paused.
50 | - `isOver`: a boolean value indicating if the counter has finished running.
51 | - `pause`: a function that, when called, will pause the counter.
52 | - `play`: a function that, when called, will resume (or start) the counter.
53 | - `reset`: a function that, when called, will reset the counter.
54 | - `togglePause`: a function that, when called, will toggle between pausing and playing the counter.
55 |
56 | Example:
57 |
58 | ```tsx
59 | import { useCountDown } from "final-countdown-js";
60 |
61 | const ReactCounter = () => {
62 | const { current, isPaused, isOver, pause, play, reset, togglePause } =
63 | useCountDown(0, 10, {
64 | startPaused: false,
65 | onFinish: () => console.log("Counter ended"),
66 | });
67 |
68 | return (
69 |
70 |
Counter value: {current.withLeadingZero}
71 |
Counter value: {current.withoutLeadingZero}
72 |
Is the counter paused? {isPaused ? "Yes" : "No"}
73 |
Has the counter over? {isOver ? "Yes" : "No"}
74 |
75 |
76 |
77 |
78 |
79 | );
80 | };
81 |
82 | export default ReactCounter;
83 | ```
84 |
85 | ### useCountUp
86 |
87 | The useCountUp hook provides a simple countup timer functionality.
88 |
89 | It takes three arguments:
90 |
91 | - `min` (number): the initial value of the counter.
92 | - `max`(number): the final value of the counter. It has to be greater than `min`.
93 | - `options`(optional object): the options for the counter.
94 | - `startPaused` (optional boolean): determines whether the counter should start in a paused state. Defaults to false.
95 | - `onFinish` (optional function): a function that will be called when the counter reaches the final value.
96 |
97 | It returns an object with the following props:
98 |
99 | - `current`: an object holding the current time of the counter in both leading zero and non-leading zero formats. This object has two properties:
100 | - `withLeadingZero`: a string indicating the current time of the counter with leading zeroes where necessary.
101 | - `withoutLeadingZero`: a string indicating the current time of the counter without leading zeros.
102 | - `isPaused`: a boolean value indicating if the counter is currently paused.
103 | - `isOver`: a boolean value indicating if the counter has finished running.
104 | - `pause`: a function that, when called, will pause the counter.
105 | - `play`: a function that, when called, will resume (or start) the counter.
106 | - `reset`: a function that, when called, will reset the counter.
107 | - `togglePause`: a function that, when called, will toggle between pausing and playing the counter.
108 |
109 | Example:
110 |
111 | ```tsx
112 | import { useCountUp } from "final-countdown-js";
113 |
114 | const ReactCounter = () => {
115 | const { current, isPaused, isOver, pause, play, reset, togglePause } =
116 | useCountUp(0, 10, {
117 | startPaused: false,
118 | onFinish: () => console.log("Counter ended"),
119 | });
120 |
121 | return (
122 |
123 |
Counter value: {current.withLeadingZero}
124 |
Counter value: {current.withoutLeadingZero}
125 |
Is the counter paused? {isPaused ? "Yes" : "No"}
126 |
Has the counter over? {isOver ? "Yes" : "No"}
127 |
128 |
129 |
130 |
131 |
132 | );
133 | };
134 |
135 | export default ReactCounter;
136 | ```
137 |
138 | ### useStopwatch
139 |
140 | The useStopwatch hook provides stopwatch functionality with or without a limit.
141 |
142 | It takes one argument:
143 |
144 | - `options`(optional object): the options for the stopwatch.
145 | - `endTime` (options string): specifies the time at which the stopwatch will stop. It must be in `dd:hh:mm:ss` format. If not specified, the stopwatch will not end.
146 | - `startPaused` (optional boolean): determines whether the stopwatch should start in a paused state. Defaults to false.
147 | - `onFinish` (optional function): a function that will be called when the stopwatch reaches the final value.
148 | - `separator` (optional string): specifies the separator to be used between days, hours, minutes, and seconds when the time is represented as a string. By default, colon (:) is used as a separator.
149 |
150 | It returns an object with the following props:
151 |
152 | - `current`: an object holding the current time of the stopwatch in both leading zero and non-leading zero formats. This object has two properties:
153 | - `withLeadingZero`: a string indicating the current time of the stopwatch with leading zeroes where necessary.
154 | - `withoutLeadingZero`: a string indicating the current time of the stopwatch without leading zeros.
155 | - `isPaused`: a boolean value indicating if the stopwatch is currently paused.
156 | - `isOver`: a boolean value indicating if the stopwatch has finished running.
157 | - `currentDays`: a number indicating the current value of the days on the stopwatch.
158 | - `currentHours`: a number indicating the current value of the hours on the stopwatch.
159 | - `currentMinutes`: a number indicating the current value of the minutes on the stopwatch.
160 | - `currentSeconds`: a number indicating the current value of the seconds on the stopwatch.
161 | - `elapsedSeconds`: a number indicating the total elapsed time, calculated in seconds, since the stopwatch started.
162 | - `remainingSeconds`: a number indicating the total remaining time, calculated in seconds, until the stopwatch reaches the initially set time. If `endTime` is not specified, it will always be 0.
163 | - `remainingTime`: analogous to the `current` object, this object holds the remaining time in both formats:
164 | - `withLeadingZero`: a string indicating the remaining time with leading zeroes. If `endTime` is not specified, it will always be 00:00:00:00.
165 | - `withoutLeadingZero`: a string indicating the remaining time without leading zeroes. If `endTime` is not specified, it will always be 0:0:0:0.
166 | - `pause`: a function that, when called, will pause the stopwatch.
167 | - `play`: a function that, when called, will resume (or start) the stopwatch.
168 | - `reset`: a function that, when called, will reset the stopwatch.
169 | - `togglePause`: a function that, when called, will toggle between pausing and playing the stopwatch.
170 |
171 | Example:
172 |
173 | ```tsx
174 | import { useStopwatch } from "final-countdown-js";
175 |
176 | const ReactCounter = () => {
177 | const {
178 | current,
179 | remainingTime,
180 | currentDays,
181 | currentHours,
182 | currentMinutes,
183 | currentSeconds,
184 | elapsedSeconds,
185 | remainingSeconds,
186 | isPaused,
187 | isOver,
188 | pause,
189 | play,
190 | reset,
191 | togglePause,
192 | } = useStopwatch({
193 | endTime: "00:00:00:10",
194 | startPaused: true,
195 | separator: "-",
196 | onFinish: () => console.log("Stopwatch ended"),
197 | });
198 |
199 | return (
200 |
218 | );
219 | };
220 |
221 | export default ReactCounter;
222 | ```
223 |
224 | ### useTimer
225 |
226 | The useTimer hook provides timer functionality.
227 |
228 | It takes two arguments:
229 |
230 | - `startTime` (string): specifies the time at which the timer will start. It must be in `dd:hh:mm:ss` format.
231 | - `options`(optional object): the options for the timer.
232 | - `startPaused` (optional boolean): determines whether the timer should start in a paused state. Defaults to false.
233 | - `onFinish` (optional function): a function that will be called when the timer reaches the final value.
234 | - `separator` (optional string): specifies the separator to be used between days, hours, minutes, and seconds when the time is represented as a string. By default, colon (:) is used as a separator.
235 |
236 | It returns an object with the following props:
237 |
238 | - `current`: an object holding the current time of the timer in both leading zero and non-leading zero formats. This object has two properties:
239 | - `withLeadingZero`: a string indicating the current time of the timer with leading zeroes where necessary.
240 | - `withoutLeadingZero`: a string indicating the current time of the timer without leading zeros.
241 | - `isPaused`: a boolean value indicating if the timer is currently paused.
242 | - `isOver`: a boolean value indicating if the timer has finished running.
243 | - `currentDays`: a number indicating the current value of the days on the timer.
244 | - `currentHours`: a number indicating the current value of the hours on the timer.
245 | - `currentMinutes`: a number indicating the current value of the minutes on the timer.
246 | - `currentSeconds`: a number indicating the current value of the seconds on the timer.
247 | - `elapsedSeconds`: a number indicating the total elapsed time, calculated in seconds, since the timer started.
248 | - `remainingSeconds`: a number indicating the total remaining time, calculated in seconds, until the timer reaches the initially set time.
249 | - `elapsedTime`: analogous to the `current` object, this object holds the elapsed time in both formats:
250 | - `withLeadingZero`: a string indicating the elapsed time with leading zeroes.
251 | - `withoutLeadingZero`: a string indicating the elapsed time without leading zeroes.
252 | - `pause`: a function that, when called, will pause the timer.
253 | - `play`: a function that, when called, will resume (or start) the timer.
254 | - `reset`: a function that, when called, will reset the timer.
255 | - `togglePause`: a function that, when called, will toggle between pausing and playing the timer.
256 |
257 | Example:
258 |
259 | ```tsx
260 | import { useTimer } from "final-countdown-js";
261 |
262 | const ReactCounter = () => {
263 | const {
264 | current,
265 | elapsedTime,
266 | currentDays,
267 | currentHours,
268 | currentMinutes,
269 | currentSeconds,
270 | elapsedSeconds,
271 | remainingSeconds,
272 | isPaused,
273 | isOver,
274 | pause,
275 | play,
276 | reset,
277 | togglePause,
278 | } = useTimer("00:00:00:10", {
279 | startPaused: true,
280 | separator: "-",
281 | onFinish: () => console.log("Timer ended"),
282 | });
283 |
284 | return (
285 |