@anoki/fse-ui
Version:
FSE UI components library
536 lines (535 loc) • 18.6 kB
JavaScript
import * as c from "react";
import { Primitive as L } from "./index.es487.js";
import { Presence as O } from "./index.es486.js";
import { createContextScope as le } from "./index.es477.js";
import { useComposedRefs as T } from "./index.es478.js";
import { useCallbackRef as x } from "./index.es565.js";
import { useDirection as ce } from "./index.es570.js";
import { useLayoutEffect as se } from "./index.es564.js";
import { clamp as ie } from "./index.es670.js";
import { composeEventHandlers as C } from "./index.es479.js";
import { j as b } from "./index.es237.js";
function ae(e, t) {
return c.useReducer((r, l) => t[r][l] ?? r, e);
}
var U = "ScrollArea", [F] = le(U), [de, p] = F(U), q = c.forwardRef(
(e, t) => {
const {
__scopeScrollArea: r,
type: l = "hover",
dir: o,
scrollHideDelay: n = 600,
...s
} = e, [i, a] = c.useState(null), [f, d] = c.useState(null), [h, u] = c.useState(null), [m, v] = c.useState(null), [A, Y] = c.useState(null), [P, _] = c.useState(0), [M, D] = c.useState(0), [j, y] = c.useState(!1), [W, H] = c.useState(!1), S = T(t, (R) => a(R)), w = ce(o);
return /* @__PURE__ */ b.jsx(
de,
{
scope: r,
type: l,
dir: w,
scrollHideDelay: n,
scrollArea: i,
viewport: f,
onViewportChange: d,
content: h,
onContentChange: u,
scrollbarX: m,
onScrollbarXChange: v,
scrollbarXEnabled: j,
onScrollbarXEnabledChange: y,
scrollbarY: A,
onScrollbarYChange: Y,
scrollbarYEnabled: W,
onScrollbarYEnabledChange: H,
onCornerWidthChange: _,
onCornerHeightChange: D,
children: /* @__PURE__ */ b.jsx(
L.div,
{
dir: w,
...s,
ref: S,
style: {
position: "relative",
// Pass corner sizes as CSS vars to reduce re-renders of context consumers
"--radix-scroll-area-corner-width": P + "px",
"--radix-scroll-area-corner-height": M + "px",
...e.style
}
}
)
}
);
}
);
q.displayName = U;
var $ = "ScrollAreaViewport", G = c.forwardRef(
(e, t) => {
const { __scopeScrollArea: r, children: l, nonce: o, ...n } = e, s = p($, r), i = c.useRef(null), a = T(t, i, s.onViewportChange);
return /* @__PURE__ */ b.jsxs(b.Fragment, { children: [
/* @__PURE__ */ b.jsx(
"style",
{
dangerouslySetInnerHTML: {
__html: "[data-radix-scroll-area-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-scroll-area-viewport]::-webkit-scrollbar{display:none}"
},
nonce: o
}
),
/* @__PURE__ */ b.jsx(
L.div,
{
"data-radix-scroll-area-viewport": "",
...n,
ref: a,
style: {
/**
* We don't support `visible` because the intention is to have at least one scrollbar
* if this component is used and `visible` will behave like `auto` in that case
* https://developer.mozilla.org/en-US/docs/Web/CSS/overflow#description
*
* We don't handle `auto` because the intention is for the native implementation
* to be hidden if using this component. We just want to ensure the node is scrollable
* so could have used either `scroll` or `auto` here. We picked `scroll` to prevent
* the browser from having to work out whether to render native scrollbars or not,
* we tell it to with the intention of hiding them in CSS.
*/
overflowX: s.scrollbarXEnabled ? "scroll" : "hidden",
overflowY: s.scrollbarYEnabled ? "scroll" : "hidden",
...e.style
},
children: /* @__PURE__ */ b.jsx("div", { ref: s.onContentChange, style: { minWidth: "100%", display: "table" }, children: l })
}
)
] });
}
);
G.displayName = $;
var g = "ScrollAreaScrollbar", J = c.forwardRef(
(e, t) => {
const { forceMount: r, ...l } = e, o = p(g, e.__scopeScrollArea), { onScrollbarXEnabledChange: n, onScrollbarYEnabledChange: s } = o, i = e.orientation === "horizontal";
return c.useEffect(() => (i ? n(!0) : s(!0), () => {
i ? n(!1) : s(!1);
}), [i, n, s]), o.type === "hover" ? /* @__PURE__ */ b.jsx(ue, { ...l, ref: t, forceMount: r }) : o.type === "scroll" ? /* @__PURE__ */ b.jsx(fe, { ...l, ref: t, forceMount: r }) : o.type === "auto" ? /* @__PURE__ */ b.jsx(K, { ...l, ref: t, forceMount: r }) : o.type === "always" ? /* @__PURE__ */ b.jsx(V, { ...l, ref: t }) : null;
}
);
J.displayName = g;
var ue = c.forwardRef((e, t) => {
const { forceMount: r, ...l } = e, o = p(g, e.__scopeScrollArea), [n, s] = c.useState(!1);
return c.useEffect(() => {
const i = o.scrollArea;
let a = 0;
if (i) {
const f = () => {
window.clearTimeout(a), s(!0);
}, d = () => {
a = window.setTimeout(() => s(!1), o.scrollHideDelay);
};
return i.addEventListener("pointerenter", f), i.addEventListener("pointerleave", d), () => {
window.clearTimeout(a), i.removeEventListener("pointerenter", f), i.removeEventListener("pointerleave", d);
};
}
}, [o.scrollArea, o.scrollHideDelay]), /* @__PURE__ */ b.jsx(O, { present: r || n, children: /* @__PURE__ */ b.jsx(
K,
{
"data-state": n ? "visible" : "hidden",
...l,
ref: t
}
) });
}), fe = c.forwardRef((e, t) => {
const { forceMount: r, ...l } = e, o = p(g, e.__scopeScrollArea), n = e.orientation === "horizontal", s = X(() => a("SCROLL_END"), 100), [i, a] = ae("hidden", {
hidden: {
SCROLL: "scrolling"
},
scrolling: {
SCROLL_END: "idle",
POINTER_ENTER: "interacting"
},
interacting: {
SCROLL: "interacting",
POINTER_LEAVE: "idle"
},
idle: {
HIDE: "hidden",
SCROLL: "scrolling",
POINTER_ENTER: "interacting"
}
});
return c.useEffect(() => {
if (i === "idle") {
const f = window.setTimeout(() => a("HIDE"), o.scrollHideDelay);
return () => window.clearTimeout(f);
}
}, [i, o.scrollHideDelay, a]), c.useEffect(() => {
const f = o.viewport, d = n ? "scrollLeft" : "scrollTop";
if (f) {
let h = f[d];
const u = () => {
const m = f[d];
h !== m && (a("SCROLL"), s()), h = m;
};
return f.addEventListener("scroll", u), () => f.removeEventListener("scroll", u);
}
}, [o.viewport, n, a, s]), /* @__PURE__ */ b.jsx(O, { present: r || i !== "hidden", children: /* @__PURE__ */ b.jsx(
V,
{
"data-state": i === "hidden" ? "hidden" : "visible",
...l,
ref: t,
onPointerEnter: C(e.onPointerEnter, () => a("POINTER_ENTER")),
onPointerLeave: C(e.onPointerLeave, () => a("POINTER_LEAVE"))
}
) });
}), K = c.forwardRef((e, t) => {
const r = p(g, e.__scopeScrollArea), { forceMount: l, ...o } = e, [n, s] = c.useState(!1), i = e.orientation === "horizontal", a = X(() => {
if (r.viewport) {
const f = r.viewport.offsetWidth < r.viewport.scrollWidth, d = r.viewport.offsetHeight < r.viewport.scrollHeight;
s(i ? f : d);
}
}, 10);
return E(r.viewport, a), E(r.content, a), /* @__PURE__ */ b.jsx(O, { present: l || n, children: /* @__PURE__ */ b.jsx(
V,
{
"data-state": n ? "visible" : "hidden",
...o,
ref: t
}
) });
}), V = c.forwardRef((e, t) => {
const { orientation: r = "vertical", ...l } = e, o = p(g, e.__scopeScrollArea), n = c.useRef(null), s = c.useRef(0), [i, a] = c.useState({
content: 0,
viewport: 0,
scrollbar: { size: 0, paddingStart: 0, paddingEnd: 0 }
}), f = oe(i.viewport, i.content), d = {
...l,
sizes: i,
onSizesChange: a,
hasThumb: f > 0 && f < 1,
onThumbChange: (u) => n.current = u,
onThumbPointerUp: () => s.current = 0,
onThumbPointerDown: (u) => s.current = u
};
function h(u, m) {
return pe(u, s.current, i, m);
}
return r === "horizontal" ? /* @__PURE__ */ b.jsx(
he,
{
...d,
ref: t,
onThumbPositionChange: () => {
if (o.viewport && n.current) {
const u = o.viewport.scrollLeft, m = B(u, i, o.dir);
n.current.style.transform = `translate3d(${m}px, 0, 0)`;
}
},
onWheelScroll: (u) => {
o.viewport && (o.viewport.scrollLeft = u);
},
onDragScroll: (u) => {
o.viewport && (o.viewport.scrollLeft = h(u, o.dir));
}
}
) : r === "vertical" ? /* @__PURE__ */ b.jsx(
be,
{
...d,
ref: t,
onThumbPositionChange: () => {
if (o.viewport && n.current) {
const u = o.viewport.scrollTop, m = B(u, i);
n.current.style.transform = `translate3d(0, ${m}px, 0)`;
}
},
onWheelScroll: (u) => {
o.viewport && (o.viewport.scrollTop = u);
},
onDragScroll: (u) => {
o.viewport && (o.viewport.scrollTop = h(u));
}
}
) : null;
}), he = c.forwardRef((e, t) => {
const { sizes: r, onSizesChange: l, ...o } = e, n = p(g, e.__scopeScrollArea), [s, i] = c.useState(), a = c.useRef(null), f = T(t, a, n.onScrollbarXChange);
return c.useEffect(() => {
a.current && i(getComputedStyle(a.current));
}, [a]), /* @__PURE__ */ b.jsx(
Z,
{
"data-orientation": "horizontal",
...o,
ref: f,
sizes: r,
style: {
bottom: 0,
left: n.dir === "rtl" ? "var(--radix-scroll-area-corner-width)" : 0,
right: n.dir === "ltr" ? "var(--radix-scroll-area-corner-width)" : 0,
"--radix-scroll-area-thumb-width": I(r) + "px",
...e.style
},
onThumbPointerDown: (d) => e.onThumbPointerDown(d.x),
onDragScroll: (d) => e.onDragScroll(d.x),
onWheelScroll: (d, h) => {
if (n.viewport) {
const u = n.viewport.scrollLeft + d.deltaX;
e.onWheelScroll(u), ne(u, h) && d.preventDefault();
}
},
onResize: () => {
a.current && n.viewport && s && l({
content: n.viewport.scrollWidth,
viewport: n.viewport.offsetWidth,
scrollbar: {
size: a.current.clientWidth,
paddingStart: N(s.paddingLeft),
paddingEnd: N(s.paddingRight)
}
});
}
}
);
}), be = c.forwardRef((e, t) => {
const { sizes: r, onSizesChange: l, ...o } = e, n = p(g, e.__scopeScrollArea), [s, i] = c.useState(), a = c.useRef(null), f = T(t, a, n.onScrollbarYChange);
return c.useEffect(() => {
a.current && i(getComputedStyle(a.current));
}, [a]), /* @__PURE__ */ b.jsx(
Z,
{
"data-orientation": "vertical",
...o,
ref: f,
sizes: r,
style: {
top: 0,
right: n.dir === "ltr" ? 0 : void 0,
left: n.dir === "rtl" ? 0 : void 0,
bottom: "var(--radix-scroll-area-corner-height)",
"--radix-scroll-area-thumb-height": I(r) + "px",
...e.style
},
onThumbPointerDown: (d) => e.onThumbPointerDown(d.y),
onDragScroll: (d) => e.onDragScroll(d.y),
onWheelScroll: (d, h) => {
if (n.viewport) {
const u = n.viewport.scrollTop + d.deltaY;
e.onWheelScroll(u), ne(u, h) && d.preventDefault();
}
},
onResize: () => {
a.current && n.viewport && s && l({
content: n.viewport.scrollHeight,
viewport: n.viewport.offsetHeight,
scrollbar: {
size: a.current.clientHeight,
paddingStart: N(s.paddingTop),
paddingEnd: N(s.paddingBottom)
}
});
}
}
);
}), [me, Q] = F(g), Z = c.forwardRef((e, t) => {
const {
__scopeScrollArea: r,
sizes: l,
hasThumb: o,
onThumbChange: n,
onThumbPointerUp: s,
onThumbPointerDown: i,
onThumbPositionChange: a,
onDragScroll: f,
onWheelScroll: d,
onResize: h,
...u
} = e, m = p(g, r), [v, A] = c.useState(null), Y = T(t, (S) => A(S)), P = c.useRef(null), _ = c.useRef(""), M = m.viewport, D = l.content - l.viewport, j = x(d), y = x(a), W = X(h, 10);
function H(S) {
if (P.current) {
const w = S.clientX - P.current.left, R = S.clientY - P.current.top;
f({ x: w, y: R });
}
}
return c.useEffect(() => {
const S = (w) => {
const R = w.target;
(v == null ? void 0 : v.contains(R)) && j(w, D);
};
return document.addEventListener("wheel", S, { passive: !1 }), () => document.removeEventListener("wheel", S, { passive: !1 });
}, [M, v, D, j]), c.useEffect(y, [l, y]), E(v, W), E(m.content, W), /* @__PURE__ */ b.jsx(
me,
{
scope: r,
scrollbar: v,
hasThumb: o,
onThumbChange: x(n),
onThumbPointerUp: x(s),
onThumbPositionChange: y,
onThumbPointerDown: x(i),
children: /* @__PURE__ */ b.jsx(
L.div,
{
...u,
ref: Y,
style: { position: "absolute", ...u.style },
onPointerDown: C(e.onPointerDown, (S) => {
S.button === 0 && (S.target.setPointerCapture(S.pointerId), P.current = v.getBoundingClientRect(), _.current = document.body.style.webkitUserSelect, document.body.style.webkitUserSelect = "none", m.viewport && (m.viewport.style.scrollBehavior = "auto"), H(S));
}),
onPointerMove: C(e.onPointerMove, H),
onPointerUp: C(e.onPointerUp, (S) => {
const w = S.target;
w.hasPointerCapture(S.pointerId) && w.releasePointerCapture(S.pointerId), document.body.style.webkitUserSelect = _.current, m.viewport && (m.viewport.style.scrollBehavior = ""), P.current = null;
})
}
)
}
);
}), z = "ScrollAreaThumb", ee = c.forwardRef(
(e, t) => {
const { forceMount: r, ...l } = e, o = Q(z, e.__scopeScrollArea);
return /* @__PURE__ */ b.jsx(O, { present: r || o.hasThumb, children: /* @__PURE__ */ b.jsx(Se, { ref: t, ...l }) });
}
), Se = c.forwardRef(
(e, t) => {
const { __scopeScrollArea: r, style: l, ...o } = e, n = p(z, r), s = Q(z, r), { onThumbPositionChange: i } = s, a = T(
t,
(h) => s.onThumbChange(h)
), f = c.useRef(void 0), d = X(() => {
f.current && (f.current(), f.current = void 0);
}, 100);
return c.useEffect(() => {
const h = n.viewport;
if (h) {
const u = () => {
if (d(), !f.current) {
const m = we(h, i);
f.current = m, i();
}
};
return i(), h.addEventListener("scroll", u), () => h.removeEventListener("scroll", u);
}
}, [n.viewport, d, i]), /* @__PURE__ */ b.jsx(
L.div,
{
"data-state": s.hasThumb ? "visible" : "hidden",
...o,
ref: a,
style: {
width: "var(--radix-scroll-area-thumb-width)",
height: "var(--radix-scroll-area-thumb-height)",
...l
},
onPointerDownCapture: C(e.onPointerDownCapture, (h) => {
const m = h.target.getBoundingClientRect(), v = h.clientX - m.left, A = h.clientY - m.top;
s.onThumbPointerDown({ x: v, y: A });
}),
onPointerUp: C(e.onPointerUp, s.onThumbPointerUp)
}
);
}
);
ee.displayName = z;
var k = "ScrollAreaCorner", re = c.forwardRef(
(e, t) => {
const r = p(k, e.__scopeScrollArea), l = !!(r.scrollbarX && r.scrollbarY);
return r.type !== "scroll" && l ? /* @__PURE__ */ b.jsx(ve, { ...e, ref: t }) : null;
}
);
re.displayName = k;
var ve = c.forwardRef((e, t) => {
const { __scopeScrollArea: r, ...l } = e, o = p(k, r), [n, s] = c.useState(0), [i, a] = c.useState(0), f = !!(n && i);
return E(o.scrollbarX, () => {
var h;
const d = ((h = o.scrollbarX) == null ? void 0 : h.offsetHeight) || 0;
o.onCornerHeightChange(d), a(d);
}), E(o.scrollbarY, () => {
var h;
const d = ((h = o.scrollbarY) == null ? void 0 : h.offsetWidth) || 0;
o.onCornerWidthChange(d), s(d);
}), f ? /* @__PURE__ */ b.jsx(
L.div,
{
...l,
ref: t,
style: {
width: n,
height: i,
position: "absolute",
right: o.dir === "ltr" ? 0 : void 0,
left: o.dir === "rtl" ? 0 : void 0,
bottom: 0,
...e.style
}
}
) : null;
});
function N(e) {
return e ? parseInt(e, 10) : 0;
}
function oe(e, t) {
const r = e / t;
return isNaN(r) ? 0 : r;
}
function I(e) {
const t = oe(e.viewport, e.content), r = e.scrollbar.paddingStart + e.scrollbar.paddingEnd, l = (e.scrollbar.size - r) * t;
return Math.max(l, 18);
}
function pe(e, t, r, l = "ltr") {
const o = I(r), n = o / 2, s = t || n, i = o - s, a = r.scrollbar.paddingStart + s, f = r.scrollbar.size - r.scrollbar.paddingEnd - i, d = r.content - r.viewport, h = l === "ltr" ? [0, d] : [d * -1, 0];
return te([a, f], h)(e);
}
function B(e, t, r = "ltr") {
const l = I(t), o = t.scrollbar.paddingStart + t.scrollbar.paddingEnd, n = t.scrollbar.size - o, s = t.content - t.viewport, i = n - l, a = r === "ltr" ? [0, s] : [s * -1, 0], f = ie(e, a);
return te([0, s], [0, i])(f);
}
function te(e, t) {
return (r) => {
if (e[0] === e[1] || t[0] === t[1]) return t[0];
const l = (t[1] - t[0]) / (e[1] - e[0]);
return t[0] + l * (r - e[0]);
};
}
function ne(e, t) {
return e > 0 && e < t;
}
var we = (e, t = () => {
}) => {
let r = { left: e.scrollLeft, top: e.scrollTop }, l = 0;
return (function o() {
const n = { left: e.scrollLeft, top: e.scrollTop }, s = r.left !== n.left, i = r.top !== n.top;
(s || i) && t(), r = n, l = window.requestAnimationFrame(o);
})(), () => window.cancelAnimationFrame(l);
};
function X(e, t) {
const r = x(e), l = c.useRef(0);
return c.useEffect(() => () => window.clearTimeout(l.current), []), c.useCallback(() => {
window.clearTimeout(l.current), l.current = window.setTimeout(r, t);
}, [r, t]);
}
function E(e, t) {
const r = x(t);
se(() => {
let l = 0;
if (e) {
const o = new ResizeObserver(() => {
cancelAnimationFrame(l), l = window.requestAnimationFrame(r);
});
return o.observe(e), () => {
window.cancelAnimationFrame(l), o.unobserve(e);
};
}
}, [e, r]);
}
var De = q, je = G, We = J, He = ee, ze = re;
export {
ze as Corner,
De as Root,
q as ScrollArea,
re as ScrollAreaCorner,
J as ScrollAreaScrollbar,
ee as ScrollAreaThumb,
G as ScrollAreaViewport,
We as Scrollbar,
He as Thumb,
je as Viewport
};
//# sourceMappingURL=index.es634.js.map