mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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 d2645534e3
.
* 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>
This commit is contained in:
parent
75cb6703a6
commit
d472c7820c
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import CustomScrollbar from './CustomScrollbar';
|
||||
import { CustomScrollbar } from './CustomScrollbar';
|
||||
|
||||
describe('CustomScrollbar', () => {
|
||||
it('renders correctly', () => {
|
||||
|
@ -1,19 +1,21 @@
|
||||
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,103 +23,86 @@ 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%',
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
private ref: React.RefObject<Scrollbars>;
|
||||
useEffect(() => {
|
||||
updateScroll();
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
updateAfterMount() {
|
||||
if (this.ref && this.ref.current) {
|
||||
const scrollbar = this.ref.current as any;
|
||||
if (scrollbar.update) {
|
||||
/**
|
||||
* 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);
|
||||
}, []);
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.updateScroll();
|
||||
}
|
||||
|
||||
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} />;
|
||||
};
|
||||
return <div {...passedProps} className={className} />;
|
||||
}
|
||||
|
||||
renderThumb = (thumb: 'thumb-horizontal' | 'thumb-vertical', passedProps: any) => {
|
||||
return <div {...passedProps} className={thumb} />;
|
||||
};
|
||||
const renderTrackHorizontal = useCallback(
|
||||
(passedProps: any) => {
|
||||
return renderTrack('track-horizontal', hideHorizontalTrack, passedProps);
|
||||
},
|
||||
[hideHorizontalTrack]
|
||||
);
|
||||
|
||||
renderTrackHorizontal = (passedProps: any) => {
|
||||
return this.renderTrack('track-horizontal', this.props.hideHorizontalTrack, passedProps);
|
||||
};
|
||||
const renderTrackVertical = useCallback(
|
||||
(passedProps: any) => {
|
||||
return renderTrack('track-vertical', hideVerticalTrack, passedProps);
|
||||
},
|
||||
[hideVerticalTrack]
|
||||
);
|
||||
|
||||
renderTrackVertical = (passedProps: any) => {
|
||||
return this.renderTrack('track-vertical', this.props.hideVerticalTrack, passedProps);
|
||||
};
|
||||
const renderThumbHorizontal = useCallback((passedProps: any) => {
|
||||
return <div {...passedProps} className="thumb-horizontal" />;
|
||||
}, []);
|
||||
|
||||
renderThumbHorizontal = (passedProps: any) => {
|
||||
return this.renderThumb('thumb-horizontal', passedProps);
|
||||
};
|
||||
const renderThumbVertical = useCallback((passedProps: any) => {
|
||||
return <div {...passedProps} className="thumb-vertical" />;
|
||||
}, []);
|
||||
|
||||
renderThumbVertical = (passedProps: any) => {
|
||||
return this.renderThumb('thumb-vertical', passedProps);
|
||||
};
|
||||
|
||||
renderView = (passedProps: any) => {
|
||||
return <div {...passedProps} className="view" />;
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
children,
|
||||
autoHeightMax,
|
||||
autoHeightMin,
|
||||
setScrollTop,
|
||||
autoHide,
|
||||
autoHideTimeout,
|
||||
hideTracksWhenNotNeeded,
|
||||
} = this.props;
|
||||
const renderView = useCallback((passedProps: any) => {
|
||||
return <div {...passedProps} className="scrollbar-view" />;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Scrollbars
|
||||
ref={this.ref}
|
||||
className={classNames('custom-scrollbar', className)}
|
||||
ref={ref}
|
||||
className={classNames(styles.customScrollbar, className)}
|
||||
onScroll={setScrollTop}
|
||||
autoHeight={true}
|
||||
autoHide={autoHide}
|
||||
@ -127,16 +112,63 @@ export class CustomScrollbar extends Component<Props> {
|
||||
// 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}
|
||||
renderTrackHorizontal={renderTrackHorizontal}
|
||||
renderTrackVertical={renderTrackVertical}
|
||||
renderThumbHorizontal={renderThumbHorizontal}
|
||||
renderThumbVertical={renderThumbVertical}
|
||||
renderView={renderView}
|
||||
>
|
||||
{children}
|
||||
</Scrollbars>
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default CustomScrollbar;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
};
|
||||
|
@ -1,57 +0,0 @@
|
||||
.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';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { FC, CSSProperties, ComponentType } from 'react';
|
||||
import { useMeasure } from 'react-use';
|
||||
import CustomScrollbar from '../CustomScrollbar/CustomScrollbar';
|
||||
import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
|
||||
|
||||
/**
|
||||
* @beta
|
||||
|
@ -1,6 +1,5 @@
|
||||
@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 && (
|
||||
|
Loading…
Reference in New Issue
Block a user