UNPKG

@anoki/fse-ui

Version:

FSE UI components library

536 lines (535 loc) • 18.6 kB
import * as c from "react"; import { Primitive as L } from "./index.es477.js"; import { Presence as O } from "./index.es476.js"; import { createContextScope as le } from "./index.es464.js"; import { useComposedRefs as T } from "./index.es465.js"; import { useCallbackRef as x } from "./index.es562.js"; import { useDirection as ce } from "./index.es569.js"; import { useLayoutEffect as se } from "./index.es561.js"; import { clamp as ie } from "./index.es665.js"; import { composeEventHandlers as C } from "./index.es466.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