From cf832e7db483743630b8509474f600ebd058d6fb Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 6 Sep 2018 14:23:28 +0300 Subject: [PATCH 1/3] wrapper for react-custom-scrollbars component --- package.json | 2 + .../components/ScrollBar/withScrollBar.tsx | 53 +++++++++++++++++++ public/sass/components/_scrollbar.scss | 43 +++++++++++++++ yarn.lock | 42 ++++++++++++++- 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 public/app/core/components/ScrollBar/withScrollBar.tsx diff --git a/package.json b/package.json index 87ba147fb4d..9ee81d7f8ac 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@types/jest": "^21.1.4", "@types/node": "^8.0.31", "@types/react": "^16.0.25", + "@types/react-custom-scrollbars": "^4.0.5", "@types/react-dom": "^16.0.3", "angular-mocks": "1.6.6", "autoprefixer": "^6.4.0", @@ -154,6 +155,7 @@ "prop-types": "^15.6.0", "rc-cascader": "^0.14.0", "react": "^16.2.0", + "react-custom-scrollbars": "^4.2.1", "react-dom": "^16.2.0", "react-grid-layout": "0.16.6", "react-highlight-words": "^0.10.0", diff --git a/public/app/core/components/ScrollBar/withScrollBar.tsx b/public/app/core/components/ScrollBar/withScrollBar.tsx new file mode 100644 index 00000000000..9f8ad942167 --- /dev/null +++ b/public/app/core/components/ScrollBar/withScrollBar.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import Scrollbars from 'react-custom-scrollbars'; + +interface WithScrollBarProps { + customClassName?: string; + autoHide?: boolean; + autoHideTimeout?: number; + autoHideDuration?: number; + hideTracksWhenNotNeeded?: boolean; +} + +const withScrollBarDefaultProps: Partial = { + customClassName: 'custom-scrollbars', + autoHide: true, + autoHideTimeout: 200, + autoHideDuration: 200, + hideTracksWhenNotNeeded: false, +}; + +/** + * Wraps component into component from `react-custom-scrollbars` + */ +export default function withScrollBar

