function Tangle({
min = -Infinity,
max = Infinity,
minWidth = undefined,
step = 1,
power = 1.2,
value = 50,
format = x => x.toLocaleString("en")
} = {}) {
const target = document.createElement("span");
Object.defineProperties(target, {
value: {
set(v) {
value = Math.max(min, Math.min(max, Math.floor(v / step) * step));
target.textContent = format(value);
},
get() {
return value;
}
}
});
if (value !== undefined) {
target.value = value;
}
if (minWidth !== undefined) {
target.style.minWidth = minWidth;
target.style.textAlign = "right";
target.style.display = "inline-block";
}
target.style.borderBottom = "dotted 1px currentColor";
target.style.cursor = "ew-resize";
target.style.touchAction = "none";
target.onselectstart = event => event.preventDefault();
target.ontouchstart = event => event.preventDefault();
target.onpointerdown = event => {
const startValue = value;
const {clientX: startX, clientY: startY, pointerId} = event;
const container = target.closest(".observablehq");
const onpointermove = (event) => {
const {clientX, clientY} = event;
const v0 = target.value;
const distance = clientX - startX + startY - clientY;
target.value = startValue + Math.abs(distance) ** power * Math.sign(distance) * step / delta;
const v1 = target.value;
if (v0 !== v1) target.dispatchEvent(new Event("input", {bubbles: true}));
};
const onpointerup = (event) => {
container.releasePointerCapture(pointerId);
container.removeEventListener("pointermove", onpointermove);
container.removeEventListener("pointercancel", onpointercancel);
container.removeEventListener("pointerup", onpointerup);
};
container.addEventListener("pointermove", onpointermove);
container.addEventListener("pointercancel", onpointerup);
container.addEventListener("pointerup", onpointerup);
container.setPointerCapture(pointerId);
};
return target;
}