Skip to content

Commit 83fd6c5

Browse files
committed
add the new property 'limits' to the library
- allows setting a limit other than min/max where the handles will stop
1 parent 6bc4b3d commit 83fd6c5

File tree

14 files changed

+787
-540
lines changed

14 files changed

+787
-540
lines changed

dist/range-slider-pips.js

Lines changed: 266 additions & 217 deletions
Large diffs are not rendered by default.

dist/range-slider-pips.mjs

Lines changed: 266 additions & 217 deletions
Large diffs are not rendered by default.

dist/svelte/components/RangePips.svelte

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,12 @@ export let focus;
2929
export let orientationStart;
3030
export let moveHandle;
3131
let clientStart = null;
32-
$:
33-
stepMax = vertical ? 50 : 100;
34-
$:
35-
tooManyPips = (max - min) / step >= stepMax;
36-
$:
37-
stepDivisor = vertical ? 10 : 20;
38-
$:
39-
reducedSteps = (max - min) / stepDivisor;
40-
$:
41-
pipStep = pipstep ?? (tooManyPips ? reducedSteps : 1);
42-
$:
43-
pipCount = Math.floor((max - min) / (step * pipStep));
32+
$: stepMax = vertical ? 50 : 100;
33+
$: tooManyPips = (max - min) / step >= stepMax;
34+
$: stepDivisor = vertical ? 10 : 20;
35+
$: reducedSteps = (max - min) / stepDivisor;
36+
$: pipStep = pipstep ?? (tooManyPips ? reducedSteps : 1);
37+
$: pipCount = Math.floor((max - min) / (step * pipStep));
4438
function labelDown(event) {
4539
clientStart = normalisedClient(event);
4640
}

dist/svelte/components/RangePips.svelte.d.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,35 @@ import { SvelteComponent } from "svelte";
22
import type { Pip, Formatter } from '../types.js';
33
declare const __propDef: {
44
props: {
5-
range?: boolean | "min" | "max" | undefined;
6-
min?: number | undefined;
7-
max?: number | undefined;
8-
step?: number | undefined;
9-
value?: number | undefined;
10-
values?: number[] | undefined;
11-
vertical?: boolean | undefined;
12-
reversed?: boolean | undefined;
13-
hoverable?: boolean | undefined;
14-
disabled?: boolean | undefined;
5+
range?: boolean | "min" | "max";
6+
min?: number;
7+
max?: number;
8+
step?: number;
9+
value?: number;
10+
values?: number[];
11+
vertical?: boolean;
12+
reversed?: boolean;
13+
hoverable?: boolean;
14+
disabled?: boolean;
1515
pipstep?: number | undefined;
1616
all?: Pip;
1717
first?: Pip;
1818
last?: Pip;
1919
rest?: Pip;
20-
prefix?: string | undefined;
21-
suffix?: string | undefined;
22-
formatter?: Formatter | undefined;
23-
precision?: number | undefined;
20+
prefix?: string;
21+
suffix?: string;
22+
formatter?: Formatter;
23+
precision?: number;
2424
focus: boolean;
25-
orientationStart: 'left' | 'right' | 'top' | 'bottom';
25+
orientationStart: "left" | "right" | "top" | "bottom";
2626
moveHandle: (index: number | null, value: number) => void;
2727
};
2828
events: {
2929
[evt: string]: CustomEvent<any>;
3030
};
3131
slots: {};
32+
exports?: {} | undefined;
33+
bindings?: string | undefined;
3234
};
3335
export type RangePipsProps = typeof __propDef.props;
3436
export type RangePipsEvents = typeof __propDef.events;

dist/svelte/components/RangeSlider.css

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
--handle-border: var(--range-handle-border, var(--handle));
1111
--range-inactive: var(--range-range-inactive, var(--handle-inactive));
1212
--range: var(--range-range, var(--handle-focus));
13+
--range-limit: var(--range-range-limit, #99a2a280);
1314
--float-inactive: var(--range-float-inactive, var(--handle-inactive));
1415
--float: var(--range-float, var(--handle-focus));
1516
--float-text: var(--range-float-text, white);
@@ -173,7 +174,8 @@
173174
transform: translate(-50%, -100%);
174175
}
175176

