function Scrubber(
values,
{
format = (value) => value,
index = false,
initial = 0,
delay = null,
autoplay = true,
loop = true,
loopDelay = null,
alternate = false
} = {}
) {
values = Array.from(values);
let form = html`<form style="font: 12px var(--sans-serif); font-variant-numeric: tabular-nums; display: flex; height: 50px; align-items: center;">
<button name=b class=button type=button ></button>
<label style="display: flex; align-items: center;">
<input id='dot' name=i type=range min=0 max=${
values.length - 1
} value=${initial} step=1 style="width: 0px;">
<output name=o style="margin-left: 0.4em;"></output>
</label>
</form>`;
let frame = null;
let timer = null;
let interval = null;
let direction = 1;
function start() {
form.b.classList.add("paused");
if (delay === null) frame = requestAnimationFrame(tick);
else interval = setInterval(tick, delay);
}
function stop() {
form.b.classList.remove("paused");
if (frame !== null) cancelAnimationFrame(frame), (frame = null);
if (timer !== null) clearTimeout(timer), (timer = null);
if (interval !== null) clearInterval(interval), (interval = null);
}
function running() {
return frame !== null || timer !== null || interval !== null;
}
console.log(form.i.value);
function tick() {
if (
form.i.valueAsNumber ===
(direction > 0 ? values.length - 1 : direction < 0 ? 0 : NaN)
) {
if (!loop) return stop();
if (alternate) direction = -direction;
if (loopDelay !== null) {
if (frame !== null) cancelAnimationFrame(frame), (frame = null);
if (interval !== null) clearInterval(interval), (interval = null);
timer = setTimeout(() => (step(), start()), loopDelay);
return;
}
}
if (delay === null) frame = requestAnimationFrame(tick);
step();
}
function step() {
form.i.valueAsNumber =
(form.i.valueAsNumber + direction + values.length) % values.length;
form.i.dispatchEvent(new CustomEvent("input", { bubbles: true }));
}
form.i.oninput = (event) => {
if (event && event.isTrusted && running()) stop();
form.value = values[form.i.valueAsNumber];
form.o.value = format(form.value, form.i.valueAsNumber, values);
};
form.b.onclick = () => {
if (running()) return stop();
direction =
alternate && form.i.valueAsNumber === values.length - 1 ? -1 : 1;
form.i.valueAsNumber = (form.i.valueAsNumber + direction) % values.length;
form.i.dispatchEvent(new CustomEvent("input", { bubbles: true }));
start();
};
form.i.oninput();
if (autoplay) start();
else stop();
Inputs.disposal(form).then(stop);
return form;
}