UNPKG

@grafana/ui

Version:
1 lines 12.6 kB
{"version":3,"file":"CustomScrollbar.mjs","sources":["../../../../src/components/CustomScrollbar/CustomScrollbar.tsx"],"sourcesContent":["import { css, cx } from '@emotion/css';\nimport { RefCallback, useCallback, useEffect, useRef } from 'react';\nimport * as React from 'react';\nimport Scrollbars, { positionValues } from 'react-custom-scrollbars-2';\n\nimport { GrafanaTheme2 } from '@grafana/data';\n\nimport { useStyles2 } from '../../themes/ThemeContext';\n\nimport { ScrollIndicators } from './ScrollIndicators';\n\nexport type ScrollbarPosition = positionValues;\n\ninterface Props {\n className?: string;\n testId?: string;\n autoHide?: boolean;\n autoHideTimeout?: number;\n autoHeightMax?: string;\n hideTracksWhenNotNeeded?: boolean;\n hideHorizontalTrack?: boolean;\n hideVerticalTrack?: boolean;\n scrollRefCallback?: RefCallback<HTMLDivElement>;\n scrollTop?: number;\n setScrollTop?: (position: ScrollbarPosition) => void;\n showScrollIndicators?: boolean;\n autoHeightMin?: number | string;\n updateAfterMountMs?: number;\n onScroll?: React.UIEventHandler;\n divId?: string;\n}\n\n/**\n * Wraps component into <Scrollbars> component from `react-custom-scrollbars`\n * @deprecated Use `ScrollContainer` from `@grafana/ui` instead. It uses native scrollbars and has a simpler API.\n */\nexport const CustomScrollbar = ({\n autoHide = false,\n autoHideTimeout = 200,\n setScrollTop,\n className,\n testId,\n autoHeightMin = '0',\n autoHeightMax = '100%',\n hideTracksWhenNotNeeded = false,\n hideHorizontalTrack,\n hideVerticalTrack,\n scrollRefCallback,\n showScrollIndicators = false,\n updateAfterMountMs,\n scrollTop,\n onScroll,\n children,\n divId,\n}: React.PropsWithChildren<Props>) => {\n const ref = useRef<Scrollbars & { view: HTMLDivElement; update: () => void }>(null);\n const styles = useStyles2(getStyles);\n\n useEffect(() => {\n if (ref.current && scrollRefCallback) {\n scrollRefCallback(ref.current.view);\n }\n }, [ref, scrollRefCallback]);\n\n useScrollTop(ref.current, scrollTop);\n\n /**\n * Special logic for doing a update a few milliseconds after mount to check for\n * updated height due to dynamic content\n */\n useEffect(() => {\n if (!updateAfterMountMs) {\n return;\n }\n setTimeout(() => {\n const scrollbar = ref.current;\n if (scrollbar?.update) {\n scrollbar.update();\n }\n }, updateAfterMountMs);\n }, [updateAfterMountMs]);\n\n function renderTrack(className: string, hideTrack: boolean | undefined, passedProps: JSX.IntrinsicElements['div']) {\n if (passedProps.style && hideTrack) {\n passedProps.style.display = 'none';\n }\n\n return <div {...passedProps} className={className} />;\n }\n\n const renderTrackHorizontal = useCallback(\n (passedProps: JSX.IntrinsicElements['div']) => {\n return renderTrack('track-horizontal', hideHorizontalTrack, passedProps);\n },\n [hideHorizontalTrack]\n );\n\n const renderTrackVertical = useCallback(\n (passedProps: JSX.IntrinsicElements['div']) => {\n return renderTrack('track-vertical', hideVerticalTrack, passedProps);\n },\n [hideVerticalTrack]\n );\n\n const renderThumbHorizontal = useCallback((passedProps: JSX.IntrinsicElements['div']) => {\n return <div {...passedProps} className=\"thumb-horizontal\" />;\n }, []);\n\n const renderThumbVertical = useCallback((passedProps: JSX.IntrinsicElements['div']) => {\n return <div {...passedProps} className=\"thumb-vertical\" />;\n }, []);\n\n const renderView = useCallback(\n (passedProps: JSX.IntrinsicElements['div']) => {\n // fixes issues of visibility on safari and ios devices\n if (passedProps.style && passedProps.style['WebkitOverflowScrolling'] === 'touch') {\n passedProps.style['WebkitOverflowScrolling'] = 'auto';\n }\n\n return <div {...passedProps} className=\"scrollbar-view\" id={divId} />;\n },\n [divId]\n );\n\n const onScrollStop = useCallback(() => {\n ref.current && setScrollTop && setScrollTop(ref.current.getValues());\n }, [setScrollTop]);\n\n return (\n <Scrollbars\n data-testid={testId}\n ref={ref}\n className={cx(styles.customScrollbar, className, {\n [styles.scrollbarWithScrollIndicators]: showScrollIndicators,\n })}\n onScrollStop={onScrollStop}\n autoHeight={true}\n autoHide={autoHide}\n autoHideTimeout={autoHideTimeout}\n hideTracksWhenNotNeeded={hideTracksWhenNotNeeded}\n // These autoHeightMin & autoHeightMax options affect firefox and chrome differently.\n // Before these where set to inherit but that caused problems with cut of legends in firefox\n autoHeightMax={autoHeightMax}\n autoHeightMin={autoHeightMin}\n renderTrackHorizontal={renderTrackHorizontal}\n renderTrackVertical={renderTrackVertical}\n renderThumbHorizontal={renderThumbHorizontal}\n renderThumbVertical={renderThumbVertical}\n renderView={renderView}\n onScroll={onScroll}\n >\n {showScrollIndicators ? <ScrollIndicators>{children}</ScrollIndicators> : children}\n </Scrollbars>\n );\n};\n\nexport default CustomScrollbar;\n\nconst getStyles = (theme: GrafanaTheme2) => {\n return {\n customScrollbar: css({\n // Fix for Firefox. For some reason sometimes .view container gets a height of its content, but in order to\n // make scroll working it should fit outer container size (scroll appears only when inner container size is\n // greater than outer one).\n display: 'flex',\n flexGrow: 1,\n '.scrollbar-view': {\n display: 'flex',\n flexGrow: 1,\n flexDirection: 'column',\n },\n '.track-vertical': {\n borderRadius: theme.shape.borderRadius(2),\n width: `${theme.spacing(1)} !important`,\n right: 0,\n bottom: theme.spacing(0.25),\n top: theme.spacing(0.25),\n },\n '.track-horizontal': {\n borderRadius: theme.shape.borderRadius(2),\n height: `${theme.spacing(1)} !important`,\n right: theme.spacing(0.25),\n bottom: theme.spacing(0.25),\n left: theme.spacing(0.25),\n },\n '.thumb-vertical': {\n background: theme.colors.action.focus,\n borderRadius: theme.shape.borderRadius(2),\n opacity: 0,\n },\n '.thumb-horizontal': {\n background: theme.colors.action.focus,\n borderRadius: theme.shape.borderRadius(2),\n opacity: 0,\n },\n '&:hover': {\n '.thumb-vertical, .thumb-horizontal': {\n opacity: 1,\n transition: 'opacity 0.3s ease-in-out',\n },\n },\n }),\n // override the scroll container position so that the scroll indicators\n // are positioned at the top and bottom correctly.\n // react-custom-scrollbars doesn't provide any way for us to hook in nicely,\n // so we have to override with !important. feelsbad.\n scrollbarWithScrollIndicators: css({\n '.scrollbar-view': {\n // Need type assertion here due to the use of !important\n // see https://github.com/frenic/csstype/issues/114#issuecomment-697201978\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n position: 'static !important' as 'static',\n },\n }),\n };\n};\n\n/**\n * Calling scrollTop on a scrollbar ref in a useEffect can race with internal state in react-custom-scrollbars-2, causing scrollTop to get called on a stale reference, which prevents the element from scrolling as desired.\n * Adding the reference to the useEffect dependency array not notify react that the reference has changed (and is an eslint violation), so we create a custom hook so updates to the reference trigger another render, fixing the race condition bug.\n *\n * @param scrollBar\n * @param scrollTop\n */\nfunction useScrollTop(\n scrollBar: (Scrollbars & { view: HTMLDivElement; update: () => void }) | null,\n scrollTop?: number\n) {\n useEffect(() => {\n if (scrollBar && scrollTop != null) {\n scrollBar.scrollTop(scrollTop);\n }\n }, [scrollTop, scrollBar]);\n}\n"],"names":["className"],"mappings":"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"}