Skip to content

Commit

Permalink
[@mantine/core] Slider: Fix restrictToMarks prop not working with a…
Browse files Browse the repository at this point in the history
…rrow and Home/End keys correctly
  • Loading branch information
rtivital committed Nov 28, 2024
1 parent dbecbe2 commit a4edfa4
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 0 deletions.
54 changes: 54 additions & 0 deletions packages/@mantine/core/src/components/Slider/Slider/Slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ import { getChangeValue } from '../utils/get-change-value/get-change-value';
import { getFloatingValue } from '../utils/get-floating-value/get-gloating-value';
import { getPosition } from '../utils/get-position/get-position';
import { getPrecision } from '../utils/get-precision/get-precision';
import {
getFirstMarkValue,
getLastMarkValue,
getNextMarkValue,
getPreviousMarkValue,
} from '../utils/get-step-mark-value/get-step-mark-value';
import classes from '../Slider.module.css';

export interface SliderProps
Expand Down Expand Up @@ -254,6 +260,14 @@ export const Slider = factory<SliderFactory>((_props, ref) => {
case 'ArrowUp': {
event.preventDefault();
thumb.current?.focus();

if (restrictToMarks && marks) {
const nextValue = getNextMarkValue(_value, marks);
setValue(nextValue);
onChangeEnd?.(nextValue);
break;
}

const nextValue = getFloatingValue(
Math.min(Math.max(_value + step!, min!), max!),
precision
Expand All @@ -266,6 +280,15 @@ export const Slider = factory<SliderFactory>((_props, ref) => {
case 'ArrowRight': {
event.preventDefault();
thumb.current?.focus();

if (restrictToMarks && marks) {
const nextValue =
dir === 'rtl' ? getPreviousMarkValue(_value, marks) : getNextMarkValue(_value, marks);
setValue(nextValue);
onChangeEnd?.(nextValue);
break;
}

const nextValue = getFloatingValue(
Math.min(Math.max(dir === 'rtl' ? _value - step! : _value + step!, min!), max!),
precision
Expand All @@ -278,6 +301,14 @@ export const Slider = factory<SliderFactory>((_props, ref) => {
case 'ArrowDown': {
event.preventDefault();
thumb.current?.focus();

if (restrictToMarks && marks) {
const nextValue = getPreviousMarkValue(_value, marks);
setValue(nextValue);
onChangeEnd?.(nextValue);
break;
}

const nextValue = getFloatingValue(
Math.min(Math.max(_value - step!, min!), max!),
precision
Expand All @@ -290,6 +321,15 @@ export const Slider = factory<SliderFactory>((_props, ref) => {
case 'ArrowLeft': {
event.preventDefault();
thumb.current?.focus();

if (restrictToMarks && marks) {
const nextValue =
dir === 'rtl' ? getNextMarkValue(_value, marks) : getPreviousMarkValue(_value, marks);
setValue(nextValue);
onChangeEnd?.(nextValue);
break;
}

const nextValue = getFloatingValue(
Math.min(Math.max(dir === 'rtl' ? _value + step! : _value - step!, min!), max!),
precision
Expand All @@ -302,6 +342,13 @@ export const Slider = factory<SliderFactory>((_props, ref) => {
case 'Home': {
event.preventDefault();
thumb.current?.focus();

if (restrictToMarks && marks) {
setValue(getFirstMarkValue(marks));
onChangeEnd?.(getFirstMarkValue(marks));
break;
}

setValue(min!);
onChangeEnd?.(min!);
break;
Expand All @@ -310,6 +357,13 @@ export const Slider = factory<SliderFactory>((_props, ref) => {
case 'End': {
event.preventDefault();
thumb.current?.focus();

if (restrictToMarks && marks) {
setValue(getLastMarkValue(marks));
onChangeEnd?.(getLastMarkValue(marks));
break;
}

setValue(max!);
onChangeEnd?.(max!);
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
getFirstMarkValue,
getLastMarkValue,
getNextMarkValue,
getPreviousMarkValue,
} from './get-step-mark-value';

describe('@mantine/core/Slider/get-step-mark-value', () => {
it('returns first mark value', () => {
expect(getFirstMarkValue([{ value: 1 }, { value: 2 }])).toBe(2);
expect(getFirstMarkValue([{ value: 1 }])).toBe(1);
expect(getFirstMarkValue([])).toBe(0);
});

it('returns last mark value', () => {
expect(getLastMarkValue([{ value: 1 }, { value: 2 }])).toBe(2);
expect(getLastMarkValue([{ value: 1 }])).toBe(1);
expect(getLastMarkValue([])).toBe(100);
});

it('returns next mark value', () => {
expect(getNextMarkValue(1, [{ value: 1 }, { value: 2 }])).toBe(2);
expect(getNextMarkValue(1, [{ value: 2 }, { value: 3 }])).toBe(2);
expect(getNextMarkValue(1, [{ value: 0 }, { value: 2 }])).toBe(2);
expect(getNextMarkValue(1, [{ value: 0 }, { value: 1 }])).toBe(1);
expect(getNextMarkValue(1, [{ value: 1 }])).toBe(1);
expect(getNextMarkValue(1, [])).toBe(1);
});

it('returns previous mark value', () => {
expect(getPreviousMarkValue(1, [{ value: 1 }, { value: 2 }])).toBe(1);
expect(getPreviousMarkValue(1, [{ value: 2 }, { value: 3 }])).toBe(1);
expect(getPreviousMarkValue(1, [{ value: 0 }, { value: 2 }])).toBe(0);
expect(getPreviousMarkValue(1, [{ value: 0 }, { value: 1 }])).toBe(0);
expect(getPreviousMarkValue(1, [{ value: 1 }])).toBe(1);
expect(getPreviousMarkValue(1, [])).toBe(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export function getNextMarkValue(
currentValue: number,
marks: { value: number; label?: React.ReactNode }[]
) {
const sortedMarks = [...marks].sort((a, b) => a.value - b.value);
const nextMark = sortedMarks.find((mark) => mark.value > currentValue);
return nextMark ? nextMark.value : currentValue;
}

export function getPreviousMarkValue(
currentValue: number,
marks: { value: number; label?: React.ReactNode }[]
) {
const sortedMarks = [...marks].sort((a, b) => b.value - a.value);
const previousMark = sortedMarks.find((mark) => mark.value < currentValue);
return previousMark ? previousMark.value : currentValue;
}

export function getFirstMarkValue(marks: { value: number; label?: React.ReactNode }[]) {
const sortedMarks = [...marks].sort((a, b) => b.value - a.value);
return sortedMarks.length > 0 ? sortedMarks[0].value : 0;
}

export function getLastMarkValue(marks: { value: number; label?: React.ReactNode }[]) {
const sortedMarks = [...marks].sort((a, b) => a.value - b.value);
return sortedMarks.length > 0 ? sortedMarks[sortedMarks.length - 1].value : 100;
}

0 comments on commit a4edfa4

Please sign in to comment.