feat: Add base project structure with API and web components
This commit is contained in:
107
web/src/components/SliderInput/index.tsx
Normal file
107
web/src/components/SliderInput/index.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import { useState, useEffect, type FC } from 'react';
|
||||
import { Slider, InputNumber, Row, Col } from 'antd';
|
||||
|
||||
interface SliderInputProps {
|
||||
value?: number;
|
||||
onChange?: (value: number | null) => void;
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
defaultValue?: number;
|
||||
disabled?: boolean;
|
||||
label?: string;
|
||||
className?: string;
|
||||
sliderClassName?: string;
|
||||
inputClassName?: string;
|
||||
marks?: Record<number, string | { style: React.CSSProperties; label: string }>;
|
||||
tooltip?: {
|
||||
open?: boolean;
|
||||
placement?: 'top' | 'left' | 'right' | 'bottom';
|
||||
formatter?: (value?: number) => React.ReactNode;
|
||||
};
|
||||
}
|
||||
|
||||
const SliderInput: FC<SliderInputProps> = ({
|
||||
value,
|
||||
onChange,
|
||||
min = 0,
|
||||
max = 100,
|
||||
step = 1,
|
||||
defaultValue = 0,
|
||||
disabled = false,
|
||||
label,
|
||||
className = '',
|
||||
sliderClassName = '',
|
||||
inputClassName = '',
|
||||
marks,
|
||||
tooltip,
|
||||
}) => {
|
||||
const [internalValue, setInternalValue] = useState<number>(value ?? defaultValue);
|
||||
|
||||
useEffect(() => {
|
||||
if (value !== undefined && value !== internalValue) {
|
||||
setInternalValue(value);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const handleSliderChange = (newValue: number) => {
|
||||
setInternalValue(newValue);
|
||||
onChange?.(newValue);
|
||||
};
|
||||
|
||||
const handleInputChange = (newValue: number | null) => {
|
||||
if (newValue === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保值在范围内
|
||||
let validValue = newValue;
|
||||
if (newValue < min) {
|
||||
validValue = min;
|
||||
} else if (newValue > max) {
|
||||
validValue = max;
|
||||
}
|
||||
|
||||
setInternalValue(validValue);
|
||||
onChange?.(validValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`rb:w-full ${className}`}>
|
||||
{label && (
|
||||
<div className="rb:text-sm rb:font-medium rb:text-gray-700">
|
||||
{label}
|
||||
</div>
|
||||
)}
|
||||
<Row gutter={16} align="middle">
|
||||
<Col flex="auto">
|
||||
<Slider
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
value={internalValue}
|
||||
onChange={handleSliderChange}
|
||||
disabled={disabled}
|
||||
marks={marks}
|
||||
tooltip={tooltip}
|
||||
className={sliderClassName}
|
||||
/>
|
||||
</Col>
|
||||
<Col flex="120px">
|
||||
<InputNumber
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
value={internalValue}
|
||||
onChange={handleInputChange}
|
||||
disabled={disabled}
|
||||
className={`rb:w-full ${inputClassName}`}
|
||||
controls
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SliderInput;
|
||||
Reference in New Issue
Block a user