-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from dkonasov/click-to-copy
click-to-copy feature
- Loading branch information
Showing
4 changed files
with
102 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
--- | ||
sidebar_position: 3 | ||
title: Click to copy | ||
--- | ||
|
||
## General description | ||
|
||
Hook that allows you to implement copy-by-click semantic – when user clicks on the interface element and gets some predefined text copied to clipboard. | ||
|
||
## Usage example | ||
|
||
```jsx | ||
export const ComponentWithCopyableText = () => { | ||
const text = 'This text will be copied!'; | ||
const [ clickHandler, copyPromise ] = useClickToCopy(text); | ||
|
||
return ( | ||
<> | ||
<div>{text}</div> | ||
<button onClick={clickHandler}>Copy text</button> | ||
</> | ||
) | ||
}; | ||
``` | ||
|
||
## API | ||
|
||
### useClickToCopy | ||
|
||
```ts | ||
declare function useClickToCopy(text: string): [() => void, Promise<void>]; | ||
``` | ||
|
||
#### Arguments | ||
|
||
|arg|type|description| | ||
|:--|:---|:----------| | ||
|`text`|`string`|Text to copy| | ||
|
||
|
||
Returns a tuple with handler for a trigger and promise, which will be resolve when the text will be copied. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { useCallback } from "react"; | ||
|
||
export function useClickToCopy(text: string): [() => void, Promise<void>] { | ||
let resolver: () => void; | ||
const promise = new Promise<void>((resolve) => { | ||
resolver = resolve; | ||
}); | ||
|
||
const handler = useCallback(async () => { | ||
await navigator.clipboard.writeText(text); | ||
|
||
resolver(); | ||
}, [text, resolver]); | ||
|
||
return [handler, promise]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export { useAutohide } from "./autohide"; | ||
export { useClickToCopy } from "./click-to-copy"; | ||
export { useShowable } from "./showable"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { describe, it, vi, expect, afterEach } from "vitest"; | ||
import { renderHook, act } from "@testing-library/react"; | ||
|
||
import { useClickToCopy } from "../src/click-to-copy"; | ||
|
||
type DeepPartial<T> = T extends object | ||
? { | ||
[P in keyof T]?: DeepPartial<T[P]>; | ||
} | ||
: T; | ||
|
||
const navigatorMock: DeepPartial<Navigator> = { | ||
clipboard: { | ||
writeText: vi.fn(() => Promise.resolve()), | ||
}, | ||
}; | ||
|
||
vi.stubGlobal("navigator", navigatorMock); | ||
|
||
describe("click to copy", () => { | ||
afterEach(() => { | ||
vi.resetAllMocks(); | ||
}); | ||
|
||
it("should call clipboard method of we API when handler is called", async () => { | ||
const { result } = renderHook(() => useClickToCopy("henlo, fren!")); | ||
const [handler] = result.current; | ||
|
||
await act(() => handler()); | ||
|
||
expect(navigatorMock.clipboard?.writeText).toHaveBeenCalledWith( | ||
"henlo, fren!", | ||
); | ||
}); | ||
|
||
it("should resolve promise when text was copied to clipboard", async () => { | ||
const { result } = renderHook(() => useClickToCopy("henlo, fren!")); | ||
const [handler, promise] = result.current; | ||
|
||
await act(() => handler()); | ||
|
||
await expect(promise).resolves.toBeFalsy(); | ||
}); | ||
}); |