Skip to content

Commit e9fd7e1

Browse files
刘欢claude
andcommitted
fix: handle edge cases for disabled array feature
- Fix README.md wording for disabled prop description - Remove empty div in disabled-handle example - Fix triggerChange to correctly handle duplicate values when syncing disabled array - Fix useOffset to prevent pushing disabled handles in pushable mode Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4b232b7 commit e9fd7e1

4 files changed

Lines changed: 41 additions & 12 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ The following APIs are shared by Slider and Range.
108108
| handle | (props) => React.ReactNode | | A handle generator which could be used to customized handle. |
109109
| included | boolean | `true` | If the value is `true`, it means a continuous value interval, otherwise, it is a independent value. |
110110
| reverse | boolean | `false` | If the value is `true`, it means the component is rendered reverse. |
111-
| disabled | boolean \| boolean[] | `false` | If `true`, handles can't be moved. Can also be an array to disable specific handles in range mode, e.g. `[true, false, true]` disables first and third handles. |
111+
| disabled | boolean \| boolean[] | `false` | If `true`, handles can't be moved. This prop can also be an array to disable specific handles in range mode, e.g. `[true, false, true]` disables first and third handles. |
112112
| keyboard | boolean | `true` | Support using keyboard to move handlers. |
113113
| dots | boolean | `false` | When the `step` value is greater than 1, you can set the `dots` to `true` if you want to render the slider with dots. |
114114
| onBeforeChange | Function | NOOP | `onBeforeChange` will be triggered when `ontouchstart` or `onmousedown` is triggered. |

docs/examples/disabled-handle.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,6 @@ export default () => (
111111
<div>
112112
single handle disabled
113113
<SingleSlider />
114-
</div>
115-
<div>
116-
117114
</div>
118115
<div style={style}>
119116
<h3>Disabled Handle + Draggable Track</h3>

src/Slider.tsx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,12 +329,32 @@ const Slider = React.forwardRef<SliderRef, SliderProps<number | number[]>>((prop
329329
) {
330330
const newDisabled = [...rawDisabled];
331331

332+
// Find the first index where arrays differ (handles duplicate values correctly)
333+
const findDiffIndex = (arr1: number[], arr2: number[]) => {
334+
const maxLen = Math.max(arr1.length, arr2.length);
335+
for (let i = 0; i < maxLen; i++) {
336+
// Count occurrences up to current index
337+
const count1 = arr1.slice(0, i + 1).filter((v) => v === arr1[i]).length;
338+
const count2 = arr2.filter((v) => v === arr1[i]).length;
339+
if (count1 > count2) {
340+
return i;
341+
}
342+
}
343+
return -1;
344+
};
345+
332346
if (cloneNextValues.length > rawValues.length) {
333-
const index = cloneNextValues.findIndex((item) => !rawValues.includes(item));
334-
newDisabled.splice(index, 0, false);
347+
// Handle added
348+
const index = findDiffIndex(cloneNextValues, rawValues);
349+
if (index !== -1) {
350+
newDisabled.splice(index, 0, false);
351+
}
335352
} else if (cloneNextValues.length < rawValues.length) {
336-
const index = rawValues.findIndex((item) => !cloneNextValues.includes(item));
337-
newDisabled.splice(index, 1);
353+
// Handle removed
354+
const index = findDiffIndex(rawValues, cloneNextValues);
355+
if (index !== -1) {
356+
newDisabled.splice(index, 1);
357+
}
338358
}
339359

340360
onDisabledChange?.(newDisabled);

src/hooks/useOffset.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -244,33 +244,45 @@ export default function useOffset(
244244
// =============== Push ==================
245245

246246
// >>>>>> Basic push
247-
// End values
247+
// End values (skip disabled handles)
248248
for (let i = valueIndex + 1; i < nextValues.length; i += 1) {
249+
if (isHandleDisabled?.(i)) {
250+
break; // Stop pushing when hitting a disabled handle
251+
}
249252
let changed = true;
250253
while (needPush(nextValues[i] - nextValues[i - 1]) && changed) {
251254
({ value: nextValues[i], changed } = offsetChangedValue(nextValues, 1, i));
252255
}
253256
}
254257

255-
// Start values
258+
// Start values (skip disabled handles)
256259
for (let i = valueIndex; i > 0; i -= 1) {
260+
if (isHandleDisabled?.(i - 1)) {
261+
break; // Stop pushing when hitting a disabled handle
262+
}
257263
let changed = true;
258264
while (needPush(nextValues[i] - nextValues[i - 1]) && changed) {
259265
({ value: nextValues[i - 1], changed } = offsetChangedValue(nextValues, -1, i - 1));
260266
}
261267
}
262268

263269
// >>>>> Revert back to safe push range
264-
// End to Start
270+
// End to Start (skip disabled handles)
265271
for (let i = nextValues.length - 1; i > 0; i -= 1) {
272+
if (isHandleDisabled?.(i) || isHandleDisabled?.(i - 1)) {
273+
continue; // Skip if either handle is disabled
274+
}
266275
let changed = true;
267276
while (needPush(nextValues[i] - nextValues[i - 1]) && changed) {
268277
({ value: nextValues[i - 1], changed } = offsetChangedValue(nextValues, -1, i - 1));
269278
}
270279
}
271280

272-
// Start to End
281+
// Start to End (skip disabled handles)
273282
for (let i = 0; i < nextValues.length - 1; i += 1) {
283+
if (isHandleDisabled?.(i) || isHandleDisabled?.(i + 1)) {
284+
continue; // Skip if either handle is disabled
285+
}
274286
let changed = true;
275287
while (needPush(nextValues[i + 1] - nextValues[i]) && changed) {
276288
({ value: nextValues[i + 1], changed } = offsetChangedValue(nextValues, 1, i + 1));

0 commit comments

Comments
 (0)