Skip to content

Commit

Permalink
add event dispatchers for start/change/end interactions
Browse files Browse the repository at this point in the history
- Also provide the values of the handles and indexes changed
- Add some tests for the dispatched events
- Update Readme.md

the Change event will also fire for keyboard interactions, but
currently I decided to avoid the "start" event for keyboard users
as it is kind of tricky to implement, and the "end" event is impossible
to implement. I may consider a focus/blur event at a later time.

resolves: #6
  • Loading branch information
simeydotme committed Jan 16, 2021
1 parent bc8766f commit ebfc946
Show file tree
Hide file tree
Showing 8 changed files with 318 additions and 93 deletions.
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A reactive, accessible, multi-thumb, range slider with the ability to display "p
![Svelte Range Slider -- focussed, including some pips](test/public/slider.png)


**[🔗 _For full documentation and examples, see the Github Pages_](https://simeydotme.github.io/svelte-range-slider-pips/)**
**[📔📘📖 _Full Documentation & Examples_](https://simeydotme.github.io/svelte-range-slider-pips/)**


---
Expand All @@ -31,8 +31,8 @@ A reactive, accessible, multi-thumb, range slider with the ability to display "p

Open your project and use the command line to install the package;
```bash
yarn add --dev svelte-range-slider-pips # or
npm install --save-dev svelte-range-slider-pips # if you prefer npm
yarn add svelte-range-slider-pips --dev # or
npm install svelte-range-slider-pips --save-dev # if you prefer npm
```

## usage
Expand Down Expand Up @@ -107,7 +107,14 @@ prop | type | default | description
**handleFormatter** | `Function` | `formatter` | A function to re-format values on the handle/float before they are displayed. Defaults to the same function given to the `formatter` property
**springValues** | `Object` | `{ stiffness: 0.15, damping: 0.4 }` | Svelte spring physics object to change the behaviour of the handle when moving

**[🔗 _For full documentation and examples, see the Github Pages_](https://simeydotme.github.io/svelte-range-slider-pips/)**
### slider events (dispatched)
event | example | `event.detail` | description
------|------------|--------|-------------
**start** | `on:start={(e) => { ... }}` | `{ activeHandle: Integer, value: Float, values: Array }` | Event fired when the user begins interaction with the slider
**change** | `on:change={(e) => { ... }}` | `{ activeHandle: Integer, previousValue: Float, value: Float, values: Array }` | Event fired when the user changes the value; returns the previous value, also
**stop** | `on:stop={(e) => { ... }}` | `{ activeHandle: Integer, startValue: Float, value: Float, values: Array }` | Event fired when the user stops interacting with slider; returns the beginning value, also

**[📔📘📖 _Full Documentation & Examples_](https://simeydotme.github.io/svelte-range-slider-pips/)**


## contribute
Expand Down
146 changes: 111 additions & 35 deletions dist/svelte-range-slider-pips.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* svelte-range-slider-pips ~ 1.5.3
* svelte-range-slider-pips ~ 1.6.0
* Multi-Thumb, Accessible, Beautiful Range Slider with Pips
* © MPL-2.0 ~ Simon Goellner <[email protected]> ~ 7/1/2021
* © MPL-2.0 ~ Simon Goellner <[email protected]> ~ 16/1/2021
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
Expand Down Expand Up @@ -126,11 +126,35 @@
function toggle_class(element, name, toggle) {
element.classList[toggle ? 'add' : 'remove'](name);
}
function custom_event(type, detail) {
const e = document.createEvent('CustomEvent');
e.initCustomEvent(type, false, false, detail);
return e;
}

let current_component;
function set_current_component(component) {
current_component = component;
}
function get_current_component() {
if (!current_component)
throw new Error(`Function called outside component initialization`);
return current_component;
}
function createEventDispatcher() {
const component = get_current_component();
return (type, detail) => {
const callbacks = component.$$.callbacks[type];
if (callbacks) {
// TODO are there situations where events could be dispatched
// in a server (non-DOM) environment?
const event = custom_event(type, detail);
callbacks.slice().forEach(fn => {
fn.call(component, event);
});
}
};
}

const dirty_components = [];
const binding_callbacks = [];
Expand Down Expand Up @@ -1104,16 +1128,16 @@

function get_each_context$1(ctx, list, i) {
const child_ctx = ctx.slice();
child_ctx[52] = list[i];
child_ctx[54] = i;
child_ctx[58] = list[i];
child_ctx[60] = i;
return child_ctx;
}

// (671:6) {#if float}
// (724:6) {#if float}
function create_if_block_2$1(ctx) {
let span;
let t0;
let t1_value = /*handleFormatter*/ ctx[18](/*value*/ ctx[52]) + "";
let t1_value = /*handleFormatter*/ ctx[18](/*value*/ ctx[58]) + "";
let t1;
let t2;

Expand All @@ -1133,7 +1157,7 @@
},
p(ctx, dirty) {
if (dirty[0] & /*prefix*/ 32768) set_data(t0, /*prefix*/ ctx[15]);
if (dirty[0] & /*handleFormatter, values*/ 262145 && t1_value !== (t1_value = /*handleFormatter*/ ctx[18](/*value*/ ctx[52]) + "")) set_data(t1, t1_value);
if (dirty[0] & /*handleFormatter, values*/ 262145 && t1_value !== (t1_value = /*handleFormatter*/ ctx[18](/*value*/ ctx[58]) + "")) set_data(t1, t1_value);
if (dirty[0] & /*suffix*/ 65536) set_data(t2, /*suffix*/ ctx[16]);
},
d(detaching) {
Expand All @@ -1142,7 +1166,7 @@
};
}

// (653:2) {#each values as value, index}
// (706:2) {#each values as value, index}
function create_each_block$1(ctx) {
let span1;
let span0;
Expand All @@ -1167,22 +1191,22 @@
attr(span1, "role", "slider");
attr(span1, "class", "rangeHandle");
attr(span1, "tabindex", "0");
attr(span1, "style", span1_style_value = "" + ((/*vertical*/ ctx[5] ? "top" : "left") + ": " + /*$springPositions*/ ctx[24][/*index*/ ctx[54]] + "%; z-index: " + (/*activeHandle*/ ctx[22] === /*index*/ ctx[54] ? 3 : 2) + ";"));
attr(span1, "style", span1_style_value = "" + ((/*vertical*/ ctx[5] ? "top" : "left") + ": " + /*$springPositions*/ ctx[24][/*index*/ ctx[60]] + "%; z-index: " + (/*activeHandle*/ ctx[22] === /*index*/ ctx[60] ? 3 : 2) + ";"));

attr(span1, "aria-valuemin", span1_aria_valuemin_value = /*range*/ ctx[1] === true && /*index*/ ctx[54] === 1
attr(span1, "aria-valuemin", span1_aria_valuemin_value = /*range*/ ctx[1] === true && /*index*/ ctx[60] === 1
? /*values*/ ctx[0][0]
: /*min*/ ctx[2]);

attr(span1, "aria-valuemax", span1_aria_valuemax_value = /*range*/ ctx[1] === true && /*index*/ ctx[54] === 0
attr(span1, "aria-valuemax", span1_aria_valuemax_value = /*range*/ ctx[1] === true && /*index*/ ctx[60] === 0
? /*values*/ ctx[0][1]
: /*max*/ ctx[3]);

attr(span1, "aria-valuenow", span1_aria_valuenow_value = /*value*/ ctx[52]);
attr(span1, "aria-valuetext", span1_aria_valuetext_value = "" + (/*prefix*/ ctx[15] + /*handleFormatter*/ ctx[18](/*value*/ ctx[52]) + /*suffix*/ ctx[16]));
attr(span1, "aria-valuenow", span1_aria_valuenow_value = /*value*/ ctx[58]);
attr(span1, "aria-valuetext", span1_aria_valuetext_value = "" + (/*prefix*/ ctx[15] + /*handleFormatter*/ ctx[18](/*value*/ ctx[58]) + /*suffix*/ ctx[16]));
attr(span1, "aria-orientation", span1_aria_orientation_value = /*vertical*/ ctx[5] ? "vertical" : "horizontal");
toggle_class(span1, "hoverable", /*hover*/ ctx[7]);
toggle_class(span1, "active", /*focus*/ ctx[20] && /*activeHandle*/ ctx[22] === /*index*/ ctx[54]);
toggle_class(span1, "press", /*handlePressed*/ ctx[21] && /*activeHandle*/ ctx[22] === /*index*/ ctx[54]);
toggle_class(span1, "active", /*focus*/ ctx[20] && /*activeHandle*/ ctx[22] === /*index*/ ctx[60]);
toggle_class(span1, "press", /*handlePressed*/ ctx[21] && /*activeHandle*/ ctx[22] === /*index*/ ctx[60]);
},
m(target, anchor) {
insert(target, span1, anchor);
Expand Down Expand Up @@ -1214,27 +1238,27 @@
if_block = null;
}

if (dirty[0] & /*vertical, $springPositions, activeHandle*/ 20971552 && span1_style_value !== (span1_style_value = "" + ((/*vertical*/ ctx[5] ? "top" : "left") + ": " + /*$springPositions*/ ctx[24][/*index*/ ctx[54]] + "%; z-index: " + (/*activeHandle*/ ctx[22] === /*index*/ ctx[54] ? 3 : 2) + ";"))) {
if (dirty[0] & /*vertical, $springPositions, activeHandle*/ 20971552 && span1_style_value !== (span1_style_value = "" + ((/*vertical*/ ctx[5] ? "top" : "left") + ": " + /*$springPositions*/ ctx[24][/*index*/ ctx[60]] + "%; z-index: " + (/*activeHandle*/ ctx[22] === /*index*/ ctx[60] ? 3 : 2) + ";"))) {
attr(span1, "style", span1_style_value);
}

if (dirty[0] & /*range, values, min*/ 7 && span1_aria_valuemin_value !== (span1_aria_valuemin_value = /*range*/ ctx[1] === true && /*index*/ ctx[54] === 1
if (dirty[0] & /*range, values, min*/ 7 && span1_aria_valuemin_value !== (span1_aria_valuemin_value = /*range*/ ctx[1] === true && /*index*/ ctx[60] === 1
? /*values*/ ctx[0][0]
: /*min*/ ctx[2])) {
attr(span1, "aria-valuemin", span1_aria_valuemin_value);
}

if (dirty[0] & /*range, values, max*/ 11 && span1_aria_valuemax_value !== (span1_aria_valuemax_value = /*range*/ ctx[1] === true && /*index*/ ctx[54] === 0
if (dirty[0] & /*range, values, max*/ 11 && span1_aria_valuemax_value !== (span1_aria_valuemax_value = /*range*/ ctx[1] === true && /*index*/ ctx[60] === 0
? /*values*/ ctx[0][1]
: /*max*/ ctx[3])) {
attr(span1, "aria-valuemax", span1_aria_valuemax_value);
}

if (dirty[0] & /*values*/ 1 && span1_aria_valuenow_value !== (span1_aria_valuenow_value = /*value*/ ctx[52])) {
if (dirty[0] & /*values*/ 1 && span1_aria_valuenow_value !== (span1_aria_valuenow_value = /*value*/ ctx[58])) {
attr(span1, "aria-valuenow", span1_aria_valuenow_value);
}

if (dirty[0] & /*prefix, handleFormatter, values, suffix*/ 360449 && span1_aria_valuetext_value !== (span1_aria_valuetext_value = "" + (/*prefix*/ ctx[15] + /*handleFormatter*/ ctx[18](/*value*/ ctx[52]) + /*suffix*/ ctx[16]))) {
if (dirty[0] & /*prefix, handleFormatter, values, suffix*/ 360449 && span1_aria_valuetext_value !== (span1_aria_valuetext_value = "" + (/*prefix*/ ctx[15] + /*handleFormatter*/ ctx[18](/*value*/ ctx[58]) + /*suffix*/ ctx[16]))) {
attr(span1, "aria-valuetext", span1_aria_valuetext_value);
}

Expand All @@ -1247,11 +1271,11 @@
}

if (dirty[0] & /*focus, activeHandle*/ 5242880) {
toggle_class(span1, "active", /*focus*/ ctx[20] && /*activeHandle*/ ctx[22] === /*index*/ ctx[54]);
toggle_class(span1, "active", /*focus*/ ctx[20] && /*activeHandle*/ ctx[22] === /*index*/ ctx[60]);
}

if (dirty[0] & /*handlePressed, activeHandle*/ 6291456) {
toggle_class(span1, "press", /*handlePressed*/ ctx[21] && /*activeHandle*/ ctx[22] === /*index*/ ctx[54]);
toggle_class(span1, "press", /*handlePressed*/ ctx[21] && /*activeHandle*/ ctx[22] === /*index*/ ctx[60]);
}
},
d(detaching) {
Expand All @@ -1263,7 +1287,7 @@
};
}

// (676:2) {#if range}
// (729:2) {#if range}
function create_if_block_1$1(ctx) {
let span;
let span_style_value;
Expand All @@ -1288,7 +1312,7 @@
};
}

// (682:2) {#if pips}
// (735:2) {#if pips}
function create_if_block$1(ctx) {
let rangepips;
let current;
Expand Down Expand Up @@ -1419,10 +1443,10 @@
listen(window, "mouseup", /*bodyMouseUp*/ ctx[35]),
listen(window, "touchend", /*bodyTouchEnd*/ ctx[36]),
listen(window, "keydown", /*bodyKeyDown*/ ctx[37]),
listen(div, "touchstart", prevent_default(/*sliderInteractStart*/ ctx[31])),
listen(div, "mousedown", /*sliderInteractStart*/ ctx[31]),
listen(div, "touchend", prevent_default(/*sliderInteractEnd*/ ctx[32])),
listen(div, "mouseup", /*sliderInteractEnd*/ ctx[32])
listen(div, "mouseup", /*sliderInteractEnd*/ ctx[32]),
listen(div, "touchstart", prevent_default(/*sliderInteractStart*/ ctx[31])),
listen(div, "touchend", prevent_default(/*sliderInteractEnd*/ ctx[32]))
];

mounted = true;
Expand Down Expand Up @@ -1590,6 +1614,7 @@
let { handleFormatter = formatter } = $$props;
let { precision = 2 } = $$props;
let { springValues = { stiffness: 0.15, damping: 0.4 } } = $$props;
const dispatch = createEventDispatcher();

// dom references
let slider;
Expand All @@ -1601,6 +1626,8 @@
let handlePressed = false;
let keyboardActive = false;
let activeHandle = values.length - 1;
let startValue;
let previousValue;

// save spring-tweened copies of the values for use
// when changing values and animating the handle/range nicely
Expand Down Expand Up @@ -1750,6 +1777,13 @@

// set the value for the handle, and align/clamp it
$$invalidate(0, values[index] = value, values);

// fire the change event when the handle moves,
// and store the previous value for the next time
if (previousValue !== alignValueToStep(value)) {
eChange();
previousValue = alignValueToStep(value);
}
}

/**
Expand Down Expand Up @@ -1859,6 +1893,11 @@
$$invalidate(21, handlePressed = true);
$$invalidate(22, activeHandle = getClosestHandle(clientPos));

// fire the start event
startValue = values[activeHandle];

eStart();

// for touch devices we want the handle to instantly
// move to the position touched for more responsive feeling
if (e.type === "touchstart") {
Expand All @@ -1872,6 +1911,11 @@
* @param {event} e the event from browser
**/
function sliderInteractEnd(e) {
// fire the stop event for touch devices
if (e.type === "touchend") {
eStop();
}

$$invalidate(21, handlePressed = false);
}

Expand Down Expand Up @@ -1911,12 +1955,18 @@
// this only works if a handle is active, which can
// only happen if there was sliderInteractStart triggered
// on the slider, already
if (handleActivated && (el === slider || slider.contains(el))) {
$$invalidate(20, focus = true);
if (handleActivated) {
if (el === slider || slider.contains(el)) {
$$invalidate(20, focus = true);

if (!targetIsHandle(el)) {
handleInteract(normalisedClient(e));
if (!targetIsHandle(el)) {
handleInteract(normalisedClient(e));
}
}

// fire the stop event for mouse device
// when the body is triggered with an active handle
eStop();
}

handleActivated = false;
Expand All @@ -1939,6 +1989,32 @@
}
}

function eStart() {
dispatch("start", {
activeHandle,
value: alignValueToStep(startValue),
values: values.map(v => alignValueToStep(v))
});
}

function eStop() {
dispatch("stop", {
activeHandle,
startValue: alignValueToStep(startValue),
value: alignValueToStep(values[activeHandle]),
values: values.map(v => alignValueToStep(v))
});
}

function eChange() {
dispatch("change", {
activeHandle,
previousValue: alignValueToStep(previousValue) || alignValueToStep(startValue) || alignValueToStep(values[activeHandle]),
value: alignValueToStep(values[activeHandle]),
values: values.map(v => alignValueToStep(v))
});
}

function div_binding($$value) {
binding_callbacks[$$value ? "unshift" : "push"](() => {
slider = $$value;
Expand Down Expand Up @@ -1983,20 +2059,20 @@
* @param {number} val the value to clamp
* @return {number} the value after it's been clamped
**/
$$invalidate(45, clampValue = function (val) {
$$invalidate(47, clampValue = function (val) {
// return the min/max if outside of that range
return val <= min ? min : val >= max ? max : val;
});
}

if ($$self.$$.dirty[0] & /*min, max, step*/ 28 | $$self.$$.dirty[1] & /*clampValue, precision*/ 16640) {
if ($$self.$$.dirty[0] & /*min, max, step*/ 28 | $$self.$$.dirty[1] & /*clampValue, precision*/ 65792) {
/**
* align the value with the steps so that it
* always sits on the closest (above/below) step
* @param {number} val the value to align
* @return {number} the value after it's been aligned
**/
$$invalidate(44, alignValueToStep = function (val) {
$$invalidate(46, alignValueToStep = function (val) {
// sanity check for performance
if (val <= min) {
return min;
Expand Down Expand Up @@ -2025,7 +2101,7 @@
});
}

if ($$self.$$.dirty[0] & /*values*/ 1 | $$self.$$.dirty[1] & /*alignValueToStep*/ 8192) {
if ($$self.$$.dirty[0] & /*values*/ 1 | $$self.$$.dirty[1] & /*alignValueToStep*/ 32768) {
// watch the values array, and trim / clamp the values to the steps
// and boundaries set up in the slider on change
$$invalidate(0, values = trimRange(values).map(v => alignValueToStep(v)));
Expand Down
Loading

0 comments on commit ebfc946

Please sign in to comment.