Spaces:
Build error
Build error
| ; | |
| "use client"; | |
| var __create = Object.create; | |
| var __defProp = Object.defineProperty; | |
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | |
| var __getOwnPropNames = Object.getOwnPropertyNames; | |
| var __getProtoOf = Object.getPrototypeOf; | |
| var __hasOwnProp = Object.prototype.hasOwnProperty; | |
| var __export = (target, all) => { | |
| for (var name in all) | |
| __defProp(target, name, { get: all[name], enumerable: true }); | |
| }; | |
| var __copyProps = (to, from, except, desc) => { | |
| if (from && typeof from === "object" || typeof from === "function") { | |
| for (let key of __getOwnPropNames(from)) | |
| if (!__hasOwnProp.call(to, key) && key !== except) | |
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | |
| } | |
| return to; | |
| }; | |
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | |
| // If the importer is in node compatibility mode or this is not an ESM | |
| // file that has been converted to a CommonJS file using a Babel- | |
| // compatible transform (i.e. "__esModule" has not been set), then set | |
| // "default" to the CommonJS "module.exports" for node compatibility. | |
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | |
| mod | |
| )); | |
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | |
| // src/index.ts | |
| var index_exports = {}; | |
| __export(index_exports, { | |
| Corner: () => Corner, | |
| Root: () => Root, | |
| ScrollArea: () => ScrollArea, | |
| ScrollAreaCorner: () => ScrollAreaCorner, | |
| ScrollAreaScrollbar: () => ScrollAreaScrollbar, | |
| ScrollAreaThumb: () => ScrollAreaThumb, | |
| ScrollAreaViewport: () => ScrollAreaViewport, | |
| Scrollbar: () => Scrollbar, | |
| Thumb: () => Thumb, | |
| Viewport: () => Viewport, | |
| createScrollAreaScope: () => createScrollAreaScope | |
| }); | |
| module.exports = __toCommonJS(index_exports); | |
| // src/scroll-area.tsx | |
| var React2 = __toESM(require("react")); | |
| var import_react_primitive = require("@radix-ui/react-primitive"); | |
| var import_react_presence = require("@radix-ui/react-presence"); | |
| var import_react_context = require("@radix-ui/react-context"); | |
| var import_react_compose_refs = require("@radix-ui/react-compose-refs"); | |
| var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref"); | |
| var import_react_direction = require("@radix-ui/react-direction"); | |
| var import_react_use_layout_effect = require("@radix-ui/react-use-layout-effect"); | |
| var import_number = require("@radix-ui/number"); | |
| var import_primitive = require("@radix-ui/primitive"); | |
| // src/use-state-machine.ts | |
| var React = __toESM(require("react")); | |
| function useStateMachine(initialState, machine) { | |
| return React.useReducer((state, event) => { | |
| const nextState = machine[state][event]; | |
| return nextState ?? state; | |
| }, initialState); | |
| } | |
| // src/scroll-area.tsx | |
| var import_jsx_runtime = require("react/jsx-runtime"); | |
| var SCROLL_AREA_NAME = "ScrollArea"; | |
| var [createScrollAreaContext, createScrollAreaScope] = (0, import_react_context.createContextScope)(SCROLL_AREA_NAME); | |
| var [ScrollAreaProvider, useScrollAreaContext] = createScrollAreaContext(SCROLL_AREA_NAME); | |
| var ScrollArea = React2.forwardRef( | |
| (props, forwardedRef) => { | |
| const { | |
| __scopeScrollArea, | |
| type = "hover", | |
| dir, | |
| scrollHideDelay = 600, | |
| ...scrollAreaProps | |
| } = props; | |
| const [scrollArea, setScrollArea] = React2.useState(null); | |
| const [viewport, setViewport] = React2.useState(null); | |
| const [content, setContent] = React2.useState(null); | |
| const [scrollbarX, setScrollbarX] = React2.useState(null); | |
| const [scrollbarY, setScrollbarY] = React2.useState(null); | |
| const [cornerWidth, setCornerWidth] = React2.useState(0); | |
| const [cornerHeight, setCornerHeight] = React2.useState(0); | |
| const [scrollbarXEnabled, setScrollbarXEnabled] = React2.useState(false); | |
| const [scrollbarYEnabled, setScrollbarYEnabled] = React2.useState(false); | |
| const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, (node) => setScrollArea(node)); | |
| const direction = (0, import_react_direction.useDirection)(dir); | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| ScrollAreaProvider, | |
| { | |
| scope: __scopeScrollArea, | |
| type, | |
| dir: direction, | |
| scrollHideDelay, | |
| scrollArea, | |
| viewport, | |
| onViewportChange: setViewport, | |
| content, | |
| onContentChange: setContent, | |
| scrollbarX, | |
| onScrollbarXChange: setScrollbarX, | |
| scrollbarXEnabled, | |
| onScrollbarXEnabledChange: setScrollbarXEnabled, | |
| scrollbarY, | |
| onScrollbarYChange: setScrollbarY, | |
| scrollbarYEnabled, | |
| onScrollbarYEnabledChange: setScrollbarYEnabled, | |
| onCornerWidthChange: setCornerWidth, | |
| onCornerHeightChange: setCornerHeight, | |
| children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| import_react_primitive.Primitive.div, | |
| { | |
| dir: direction, | |
| ...scrollAreaProps, | |
| ref: composedRefs, | |
| style: { | |
| position: "relative", | |
| // Pass corner sizes as CSS vars to reduce re-renders of context consumers | |
| ["--radix-scroll-area-corner-width"]: cornerWidth + "px", | |
| ["--radix-scroll-area-corner-height"]: cornerHeight + "px", | |
| ...props.style | |
| } | |
| } | |
| ) | |
| } | |
| ); | |
| } | |
| ); | |
| ScrollArea.displayName = SCROLL_AREA_NAME; | |
| var VIEWPORT_NAME = "ScrollAreaViewport"; | |
| var ScrollAreaViewport = React2.forwardRef( | |
| (props, forwardedRef) => { | |
| const { __scopeScrollArea, children, nonce, ...viewportProps } = props; | |
| const context = useScrollAreaContext(VIEWPORT_NAME, __scopeScrollArea); | |
| const ref = React2.useRef(null); | |
| const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref, context.onViewportChange); | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ | |
| /* @__PURE__ */ (0, import_jsx_runtime.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 | |
| } | |
| ), | |
| /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| import_react_primitive.Primitive.div, | |
| { | |
| "data-radix-scroll-area-viewport": "", | |
| ...viewportProps, | |
| ref: composedRefs, | |
| 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: context.scrollbarXEnabled ? "scroll" : "hidden", | |
| overflowY: context.scrollbarYEnabled ? "scroll" : "hidden", | |
| ...props.style | |
| }, | |
| children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: context.onContentChange, style: { minWidth: "100%", display: "table" }, children }) | |
| } | |
| ) | |
| ] }); | |
| } | |
| ); | |
| ScrollAreaViewport.displayName = VIEWPORT_NAME; | |
| var SCROLLBAR_NAME = "ScrollAreaScrollbar"; | |
| var ScrollAreaScrollbar = React2.forwardRef( | |
| (props, forwardedRef) => { | |
| const { forceMount, ...scrollbarProps } = props; | |
| const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea); | |
| const { onScrollbarXEnabledChange, onScrollbarYEnabledChange } = context; | |
| const isHorizontal = props.orientation === "horizontal"; | |
| React2.useEffect(() => { | |
| isHorizontal ? onScrollbarXEnabledChange(true) : onScrollbarYEnabledChange(true); | |
| return () => { | |
| isHorizontal ? onScrollbarXEnabledChange(false) : onScrollbarYEnabledChange(false); | |
| }; | |
| }, [isHorizontal, onScrollbarXEnabledChange, onScrollbarYEnabledChange]); | |
| return context.type === "hover" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollAreaScrollbarHover, { ...scrollbarProps, ref: forwardedRef, forceMount }) : context.type === "scroll" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollAreaScrollbarScroll, { ...scrollbarProps, ref: forwardedRef, forceMount }) : context.type === "auto" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollAreaScrollbarAuto, { ...scrollbarProps, ref: forwardedRef, forceMount }) : context.type === "always" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollAreaScrollbarVisible, { ...scrollbarProps, ref: forwardedRef }) : null; | |
| } | |
| ); | |
| ScrollAreaScrollbar.displayName = SCROLLBAR_NAME; | |
| var ScrollAreaScrollbarHover = React2.forwardRef((props, forwardedRef) => { | |
| const { forceMount, ...scrollbarProps } = props; | |
| const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea); | |
| const [visible, setVisible] = React2.useState(false); | |
| React2.useEffect(() => { | |
| const scrollArea = context.scrollArea; | |
| let hideTimer = 0; | |
| if (scrollArea) { | |
| const handlePointerEnter = () => { | |
| window.clearTimeout(hideTimer); | |
| setVisible(true); | |
| }; | |
| const handlePointerLeave = () => { | |
| hideTimer = window.setTimeout(() => setVisible(false), context.scrollHideDelay); | |
| }; | |
| scrollArea.addEventListener("pointerenter", handlePointerEnter); | |
| scrollArea.addEventListener("pointerleave", handlePointerLeave); | |
| return () => { | |
| window.clearTimeout(hideTimer); | |
| scrollArea.removeEventListener("pointerenter", handlePointerEnter); | |
| scrollArea.removeEventListener("pointerleave", handlePointerLeave); | |
| }; | |
| } | |
| }, [context.scrollArea, context.scrollHideDelay]); | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || visible, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| ScrollAreaScrollbarAuto, | |
| { | |
| "data-state": visible ? "visible" : "hidden", | |
| ...scrollbarProps, | |
| ref: forwardedRef | |
| } | |
| ) }); | |
| }); | |
| var ScrollAreaScrollbarScroll = React2.forwardRef((props, forwardedRef) => { | |
| const { forceMount, ...scrollbarProps } = props; | |
| const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea); | |
| const isHorizontal = props.orientation === "horizontal"; | |
| const debounceScrollEnd = useDebounceCallback(() => send("SCROLL_END"), 100); | |
| const [state, send] = useStateMachine("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" | |
| } | |
| }); | |
| React2.useEffect(() => { | |
| if (state === "idle") { | |
| const hideTimer = window.setTimeout(() => send("HIDE"), context.scrollHideDelay); | |
| return () => window.clearTimeout(hideTimer); | |
| } | |
| }, [state, context.scrollHideDelay, send]); | |
| React2.useEffect(() => { | |
| const viewport = context.viewport; | |
| const scrollDirection = isHorizontal ? "scrollLeft" : "scrollTop"; | |
| if (viewport) { | |
| let prevScrollPos = viewport[scrollDirection]; | |
| const handleScroll = () => { | |
| const scrollPos = viewport[scrollDirection]; | |
| const hasScrollInDirectionChanged = prevScrollPos !== scrollPos; | |
| if (hasScrollInDirectionChanged) { | |
| send("SCROLL"); | |
| debounceScrollEnd(); | |
| } | |
| prevScrollPos = scrollPos; | |
| }; | |
| viewport.addEventListener("scroll", handleScroll); | |
| return () => viewport.removeEventListener("scroll", handleScroll); | |
| } | |
| }, [context.viewport, isHorizontal, send, debounceScrollEnd]); | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || state !== "hidden", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| ScrollAreaScrollbarVisible, | |
| { | |
| "data-state": state === "hidden" ? "hidden" : "visible", | |
| ...scrollbarProps, | |
| ref: forwardedRef, | |
| onPointerEnter: (0, import_primitive.composeEventHandlers)(props.onPointerEnter, () => send("POINTER_ENTER")), | |
| onPointerLeave: (0, import_primitive.composeEventHandlers)(props.onPointerLeave, () => send("POINTER_LEAVE")) | |
| } | |
| ) }); | |
| }); | |
| var ScrollAreaScrollbarAuto = React2.forwardRef((props, forwardedRef) => { | |
| const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea); | |
| const { forceMount, ...scrollbarProps } = props; | |
| const [visible, setVisible] = React2.useState(false); | |
| const isHorizontal = props.orientation === "horizontal"; | |
| const handleResize = useDebounceCallback(() => { | |
| if (context.viewport) { | |
| const isOverflowX = context.viewport.offsetWidth < context.viewport.scrollWidth; | |
| const isOverflowY = context.viewport.offsetHeight < context.viewport.scrollHeight; | |
| setVisible(isHorizontal ? isOverflowX : isOverflowY); | |
| } | |
| }, 10); | |
| useResizeObserver(context.viewport, handleResize); | |
| useResizeObserver(context.content, handleResize); | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || visible, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| ScrollAreaScrollbarVisible, | |
| { | |
| "data-state": visible ? "visible" : "hidden", | |
| ...scrollbarProps, | |
| ref: forwardedRef | |
| } | |
| ) }); | |
| }); | |
| var ScrollAreaScrollbarVisible = React2.forwardRef((props, forwardedRef) => { | |
| const { orientation = "vertical", ...scrollbarProps } = props; | |
| const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea); | |
| const thumbRef = React2.useRef(null); | |
| const pointerOffsetRef = React2.useRef(0); | |
| const [sizes, setSizes] = React2.useState({ | |
| content: 0, | |
| viewport: 0, | |
| scrollbar: { size: 0, paddingStart: 0, paddingEnd: 0 } | |
| }); | |
| const thumbRatio = getThumbRatio(sizes.viewport, sizes.content); | |
| const commonProps = { | |
| ...scrollbarProps, | |
| sizes, | |
| onSizesChange: setSizes, | |
| hasThumb: Boolean(thumbRatio > 0 && thumbRatio < 1), | |
| onThumbChange: (thumb) => thumbRef.current = thumb, | |
| onThumbPointerUp: () => pointerOffsetRef.current = 0, | |
| onThumbPointerDown: (pointerPos) => pointerOffsetRef.current = pointerPos | |
| }; | |
| function getScrollPosition(pointerPos, dir) { | |
| return getScrollPositionFromPointer(pointerPos, pointerOffsetRef.current, sizes, dir); | |
| } | |
| if (orientation === "horizontal") { | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| ScrollAreaScrollbarX, | |
| { | |
| ...commonProps, | |
| ref: forwardedRef, | |
| onThumbPositionChange: () => { | |
| if (context.viewport && thumbRef.current) { | |
| const scrollPos = context.viewport.scrollLeft; | |
| const offset = getThumbOffsetFromScroll(scrollPos, sizes, context.dir); | |
| thumbRef.current.style.transform = `translate3d(${offset}px, 0, 0)`; | |
| } | |
| }, | |
| onWheelScroll: (scrollPos) => { | |
| if (context.viewport) context.viewport.scrollLeft = scrollPos; | |
| }, | |
| onDragScroll: (pointerPos) => { | |
| if (context.viewport) { | |
| context.viewport.scrollLeft = getScrollPosition(pointerPos, context.dir); | |
| } | |
| } | |
| } | |
| ); | |
| } | |
| if (orientation === "vertical") { | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| ScrollAreaScrollbarY, | |
| { | |
| ...commonProps, | |
| ref: forwardedRef, | |
| onThumbPositionChange: () => { | |
| if (context.viewport && thumbRef.current) { | |
| const scrollPos = context.viewport.scrollTop; | |
| const offset = getThumbOffsetFromScroll(scrollPos, sizes); | |
| thumbRef.current.style.transform = `translate3d(0, ${offset}px, 0)`; | |
| } | |
| }, | |
| onWheelScroll: (scrollPos) => { | |
| if (context.viewport) context.viewport.scrollTop = scrollPos; | |
| }, | |
| onDragScroll: (pointerPos) => { | |
| if (context.viewport) context.viewport.scrollTop = getScrollPosition(pointerPos); | |
| } | |
| } | |
| ); | |
| } | |
| return null; | |
| }); | |
| var ScrollAreaScrollbarX = React2.forwardRef((props, forwardedRef) => { | |
| const { sizes, onSizesChange, ...scrollbarProps } = props; | |
| const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea); | |
| const [computedStyle, setComputedStyle] = React2.useState(); | |
| const ref = React2.useRef(null); | |
| const composeRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref, context.onScrollbarXChange); | |
| React2.useEffect(() => { | |
| if (ref.current) setComputedStyle(getComputedStyle(ref.current)); | |
| }, [ref]); | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| ScrollAreaScrollbarImpl, | |
| { | |
| "data-orientation": "horizontal", | |
| ...scrollbarProps, | |
| ref: composeRefs, | |
| sizes, | |
| style: { | |
| bottom: 0, | |
| left: context.dir === "rtl" ? "var(--radix-scroll-area-corner-width)" : 0, | |
| right: context.dir === "ltr" ? "var(--radix-scroll-area-corner-width)" : 0, | |
| ["--radix-scroll-area-thumb-width"]: getThumbSize(sizes) + "px", | |
| ...props.style | |
| }, | |
| onThumbPointerDown: (pointerPos) => props.onThumbPointerDown(pointerPos.x), | |
| onDragScroll: (pointerPos) => props.onDragScroll(pointerPos.x), | |
| onWheelScroll: (event, maxScrollPos) => { | |
| if (context.viewport) { | |
| const scrollPos = context.viewport.scrollLeft + event.deltaX; | |
| props.onWheelScroll(scrollPos); | |
| if (isScrollingWithinScrollbarBounds(scrollPos, maxScrollPos)) { | |
| event.preventDefault(); | |
| } | |
| } | |
| }, | |
| onResize: () => { | |
| if (ref.current && context.viewport && computedStyle) { | |
| onSizesChange({ | |
| content: context.viewport.scrollWidth, | |
| viewport: context.viewport.offsetWidth, | |
| scrollbar: { | |
| size: ref.current.clientWidth, | |
| paddingStart: toInt(computedStyle.paddingLeft), | |
| paddingEnd: toInt(computedStyle.paddingRight) | |
| } | |
| }); | |
| } | |
| } | |
| } | |
| ); | |
| }); | |
| var ScrollAreaScrollbarY = React2.forwardRef((props, forwardedRef) => { | |
| const { sizes, onSizesChange, ...scrollbarProps } = props; | |
| const context = useScrollAreaContext(SCROLLBAR_NAME, props.__scopeScrollArea); | |
| const [computedStyle, setComputedStyle] = React2.useState(); | |
| const ref = React2.useRef(null); | |
| const composeRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref, context.onScrollbarYChange); | |
| React2.useEffect(() => { | |
| if (ref.current) setComputedStyle(getComputedStyle(ref.current)); | |
| }, [ref]); | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| ScrollAreaScrollbarImpl, | |
| { | |
| "data-orientation": "vertical", | |
| ...scrollbarProps, | |
| ref: composeRefs, | |
| sizes, | |
| style: { | |
| top: 0, | |
| right: context.dir === "ltr" ? 0 : void 0, | |
| left: context.dir === "rtl" ? 0 : void 0, | |
| bottom: "var(--radix-scroll-area-corner-height)", | |
| ["--radix-scroll-area-thumb-height"]: getThumbSize(sizes) + "px", | |
| ...props.style | |
| }, | |
| onThumbPointerDown: (pointerPos) => props.onThumbPointerDown(pointerPos.y), | |
| onDragScroll: (pointerPos) => props.onDragScroll(pointerPos.y), | |
| onWheelScroll: (event, maxScrollPos) => { | |
| if (context.viewport) { | |
| const scrollPos = context.viewport.scrollTop + event.deltaY; | |
| props.onWheelScroll(scrollPos); | |
| if (isScrollingWithinScrollbarBounds(scrollPos, maxScrollPos)) { | |
| event.preventDefault(); | |
| } | |
| } | |
| }, | |
| onResize: () => { | |
| if (ref.current && context.viewport && computedStyle) { | |
| onSizesChange({ | |
| content: context.viewport.scrollHeight, | |
| viewport: context.viewport.offsetHeight, | |
| scrollbar: { | |
| size: ref.current.clientHeight, | |
| paddingStart: toInt(computedStyle.paddingTop), | |
| paddingEnd: toInt(computedStyle.paddingBottom) | |
| } | |
| }); | |
| } | |
| } | |
| } | |
| ); | |
| }); | |
| var [ScrollbarProvider, useScrollbarContext] = createScrollAreaContext(SCROLLBAR_NAME); | |
| var ScrollAreaScrollbarImpl = React2.forwardRef((props, forwardedRef) => { | |
| const { | |
| __scopeScrollArea, | |
| sizes, | |
| hasThumb, | |
| onThumbChange, | |
| onThumbPointerUp, | |
| onThumbPointerDown, | |
| onThumbPositionChange, | |
| onDragScroll, | |
| onWheelScroll, | |
| onResize, | |
| ...scrollbarProps | |
| } = props; | |
| const context = useScrollAreaContext(SCROLLBAR_NAME, __scopeScrollArea); | |
| const [scrollbar, setScrollbar] = React2.useState(null); | |
| const composeRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, (node) => setScrollbar(node)); | |
| const rectRef = React2.useRef(null); | |
| const prevWebkitUserSelectRef = React2.useRef(""); | |
| const viewport = context.viewport; | |
| const maxScrollPos = sizes.content - sizes.viewport; | |
| const handleWheelScroll = (0, import_react_use_callback_ref.useCallbackRef)(onWheelScroll); | |
| const handleThumbPositionChange = (0, import_react_use_callback_ref.useCallbackRef)(onThumbPositionChange); | |
| const handleResize = useDebounceCallback(onResize, 10); | |
| function handleDragScroll(event) { | |
| if (rectRef.current) { | |
| const x = event.clientX - rectRef.current.left; | |
| const y = event.clientY - rectRef.current.top; | |
| onDragScroll({ x, y }); | |
| } | |
| } | |
| React2.useEffect(() => { | |
| const handleWheel = (event) => { | |
| const element = event.target; | |
| const isScrollbarWheel = scrollbar?.contains(element); | |
| if (isScrollbarWheel) handleWheelScroll(event, maxScrollPos); | |
| }; | |
| document.addEventListener("wheel", handleWheel, { passive: false }); | |
| return () => document.removeEventListener("wheel", handleWheel, { passive: false }); | |
| }, [viewport, scrollbar, maxScrollPos, handleWheelScroll]); | |
| React2.useEffect(handleThumbPositionChange, [sizes, handleThumbPositionChange]); | |
| useResizeObserver(scrollbar, handleResize); | |
| useResizeObserver(context.content, handleResize); | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| ScrollbarProvider, | |
| { | |
| scope: __scopeScrollArea, | |
| scrollbar, | |
| hasThumb, | |
| onThumbChange: (0, import_react_use_callback_ref.useCallbackRef)(onThumbChange), | |
| onThumbPointerUp: (0, import_react_use_callback_ref.useCallbackRef)(onThumbPointerUp), | |
| onThumbPositionChange: handleThumbPositionChange, | |
| onThumbPointerDown: (0, import_react_use_callback_ref.useCallbackRef)(onThumbPointerDown), | |
| children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| import_react_primitive.Primitive.div, | |
| { | |
| ...scrollbarProps, | |
| ref: composeRefs, | |
| style: { position: "absolute", ...scrollbarProps.style }, | |
| onPointerDown: (0, import_primitive.composeEventHandlers)(props.onPointerDown, (event) => { | |
| const mainPointer = 0; | |
| if (event.button === mainPointer) { | |
| const element = event.target; | |
| element.setPointerCapture(event.pointerId); | |
| rectRef.current = scrollbar.getBoundingClientRect(); | |
| prevWebkitUserSelectRef.current = document.body.style.webkitUserSelect; | |
| document.body.style.webkitUserSelect = "none"; | |
| if (context.viewport) context.viewport.style.scrollBehavior = "auto"; | |
| handleDragScroll(event); | |
| } | |
| }), | |
| onPointerMove: (0, import_primitive.composeEventHandlers)(props.onPointerMove, handleDragScroll), | |
| onPointerUp: (0, import_primitive.composeEventHandlers)(props.onPointerUp, (event) => { | |
| const element = event.target; | |
| if (element.hasPointerCapture(event.pointerId)) { | |
| element.releasePointerCapture(event.pointerId); | |
| } | |
| document.body.style.webkitUserSelect = prevWebkitUserSelectRef.current; | |
| if (context.viewport) context.viewport.style.scrollBehavior = ""; | |
| rectRef.current = null; | |
| }) | |
| } | |
| ) | |
| } | |
| ); | |
| }); | |
| var THUMB_NAME = "ScrollAreaThumb"; | |
| var ScrollAreaThumb = React2.forwardRef( | |
| (props, forwardedRef) => { | |
| const { forceMount, ...thumbProps } = props; | |
| const scrollbarContext = useScrollbarContext(THUMB_NAME, props.__scopeScrollArea); | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_presence.Presence, { present: forceMount || scrollbarContext.hasThumb, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollAreaThumbImpl, { ref: forwardedRef, ...thumbProps }) }); | |
| } | |
| ); | |
| var ScrollAreaThumbImpl = React2.forwardRef( | |
| (props, forwardedRef) => { | |
| const { __scopeScrollArea, style, ...thumbProps } = props; | |
| const scrollAreaContext = useScrollAreaContext(THUMB_NAME, __scopeScrollArea); | |
| const scrollbarContext = useScrollbarContext(THUMB_NAME, __scopeScrollArea); | |
| const { onThumbPositionChange } = scrollbarContext; | |
| const composedRef = (0, import_react_compose_refs.useComposedRefs)( | |
| forwardedRef, | |
| (node) => scrollbarContext.onThumbChange(node) | |
| ); | |
| const removeUnlinkedScrollListenerRef = React2.useRef(void 0); | |
| const debounceScrollEnd = useDebounceCallback(() => { | |
| if (removeUnlinkedScrollListenerRef.current) { | |
| removeUnlinkedScrollListenerRef.current(); | |
| removeUnlinkedScrollListenerRef.current = void 0; | |
| } | |
| }, 100); | |
| React2.useEffect(() => { | |
| const viewport = scrollAreaContext.viewport; | |
| if (viewport) { | |
| const handleScroll = () => { | |
| debounceScrollEnd(); | |
| if (!removeUnlinkedScrollListenerRef.current) { | |
| const listener = addUnlinkedScrollListener(viewport, onThumbPositionChange); | |
| removeUnlinkedScrollListenerRef.current = listener; | |
| onThumbPositionChange(); | |
| } | |
| }; | |
| onThumbPositionChange(); | |
| viewport.addEventListener("scroll", handleScroll); | |
| return () => viewport.removeEventListener("scroll", handleScroll); | |
| } | |
| }, [scrollAreaContext.viewport, debounceScrollEnd, onThumbPositionChange]); | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| import_react_primitive.Primitive.div, | |
| { | |
| "data-state": scrollbarContext.hasThumb ? "visible" : "hidden", | |
| ...thumbProps, | |
| ref: composedRef, | |
| style: { | |
| width: "var(--radix-scroll-area-thumb-width)", | |
| height: "var(--radix-scroll-area-thumb-height)", | |
| ...style | |
| }, | |
| onPointerDownCapture: (0, import_primitive.composeEventHandlers)(props.onPointerDownCapture, (event) => { | |
| const thumb = event.target; | |
| const thumbRect = thumb.getBoundingClientRect(); | |
| const x = event.clientX - thumbRect.left; | |
| const y = event.clientY - thumbRect.top; | |
| scrollbarContext.onThumbPointerDown({ x, y }); | |
| }), | |
| onPointerUp: (0, import_primitive.composeEventHandlers)(props.onPointerUp, scrollbarContext.onThumbPointerUp) | |
| } | |
| ); | |
| } | |
| ); | |
| ScrollAreaThumb.displayName = THUMB_NAME; | |
| var CORNER_NAME = "ScrollAreaCorner"; | |
| var ScrollAreaCorner = React2.forwardRef( | |
| (props, forwardedRef) => { | |
| const context = useScrollAreaContext(CORNER_NAME, props.__scopeScrollArea); | |
| const hasBothScrollbarsVisible = Boolean(context.scrollbarX && context.scrollbarY); | |
| const hasCorner = context.type !== "scroll" && hasBothScrollbarsVisible; | |
| return hasCorner ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollAreaCornerImpl, { ...props, ref: forwardedRef }) : null; | |
| } | |
| ); | |
| ScrollAreaCorner.displayName = CORNER_NAME; | |
| var ScrollAreaCornerImpl = React2.forwardRef((props, forwardedRef) => { | |
| const { __scopeScrollArea, ...cornerProps } = props; | |
| const context = useScrollAreaContext(CORNER_NAME, __scopeScrollArea); | |
| const [width, setWidth] = React2.useState(0); | |
| const [height, setHeight] = React2.useState(0); | |
| const hasSize = Boolean(width && height); | |
| useResizeObserver(context.scrollbarX, () => { | |
| const height2 = context.scrollbarX?.offsetHeight || 0; | |
| context.onCornerHeightChange(height2); | |
| setHeight(height2); | |
| }); | |
| useResizeObserver(context.scrollbarY, () => { | |
| const width2 = context.scrollbarY?.offsetWidth || 0; | |
| context.onCornerWidthChange(width2); | |
| setWidth(width2); | |
| }); | |
| return hasSize ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| import_react_primitive.Primitive.div, | |
| { | |
| ...cornerProps, | |
| ref: forwardedRef, | |
| style: { | |
| width, | |
| height, | |
| position: "absolute", | |
| right: context.dir === "ltr" ? 0 : void 0, | |
| left: context.dir === "rtl" ? 0 : void 0, | |
| bottom: 0, | |
| ...props.style | |
| } | |
| } | |
| ) : null; | |
| }); | |
| function toInt(value) { | |
| return value ? parseInt(value, 10) : 0; | |
| } | |
| function getThumbRatio(viewportSize, contentSize) { | |
| const ratio = viewportSize / contentSize; | |
| return isNaN(ratio) ? 0 : ratio; | |
| } | |
| function getThumbSize(sizes) { | |
| const ratio = getThumbRatio(sizes.viewport, sizes.content); | |
| const scrollbarPadding = sizes.scrollbar.paddingStart + sizes.scrollbar.paddingEnd; | |
| const thumbSize = (sizes.scrollbar.size - scrollbarPadding) * ratio; | |
| return Math.max(thumbSize, 18); | |
| } | |
| function getScrollPositionFromPointer(pointerPos, pointerOffset, sizes, dir = "ltr") { | |
| const thumbSizePx = getThumbSize(sizes); | |
| const thumbCenter = thumbSizePx / 2; | |
| const offset = pointerOffset || thumbCenter; | |
| const thumbOffsetFromEnd = thumbSizePx - offset; | |
| const minPointerPos = sizes.scrollbar.paddingStart + offset; | |
| const maxPointerPos = sizes.scrollbar.size - sizes.scrollbar.paddingEnd - thumbOffsetFromEnd; | |
| const maxScrollPos = sizes.content - sizes.viewport; | |
| const scrollRange = dir === "ltr" ? [0, maxScrollPos] : [maxScrollPos * -1, 0]; | |
| const interpolate = linearScale([minPointerPos, maxPointerPos], scrollRange); | |
| return interpolate(pointerPos); | |
| } | |
| function getThumbOffsetFromScroll(scrollPos, sizes, dir = "ltr") { | |
| const thumbSizePx = getThumbSize(sizes); | |
| const scrollbarPadding = sizes.scrollbar.paddingStart + sizes.scrollbar.paddingEnd; | |
| const scrollbar = sizes.scrollbar.size - scrollbarPadding; | |
| const maxScrollPos = sizes.content - sizes.viewport; | |
| const maxThumbPos = scrollbar - thumbSizePx; | |
| const scrollClampRange = dir === "ltr" ? [0, maxScrollPos] : [maxScrollPos * -1, 0]; | |
| const scrollWithoutMomentum = (0, import_number.clamp)(scrollPos, scrollClampRange); | |
| const interpolate = linearScale([0, maxScrollPos], [0, maxThumbPos]); | |
| return interpolate(scrollWithoutMomentum); | |
| } | |
| function linearScale(input, output) { | |
| return (value) => { | |
| if (input[0] === input[1] || output[0] === output[1]) return output[0]; | |
| const ratio = (output[1] - output[0]) / (input[1] - input[0]); | |
| return output[0] + ratio * (value - input[0]); | |
| }; | |
| } | |
| function isScrollingWithinScrollbarBounds(scrollPos, maxScrollPos) { | |
| return scrollPos > 0 && scrollPos < maxScrollPos; | |
| } | |
| var addUnlinkedScrollListener = (node, handler = () => { | |
| }) => { | |
| let prevPosition = { left: node.scrollLeft, top: node.scrollTop }; | |
| let rAF = 0; | |
| (function loop() { | |
| const position = { left: node.scrollLeft, top: node.scrollTop }; | |
| const isHorizontalScroll = prevPosition.left !== position.left; | |
| const isVerticalScroll = prevPosition.top !== position.top; | |
| if (isHorizontalScroll || isVerticalScroll) handler(); | |
| prevPosition = position; | |
| rAF = window.requestAnimationFrame(loop); | |
| })(); | |
| return () => window.cancelAnimationFrame(rAF); | |
| }; | |
| function useDebounceCallback(callback, delay) { | |
| const handleCallback = (0, import_react_use_callback_ref.useCallbackRef)(callback); | |
| const debounceTimerRef = React2.useRef(0); | |
| React2.useEffect(() => () => window.clearTimeout(debounceTimerRef.current), []); | |
| return React2.useCallback(() => { | |
| window.clearTimeout(debounceTimerRef.current); | |
| debounceTimerRef.current = window.setTimeout(handleCallback, delay); | |
| }, [handleCallback, delay]); | |
| } | |
| function useResizeObserver(element, onResize) { | |
| const handleResize = (0, import_react_use_callback_ref.useCallbackRef)(onResize); | |
| (0, import_react_use_layout_effect.useLayoutEffect)(() => { | |
| let rAF = 0; | |
| if (element) { | |
| const resizeObserver = new ResizeObserver(() => { | |
| cancelAnimationFrame(rAF); | |
| rAF = window.requestAnimationFrame(handleResize); | |
| }); | |
| resizeObserver.observe(element); | |
| return () => { | |
| window.cancelAnimationFrame(rAF); | |
| resizeObserver.unobserve(element); | |
| }; | |
| } | |
| }, [element, handleResize]); | |
| } | |
| var Root = ScrollArea; | |
| var Viewport = ScrollAreaViewport; | |
| var Scrollbar = ScrollAreaScrollbar; | |
| var Thumb = ScrollAreaThumb; | |
| var Corner = ScrollAreaCorner; | |
| //# sourceMappingURL=index.js.map | |