(WrappedComponent: React.ComponentType

) { + return class extends React.Component

{ + static defaultProps = withScrollBarDefaultProps; + + render() { + // Use type casting here in order to get rest of the props working. See more + // https://github.com/Microsoft/TypeScript/issues/14409 + // https://github.com/Microsoft/TypeScript/pull/13288 + const { autoHide, autoHideTimeout, autoHideDuration, hideTracksWhenNotNeeded, customClassName, ...props } = this + .props as WithScrollBarProps; + const scrollProps = { autoHide, autoHideTimeout, autoHideDuration, hideTracksWhenNotNeeded }; + + return ( +

} + renderTrackVertical={props =>
} + renderThumbHorizontal={props =>
} + renderThumbVertical={props =>
} + renderView={props =>
} + {...scrollProps} + > + + + ); + } + }; +} diff --git a/public/sass/components/_scrollbar.scss b/public/sass/components/_scrollbar.scss index 78173b73f47..adb9e0c54c0 100644 --- a/public/sass/components/_scrollbar.scss +++ b/public/sass/components/_scrollbar.scss @@ -294,3 +294,46 @@ padding-top: 1px; } } + +// Custom styles for 'react-custom-scrollbars' + +.custom-scrollbars { + // 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; + } + + .track-vertical { + border-radius: 3px; + width: 6px !important; + + right: 2px; + bottom: 2px; + top: 2px; + } + + .track-horizontal { + border-radius: 3px; + height: 6px !important; + + right: 2px; + bottom: 2px; + left: 2px; + } + + .thumb-vertical { + @include gradient-vertical($scrollbarBackground, $scrollbarBackground2); + border-radius: 6px; + } + + .thumb-horizontal { + @include gradient-horizontal($scrollbarBackground, $scrollbarBackground2); + border-radius: 6px; + } +} diff --git a/yarn.lock b/yarn.lock index c15c77cc45f..54f7572d5d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -473,6 +473,10 @@ add-dom-event-listener@1.x: dependencies: object-assign "4.x" +add-px-to-style@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/add-px-to-style/-/add-px-to-style-1.0.0.tgz#d0c135441fa8014a8137904531096f67f28f263a" + agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce" @@ -3406,6 +3410,14 @@ dom-converter@~0.1: dependencies: utila "~0.3" +dom-css@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/dom-css/-/dom-css-2.1.0.tgz#fdbc2d5a015d0a3e1872e11472bbd0e7b9e6a202" + dependencies: + add-px-to-style "1.0.0" + prefix-style "2.0.1" + to-camel-case "1.0.0" + dom-helpers@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6" @@ -9137,6 +9149,10 @@ prebuild-install@^2.3.0: tunnel-agent "^0.6.0" which-pm-runs "^1.0.0" +prefix-style@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/prefix-style/-/prefix-style-2.0.1.tgz#66bba9a870cfda308a5dc20e85e9120932c95a06" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -9388,7 +9404,7 @@ qw@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4" -raf@^3.4.0: +raf@^3.1.0, raf@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575" dependencies: @@ -9496,6 +9512,14 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-custom-scrollbars@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/react-custom-scrollbars/-/react-custom-scrollbars-4.2.1.tgz#830fd9502927e97e8a78c2086813899b2a8b66db" + dependencies: + dom-css "^2.0.0" + prop-types "^15.5.10" + raf "^3.1.0" + react-dom@^16.2.0: version "16.4.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.0.tgz#099f067dd5827ce36a29eaf9a6cdc7cbf6216b1e" @@ -11335,10 +11359,20 @@ to-buffer@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" +to-camel-case@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-camel-case/-/to-camel-case-1.0.0.tgz#1a56054b2f9d696298ce66a60897322b6f423e46" + dependencies: + to-space-case "^1.0.0" + to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-no-case@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a" + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -11361,6 +11395,12 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +to-space-case@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17" + dependencies: + to-no-case "^1.0.0" + toposort@^1.0.0: version "1.0.7" resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" From a186bc01e0c3c61ef9a44cbc2beb6d332e77d823 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 6 Sep 2018 15:36:22 +0300 Subject: [PATCH 2/3] tests for withScrollBar() wrapper --- .../__snapshots__/withScrollBar.test.tsx.snap | 86 +++++++++++++++++++ .../ScrollBar/withScrollBar.test.tsx | 23 +++++ 2 files changed, 109 insertions(+) create mode 100644 public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap create mode 100644 public/app/core/components/ScrollBar/withScrollBar.test.tsx diff --git a/public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap b/public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap new file mode 100644 index 00000000000..c6b9b5bb37d --- /dev/null +++ b/public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap @@ -0,0 +1,86 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`withScrollBar renders correctly 1`] = ` +
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/public/app/core/components/ScrollBar/withScrollBar.test.tsx b/public/app/core/components/ScrollBar/withScrollBar.test.tsx new file mode 100644 index 00000000000..89a24a7db8e --- /dev/null +++ b/public/app/core/components/ScrollBar/withScrollBar.test.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import withScrollBar from './withScrollBar'; + +class TestComponent extends React.Component { + render() { + return
; + } +} + +describe('withScrollBar', () => { + it('renders correctly', () => { + const TestComponentWithScroll = withScrollBar(TestComponent); + const tree = renderer + .create( + +

Scrollable content

+
+ ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); From 8fca79e87e6855e433004967146f340b1f7b9659 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 6 Sep 2018 22:52:14 +0300 Subject: [PATCH 3/3] scrollbar refactor: replace HOC by component with children --- .../ScrollBar/GrafanaScrollbar.test.tsx | 16 ++++++ .../components/ScrollBar/GrafanaScrollbar.tsx | 48 +++++++++++++++++ ...sx.snap => GrafanaScrollbar.test.tsx.snap} | 8 +-- .../ScrollBar/withScrollBar.test.tsx | 23 -------- .../components/ScrollBar/withScrollBar.tsx | 53 ------------------- 5 files changed, 68 insertions(+), 80 deletions(-) create mode 100644 public/app/core/components/ScrollBar/GrafanaScrollbar.test.tsx create mode 100644 public/app/core/components/ScrollBar/GrafanaScrollbar.tsx rename public/app/core/components/ScrollBar/__snapshots__/{withScrollBar.test.tsx.snap => GrafanaScrollbar.test.tsx.snap} (94%) delete mode 100644 public/app/core/components/ScrollBar/withScrollBar.test.tsx delete mode 100644 public/app/core/components/ScrollBar/withScrollBar.tsx diff --git a/public/app/core/components/ScrollBar/GrafanaScrollbar.test.tsx b/public/app/core/components/ScrollBar/GrafanaScrollbar.test.tsx new file mode 100644 index 00000000000..7e519acd29d --- /dev/null +++ b/public/app/core/components/ScrollBar/GrafanaScrollbar.test.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import GrafanaScrollbar from './GrafanaScrollbar'; + +describe('GrafanaScrollbar', () => { + it('renders correctly', () => { + const tree = renderer + .create( + +

Scrollable content

+
+ ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/public/app/core/components/ScrollBar/GrafanaScrollbar.tsx b/public/app/core/components/ScrollBar/GrafanaScrollbar.tsx new file mode 100644 index 00000000000..24e5b0d8828 --- /dev/null +++ b/public/app/core/components/ScrollBar/GrafanaScrollbar.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import Scrollbars from 'react-custom-scrollbars'; + +interface GrafanaScrollBarProps { + customClassName?: string; + autoHide?: boolean; + autoHideTimeout?: number; + autoHideDuration?: number; + hideTracksWhenNotNeeded?: boolean; +} + +const grafanaScrollBarDefaultProps: Partial = { + customClassName: 'custom-scrollbars', + autoHide: true, + autoHideTimeout: 200, + autoHideDuration: 200, + hideTracksWhenNotNeeded: false, +}; + +/** + * Wraps component into component from `react-custom-scrollbars` + */ +class GrafanaScrollbar extends React.Component { + static defaultProps = grafanaScrollBarDefaultProps; + + render() { + const { customClassName, children, ...scrollProps } = this.props; + + return ( +
} + renderTrackVertical={props =>
} + renderThumbHorizontal={props =>
} + renderThumbVertical={props =>
} + renderView={props =>
} + {...scrollProps} + > + {children} + + ); + } +} + +export default GrafanaScrollbar; diff --git a/public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap b/public/app/core/components/ScrollBar/__snapshots__/GrafanaScrollbar.test.tsx.snap similarity index 94% rename from public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap rename to public/app/core/components/ScrollBar/__snapshots__/GrafanaScrollbar.test.tsx.snap index c6b9b5bb37d..8e4f51e3587 100644 --- a/public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap +++ b/public/app/core/components/ScrollBar/__snapshots__/GrafanaScrollbar.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`withScrollBar renders correctly 1`] = ` +exports[`GrafanaScrollbar renders correctly 1`] = `
-
+

+ Scrollable content +

; - } -} - -describe('withScrollBar', () => { - it('renders correctly', () => { - const TestComponentWithScroll = withScrollBar(TestComponent); - const tree = renderer - .create( - -

Scrollable content

-
- ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); -}); diff --git a/public/app/core/components/ScrollBar/withScrollBar.tsx b/public/app/core/components/ScrollBar/withScrollBar.tsx deleted file mode 100644 index 9f8ad942167..00000000000 --- a/public/app/core/components/ScrollBar/withScrollBar.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React from 'react'; -import Scrollbars from 'react-custom-scrollbars'; - -interface WithScrollBarProps { - customClassName?: string; - autoHide?: boolean; - autoHideTimeout?: number; - autoHideDuration?: number; - hideTracksWhenNotNeeded?: boolean; -} - -const withScrollBarDefaultProps: Partial = { - customClassName: 'custom-scrollbars', - autoHide: true, - autoHideTimeout: 200, - autoHideDuration: 200, - hideTracksWhenNotNeeded: false, -}; - -/** - * Wraps component into component from `react-custom-scrollbars` - */ -export default function withScrollBar

(WrappedComponent: React.ComponentType

) { - return class extends React.Component

{ - static defaultProps = withScrollBarDefaultProps; - - render() { - // Use type casting here in order to get rest of the props working. See more - // https://github.com/Microsoft/TypeScript/issues/14409 - // https://github.com/Microsoft/TypeScript/pull/13288 - const { autoHide, autoHideTimeout, autoHideDuration, hideTracksWhenNotNeeded, customClassName, ...props } = this - .props as WithScrollBarProps; - const scrollProps = { autoHide, autoHideTimeout, autoHideDuration, hideTracksWhenNotNeeded }; - - return ( -

} - renderTrackVertical={props =>
} - renderThumbHorizontal={props =>
} - renderThumbVertical={props =>
} - renderView={props =>
} - {...scrollProps} - > - - - ); - } - }; -}