Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from 'react';
import { useMergedRef, useMove, useUncontrolled } from '@mantine/hooks';
import { clamp, useMergedRef, useMove, useUncontrolled } from '@mantine/hooks';
import {
BoxProps,
createVarsResolver,
Expand Down Expand Up @@ -58,6 +58,9 @@ export interface RangeSliderProps
/** Maximum possible value, `100` by default */
max?: number;

/** Domain of the slider, defines the full range of possible values, `[min, max]` by default */
domain?: [number, number];

/** Number by which value will be incremented/decremented with thumb drag and arrows, `1` by default */
step?: number;

Expand Down Expand Up @@ -175,6 +178,7 @@ export const RangeSlider = factory<RangeSliderFactory>((_props, ref) => {
size,
min,
max,
domain,
minRange,
maxRange,
step,
Expand Down Expand Up @@ -228,9 +232,10 @@ export const RangeSlider = factory<RangeSliderFactory>((_props, ref) => {
const thumbs = useRef<HTMLDivElement[]>([]);
const root = useRef<HTMLDivElement>(null);
const thumbIndex = useRef<number | undefined>(undefined);
const [domainMin, domainMax] = domain || [min!, max!];
const positions = [
getPosition({ value: _value[0], min: min!, max: max! }),
getPosition({ value: _value[1], min: min!, max: max! }),
getPosition({ value: _value[0], min: domainMin, max: domainMax }),
getPosition({ value: _value[1], min: domainMin, max: domainMax }),
];

const precision = _precision ?? getPrecision(step!);
Expand Down Expand Up @@ -281,33 +286,34 @@ export const RangeSlider = factory<RangeSliderFactory>((_props, ref) => {
}
}
} else {
clone[index] = val;
const clampedVal = clamp(val, min!, max!);
clone[index] = clampedVal;

if (index === 0) {
if (val > clone[1] - (minRange! - 0.000000001)) {
clone[1] = Math.min(val + minRange!, max!);
if (clampedVal > clone[1] - (minRange! - 0.000000001)) {
clone[1] = Math.min(clampedVal + minRange!, max!);
}

if (val > (max! - (minRange! - 0.000000001) || min!)) {
if (clampedVal > (max! - (minRange! - 0.000000001) || min!)) {
clone[index] = valueRef.current[index];
}

if (clone[1] - val > maxRange!) {
clone[1] = val + maxRange!;
if (clone[1] - clampedVal > maxRange!) {
clone[1] = clampedVal + maxRange!;
}
}

if (index === 1) {
if (val < clone[0] + minRange!) {
clone[0] = Math.max(val - minRange!, min!);
if (clampedVal < clone[0] + minRange!) {
clone[0] = Math.max(clampedVal - minRange!, min!);
}

if (val < clone[0] + minRange!) {
if (clampedVal < clone[0] + minRange!) {
clone[index] = valueRef.current[index];
}

if (val - clone[0] > maxRange!) {
clone[0] = val - maxRange!;
if (clampedVal - clone[0] > maxRange!) {
clone[0] = clampedVal - maxRange!;
}
}
}
Expand All @@ -332,8 +338,8 @@ export const RangeSlider = factory<RangeSliderFactory>((_props, ref) => {
if (!disabled) {
const nextValue = getChangeValue({
value: val,
min: min!,
max: max!,
min: domainMin,
max: domainMax,
step: step!,
precision,
});
Expand Down Expand Up @@ -497,8 +503,8 @@ export const RangeSlider = factory<RangeSliderFactory>((_props, ref) => {
filled={positions[1] - positions[0]}
marks={marks}
inverted={inverted}
min={min!}
max={max!}
min={domainMin}
max={domainMax}
value={_value[1]}
disabled={disabled}
containerProps={{
Expand Down
9 changes: 9 additions & 0 deletions packages/@mantine/core/src/components/Slider/Slider.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ export function SizeSlider() {
);
}

export function DomainSlider() {
return (
<div style={{ padding: 40, maxWidth: 300 }}>
<Slider domain={[0, 100]} min={20} max={60} />
<RangeSlider domain={[0, 100]} min={20} max={60} />
</div>
);
}

export function Range() {
return (
<div style={{ padding: 40, maxWidth: 400 }}>
Expand Down
28 changes: 17 additions & 11 deletions packages/@mantine/core/src/components/Slider/Slider/Slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ export interface SliderProps
/** Maximum possible value, `100` by default */
max?: number;

/** Domain of the slider, defines the full range of possible values, `[min, max]` by default */
domain?: [number, number];

/** Number by which value will be incremented/decremented with thumb drag and arrows, `1` by default */
step?: number;

Expand Down Expand Up @@ -164,6 +167,7 @@ export const Slider = factory<SliderFactory>((_props, ref) => {
size,
min,
max,
domain,
step,
precision: _precision,
defaultValue,
Expand Down Expand Up @@ -219,7 +223,8 @@ export const Slider = factory<SliderFactory>((_props, ref) => {

const root = useRef<HTMLDivElement>(null);
const thumb = useRef<HTMLDivElement>(null);
const position = getPosition({ value: _value, min: min!, max: max! });
const [domainMin, domainMax] = domain || [min!, max!];
const position = getPosition({ value: _value, min: domainMin, max: domainMax });
const scaledValue = scale!(_value);
const _label = typeof label === 'function' ? label(scaledValue) : label;
const precision = _precision ?? getPrecision(step!);
Expand All @@ -229,23 +234,24 @@ export const Slider = factory<SliderFactory>((_props, ref) => {
if (!disabled) {
const nextValue = getChangeValue({
value: x,
min: min!,
max: max!,
min: domainMin,
max: domainMax,
step: step!,
precision,
});
const clampedValue = clamp(nextValue, min!, max!);
setValue(
restrictToMarks && marks?.length
? findClosestNumber(
nextValue,
clampedValue,
marks.map((mark) => mark.value)
)
: nextValue
: clampedValue
);
valueRef.current = nextValue;
valueRef.current = clampedValue;
}
},
[disabled, min, max, step, precision, setValue, marks, restrictToMarks]
[disabled, min, max, domainMin, domainMax, step, precision, setValue, marks, restrictToMarks]
);

const handleScrubEnd = useCallback(() => {
Expand Down Expand Up @@ -409,8 +415,8 @@ export const Slider = factory<SliderFactory>((_props, ref) => {
offset={0}
filled={position}
marks={marks}
min={min!}
max={max!}
min={domainMin}
max={domainMax}
value={scaledValue}
disabled={disabled}
containerProps={{
Expand All @@ -420,8 +426,8 @@ export const Slider = factory<SliderFactory>((_props, ref) => {
}}
>
<Thumb
max={max!}
min={min!}
max={domainMax}
min={domainMin}
value={scaledValue}
position={position}
dragging={active}
Expand Down
Loading