/* * Copyright 2025 coze-dev Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import React, { type FC } from 'react'; import { isInteger, isNumber, isUndefined } from 'lodash-es'; import classNames from 'classnames'; import { type SliderProps } from '@coze-arch/bot-semi/Slider'; import { type CommonFieldProps } from '@coze-arch/bot-semi/Form'; import { withField, InputNumber, Slider } from '@coze-arch/bot-semi'; import { IconMinus, IconPlus } from '@douyinfe/semi-icons'; import { RCSliderWrapper, type RCSliderProps } from '../rc-slider-wrapper'; import s from './index.module.less'; interface InputSliderProps { value?: number; onChange?: (v: number) => void; max?: number; min?: number; step?: number; disabled?: boolean; decimalPlaces?: number; marks?: SliderProps['marks']; className?: string; /** Whether to use rc-slider to replace semi-slider? At present, there is an obvious bug in semi-slider. In the zoom scene, there is a problem with drag and drop positioning, which has been fed back and is waiting to be fixed. */ useRcSlider?: boolean; } const POWVAL = 10; const formateDecimalPlacesString = ( value: string | number, prevValue?: number, decimalPlaces?: number, ) => { if (isUndefined(decimalPlaces)) { return value.toString(); } const numberValue = Number(value); const stringValue = value.toString(); if (Number.isNaN(numberValue)) { return `${value}`; } if (decimalPlaces === 0 && !isInteger(Number(value)) && prevValue) { return `${prevValue}`; } const decimalPointIndex = stringValue.indexOf('.'); if (decimalPointIndex < 0) { return stringValue; } const formattedValue = stringValue.substring( 0, decimalPointIndex + 1 + decimalPlaces, ); if (formattedValue.endsWith('.') && decimalPlaces === 0) { return formattedValue.substring(0, formattedValue.length - 1); } return formattedValue; }; const formateDecimalPlacesNumber = ( value: number, prevValue?: number, decimalPlaces?: number, ) => { if (isUndefined(decimalPlaces)) { return value; } if (decimalPlaces === 0 && !isInteger(value) && prevValue) { return prevValue; } const pow = Math.pow(POWVAL, decimalPlaces); return Math.round(value * pow) / pow; }; const BaseInputSlider: React.FC = ({ value, onChange, max = 1, min = 0, step = 1, disabled, decimalPlaces, marks, className, useRcSlider = false, }) => { const onNumberChange = (numberValue: number) => { const formattedValue = formateDecimalPlacesNumber( numberValue, value, decimalPlaces, ); onChange?.(formattedValue); }; return (
{useRcSlider ? ( { if (typeof v === 'number') { onChange?.(v); } }} /> ) : ( { if (typeof v === 'number') { onChange?.(v); } }} /> )}
{ e.stopPropagation(); if (isNumber(value) && value <= min) { return; } if (!disabled && value !== undefined) { onNumberChange(value - step); } }} /> formateDecimalPlacesString(inputValue, value) } hideButtons onNumberChange={onNumberChange} max={max} min={min} /> { if (isNumber(value) && value >= max) { return; } e.stopPropagation(); if (!disabled && value !== undefined) { onNumberChange(value + step); } }} />
); }; export const InputSlider: FC = withField(BaseInputSlider);