import { useState } from 'react'; import { Box, inputLabelClasses as muiInputLabelClasses, OutlinedInputProps as MUIOutlinedInputProps, outlinedInputClasses as muiOutlinedInputClasses, Slider as MUISlider, sliderClasses as muiSliderClasses, SliderProps as MUISliderProps, FormControl, } from '@mui/material'; import { BORDER_RADIUS, GREY } from '../lib/consts/DEFAULT_THEME'; import InputMessageBox from './InputMessageBox'; import { MessageBoxProps } from './MessageBox'; import OutlinedInput from './OutlinedInput'; import OutlinedInputLabel, { OutlinedInputLabelProps, } from './OutlinedInputLabel'; import { BodyText } from './Text'; type SliderOnBlur = Exclude; type SliderOnChange = Exclude; type SliderOnFocus = Exclude; type SliderValue = Exclude; type SliderOptionalProps = { inputLabelProps?: Partial; isAllowTextInput?: boolean; labelId?: string; messageBoxProps?: Partial; sliderProps?: Omit & { onChange?: (value: number | number[]) => void; }; }; type SliderProps = { label: string; value: SliderValue; } & SliderOptionalProps; type TextInputOnChange = Exclude; const SLIDER_DEFAULT_PROPS: Required = { inputLabelProps: {}, isAllowTextInput: false, labelId: '', messageBoxProps: {}, sliderProps: {}, }; const createInputLabelDecorator = ({ isFocused, label, }: { isFocused?: boolean; label: string; }) => { const borderColor = GREY; const borderStyle = 'solid'; const content = '""'; let rootTop = '0'; let labelGapMargin = '0 .6em 0 .4em'; let borderWidth = '1px 0 0 0'; let opacity = '0.3'; if (isFocused) { rootTop = '-1px'; labelGapMargin = '0 1em 0 1em'; borderWidth = '2px 0 0 0'; opacity = '1'; } return ( :last-child': { flexGrow: 1, }, }} > ); }; const createOutlinedInput = ({ isFocused, max, min, onBlur, onChange, onFocus, sliderValue, sx, }: { isFocused?: boolean; max?: number; min?: number; onBlur?: SliderOnBlur; onChange?: TextInputOnChange; onFocus?: SliderOnFocus; sliderValue?: SliderValue; sx?: MUISliderProps['sx']; }) => ( ); const Slider = ({ messageBoxProps = SLIDER_DEFAULT_PROPS.messageBoxProps, isAllowTextInput = SLIDER_DEFAULT_PROPS.isAllowTextInput, label, labelId = SLIDER_DEFAULT_PROPS.labelId, inputLabelProps = SLIDER_DEFAULT_PROPS.inputLabelProps, sliderProps = SLIDER_DEFAULT_PROPS.sliderProps, value, }: SliderProps): JSX.Element => { const { max, min, onChange: sliderChangeCallback, sx: sliderSx, valueLabelDisplay: sliderValueLabelDisplay, } = sliderProps; const [isFocused, setIsFocused] = useState(false); const handleLocalSliderBlur: SliderOnBlur = () => { setIsFocused(false); }; const handleLocalSliderFocus: SliderOnFocus = () => { setIsFocused(true); }; const handleSliderChange: SliderOnChange = (event, newValue) => { sliderChangeCallback?.call(null, newValue); }; const handleTextInputChange: TextInputOnChange = ({ target: { value: newValue }, }) => { sliderChangeCallback?.call(null, parseFloat(newValue)); }; return ( {label} {createInputLabelDecorator({ isFocused, label })} :first-child': { flexGrow: 1 }, }} > {createOutlinedInput({ isFocused, max, min, onBlur: handleLocalSliderBlur, onChange: handleTextInputChange, onFocus: handleLocalSliderFocus, sliderValue: value, sx: isAllowTextInput ? undefined : { visibility: 'collapse', }, })} {/* eslint-disable-next-line react/jsx-props-no-spreading */} ); }; Slider.defaultProps = SLIDER_DEFAULT_PROPS; export type { SliderProps }; export default Slider;