diff --git a/README.md b/README.md
index 8b5a1c6..876516d 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@ A lightweight library that provides two essential custom hooks for your react or
- **`useInterval`**: Set up recurring functions at specified intervals.
- **`useTimeout`**: Delay execution of a function for a specified time.
- **`useDebouncedValue`**: Debounce a value, updating it after a specified delay.
+- **`useCopyToClipboard`**: Copies text to clipboard
## Installation
@@ -22,7 +23,7 @@ npm install @shurutech/react-hook-tools
#### Syntax:
-```
+```jsx
useInterval(()=>{
// functionality
},time)
@@ -31,7 +32,7 @@ Note: Time will in milliseconds ( > 0 ) if you need to run interval, and undefin
#### Example
-```
+```jsx
import { useInterval } from '@shurutech/react-hook-tools';
const IntervalComponent = () => {
@@ -47,7 +48,7 @@ const IntervalComponent = () => {
#### Syntax:
-```
+```jsx
useTimeout(()=>{
// functionality
},time)
@@ -56,7 +57,7 @@ Note: Time will in milliseconds ( > 0 ) if you need to run interval, and undefin
#### Example
-```
+```jsx
import { useTimeout } from '@shurutech/react-hook-tools';
const TimerComponent = () => {
@@ -72,13 +73,13 @@ const TimerComponent = () => {
#### Syntax:
-```
+```jsx
const debouncedValue = useDebouncedValue(value, delay);
```
#### Example
-```
+```jsx
import { useDebouncedValue } from '@shurutech/react-hook-tools';
const SearchComponent = () => {
@@ -103,6 +104,37 @@ const SearchComponent = () => {
};
```
+### useCopyToClipboard:
+
+#### Syntax:
+
+```jsx
+const [copiedText, copyFunction] = useCopyToClipboard()
+```
+
+#### Example
+
+```jsx
+import { useCopyToClipboard } from '@shurutech/react-hook-tools';
+
+const CopyComponent = () => {
+ const [copiedText, copyFunction] = useCopyToClipboard()
+
+ const handleCopy = async () => {
+ const copyStatus = await copyFunction("Hello, World!")
+
+ if(copyStatus)
+ console.log("Text copied successfully!")
+ else
+ console.log("Copy failed!")
+ }
+
+ return (
+
+ );
+};
+```
+
## How to Contribute
1. Fork this repository to your GitHub account and clone it locally.
diff --git a/src/hooks/useCopyToClipboard.js b/src/hooks/useCopyToClipboard.js
new file mode 100644
index 0000000..5fc86c2
--- /dev/null
+++ b/src/hooks/useCopyToClipboard.js
@@ -0,0 +1,58 @@
+import { useCallback, useState } from "react";
+
+/**
+ *
+ * @description Custom hook that copies text to the clipboard using the `Clipboard API`.
+ *
+ *
+ * @typedef {string | null} CopiedValue
+ * @typedef {(text: string) => Promise} CopyFunction
+ *
+ * @returns {[CopiedValue, CopyFunction]}
+ *
+ * @example
+ * ```jsx
+ *
+ * const [copiedText, copyFunction] = useCopyToClipboard()
+ *
+ * const handleCopy = async () => {
+ * const copyStatus = await copyFunction("Hello, World!")
+ * if(copyStatus) console.log("Text copied successfully!")
+ * else console.log("Copy failed!")
+ * }
+ *
+ *
+ * ```
+ */
+export function useCopyToClipboard() {
+ const [copiedText, setCopiedText] = useState(null);
+
+ /**
+ * @description Function that copies text to the clipboard.
+ * @type {CopyFunction}
+ */
+ const copyFunction = useCallback(
+ async (text) => {
+ if (!navigator.clipboard) {
+ // Clipboard API not available
+ console.warn("Clipboard API not available");
+ return false;
+ }
+
+ try {
+ await navigator.clipboard.writeText(text);
+ setCopiedText(text);
+
+ return true;
+ } catch (error) {
+ console.warn("Copy to clipboard failed", error);
+ setCopiedText(null);
+
+ return false;
+ }
+ },
+ []
+ );
+
+ return [copiedText, copyFunction];
+}
diff --git a/src/hooks/useDebouncedValue.js b/src/hooks/useDebouncedValue.js
index bad2353..15313c9 100644
--- a/src/hooks/useDebouncedValue.js
+++ b/src/hooks/useDebouncedValue.js
@@ -1,4 +1,4 @@
-import { useState, useEffect } from 'react';
+import { useEffect, useState } from 'react';
export function useDebouncedValue(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
diff --git a/src/hooks/useInterval.js b/src/hooks/useInterval.js
index db5cbb2..330df84 100644
--- a/src/hooks/useInterval.js
+++ b/src/hooks/useInterval.js
@@ -1,8 +1,33 @@
-import { useEffect, useRef } from 'react'
+import { useEffect, useRef } from 'react';
+import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';
+/**
+ * @description Custom hook that creates an interval that invokes a callback function at a specified delay using the `setInterval` API.
+ *
+ *
+ * @param {() => void} callback The function to be invoked at each interval.
+ * @param {number | null} delay The time, in milliseconds, between each invocation of the callback. Use null to clear the interval.
+ *
+ * @returns {void} This hook does not return anything.
+ *
+ * @example
+ * ```jsx
+ * const [count, setCount] = useState(0)
+ * const counter = () => {
+ * setCount(x => x + 1)
+ * }
+ * // Increment the count every 2 seconds
+ * useInterval(counter, 2000)
+ * ```
+ */
export function useInterval(callback, delay) {
const savedCallback = useRef(callback)
+ // Remember the latest callback if it changes.
+ useIsomorphicLayoutEffect(() => {
+ savedCallback.current = callback;
+ }, [callback]);
+
useEffect(() => {
if (delay === null) {
return
diff --git a/src/hooks/useIsomorphicLayoutEffect.js b/src/hooks/useIsomorphicLayoutEffect.js
new file mode 100644
index 0000000..49ca31f
--- /dev/null
+++ b/src/hooks/useIsomorphicLayoutEffect.js
@@ -0,0 +1,4 @@
+import { useEffect, useLayoutEffect } from 'react'
+
+export const useIsomorphicLayoutEffect =
+ typeof window !== 'undefined' ? useLayoutEffect : useEffect
diff --git a/src/hooks/useTimeout.js b/src/hooks/useTimeout.js
index 101dd20..cbf0183 100644
--- a/src/hooks/useTimeout.js
+++ b/src/hooks/useTimeout.js
@@ -1,19 +1,43 @@
-import { useEffect, useRef } from 'react'
+import { useEffect, useRef } from "react";
+import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect";
+/**
+ * @description Custom hook that handles timeouts in React components using the setTimeout API.
+ *
+ *
+ * @param {() => void} callback The function to be executed when the timeout elapses.
+ * @param {number | null} delay The duration (in milliseconds) for the timeout. Set to null to clear the timeout.
+ *
+ * @returns {void} This hook does not return anything.
+ *
+ * @example
+ * ```jsx
+ * const [visible, setVisible] = useState(true)
+ * const hide = () => {
+ * setVisible(false)
+ * }
+ * useTimeout(hide, 5000)
+ * ```
+ */
export function useTimeout(callback, delay) {
- const savedCallback = useRef(callback)
+ const savedCallback = useRef(callback);
+
+ // Remember the latest callback if it changes.
+ useIsomorphicLayoutEffect(() => {
+ savedCallback.current = callback;
+ }, [callback]);
useEffect(() => {
if (!delay && delay !== 0) {
- return
+ return;
}
const id = setTimeout(() => {
- savedCallback.current()
- }, delay)
+ savedCallback.current();
+ }, delay);
return () => {
- clearTimeout(id)
- }
- }, [delay])
-}
\ No newline at end of file
+ clearTimeout(id);
+ };
+ }, [delay]);
+}
diff --git a/src/index.js b/src/index.js
index 0f45f06..7a00e81 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,5 +1,6 @@
-import { useInterval } from "./hooks/useInterval";
-import { useTimeout } from "./hooks/useTimeout";
-import { useDebouncedValue } from "./hooks/useDebouncedValue";
+export { useCopyToClipboard } from './hooks/useCopyToClipboard';
+export { useDebouncedValue } from "./hooks/useDebouncedValue";
+export { useInterval } from "./hooks/useInterval";
+export { useIsomorphicLayoutEffect } from "./hooks/useIsomorphicLayoutEffect";
+export { useTimeout } from "./hooks/useTimeout";
-export {useInterval,useTimeout,useDebouncedValue}
\ No newline at end of file