import { TLFrameShape, TLShapeId, useEditor, useValue } from '@tldraw/editor' import { forwardRef, useCallback, useEffect, useRef } from 'react' import { PORTRAIT_BREAKPOINT } from '../../../ui/constants' import { useBreakpoint } from '../../../ui/context/breakpoints' import { useTranslation } from '../../../ui/hooks/useTranslation/useTranslation' import { defaultEmptyAs } from '../frameHelpers' export const FrameLabelInput = forwardRef< HTMLInputElement, { id: TLShapeId; name: string; isEditing: boolean } >(({ id, name, isEditing }, ref) => { const editor = useEditor() const breakpoint = useBreakpoint() const isCoarsePointer = useValue( 'isCoarsePointer', () => editor.getInstanceState().isCoarsePointer, [editor] ) const shouldUseWindowPrompt = breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM && isCoarsePointer const promptOpen = useRef(false) const msg = useTranslation() const handlePointerDown = useCallback( (e: React.PointerEvent) => { if (isEditing) editor.markEventAsHandled(e) }, [editor, isEditing] ) const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.nativeEvent.isComposing) { // need to prevent the enter keydown making it's way up to the Idle state // and sending us back into edit mode editor.markEventAsHandled(e) e.currentTarget.blur() editor.setEditingShape(null) } }, [editor] ) const renameFrame = useCallback( (value: string) => { const shape = editor.getShape(id) if (!shape) return const name = shape.props.name if (name === value) return editor.updateShapes([ { id, type: 'frame', props: { name: value }, }, ]) }, [id, editor] ) const handleBlur = useCallback( (e: React.FocusEvent) => { renameFrame(e.currentTarget.value) }, [renameFrame] ) const handleChange = useCallback( (e: React.ChangeEvent) => { renameFrame(e.currentTarget.value) }, [renameFrame] ) /* Mobile rename uses window.prompt */ useEffect(() => { if (!isEditing) { promptOpen.current = false return } if (isEditing && shouldUseWindowPrompt && !promptOpen.current) { promptOpen.current = true const shape = editor.getShape(id) const currentName = shape?.props.name ?? '' const newName = window.prompt(msg('action.rename'), currentName) promptOpen.current = false if (newName !== null) renameFrame(newName) editor.setEditingShape(null) } }, [isEditing, shouldUseWindowPrompt, id, msg, renameFrame, editor]) return (
{defaultEmptyAs(name, 'Frame') + String.fromCharCode(8203)}
) })