virtua
Version:
A zero-config, fast and small (~3kB) virtual list (and grid) component for React, Vue, Solid and Svelte.
775 lines (765 loc) • 26.7 kB
JavaScript
var e = require("vue");
const t = null, {min: r, max: o, abs: n, floor: s} = Math, i = (e, t, n) => r(n, o(t, e)), l = e => [ ...e ].sort((e, t) => e - t), c = "function" == typeof queueMicrotask ? queueMicrotask : e => {
Promise.resolve().then(e);
}, a = () => {
let e;
return [ new Promise(t => {
e = t;
}), e ];
}, u = e => {
let t;
return () => (e && (t = e(), e = void 0), t);
}, f = (e, t, r) => {
const o = r ? "unshift" : "push";
for (let r = 0; r < t; r++) e[o](-1);
return e;
}, d = (e, t) => {
const r = e.t[t];
return -1 === r ? e.o : r;
}, p = (e, t, o) => {
const n = -1 === e.t[t];
return e.t[t] = o, e.i = r(t, e.i), n;
}, m = (e, t) => {
if (!e.l) return 0;
if (e.i >= t) return e.u[t];
e.i < 0 && (e.u[0] = 0, e.i = 0);
let r = e.i, o = e.u[r];
for (;r < t; ) o += d(e, r), e.u[++r] = o;
return e.i = t, o;
}, h = (e, t, r = 0, o = e.l - 1) => {
let n = r;
for (;r <= o; ) {
const i = s((r + o) / 2);
m(e, i) <= t ? (n = i, r = i + 1) : o = i - 1;
}
return i(n, 0, e.l - 1);
}, _ = (e, t, o) => {
const n = t - e.l;
return e.i = o ? -1 : r(t - 1, e.i), e.l = t, n > 0 ? (f(e.u, n), f(e.t, n, o),
e.o * n) : (e.u.splice(n), (o ? e.t.splice(0, -n) : e.t.splice(n)).reduce((t, r) => t - (-1 === r ? e.o : r), 0));
}, b = e => e.documentElement, g = e => e.ownerDocument, v = e => e.defaultView, y = /*#__PURE__*/ u(() => !!/iP(hone|od|ad)/.test(navigator.userAgent) || "MacIntel" === navigator.platform && navigator.maxTouchPoints > 0), S = /*#__PURE__*/ u(() => "scrollBehavior" in b(document).style), z = (e, s = 40, i = 0, c, a = !1) => {
let u = !!i, b = 1, g = 0, v = 0, S = 0, z = 0, x = 0, $ = 0, w = 0, I = 0, O = t, k = [ 0, u ? o(i - 1, 0) : -1 ], j = 0, N = !1;
const q = ((e, t, n) => ({
o: t,
t: n ? f(n.slice(0, r(e, n.length)), o(0, e - n.length)) : f([], e),
l: e,
i: -1,
u: f([], e + 1)
}))(e, c ? c[1] : s, c && c[0]), B = new Set, T = () => S - v, M = () => T() + x + z, E = (e, t) => ((e, t, o, n) => {
if (n = r(n, e.l - 1), m(e, n) <= t) {
const r = h(e, o, n);
return [ h(e, t, n, r), r ];
}
{
const r = h(e, t, void 0, n);
return [ r, h(e, o, r) ];
}
})(q, e, t, k[0]), P = () => m(q, q.l), R = (e, t) => {
const r = m(q, e) - x;
return t ? P() - r - A(e) : r;
}, A = e => d(q, e), C = (e, t = -1) => q.t[e] === t, H = e => {
e && (y() && 0 !== w || O && 1 === I ? x += e : z += e);
};
return {
p: () => {
B.clear();
},
m: () => b,
h: () => (e => [ e.t.slice(), e.o ])(q),
v: (e = 200) => {
if (!N || u) return k;
let t, n;
if ($) [t, n] = k; else {
let s = o(0, M()), i = s + g;
a || (e = o(0, e), 1 !== w && (s -= e), 2 !== w && (i += e)), [t, n] = k = E(o(0, s), o(0, i)),
O && (t = r(t, O[0]), n = o(n, O[1]));
}
return [ o(t, 0), r(n, q.l - 1) ];
},
S: e => h(q, e - v),
I: C,
O: R,
k: A,
j: () => q.l,
N: () => S,
q: () => 0 !== w,
B: () => g,
T: () => v,
M: P,
P: () => ($ = z, z = 0, [ $, 2 === I ]),
R: (e, t) => {
const r = [ e, t ];
return B.add(r), () => {
B.delete(r);
};
},
A: (e, r) => {
let s, i, c = 0;
switch (e) {
case 1:
{
if (r === S && 0 === I) break;
const e = $;
$ = 0;
const t = r - S, o = n(t);
e && o < n(e) + 1 || 0 !== I || (w = t < 0 ? 2 : 1), u && (u = !1), S = r, c = 4;
const s = T();
s >= -g && s <= P() && (c += 1, i = o > g);
break;
}
case 2:
c = 8, 0 !== w && (s = !0, c += 1), w = 0, I = 0, O = t;
break;
case 3:
{
const e = r.filter(([e, t]) => !C(e, t));
if (!e.length) break;
H(e.reduce((e, [t, r]) => {
let o;
if (2 === I) o = !0; else if (O && 1 === I) o = t < O[0]; else {
const e = T(), r = R(t), n = A(t);
o = 1 !== w && 0 === I ? r + n < e : r < e && r + n < e + g;
}
return o && (e += r - A(t)), e;
}, 0));
for (const [t, r] of e) {
const e = A(t), o = p(q, t, r);
a && (j += o ? r : r - e);
}
a && g && j > g && (H(((e, t) => {
let r = 0;
const n = [];
e.t.forEach((e, o) => {
-1 !== e && (n.push(e), o < t && r++);
}), e.i = -1;
const s = l(n), i = s.length, c = i / 2 | 0, a = i % 2 == 0 ? (s[c - 1] + s[c]) / 2 : s[c], u = e.o;
return ((e.o = a) - u) * o(t - r, 0);
})(q, h(q, M()))), a = !1), c = 3, i = !0;
break;
}
case 4:
g !== r && (g || (N = i = !0), g = r, c = 3);
break;
case 5:
r[1] ? (H(_(q, r[0], !0)), I = 2, c = 1) : (_(q, r[0]), c = 1);
break;
case 6:
v = r;
break;
case 7:
I = 1;
break;
case 8:
O = E(r, r + g), c = 1;
}
c && (b = 1 + (2147483647 & b), s && x && (z += x, x = 0), B.forEach(([e, t]) => {
c & e && t(i);
}));
}
};
}, x = setTimeout, $ = (e, t) => t ? -e : e, w = (e, r, o, n, s, i) => {
const l = Date.now;
let c = 0, a = !1, u = !1, f = !1, d = !1;
const p = (() => {
let r;
const o = () => {
r != t && clearTimeout(r);
}, n = () => {
o(), r = x(() => {
r = t, (() => {
if (a || u) return a = !1, void p();
f = !1, e.A(2);
})();
}, 150);
};
return n.C = o, n;
})(), m = () => {
c = l(), f && (d = !0), i && e.A(6, i()), e.A(1, n()), p();
}, h = t => {
if (a || !e.q() || t.ctrlKey) return;
const r = l() - c;
150 > r && 50 < r && (o ? t.deltaX : t.deltaY) && (a = !0);
}, _ = () => {
u = !0, f = d = !1;
}, b = () => {
u = !1, y() && (f = !0);
};
return r.addEventListener("scroll", m), r.addEventListener("wheel", h, {
passive: !0
}), r.addEventListener("touchstart", _, {
passive: !0
}), r.addEventListener("touchend", b, {
passive: !0
}), {
H: () => {
r.removeEventListener("scroll", m), r.removeEventListener("wheel", h), r.removeEventListener("touchstart", _),
r.removeEventListener("touchend", b), p.C();
},
V: () => {
const [t, r] = e.P();
t && (s(t, r, d), d = !1, r && e.B() > e.M() && e.A(1, n()));
}
};
}, I = (e, t, r) => {
let o;
return [ async (n, s) => {
if (!await t()) return;
o && o();
const i = () => {
const [t, r] = a();
return o = () => {
r(!1);
}, e.B() && x(o, 150), [ t, e.R(2, () => {
r(!0);
}) ];
};
if (s && S()) e.A(8, n()), c(async () => {
for (;;) {
let t = !0;
for (let [r, o] = e.v(); r <= o; r++) if (e.I(r)) {
t = !1;
break;
}
if (t) break;
const [r, o] = i();
try {
if (!await r) return;
} finally {
o();
}
}
e.A(7), r(n(), s);
}); else for (;;) {
const [t, o] = i();
try {
if (e.A(7), r(n()), !await t) return;
} finally {
o();
}
}
}, () => {
o && o();
} ];
}, O = e => {
let t;
return {
F(r) {
(t || (t = new (v(g(r)).ResizeObserver)(e))).observe(r);
},
J(e) {
t.unobserve(e);
},
H() {
t && t.disconnect();
}
};
}, k = /*#__PURE__*/ e.defineComponent({
props: {
L: {
type: Object,
required: !0
},
W: {
type: Object,
required: !0
},
X: {
type: Object,
required: !0
},
Y: {
type: Function,
required: !0
},
D: {
type: Number,
required: !0
},
U: {
type: Boolean
},
G: {
type: Boolean
},
K: {
type: Boolean
},
Z: {
type: String,
required: !0
},
ee: Object
},
setup(t) {
const r = e.ref(), o = e.computed(() => t.L.value && t.W.O(t.D, t.K)), n = e.computed(() => t.L.value && t.W.I(t.D));
return e.watch(() => r.value && t.D, (e, o, n) => {
n(t.Y(r.value, t.D));
}, {
flush: "post"
}), () => {
const {X: s, U: i, G: l, Z: c} = t, a = n.value, {style: u, ...f} = t.ee ?? {}, d = {
contain: "layout style",
position: a && l ? void 0 : "absolute",
[i ? "height" : "width"]: "100%",
[i ? "top" : "left"]: "0px",
[i ? "left" : "top"]: o.value + "px",
visibility: !a || l ? void 0 : "hidden",
...u
};
return i && (d.display = "inline-flex"), e.createVNode(c, e.mergeProps({
ref: r,
style: d
}, f), "function" == typeof (p = s) || "[object Object]" === Object.prototype.toString.call(p) && !e.isVNode(p) ? s : {
default: () => [ s ],
_: 2
}, 16, [ "style" ]);
var p;
};
}
}), j = (e, t) => {
if (1 === e.length) {
const t = e[0].key;
if (null != t) return t;
}
return "_" + t;
}, N = (e, t) => e[0] === t[0] && e[1] === t[1], q = /*#__PURE__*/ e.defineComponent({
props: {
data: {
type: Array,
required: !0
},
bufferSize: Number,
itemSize: Number,
shift: Boolean,
horizontal: Boolean,
startMargin: {
type: Number,
default: 0
},
ssrCount: Number,
scrollRef: Object,
as: {
type: String,
default: "div"
},
item: {
type: String,
default: "div"
},
itemProps: Function,
keepMounted: Array,
cache: Object
},
emits: [ "scroll", "scrollEnd" ],
setup(r, {emit: n, expose: s, slots: c}) {
let u = !!r.ssrCount;
const f = r.horizontal, d = e.ref(), p = z(r.data.length, r.itemSize, r.ssrCount, r.cache, !r.itemSize), m = ((e, r) => {
let o;
const n = r ? "width" : "height", s = new WeakMap, i = O(r => {
const i = [];
for (const {target: l, contentRect: c} of r) if (l.offsetParent) if (l === o) e.A(4, c[n]); else {
const e = s.get(l);
e != t && i.push([ e, c[n] ]);
}
i.length && e.A(3, i);
});
return {
te(e) {
i.F(o = e);
},
re: (e, t) => (s.set(e, t), i.F(e), () => {
s.delete(e), i.J(e);
}),
p: i.H
};
})(p, f), h = ((e, t) => {
let r, o, n = a(), s = !1;
const l = t ? "scrollLeft" : "scrollTop", c = t ? "overflowX" : "overflowY", [u, f] = I(e, () => n[0], (e, o) => {
e = $(e, s), o ? r.scrollTo({
[t ? "left" : "top"]: e,
behavior: "smooth"
}) : r[l] = e;
});
return {
oe(i, a) {
r = a, t && (s = "rtl" === getComputedStyle(a).direction), o = w(e, a, t, () => $(a[l], s), (t, r, o) => {
if (o) {
const e = a.style, t = e[c];
e[c] = "hidden", x(() => {
e[c] = t;
});
}
a[l] = $(e.N() + t, s), r && f();
}), n[1](!0);
},
p() {
o && o.H(), n[1](!1), n = a();
},
ne: () => s,
se(e) {
u(() => e);
},
ie(t) {
t += e.N(), u(() => t);
},
le(t, {align: r, smooth: o, offset: n = 0} = {}) {
if (t = i(t, 0, e.j() - 1), "nearest" === r) {
const o = e.O(t), n = e.N();
if (o < n) r = "start"; else {
if (!(o + e.k(t) > n + e.B())) return;
r = "end";
}
}
u(() => n + e.T() + e.O(t) + ("end" === r ? e.k(t) - e.B() : "center" === r ? (e.k(t) - e.B()) / 2 : 0), o);
},
ce: () => {
o && o.V();
}
};
})(p, f), _ = e.ref(p.m());
p.R(1, () => {
_.value = p.m();
}), p.R(4, () => {
n("scroll", p.N());
}), p.R(8, () => {
n("scrollEnd");
});
const b = e.computed(e => {
_.value;
const t = p.v(r.bufferSize);
return e && N(e, t) ? e : t;
}), g = e.computed(() => _.value && p.q()), v = e.computed(() => _.value && p.M());
return e.onMounted(() => {
u = !1;
const t = d.value, o = requestAnimationFrame(() => {
const e = e => {
m.te(e), h.oe(t, e);
};
r.scrollRef ? e(r.scrollRef) : e(t.parentElement);
});
e.onUnmounted(() => {
cancelAnimationFrame(o);
});
}), e.onUnmounted(() => {
p.p(), m.p(), h.p();
}), e.watch(() => r.data.length, e => {
p.A(5, [ e, r.shift ]);
}), e.watch(() => r.startMargin, e => {
p.A(6, e);
}, {
immediate: !0
}), e.watch([ _ ], () => {
h.ce();
}, {
flush: "post"
}), s({
get cache() {
return p.h();
},
get scrollOffset() {
return p.N();
},
get scrollSize() {
return (e => o(e.M(), e.B()))(p);
},
get viewportSize() {
return p.B();
},
findItemIndex: p.S,
getItemOffset: p.O,
getItemSize: p.k,
scrollToIndex: h.le,
scrollTo: h.se,
scrollBy: h.ie
}), () => {
const t = r.as, o = r.item, n = v.value, s = h.ne(), i = [], a = t => {
const n = c.default({
item: r.data[t],
index: t
});
return e.createVNode(k, {
key: j(n, t),
L: _,
W: p,
Y: m.re,
D: t,
X: n,
U: f,
K: s,
G: u,
Z: o,
ee: r.itemProps?.({
item: r.data[t],
index: t
})
}, null, 8, [ "_stateVersion", "_store", "_resizer", "_index", "_children", "_isHorizontal", "_isNegative", "_isSSR", "_as", "_itemProps" ]);
};
if (r.keepMounted) {
const e = new Set(r.keepMounted);
for (let [t, r] = b.value; t <= r; t++) e.add(t);
l([ ...e ]).forEach(e => {
i.push(a(e));
});
} else for (let [e, t] = b.value; e <= t; e++) i.push(a(e));
return e.createVNode(t, {
ref: d,
style: {
contain: "size style",
overflowAnchor: "none",
flex: "none",
position: "relative",
width: f ? n + "px" : "100%",
height: f ? "100%" : n + "px",
pointerEvents: g.value ? "none" : void 0
}
}, "function" == typeof (y = i) || "[object Object]" === Object.prototype.toString.call(y) && !e.isVNode(y) ? i : {
default: () => [ i ],
_: 2
}, 8, [ "style" ]);
var y;
};
}
}), B = /*#__PURE__*/ e.defineComponent({
props: {
data: {
type: Array,
required: !0
},
bufferSize: Number,
itemSize: Number,
shift: Boolean,
horizontal: Boolean,
ssrCount: Number,
itemProps: Function,
keepMounted: Array,
cache: Object
},
emits: [ "scroll", "scrollEnd" ],
setup(t, {emit: r, expose: o, slots: n}) {
const s = t.horizontal, i = e => {
r("scroll", e);
}, l = () => {
r("scrollEnd");
}, c = e.ref();
return o({
get cache() {
return c.value.cache;
},
get scrollOffset() {
return c.value.scrollOffset;
},
get scrollSize() {
return c.value.scrollSize;
},
get viewportSize() {
return c.value.viewportSize;
},
findItemIndex: (...e) => c.value.findItemIndex(...e),
getItemOffset: (...e) => c.value.getItemOffset(...e),
getItemSize: (...e) => c.value.getItemSize(...e),
scrollToIndex: (...e) => c.value.scrollToIndex(...e),
scrollTo: (...e) => c.value.scrollTo(...e),
scrollBy: (...e) => c.value.scrollBy(...e)
}), () => {
return e.createVNode("div", {
style: {
display: s ? "inline-block" : "block",
[s ? "overflowX" : "overflowY"]: "auto",
contain: "strict",
width: "100%",
height: "100%"
}
}, [ e.createVNode(q, {
ref: c,
data: t.data,
bufferSize: t.bufferSize,
itemSize: t.itemSize,
itemProps: t.itemProps,
shift: t.shift,
ssrCount: t.ssrCount,
horizontal: s,
keepMounted: t.keepMounted,
cache: t.cache,
onScroll: i,
onScrollEnd: l
}, (r = n, "function" == typeof r || "[object Object]" === Object.prototype.toString.call(r) && !e.isVNode(r) ? n : {
default: () => [ n ],
_: 2
}), 8, [ "data", "bufferSize", "itemSize", "itemProps", "shift", "ssrCount", "horizontal", "keepMounted", "cache", "onScroll", "onScrollEnd" ]) ], 4);
var r;
};
}
}), T = /*#__PURE__*/ e.defineComponent({
props: {
data: {
type: Array,
required: !0
},
bufferSize: Number,
itemSize: Number,
shift: Boolean,
horizontal: Boolean,
as: {
type: String,
default: "div"
},
item: {
type: String,
default: "div"
},
cache: Object
},
emits: [ "scroll", "scrollEnd" ],
setup(r, {emit: o, slots: n, expose: s}) {
const l = r.horizontal, u = e.ref(), f = z(r.data.length, r.itemSize, void 0, r.cache, !r.itemSize), d = ((e, r) => {
const o = r ? "width" : "height", n = r ? "innerWidth" : "innerHeight", s = new WeakMap, i = O(r => {
const n = [];
for (const {target: e, contentRect: i} of r) {
if (!e.offsetParent) continue;
const r = s.get(e);
r != t && n.push([ r, i[o] ]);
}
n.length && e.A(3, n);
});
let l;
return {
te(t) {
const r = v(g(t)), o = () => {
e.A(4, r[n]);
};
r.addEventListener("resize", o), c(o), l = () => {
r.removeEventListener("resize", o);
};
},
re: (e, t) => (s.set(e, t), i.F(e), () => {
s.delete(e), i.J(e);
}),
p() {
l && l(), i.H();
}
};
})(f, l), p = ((e, t) => {
let r, o, n = a(), s = !1;
const l = t ? "left" : "top", [c] = I(e, () => n[0], (e, t) => {
e = $(e, s);
const o = v(g(r));
t ? o.scroll({
[l]: e,
behavior: "smooth"
}) : o.scroll({
[l]: e
});
}), u = (e, t, r, o, n = 0) => {
const i = o ? "offsetLeft" : "offsetTop", l = n + (o && s ? r.innerWidth - e[i] - e.offsetWidth : e[i]), c = e.offsetParent;
return e !== t && c ? u(c, t, r, o, l) : l;
};
return {
oe(i) {
r = i;
const c = t ? "scrollX" : "scrollY", a = g(i), f = v(a);
t && (s = "rtl" === getComputedStyle(b(a)).direction), o = w(e, f, t, () => $(f[c], s), (t, r) => {
r ? f.scroll({
[l]: $(e.N() + t, s)
}) : f.scrollBy({
[l]: $(t, s)
});
}, () => u(i, a.body, f, t)), n[1](!0);
},
p() {
o && o.H(), r = void 0, n[1](!1), n = a();
},
ne: () => s,
ce: () => {
o && o.V();
},
le(o, {align: n, smooth: s, offset: l = 0} = {}) {
if (!r) return;
if (o = i(o, 0, e.j() - 1), "nearest" === n) {
const t = e.O(o), r = e.N();
if (t < r) n = "start"; else {
if (!(t + e.k(o) > r + e.B())) return;
n = "end";
}
}
const a = g(r), f = v(a), d = b(a), p = () => e.B() - (t ? d.clientWidth : d.clientHeight);
c(() => l + u(r, a.body, f, t) + e.O(o) + ("end" === n ? e.k(o) - (e.B() - p()) : "center" === n ? (e.k(o) - (e.B() - p())) / 2 : 0), s);
}
};
})(f, l), m = e.ref(f.m());
f.R(1, () => {
m.value = f.m();
}), f.R(4, () => {
o("scroll");
}), f.R(8, () => {
o("scrollEnd");
});
const h = e.computed(e => {
m.value;
const t = f.v(r.bufferSize);
return e && N(e, t) ? e : t;
}), _ = e.computed(() => m.value && f.q()), y = e.computed(() => m.value && f.M());
return e.onMounted(() => {
const e = u.value;
e && (d.te(e), p.oe(e));
}), e.onUnmounted(() => {
f.p(), d.p(), p.p();
}), e.watch(() => r.data.length, e => {
f.A(5, [ e, r.shift ]);
}), e.watch([ m ], () => {
p.ce();
}, {
flush: "post"
}), s({
get cache() {
return f.h();
},
get scrollOffset() {
return f.N();
},
get viewportSize() {
return f.B();
},
findItemIndex: f.S,
getItemOffset: f.O,
getItemSize: f.k,
scrollToIndex: p.le
}), () => {
const t = r.as, o = r.item, s = y.value, i = p.ne(), c = [];
for (let [t, s] = h.value; t <= s; t++) {
const s = n.default({
item: r.data[t],
index: t
});
c.push(e.createVNode(k, {
key: j(s, t),
L: m,
W: f,
Y: d.re,
D: t,
X: s,
U: l,
K: i,
Z: o
}, null, 8, [ "_stateVersion", "_store", "_resizer", "_index", "_children", "_isHorizontal", "_isNegative", "_as" ]));
}
return e.createVNode(t, {
ref: u,
style: {
contain: "size style",
overflowAnchor: "none",
flex: "none",
position: "relative",
width: l ? s + "px" : "100%",
height: l ? "100%" : s + "px",
pointerEvents: _.value ? "none" : void 0
}
}, "function" == typeof (a = c) || "[object Object]" === Object.prototype.toString.call(a) && !e.isVNode(a) ? c : {
default: () => [ c ],
_: 2
}, 8, [ "style" ]);
var a;
};
}
});
exports.VList = B, exports.Virtualizer = q, exports.WindowVirtualizer = T;
//# sourceMappingURL=index.cjs.map