import * as classNames from "classnames"; import * as React from "react"; import { Form, Input, InputProps } from "semantic-ui-react"; import { Duration } from "@common/Duration"; import "@client/styles/DurationView"; export interface DurationViewProps { label?: string; inline?: boolean; duration: Duration; onDurationChange?: (newDuration: Duration) => void; className?: string; } function roundOrString(val: number | string): number | string { if (typeof val === "number") { return Math.round(val); } else { return val; } } interface NumberInputProps { className?: string; label?: string; value: number; max?: number; onChange: (value: number) => void; } function NumberInput(props: NumberInputProps): React.ReactElement { const [valueState, setValueState] = React.useState(props.value); const [elementId, setElementId] = React.useState(() => `NumberInput-${Math.round(Math.random() * 100000000)}`); const [isWheelChange, setIsWheelChange] = React.useState(false); const onChange: InputProps["onChange"] = (_e, data) => { setValueState(data.value); const newValue = parseFloat(data.value); if (!isNaN(newValue) && data.value.length > 0 && isWheelChange) { props.onChange(Math.round(newValue)); setIsWheelChange(false); } }; const onBlur: React.FocusEventHandler = () => { const newValue = (typeof valueState === "number") ? valueState : parseFloat(valueState); if (!props.onChange || isNaN(newValue)) { return; } if (props.value !== newValue) { props.onChange(Math.round(newValue)); } }; const onWheel = (e: Event) => { // do nothing setIsWheelChange(true); }; React.useEffect(() => { const el = document.getElementById(elementId); if (el) { // Not passive events el.addEventListener("wheel", onWheel); } }); React.useEffect(() => { if (props.value !== valueState) { setValueState(props.value); } }, [props.value]); return } export default class DurationView extends React.Component { render() { const { duration, label, inline, onDurationChange, className } = this.props; const inputsClassName = classNames("durationInputs", { inline }); if (onDurationChange) { return ( {label && }
); } else { return ( {label && } {duration.minutes}M{" "} {duration.seconds}S ); } } componentWillReceiveProps(nextProps: Readonly) { if (nextProps.duration.minutes !== this.props.duration.minutes || nextProps.duration.seconds !== this.props.duration.seconds) { this.setState({ minutes: nextProps.duration.minutes, seconds: nextProps.duration.seconds, }); } } private onMinutesChange = (newMinutes: number) => { if (this.props.onDurationChange) { this.props.onDurationChange(this.props.duration.withMinutes(newMinutes)); } }; private onSecondsChange = (newSeconds: number) => { if (this.props.onDurationChange) { this.props.onDurationChange(this.props.duration.withSeconds(newSeconds)); } }; }