176-
.rangeSlider .rangeBar {
177+
.rangeSlider .rangeBar,
178+
.rangeSlider .rangeLimit {
177179
position: absolute;
178180
display: block;
179181
transition: background 0.2s ease;
@@ -184,7 +186,8 @@
184186
z-index: 1;
185187
}
186188

187-
.rangeSlider.vertical .rangeBar {
189+
.rangeSlider.vertical .rangeBar,
190+
.rangeSlider.vertical .rangeLimit {
188191
width: 0.5em;
189192
height: auto;
190193
}
@@ -204,6 +207,11 @@
204207
background-color: var(--range);
205208
}
206209

210+
.rangeSlider .rangeLimit {
211+
background-color: #99a2a280;
212+
background-color: var(--range-limit);
213+
}
214+
207215
.rangeSlider .rangeNub {
208216
background-color: #99a2a2;
209217
background-color: var(--handle-inactive);

dist/svelte/components/RangeSlider.svelte

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export let float = false;
2525
export let reversed = false;
2626
export let hoverable = true;
2727
export let disabled = false;
28+
export let limits = null;
2829
export let pips = false;
2930
export let pipstep = void 0;
3031
export let all = true;
@@ -80,15 +81,12 @@ const checkAriaLabels = () => {
8081
};
8182
checkValueIsNumber();
8283
checkValuesIsArray();
83-
$:
84-
value, updateValues();
85-
$:
86-
values, updateValue();
87-
$:
88-
ariaLabels, checkAriaLabels();
84+
$: value, updateValues();
85+
$: values, updateValue();
86+
$: ariaLabels, checkAriaLabels();
8987
$: {
9088
const trimmedAlignedValues = trimRange(
91-
values.map((v) => alignValueToStep(v, min, max, step, precision))
89+
values.map((v) => alignValueToStep(v, min, max, step, precision, limits))
9290
);
9391
if (!(values.length === trimmedAlignedValues.length) || !values.every(
9492
(element, index) => coerceFloat(element, precision) === trimmedAlignedValues[index]
@@ -105,13 +103,10 @@ $: {
105103
}
106104
valueLength = values.length;
107105
}
108-
$:
109-
orientationStart = vertical ? reversed ? "top" : "bottom" : reversed ? "right" : "left";
110-
$:
111-
orientationEnd = vertical ? reversed ? "bottom" : "top" : reversed ? "left" : "right";
106+
$: orientationStart = vertical ? reversed ? "top" : "bottom" : reversed ? "right" : "left";
107+
$: orientationEnd = vertical ? reversed ? "bottom" : "top" : reversed ? "left" : "right";
112108
function targetIsHandle(el) {
113-
if (!slider)
114-
return false;
109+
if (!slider) return false;
115110
const handles = slider.querySelectorAll(".handle");
116111
const isHandle = Array.prototype.includes.call(handles, el);
117112
const isChild = Array.prototype.some.call(handles, (e) => e.contains(el));
@@ -127,8 +122,7 @@ function trimRange(values2) {
127122
}
128123
}
129124
function getClosestHandle(clientPos) {
130-
if (!slider)
131-
return 0;
125+
if (!slider) return 0;
132126
const dims = slider.getBoundingClientRect();
133127
let handlePos = 0;
134128
let handlePercent = 0;
@@ -158,8 +152,7 @@ function getClosestHandle(clientPos) {
158152
return closest;
159153
}
160154
function handleInteract(clientPos) {
161-
if (!slider)
162-
return;
155+
if (!slider) return;
163156
const dims = slider.getBoundingClientRect();
164157
let handlePos = 0;
165158
let handlePercent = 0;
@@ -177,7 +170,7 @@ function handleInteract(clientPos) {
177170
moveHandle(activeHandle, handleVal);
178171
}
179172
function moveHandle(index, value2) {
180-
value2 = alignValueToStep(value2, min, max, step, precision);
173+
value2 = alignValueToStep(value2, min, max, step, precision, limits);
181174
if (index === null) {
182175
index = activeHandle;
183176
}
@@ -297,7 +290,8 @@ function sliderInteractStart(event) {
297290
min,
298291
max,
299292
step,
300-
precision
293+
precision,
294+
limits
301295
);
302296
eStart();
303297
if (event.type === "touchstart" && !target.matches(".pipVal")) {
@@ -357,15 +351,15 @@ function eStart() {
357351
!disabled && dispatch("start", {
358352
activeHandle,
359353
value: startValue,
360-
values: values.map((v) => alignValueToStep(v, min, max, step, precision))
354+
values: values.map((v) => alignValueToStep(v, min, max, step, precision, limits))
361355
});
362356
}
363357
function eStop() {
364358
!disabled && dispatch("stop", {
365359
activeHandle,
366360
startValue,
367361
value: values[activeHandle],
368-
values: values.map((v) => alignValueToStep(v, min, max, step, precision))
362+
values: values.map((v) => alignValueToStep(v, min, max, step, precision, limits))
369363
});
370364
}
371365
function eChange() {
@@ -374,7 +368,7 @@ function eChange() {
374368
startValue,
375369
previousValue: typeof previousValue === "undefined" ? startValue : previousValue,
376370
value: values[activeHandle],
377-
values: values.map((v) => alignValueToStep(v, min, max, step, precision))
371+
values: values.map((v) => alignValueToStep(v, min, max, step, precision, limits))
378372
});
379373
}
380374
function ariaLabelFormatter(value2, index) {
@@ -440,6 +434,13 @@ function ariaLabelFormatter(value2, index) {
440434
{/if}
441435
</span>
442436
{/each}
437+
{#if limits}
438+
<span
439+
class="rangeLimit"
440+
style="{orientationStart}: {valueAsPercent(limits[0], min, max, precision)}%;
441+
{orientationEnd}: {100 - valueAsPercent(limits[1], min, max, precision)}%;"
442+
/>
443+
{/if}
443444
{#if range}
444445
<span
445446
class="rangeBar"
@@ -497,6 +498,7 @@ function ariaLabelFormatter(value2, index) {
497498
--handle-border: var(--range-handle-border, var(--handle));
498499
--range-inactive: var(--range-range-inactive, var(--handle-inactive));
499500
--range: var(--range-range, var(--handle-focus));
501+
--range-limit: var(--range-range-limit, #99a2a280);
500502
--float-inactive: var(--range-float-inactive, var(--handle-inactive));
501503
--float: var(--range-float, var(--handle-focus));
502504
--float-text: var(--range-float-text, white);
@@ -660,7 +662,8 @@ function ariaLabelFormatter(value2, index) {
660662
transform: translate(-50%, -100%);
661663
}
662664
663-
:global(.rangeSlider .rangeBar) {
665+
:global(.rangeSlider .rangeBar),
666+
:global(.rangeSlider .rangeLimit) {
664667
position: absolute;
665668
display: block;
666669
transition: background 0.2s ease;
@@ -671,7 +674,8 @@ function ariaLabelFormatter(value2, index) {
671674
z-index: 1;
672675
}
673676
674-
:global(.rangeSlider.vertical .rangeBar) {
677+
:global(.rangeSlider.vertical .rangeBar),
678+
:global(.rangeSlider.vertical .rangeLimit) {
675679
width: 0.5em;
676680
height: auto;
677681
}
@@ -691,6 +695,11 @@ function ariaLabelFormatter(value2, index) {
691695
background-color: var(--range);
692696
}
693697
698+
:global(.rangeSlider .rangeLimit) {
699+
background-color: #99a2a280;
700+
background-color: var(--range-limit);
701+
}
702+
694703
:global(.rangeSlider .rangeNub) {
695704
background-color: #99a2a2;
696705
background-color: var(--handle-inactive);

dist/svelte/components/RangeSlider.svelte.d.ts

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,33 @@ import type { Pip, Formatter } from '../types.js';
44
declare const __propDef: {
55
props: {
66
slider?: HTMLDivElement | undefined;
7-
range?: boolean | "min" | "max" | undefined;
8-
pushy?: boolean | undefined;
9-
min?: number | undefined;
10-
max?: number | undefined;
11-
step?: number | undefined;
12-
values?: number[] | undefined;
13-
value?: number | undefined;
14-
vertical?: boolean | undefined;
15-
float?: boolean | undefined;
16-
reversed?: boolean | undefined;
17-
hoverable?: boolean | undefined;
18-
disabled?: boolean | undefined;
19-
pips?: boolean | undefined;
7+
range?: boolean | "min" | "max";
8+
pushy?: boolean;
9+
min?: number;
10+
max?: number;
11+
step?: number;
12+
values?: number[];
13+
value?: number;
14+
vertical?: boolean;
15+
float?: boolean;
16+
reversed?: boolean;
17+
hoverable?: boolean;
18+
disabled?: boolean;
19+
limits?: null | [number, number];
20+
pips?: boolean;
2021
pipstep?: number | undefined;
2122
all?: Pip;
2223
first?: Pip;
2324
last?: Pip;
2425
rest?: Pip;
2526
id?: string | undefined;
26-
prefix?: string | undefined;
27-
suffix?: string | undefined;
28-
formatter?: Formatter | undefined;
29-
handleFormatter?: Formatter | undefined;
30-
ariaLabels?: string[] | undefined;
31-
precision?: number | undefined;
32-
springValues?: SpringOpts | undefined;
27+
prefix?: string;
28+
suffix?: string;
29+
formatter?: Formatter;
30+
handleFormatter?: Formatter;
31+
ariaLabels?: string[];
32+
precision?: number;
33+
springValues?: SpringOpts;
3334
};
3435
events: {
3536
start: CustomEvent<any>;
@@ -39,6 +40,8 @@ declare const __propDef: {
3940
[evt: string]: CustomEvent<any>;
4041
};
4142
slots: {};
43+
exports?: {} | undefined;
44+
bindings?: string | undefined;
4245
};
4346
export type RangeSliderProps = typeof __propDef.props;
4447
export type RangeSliderEvents = typeof __propDef.events;

dist/svelte/utils.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export declare const valueAsPercent: (value: number, min: number, max: number, p
3535
* @param {number} precision the number of decimal places to fix to
3636
* @return {number} the value after it's been aligned
3737
**/
38-
export declare const alignValueToStep: (value: number, min: number, max: number, step: number, precision?: number) => number;
38+
export declare const alignValueToStep: (value: number, min: number, max: number, step: number, precision?: number, limits?: [number, number] | null) => number;
3939
/**
4040
* helper to take a string of html and return only the text
4141
* @param {string} possibleHtml the string that may contain html

dist/svelte/utils.js

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,10 @@ export const valueAsPercent = function (value, min, max, precision = 2) {
5050
* @param {number} precision the number of decimal places to fix to
5151
* @return {number} the value after it's been aligned
5252
**/
53-
export const alignValueToStep = function (value, min, max, step, precision = 2) {
54-
// sanity check for performance
55-
if (value <= min) {
56-
return coerceFloat(min, precision);
57-
}
58-
else if (value >= max) {
59-
return coerceFloat(max, precision);
60-
}
61-
else {
62-
value = coerceFloat(value, precision);
63-
}
53+
export const alignValueToStep = function (value, min, max, step, precision = 2, limits = null) {
54+
// if limits are provided, clamp the value between the limits
55+
// if no limits are provided, clamp the value between the min and max
56+
value = clampValue(value, limits?.[0] ?? min, limits?.[1] ?? max);
6457
// find the middle-point between steps
6558
// and see if the value is closer to the
6659
// next step, or previous step
@@ -70,7 +63,7 @@ export const alignValueToStep = function (value, min, max, step, precision = 2)
7063
aligned += remainder > 0 ? step : -step;
7164
}
7265
// make sure the value is within acceptable limits
73-
aligned = clampValue(aligned, min, max);
66+
aligned = clampValue(aligned, limits?.[0] ?? min, limits?.[1] ?? max);
7467
// make sure the returned value is set to the precision desired
7568
// this is also because javascript often returns weird floats
7669
// when dealing with odd numbers and percentages

0 commit comments

Comments
 (0)