hightable
Version:
A dynamic windowed scrolling table component for react
1,355 lines (1,354 loc) • 45.2 kB
JavaScript
import { jsx as x, jsxs as X } from "react/jsx-runtime";
import { createContext as oe, useContext as Z, useEffect as G, useCallback as y, useState as $, useMemo as T, useRef as F, forwardRef as mt, useImperativeHandle as bt } from "react";
import { flushSync as xt } from "react-dom";
function mn(e) {
const t = e.then((n) => (t.resolved = n, n)).catch((n) => {
throw t.rejected = n, n;
});
return t;
}
function Ne(e) {
const t = Promise.resolve(e);
return t.resolved = e, t;
}
function je() {
let e, t;
const n = new Promise((r, i) => {
e = r, t = i;
});
return n.resolve = (r) => {
n.resolved = r, e(r);
}, n.reject = (r) => {
n.rejected = r, t(r);
}, n;
}
function Rt(e) {
return {
index: je(),
cells: Object.fromEntries(e.map((t) => [t, je()]))
};
}
function It(e, t, n) {
const r = new Array(t).fill(null).map(() => Rt(n));
return e.then((i) => {
i.length !== t && console.warn(`Expected ${t} rows, got ${i.length}`), i.forEach(
(o, s) => {
const l = r[s];
if (l === void 0)
throw new Error(`Expected row ${s} to exist`);
for (const c of n) {
const d = l.cells[c];
if (d === void 0)
throw new Error(`Expected cell ${c} to exist in row ${s}`);
o.cells[c] instanceof Promise ? o.cells[c].then((u) => {
d.resolve(u);
}).catch((u) => {
d.reject(u);
}) : d.resolve(o.cells[c]);
}
o.index instanceof Promise ? o.index.then((c) => {
l.index.resolve(c);
}).catch((c) => {
l.index.reject(c);
}) : l.index.resolve(o.index);
}
);
}).catch((i) => {
r.forEach((o) => {
for (const s of Object.values(o.cells))
s.reject(i);
o.index.reject(i);
});
}), r;
}
async function Et(e) {
const t = e.index, n = Object.values(e.cells), r = Object.keys(e.cells), [i, ...o] = await Promise.all([t, ...n]);
return {
index: i,
cells: Object.fromEntries(r.map((s, l) => [s, o[l]]))
};
}
function bn(e) {
return Promise.all(e.map(Et));
}
function St(e) {
return e.getColumn ? e.getColumn : function({ column: n, start: r = 0, end: i = e.numRows }) {
if (!e.header.includes(n))
throw new Error(`Invalid column: ${n}`);
return Promise.all(e.rows({ start: r, end: i }).map((o) => o.cells[n]));
};
}
async function Be({ data: e, column: t }) {
if (!e.header.includes(t))
throw new Error(`Invalid column: ${t}`);
const r = (await St(e)({ column: t })).map((l, c) => ({ value: l, index: c })), i = Array.from(r).sort(({ value: l }, { value: c }) => l < c ? -1 : l > c ? 1 : 0), o = i.length;
return i.reduce(({ lastValue: l, lastRank: c, ranks: d }, { value: u, index: g }, f) => u === l ? (d[g] = c, { ranks: d, lastValue: l, lastRank: c }) : (d[g] = f, { ranks: d, lastValue: u, lastRank: f }), { ranks: Array(o).fill(-1), lastValue: void 0, lastRank: 0 }).ranks;
}
function Ue(e) {
if (!(0 in e))
throw new Error("orderBy should have at least one element");
const t = e[0].ranks.length;
return Array.from({ length: t }, (i, o) => o).sort((i, o) => {
for (const { direction: s, ranks: l } of e) {
const c = l[i], d = l[o];
if (c === void 0 || d === void 0)
throw new Error("Invalid ranks");
const u = s === "ascending" ? 1 : -1;
if (c < d) return -u;
if (c > d) return u;
}
return 0;
});
}
function Fe({ data: e }) {
const { numRows: t } = e, n = Array.from({ length: t }, (r, i) => i);
return Promise.resolve(n);
}
function xn(e) {
if (e.sortable) return e;
const t = /* @__PURE__ */ new Map();
return {
...e,
rows({ start: n, end: r, orderBy: i }) {
if (i && i.length > 0) {
if (i.some(({ column: u }) => !e.header.includes(u)))
throw new Error(`Invalid orderBy field: ${i.map(({ column: u }) => u).join(", ")}`);
const s = [...i, { column: "", direction: "ascending" }].map(async ({ column: u, direction: g }) => {
const f = t.get(u) ?? (u === "" ? Fe({ data: e }) : Be({ data: e, column: u }));
t.has(u) || t.set(u, f);
const h = await f;
return { column: u, direction: g, ranks: h };
}), d = Promise.all(s).then(Ue).then((u) => u.slice(n, r)).then((u) => Promise.all(
// TODO(SL): optimize to fetch groups of rows instead of individual rows?
u.map((g) => {
const f = e.rows({ start: g, end: g + 1 });
if (!(0 in f))
throw new Error("data.rows should have return one async row");
return f[0];
})
));
return It(d, r - n, e.header);
} else
return e.rows({ start: n, end: r });
},
sortable: !0
};
}
function Rn(e) {
if (!(0 in e))
return { header: [], numRows: 0, rows: () => [], getColumn: () => Promise.resolve([]) };
const t = Object.keys(e[0]);
return {
header: t,
numRows: e.length,
rows({ start: n, end: r }) {
return e.slice(n, r).map((i, o) => ({
index: Ne(n + o),
cells: Object.fromEntries(Object.entries(i).map(([s, l]) => [s, Ne(l)]))
}));
},
getColumn({ column: n, start: r = 0, end: i = e.length }) {
if (!t.includes(n))
throw new Error(`Invalid column: ${n}`);
return Promise.resolve(e.slice(r, i).map((o) => o[n]));
}
};
}
function Ce() {
return { ranges: [], anchor: void 0 };
}
function _(e) {
return Number.isInteger(e) && e >= 0;
}
function we(e) {
return _(e.start) && _(e.end) && e.end > e.start;
}
function Q(e) {
if (e.length === 0)
return !0;
if (e.some((t) => !we(t)))
return !1;
for (let t = 0; t < e.length - 1; t++) {
const n = e[t], r = e[t + 1];
if (!n || !r || n.end >= r.start)
return !1;
}
return !0;
}
function Ie({ ranges: e, index: t }) {
if (!_(t))
throw new Error("Invalid index");
if (!Q(e))
throw new Error("Invalid ranges");
return e.some((n) => n.start <= t && t < n.end);
}
function ze({ ranges: e, length: t }) {
if (!Q(e))
throw new Error("Invalid ranges");
if (t && !_(t))
throw new Error("Invalid length");
return e.length === 1 && 0 in e && e[0].start === 0 && e[0].end === t;
}
function Je({ ranges: e, length: t }) {
if (!Q(e))
throw new Error("Invalid ranges");
if (t && !_(t))
throw new Error("Invalid length");
return ze({ ranges: e, length: t }) ? [] : [{ start: 0, end: t }];
}
function Ee({ ranges: e, range: t }) {
if (!Q(e))
throw new Error("Invalid ranges");
if (!we(t))
throw new Error("Invalid range");
const n = [], { start: r, end: i } = t;
let o = 0;
for (; o < e.length; ) {
const s = e[o];
if (!s)
throw new Error("Invalid range");
if (s.end >= r)
break;
n.push({ ...s }), o++;
}
for (; o < e.length; ) {
const s = e[o];
if (!s)
throw new Error("Invalid range");
if (s.start > i)
break;
t.start = Math.min(t.start, s.start), t.end = Math.max(t.end, s.end), o++;
}
for (n.push(t); o < e.length; ) {
const s = e[o];
if (!s)
throw new Error("Invalid range");
n.push({ ...s }), o++;
}
return n;
}
function Dt({ ranges: e, index: t }) {
return Ee({ ranges: e, range: { start: t, end: t + 1 } });
}
function qe({ ranges: e, range: t }) {
if (!Q(e))
throw new Error("Invalid ranges");
if (!we(t))
throw new Error("Invalid range");
const n = [], { start: r, end: i } = t;
let o = 0;
for (; o < e.length; ) {
const s = e[o];
if (!s)
throw new Error("Invalid range");
if (s.end >= r)
break;
n.push({ ...s }), o++;
}
for (; o < e.length; ) {
const s = e[o];
if (!s)
throw new Error("Invalid range");
if (s.start >= i)
break;
s.start < r && n.push({ start: s.start, end: r }), s.end > i && n.push({ start: i, end: s.end }), o++;
}
for (; o < e.length; ) {
const s = e[o];
if (!s)
throw new Error("Invalid range");
n.push({ ...s }), o++;
}
return n;
}
function Xe({ ranges: e, anchor: t, index: n }) {
if (!Q(e))
throw new Error("Invalid ranges");
if (t === void 0)
return e;
if (!_(t))
throw new Error("Invalid anchor");
if (!_(n))
throw new Error("Invalid index");
if (t === n)
return Se({ ranges: e, index: n });
const r = t < n ? { start: t, end: n + 1 } : { start: n, end: t + 1 };
if (!we(r))
throw new Error("Invalid range");
return Ie({ ranges: e, index: t }) ? Ee({ ranges: e, range: r }) : qe({ ranges: e, range: r });
}
function Se({ ranges: e, index: t }) {
if (!_(t))
throw new Error("Invalid index");
const n = { start: t, end: t + 1 };
return Ie({ ranges: e, index: t }) ? qe({ ranges: e, range: n }) : Ee({ ranges: e, range: n });
}
function Pt({ selection: e, index: t }) {
return { ranges: Se({ ranges: e.ranges, index: t }), anchor: t };
}
function kt({ selection: e, index: t }) {
return { ranges: Xe({ ranges: e.ranges, anchor: e.anchor, index: t }), anchor: t };
}
function Ot(e) {
const t = e.length, n = Array(t).fill(-1);
return e.forEach((r, i) => {
if (r < 0 || r >= t)
throw new Error("Invalid index: out of bounds");
if (!Number.isInteger(r))
throw new Error("Invalid index: not an integer");
if (n[r] !== -1)
throw new Error("Duplicate index");
n[r] = i;
}), n;
}
function Ke({ index: e, array: t }) {
const n = t[e];
if (n === void 0)
throw new Error("Data index not found in the data frame");
return n;
}
function Me({ selection: e, permutationIndexes: t }) {
const n = t.length, { ranges: r, anchor: i } = e;
if (!Q(e.ranges))
throw new Error("Invalid ranges");
if (i !== void 0 && !_(i))
throw new Error("Invalid anchor");
let o = [];
if (r.length === 0)
o = [];
else if (r.length === 1 && 0 in r && r[0].start === 0 && r[0].end === n)
o = [{ start: 0, end: n }];
else
for (const l of r) {
const { start: c, end: d } = l;
for (let u = c; u < d; u++)
o = Dt({ ranges: o, index: Ke({ index: u, array: t }) });
}
const s = i !== void 0 ? Ke({ index: i, array: t }) : void 0;
return { ranges: o, anchor: s };
}
async function At({
tableIndex: e,
selection: t,
orderBy: n,
data: r,
ranksMap: i,
setRanksMap: o
}) {
if (!r.sortable)
throw new Error("Data frame is not sortable");
const l = [...n, { column: "", direction: "ascending" }].map(({ column: v, direction: m }) => ({
column: v,
direction: m,
ranks: i.get(v) ?? (v === "" ? Fe({ data: r }) : Be({ data: r, column: v }))
}));
l.some(({ column: v }) => !i.has(v)) && o((v) => {
const m = new Map(v);
return l.forEach(({ column: a, ranks: b }) => m.set(a, b)), m;
});
const c = await Promise.all(l.map(async ({ column: v, direction: m, ranks: a }) => ({ column: v, direction: m, ranks: await a }))), d = Ue(c), u = Ot(d), g = Me({ selection: t, permutationIndexes: u }), { ranges: f, anchor: h } = g, S = e, w = { ranges: Xe({ ranges: f, anchor: h, index: e }), anchor: S };
return Me({ selection: w, permutationIndexes: d });
}
function $t(e, t) {
return e.length !== t.length ? !1 : e.every((n, r) => {
const i = t[r];
return i ? n.column === i.column && n.direction === i.direction : !1;
});
}
function Nt(e, t) {
const n = [];
let r;
const i = [];
for (const o of e)
r ? i.push(o) : o.column === t ? r = o : n.push(o);
return { prefix: n, item: r, suffix: i };
}
function jt(e, t) {
const { prefix: n, item: r, suffix: i } = Nt(t, e);
return r && n.length === 0 ? r.direction === "ascending" ? [{ column: e, direction: "descending" }, ...i] : [...i] : [{ column: e, direction: "ascending" }, ...n, ...i];
}
function Ge(e) {
const t = e ? `${e}px` : void 0;
return { minWidth: t, maxWidth: t };
}
function xe(e) {
return e.offsetWidth + 1;
}
function Ct(e) {
return e.clientWidth - 1;
}
function ne(e) {
return typeof e == "number" && Number.isFinite(e) && !isNaN(e) && e >= 0;
}
function Le(e) {
return (e == null ? void 0 : e.width) !== void 0 && e.measured === void 0;
}
function Kt(e) {
let t = 0;
for (const { width: n, indexes: r } of e)
t += n * r.length;
return t;
}
function Mt({
columnWidths: e,
availableWidth: t,
clamp: n,
numColumns: r
}) {
var S;
if (!ne(t))
return e;
const i = n(0), o = e.filter((w) => (w == null ? void 0 : w.measured) !== void 0).length;
if (o === 0)
return e;
let s = t;
for (const w of e)
if ((w == null ? void 0 : w.measured) === void 0) {
if ((w == null ? void 0 : w.width) === void 0) {
s -= i;
continue;
}
s -= w.width;
}
e.length < r && (s -= (r - e.length) * i);
const l = 5, c = r <= 3 ? 1 / r : 0.3, d = n(c * s - l), u = /* @__PURE__ */ new Map();
for (const [w, p] of e.entries())
if ((p == null ? void 0 : p.measured) !== void 0) {
const { measured: v } = p, m = u.get(v);
m ? m.push(w) : u.set(v, [w]);
}
const g = [...u.entries()].map(
([w, p]) => ({ width: w, indexes: p })
).sort((w, p) => w.width - p.width);
let f = 0;
for (; g.length > 0 && f < 100; ) {
f++;
const w = Kt(g);
if (w <= s) {
const m = Math.floor((s - w) / o);
for (const a of g)
a.width = n(a.width + m);
break;
}
const p = g.at(-1), v = g.at(-2);
if (p === void 0 || p.width <= d)
break;
v === void 0 || v.width < d ? p.width = d : (g.pop(), v.indexes.push(...p.indexes));
}
let h;
for (const { width: w, indexes: p } of g)
for (const v of p) {
const m = {
width: w,
measured: (S = e[v]) == null ? void 0 : S.measured
// keep the measured width if it exists (it should)
};
e[v] = m, h = m, s -= w;
}
return h !== void 0 && s > 0 && (h.width = n(h.width + s)), e;
}
const re = {
colIndex: 1,
// the cursor cell is initially the top-left cell
rowIndex: 1,
//
shouldFocus: !1,
enterCellsNavigation: !1,
onTableKeyDown: void 0,
onScrollKeyDown: void 0,
setColIndex: void 0,
setRowIndex: void 0,
setShouldFocus: void 0,
setEnterCellsNavigation: void 0
}, De = oe(re);
function Lt({ colCount: e, rowCount: t, rowPadding: n, children: r }) {
const [i, o] = $(re.colIndex), [s, l] = $(re.rowIndex), [c, d] = $(!1), [u, g] = $(!1), f = y((p) => {
const { key: v } = p, m = p.ctrlKey || p.metaKey;
if (v === "ArrowRight")
o(m ? e : (a) => a < e ? a + 1 : a);
else if (v === "ArrowLeft")
o(m ? 1 : (a) => a > 1 ? a - 1 : a);
else if (v === "ArrowDown")
l(m ? t : (a) => a < t ? a + 1 : a);
else if (v === "ArrowUp")
l(m ? 1 : (a) => a > 1 ? a - 1 : a);
else if (v === "Home")
m && l(1), o(1);
else if (v === "End")
m && l(t), o(e);
else if (v === "PageDown")
l((a) => a + n <= t ? a + n : t);
else if (v === "PageUp")
l((a) => a - n >= 1 ? a - n : 1);
else if (v !== " ")
return;
p.stopPropagation(), p.preventDefault(), d(!0);
}, [e, t, n]), h = y((p) => {
const { key: v } = p;
(v === "Tab" && !p.shiftKey || v === "Enter" || v === " ") && (p.stopPropagation(), p.preventDefault(), g(!0), d(!0));
}, []), S = y(() => {
o(re.colIndex), l(re.rowIndex), g(!0), d(!0);
}, []), w = T(() => ({
colIndex: i,
rowIndex: s,
onTableKeyDown: f,
onScrollKeyDown: h,
setColIndex: o,
setRowIndex: l,
shouldFocus: c,
setShouldFocus: d,
enterCellsNavigation: u,
setEnterCellsNavigation: g,
focusFirstCell: S
}), [
i,
s,
f,
h,
c,
u,
g,
S
]);
return /* @__PURE__ */ x(De.Provider, { value: w, children: r });
}
function ge({ ref: e, ariaColIndex: t, ariaRowIndex: n }) {
const { colIndex: r, rowIndex: i, setColIndex: o, setRowIndex: s, shouldFocus: l, setShouldFocus: c } = Z(De), d = t === r && n === i, u = n === 1 || t === 1;
G(() => {
e.current && d && l && (u || e.current.scrollIntoView({ behavior: "auto", block: "nearest", inline: "nearest" }), e.current.focus(), c == null || c(!1));
}, [e, d, u, l, c]);
const g = d ? 0 : -1, f = y(() => {
o == null || o(t), s == null || s(n), c == null || c(!0);
}, [o, s, c, t, n]);
return {
tabIndex: g,
navigateToCell: f
};
}
function Tt() {
return Z(De);
}
function Ht({ key: e, parse: t }) {
const n = localStorage.getItem(e);
return n ? (t ?? JSON.parse)(n) : void 0;
}
function Vt({ key: e, value: t, stringify: n }) {
e !== void 0 && (t === void 0 ? localStorage.removeItem(e) : localStorage.setItem(e, (n ?? JSON.stringify)(t)));
}
function _t({ key: e, parse: t, stringify: n } = {}) {
const [r, i] = $(void 0), [o, s] = $(void 0);
return e !== o && (e !== void 0 && i(Ht({ key: e, parse: t })), s(e)), G(() => {
Vt({ key: e, value: r, stringify: n });
}, [r, e, n]), [r, i];
}
const Qe = oe({});
function Bt({ children: e, localStorageKey: t, numColumns: n, minWidth: r }) {
if (!ne(r))
throw new Error(`Invalid minWidth: ${r}. It must be a positive number.`);
if (!Number.isInteger(n) || n < 0)
throw new Error(`Invalid numColumns: ${n}. It must be a positive integer.`);
const [i, o] = $(0), s = y((a) => Math.floor(Math.max(a, r)), [r]), [l, c] = _t({ key: t, parse: u, stringify: d });
function d(a) {
const b = a.map((I) => Le(I) ? { width: I.width } : void 0);
return JSON.stringify(b);
}
function u(a) {
const b = JSON.parse(a);
return Array.isArray(b) ? b.map((I) => I == null || typeof I != "object" || !("width" in I) ? void 0 : { width: ne(I.width) ? s(I.width) : void 0 }) : [];
}
const g = y((a) => Number.isInteger(a) && a >= 0 && a < n, [n]), f = y((a) => {
var b;
return (b = l == null ? void 0 : l[a]) == null ? void 0 : b.width;
}, [l]), h = y((a) => Ge(f(a)), [f]), S = y((a) => Le(l == null ? void 0 : l[a]), [l]), w = y(({ columnIndex: a, width: b }) => {
!ne(b) || !g(a) || c((I) => {
const A = [...I ?? []];
return A[a] = { ...A[a] ?? {}, width: s(b), measured: void 0 }, A;
});
}, [s, g, c]), p = y(({ columnIndex: a, measured: b }) => {
!ne(b) || !g(a) || c((I) => {
const A = [...I ?? []];
return A[a] = { ...A[a] ?? {}, measured: s(b), width: void 0 }, Mt({ columnWidths: A, availableWidth: i, clamp: s, numColumns: n });
});
}, [i, s, g, n, c]), v = y(({ columnIndex: a }) => {
g(a) && c((b) => {
const I = [...b ?? []];
return I[a] = { ...I[a] ?? {}, measured: void 0, width: void 0 }, I;
});
}, [g, c]), m = T(() => ({
getColumnWidth: f,
getColumnStyle: h,
isFixedColumn: S,
setAvailableWidth: o,
forceWidth: w,
measureWidth: p,
removeWidth: v
}), [f, h, S, o, w, p, v]);
return /* @__PURE__ */ x(Qe.Provider, { value: m, children: e });
}
function Pe() {
return Z(Qe);
}
function Ut() {
return {
data: {
numRows: 0,
header: [],
rows: () => []
},
key: "default"
};
}
const Ye = oe(Ut());
function Te() {
return crypto.randomUUID();
}
function Ft({ children: e, data: t }) {
const [n, r] = $(Te()), [i, o] = $(t);
return t !== i && (r(Te()), o(t)), /* @__PURE__ */ x(Ye.Provider, { value: {
data: t,
key: n
}, children: e });
}
function Ze() {
return Z(Ye);
}
function We({ value: e, onChange: t, defaultValue: n, disabled: r }) {
const [i] = $(e), [o] = $(e !== void 0), [s] = $(r ?? !1), [l, c] = $(n), d = y((u) => {
t == null || t(u), c(u);
}, [t]);
return s ? {} : o ? (e === void 0 && console.warn("The value is controlled (it has no local state) because the property was initially defined. It cannot be set to undefined now (it is set back to the initial value)."), {
value: e ?? i,
// read-only if onChange is undefined
onChange: t
}) : (e !== void 0 && console.warn("The value is uncontrolled (it only has a local state) because the property was initially undefined. It cannot be set to a value now and is ignored."), { value: l, onChange: d });
}
const et = oe({});
function zt({ children: e, orderBy: t, onOrderByChange: n, disabled: r }) {
const i = We({
value: t,
onChange: n,
defaultValue: [],
disabled: r
});
return /* @__PURE__ */ x(et.Provider, { value: {
orderBy: i.value,
onOrderByChange: i.onChange
}, children: e });
}
function Jt() {
return Z(et);
}
const tt = oe({});
function qt({ children: e, selection: t, onSelectionChange: n }) {
const r = We({
value: t,
onChange: n,
defaultValue: Ce(),
disabled: t === void 0 && n === void 0
}), i = y((o, s) => {
var d, u;
const { key: l, shiftKey: c } = o;
if (l === "Escape")
(d = r.onChange) == null || d.call(r, Ce());
else if (l === "a" && (o.ctrlKey || o.metaKey))
o.preventDefault(), r.value && ((u = r.onChange) == null || u.call(r, { ranges: Je({ ranges: r.value.ranges, length: s }) }));
else if (l === " " && c) {
const { target: g } = o;
if (!r.value || !r.onChange || !(g instanceof HTMLTableCellElement))
return;
const f = Number(g.getAttribute("data-rowindex"));
if (!(g.getAttribute("role") === "cell") || isNaN(f) || !Number.isInteger(f) || f < 0 || f >= s)
return;
o.preventDefault(), r.onChange({ ranges: Se({ ranges: r.value.ranges, index: f }), anchor: f });
}
}, [r]);
return /* @__PURE__ */ x(tt.Provider, { value: {
selection: r.value,
onSelectionChange: r.onChange,
onTableKeyDown: i
}, children: e });
}
function Xt({ numRows: e }) {
const t = Z(tt), { selection: n, onSelectionChange: r } = t, i = y(() => {
if (!(!n || !r))
return () => {
r({
ranges: Je({ ranges: n.ranges, length: e }),
anchor: void 0
});
};
}, [r, e, n]);
return {
...t,
toggleAllRows: i()
};
}
function Re(e) {
return typeof e == "string" ? e : typeof e == "number" || typeof e == "bigint" ? e.toLocaleString("en-US") : typeof e == "boolean" ? e.toString() : Array.isArray(e) ? `[
${e.map((t) => He(Re(t), 2)).join(`,
`)}
]` : e == null ? JSON.stringify(e) : e instanceof Date ? e.toISOString() : typeof e == "object" ? `{
${Object.entries(e).filter((t) => t[1] !== void 0).map(([t, n]) => He(`${t}: ${Re(n)}`, 2)).join(`,
`)}
}` : JSON.stringify(e);
}
function He(e, t) {
return e == null ? void 0 : e.split(`
`).map((n) => " ".repeat(t) + n).join(`
`);
}
function Gt(e, t) {
let n = !1, r = !1;
function i() {
e(), r = !1, n = !0, setTimeout(() => {
n = !1, r && i();
}, t);
}
return () => {
n ? r = !0 : i();
};
}
function Qt({ onDoubleClick: e, onMouseDown: t, onKeyDown: n, stringify: r, columnIndex: i, value: o, hasResolved: s, className: l, ariaColIndex: c, ariaRowIndex: d, dataRowIndex: u }) {
const g = F(null), { tabIndex: f, navigateToCell: h } = ge({ ref: g, ariaColIndex: c, ariaRowIndex: d }), S = y((b) => {
h(), t == null || t(b);
}, [t, h]), w = y((b) => {
h(), e == null || e(b);
}, [e, h]), { getColumnStyle: p } = Pe(), v = p == null ? void 0 : p(i), m = T(() => r(o), [r, o]), a = T(() => {
if (m !== void 0) {
if (m.length > 400)
return `${m.slice(0, 397)}…`;
if (m.length > 100)
return m;
}
}, [m]);
return /* @__PURE__ */ x(
"td",
{
ref: g,
role: "cell",
"aria-busy": !s,
"aria-rowindex": d,
"aria-colindex": c,
"data-rowindex": u,
tabIndex: f,
onDoubleClick: w,
onMouseDown: S,
onKeyDown: n,
style: v,
className: l,
title: a,
children: m
}
);
}
function fe({
children: e,
selected: t,
ariaRowIndex: n,
title: r
}) {
return /* @__PURE__ */ x(
"tr",
{
role: "row",
"aria-rowindex": n,
title: r,
"aria-selected": t,
children: e
}
);
}
function be({ children: e, checked: t, onCheckboxPress: n, style: r, busy: i, ariaColIndex: o, ariaRowIndex: s, dataRowIndex: l }) {
const c = F(null), { tabIndex: d, navigateToCell: u } = ge({ ref: c, ariaColIndex: o, ariaRowIndex: s }), g = y((p) => {
u(), n == null || n(p.shiftKey);
}, [n, u]), f = y((p) => {
(p.key === "Enter" || p.key === " ") && (p.preventDefault(), p.stopPropagation(), n == null || n(p.shiftKey));
}, [n]), h = t !== void 0, S = n === void 0, w = y((p) => {
p.preventDefault();
}, []);
return /* @__PURE__ */ X(
"th",
{
ref: c,
scope: "row",
role: "rowheader",
style: r,
onClick: g,
onKeyDown: f,
"aria-busy": i,
"aria-checked": t,
"aria-rowindex": s,
"aria-colindex": o,
"aria-disabled": S,
tabIndex: d,
"data-rowindex": l,
children: [
/* @__PURE__ */ x("span", { children: e }),
h && /* @__PURE__ */ x(
"input",
{
type: "checkbox",
onChange: w,
readOnly: S,
disabled: S,
checked: t,
role: "presentation",
tabIndex: -1
}
)
]
}
);
}
function Yt({ children: e, checked: t, onCheckboxPress: n, style: r, ariaColIndex: i, ariaRowIndex: o }, s) {
const l = F(null);
bt(s, () => ({
get offsetWidth() {
var w;
return ((w = l.current) == null ? void 0 : w.offsetWidth) ?? 0;
}
}), []);
const { tabIndex: c, navigateToCell: d } = ge({ ref: l, ariaColIndex: i, ariaRowIndex: o }), u = y(() => {
d(), n == null || n();
}, [n, d]), g = y((w) => {
(w.key === "Enter" || w.key === " ") && (w.preventDefault(), w.stopPropagation(), n == null || n());
}, [n]), f = t !== void 0, h = n === void 0, S = y((w) => {
w.preventDefault();
}, []);
return /* @__PURE__ */ x(
"td",
{
ref: l,
style: r,
onClick: u,
onKeyDown: g,
"aria-checked": t,
"aria-rowindex": o,
"aria-colindex": i,
"aria-disabled": h,
tabIndex: c,
children: f ? /* @__PURE__ */ x(
"input",
{
type: "checkbox",
onChange: S,
readOnly: h,
disabled: h,
checked: t,
role: "presentation",
tabIndex: -1
}
) : /* @__PURE__ */ x("span", { children: e })
}
);
}
const Zt = mt(Yt), Ve = 10, _e = 100;
function Wt({ autoResize: e, forceWidth: t, width: n, tabIndex: r, navigateToCell: i }) {
const [o, s] = $(void 0), [l, c] = $(!1), d = y(() => {
o || e == null || e(), i == null || i();
}, [e, i, o]), u = y((a) => {
a.stopPropagation();
}, []), g = y((a) => {
if (i == null || i(), a.stopPropagation(), n === void 0)
return;
const { clientX: b, currentTarget: I, pointerId: A } = a;
s({ clientX: b, pointerId: A, width: n }), "setPointerCapture" in I && I.setPointerCapture(A);
}, [i, n]), f = y((a) => {
!o || a.pointerId !== o.pointerId || t == null || t(o.width - o.clientX + a.clientX);
}, [t, o]), h = y((a) => {
a.stopPropagation(), s((b) => {
if (!(b && a.pointerId === b.pointerId))
return b;
});
}, []), S = y(() => {
c(!0);
}, []), w = y(() => {
c(!1);
}, []), p = y((a) => {
if (l && ([" ", "ArrowRight", "ArrowLeft", "ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End"].includes(a.key) && a.preventDefault(), a.stopPropagation(), !o)) {
if (a.key === "Escape") {
c(!1), i == null || i();
return;
}
if (a.key === "Enter" || a.key === " ") {
d();
return;
}
n !== void 0 && (a.key === "ArrowRight" || a.key === "ArrowUp" ? t == null || t(n + Ve) : a.key === "ArrowLeft" || a.key === "ArrowDown" ? t == null || t(n - Ve) : a.key === "PageUp" ? t == null || t(n + _e) : a.key === "PageDown" ? t == null || t(n - _e) : a.key === "Home" && (t == null || t(0)));
}
}, [d, o, t, n, l, i]), v = o !== void 0 || l, m = T(() => n === void 0 ? "No width set." : `Width set to ${n} pixels.`, [n]);
return /* @__PURE__ */ x(
"span",
{
role: "spinbutton",
"aria-orientation": "vertical",
"aria-busy": v,
"aria-valuemin": 0,
"aria-valuenow": n,
"aria-valuetext": m,
"aria-label": "Resize column",
"aria-description": 'Press "Enter" or "Space" to autoresize the column (press again to unset the width). Press "Escape" to cancel resizing. Press "ArrowRight/ArrowUp" or "ArrowLeft/ArrowDown" to resize the column by 10 pixels. Press PageUp/PageDown to resize the column by 100 pixels.',
onDoubleClick: d,
onPointerDown: g,
onPointerMove: f,
onPointerUp: h,
onClick: u,
onFocus: S,
onBlur: w,
onKeyDown: p,
tabIndex: r
}
);
}
function en({ columnIndex: e, columnName: t, columnConfig: n, dataReady: r, direction: i, onClick: o, orderByIndex: s, orderBySize: l, ariaColIndex: c, ariaRowIndex: d, className: u, children: g }) {
const f = F(null), { tabIndex: h, navigateToCell: S } = ge({ ref: f, ariaColIndex: c, ariaRowIndex: d }), w = y(() => {
S(), o == null || o();
}, [o, S]), p = !!o, { getColumnStyle: v, isFixedColumn: m, getColumnWidth: a, measureWidth: b, forceWidth: I, removeWidth: A } = Pe(), Y = v == null ? void 0 : v(e), z = (m == null ? void 0 : m(e)) === !0 ? !0 : void 0, J = a == null ? void 0 : a(e), N = y((K) => {
I == null || I({ columnIndex: e, width: K });
}, [I, e]);
G(() => {
const K = f.current;
if (r && K && J === void 0) {
const C = xe(K);
if (isNaN(C))
return;
b == null || b({ columnIndex: e, measured: C });
}
}, [r, b, J, e]);
const pe = y(() => {
const K = f.current;
if (K && b && I && A) {
xt(() => {
A({ columnIndex: e });
});
const C = xe(K);
if (isNaN(C))
return;
z && J === C ? b({ columnIndex: e, measured: C }) : I({ columnIndex: e, width: C });
}
}, [b, I, A, e, z, J]), q = T(() => p ? s !== void 0 && s > 0 ? `Press to sort by ${t} in ascending order` : i === "ascending" ? `Press to sort by ${t} in descending order` : i === "descending" ? `Press to stop sorting by ${t}` : `Press to sort by ${t} in ascending order` : `The column ${t} cannot be sorted`, [p, t, i, s]), ie = y((K) => {
K.target === f.current && (K.key === "Enter" || K.key === " ") && (K.preventDefault(), K.stopPropagation(), o == null || o());
}, [o]);
return /* @__PURE__ */ X(
"th",
{
ref: f,
scope: "col",
role: "columnheader",
"aria-sort": i ?? (p ? "none" : void 0),
"data-order-by-index": l !== void 0 ? s : void 0,
"data-order-by-size": l,
"aria-label": t,
"aria-description": q,
"aria-rowindex": d,
"aria-colindex": c,
tabIndex: h,
title: q,
onClick: w,
onKeyDown: ie,
style: Y,
className: u,
"data-fixed-width": z,
children: [
(n == null ? void 0 : n.headerComponent) ?? g,
/* @__PURE__ */ x(
Wt,
{
forceWidth: N,
autoResize: pe,
width: J,
tabIndex: h,
navigateToCell: S
}
)
]
}
);
}
function tn({
header: e,
orderBy: t,
onOrderByChange: n,
dataReady: r,
ariaRowIndex: i,
columnClassNames: o = []
}) {
const s = y(
(c) => {
if (!(!n || !t))
return () => {
n(jt(c, t));
};
},
[t, n]
), l = T(() => new Map((t ?? []).map(({ column: c, direction: d }, u) => [c, { direction: d, index: u }])), [t]);
return e.map((c) => {
var h, S;
const { key: d, index: u, ...g } = c, f = u + 2;
return (
// The ColumnHeader component width is controlled by the parent
/* @__PURE__ */ x(
en,
{
dataReady: r,
direction: (h = l.get(d)) == null ? void 0 : h.direction,
orderByIndex: (S = l.get(d)) == null ? void 0 : S.index,
orderBySize: t == null ? void 0 : t.length,
onClick: s(d),
columnName: d,
columnIndex: u,
className: o[u],
ariaColIndex: f,
ariaRowIndex: i,
columnConfig: g,
children: d
},
u
)
);
});
}
function nt(e) {
return e === void 0 ? "" : (e + 1).toLocaleString("en-US");
}
function nn(e, t) {
const n = Object.keys(e.cells).length;
if (n > 0 && n !== t)
return `Row ${nt(e.index)} length ${n} does not match header length ${t}`;
}
const rn = "_hightable_1y6f4_1", on = "_table-scroll_1y6f4_16", sn = "_mock-row-label_1y6f4_140", an = "_styled_1y6f4_152", ln = "_top-border_1y6f4_174", ee = {
hightable: rn,
tableScroll: on,
mockRowLabel: sn,
styled: an,
topBorder: ln
};
function cn(e, t) {
return T(() => {
const n = new Set(e), r = e.map((i, o) => ({
key: i,
index: o,
...(t == null ? void 0 : t[i]) ?? {}
}));
if (t)
for (const i of Object.keys(t))
n.has(i) || console.warn(
`[HighTable] columnConfiguration has unknown key “${i}”. It will be ignored.`
);
return r;
}, [e, t]);
}
const he = 33, un = 50, rt = 20, dn = 20, te = 2, fn = ":column:states";
function In(e) {
return /* @__PURE__ */ x(Ft, { data: e.data, children: /* @__PURE__ */ x(hn, { ...e }) });
}
function hn(e) {
const { data: t, key: n } = Ze(), { cacheKey: r, orderBy: i, onOrderByChange: o, selection: s, onSelectionChange: l } = e, c = t.header.length + 1, d = t.numRows + 1;
return (
/* important: key={key} ensures the local state is recreated if the data has changed */
/* @__PURE__ */ x(zt, { orderBy: i, onOrderByChange: o, disabled: !t.sortable, children: /* @__PURE__ */ x(qt, { selection: s, onSelectionChange: l, children: /* @__PURE__ */ x(Bt, { localStorageKey: r ? `${r}${fn}` : void 0, numColumns: t.header.length, minWidth: un, children: /* @__PURE__ */ x(Lt, { colCount: c, rowCount: d, rowPadding: e.padding ?? rt, children: /* @__PURE__ */ x(wn, { ...e }) }) }, n) }) }, n)
);
}
function wn({
overscan: e = dn,
padding: t = rt,
focus: n = !0,
onDoubleClickCell: r,
onMouseDownCell: i,
onKeyDownCell: o,
onError: s = console.error,
stringify: l = Re,
className: c = "",
columnClassNames: d = [],
styled: u = !0,
columnConfiguration: g
}) {
const { data: f } = Ze(), [h, S] = $(void 0), [w, p] = $({ start: 0, end: 0 }), { enterCellsNavigation: v, setEnterCellsNavigation: m, onTableKeyDown: a, onScrollKeyDown: b, rowIndex: I, colIndex: A, focusFirstCell: Y } = Tt(), [z, J] = $({ rowIndex: I, colIndex: A }), [N, pe] = $(f.numRows), { setAvailableWidth: q } = Pe(), [ie, K] = $(() => /* @__PURE__ */ new Map()), { orderBy: C, onOrderByChange: ot } = Jt(), { selection: H, onSelectionChange: ve, toggleAllRows: it, onTableKeyDown: se } = Xt({ numRows: N }), ae = cn(f.header, g), st = y((R) => {
a == null || a(R), se == null || se(R, N);
}, [a, se, N]), ke = F(0), at = y(({ tableIndex: R, dataIndex: D }) => {
if (H && ve && D !== void 0)
return (k) => {
E(k, H, ve, D);
};
async function E(k, P, L, V) {
if (!(k && P.anchor !== void 0)) {
L(Pt({ selection: P, index: V }));
return;
}
if (!C || C.length === 0) {
L(kt({ selection: P, index: V }));
return;
}
const j = ++ke.current, O = await At({
selection: P,
tableIndex: R,
orderBy: C,
data: f,
ranksMap: ie,
setRanksMap: K
});
j === ke.current && L(O);
}
}, [f, ve, C, ie, H]), lt = T(() => {
if (H)
return ze({ ranges: H.ranges, length: N });
}, [H, N]), ct = y((R) => {
if (!(!H || R === void 0))
return Ie({ ranges: H.ranges, index: R });
}, [H]), le = (N + 1) * he, ut = h ? Math.max(0, h.offset - t) * he : 0, ye = F(null), B = F(null), me = F(0);
G(() => {
if (!h || !v && z.rowIndex === I && z.colIndex === A)
return;
m == null || m(!1), J({ rowIndex: I, colIndex: A });
const R = I - te, D = B.current;
if (!D)
return;
let E = D.scrollTop;
(R < h.offset || R >= h.offset + h.rows.length) && (E = R * he), E !== D.scrollTop && (D.scrollTop = E);
}, [I, A, h, z, t, v, m]), G(() => {
function R() {
var U, de;
const k = (U = B.current) == null ? void 0 : U.clientHeight, P = k === void 0 || k === 0 ? 100 : k, L = ((de = B.current) == null ? void 0 : de.scrollTop) ?? 0, V = Math.floor(N * L / le), M = Math.ceil(N * (L + P) / le), j = Math.max(0, V - e), O = Math.min(N, M + e);
if (isNaN(j)) throw new Error(`invalid start row ${j}`);
if (isNaN(O)) throw new Error(`invalid end row ${O}`);
if (O - j > 1e3) throw new Error(`attempted to render too many rows ${O - j} table must be contained in a scrollable div`);
p({ start: j, end: O });
}
function D() {
if (B.current && ye.current) {
const k = Ct(B.current), P = xe(ye.current);
q == null || q(k - P);
}
}
R(), D();
const E = B.current;
return E == null || E.addEventListener("scroll", R), window.addEventListener("resize", R), window.addEventListener("resize", D), () => {
E == null || E.removeEventListener("scroll", R), window.removeEventListener("resize", R), window.removeEventListener("resize", D);
};
}, [N, e, t, le, q]), G(() => {
async function R() {
const { start: D, end: E } = w, k = C ?? [];
if (!(h && h.data === f && D === h.offset && E === h.offset + h.rows.length && $t(h.orderedBy, k))) {
if (D === E) {
S({
offset: D,
rows: [],
orderedBy: k,
data: f
});
return;
}
try {
const P = ++me.current, L = f.rows({ start: D, end: E, orderBy: k }), V = Gt(() => {
const M = [];
for (const O of L) {
const U = { cells: {} };
for (const [de, $e] of Object.entries(O.cells))
"resolved" in $e && (U.cells[de] = $e.resolved);
"resolved" in O.index && (U.index = O.index.resolved), M.push(U);
}
S({
offset: D,
rows: M,
orderedBy: k,
data: f
});
}, 10);
V();
for (const M of L)
for (const j of [M.index, ...Object.values(M.cells)])
j.then(() => {
me.current === P && V();
}).catch((O) => {
me.current === P && typeof O == "object" && O !== null && "numRows" in O && typeof O.numRows == "number" && O.numRows >= 0 && O.numRows < N && Number.isInteger(O.numRows) && pe(O.numRows);
});
await Promise.all(L.flatMap((M) => [M.index, ...Object.values(M.cells)]));
} catch (P) {
s(P);
}
}
}
R();
}, [f, s, C, h, w, N]);
const dt = y((R, D) => {
if (!(!r || D === void 0))
return (E) => {
r(E, R, D);
};
}, [r]), ft = y((R, D) => {
if (!(!i || D === void 0))
return (E) => {
i(E, R, D);
};
}, [i]), ht = y((R, D) => {
if (!(!o || D === void 0))
return (E) => {
o(E, R, D);
};
}, [o]);
G(() => {
n && (Y == null || Y());
}, [f, n, Y]);
const ce = (h == null ? void 0 : h.offset) ?? 0, Oe = (h == null ? void 0 : h.rows.length) ?? 0, Ae = Array.from({ length: Math.min(t, ce) }, () => []), wt = Array.from({ length: Math.min(t, N - ce - Oe) }, () => []), ue = T(() => Math.ceil(Math.log10(N + 1)) * 4 + 22, [N]), W = T(() => Ge(ue), [ue]), gt = T(() => ({
"--column-header-height": `${he}px`,
"--row-number-width": `${ue}px`
}), [ue]), pt = y((R) => {
R.target === B.current && (b == null || b(R));
}, [b]);
if (!ae.length) return;
const vt = ae.length + 1, yt = N + 1;
return /* @__PURE__ */ X("div", { className: `${ee.hightable} ${u ? ee.styled : ""} ${c}`, children: [
/* @__PURE__ */ x("div", { className: ee.topBorder, role: "presentation" }),
/* @__PURE__ */ x("div", { className: ee.tableScroll, ref: B, role: "group", "aria-labelledby": "caption", style: gt, onKeyDown: pt, tabIndex: 0, children: /* @__PURE__ */ x("div", { style: { height: `${le}px` }, children: /* @__PURE__ */ X(
"table",
{
"aria-readonly": !0,
"aria-colcount": vt,
"aria-rowcount": yt,
"aria-multiselectable": H !== void 0,
role: "grid",
style: { top: `${ut}px` },
onKeyDown: st,
children: [
/* @__PURE__ */ x("caption", { id: "caption", hidden: !0, children: "Virtual-scroll table" }),
/* @__PURE__ */ x("thead", { role: "rowgroup", children: /* @__PURE__ */ X(fe, { ariaRowIndex: 1, children: [
/* @__PURE__ */ x(
Zt,
{
onCheckboxPress: it,
checked: lt,
style: W,
ariaColIndex: 1,
ariaRowIndex: 1,
ref: ye,
children: " "
}
),
/* @__PURE__ */ x(
tn,
{
dataReady: h !== void 0,
header: ae,
orderBy: C,
onOrderByChange: ot,
columnClassNames: d,
ariaRowIndex: 1
}
)
] }) }),
/* @__PURE__ */ X("tbody", { role: "rowgroup", children: [
Ae.map((R, D) => {
const E = ce - Ae.length + D, k = E + te;
return /* @__PURE__ */ x(fe, { ariaRowIndex: k, children: /* @__PURE__ */ x(be, { style: W, ariaColIndex: 1, ariaRowIndex: k }) }, E);
}),
h == null ? void 0 : h.rows.map((R, D) => {
const E = h.offset + D, k = C === void 0 || C.length === 0 ? E : void 0, P = R.index ?? k, L = ct(P), V = E + te;
return /* @__PURE__ */ X(
fe,
{
selected: L,
ariaRowIndex: V,
title: nn(R, ae.length),
children: [
/* @__PURE__ */ x(
be,
{
busy: P === void 0,
style: W,
onCheckboxPress: at({ tableIndex: E, dataIndex: P }),
checked: L,
showCheckBox: H !== void 0,
ariaColIndex: 1,
ariaRowIndex: V,
dataRowIndex: P,
children: nt(P)
}
),
f.header.map((M, j) => {
const O = M in R.cells, U = R.cells[M];
return /* @__PURE__ */ x(
Qt,
{
onDoubleClick: dt(j, P),
onMouseDown: ft(j, P),
onKeyDown: ht(j, P),
stringify: l,
value: U,
columnIndex: j,
hasResolved: O,
className: d[j],
ariaColIndex: j + te,
ariaRowIndex: V,
dataRowIndex: P
},
j
);
})
]
},
E
);
}),
wt.map((R, D) => {
const E = ce + Oe + D, k = E + te;
return /* @__PURE__ */ x(fe, { ariaRowIndex: k, children: /* @__PURE__ */ x(be, { style: W, ariaColIndex: 1, ariaRowIndex: k }) }, E);
})
] })
]
}
) }) }),
/* @__PURE__ */ x("div", { className: ee.mockRowLabel, style: W, children: " " })
] });
}
function En(e) {
const t = {};
let n = 0, r = 0;
return {
...e,
rows({ start: i, end: o, orderBy: s }) {
const l = gn(s), c = t[l] ?? new Array(e.numRows);
l in t || (t[l] = c);
const d = n + r;
d && !(d % 10) && console.log(`Cache hits: ${n} / ${n + r} (${(100 * n / (n + r)).toFixed(1)}%)`);
let u, g = !1;
for (let f = i; f <= o; f++)
if (f < o && !c[f])
u ?? (u = f);
else if (u !== void 0) {
const h = f, S = e.rows({ start: u, end: h, orderBy: s });
for (let w = 0; w < h - u; w++)
c[u + w] = S[w];
u = void 0, g = !0;
}
return g ? r++ : n++, c.slice(i, o).map((f) => {
if (!f)
throw new Error("Row not cached");
return f;
});
}
};
}
function gn(e) {
if (!e || e.length === 0)
return "";
if (!(0 in e))
throw new Error("orderBy should have at least one element");
return JSON.stringify(e);
}
export {
In as HighTable,
Rn as arrayDataFrame,
It as asyncRows,
Et as awaitRow,
bn as awaitRows,
In as default,
St as getGetColumn,
je as resolvablePromise,
Rt as resolvableRow,
En as rowCache,
xn as sortableDataFrame,
Re as stringify,
mn as wrapPromise,
Ne as wrapResolved
};
//# sourceMappingURL=HighTable.js.map