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"