lexio
Version:
Quickest way to production grade RAG UI.
615 lines (614 loc) • 21.2 kB
JavaScript
import * as S from "react";
import { flushSync as T } from "react-dom";
function p(o, r, e) {
let s = e.initialDeps ?? [], t;
function n() {
var i, l, h, c;
let a;
e.key && ((i = e.debug) != null && i.call(e)) && (a = Date.now());
const u = o();
if (!(u.length !== s.length || u.some((m, f) => s[f] !== m)))
return t;
s = u;
let v;
if (e.key && ((l = e.debug) != null && l.call(e)) && (v = Date.now()), t = r(...u), e.key && ((h = e.debug) != null && h.call(e))) {
const m = Math.round((Date.now() - a) * 100) / 100, f = Math.round((Date.now() - v) * 100) / 100, x = f / 16, E = (g, C) => {
for (g = String(g); g.length < C; )
g = " " + g;
return g;
};
console.info(
`%c⏱ ${E(f, 5)} /${E(m, 5)} ms`,
`
font-size: .6rem;
font-weight: bold;
color: hsl(${Math.max(
0,
Math.min(120 - 120 * x, 120)
)}deg 100% 31%);`,
e == null ? void 0 : e.key
);
}
return (c = e == null ? void 0 : e.onChange) == null || c.call(e, t), t;
}
return n.updateDeps = (i) => {
s = i;
}, n;
}
function z(o, r) {
if (o === void 0)
throw new Error(`Unexpected undefined${r ? `: ${r}` : ""}`);
return o;
}
const R = (o, r) => Math.abs(o - r) < 1, M = (o, r, e) => {
let s;
return function(...t) {
o.clearTimeout(s), s = o.setTimeout(() => r.apply(this, t), e);
};
}, _ = (o) => o, W = (o) => {
const r = Math.max(o.startIndex - o.overscan, 0), e = Math.min(o.endIndex + o.overscan, o.count - 1), s = [];
for (let t = r; t <= e; t++)
s.push(t);
return s;
}, k = (o, r) => {
const e = o.scrollElement;
if (!e)
return;
const s = o.targetWindow;
if (!s)
return;
const t = (i) => {
const { width: l, height: h } = i;
r({ width: Math.round(l), height: Math.round(h) });
};
if (t(e.getBoundingClientRect()), !s.ResizeObserver)
return () => {
};
const n = new s.ResizeObserver((i) => {
const l = () => {
const h = i[0];
if (h != null && h.borderBoxSize) {
const c = h.borderBoxSize[0];
if (c) {
t({ width: c.inlineSize, height: c.blockSize });
return;
}
}
t(e.getBoundingClientRect());
};
o.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(l) : l();
});
return n.observe(e, { box: "border-box" }), () => {
n.unobserve(e);
};
}, b = {
passive: !0
}, A = (o, r) => {
const e = o.scrollElement;
if (!e)
return;
const s = () => {
r({ width: e.innerWidth, height: e.innerHeight });
};
return s(), e.addEventListener("resize", s, b), () => {
e.removeEventListener("resize", s);
};
}, w = typeof window > "u" ? !0 : "onscrollend" in window, D = (o, r) => {
const e = o.scrollElement;
if (!e)
return;
const s = o.targetWindow;
if (!s)
return;
let t = 0;
const n = o.options.useScrollendEvent && w ? () => {
} : M(
s,
() => {
r(t, !1);
},
o.options.isScrollingResetDelay
), i = (a) => () => {
const { horizontal: u, isRtl: d } = o.options;
t = u ? e.scrollLeft * (d && -1 || 1) : e.scrollTop, n(), r(t, a);
}, l = i(!0), h = i(!1);
h(), e.addEventListener("scroll", l, b);
const c = o.options.useScrollendEvent && w;
return c && e.addEventListener("scrollend", h, b), () => {
e.removeEventListener("scroll", l), c && e.removeEventListener("scrollend", h);
};
}, F = (o, r) => {
const e = o.scrollElement;
if (!e)
return;
const s = o.targetWindow;
if (!s)
return;
let t = 0;
const n = o.options.useScrollendEvent && w ? () => {
} : M(
s,
() => {
r(t, !1);
},
o.options.isScrollingResetDelay
), i = (a) => () => {
t = e[o.options.horizontal ? "scrollX" : "scrollY"], n(), r(t, a);
}, l = i(!0), h = i(!1);
h(), e.addEventListener("scroll", l, b);
const c = o.options.useScrollendEvent && w;
return c && e.addEventListener("scrollend", h, b), () => {
e.removeEventListener("scroll", l), c && e.removeEventListener("scrollend", h);
};
}, L = (o, r, e) => {
if (r != null && r.borderBoxSize) {
const s = r.borderBoxSize[0];
if (s)
return Math.round(
s[e.options.horizontal ? "inlineSize" : "blockSize"]
);
}
return Math.round(
o.getBoundingClientRect()[e.options.horizontal ? "width" : "height"]
);
}, j = (o, {
adjustments: r = 0,
behavior: e
}, s) => {
var t, n;
const i = o + r;
(n = (t = s.scrollElement) == null ? void 0 : t.scrollTo) == null || n.call(t, {
[s.options.horizontal ? "left" : "top"]: i,
behavior: e
});
}, B = (o, {
adjustments: r = 0,
behavior: e
}, s) => {
var t, n;
const i = o + r;
(n = (t = s.scrollElement) == null ? void 0 : t.scrollTo) == null || n.call(t, {
[s.options.horizontal ? "left" : "top"]: i,
behavior: e
});
};
class P {
constructor(r) {
this.unsubs = [], this.scrollElement = null, this.targetWindow = null, this.isScrolling = !1, this.scrollToIndexTimeoutId = null, this.measurementsCache = [], this.itemSizeCache = /* @__PURE__ */ new Map(), this.pendingMeasuredCacheIndexes = [], this.scrollRect = null, this.scrollOffset = null, this.scrollDirection = null, this.scrollAdjustments = 0, this.elementsCache = /* @__PURE__ */ new Map(), this.observer = /* @__PURE__ */ (() => {
let e = null;
const s = () => e || (!this.targetWindow || !this.targetWindow.ResizeObserver ? null : e = new this.targetWindow.ResizeObserver((t) => {
t.forEach((n) => {
const i = () => {
this._measureElement(n.target, n);
};
this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(i) : i();
});
}));
return {
disconnect: () => {
var t;
(t = s()) == null || t.disconnect(), e = null;
},
observe: (t) => {
var n;
return (n = s()) == null ? void 0 : n.observe(t, { box: "border-box" });
},
unobserve: (t) => {
var n;
return (n = s()) == null ? void 0 : n.unobserve(t);
}
};
})(), this.range = null, this.setOptions = (e) => {
Object.entries(e).forEach(([s, t]) => {
typeof t > "u" && delete e[s];
}), this.options = {
debug: !1,
initialOffset: 0,
overscan: 1,
paddingStart: 0,
paddingEnd: 0,
scrollPaddingStart: 0,
scrollPaddingEnd: 0,
horizontal: !1,
getItemKey: _,
rangeExtractor: W,
onChange: () => {
},
measureElement: L,
initialRect: { width: 0, height: 0 },
scrollMargin: 0,
gap: 0,
indexAttribute: "data-index",
initialMeasurementsCache: [],
lanes: 1,
isScrollingResetDelay: 150,
enabled: !0,
isRtl: !1,
useScrollendEvent: !1,
useAnimationFrameWithResizeObserver: !1,
...e
};
}, this.notify = (e) => {
var s, t;
(t = (s = this.options).onChange) == null || t.call(s, this, e);
}, this.maybeNotify = p(
() => (this.calculateRange(), [
this.isScrolling,
this.range ? this.range.startIndex : null,
this.range ? this.range.endIndex : null
]),
(e) => {
this.notify(e);
},
{
key: !1,
debug: () => this.options.debug,
initialDeps: [
this.isScrolling,
this.range ? this.range.startIndex : null,
this.range ? this.range.endIndex : null
]
}
), this.cleanup = () => {
this.unsubs.filter(Boolean).forEach((e) => e()), this.unsubs = [], this.observer.disconnect(), this.scrollElement = null, this.targetWindow = null;
}, this._didMount = () => () => {
this.cleanup();
}, this._willUpdate = () => {
var e;
const s = this.options.enabled ? this.options.getScrollElement() : null;
if (this.scrollElement !== s) {
if (this.cleanup(), !s) {
this.maybeNotify();
return;
}
this.scrollElement = s, this.scrollElement && "ownerDocument" in this.scrollElement ? this.targetWindow = this.scrollElement.ownerDocument.defaultView : this.targetWindow = ((e = this.scrollElement) == null ? void 0 : e.window) ?? null, this.elementsCache.forEach((t) => {
this.observer.observe(t);
}), this._scrollToOffset(this.getScrollOffset(), {
adjustments: void 0,
behavior: void 0
}), this.unsubs.push(
this.options.observeElementRect(this, (t) => {
this.scrollRect = t, this.maybeNotify();
})
), this.unsubs.push(
this.options.observeElementOffset(this, (t, n) => {
this.scrollAdjustments = 0, this.scrollDirection = n ? this.getScrollOffset() < t ? "forward" : "backward" : null, this.scrollOffset = t, this.isScrolling = n, this.maybeNotify();
})
);
}
}, this.getSize = () => this.options.enabled ? (this.scrollRect = this.scrollRect ?? this.options.initialRect, this.scrollRect[this.options.horizontal ? "width" : "height"]) : (this.scrollRect = null, 0), this.getScrollOffset = () => this.options.enabled ? (this.scrollOffset = this.scrollOffset ?? (typeof this.options.initialOffset == "function" ? this.options.initialOffset() : this.options.initialOffset), this.scrollOffset) : (this.scrollOffset = null, 0), this.getFurthestMeasurement = (e, s) => {
const t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
for (let i = s - 1; i >= 0; i--) {
const l = e[i];
if (t.has(l.lane))
continue;
const h = n.get(
l.lane
);
if (h == null || l.end > h.end ? n.set(l.lane, l) : l.end < h.end && t.set(l.lane, !0), t.size === this.options.lanes)
break;
}
return n.size === this.options.lanes ? Array.from(n.values()).sort((i, l) => i.end === l.end ? i.index - l.index : i.end - l.end)[0] : void 0;
}, this.getMeasurementOptions = p(
() => [
this.options.count,
this.options.paddingStart,
this.options.scrollMargin,
this.options.getItemKey,
this.options.enabled
],
(e, s, t, n, i) => (this.pendingMeasuredCacheIndexes = [], {
count: e,
paddingStart: s,
scrollMargin: t,
getItemKey: n,
enabled: i
}),
{
key: !1
}
), this.getMeasurements = p(
() => [this.getMeasurementOptions(), this.itemSizeCache],
({ count: e, paddingStart: s, scrollMargin: t, getItemKey: n, enabled: i }, l) => {
if (!i)
return this.measurementsCache = [], this.itemSizeCache.clear(), [];
this.measurementsCache.length === 0 && (this.measurementsCache = this.options.initialMeasurementsCache, this.measurementsCache.forEach((a) => {
this.itemSizeCache.set(a.key, a.size);
}));
const h = this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;
this.pendingMeasuredCacheIndexes = [];
const c = this.measurementsCache.slice(0, h);
for (let a = h; a < e; a++) {
const u = n(a), d = this.options.lanes === 1 ? c[a - 1] : this.getFurthestMeasurement(c, a), v = d ? d.end + this.options.gap : s + t, m = l.get(u), f = typeof m == "number" ? m : this.options.estimateSize(a), x = v + f, E = d ? d.lane : a % this.options.lanes;
c[a] = {
index: a,
start: v,
size: f,
end: x,
key: u,
lane: E
};
}
return this.measurementsCache = c, c;
},
{
key: !1,
debug: () => this.options.debug
}
), this.calculateRange = p(
() => [
this.getMeasurements(),
this.getSize(),
this.getScrollOffset(),
this.options.lanes
],
(e, s, t, n) => this.range = e.length > 0 && s > 0 ? V({
measurements: e,
outerSize: s,
scrollOffset: t,
lanes: n
}) : null,
{
key: !1,
debug: () => this.options.debug
}
), this.getVirtualIndexes = p(
() => {
let e = null, s = null;
const t = this.calculateRange();
return t && (e = t.startIndex, s = t.endIndex), this.maybeNotify.updateDeps([this.isScrolling, e, s]), [
this.options.rangeExtractor,
this.options.overscan,
this.options.count,
e,
s
];
},
(e, s, t, n, i) => n === null || i === null ? [] : e({
startIndex: n,
endIndex: i,
overscan: s,
count: t
}),
{
key: !1,
debug: () => this.options.debug
}
), this.indexFromElement = (e) => {
const s = this.options.indexAttribute, t = e.getAttribute(s);
return t ? parseInt(t, 10) : (console.warn(
`Missing attribute name '${s}={index}' on measured element.`
), -1);
}, this._measureElement = (e, s) => {
const t = this.indexFromElement(e), n = this.measurementsCache[t];
if (!n)
return;
const i = n.key, l = this.elementsCache.get(i);
l !== e && (l && this.observer.unobserve(l), this.observer.observe(e), this.elementsCache.set(i, e)), e.isConnected && this.resizeItem(t, this.options.measureElement(e, s, this));
}, this.resizeItem = (e, s) => {
const t = this.measurementsCache[e];
if (!t)
return;
const n = this.itemSizeCache.get(t.key) ?? t.size, i = s - n;
i !== 0 && ((this.shouldAdjustScrollPositionOnItemSizeChange !== void 0 ? this.shouldAdjustScrollPositionOnItemSizeChange(t, i, this) : t.start < this.getScrollOffset() + this.scrollAdjustments) && this._scrollToOffset(this.getScrollOffset(), {
adjustments: this.scrollAdjustments += i,
behavior: void 0
}), this.pendingMeasuredCacheIndexes.push(t.index), this.itemSizeCache = new Map(this.itemSizeCache.set(t.key, s)), this.notify(!1));
}, this.measureElement = (e) => {
if (!e) {
this.elementsCache.forEach((s, t) => {
s.isConnected || (this.observer.unobserve(s), this.elementsCache.delete(t));
});
return;
}
this._measureElement(e, void 0);
}, this.getVirtualItems = p(
() => [this.getVirtualIndexes(), this.getMeasurements()],
(e, s) => {
const t = [];
for (let n = 0, i = e.length; n < i; n++) {
const l = e[n], h = s[l];
t.push(h);
}
return t;
},
{
key: !1,
debug: () => this.options.debug
}
), this.getVirtualItemForOffset = (e) => {
const s = this.getMeasurements();
if (s.length !== 0)
return z(
s[I(
0,
s.length - 1,
(t) => z(s[t]).start,
e
)]
);
}, this.getOffsetForAlignment = (e, s, t = 0) => {
const n = this.getSize(), i = this.getScrollOffset();
s === "auto" && (s = e >= i + n ? "end" : "start"), s === "center" ? e += (t - n) / 2 : s === "end" && (e -= n);
const l = this.options.horizontal ? "scrollWidth" : "scrollHeight", c = (this.scrollElement ? "document" in this.scrollElement ? this.scrollElement.document.documentElement[l] : this.scrollElement[l] : 0) - n;
return Math.max(Math.min(c, e), 0);
}, this.getOffsetForIndex = (e, s = "auto") => {
e = Math.max(0, Math.min(e, this.options.count - 1));
const t = this.measurementsCache[e];
if (!t)
return;
const n = this.getSize(), i = this.getScrollOffset();
if (s === "auto")
if (t.end >= i + n - this.options.scrollPaddingEnd)
s = "end";
else if (t.start <= i + this.options.scrollPaddingStart)
s = "start";
else
return [i, s];
const l = s === "end" ? t.end + this.options.scrollPaddingEnd : t.start - this.options.scrollPaddingStart;
return [
this.getOffsetForAlignment(l, s, t.size),
s
];
}, this.isDynamicMode = () => this.elementsCache.size > 0, this.cancelScrollToIndex = () => {
this.scrollToIndexTimeoutId !== null && this.targetWindow && (this.targetWindow.clearTimeout(this.scrollToIndexTimeoutId), this.scrollToIndexTimeoutId = null);
}, this.scrollToOffset = (e, { align: s = "start", behavior: t } = {}) => {
this.cancelScrollToIndex(), t === "smooth" && this.isDynamicMode() && console.warn(
"The `smooth` scroll behavior is not fully supported with dynamic size."
), this._scrollToOffset(this.getOffsetForAlignment(e, s), {
adjustments: void 0,
behavior: t
});
}, this.scrollToIndex = (e, { align: s = "auto", behavior: t } = {}) => {
e = Math.max(0, Math.min(e, this.options.count - 1)), this.cancelScrollToIndex(), t === "smooth" && this.isDynamicMode() && console.warn(
"The `smooth` scroll behavior is not fully supported with dynamic size."
);
const n = this.getOffsetForIndex(e, s);
if (!n) return;
const [i, l] = n;
this._scrollToOffset(i, { adjustments: void 0, behavior: t }), t !== "smooth" && this.isDynamicMode() && this.targetWindow && (this.scrollToIndexTimeoutId = this.targetWindow.setTimeout(() => {
if (this.scrollToIndexTimeoutId = null, this.elementsCache.has(
this.options.getItemKey(e)
)) {
const [c] = z(
this.getOffsetForIndex(e, l)
);
R(c, this.getScrollOffset()) || this.scrollToIndex(e, { align: l, behavior: t });
} else
this.scrollToIndex(e, { align: l, behavior: t });
}));
}, this.scrollBy = (e, { behavior: s } = {}) => {
this.cancelScrollToIndex(), s === "smooth" && this.isDynamicMode() && console.warn(
"The `smooth` scroll behavior is not fully supported with dynamic size."
), this._scrollToOffset(this.getScrollOffset() + e, {
adjustments: void 0,
behavior: s
});
}, this.getTotalSize = () => {
var e;
const s = this.getMeasurements();
let t;
if (s.length === 0)
t = this.options.paddingStart;
else if (this.options.lanes === 1)
t = ((e = s[s.length - 1]) == null ? void 0 : e.end) ?? 0;
else {
const n = Array(this.options.lanes).fill(null);
let i = s.length - 1;
for (; i >= 0 && n.some((l) => l === null); ) {
const l = s[i];
n[l.lane] === null && (n[l.lane] = l.end), i--;
}
t = Math.max(...n.filter((l) => l !== null));
}
return Math.max(
t - this.options.scrollMargin + this.options.paddingEnd,
0
);
}, this._scrollToOffset = (e, {
adjustments: s,
behavior: t
}) => {
this.options.scrollToFn(e, { behavior: t, adjustments: s }, this);
}, this.measure = () => {
this.itemSizeCache = /* @__PURE__ */ new Map(), this.notify(!1);
}, this.setOptions(r);
}
}
const I = (o, r, e, s) => {
for (; o <= r; ) {
const t = (o + r) / 2 | 0, n = e(t);
if (n < s)
o = t + 1;
else if (n > s)
r = t - 1;
else
return t;
}
return o > 0 ? o - 1 : 0;
};
function V({
measurements: o,
outerSize: r,
scrollOffset: e,
lanes: s
}) {
const t = o.length - 1, n = (h) => o[h].start;
if (o.length <= s)
return {
startIndex: 0,
endIndex: t
};
let i = I(
0,
t,
n,
e
), l = i;
if (s === 1)
for (; l < t && o[l].end < e + r; )
l++;
else if (s > 1) {
const h = Array(s).fill(0);
for (; l < t && h.some((a) => a < e + r); ) {
const a = o[l];
h[a.lane] = a.end, l++;
}
const c = Array(s).fill(e + r);
for (; i >= 0 && c.some((a) => a >= e); ) {
const a = o[i];
c[a.lane] = a.start, i--;
}
i = Math.max(0, i - i % s), l = Math.min(t, l + (s - 1 - l % s));
}
return { startIndex: i, endIndex: l };
}
const y = typeof document < "u" ? S.useLayoutEffect : S.useEffect;
function O(o) {
const r = S.useReducer(() => ({}), {})[1], e = {
...o,
onChange: (t, n) => {
var i;
n ? T(r) : r(), (i = o.onChange) == null || i.call(o, t, n);
}
}, [s] = S.useState(
() => new P(e)
);
return s.setOptions(e), y(() => s._didMount(), []), y(() => s._willUpdate()), s;
}
function H(o) {
return O({
observeElementRect: k,
observeElementOffset: D,
scrollToFn: B,
...o
});
}
function $(o) {
return O({
getScrollElement: () => typeof document < "u" ? window : null,
observeElementRect: A,
observeElementOffset: F,
scrollToFn: j,
initialOffset: () => typeof document < "u" ? window.scrollY : 0,
...o
});
}
export {
P as Virtualizer,
R as approxEqual,
M as debounce,
_ as defaultKeyExtractor,
W as defaultRangeExtractor,
B as elementScroll,
L as measureElement,
p as memo,
z as notUndefined,
D as observeElementOffset,
k as observeElementRect,
F as observeWindowOffset,
A as observeWindowRect,
H as useVirtualizer,
$ as useWindowVirtualizer,
j as windowScroll
};