import React, { Component } from 'react'; import Tooltip from '../../../base/tooltip/components/Tooltip'; import { TOOLTIP_POSITION } from '../../../base/ui/constants.any'; /** * The type of the React {@code Component} props of {@link ReactionButton}. */ interface IProps { /** * A succinct description of what the button does. Used by accessibility * tools and torture tests. */ accessibilityLabel: string; /** * The Icon of this {@code AbstractToolbarButton}. */ icon: Object; /** * The style of the Icon of this {@code AbstractToolbarButton}. */ iconStyle?: Object; /** * Optional label for the button. */ label?: string; /** * On click handler. */ onClick: Function; /** * {@code AbstractToolbarButton} Styles. */ style?: Array | Object; /** * An optional modifier to render the button toggled. */ toggled?: boolean; /** * Optional text to display in the tooltip. */ tooltip?: string; /** * From which direction the tooltip should appear, relative to the * button. */ tooltipPosition: TOOLTIP_POSITION; /** * The color underlying the button. */ underlayColor?: any; } /** * The type of the React {@code Component} state of {@link ReactionButton}. */ interface IState { /** * Used to determine zoom level on reaction burst. */ increaseLevel: number; /** * Timeout ID to reset reaction burst. */ increaseTimeout: number | null; } /** * Represents a button in the reactions menu. * * @augments AbstractToolbarButton */ class ReactionButton extends Component { /** * Default values for {@code ReactionButton} component's properties. * * @static */ static defaultProps = { tooltipPosition: 'top' }; /** * Initializes a new {@code ReactionButton} instance. * * @inheritdoc */ constructor(props: IProps) { super(props); this._onKeyDown = this._onKeyDown.bind(this); this._onClickHandler = this._onClickHandler.bind(this); this._onClick = this._onClick.bind(this); this.state = { increaseLevel: 0, increaseTimeout: null }; } /** * Handles clicking/pressing this {@code AbstractToolbarButton} by * forwarding the event to the {@code onClick} prop of this instance if any. * * @protected * @returns {*} The result returned by the invocation of the {@code onClick} * prop of this instance if any. */ _onClick(...args: any) { const { onClick } = this.props; return onClick?.(...args); } /** * Handles 'Enter' key on the button to trigger onClick for accessibility. * We should be handling Space onKeyUp but it conflicts with PTT. * * @param {Object} event - The key event. * @private * @returns {void} */ _onKeyDown(event: React.KeyboardEvent) { // If the event coming to the dialog has been subject to preventDefault // we don't handle it here. if (event.defaultPrevented) { return; } if (event.key === 'Enter') { event.preventDefault(); event.stopPropagation(); this.props.onClick(); } } /** * Handles reaction button click. * * @param {Event} event - The click event. * @returns {void} */ _onClickHandler(event: any) { event.preventDefault(); event.stopPropagation(); this.props.onClick(); clearTimeout(this.state.increaseTimeout ?? 0); const timeout = window.setTimeout(() => { this.setState({ increaseLevel: 0 }); }, 500); this.setState(state => { return { increaseLevel: state.increaseLevel + 1, increaseTimeout: timeout }; }); } /** * Renders the button of this {@code ReactionButton}. * * @param {Object} children - The children, if any, to be rendered inside * the button. Presumably, contains the emoji of this {@code ReactionButton}. * @protected * @returns {ReactElement} The button of this {@code ReactionButton}. */ _renderButton(children: React.ReactElement) { return (
{ this.props.tooltip ? { children } : children }
); } /** * Renders the icon (emoji) of this {@code reactionButton}. * * @inheritdoc */ _renderIcon() { const { toggled, icon, label } = this.props; const { increaseLevel } = this.state; return (
12 ? 12 : increaseLevel}` }>{icon} {label && {label}}
); } /** * Implements React's {@link Component#render()}. * * @inheritdoc * @returns {ReactElement} */ override render() { return this._renderButton(this._renderIcon()); } } export default ReactionButton;