import styled from '@emotion/styled'; import type { FormEvent } from 'react'; import { useCallback, useEffect, useMemo, useRef } from 'react'; import Button from '../../component/elements/Button.js'; import { StandardDialog } from '../../component/elements/StandardDialog.tsx'; import { StyledDialogBody } from '../../component/elements/StyledDialogBody.js'; import type { ClipboardMode } from './types.js'; const ClipboardForm = styled.form` padding: 0.5rem; > label { display: flex; flex-direction: column; gap: 0.5rem; } textarea { padding: 0.5rem; } `; const Actions = styled.div` display: flex; gap: 0.5rem; justify-content: flex-end; `; interface CFBP { mode: ClipboardMode | undefined; label?: string; onDismiss: () => void; } interface ClipboardFallbackProps extends CFBP, Partial>, Partial< Omit >, Partial>, Partial< Omit > {} function throwError(props: ClipboardFallbackProps, prop: string) { throw new Error(`props.${prop} is mandatory with ${String(props.mode)} mode`); } function assertReadProps( props: ClipboardFallbackProps, ): asserts props is ClipboardFallbackReadProps { if (typeof props.onRead !== 'function') throwError(props, 'onRead'); } function assertReadTextProps( props: ClipboardFallbackProps, ): asserts props is ClipboardFallbackReadTextProps { if (typeof props.onReadText !== 'function') throwError(props, 'onReadText'); } function assertWriteProps( props: ClipboardFallbackProps, ): asserts props is ClipboardFallbackWriteProps { if (!props.file) throwError(props, 'file'); if (typeof props.onDismiss !== 'function') throwError(props, 'onDismiss'); } function assertWriteTextProps( props: ClipboardFallbackProps, ): asserts props is ClipboardFallbackWriteTextProps { if (typeof props.text !== 'string') throwError(props, 'text'); if (typeof props.onDismiss !== 'function') throwError(props, 'onDismiss'); } /** * switch between ClipboardFallback variant over mode props * mode === read => ClipboardFallbackReadProps * mode === readText => ClipboardFallbackReadTextProps * mode === write => ClipboardFallbackWriteProps * mode === writeText => ClipboardFallbackWriteTextProps * * implement what you need in function what part of the clipboard api from useClipboard you use * props will be checked at runtime * * @param props */ function ClipboardFallback(props: ClipboardFallbackProps) { switch (props.mode) { case 'read': assertReadProps(props); return ; case 'readText': assertReadTextProps(props); return ; case 'write': { assertWriteProps(props); return ; } case 'writeText': assertWriteTextProps(props); return ; default: return null; } } /** * return null if !props.mode * * @param props * @see ClipboardFallback */ export function ClipboardFallbackModal(props: ClipboardFallbackProps) { if (!props.mode) return null; const titles: Record = { read: `Import data from file`, readText: `Paste text from clipboard`, write: `Export data to file`, writeText: `Copy text from text area`, }; return ( ); } interface ClipboardFallbackReadProps extends CFBP { onRead: (file: File) => void; mode: 'read'; } function ClipboardFallbackRead(props: ClipboardFallbackReadProps) { const onFileRef = useRef(props.onRead); useEffect(() => { onFileRef.current = props.onRead; }); const onSubmit = useCallback((event: FormEvent) => { event.preventDefault(); const data = new FormData(event.currentTarget); const file = data.get('file'); if (!(file instanceof File)) return; onFileRef.current(file); }, []); if (props.mode !== 'read') return null; return (

We were not able to read from your clipboard. Please input your data in the file field

Submit Cancel
); } interface ClipboardFallbackReadTextProps extends CFBP { onReadText: (text: string) => void; mode: 'readText'; } function ClipboardFallbackReadText(props: ClipboardFallbackReadTextProps) { const onTextRef = useRef(props.onReadText); useEffect(() => { onTextRef.current = props.onReadText; }); const onSubmit = useCallback((event: FormEvent) => { event.preventDefault(); const data = new FormData(event.currentTarget); const text = data.get('text'); if (typeof text !== 'string') return; onTextRef.current(text); }, []); if (props.mode !== 'readText') return null; return ( ); }