import { useMergeRefs } from '@floating-ui/react'; import { EMPTY_CELL } from '@scrabble-solver/constants'; import { type ChangeEventHandler, type FocusEventHandler, type FunctionComponent, type KeyboardEventHandler, type MouseEventHandler, type Ref, type TouchEventHandler, useCallback, useMemo, useRef, } from 'react'; import { useAppLayout } from 'hooks'; import { getTileSizes, noop } from 'lib'; import { selectLocale, useTypedSelector } from 'state'; import { TilePure } from './TilePure'; interface Props { 'aria-label': string; autoFocus?: boolean; character?: string; className?: string; disabled?: boolean; highlighted?: boolean; inputRef?: Ref; isBlank?: boolean; isValid?: boolean; placeholder?: string; points?: number; raised?: boolean; size: number; tabIndex?: number; onChange?: ChangeEventHandler; onFocus?: FocusEventHandler; onKeyDown?: KeyboardEventHandler; onMouseDown?: MouseEventHandler; onTouchStart?: TouchEventHandler; } export const Tile: FunctionComponent = ({ 'aria-label': ariaLabel, autoFocus, className, character = '', disabled, highlighted, inputRef, isBlank, isValid, placeholder, points, raised, size, tabIndex, onChange, onFocus = noop, onKeyDown = noop, onMouseDown = noop, onTouchStart = noop, }) => { const locale = useTypedSelector(selectLocale); const { showTilePoints } = useAppLayout(); const { pointsFontSize, tileSize } = getTileSizes(size); const style = useMemo(() => ({ height: tileSize, width: tileSize }), [tileSize]); const pointsStyle = useMemo(() => ({ fontSize: pointsFontSize }), [pointsFontSize]); const ref = useRef(null); const mergedRef = useMergeRefs(inputRef ? [ref, inputRef] : [ref]); const isEmpty = !character || character === EMPTY_CELL; const canShowPoints = showTilePoints && (!isEmpty || isBlank) && typeof points !== 'undefined'; const pointsFormatted = typeof points === 'number' ? points.toLocaleString(locale) : ''; const handleKeyDown: KeyboardEventHandler = useCallback( (event) => { ref.current?.select(); onKeyDown(event); }, [onKeyDown], ); return ( ); };