diff --git a/.size-limit.js b/.size-limit.js
index b55df1ec040fa6..164b054fb0bcfa 100644
--- a/.size-limit.js
+++ b/.size-limit.js
@@ -27,7 +27,7 @@ module.exports = [
name: 'The size of all the modules of material-ui.',
webpack: true,
path: 'packages/material-ui/build/index.js',
- limit: '94.9 KB',
+ limit: '94.7 KB',
},
{
name: 'The main bundle of the docs',
diff --git a/packages/material-ui/package.json b/packages/material-ui/package.json
index 4db8533948bd08..e24c8d8930d954 100644
--- a/packages/material-ui/package.json
+++ b/packages/material-ui/package.json
@@ -60,7 +60,6 @@
"react-jss": "^8.1.0",
"react-transition-group": "^2.2.1",
"recompose": "^0.27.0",
- "scroll": "^2.0.3",
"warning": "^4.0.1"
},
"sideEffects": false,
diff --git a/packages/material-ui/src/Tabs/Tabs.js b/packages/material-ui/src/Tabs/Tabs.js
index 40af221f796247..d6e6cf132f3abc 100644
--- a/packages/material-ui/src/Tabs/Tabs.js
+++ b/packages/material-ui/src/Tabs/Tabs.js
@@ -7,9 +7,7 @@ import classNames from 'classnames';
import EventListener from 'react-event-listener';
import debounce from 'debounce'; // < 1kb payload overhead when lodash/debounce is > 3kb.
import { getNormalizedScrollLeft, detectScrollType } from 'normalize-scroll-left';
-// TODO: should we fork it?
-// https://github.com/michaelrhodes/scroll/issues/10
-import scroll from 'scroll';
+import animate from '../internal/animate';
import ScrollbarSize from './ScrollbarSize';
import withStyles from '../styles/withStyles';
import TabIndicator from './TabIndicator';
@@ -199,7 +197,7 @@ class Tabs extends React.Component {
const nextScrollLeft = this.tabsRef.scrollLeft + delta * multiplier;
// Fix for Edge
const invert = theme.direction === 'rtl' && detectScrollType() === 'reverse' ? -1 : 1;
- scroll.left(this.tabsRef, invert * nextScrollLeft);
+ this.scroll(invert * nextScrollLeft);
};
scrollSelectedIntoView = () => {
@@ -213,14 +211,18 @@ class Tabs extends React.Component {
if (tabMeta.left < tabsMeta.left) {
// left side of button is out of view
const nextScrollLeft = tabsMeta.scrollLeft + (tabMeta.left - tabsMeta.left);
- scroll.left(this.tabsRef, nextScrollLeft);
+ this.scroll(nextScrollLeft);
} else if (tabMeta.right > tabsMeta.right) {
// right side of button is out of view
const nextScrollLeft = tabsMeta.scrollLeft + (tabMeta.right - tabsMeta.right);
- scroll.left(this.tabsRef, nextScrollLeft);
+ this.scroll(nextScrollLeft);
}
};
+ scroll = value => {
+ animate('scrollLeft', this.tabsRef, value);
+ };
+
updateScrollButtonState = () => {
const { scrollable, scrollButtons, theme } = this.props;
diff --git a/packages/material-ui/src/Tabs/Tabs.test.js b/packages/material-ui/src/Tabs/Tabs.test.js
index 8e4692319a6df9..b2da3ab8f10486 100644
--- a/packages/material-ui/src/Tabs/Tabs.test.js
+++ b/packages/material-ui/src/Tabs/Tabs.test.js
@@ -1,7 +1,6 @@
import React from 'react';
import { assert } from 'chai';
import { spy, stub, useFakeTimers } from 'sinon';
-import scroll from 'scroll';
import { ShallowWrapper } from 'enzyme';
import consoleErrorMock from 'test/utils/consoleErrorMock';
import { createShallow, createMount, getClasses, unwrap } from '../test-utils';
@@ -574,7 +573,6 @@ describe('', () => {
let metaStub;
beforeEach(() => {
- scrollStub = stub(scroll, 'left');
const wrapper = shallow(
@@ -582,11 +580,12 @@ describe('', () => {
,
);
instance = wrapper.instance();
+ scrollStub = stub(instance, 'scroll');
metaStub = stub(instance, 'getTabsMeta');
});
afterEach(() => {
- scroll.left.restore();
+ instance.scroll.restore();
});
it('should scroll left tab into view', () => {
@@ -596,7 +595,7 @@ describe('', () => {
});
instance.scrollSelectedIntoView();
- assert.strictEqual(scrollStub.args[0][1], 0, 'should scroll to 0 position');
+ assert.strictEqual(scrollStub.args[0][0], 0, 'should scroll to 0 position');
});
it('should scroll right tab into view', () => {
@@ -606,7 +605,7 @@ describe('', () => {
});
instance.scrollSelectedIntoView();
- assert.strictEqual(scrollStub.args[0][1], 10, 'should scroll to 10 position');
+ assert.strictEqual(scrollStub.args[0][0], 10, 'should scroll to 10 position');
});
it('should support value=false', () => {
diff --git a/packages/material-ui/src/internal/animate.js b/packages/material-ui/src/internal/animate.js
new file mode 100644
index 00000000000000..a1ab7d063ec558
--- /dev/null
+++ b/packages/material-ui/src/internal/animate.js
@@ -0,0 +1,51 @@
+function easeInOutSin(time) {
+ return (1 + Math.sin(Math.PI * time - Math.PI / 2)) / 2;
+}
+
+function animate(prop, element, to, options = {}, cb = () => {}) {
+ const {
+ ease = easeInOutSin,
+ duration = 300, // standard
+ } = options;
+
+ let start = null;
+ const from = element[prop];
+ let cancelled = false;
+
+ const cancel = () => {
+ cancelled = true;
+ };
+
+ const step = timestamp => {
+ if (cancelled) {
+ cb(new Error('Animation cancelled'));
+ return;
+ }
+
+ if (start === null) {
+ start = timestamp;
+ }
+ const time = Math.min(1, (timestamp - start) / duration);
+
+ element[prop] = ease(time) * (to - from) + from;
+
+ if (time >= 1) {
+ requestAnimationFrame(() => {
+ cb(null);
+ });
+ return;
+ }
+
+ requestAnimationFrame(step);
+ };
+
+ if (from === to) {
+ cb(new Error('Element already at target position'));
+ return cancel;
+ }
+
+ requestAnimationFrame(step);
+ return cancel;
+}
+
+export default animate;
diff --git a/packages/material-ui/src/internal/animate.test.js b/packages/material-ui/src/internal/animate.test.js
new file mode 100644
index 00000000000000..f0b8fe9dc2e4fe
--- /dev/null
+++ b/packages/material-ui/src/internal/animate.test.js
@@ -0,0 +1,32 @@
+import { assert } from 'chai';
+import animate from './animate';
+
+describe('animate', () => {
+ let container;
+
+ before(() => {
+ container = document.createElement('div');
+ container.style.cssText = [
+ 'height: 100px',
+ 'width: 100px',
+ 'overflow: scroll',
+ 'border: 1px solid #000',
+ ].join(';');
+ const box = document.createElement('div');
+ box.style.cssText = ['height: 100px', 'width: 1000px'].join(';');
+ container.appendChild(box);
+ document.body.appendChild(container);
+ });
+
+ after(() => {
+ document.body.removeChild(container);
+ });
+
+ it('should work', done => {
+ container.scrollLeft = 200;
+ animate('scrollLeft', container, 300, {}, () => {
+ assert.strictEqual(container.scrollLeft, 300);
+ done();
+ });
+ });
+});
diff --git a/yarn.lock b/yarn.lock
index 5e6166070ea3f1..5c9884cce0b773 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3771,10 +3771,6 @@ dom-serializer@0, dom-serializer@~0.1.0:
domelementtype "~1.1.1"
entities "~1.1.1"
-dom-walk@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
-
domain-browser@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
@@ -5096,13 +5092,6 @@ global-dirs@^0.1.0:
dependencies:
ini "^1.3.4"
-global@~4.3.0:
- version "4.3.2"
- resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f"
- dependencies:
- min-document "^2.19.0"
- process "~0.5.1"
-
globals@^11.1.0, globals@^11.7.0:
version "11.7.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673"
@@ -6964,12 +6953,6 @@ mimic-response@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
-min-document@^2.19.0:
- version "2.19.0"
- resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
- dependencies:
- dom-walk "^0.1.0"
-
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
@@ -8100,10 +8083,6 @@ process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
-process@~0.5.1:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf"
-
progress@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f"
@@ -8275,12 +8254,6 @@ raf@^3.4.0:
dependencies:
performance-now "^2.1.0"
-rafl@~1.2.1:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/rafl/-/rafl-1.2.2.tgz#fe930f758211020d47e38815f5196a8be4150740"
- dependencies:
- global "~4.3.0"
-
railroad-diagrams@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
@@ -9185,12 +9158,6 @@ schema-utils@^0.4.2, schema-utils@^0.4.3, schema-utils@^0.4.4, schema-utils@^0.4
ajv "^6.1.0"
ajv-keywords "^3.1.0"
-scroll@^2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/scroll/-/scroll-2.0.3.tgz#0951b785544205fd17753bc3d294738ba16fc2ab"
- dependencies:
- rafl "~1.2.1"
-
section-iterator@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/section-iterator/-/section-iterator-2.0.0.tgz#bf444d7afeeb94ad43c39ad2fb26151627ccba2a"