import { forwardRef, useImperativeHandle, useRef, useState } from 'react'; import classnames from 'classnames'; import styles from './InternalIconButton.css'; import Flex from '../Flex'; import icons from '../icons/index'; import InternalPog from '../Pog/InternalPog'; import touchableStyles from '../TapArea.css'; import TextUI from '../TextUI'; import Tooltip from '../Tooltip'; import useFocusVisible from '../useFocusVisible'; import useTapFeedback from '../useTapFeedback'; import useExperimentalTheme from '../utils/useExperimentalTheme'; import { Indexable } from '../zIndex'; type Props = { accessibilityLabel: string; accessibilityControls?: string; accessibilityExpanded?: boolean; accessibilityHaspopup?: boolean; accessibilityPopupRole?: 'menu' | 'dialog'; focusColor?: 'lightBackground' | 'darkBackground'; bgColor?: | 'transparent' | 'transparentDarkBackground' | 'transparentDarkGray' | 'gray' | 'lightGray' | 'washLight' | 'white' | 'red' | 'elevation'; dangerouslySetSvgPath?: { __path: string; }; dataTestId?: string; disabled?: boolean; icon?: keyof typeof icons; iconColor?: 'gray' | 'darkGray' | 'red' | 'white' | 'brandPrimary' | 'light' | 'dark'; label?: string; name?: string; onClick?: (arg1: { event: React.MouseEvent | React.KeyboardEvent; }) => void; padding?: 1 | 2 | 3 | 4 | 5; // eslint-disable-next-line react/no-unused-prop-types ref?: HTMLButtonElement; selected?: boolean; size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 56; tabIndex?: -1 | 0; tooltip?: { accessibilityLabel?: string; inline?: boolean; idealDirection?: 'up' | 'right' | 'down' | 'left'; text: string; zIndex?: Indexable; }; type?: 'submit' | 'button'; }; const InternalIconButtonWithForwardRef = forwardRef(function IconButton( { accessibilityControls, accessibilityExpanded, accessibilityHaspopup, accessibilityLabel, accessibilityPopupRole, bgColor, focusColor = 'lightBackground', dangerouslySetSvgPath, dataTestId, disabled, icon, iconColor, label, name, onClick, padding, selected, size = 'lg', tabIndex = 0, tooltip, type, }: Props, ref, ) { const innerRef = useRef(null); // When using both forwardRef and innerRef, React.useimperativehandle() allows a parent component // that renders to call inputRef.current.focus() // @ts-expect-error - TS2322 - Type 'HTMLButtonElement | null' is not assignable to type 'HTMLButtonElement'. useImperativeHandle(ref, () => innerRef.current); const theme = useExperimentalTheme(); const { compressStyle, isTapping, handleBlur, handleMouseDown, handleMouseUp, handleTouchStart, handleTouchMove, handleTouchCancel, handleTouchEnd, } = useTapFeedback({ height: innerRef?.current?.clientHeight, width: innerRef?.current?.clientWidth, }); const [isActive, setActive] = useState(false); const [isFocused, setFocused] = useState(false); const [isHovered, setHovered] = useState(false); const { isFocusVisible } = useFocusVisible(); let labelColor: 'default' | 'disabled' | 'inverse' = 'default'; if (disabled) { labelColor = 'disabled'; } else if (bgColor === 'transparentDarkBackground' && iconColor === 'white') { labelColor = 'inverse'; } const labelStyle = classnames(styles.label, { [styles.activeText]: isActive && !isHovered, [styles.hoverText]: isHovered && !isActive, }); const divStyles = classnames(styles.button, touchableStyles.tapTransition, { [styles.disabled]: disabled && !theme.MAIN, [styles.disabledVr]: disabled && theme.MAIN, [styles.enabled]: !disabled, [touchableStyles.tapCompress]: !disabled && isTapping, }); const buttonComponent = ( ); const labelComponent = (
{label}
); const buttonWithTooltip = tooltip?.text ? ( {buttonComponent} ) : ( buttonComponent ); return label && size === 'xl' ? ( {buttonWithTooltip} {labelComponent} ) : ( buttonWithTooltip ); }); InternalIconButtonWithForwardRef.displayName = 'IconButton'; export default InternalIconButtonWithForwardRef;