import type { NodeKey } from 'lexical'; import type { JSX } from 'react'; import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection'; import { mergeRegister } from '@lexical/utils'; import { $setSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, KEY_ESCAPE_COMMAND, SELECTION_CHANGE_COMMAND, } from 'lexical'; import { useCallback, useEffect, useMemo, useRef } from 'react'; import { getS3Url } from '../s3Config'; interface AudioComponentProps { nodeKey: NodeKey; src: string; fileKey?: string; uploadProgress?: number; uploadError?: string; } export default function AudioComponent({ nodeKey, src, fileKey, uploadProgress, uploadError, }: AudioComponentProps): JSX.Element { const [editor] = useLexicalComposerContext(); const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey); const containerRef = useRef(null); const audioRef = useRef(null); const resolvedSrc = useMemo(() => { if (fileKey) { return getS3Url(fileKey); } return src; }, [fileKey, src]); const isUploading = uploadProgress !== undefined && uploadProgress < 100 && !uploadError; const handleEscape = useCallback(() => { if (!isSelected) { return false; } $setSelection(null); editor.update(() => { setSelected(true); editor.getRootElement()?.focus(); }); return true; }, [editor, isSelected, setSelected]); const handleClick = useCallback( (event: MouseEvent) => { if (!containerRef.current) { return false; } if (containerRef.current.contains(event.target as Node)) { if (event.shiftKey) { setSelected(!isSelected); } else { clearSelection(); setSelected(true); } return true; } return false; }, [clearSelection, isSelected, setSelected], ); useEffect(() => { return mergeRegister( editor.registerCommand( SELECTION_CHANGE_COMMAND, () => false, COMMAND_PRIORITY_LOW, ), editor.registerCommand( CLICK_COMMAND, handleClick, COMMAND_PRIORITY_LOW, ), editor.registerCommand( KEY_ESCAPE_COMMAND, handleEscape, COMMAND_PRIORITY_LOW, ), ); }, [editor, handleClick, handleEscape]); const borderColor = uploadError ? 'rgba(244, 67, 54, 0.6)' : isSelected ? 'var(--accent-color, #4CAF50)' : 'var(--border-color, #ccc)'; return (
{ clearSelection(); setSelected(true); }} >
{resolvedSrc ? (
); }