import { useMemo, useCallback } from 'react'; import { OptionTypes } from 'librechat-data-provider'; import type { DynamicSettingProps } from 'librechat-data-provider'; import { Label, Slider, HoverCard, Input, InputNumber, HoverCardTrigger } from '~/components/ui'; import { useLocalize, useDebouncedInput, useParameterEffects, TranslationKeys } from '~/hooks'; import { cn, defaultTextProps, optionText } from '~/utils'; import { ESide, defaultDebouncedDelay } from '~/common'; import { useChatContext } from '~/Providers'; import OptionHover from './OptionHover'; function DynamicSlider({ label = '', settingKey, defaultValue, range, description = '', columnSpan, setOption, optionType, options, enumMappings, readonly = false, showDefault = false, includeInput = true, labelCode = false, descriptionCode = false, conversation, }: DynamicSettingProps) { const localize = useLocalize(); const { preset } = useChatContext(); const isEnum = useMemo( () => (!range && options && options.length > 0) ?? false, [options, range], ); const [setInputValue, inputValue, setLocalValue] = useDebouncedInput({ optionKey: settingKey, initialValue: optionType !== OptionTypes.Custom ? conversation?.[settingKey] : defaultValue, setter: () => ({}), setOption, delay: isEnum ? 0 : defaultDebouncedDelay, }); useParameterEffects({ preset, settingKey, defaultValue, conversation, inputValue, setInputValue: setLocalValue, }); const selectedValue = useMemo(() => { if (isEnum) { return conversation?.[settingKey] ?? defaultValue; } // TODO: custom logic, add to payload but not to conversation return inputValue; }, [conversation, defaultValue, settingKey, inputValue, isEnum]); const enumToNumeric = useMemo(() => { if (isEnum && options) { return options.reduce( (acc, mapping, index) => { acc[mapping] = index; return acc; }, {} as Record, ); } return {}; }, [isEnum, options]); const valueToEnumOption = useMemo(() => { if (isEnum && options) { return options.reduce( (acc, option, index) => { acc[index] = option; return acc; }, {} as Record, ); } return {}; }, [isEnum, options]); const getDisplayValue = useCallback( (value: string | number | undefined | null): string => { if (isEnum && enumMappings && value != null) { const stringValue = String(value); // Check if the value exists in enumMappings if (stringValue in enumMappings) { const mappedValue = String(enumMappings[stringValue]); // Check if the mapped value is a localization key if (mappedValue.startsWith('com_')) { return localize(mappedValue as TranslationKeys) ?? mappedValue; } return mappedValue; } } // Always return a string for Input component compatibility if (value != null) { return String(value); } return String(defaultValue ?? ''); }, [isEnum, enumMappings, defaultValue, localize], ); const getDefaultDisplayValue = useCallback((): string => { if (defaultValue != null && enumMappings) { const stringDefault = String(defaultValue); if (stringDefault in enumMappings) { const mappedValue = String(enumMappings[stringDefault]); // Check if the mapped value is a localization key if (mappedValue.startsWith('com_')) { return localize(mappedValue as TranslationKeys) ?? mappedValue; } return mappedValue; } } return String(defaultValue ?? ''); }, [defaultValue, enumMappings, localize]); const handleValueChange = useCallback( (value: number) => { if (isEnum) { setInputValue(valueToEnumOption[value]); } else { setInputValue(value); } }, [isEnum, setInputValue, valueToEnumOption], ); const max = useMemo(() => { if (isEnum && options) { return options.length - 1; } else if (range) { return range.max; } else { return 0; } }, [isEnum, options, range]); if (!range && !isEnum) { return null; } return (
{includeInput && !isEnum ? ( setInputValue(Number(value))} max={range ? range.max : (options?.length ?? 0) - 1} min={range ? range.min : 0} step={range ? (range.step ?? 1) : 1} controls={false} className={cn( defaultTextProps, cn( optionText, 'reset-rc-number-input reset-rc-number-input-text-right h-auto w-12 border-0 py-1 text-xs group-hover/temp:border-gray-200', ), )} /> ) : ( ({})} className={cn( defaultTextProps, cn( optionText, 'reset-rc-number-input h-auto w-14 border-0 py-1 pl-1 text-center text-xs group-hover/temp:border-gray-200', ), )} /> )}
handleValueChange(value[0])} onDoubleClick={() => setInputValue(defaultValue as string | number)} max={max} min={range ? range.min : 0} step={range ? (range.step ?? 1) : 1} className="flex h-4 w-full" />
{description && ( )}
); } export default DynamicSlider;