virtua
Version:
A zero-config, fast and small (~3kB) virtual list (and grid) component for React, Vue, Solid and Svelte.
701 lines (686 loc) • 23 kB
JavaScript
import { createComponent as e, Dynamic as t, spread as r, mergeProps as n, insert as o, template as s, use as i, effect as c, setStyleProperty as l } from "solid-js/web";
import { mergeProps as u, createEffect as f, createMemo as a, onCleanup as d, createSignal as g, onMount as h, createComputed as p, on as v, untrack as m, For as S, splitProps as $ } from "solid-js";
const b = null, {min: z, max: w, abs: x, floor: y} = Math, _ = (e, t, r) => z(r, w(t, e)), I = e => [ ...e ].sort((e, t) => e - t), k = "function" == typeof queueMicrotask ? queueMicrotask : e => {
Promise.resolve().then(e);
}, T = () => {
let e;
return [ new Promise(t => {
e = t;
}), e ];
}, M = e => {
let t;
return () => (e && (t = e(), e = void 0), t);
}, O = (e, t, r) => {
const n = r ? "unshift" : "push";
for (let r = 0; r < t; r++) e[n](-1);
return e;
}, R = (e, t) => {
const r = e.o[t];
return -1 === r ? e.i : r;
}, J = (e, t, r) => {
const n = -1 === e.o[t];
return e.o[t] = r, e.l = z(t, e.l), n;
}, P = (e, t) => {
if (!e.u) return 0;
if (e.l >= t) return e.h[t];
e.l < 0 && (e.h[0] = 0, e.l = 0);
let r = e.l, n = e.h[r];
for (;r < t; ) n += R(e, r), e.h[++r] = n;
return e.l = t, n;
}, B = (e, t, r = 0, n = e.u - 1) => {
let o = r;
for (;r <= n; ) {
const s = y((r + n) / 2);
P(e, s) <= t ? (o = s, r = s + 1) : n = s - 1;
}
return _(o, 0, e.u - 1);
}, C = (e, t, r) => {
const n = t - e.u;
return e.l = r ? -1 : z(t - 1, e.l), e.u = t, n > 0 ? (O(e.h, n), O(e.o, n, r),
e.i * n) : (e.h.splice(n), (r ? e.o.splice(0, -n) : e.o.splice(n)).reduce((t, r) => t - (-1 === r ? e.i : r), 0));
}, E = e => e.documentElement, H = e => e.ownerDocument, L = e => e.defaultView, W = /*#__PURE__*/ M(() => !!/iP(hone|od|ad)/.test(navigator.userAgent) || "MacIntel" === navigator.platform && navigator.maxTouchPoints > 0), j = /*#__PURE__*/ M(() => "scrollBehavior" in E(document).style), q = (e, t = 40, r = 0, n, o = !1) => {
let s = !!r, i = 1, c = 0, l = 0, u = 0, f = 0, a = 0, d = 0, g = 0, h = 0, p = b, v = [ 0, s ? w(r - 1, 0) : -1 ], m = 0, S = !1;
const $ = ((e, t, r) => ({
i: t,
o: r ? O(r.slice(0, z(e, r.length)), w(0, e - r.length)) : O([], e),
u: e,
l: -1,
h: O([], e + 1)
}))(e, n ? n[1] : t, n && n[0]), y = new Set, _ = () => u - l, k = () => _() + a + f, T = (e, t) => ((e, t, r, n) => {
if (n = z(n, e.u - 1), P(e, n) <= t) {
const o = B(e, r, n);
return [ B(e, t, n, o), o ];
}
{
const o = B(e, t, void 0, n);
return [ o, B(e, r, o) ];
}
})($, e, t, v[0]), M = () => P($, $.u), E = (e, t) => {
const r = P($, e) - a;
return t ? M() - r - H(e) : r;
}, H = e => R($, e), L = (e, t = -1) => $.o[e] === t, j = e => {
e && (W() && 0 !== g || p && 1 === h ? a += e : f += e);
};
return {
p: () => {
y.clear();
},
v: () => i,
m: () => (e => [ e.o.slice(), e.i ])($),
S: (e = 200) => {
if (!S || s) return v;
let t, r;
if (d) [t, r] = v; else {
let n = w(0, k()), s = n + c;
o || (e = w(0, e), 1 !== g && (n -= e), 2 !== g && (s += e)), [t, r] = v = T(w(0, n), w(0, s)),
p && (t = z(t, p[0]), r = w(r, p[1]));
}
return [ w(t, 0), z(r, $.u - 1) ];
},
$: e => B($, e - l),
_: L,
I: E,
k: H,
T: () => $.u,
M: () => u,
O: () => 0 !== g,
R: () => c,
J: () => l,
P: M,
B: () => (d = f, f = 0, [ d, 2 === h ]),
C: (e, t) => {
const r = [ e, t ];
return y.add(r), () => {
y.delete(r);
};
},
H: (e, t) => {
let r, n, v = 0;
switch (e) {
case 1:
{
if (t === u && 0 === h) break;
const e = d;
d = 0;
const r = t - u, o = x(r);
e && o < x(e) + 1 || 0 !== h || (g = r < 0 ? 2 : 1), s && (s = !1), u = t, v = 4;
const i = _();
i >= -c && i <= M() && (v += 1, n = o > c);
break;
}
case 2:
v = 8, 0 !== g && (r = !0, v += 1), g = 0, h = 0, p = b;
break;
case 3:
{
const e = t.filter(([e, t]) => !L(e, t));
if (!e.length) break;
j(e.reduce((e, [t, r]) => {
let n;
if (2 === h) n = !0; else if (p && 1 === h) n = t < p[0]; else {
const e = _(), r = E(t), o = H(t);
n = 1 !== g && 0 === h ? r + o < e : r < e && r + o < e + c;
}
return n && (e += r - H(t)), e;
}, 0));
for (const [t, r] of e) {
const e = H(t), n = J($, t, r);
o && (m += n ? r : r - e);
}
o && c && m > c && (j(((e, t) => {
let r = 0;
const n = [];
e.o.forEach((e, o) => {
-1 !== e && (n.push(e), o < t && r++);
}), e.l = -1;
const o = I(n), s = o.length, i = s / 2 | 0, c = s % 2 == 0 ? (o[i - 1] + o[i]) / 2 : o[i], l = e.i;
return ((e.i = c) - l) * w(t - r, 0);
})($, B($, k()))), o = !1), v = 3, n = !0;
break;
}
case 4:
c !== t && (c || (S = n = !0), c = t, v = 3);
break;
case 5:
t[1] ? (j(C($, t[0], !0)), h = 2, v = 1) : (C($, t[0]), v = 1);
break;
case 6:
l = t;
break;
case 7:
h = 1;
break;
case 8:
p = T(t, t + c), v = 1;
}
v && (i = 1 + (2147483647 & i), r && a && (f += a, a = 0), y.forEach(([e, t]) => {
v & e && t(n);
}));
}
};
}, N = setTimeout, V = (e, t) => t ? -e : e, X = (e, t, r, n, o, s) => {
const i = Date.now;
let c = 0, l = !1, u = !1, f = !1, a = !1;
const d = (() => {
let t;
const r = () => {
t != b && clearTimeout(t);
}, n = () => {
r(), t = N(() => {
t = b, (() => {
if (l || u) return l = !1, void d();
f = !1, e.H(2);
})();
}, 150);
};
return n.L = r, n;
})(), g = () => {
c = i(), f && (a = !0), s && e.H(6, s()), e.H(1, n()), d();
}, h = t => {
if (l || !e.O() || t.ctrlKey) return;
const n = i() - c;
150 > n && 50 < n && (r ? t.deltaX : t.deltaY) && (l = !0);
}, p = () => {
u = !0, f = a = !1;
}, v = () => {
u = !1, W() && (f = !0);
};
return t.addEventListener("scroll", g), t.addEventListener("wheel", h, {
passive: !0
}), t.addEventListener("touchstart", p, {
passive: !0
}), t.addEventListener("touchend", v, {
passive: !0
}), {
W: () => {
t.removeEventListener("scroll", g), t.removeEventListener("wheel", h), t.removeEventListener("touchstart", p),
t.removeEventListener("touchend", v), d.L();
},
j: () => {
const [t, r] = e.B();
t && (o(t, r, a), a = !1, r && e.R() > e.P() && e.H(1, n()));
}
};
}, Y = (e, t, r) => {
let n;
return [ async (o, s) => {
if (!await t()) return;
n && n();
const i = () => {
const [t, r] = T();
return n = () => {
r(!1);
}, e.R() && N(n, 150), [ t, e.C(2, () => {
r(!0);
}) ];
};
if (s && j()) e.H(8, o()), k(async () => {
for (;;) {
let t = !0;
for (let [r, n] = e.S(); r <= n; r++) if (e._(r)) {
t = !1;
break;
}
if (t) break;
const [r, n] = i();
try {
if (!await r) return;
} finally {
n();
}
}
e.H(7), r(o(), s);
}); else for (;;) {
const [t, n] = i();
try {
if (e.H(7), r(o()), !await t) return;
} finally {
n();
}
}
}, () => {
n && n();
} ];
}, D = e => {
let t;
return {
q(r) {
(t || (t = new (L(H(r)).ResizeObserver)(e))).observe(r);
},
N(e) {
t.unobserve(e);
},
W() {
t && t.disconnect();
}
};
}, U = r => {
let n;
r = u({
V: "div"
}, r), f(() => {
n && d(r.X(n, r.Y));
});
const o = a(() => {
const e = r.D, t = {
contain: "layout style",
position: "absolute",
[e ? "height" : "width"]: "100%",
[e ? "top" : "left"]: "0px",
[e ? "left" : "top"]: r.U + "px",
visibility: r.A ? "hidden" : void 0
};
return e && (t.display = "inline-flex"), t;
});
return e(t, {
get component() {
return r.V;
},
get index() {
return r.Y;
},
ref(e) {
"function" == typeof n ? n(e) : n = e;
},
get style() {
return o();
},
get children() {
return r.F;
}
});
}, A = (e, t) => e[0] === t[0] && e[1] === t[1], F = r => {
let n;
const {itemSize: o, horizontal: s = !1, cache: i} = r;
r = u({
as: "div"
}, r);
const c = q(r.data.length, o, void 0, i, !o), l = ((e, t) => {
let r;
const n = t ? "width" : "height", o = new WeakMap, s = D(t => {
const s = [];
for (const {target: i, contentRect: c} of t) if (i.offsetParent) if (i === r) e.H(4, c[n]); else {
const e = o.get(i);
e != b && s.push([ e, c[n] ]);
}
s.length && e.H(3, s);
});
return {
G(e) {
s.q(r = e);
},
K: (e, t) => (o.set(e, t), s.q(e), () => {
o.delete(e), s.N(e);
}),
p: s.W
};
})(c, s), $ = ((e, t) => {
let r, n, o = T(), s = !1;
const i = t ? "scrollLeft" : "scrollTop", c = t ? "overflowX" : "overflowY", [l, u] = Y(e, () => o[0], (e, n) => {
e = V(e, s), n ? r.scrollTo({
[t ? "left" : "top"]: e,
behavior: "smooth"
}) : r[i] = e;
});
return {
Z(l, f) {
r = f, t && (s = "rtl" === getComputedStyle(f).direction), n = X(e, f, t, () => V(f[i], s), (t, r, n) => {
if (n) {
const e = f.style, t = e[c];
e[c] = "hidden", N(() => {
e[c] = t;
});
}
f[i] = V(e.M() + t, s), r && u();
}), o[1](!0);
},
p() {
n && n.W(), o[1](!1), o = T();
},
ee: () => s,
te(e) {
l(() => e);
},
re(t) {
t += e.M(), l(() => t);
},
ne(t, {align: r, smooth: n, offset: o = 0} = {}) {
if (t = _(t, 0, e.T() - 1), "nearest" === r) {
const n = e.I(t), o = e.M();
if (n < o) r = "start"; else {
if (!(n + e.k(t) > o + e.R())) return;
r = "end";
}
}
l(() => o + e.J() + e.I(t) + ("end" === r ? e.k(t) - e.R() : "center" === r ? (e.k(t) - e.R()) / 2 : 0), n);
},
oe: () => {
n && n.j();
}
};
})(c, s), [z, x] = g(c.v());
c.C(1, () => {
x(c.v());
}), c.C(4, () => {
r.onScroll?.(c.M());
}), c.C(8, () => {
r.onScrollEnd?.();
});
const y = a(e => {
z();
const t = c.S(r.bufferSize);
return e && A(e, t) ? e : t;
}), k = a(() => z() && c.O()), M = a(() => z() && c.P()), O = a(() => z() && $.ee());
h(() => {
r.ref && r.ref({
get cache() {
return c.m();
},
get scrollOffset() {
return c.M();
},
get scrollSize() {
return (e => w(e.P(), e.R()))(c);
},
get viewportSize() {
return c.R();
},
findItemIndex: c.$,
getItemOffset: c.I,
getItemSize: c.k,
scrollToIndex: $.ne,
scrollTo: $.te,
scrollBy: $.re
});
const e = n, t = r.scrollRef || e.parentElement;
l.G(t), $.Z(e, t), d(() => {
r.ref && r.ref(), c.p(), l.p(), $.p();
});
}), p(v(() => r.startMargin || 0, e => {
e !== c.J() && c.H(6, e);
})), f(v(z, () => {
$.oe();
}));
const R = a(() => {
const e = r.data.length;
m(() => {
e !== c.T() && c.H(5, [ e, r.shift ]);
});
const t = [], n = [];
if (r.keepMounted) {
const e = new Set(r.keepMounted);
for (let [t, r] = y(); t <= r; t++) e.add(t);
I([ ...e ]).forEach(e => {
t.push(r.data[e]), n.push(e);
});
} else for (let [e, o] = y(); e <= o; e++) t.push(r.data[e]), n.push(e);
return {
se: t,
ie: n
};
});
return e(t, {
get component() {
return r.as;
},
ref(e) {
"function" == typeof n ? n(e) : n = e;
},
get style() {
return {
contain: "size style",
"overflow-anchor": "none",
flex: "none",
position: "relative",
width: s ? M() + "px" : "100%",
height: s ? "100%" : M() + "px",
"pointer-events": k() ? "none" : void 0
};
},
get children() {
return e(S, {
get each() {
return R().se;
},
children: (t, n) => ((t, n) => {
const o = a(() => (z(), c.I(n(), O()))), i = a(() => (z(), c._(n()))), u = a(() => m(() => r.children(t, n)));
return e(U, {
get V() {
return r.item;
},
get Y() {
return n();
},
get X() {
return l.K;
},
get U() {
return o();
},
get A() {
return i();
},
get F() {
return u();
},
D: s
});
})(t, a(() => R().ie[n()]))
});
}
});
};
var G = /*#__PURE__*/ s("<div>");
const K = t => {
const [s, i] = $(t, [ "ref", "data", "children", "bufferSize", "itemSize", "shift", "horizontal", "keepMounted", "cache", "item", "onScroll", "onScrollEnd", "style" ]);
return c = G(), r(c, n(i, {
get style() {
return {
display: s.horizontal ? "inline-block" : "block",
[s.horizontal ? "overflow-x" : "overflow-y"]: "auto",
contain: "strict",
width: "100%",
height: "100%",
...s.style
};
}
}), !1, !0), o(c, e(F, {
ref(e) {
var t = s.ref;
"function" == typeof t ? t(e) : s.ref = e;
},
get data() {
return s.data;
},
get bufferSize() {
return s.bufferSize;
},
get itemSize() {
return s.itemSize;
},
get shift() {
return s.shift;
},
get horizontal() {
return s.horizontal;
},
get keepMounted() {
return s.keepMounted;
},
get cache() {
return s.cache;
},
get item() {
return s.item;
},
get onScroll() {
return s.onScroll;
},
get onScrollEnd() {
return s.onScrollEnd;
},
get children() {
return s.children;
}
})), c;
var c;
};
var Q = /*#__PURE__*/ s('<div style="contain:size style;overflow-anchor:none;flex:none;position:relative">');
const Z = t => {
let r;
const {ref: n, data: s, children: u, itemSize: p, shift: $, horizontal: z = !1, cache: w, onScrollEnd: x} = t, y = q(t.data.length, p, void 0, w, !p), I = ((e, t) => {
const r = t ? "width" : "height", n = t ? "innerWidth" : "innerHeight", o = new WeakMap, s = D(t => {
const n = [];
for (const {target: e, contentRect: s} of t) {
if (!e.offsetParent) continue;
const t = o.get(e);
t != b && n.push([ t, s[r] ]);
}
n.length && e.H(3, n);
});
let i;
return {
G(t) {
const r = L(H(t)), o = () => {
e.H(4, r[n]);
};
r.addEventListener("resize", o), k(o), i = () => {
r.removeEventListener("resize", o);
};
},
K: (e, t) => (o.set(e, t), s.q(e), () => {
o.delete(e), s.N(e);
}),
p() {
i && i(), s.W();
}
};
})(y, z), M = ((e, t) => {
let r, n, o = T(), s = !1;
const i = t ? "left" : "top", [c] = Y(e, () => o[0], (e, t) => {
e = V(e, s);
const n = L(H(r));
t ? n.scroll({
[i]: e,
behavior: "smooth"
}) : n.scroll({
[i]: e
});
}), l = (e, t, r, n, o = 0) => {
const i = n ? "offsetLeft" : "offsetTop", c = o + (n && s ? r.innerWidth - e[i] - e.offsetWidth : e[i]), u = e.offsetParent;
return e !== t && u ? l(u, t, r, n, c) : c;
};
return {
Z(c) {
r = c;
const u = t ? "scrollX" : "scrollY", f = H(c), a = L(f);
t && (s = "rtl" === getComputedStyle(E(f)).direction), n = X(e, a, t, () => V(a[u], s), (t, r) => {
r ? a.scroll({
[i]: V(e.M() + t, s)
}) : a.scrollBy({
[i]: V(t, s)
});
}, () => l(c, f.body, a, t)), o[1](!0);
},
p() {
n && n.W(), r = void 0, o[1](!1), o = T();
},
ee: () => s,
oe: () => {
n && n.j();
},
ne(n, {align: o, smooth: s, offset: i = 0} = {}) {
if (!r) return;
if (n = _(n, 0, e.T() - 1), "nearest" === o) {
const t = e.I(n), r = e.M();
if (t < r) o = "start"; else {
if (!(t + e.k(n) > r + e.R())) return;
o = "end";
}
}
const u = H(r), f = L(u), a = E(u), d = () => e.R() - (t ? a.clientWidth : a.clientHeight);
c(() => i + l(r, u.body, f, t) + e.I(n) + ("end" === o ? e.k(n) - (e.R() - d()) : "center" === o ? (e.k(n) - (e.R() - d())) / 2 : 0), s);
}
};
})(y, z), [O, R] = g(y.v());
y.C(1, () => {
R(y.v());
}), y.C(4, () => {
t.onScroll?.();
}), y.C(8, () => {
t.onScrollEnd?.();
});
const J = a(e => {
O();
const r = y.S(t.bufferSize);
return e && A(e, r) ? e : r;
}), P = a(() => O() && y.O()), B = a(() => O() && y.P()), C = a(() => O() && M.ee());
h(() => {
t.ref && t.ref({
get cache() {
return y.m();
},
get scrollOffset() {
return y.M();
},
get viewportSize() {
return y.R();
},
findItemIndex: y.$,
getItemOffset: y.I,
getItemSize: y.k,
scrollToIndex: M.ne
}), I.G(r), M.Z(r), d(() => {
t.ref && t.ref(), y.p(), I.p(), M.p();
});
}), f(v(O, () => {
M.oe();
}));
const W = a(() => {
const e = t.data.length;
m(() => {
e !== y.T() && y.H(5, [ e, t.shift ]);
});
const r = [];
for (let [e, n] = J(); e <= n; e++) r.push(t.data[e]);
return r;
});
return j = Q(), "function" == typeof r ? i(r, j) : r = j, o(j, e(S, {
get each() {
return W();
},
children: (r, n) => {
const o = a(() => J()[0] + n()), s = a(() => (O(), y.I(o(), C()))), i = a(() => (O(),
y._(o()))), c = a(() => m(() => t.children(r, o)));
return e(U, {
get Y() {
return o();
},
get X() {
return I.K;
},
get U() {
return s();
},
get A() {
return i();
},
get F() {
return c();
},
D: z
});
}
})), c(e => {
var t = z ? B() + "px" : "100%", r = z ? "100%" : B() + "px", n = P() ? "none" : void 0;
return t !== e.e && l(j, "width", e.e = t), r !== e.t && l(j, "height", e.t = r),
n !== e.a && l(j, "pointer-events", e.a = n), e;
}, {
e: void 0,
t: void 0,
a: void 0
}), j;
var j;
};
export { K as VList, F as Virtualizer, Z as WindowVirtualizer };
//# sourceMappingURL=index.js.map