From 2b0f36b1b2065c026d32c2769fbedbda5cac7454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Sat, 20 Jul 2024 16:40:44 +0800 Subject: [PATCH] feat: support min & max count --- assets/index.less | 1 + docs/examples/editable.tsx | 2 ++ src/Slider.tsx | 30 +++++++++++++++++++----------- src/hooks/useDrag.ts | 5 ++++- src/hooks/useRange.ts | 14 ++++++++++---- 5 files changed, 36 insertions(+), 16 deletions(-) diff --git a/assets/index.less b/assets/index.less index e2cb4e411..64daded8e 100644 --- a/assets/index.less +++ b/assets/index.less @@ -68,6 +68,7 @@ cursor: -webkit-grab; cursor: grab; opacity: 0.8; + user-select: none; touch-action: pan-x; &-dragging&-dragging&-dragging { diff --git a/docs/examples/editable.tsx b/docs/examples/editable.tsx index 542a31549..55dd11e98 100644 --- a/docs/examples/editable.tsx +++ b/docs/examples/editable.tsx @@ -18,6 +18,8 @@ export default () => { // range range={{ editable: true, + minCount: 1, + maxCount: 4, }} // track={false} min={0} diff --git a/src/Slider.tsx b/src/Slider.tsx index 446b79989..033e41699 100644 --- a/src/Slider.tsx +++ b/src/Slider.tsx @@ -40,6 +40,10 @@ import type { export type RangeConfig = { editable?: boolean; draggableTrack?: boolean; + /** Set min count when `editable` */ + minCount?: number; + /** Set max count when `editable` */ + maxCount?: number; }; export interface SliderProps { @@ -59,6 +63,7 @@ export interface SliderProps { // Value range?: boolean | RangeConfig; + /** @deprecated Use `range.minCount` or `range.maxCount` to handle this */ count?: number; min?: number; max?: number; @@ -185,7 +190,7 @@ const Slider = React.forwardRef>((prop }, [reverse, vertical]); // ============================ Range ============================= - const [rangeEnabled, rangeEditable, rangeDraggableTrack] = useRange(range); + const [rangeEnabled, rangeEditable, rangeDraggableTrack, minCount, maxCount] = useRange(range); const mergedMin = React.useMemo(() => (isFinite(min) ? min : 0), [min]); const mergedMax = React.useMemo(() => (isFinite(max) ? max : 100), [max]); @@ -312,17 +317,19 @@ const Slider = React.forwardRef>((prop }); const onDelete = (index: number) => { - if (!disabled && rangeEditable) { - const cloneNextValues = [...rawValues]; - cloneNextValues.splice(index, 1); + if (disabled || !rangeEditable || rawValues.length <= minCount) { + return; + } - onBeforeChange?.(getTriggerValue(cloneNextValues)); - triggerChange(cloneNextValues); + const cloneNextValues = [...rawValues]; + cloneNextValues.splice(index, 1); - const nextFocusIndex = Math.max(0, index - 1); - handlesRef.current.hideHelp(); - handlesRef.current.focus(nextFocusIndex); - } + onBeforeChange?.(getTriggerValue(cloneNextValues)); + triggerChange(cloneNextValues); + + const nextFocusIndex = Math.max(0, index - 1); + handlesRef.current.hideHelp(); + handlesRef.current.focus(nextFocusIndex); }; const [draggingIndex, draggingValue, draggingDelete, cacheValues, onStartDrag] = useDrag( @@ -336,6 +343,7 @@ const Slider = React.forwardRef>((prop finishChange, offsetValues, rangeEditable, + minCount, ); /** @@ -365,7 +373,7 @@ const Slider = React.forwardRef>((prop let focusIndex = valueIndex; - if (rangeEditable && valueDist !== 0) { + if (rangeEditable && valueDist !== 0 && (!maxCount || rawValues.length < maxCount)) { cloneNextValues.splice(valueBeforeIndex + 1, 0, newValue); focusIndex = valueBeforeIndex + 1; } else { diff --git a/src/hooks/useDrag.ts b/src/hooks/useDrag.ts index 8b4980253..7413ff0df 100644 --- a/src/hooks/useDrag.ts +++ b/src/hooks/useDrag.ts @@ -23,6 +23,7 @@ function useDrag( finishChange: (draggingDelete: boolean) => void, offsetValues: OffsetValues, editable: boolean, + minCount: number, ): [ draggingIndex: number, draggingValue: number, @@ -159,7 +160,9 @@ function useDrag( } // Check if need mark remove - deleteMark = editable ? Math.abs(removeDist) > REMOVE_DIST : false; + deleteMark = editable + ? Math.abs(removeDist) > REMOVE_DIST && minCount < cacheValues.length + : false; setDraggingDelete(deleteMark); updateCacheValue(valueIndex, offSetPercent, deleteMark); diff --git a/src/hooks/useRange.ts b/src/hooks/useRange.ts index ff109f239..4605a1b60 100644 --- a/src/hooks/useRange.ts +++ b/src/hooks/useRange.ts @@ -4,18 +4,24 @@ import type { SliderProps } from '../Slider'; export default function useRange( range?: SliderProps['range'], -): [range: boolean, rangeEditable: boolean, rangeDraggableTrack: boolean] { +): [ + range: boolean, + rangeEditable: boolean, + rangeDraggableTrack: boolean, + minCount: number, + maxCount?: number, +] { return useMemo(() => { if (range === true || !range) { - return [!!range, false, false]; + return [!!range, false, false, 0]; } - const { editable, draggableTrack } = range; + const { editable, draggableTrack, minCount, maxCount } = range; if (process.env.NODE_ENV !== 'production') { warning(!editable || !draggableTrack, '`editable` can not work with `draggableTrack`.'); } - return [true, editable, !editable && draggableTrack]; + return [true, editable, !editable && draggableTrack, minCount || 0, maxCount]; }, [range]); }