function ScrollInput(
data = d3.range(150),
{ height = `200px`, width = `100px`, type = "number" } = {}
) {
const padding_box = html`<div style="height: 50%; border: 1px dashed orange;"></div>`;
const child_style = `
font-family: monospace;
display: grid;
place-items: center;
scroll-snap-align: center;
`;
const children = data.map(
(d) => html`<div data-value=${d} style=${child_style}>${d}</div>`
);
const parent_style = `
height: 100%;
overflow: scroll;
scroll-snap-type: y mandatory;
overscroll-behavior: contain;
`;
const pad = () => html`<div style="height: 50%;"></div>`;
const scroll_box = html`<div id="scroll-box" style=${parent_style}>${pad()}${children}${pad()}</div>`;
const overlay_style = `
pointer-events: none;
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
border: 1px solid black;
`;
const overlay = html`<div style=${overlay_style}> </div>`;
const wrapper_style = `position: relative; height: ${height}; width: ${width}`;
const wrapper = html`<form style=${wrapper_style}>${scroll_box}${overlay}</form>`;
let value;
scroll_box.onscroll = (event) => {
event.stopPropagation();
event.preventDefault();
const rect = scroll_box.getBoundingClientRect();
const { x, y, width, height } = rect;
const middle = { x: x + width / 2, y: y + height / 2 };
const elem = document.elementFromPoint(middle.x, middle.y);
value = elem.dataset?.value;
wrapper.dispatchEvent(new CustomEvent("input"));
};
Object.defineProperty(wrapper, "value", {
get() {
return value;
},
set(v) {
value = v;
const child = scroll_box.querySelector(`div[data-value="${v}"]`);
const child_height = child.getBoundingClientRect().height;
const parent_height = scroll_box.getBoundingClientRect().height;
scroll_box.scrollTo({
behavior: `instant`,
top: child.offsetTop + child_height / 2 - parent_height / 2,
left: 0
});
}
});
return wrapper;
}