import React from "react"; import { HelperUtils } from "@dndbeyond/character-rules-engine/es"; import { ThemeButton } from "../common/Button"; interface Props { quantity: number; minimum: number; maximum: number | null; label: string; onUpdate?: (quantity: number) => void; isReadonly: boolean; } interface State { quantity: number; newQuantity: number | null; } export default class SimpleQuantity extends React.PureComponent { static defaultProps = { label: "Quantity", minimum: 0, maximum: null, isReadonly: false, }; constructor(props) { super(props); this.state = { quantity: props.quantity, newQuantity: props.quantity, }; } componentDidUpdate( prevProps: Readonly, prevState: Readonly, snapshot?: any ): void { const { quantity } = this.props; if (quantity !== prevState.quantity) { this.setState({ quantity, newQuantity: quantity, }); } } handleUpdate = (): void => { const { newQuantity } = this.state; const { onUpdate, quantity } = this.props; if (newQuantity !== quantity && onUpdate) { onUpdate(newQuantity === null ? 0 : newQuantity); } }; handleAmountChange = (evt: React.ChangeEvent): void => { this.setState({ newQuantity: HelperUtils.parseInputInt(evt.target.value, null), }); }; handleAmountKeyUp = (evt: React.KeyboardEvent): void => { const { minimum, maximum } = this.props; if (evt.key === "Enter") { const parsedValue = HelperUtils.parseInputInt( (evt.target as HTMLInputElement).value ); const clampedValue = HelperUtils.clampInt( parsedValue ?? minimum, minimum, maximum ); this.setState( { quantity: clampedValue, newQuantity: clampedValue, }, this.handleUpdate ); } }; handleAmountBlur = (evt: React.FocusEvent): void => { const { minimum, maximum } = this.props; const parsedValue = HelperUtils.parseInputInt(evt.target.value); const clampedValue = HelperUtils.clampInt( parsedValue ?? minimum, minimum, maximum ); this.setState( { quantity: clampedValue, newQuantity: clampedValue, }, this.handleUpdate ); }; handleIncrementClick = () => { const { quantity, isReadonly } = this.props; if (!isReadonly) { let newValue: number = quantity + 1; this.setState( { quantity: newValue, newQuantity: newValue, }, this.handleUpdate ); } }; handleDecrementClick = () => { const { quantity, isReadonly } = this.props; if (!isReadonly) { let newValue: number = quantity - 1; this.setState( { quantity: newValue, newQuantity: newValue, }, this.handleUpdate ); } }; render() { const { newQuantity } = this.state; const { label, quantity, minimum, maximum, isReadonly } = this.props; return (
{label}
= maximum} isInteractive={!isReadonly} aria-label={"increase quantity"} data-testid={"increase-quantity"} />
); } }