Skip to content

Commit 52c7208

Browse files
author
刘欢
committed
feat: add onDisabledChange callback to sync disabled handles in editable mode
1 parent 0667d6f commit 52c7208

3 files changed

Lines changed: 109 additions & 2 deletions

File tree

docs/examples/disabled-handle.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const EditableWithDisabled = () => {
2424
value={value}
2525
onChange={(v) => setValue(v as number[])}
2626
disabled={disabled}
27+
onDisabledChange={setDisabled}
2728
/>
2829
<div style={{ marginTop: 16 }}>
2930
{value.map((val, index) => (
@@ -90,8 +91,28 @@ const DisabledHandleAsBoundary = () => {
9091
);
9192
};
9293

94+
const SingleSlider = () => {
95+
const [value1, setValue1] = useState(30);
96+
const [value2, setValue2] = useState(30);
97+
98+
return (
99+
<div>
100+
<Slider value={value1} onChange={(v) => setValue1(v as number)} disabled />
101+
<br/>
102+
<Slider value={value2} onChange={(v) => setValue2(v as number)} disabled={false} />
103+
</div>
104+
);
105+
}
106+
93107
export default () => (
94108
<div>
109+
<div>
110+
single handle disabled
111+
<SingleSlider />
112+
</div>
113+
<div>
114+
115+
</div>
95116
<div style={style}>
96117
<h3>Disabled Handle + Draggable Track</h3>
97118
<p>Toggle checkboxes to disable/enable specific handles. Drag the track area to move the range.</p>

src/Slider.tsx

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ export interface SliderProps<ValueType = number | number[]> {
7878
/** @deprecated Use `onChangeComplete` instead */
7979
onAfterChange?: (value: ValueType) => void;
8080
onChangeComplete?: (value: ValueType) => void;
81+
/** Callback when disabled array needs to be updated (e.g., when handles are added/removed in editable mode) */
82+
onDisabledChange?: (disabled: boolean[]) => void;
8183

8284
// Cross
8385
allowCross?: boolean;
@@ -149,6 +151,7 @@ const Slider = React.forwardRef<SliderRef, SliderProps<number | number[]>>((prop
149151
onBeforeChange,
150152
onAfterChange,
151153
onChangeComplete,
154+
onDisabledChange,
152155

153156
// Cross
154157
allowCross = true,
@@ -191,9 +194,12 @@ const Slider = React.forwardRef<SliderRef, SliderProps<number | number[]>>((prop
191194
const disabled = React.useMemo(() => {
192195
if (typeof rawDisabled === 'boolean') {
193196
return rawDisabled;
194-
};
197+
}
198+
if (Array.isArray(value)) {
199+
return value.every((_, index) => rawDisabled[index]);
200+
}
195201

196-
return Array.isArray(value) && value.length === rawDisabled.length && rawDisabled.every(Boolean);
202+
return false;
197203
}, [rawDisabled, value]);
198204

199205
const isHandleDisabled = React.useCallback(
@@ -315,6 +321,25 @@ const Slider = React.forwardRef<SliderRef, SliderProps<number | number[]>>((prop
315321
// Order first
316322
const cloneNextValues = [...nextValues].sort((a, b) => a - b);
317323

324+
// Sync disabled array when values length changes (add/remove handles in editable mode)
325+
if (
326+
typeof rawDisabled !== 'boolean' &&
327+
Array.isArray(rawDisabled) &&
328+
cloneNextValues.length !== rawValues.length
329+
) {
330+
const newDisabled = [...rawDisabled];
331+
332+
if (cloneNextValues.length > rawValues.length) {
333+
const index = cloneNextValues.findIndex((item) => !rawValues.includes(item));
334+
newDisabled.splice(index, 0, false);
335+
} else if (cloneNextValues.length < rawValues.length) {
336+
const index = rawValues.findIndex((item) => !cloneNextValues.includes(item));
337+
newDisabled.splice(index, 1);
338+
}
339+
340+
onDisabledChange?.(newDisabled);
341+
}
342+
318343
// Trigger event if needed
319344
if (onChange && !isEqual(cloneNextValues, rawValues, true)) {
320345
onChange(getTriggerValue(cloneNextValues));

tests/Range.test.tsx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,5 +1003,66 @@ describe('Range', () => {
10031003
// Should not trigger onChange because all handles are disabled
10041004
expect(onChange).not.toHaveBeenCalled();
10051005
});
1006+
1007+
it('editable: onDisabledChange called when adding handle', () => {
1008+
const onChange = jest.fn();
1009+
const onDisabledChange = jest.fn();
1010+
const { container } = render(
1011+
<Slider
1012+
range={{ editable: true }}
1013+
value={[0, 100]}
1014+
disabled={[true, false]}
1015+
onChange={onChange}
1016+
onDisabledChange={onDisabledChange}
1017+
/>,
1018+
);
1019+
1020+
// Click to add a handle between 0 and 100
1021+
doMouseDown(container, 50, 'rc-slider', true);
1022+
1023+
expect(onChange).toHaveBeenCalledWith([0, 50, 100]);
1024+
expect(onDisabledChange).toHaveBeenCalledWith([true, false, false]);
1025+
});
1026+
1027+
it('editable: onDisabledChange called when removing handle', () => {
1028+
const onChange = jest.fn();
1029+
const onDisabledChange = jest.fn();
1030+
const { container } = render(
1031+
<Slider
1032+
range={{ editable: true }}
1033+
value={[0, 50, 100]}
1034+
disabled={[false, true, false]}
1035+
onChange={onChange}
1036+
onDisabledChange={onDisabledChange}
1037+
/>,
1038+
);
1039+
1040+
// Drag first handle (enabled) out to delete it
1041+
doMouseMove(container, 0, 1000);
1042+
1043+
expect(onChange).toHaveBeenCalledWith([50, 100]);
1044+
expect(onDisabledChange).toHaveBeenCalledWith([true, false]);
1045+
});
1046+
1047+
it('editable: disabled array stays in sync when adding between disabled handles', () => {
1048+
const onChange = jest.fn();
1049+
const onDisabledChange = jest.fn();
1050+
const { container } = render(
1051+
<Slider
1052+
range={{ editable: true }}
1053+
value={[20, 60]}
1054+
disabled={[true, true]}
1055+
onChange={onChange}
1056+
onDisabledChange={onDisabledChange}
1057+
/>,
1058+
);
1059+
1060+
// Click to add a handle between 20 and 60
1061+
doMouseDown(container, 40, 'rc-slider', true);
1062+
1063+
// Should not trigger onChange because both surrounding handles are disabled
1064+
expect(onChange).not.toHaveBeenCalled();
1065+
expect(onDisabledChange).not.toHaveBeenCalled();
1066+
});
10061067
});
10071068
});

0 commit comments

Comments
 (0)