Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@radix-ui/react-scroll-area

Package Overview
Dependencies
Maintainers
6
Versions
214
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@radix-ui/react-scroll-area - npm Package Compare versions

Comparing version 1.1.0-rc.2 to 1.1.0-rc.3

1408

dist/index.js
"use strict";
"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 __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
if (typeof require !== "undefined") return require.apply(this, arguments);
throw Error('Dynamic require of "' + x + '" is not supported');
});
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 __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);
// packages/react/scroll-area/src/ScrollArea.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");
// packages/react/scroll-area/src/index.ts
var src_exports = {};
__export(src_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(src_exports);
// packages/react/scroll-area/src/useStateMachine.ts
var React = __toESM(__require("react"));
function useStateMachine(initialState, machine) {
return React.useReducer((state, event) => {
const nextState = machine[state][event];
return nextState ?? state;
}, initialState);
}
// packages/react/scroll-area/src/ScrollArea.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");
// packages/react/scroll-area/src/ScrollArea.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)(
// packages/react/scroll-area/src/useStateMachine.ts
var React = __toESM(require("react"));
function useStateMachine(initialState, machine) {
return React.useReducer((state, event) => {
const nextState = machine[state][event];
return nextState ?? state;
}, initialState);
}
// packages/react/scroll-area/src/ScrollArea.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,
{
"data-radix-scroll-area-viewport": "",
...viewportProps,
dir: direction,
...scrollAreaProps,
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/overflowed#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",
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
},
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) => {
);
}
);
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/overflowed#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";
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 = {
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,
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);
ref: forwardedRef
}
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);
}
}
}
);
) });
});
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"
}
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);
}
});
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);
}
return null;
}, [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 }
});
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]);
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)(
ScrollAreaScrollbarImpl,
ScrollAreaScrollbarX,
{
"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
...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)`;
}
},
onThumbPointerDown: (pointerPos) => props.onThumbPointerDown(pointerPos.x),
onDragScroll: (pointerPos) => props.onDragScroll(pointerPos.x),
onWheelScroll: (event, maxScrollPos) => {
onWheelScroll: (scrollPos) => {
if (context.viewport) context.viewport.scrollLeft = scrollPos;
},
onDragScroll: (pointerPos) => {
if (context.viewport) {
const scrollPos = context.viewport.scrollLeft + event.deltaX;
props.onWheelScroll(scrollPos);
if (isScrollingWithinScrollbarBounds(scrollPos, maxScrollPos)) {
event.preventDefault();
}
context.viewport.scrollLeft = getScrollPosition(pointerPos, context.dir);
}
},
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]);
}
if (orientation === "vertical") {
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
ScrollAreaScrollbarImpl,
ScrollAreaScrollbarY,
{
"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();
}
...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)`;
}
},
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)
}
});
}
onWheelScroll: (scrollPos) => {
if (context.viewport) context.viewport.scrollTop = scrollPos;
},
onDragScroll: (pointerPos) => {
if (context.viewport) context.viewport.scrollTop = getScrollPosition(pointerPos);
}
}
);
});
var [ScrollbarProvider, useScrollbarContext] = createScrollAreaContext(SCROLLBAR_NAME);
var ScrollAreaScrollbarImpl = React2.forwardRef((props, forwardedRef) => {
const {
__scopeScrollArea,
}
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,
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;
})
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 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();
const debounceScrollEnd = useDebounceCallback(() => {
if (removeUnlinkedScrollListenerRef.current) {
removeUnlinkedScrollListenerRef.current();
removeUnlinkedScrollListenerRef.current = void 0;
});
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();
}
}
}, 100);
React2.useEffect(() => {
const viewport = scrollAreaContext.viewport;
if (viewport) {
const handleScroll = () => {
debounceScrollEnd();
if (!removeUnlinkedScrollListenerRef.current) {
const listener = addUnlinkedScrollListener(viewport, onThumbPositionChange);
removeUnlinkedScrollListenerRef.current = listener;
onThumbPositionChange();
},
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)
}
};
onThumbPositionChange();
viewport.addEventListener("scroll", handleScroll);
return () => viewport.removeEventListener("scroll", handleScroll);
});
}
}, [scrollAreaContext.viewport, debounceScrollEnd, onThumbPositionChange]);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
}
}
);
});
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,
{
"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 });
...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);
}
}),
onPointerUp: (0, import_primitive.composeEventHandlers)(props.onPointerUp, scrollbarContext.onThumbPointerUp)
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;
})
}
);
)
}
);
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)(
});
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();
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,
{
...cornerProps,
ref: forwardedRef,
"data-state": scrollbarContext.hasThumb ? "visible" : "hidden",
...thumbProps,
ref: composedRef,
style: {
width,
height,
position: "absolute",
right: context.dir === "ltr" ? 0 : void 0,
left: context.dir === "rtl" ? 0 : void 0,
bottom: 0,
...props.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)
}
) : null;
});
function toInt(value) {
return value ? parseInt(value, 10) : 0;
);
}
function getThumbRatio(viewportSize, contentSize) {
const ratio = viewportSize / contentSize;
return isNaN(ratio) ? 0 : ratio;
);
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;
}
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 };
);
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;
(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;
})();
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
{
"name": "@radix-ui/react-scroll-area",
"version": "1.1.0-rc.2",
"version": "1.1.0-rc.3",
"license": "MIT",

@@ -31,11 +31,11 @@ "exports": {

"dependencies": {
"@radix-ui/number": "1.1.0-rc.2",
"@radix-ui/primitive": "1.1.0-rc.2",
"@radix-ui/react-compose-refs": "1.1.0-rc.2",
"@radix-ui/react-context": "1.1.0-rc.2",
"@radix-ui/react-direction": "1.1.0-rc.2",
"@radix-ui/react-presence": "1.1.0-rc.2",
"@radix-ui/react-primitive": "1.1.0-rc.2",
"@radix-ui/react-use-callback-ref": "1.1.0-rc.2",
"@radix-ui/react-use-layout-effect": "1.1.0-rc.2"
"@radix-ui/number": "1.1.0-rc.3",
"@radix-ui/primitive": "1.1.0-rc.3",
"@radix-ui/react-compose-refs": "1.1.0-rc.3",
"@radix-ui/react-context": "1.1.0-rc.3",
"@radix-ui/react-direction": "1.1.0-rc.3",
"@radix-ui/react-presence": "1.1.0-rc.3",
"@radix-ui/react-primitive": "1.1.0-rc.3",
"@radix-ui/react-use-callback-ref": "1.1.0-rc.3",
"@radix-ui/react-use-layout-effect": "1.1.0-rc.3"
},

@@ -42,0 +42,0 @@ "devDependencies": {

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc