import { FormControl, FormControlProps, FormLabel, FormLabelProps, HStack, NumberDecrementStepper, NumberIncrementStepper, NumberInput, NumberInputField, NumberInputFieldProps, NumberInputProps, NumberInputStepper, NumberInputStepperProps, Slider, SliderFilledTrack, SliderMark, SliderMarkProps, SliderThumb, SliderThumbProps, SliderTrack, SliderTrackProps, Tooltip, TooltipProps, } from '@chakra-ui/react'; import React, { FocusEvent, useMemo, useState, useEffect } from 'react'; import { BiReset } from 'react-icons/bi'; import IAIIconButton, { IAIIconButtonProps } from './IAIIconButton'; import _ from 'lodash'; export type IAIFullSliderProps = { label: string; value: number; min?: number; max?: number; step?: number; onChange: (v: number) => void; withSliderMarks?: boolean; sliderMarkLeftOffset?: number; sliderMarkRightOffset?: number; withInput?: boolean; isInteger?: boolean; width?: string | number; inputWidth?: string | number; inputReadOnly?: boolean; withReset?: boolean; handleReset?: () => void; isResetDisabled?: boolean; isSliderDisabled?: boolean; isInputDisabled?: boolean; tooltipSuffix?: string; hideTooltip?: boolean; isCompact?: boolean; styleClass?: string; sliderFormControlProps?: FormControlProps; sliderFormLabelProps?: FormLabelProps; sliderMarkProps?: Omit; sliderTrackProps?: SliderTrackProps; sliderThumbProps?: SliderThumbProps; sliderNumberInputProps?: NumberInputProps; sliderNumberInputFieldProps?: NumberInputFieldProps; sliderNumberInputStepperProps?: NumberInputStepperProps; sliderTooltipProps?: Omit; sliderIAIIconButtonProps?: IAIIconButtonProps; }; export default function IAISlider(props: IAIFullSliderProps) { const [showTooltip, setShowTooltip] = useState(false); const { label, value, min = 1, max = 100, step = 1, onChange, width = '100%', tooltipSuffix = '', withSliderMarks = false, sliderMarkLeftOffset = 0, sliderMarkRightOffset = -7, withInput = false, isInteger = false, inputWidth = '5.5rem', inputReadOnly = false, withReset = false, hideTooltip = false, isCompact = false, handleReset, isResetDisabled, isSliderDisabled, isInputDisabled, styleClass, sliderFormControlProps, sliderFormLabelProps, sliderMarkProps, sliderTrackProps, sliderThumbProps, sliderNumberInputProps, sliderNumberInputFieldProps, sliderNumberInputStepperProps, sliderTooltipProps, sliderIAIIconButtonProps, ...rest } = props; const [localInputValue, setLocalInputValue] = useState< string | number | undefined >(String(value)); useEffect(() => { setLocalInputValue(value); }, [value]); const numberInputMax = useMemo( () => (sliderNumberInputProps?.max ? sliderNumberInputProps.max : max), [max, sliderNumberInputProps?.max] ); const handleSliderChange = (v: number) => { onChange(v); }; const handleInputBlur = (e: FocusEvent) => { if (e.target.value === '') e.target.value = String(min); const clamped = _.clamp( isInteger ? Math.floor(Number(e.target.value)) : Number(localInputValue), min, numberInputMax ); onChange(clamped); }; const handleInputChange = (v: number | string) => { setLocalInputValue(v); }; const handleResetDisable = () => { if (!handleReset) return; handleReset(); }; return ( {label} setShowTooltip(true)} onMouseLeave={() => setShowTooltip(false)} focusThumbOnChange={false} isDisabled={isSliderDisabled} width={width} {...rest} > {withSliderMarks && ( <> {min} {max} )} {withInput && ( onChange(Number(localInputValue))} className="invokeai__slider-number-stepper" /> onChange(Number(localInputValue))} className="invokeai__slider-number-stepper" /> )} {withReset && ( } onClick={handleResetDisable} isDisabled={isResetDisabled} {...sliderIAIIconButtonProps} /> )} ); }