UNPKG

@yamada-ui/scroll-area

Version:

Yamada UI scroll area component

181 lines (179 loc) • 5.47 kB
"use client" // src/scroll-area.tsx import { forwardRef, omitThemeProps, ui, useComponentStyle } from "@yamada-ui/core"; import { cx, dataAttr, handlerAll, isMac, merge, mergeRefs, useSafeLayoutEffect, vendor } from "@yamada-ui/utils"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { jsx } from "react/jsx-runtime"; var neverStyles = { "&::-webkit-scrollbar": { display: "none" }, scrollbarWidth: "none", _scrollbar: { display: "none" } }; var hiddenStyles = { "&::-webkit-scrollbar-thumb": { bg: "transparent" }, "&::-webkit-scrollbar-track": { bg: "transparent" }, "@-moz-document url-prefix()": { scrollbarColor: "transparent transparent", _dark: { scrollbarColor: "transparent transparent" }, _light: { scrollbarColor: "transparent transparent" } }, _dark: { "&::-webkit-scrollbar-thumb": { bg: "transparent" }, "&::-webkit-scrollbar-track": { bg: "transparent" }, _scrollbarThumb: { bg: "transparent" }, _scrollbarTrack: { bg: "transparent" } }, _light: { "&::-webkit-scrollbar-thumb": { bg: "transparent" }, "&::-webkit-scrollbar-track": { bg: "transparent" }, _scrollbarThumb: { bg: "transparent" }, _scrollbarTrack: { bg: "transparent" } }, _scrollbarThumb: { bg: "transparent" }, _scrollbarTrack: { bg: "transparent" } }; var ScrollArea = forwardRef((props, ref) => { const [styles, mergedProps] = useComponentStyle("ScrollArea", props); const { type = "hover", overflow = "overlay", scrollHideDelay = 1e3, onScrollPositionChange, ...rest } = omitThemeProps(mergedProps); const [isHovered, setIsHovered] = useState(false); const [isScrolling, setIsScrolling] = useState(false); const isAlways = type === "always"; const isNever = type === "never"; const isSafari = isMac() && vendor(/apple/i); const hoverTimeout = useRef(void 0); const scrollTimeout = useRef(void 0); const scrollAreaRef = useRef(null); const scrollPosition = useRef({ x: 0, y: 0 }); useSafeLayoutEffect(() => { if (!scrollAreaRef.current || !isSafari) return; scrollAreaRef.current.scrollLeft = scrollPosition.current.x; scrollAreaRef.current.scrollTop = scrollPosition.current.y; }); const onMouseEnter = useCallback(() => { if (type !== "hover") return; clearTimeout(hoverTimeout.current); setIsHovered(true); }, [type]); const onMouseLeave = useCallback(() => { if (type !== "hover") return; hoverTimeout.current = setTimeout( () => setIsHovered(false), scrollHideDelay ); }, [scrollHideDelay, type]); const onScroll = useCallback( (ev) => { const el = ev.target; const { scrollLeft: x, scrollTop: y } = el; const { x: prevX, y: prevY } = scrollPosition.current; const isEqual = Math.abs(x - prevX) <= 5 && Math.abs(y - prevY) <= 5; onScrollPositionChange == null ? void 0 : onScrollPositionChange({ x, y }); scrollPosition.current = { x, y }; if (type !== "scroll" || isEqual) return; if (!isScrolling) setIsScrolling(true); clearTimeout(scrollTimeout.current); scrollTimeout.current = setTimeout( () => setIsScrolling(false), scrollHideDelay ); }, [isScrolling, onScrollPositionChange, scrollHideDelay, type] ); useEffect(() => { return () => { if (hoverTimeout.current) clearTimeout(hoverTimeout.current); if (scrollTimeout.current) clearTimeout(scrollTimeout.current); }; }, []); const css = useMemo(() => { const baseStyle = { overflow, ...styles }; if (isNever) { return merge(baseStyle, neverStyles); } else { return merge( baseStyle, !isAlways && !isHovered && !isScrolling ? hiddenStyles : {} ); } }, [isAlways, isHovered, isNever, isScrolling, overflow, styles]); const computedProps = useMemo( () => ({ __css: css, ...rest, onMouseEnter: handlerAll(rest.onMouseEnter, onMouseEnter), onMouseLeave: handlerAll(rest.onMouseLeave, onMouseLeave), onScroll: handlerAll(rest.onScroll, onScroll) }), [css, onMouseEnter, onMouseLeave, onScroll, rest] ); if (isSafari) { const componentKey = `${isHovered}-${isScrolling}`; return /* @__PURE__ */ jsx( InternalScrollArea, { ref: mergeRefs(ref, scrollAreaRef), "data-hovered": dataAttr(isHovered), "data-key": componentKey, "data-scrolling": dataAttr(isScrolling), ...computedProps }, componentKey ); } else { return /* @__PURE__ */ jsx( InternalScrollArea, { ref, "data-hovered": dataAttr(isHovered), "data-scrolling": dataAttr(isScrolling), ...computedProps } ); } }); ScrollArea.displayName = "ScrollArea"; ScrollArea.__ui__ = "ScrollArea"; var InternalScrollArea = forwardRef( ({ className, children, innerProps, ...rest }, ref) => { return /* @__PURE__ */ jsx( ui.div, { ref, className: cx("ui-scroll-area", className), tabIndex: 0, ...rest, children: innerProps ? /* @__PURE__ */ jsx(ui.div, { className: "ui-scroll-area__inner", ...innerProps, children }) : children } ); } ); InternalScrollArea.displayName = "InternalScrollArea"; InternalScrollArea.__ui__ = "InternalScrollArea"; export { ScrollArea }; //# sourceMappingURL=chunk-JXGXFEFI.mjs.map