UNPKG

@coocoon/react-awesome-query-builder

Version:

User-friendly query builder for React. Demo: https://ukrbublik.github.io/react-awesome-query-builder

178 lines (159 loc) 4.63 kB
import React, { useEffect } from "react"; import Slider from "@mui/material/Slider"; import TextField from "@mui/material/TextField"; import FormControl from "@mui/material/FormControl"; export default (props) => { const {config, placeholders, customProps, value, setValue, min, max, step, marks, readonly, textSeparators} = props; const {defaultSliderWidth} = config.settings; useEffect(() => { const [valueFrom, valueTo] = props.value || [undefined, undefined]; if (props.value && (valueFrom == undefined || valueTo == undefined)) { // happens if we changed op from '==' to 'between' // (I know, timeout is dirty hack..) setTimeout(() => { const oneValue = valueFrom || valueTo; const value = [oneValue, oneValue]; setValue(value); }, 1); } }, []); const handleSliderChange = (_e, newValues) => { setValue(newValues); }; const handleInputChangeFrom = (e) => { // TIP: need to use props.value instead of value let valueFrom = e.target.value; if (valueFrom === "" || valueFrom == null) valueFrom = undefined; else valueFrom = Number(valueFrom); let value = props.value ? [...props.value] : [undefined, undefined]; value[0] = valueFrom; setValue(value); }; const handleInputChangeTo = (e) => { let valueTo = e.target.value; if (valueTo === "" || valueTo == null) valueTo = undefined; else valueTo = Number(valueTo); let value = props.value ? [...props.value] : [undefined, undefined]; value[1] = valueTo; setValue(value); }; const handleInputBlur = () => { // TIP: Fix if typed value out of range in inputs if (!value) return; if (value[0] < min) { setValue([min, value[1]]); } else if (value[1] > max) { setValue([value[0], max]); } }; const {width, ...rest} = customProps || {}; const customInputProps = rest.input || {}; const customSliderProps = rest.slider || rest; // marks example: { 0: "0%", 100: React.createElement('strong', null, "100%") } const muiMarks = marks ? Object.keys(marks).map(v => ({ value: Number(v), label: typeof marks[v] === "object" || typeof marks[v] === "undefined" ? marks[v] : <p>{marks[v]}</p> })) : false; // TIP: Can't pass undefined to MUI, cause it means uncontrolled component use. // For empty value input needs "", slider needs null or 0, but null will cause problems with range mode let sliderValue = value ? [...value] : [undefined, undefined]; let [valueFrom, valueTo] = sliderValue; if (valueFrom == undefined) { valueFrom = ""; sliderValue[0] = 0; } if (valueTo == undefined) { valueTo = ""; sliderValue[1] = 0; } const FromInputCmp = ( <TextField variant="standard" type="number" value={valueFrom} placeholder={placeholders[0]} InputProps={{ readOnly: readonly, }} inputProps={{ min: min, max: max, step: step, }} disabled={readonly} onChange={handleInputChangeFrom} onBlur={handleInputBlur} size="small" {...customInputProps} /> ); const ToInputCmp = ( <TextField variant="standard" type="number" value={valueTo} placeholder={placeholders[1]} InputProps={{ readOnly: readonly, }} inputProps={{ min: min, max: max, step: step, }} disabled={readonly} onChange={handleInputChangeTo} onBlur={handleInputBlur} size="small" {...customInputProps} /> ); const SliderCmp = ( <Slider value={sliderValue} onChange={handleSliderChange} disabled={readonly} min={min} max={max} step={step} marks={muiMarks} valueLabelDisplay="auto" size="small" {...customSliderProps} /> ); const stylesWrapper = { display: "inline-flex", }; const stylesInputWrapper = { marginLeft: "5px", }; const stylesSliderWrapper = { marginLeft: "5px", paddingLeft: "12px", marginBottom: muiMarks && "-16px", width: width || defaultSliderWidth, }; return ( <FormControl> <div style={stylesWrapper}> <div style={stylesInputWrapper}> {FromInputCmp} </div> <div className={"widget--sep"}> <span>{ textSeparators[1] }</span> </div> <div style={stylesInputWrapper}> {ToInputCmp} </div> <div style={stylesSliderWrapper}> {SliderCmp} </div> </div> </FormControl> ); };