misc_pterodactyl-panel/resources/scripts/components/elements/CopyOnClick.tsx

71 lines
2.3 KiB
TypeScript
Raw Normal View History

import classNames from 'classnames';
2022-11-25 20:25:03 +00:00
import copy from 'copy-to-clipboard';
import type { MouseEvent, ReactNode } from 'react';
import { Children, cloneElement, isValidElement, useEffect, useState } from 'react';
import Portal from '@/components/elements/Portal';
import FadeTransition from '@/components/elements/transitions/FadeTransition';
2022-07-02 22:53:03 +00:00
interface CopyOnClickProps {
text: string | number | null | undefined;
showInNotification?: boolean;
2022-11-25 20:25:03 +00:00
children: ReactNode;
2022-07-02 22:53:03 +00:00
}
const CopyOnClick = ({ text, showInNotification = true, children }: CopyOnClickProps) => {
const [copied, setCopied] = useState(false);
useEffect(() => {
if (!copied) return;
const timeout = setTimeout(() => {
setCopied(false);
}, 2500);
return () => {
clearTimeout(timeout);
};
}, [copied]);
2022-11-25 20:25:03 +00:00
if (!isValidElement(children)) {
throw new Error('Component passed to <CopyOnClick/> must be a valid React element.');
}
const child = !text
2022-11-25 20:25:03 +00:00
? Children.only(children)
: cloneElement(Children.only(children), {
// @ts-expect-error I don't know
className: classNames(children.props.className || '', 'cursor-pointer'),
2022-11-25 20:25:03 +00:00
onClick: (e: MouseEvent<HTMLElement>) => {
copy(String(text));
setCopied(true);
if (typeof children.props.onClick === 'function') {
children.props.onClick(e);
}
},
});
return (
<>
{copied && (
<Portal>
2022-11-25 20:25:03 +00:00
<FadeTransition show duration="duration-250" key={copied ? 'visible' : 'invisible'}>
2023-01-12 19:31:47 +00:00
<div className="fixed bottom-0 right-0 z-50 m-4">
<div className="rounded-md bg-neutral-600/95 py-3 px-4 text-slate-200 shadow">
2022-07-02 22:53:03 +00:00
<p>
{showInNotification
? `Copied "${String(text)}" to clipboard.`
: 'Copied text to clipboard.'}
</p>
</div>
</div>
2022-11-25 20:25:03 +00:00
</FadeTransition>
</Portal>
)}
{child}
</>
);
};
export default CopyOnClick;