Commit d472c782 by Uchechukwu Obasi Committed by GitHub

CustomScrollbar: migrated styles from sass to emotion (#30506)

* CustomScrollbar: migrated styles from sass to emotion

* fixes frontend test

* updated changes

* fixed page props and applied changes to all occurences

* moved the getStyles function to the bottom of the file

* made some changes

* fixed snapshot test

* Revert "Merge branch 'refactor-customscrollbar-30354' of https://github.com/grafana/grafana into refactor-customscrollbar-30354"

This reverts commit c45ee30b6b297991a1628e9b21c4121dc78e376c, reversing
changes made to d2645534e39c4ffda30a948f4a892c1c68ec38ca.

* improved props name

* made use of theme variables for style consistency

* fixed snapshot test and updated some theme changes

* removed hover effects from customScrollbar style

* made some changes

* updated some changes

* added label to class names

* changed to a functional component and improved styling

* fixes snapshot test

* fixes small nit

* minor tweaks

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
parent 75cb6703
import React from 'react';
import renderer from 'react-test-renderer';
import CustomScrollbar from './CustomScrollbar';
import { CustomScrollbar } from './CustomScrollbar';
describe('CustomScrollbar', () => {
it('renders correctly', () => {
......
import React, { Component } from 'react';
import React, { FC, useCallback, useEffect, useRef } from 'react';
import isNil from 'lodash/isNil';
import classNames from 'classnames';
import { css } from 'emotion';
import Scrollbars from 'react-custom-scrollbars';
import { useStyles } from '../../themes';
import { GrafanaTheme } from '@grafana/data';
interface Props {
className?: string;
autoHide?: boolean;
autoHideTimeout?: number;
autoHideDuration?: number;
autoHeightMax?: string;
hideTracksWhenNotNeeded?: boolean;
hideHorizontalTrack?: boolean;
hideVerticalTrack?: boolean;
scrollTop?: number;
setScrollTop: (event: any) => void;
setScrollTop?: (event: any) => void;
autoHeightMin?: number | string;
updateAfterMountMs?: number;
}
......@@ -21,122 +23,152 @@ interface Props {
/**
* Wraps component into <Scrollbars> component from `react-custom-scrollbars`
*/
export class CustomScrollbar extends Component<Props> {
static defaultProps: Partial<Props> = {
autoHide: false,
autoHideTimeout: 200,
autoHideDuration: 200,
setScrollTop: () => {},
hideTracksWhenNotNeeded: false,
autoHeightMin: '0',
autoHeightMax: '100%',
};
private ref: React.RefObject<Scrollbars>;
constructor(props: Props) {
super(props);
this.ref = React.createRef<Scrollbars>();
}
updateScroll() {
const ref = this.ref.current;
const { scrollTop } = this.props;
if (ref && !isNil(scrollTop)) {
ref.scrollTop(scrollTop);
}
}
componentDidMount() {
this.updateScroll();
// this logic is to make scrollbar visible when content is added body after mount
if (this.props.updateAfterMountMs) {
setTimeout(() => this.updateAfterMount(), this.props.updateAfterMountMs);
export const CustomScrollbar: FC<Props> = ({
autoHide = false,
autoHideTimeout = 200,
setScrollTop,
className,
autoHeightMin = '0',
autoHeightMax = '100%',
hideTracksWhenNotNeeded = false,
hideHorizontalTrack,
hideVerticalTrack,
updateAfterMountMs,
scrollTop,
children,
}) => {
const ref = useRef<Scrollbars>(null);
const styles = useStyles(getStyles);
const updateScroll = () => {
if (ref.current && !isNil(scrollTop)) {
ref.current.scrollTop(scrollTop);
}
}
updateAfterMount() {
if (this.ref && this.ref.current) {
const scrollbar = this.ref.current as any;
if (scrollbar.update) {
scrollbar.update();
}
}
}
};
componentDidUpdate() {
this.updateScroll();
useEffect(() => {
updateScroll();
});
/**
* Special logic for doing a update a few milliseconds after mount to check for
* updated height due to dynamic content
*/
if (updateAfterMountMs) {
useEffect(() => {
setTimeout(() => {
const scrollbar = ref.current as any;
if (scrollbar?.update) {
scrollbar.update();
}
}, updateAfterMountMs);
}, []);
}
renderTrack = (track: 'track-vertical' | 'track-horizontal', hideTrack: boolean | undefined, passedProps: any) => {
function renderTrack(className: string, hideTrack: boolean | undefined, passedProps: any) {
if (passedProps.style && hideTrack) {
passedProps.style.display = 'none';
}
return <div {...passedProps} className={track} />;
};
renderThumb = (thumb: 'thumb-horizontal' | 'thumb-vertical', passedProps: any) => {
return <div {...passedProps} className={thumb} />;
};
renderTrackHorizontal = (passedProps: any) => {
return this.renderTrack('track-horizontal', this.props.hideHorizontalTrack, passedProps);
};
renderTrackVertical = (passedProps: any) => {
return this.renderTrack('track-vertical', this.props.hideVerticalTrack, passedProps);
};
return <div {...passedProps} className={className} />;
}
renderThumbHorizontal = (passedProps: any) => {
return this.renderThumb('thumb-horizontal', passedProps);
};
const renderTrackHorizontal = useCallback(
(passedProps: any) => {
return renderTrack('track-horizontal', hideHorizontalTrack, passedProps);
},
[hideHorizontalTrack]
);
const renderTrackVertical = useCallback(
(passedProps: any) => {
return renderTrack('track-vertical', hideVerticalTrack, passedProps);
},
[hideVerticalTrack]
);
const renderThumbHorizontal = useCallback((passedProps: any) => {
return <div {...passedProps} className="thumb-horizontal" />;
}, []);
const renderThumbVertical = useCallback((passedProps: any) => {
return <div {...passedProps} className="thumb-vertical" />;
}, []);
const renderView = useCallback((passedProps: any) => {
return <div {...passedProps} className="scrollbar-view" />;
}, []);
return (
<Scrollbars
ref={ref}
className={classNames(styles.customScrollbar, className)}
onScroll={setScrollTop}
autoHeight={true}
autoHide={autoHide}
autoHideTimeout={autoHideTimeout}
hideTracksWhenNotNeeded={hideTracksWhenNotNeeded}
// These autoHeightMin & autoHeightMax options affect firefox and chrome differently.
// Before these where set to inherit but that caused problems with cut of legends in firefox
autoHeightMax={autoHeightMax}
autoHeightMin={autoHeightMin}
renderTrackHorizontal={renderTrackHorizontal}
renderTrackVertical={renderTrackVertical}
renderThumbHorizontal={renderThumbHorizontal}
renderThumbVertical={renderThumbVertical}
renderView={renderView}
>
{children}
</Scrollbars>
);
};
renderThumbVertical = (passedProps: any) => {
return this.renderThumb('thumb-vertical', passedProps);
};
export default CustomScrollbar;
renderView = (passedProps: any) => {
return <div {...passedProps} className="view" />;
const getStyles = (theme: GrafanaTheme) => {
return {
customScrollbar: css`
// Fix for Firefox. For some reason sometimes .view container gets a height of its content, but in order to
// make scroll working it should fit outer container size (scroll appears only when inner container size is
// greater than outer one).
display: flex;
flex-grow: 1;
.scrollbar-view {
display: flex;
flex-grow: 1;
flex-direction: column;
}
.track-vertical {
border-radius: ${theme.border.radius.md};
width: ${theme.spacing.sm} !important;
right: 0px;
bottom: ${theme.spacing.xxs};
top: ${theme.spacing.xxs};
}
.track-horizontal {
border-radius: ${theme.border.radius.md};
height: ${theme.spacing.sm} !important;
right: ${theme.spacing.xxs};
bottom: ${theme.spacing.xxs};
left: ${theme.spacing.xxs};
}
.thumb-vertical {
background: ${theme.colors.bg3};
border-radius: ${theme.border.radius.md};
opacity: 0;
}
.thumb-horizontal {
background: ${theme.colors.bg3};
border-radius: ${theme.border.radius.md};
opacity: 0;
}
&:hover {
.thumb-vertical,
.thumb-horizontal {
opacity: 1;
transition: opacity 0.3s ease-in-out;
}
}
`,
};
render() {
const {
className,
children,
autoHeightMax,
autoHeightMin,
setScrollTop,
autoHide,
autoHideTimeout,
hideTracksWhenNotNeeded,
} = this.props;
return (
<Scrollbars
ref={this.ref}
className={classNames('custom-scrollbar', className)}
onScroll={setScrollTop}
autoHeight={true}
autoHide={autoHide}
autoHideTimeout={autoHideTimeout}
hideTracksWhenNotNeeded={hideTracksWhenNotNeeded}
// These autoHeightMin & autoHeightMax options affect firefox and chrome differently.
// Before these where set to inherit but that caused problems with cut of legends in firefox
autoHeightMax={autoHeightMax}
autoHeightMin={autoHeightMin}
renderTrackHorizontal={this.renderTrackHorizontal}
renderTrackVertical={this.renderTrackVertical}
renderThumbHorizontal={this.renderThumbHorizontal}
renderThumbVertical={this.renderThumbVertical}
renderView={this.renderView}
>
{children}
</Scrollbars>
);
}
}
export default CustomScrollbar;
};
.custom-scrollbar {
// Fix for Firefox. For some reason sometimes .view container gets a height of its content, but in order to
// make scroll working it should fit outer container size (scroll appears only when inner container size is
// greater than outer one).
display: flex;
flex-grow: 1;
.view {
display: flex;
flex-grow: 1;
flex-direction: column;
}
.track-vertical {
border-radius: 3px;
width: 8px !important;
right: 2px;
bottom: 2px;
top: 2px;
}
.track-horizontal {
border-radius: 3px;
height: 8px !important;
right: 2px;
bottom: 2px;
left: 2px;
}
.thumb-vertical {
@include gradient-vertical($scrollbarBackground, $scrollbarBackground2);
border-radius: 6px;
opacity: 0;
}
.thumb-horizontal {
@include gradient-horizontal($scrollbarBackground, $scrollbarBackground2);
border-radius: 6px;
opacity: 0;
}
&:hover {
.thumb-vertical,
.thumb-horizontal {
opacity: 0.8;
transition: opacity 0.3s ease-in-out;
}
}
// page scrollbar should stick to left side to aid hitting it
&--page {
.track-vertical {
right: 0;
}
}
}
......@@ -2,7 +2,7 @@
exports[`CustomScrollbar renders correctly 1`] = `
<div
className="custom-scrollbar"
className="css-1fb8j9z"
style={
Object {
"height": "auto",
......@@ -15,7 +15,7 @@ exports[`CustomScrollbar renders correctly 1`] = `
}
>
<div
className="view"
className="scrollbar-view"
style={
Object {
"WebkitOverflowScrolling": "touch",
......
......@@ -4,7 +4,7 @@ import RcDrawer from 'rc-drawer';
import { css } from 'emotion';
import { selectors } from '@grafana/e2e-selectors';
import CustomScrollbar from '../CustomScrollbar/CustomScrollbar';
import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
import { IconButton } from '../IconButton/IconButton';
import { stylesFactory, useTheme } from '../../themes';
......
import React, { FC, CSSProperties, ComponentType } from 'react';
import { useMeasure } from 'react-use';
import CustomScrollbar from '../CustomScrollbar/CustomScrollbar';
import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
/**
* @beta
......
@import 'ButtonCascader/ButtonCascader';
@import 'ColorPicker/ColorPicker';
@import 'CustomScrollbar/CustomScrollbar';
@import 'Drawer/Drawer';
@import 'FormField/FormField';
@import 'RefreshPicker/RefreshPicker';
......
......@@ -47,7 +47,7 @@ class Page extends Component<Props> {
const { navModel, children, ...otherProps } = this.props;
return (
<div {...otherProps} className="page-scrollbar-wrapper">
<CustomScrollbar autoHeightMin={'100%'} className="custom-scrollbar--page">
<CustomScrollbar autoHeightMin={'100%'}>
<div className="page-scrollbar-content">
<PageHeader model={navModel} />
{children}
......
......@@ -316,7 +316,6 @@ export class DashboardPage extends PureComponent<Props, State> {
scrollTop={updateScrollTop}
hideHorizontalTrack={true}
updateAfterMountMs={500}
className="custom-scrollbar--page"
>
<div className="dashboard-content">
{initError && this.renderInitFailedState()}
......
......@@ -106,14 +106,8 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
className="dashboard-scroll"
>
<CustomScrollbar
autoHeightMax="100%"
autoHeightMin="100%"
autoHide={false}
autoHideDuration={200}
autoHideTimeout={200}
className="custom-scrollbar--page"
hideHorizontalTrack={true}
hideTracksWhenNotNeeded={false}
setScrollTop={[Function]}
updateAfterMountMs={500}
>
......@@ -481,14 +475,8 @@ exports[`DashboardPage When dashboard has editview url state should render setti
className="dashboard-scroll"
>
<CustomScrollbar
autoHeightMax="100%"
autoHeightMin="100%"
autoHide={false}
autoHideDuration={200}
autoHideTimeout={200}
className="custom-scrollbar--page"
hideHorizontalTrack={true}
hideTracksWhenNotNeeded={false}
setScrollTop={[Function]}
updateAfterMountMs={500}
>
......
......@@ -31,7 +31,7 @@ export class Wrapper extends Component<WrapperProps> {
return (
<div className="page-scrollbar-wrapper">
<CustomScrollbar autoHeightMin={'100%'} autoHeightMax={''} className="custom-scrollbar--page">
<CustomScrollbar autoHeightMin={'100%'}>
<div className="explore-wrapper">
<ErrorBoundaryAlert style="page">
<Explore exploreId={ExploreId.left} />
......
......@@ -337,13 +337,7 @@ export class QueryGroup extends PureComponent<Props, State> {
const styles = getStyles();
return (
<CustomScrollbar
autoHeightMin="100%"
autoHide={true}
updateAfterMountMs={300}
scrollTop={scrollTop}
setScrollTop={this.setScrollTop}
>
<CustomScrollbar autoHeightMin="100%" scrollTop={scrollTop} setScrollTop={this.setScrollTop}>
<div className={styles.innerWrapper}>
{this.renderTopSection(styles)}
{dsSettings && (
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment