Skip to content

[URH-51] useClipboard 신규 #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Aug 13, 2024
58 changes: 58 additions & 0 deletions src/hooks/useClipboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useState, useEffect } from 'react';
import { imgToBlob } from '../utils';

/**
* 클립보드에 텍스트나 이미지를 복사하는 커스텀 훅
*
* @returns {boolean} `copied`: 복사 작업의 성공 여부를 나타내는 플래그
* @returns {(string) => Promise<void>} `copyText`: 텍스트를 클립보드에 복사하는 비동기 함수
* @returns {(string) => void} `copyImg`: 주어진 경로의 이미지를 클립보드에 복사하는 함수
*
* @description
* 클립보드 API가 지원되지 않는 경우 에러를 발생시킵니다.
*/
const useClipboard = () => {
const [copied, setCopied] = useState(false);

if (!navigator.clipboard) {
throw new Error('Clipboard API not supported.');
}

const handleCopy = async (copy: () => Promise<void>) => {
setCopied(false);
try {
await copy();
setCopied(true);
} catch (error) {
setCopied(false);
console.error(error);
throw new Error(`Failed to save to clipboard.`);
}
};

const copyText = (text: string) => {
handleCopy(() => navigator.clipboard.writeText(text));
};

const copyImg = (path: string) => {
imgToBlob(path, async (imgBlob) => {
if (!imgBlob) return;
handleCopy(() =>
navigator.clipboard.write([new ClipboardItem({ 'image/png': imgBlob })])
);
});
};

useEffect(() => {
if (copied) {
const timer = setTimeout(() => {
setCopied(false);
}, 5000);
return () => clearTimeout(timer);
}
}, [copied]);

return { copied, copyText, copyImg };
};

export default useClipboard;
18 changes: 18 additions & 0 deletions src/utils/imgToBlob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const img = new Image();
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

export const imgToBlob = (path: string, func: (blob: Blob | null) => void) => {
img.crossOrigin = 'Anonymous';
img.onload = function () {
if (this instanceof HTMLImageElement) {
canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;
ctx?.drawImage(this, 0, 0);
canvas.toBlob((blob) => {
func(blob);
}, 'image/png');
}
};
img.src = path;
};
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { delayExecution, type CancelToken } from './delayExecution';
export { throttle } from './throttle';
export { isClient } from './isClient';
export { isTouchDevice } from './isTouchDevice';
export { imgToBlob } from './imgToBlob';
Loading