import {useEffect, useMemo, useRef, useState} from 'react'; import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; import {motion} from 'framer-motion'; import {GrowingInput} from 'sentry/components/growingInput'; import {Tooltip} from 'sentry/components/tooltip'; interface EditableTabTitleProps { isEditing: boolean; isSelected: boolean; label: string; onChange: (newLabel: string) => void; setIsEditing: (isEditing: boolean) => void; } function EditableTabTitle({ label, onChange, isEditing, isSelected, setIsEditing, }: EditableTabTitleProps) { const [inputValue, setInputValue] = useState(label); useEffect(() => { setInputValue(label); }, [label]); const theme = useTheme(); const inputRef = useRef(null); const isEmpty = !inputValue.trim(); const memoizedStyles = useMemo(() => { return {fontWeight: isSelected ? theme.fontWeightBold : theme.fontWeightNormal}; }, [isSelected, theme.fontWeightBold, theme.fontWeightNormal]); const handleOnBlur = (e: React.FocusEvent) => { e.stopPropagation(); e.preventDefault(); const trimmedInputValue = inputValue.trim(); if (!isEditing) { return; } if (isEmpty) { setInputValue(label); setIsEditing(false); return; } if (trimmedInputValue !== label) { onChange(trimmedInputValue); setInputValue(trimmedInputValue); } setIsEditing(false); }; const handleOnKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { inputRef.current?.blur(); } if (e.key === 'Escape') { setInputValue(label.trim()); setIsEditing(false); } if (e.key === 'ArrowLeft' || e.key === 'ArrowRight' || e.key === ' ') { e.stopPropagation(); } }; useEffect(() => { if (isEditing) { requestAnimationFrame(() => { inputRef.current?.focus(); inputRef.current?.select(); }); } else { inputRef.current?.blur(); } }, [isEditing, inputRef]); const handleOnChange = (e: React.ChangeEvent) => { setInputValue(e.target.value); }; return ( {isSelected && isEditing ? ( { e.stopPropagation(); if (!isEditing) { e.preventDefault(); } }} onMouseDown={e => { e.stopPropagation(); if (!isEditing) { e.preventDefault(); } }} /> ) : ( setIsEditing(true)} onPointerDown={e => { if (isSelected) { e.stopPropagation(); e.preventDefault(); } }} onMouseDown={e => { if (isSelected) { e.stopPropagation(); e.preventDefault(); } }} isSelected={isSelected} > {label} )} ); } export default EditableTabTitle; const UnselectedTabTitle = styled('div')<{isSelected: boolean}>` height: 20px; max-width: ${p => (p.isSelected ? '325px' : '310px')}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding-right: 1px; cursor: pointer; `; const StyledGrowingInput = styled(GrowingInput)<{ isEditing: boolean; }>` position: relative; border: none; margin: 0; padding: 0; background: transparent; min-height: 0px; height: 20px; border-radius: 0px; text-overflow: ellipsis; cursor: text; max-width: 325px; &, &:focus, &:active, &:hover { box-shadow: none; } `;