UNPKG

react-window

Version:

<img src="https://react-window.vercel.app/og.svg" alt="react-window logo" width="400" height="210" />

959 lines (958 loc) 20.3 kB
"use client"; import { jsx as ee } from "react/jsx-runtime"; import { useState as M, useLayoutEffect as re, useEffect as J, useMemo as A, useRef as K, useCallback as D, memo as le, useImperativeHandle as ce, createElement as X } from "react"; function xe(e) { let t = e; for (; t; ) { if (t.dir) return t.dir === "rtl"; t = t.parentElement; } return !1; } function ve(e, t) { const [s, r] = M(t === "rtl"); return re(() => { e && (t || r(xe(e))); }, [t, e]), s; } const q = typeof window < "u" ? re : J; function ie(e) { if (e !== void 0) switch (typeof e) { case "number": return e; case "string": { if (e.endsWith("px")) return parseFloat(e); break; } } } function be({ box: e, defaultHeight: t, defaultWidth: s, disabled: r, element: n, mode: o, style: i }) { const { styleHeight: f, styleWidth: l } = A( () => ({ styleHeight: ie(i?.height), styleWidth: ie(i?.width) }), [i?.height, i?.width] ), [a, d] = M({ height: t, width: s }), c = r || o === "only-height" && f !== void 0 || o === "only-width" && l !== void 0 || f !== void 0 && l !== void 0; return q(() => { if (n === null || c) return; const h = new ResizeObserver((p) => { for (const I of p) { const { contentRect: u, target: w } = I; n === w && d((m) => m.height === u.height && m.width === u.width ? m : { height: u.height, width: u.width }); } }); return h.observe(n, { box: e }), () => { h?.unobserve(n); }; }, [e, c, n, f, l]), A( () => ({ height: f ?? a.height, width: l ?? a.width }), [a, f, l] ); } function ae(e) { const t = K(() => { throw new Error("Cannot call during render."); }); return q(() => { t.current = e; }, [e]), D((s) => t.current?.(s), [t]); } let U = null; function Ie(e = !1) { if (U === null || e) { const t = document.createElement("div"), s = t.style; s.width = "50px", s.height = "50px", s.overflow = "scroll", s.direction = "rtl"; const r = document.createElement("div"), n = r.style; return n.width = "100px", n.height = "100px", t.appendChild(r), document.body.appendChild(t), t.scrollLeft > 0 ? U = "positive-descending" : (t.scrollLeft = 1, t.scrollLeft === 0 ? U = "negative" : U = "positive-ascending"), document.body.removeChild(t), U; } return U; } function Z({ containerElement: e, direction: t, isRtl: s, scrollOffset: r }) { if (t === "horizontal" && s) switch (Ie()) { case "negative": return -r; case "positive-descending": { if (e) { const { clientWidth: n, scrollLeft: o, scrollWidth: i } = e; return i - n - o; } break; } } return r; } function L(e, t = "Assertion error") { if (!e) throw console.error(t), Error(t); } function Y(e, t) { if (e === t) return !0; if (!!e != !!t || (L(e !== void 0), L(t !== void 0), Object.keys(e).length !== Object.keys(t).length)) return !1; for (const s in e) if (!Object.is(t[s], e[s])) return !1; return !0; } function fe({ cachedBounds: e, itemCount: t, itemSize: s }) { if (t === 0) return 0; if (typeof s == "number") return t * s; { const r = e.get( e.size === 0 ? 0 : e.size - 1 ); L(r !== void 0, "Unexpected bounds cache miss"); const n = (r.scrollOffset + r.size) / e.size; return t * n; } } function we({ align: e, cachedBounds: t, index: s, itemCount: r, itemSize: n, containerScrollOffset: o, containerSize: i }) { if (s < 0 || s >= r) throw RangeError(`Invalid index specified: ${s}`, { cause: `Index ${s} is not within the range of 0 - ${r - 1}` }); const f = fe({ cachedBounds: t, itemCount: r, itemSize: n }), l = t.get(s), a = Math.max( 0, Math.min(f - i, l.scrollOffset) ), d = Math.max( 0, l.scrollOffset - i + l.size ); switch (e === "smart" && (o >= d && o <= a ? e = "auto" : e = "center"), e) { case "start": return a; case "end": return d; case "center": return l.scrollOffset <= i / 2 ? 0 : l.scrollOffset + l.size / 2 >= f - i / 2 ? f - i : l.scrollOffset + l.size / 2 - i / 2; case "auto": default: return o >= d && o <= a ? o : o < d ? d : a; } } function P({ cachedBounds: e, containerScrollOffset: t, containerSize: s, itemCount: r, overscanCount: n }) { const o = r - 1; let i = 0, f = -1, l = 0, a = -1, d = 0; for (; d < o; ) { const c = e.get(d); if (c.scrollOffset + c.size > t) break; d++; } for (i = d, l = Math.max(0, i - n); d < o; ) { const c = e.get(d); if (c.scrollOffset + c.size >= t + s) break; d++; } return f = Math.min(o, d), a = Math.min(r - 1, f + n), i < 0 && (i = 0, f = -1, l = 0, a = -1), { startIndexVisible: i, stopIndexVisible: f, startIndexOverscan: l, stopIndexOverscan: a }; } function me({ itemCount: e, itemProps: t, itemSize: s }) { const r = /* @__PURE__ */ new Map(); return { get(n) { for (L(n < e, `Invalid index ${n}`); r.size - 1 < n; ) { const i = r.size; let f; switch (typeof s) { case "function": { f = s(i, t); break; } case "number": { f = s; break; } } if (i === 0) r.set(i, { size: f, scrollOffset: 0 }); else { const l = r.get(i - 1); L( l !== void 0, `Unexpected bounds cache miss for index ${n}` ), r.set(i, { scrollOffset: l.scrollOffset + l.size, size: f }); } } const o = r.get(n); return L( o !== void 0, `Unexpected bounds cache miss for index ${n}` ), o; }, set(n, o) { r.set(n, o); }, get size() { return r.size; } }; } function Oe({ itemCount: e, itemProps: t, itemSize: s }) { return A( () => me({ itemCount: e, itemProps: t, itemSize: s }), [e, t, s] ); } function ye({ containerSize: e, itemSize: t }) { let s; switch (typeof t) { case "string": { L( t.endsWith("%"), `Invalid item size: "${t}"; string values must be percentages (e.g. "100%")` ), L( e !== void 0, "Container size must be defined if a percentage item size is specified" ), s = e * parseInt(t) / 100; break; } default: { s = t; break; } } return s; } function te({ containerElement: e, containerStyle: t, defaultContainerSize: s = 0, direction: r, isRtl: n = !1, itemCount: o, itemProps: i, itemSize: f, onResize: l, overscanCount: a }) { const { height: d = s, width: c = s } = be({ defaultHeight: r === "vertical" ? s : void 0, defaultWidth: r === "horizontal" ? s : void 0, element: e, mode: r === "vertical" ? "only-height" : "only-width", style: t }), h = K({ height: 0, width: 0 }), p = r === "vertical" ? d : c, I = ye({ containerSize: p, itemSize: f }); re(() => { if (typeof l == "function") { const g = h.current; (g.height !== d || g.width !== c) && (l({ height: d, width: c }, { ...g }), g.height = d, g.width = c); } }, [d, l, c]); const u = Oe({ itemCount: o, itemProps: i, itemSize: I }), w = D( (g) => u.get(g), [u] ), [m, O] = M( () => P({ cachedBounds: u, // TODO Potentially support a defaultScrollOffset prop? containerScrollOffset: 0, containerSize: p, itemCount: o, overscanCount: a }) ), { startIndexVisible: G, startIndexOverscan: x, stopIndexVisible: F, stopIndexOverscan: V } = { startIndexVisible: Math.min(o - 1, m.startIndexVisible), startIndexOverscan: Math.min(o - 1, m.startIndexOverscan), stopIndexVisible: Math.min(o - 1, m.stopIndexVisible), stopIndexOverscan: Math.min(o - 1, m.stopIndexOverscan) }, z = D( () => fe({ cachedBounds: u, itemCount: o, itemSize: I }), [u, o, I] ), $ = D( (g) => { const S = Z({ containerElement: e, direction: r, isRtl: n, scrollOffset: g }); return P({ cachedBounds: u, containerScrollOffset: S, containerSize: p, itemCount: o, overscanCount: a }); }, [ u, e, p, r, n, o, a ] ); q(() => { const g = (r === "vertical" ? e?.scrollTop : e?.scrollLeft) ?? 0; O($(g)); }, [e, r, $]), q(() => { if (!e) return; const g = () => { O((S) => { const { scrollLeft: E, scrollTop: b } = e, v = Z({ containerElement: e, direction: r, isRtl: n, scrollOffset: r === "vertical" ? b : E }), R = P({ cachedBounds: u, containerScrollOffset: v, containerSize: p, itemCount: o, overscanCount: a }); return Y(R, S) ? S : R; }); }; return e.addEventListener("scroll", g), () => { e.removeEventListener("scroll", g); }; }, [ u, e, p, r, o, a ]); const y = ae( ({ align: g = "auto", containerScrollOffset: S, index: E }) => { let b = we({ align: g, cachedBounds: u, containerScrollOffset: S, containerSize: p, index: E, itemCount: o, itemSize: I }); if (e) { if (b = Z({ containerElement: e, direction: r, isRtl: n, scrollOffset: b }), typeof e.scrollTo != "function") { const v = $(b); Y(m, v) || O(v); } return b; } } ); return { getCellBounds: w, getEstimatedSize: z, scrollToIndex: y, startIndexOverscan: x, startIndexVisible: G, stopIndexOverscan: V, stopIndexVisible: F }; } function de(e) { return A(() => e, Object.values(e)); } function ue(e, t) { const { ariaAttributes: s, style: r, ...n } = e, { ariaAttributes: o, style: i, ...f } = t; return Y(s, o) && Y(r, i) && Y(n, f); } function Ee({ cellComponent: e, cellProps: t, children: s, className: r, columnCount: n, columnWidth: o, defaultHeight: i = 0, defaultWidth: f = 0, dir: l, gridRef: a, onCellsRendered: d, onResize: c, overscanCount: h = 3, rowCount: p, rowHeight: I, style: u, tagName: w = "div", ...m }) { const O = de(t), G = A( () => le(e, ue), [e] ), [x, F] = M(null), V = ve(x, l), { getCellBounds: z, getEstimatedSize: $, startIndexOverscan: y, startIndexVisible: g, scrollToIndex: S, stopIndexOverscan: E, stopIndexVisible: b } = te({ containerElement: x, containerStyle: u, defaultContainerSize: f, direction: "horizontal", isRtl: V, itemCount: n, itemProps: O, itemSize: o, onResize: c, overscanCount: h }), { getCellBounds: v, getEstimatedSize: R, startIndexOverscan: k, startIndexVisible: ne, scrollToIndex: Q, stopIndexOverscan: _, stopIndexVisible: oe } = te({ containerElement: x, containerStyle: u, defaultContainerSize: i, direction: "vertical", itemCount: p, itemProps: O, itemSize: I, onResize: c, overscanCount: h }); ce( a, () => ({ get element() { return x; }, scrollToCell({ behavior: H = "auto", columnAlign: T = "auto", columnIndex: W, rowAlign: B = "auto", rowIndex: j }) { const N = S({ align: T, containerScrollOffset: x?.scrollLeft ?? 0, index: W }), ge = Q({ align: B, containerScrollOffset: x?.scrollTop ?? 0, index: j }); typeof x?.scrollTo == "function" && x.scrollTo({ behavior: H, left: N, top: ge }); }, scrollToColumn({ align: H = "auto", behavior: T = "auto", index: W }) { const B = S({ align: H, containerScrollOffset: x?.scrollLeft ?? 0, index: W }); typeof x?.scrollTo == "function" && x.scrollTo({ behavior: T, left: B }); }, scrollToRow({ align: H = "auto", behavior: T = "auto", index: W }) { const B = Q({ align: H, containerScrollOffset: x?.scrollTop ?? 0, index: W }); typeof x?.scrollTo == "function" && x.scrollTo({ behavior: T, top: B }); } }), [x, S, Q] ), J(() => { y >= 0 && E >= 0 && k >= 0 && _ >= 0 && d && d( { columnStartIndex: g, columnStopIndex: b, rowStartIndex: ne, rowStopIndex: oe }, { columnStartIndex: y, columnStopIndex: E, rowStartIndex: k, rowStopIndex: _ } ); }, [ d, y, g, E, b, k, ne, _, oe ]); const he = A(() => { const H = []; if (n > 0 && p > 0) for (let T = k; T <= _; T++) { const W = v(T), B = []; for (let j = y; j <= E; j++) { const N = z(j); B.push( /* @__PURE__ */ X( G, { ...O, ariaAttributes: { "aria-colindex": j + 1, role: "gridcell" }, columnIndex: j, key: j, rowIndex: T, style: { position: "absolute", left: V ? void 0 : 0, right: V ? 0 : void 0, transform: `translate(${V ? -N.scrollOffset : N.scrollOffset}px, ${W.scrollOffset}px)`, height: W.size, width: N.size } } ) ); } H.push( /* @__PURE__ */ ee("div", { role: "row", "aria-rowindex": T + 1, children: B }, T) ); } return H; }, [ G, O, n, y, E, z, v, V, p, k, _ ]), pe = /* @__PURE__ */ ee( "div", { "aria-hidden": !0, style: { height: R(), width: $(), zIndex: -1 } } ); return X( w, { "aria-colcount": n, "aria-rowcount": p, role: "grid", ...m, className: r, dir: l, ref: F, style: { position: "relative", maxHeight: "100%", maxWidth: "100%", flexGrow: 1, overflow: "auto", ...u } }, he, s, pe ); } const Re = M, Ve = K; function ze(e) { return e != null && typeof e == "object" && "getAverageRowHeight" in e && typeof e.getAverageRowHeight == "function"; } const se = "data-react-window-index"; function Ae({ children: e, className: t, defaultHeight: s = 0, listRef: r, onResize: n, onRowsRendered: o, overscanCount: i = 3, rowComponent: f, rowCount: l, rowHeight: a, rowProps: d, tagName: c = "div", style: h, ...p }) { const I = de(d), u = A( () => le(f, ue), [f] ), [w, m] = M(null), O = ze(a), G = A(() => O ? (b) => a.getRowHeight(b) ?? a.getAverageRowHeight() : a, [O, a]), { getCellBounds: x, getEstimatedSize: F, scrollToIndex: V, startIndexOverscan: z, startIndexVisible: $, stopIndexOverscan: y, stopIndexVisible: g } = te({ containerElement: w, containerStyle: h, defaultContainerSize: s, direction: "vertical", itemCount: l, itemProps: I, itemSize: G, onResize: n, overscanCount: i }); ce( r, () => ({ get element() { return w; }, scrollToRow({ align: b = "auto", behavior: v = "auto", index: R }) { const k = V({ align: b, containerScrollOffset: w?.scrollTop ?? 0, index: R }); typeof w?.scrollTo == "function" && w.scrollTo({ behavior: v, top: k }); } }), [w, V] ), q(() => { if (!w) return; const b = Array.from(w.children).filter((v, R) => { if (v.hasAttribute("aria-hidden")) return !1; const k = `${z + R}`; return v.setAttribute(se, k), !0; }); if (O) return a.observeRowElements(b); }, [ w, O, a, z, y ]), J(() => { z >= 0 && y >= 0 && o && o( { startIndex: $, stopIndex: g }, { startIndex: z, stopIndex: y } ); }, [ o, z, $, y, g ]); const S = A(() => { const b = []; if (l > 0) for (let v = z; v <= y; v++) { const R = x(v); b.push( /* @__PURE__ */ X( u, { ...I, ariaAttributes: { "aria-posinset": v + 1, "aria-setsize": l, role: "listitem" }, key: v, index: v, style: { position: "absolute", left: 0, transform: `translateY(${R.scrollOffset}px)`, // In case of dynamic row heights, don't specify a height style // otherwise a default/estimated height would mask the actual height height: O ? void 0 : R.size, width: "100%" } } ) ); } return b; }, [ u, x, O, l, I, z, y ]), E = /* @__PURE__ */ ee( "div", { "aria-hidden": !0, style: { height: F(), width: "100%", zIndex: -1 } } ); return X( c, { role: "list", ...p, className: t, ref: m, style: { position: "relative", maxHeight: "100%", flexGrow: 1, overflowY: "auto", ...h } }, S, e, E ); } function ke({ defaultRowHeight: e, key: t }) { const [s, r] = M({ key: t, map: /* @__PURE__ */ new Map() }); s.key !== t && r({ key: t, map: /* @__PURE__ */ new Map() }); const { map: n } = s, o = D(() => { let c = 0; return n.forEach((h) => { c += h; }), c === 0 ? e : c / n.size; }, [e, n]), i = D( (c) => { const h = n.get(c); return h !== void 0 ? h : (n.set(c, e), e); }, [e, n] ), f = D((c, h) => { r((p) => { if (p.map.get(c) === h) return p; const I = new Map(p.map); return I.set(c, h), { ...p, map: I }; }); }, []), l = ae( (c) => { c.length !== 0 && c.forEach((h) => { const { borderBoxSize: p, target: I } = h, u = I.getAttribute(se); L( u !== null, `Invalid ${se} attribute value` ); const w = parseInt(u), { blockSize: m } = p[0]; m && f(w, m); }); } ), [a] = M( () => new ResizeObserver(l) ); J(() => () => { a.disconnect(); }, [a]); const d = D( (c) => (c.forEach((h) => a.observe(h)), () => { c.forEach((h) => a.unobserve(h)); }), [a] ); return A( () => ({ getAverageRowHeight: o, getRowHeight: i, setRowHeight: f, observeRowElements: d }), [o, i, f, d] ); } const Le = M, Me = K; let C = -1; function $e(e = !1) { if (C === -1 || e) { const t = document.createElement("div"), s = t.style; s.width = "50px", s.height = "50px", s.overflow = "scroll", document.body.appendChild(t), C = t.offsetWidth - t.clientWidth, document.body.removeChild(t); } return C; } export { Ee as Grid, Ae as List, $e as getScrollbarSize, ke as useDynamicRowHeight, Re as useGridCallbackRef, Ve as useGridRef, Le as useListCallbackRef, Me as useListRef }; //# sourceMappingURL=react-window.js.map