diff --git a/package-lock.json b/package-lock.json
index 58f8905dd..6fad3fc16 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1232,45 +1232,74 @@
}
},
"@material/tab": {
- "version": "0.41.0",
- "resolved": "https://registry.npmjs.org/@material/tab/-/tab-0.41.0.tgz",
- "integrity": "sha512-yM6eYD8Kgrk2cHa+zN3GYIK4Mt6EsSxDIpaArE6JopqRpalULjiOk83hWVPR1V95xphnzYAWM1YF6I6JexE9kw==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@material/tab/-/tab-1.0.1.tgz",
+ "integrity": "sha512-//JXHaL1ebTpR6Z1mZpd6Ltry/kD840HSI/NQRMCdjxKjdap3cVtNfjRZ5ST4snGEqihLQ7gsqfDg/XZ5k0j3g==",
"dev": true,
"requires": {
- "@material/base": "^0.41.0",
- "@material/ripple": "^0.41.0",
- "@material/rtl": "^0.40.1",
- "@material/tab-indicator": "^0.41.0",
- "@material/theme": "^0.41.0",
- "@material/typography": "^0.41.0"
+ "@material/base": "^1.0.0",
+ "@material/ripple": "^1.0.1",
+ "@material/rtl": "^0.42.0",
+ "@material/tab-indicator": "^1.0.0",
+ "@material/theme": "^1.0.0",
+ "@material/typography": "^1.0.0",
+ "tslib": "^1.9.3"
},
"dependencies": {
- "@material/base": {
- "version": "0.41.0",
- "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz",
- "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==",
- "dev": true
+ "@material/animation": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@material/animation/-/animation-1.0.0.tgz",
+ "integrity": "sha512-Ed5/vggn6ZhSJ87yn3ZS1d826VJNFz73jHF2bSsgRtHDoB8KCuOwQMfdgAgDa4lKDF6CDIPCKBZPKrs2ubehdw==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.3"
+ }
+ },
+ "@material/dom": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@material/dom/-/dom-1.0.1.tgz",
+ "integrity": "sha512-7gb9Tk8YBn2fLEa5fJfvDexG0QxvRGDb8c6uZEhvK4bTd2ZHCfHg9KrO+smC6Trbn5jC+FsBvdRZBbMjtS/E4g==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.3"
+ }
},
"@material/ripple": {
- "version": "0.41.0",
- "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz",
- "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-1.0.1.tgz",
+ "integrity": "sha512-aBigRoVMjIU2lLDq7TMocI2H2YFbO1hICs5FTdSRp4Yis/QFTrgaW32q8yuHdZI56j+b2BWIWapqA2xpSmCMXQ==",
"dev": true,
"requires": {
- "@material/animation": "^0.41.0",
- "@material/base": "^0.41.0",
- "@material/theme": "^0.41.0"
+ "@material/animation": "^1.0.0",
+ "@material/base": "^1.0.0",
+ "@material/dom": "^1.0.1",
+ "@material/feature-targeting": "^0.44.1",
+ "@material/theme": "^1.0.0",
+ "tslib": "^1.9.3"
}
},
- "@material/tab-indicator": {
- "version": "0.41.0",
- "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-0.41.0.tgz",
- "integrity": "sha512-IBJEO+O8OnFVgRAn4CCGccpyNPF1bvTp5+1foD46S2u7XZLD7ejfxTQhqE5HYWtVLQ3zk1aYo3+N9+oSUkpM2w==",
+ "@material/rtl": {
+ "version": "0.42.0",
+ "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.42.0.tgz",
+ "integrity": "sha512-VrnrKJzhmspsN8WXHuxxBZ69yM5IwhCUqWr1t1eNfw3ZEvEj7i1g3P31HGowKThIN1dc1Wh4LE14rCISWCtv5w==",
+ "dev": true
+ },
+ "@material/theme": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@material/theme/-/theme-1.0.0.tgz",
+ "integrity": "sha512-Bg/BQLU5MmCwtQ3DHcSs9DodZB8PTvuItv1wXrP54S/wBVwryIB5uMDmERhnItbNnAFbkKhlAuhn1asMmMzfkQ==",
"dev": true,
"requires": {
- "@material/animation": "^0.41.0",
- "@material/base": "^0.41.0",
- "@material/theme": "^0.41.0"
+ "@material/feature-targeting": "^0.44.1"
+ }
+ },
+ "@material/typography": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@material/typography/-/typography-1.0.0.tgz",
+ "integrity": "sha512-Oeqbjci1cC7jTE8/n3dwnkqKe9ZeWiaE+rgMtRYtRFw1HvAw14SpGA5EEAS/Li2Hu2KZ50FYCe3HYqShfxtChA==",
+ "dev": true,
+ "requires": {
+ "@material/feature-targeting": "^0.44.1"
}
}
}
@@ -1293,6 +1322,42 @@
"integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==",
"dev": true
},
+ "@material/ripple": {
+ "version": "0.41.0",
+ "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz",
+ "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==",
+ "dev": true,
+ "requires": {
+ "@material/animation": "^0.41.0",
+ "@material/base": "^0.41.0",
+ "@material/theme": "^0.41.0"
+ }
+ },
+ "@material/tab": {
+ "version": "0.41.0",
+ "resolved": "https://registry.npmjs.org/@material/tab/-/tab-0.41.0.tgz",
+ "integrity": "sha512-yM6eYD8Kgrk2cHa+zN3GYIK4Mt6EsSxDIpaArE6JopqRpalULjiOk83hWVPR1V95xphnzYAWM1YF6I6JexE9kw==",
+ "dev": true,
+ "requires": {
+ "@material/base": "^0.41.0",
+ "@material/ripple": "^0.41.0",
+ "@material/rtl": "^0.40.1",
+ "@material/tab-indicator": "^0.41.0",
+ "@material/theme": "^0.41.0",
+ "@material/typography": "^0.41.0"
+ }
+ },
+ "@material/tab-indicator": {
+ "version": "0.41.0",
+ "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-0.41.0.tgz",
+ "integrity": "sha512-IBJEO+O8OnFVgRAn4CCGccpyNPF1bvTp5+1foD46S2u7XZLD7ejfxTQhqE5HYWtVLQ3zk1aYo3+N9+oSUkpM2w==",
+ "dev": true,
+ "requires": {
+ "@material/animation": "^0.41.0",
+ "@material/base": "^0.41.0",
+ "@material/theme": "^0.41.0"
+ }
+ },
"@material/tab-scroller": {
"version": "0.41.0",
"resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-0.41.0.tgz",
diff --git a/package.json b/package.json
index a68f470e4..2057690e4 100644
--- a/package.json
+++ b/package.json
@@ -82,7 +82,7 @@
"@material/select": "^0.40.1",
"@material/snackbar": "^0.43.0",
"@material/switch": "^0.41.0",
- "@material/tab": "^0.41.0",
+ "@material/tab": "^1.0.0",
"@material/tab-bar": "^0.41.0",
"@material/tab-indicator": "^1.0.0",
"@material/tab-scroller": "^1.0.0",
diff --git a/packages/tab-bar/index.tsx b/packages/tab-bar/index.tsx
index c2d5d58a1..fa95ec124 100644
--- a/packages/tab-bar/index.tsx
+++ b/packages/tab-bar/index.tsx
@@ -47,7 +47,18 @@ class TabBar extends React.Component<
this.foundation.init();
const {activeIndex, indexInView} = this.props;
if (this.tabList[activeIndex]) {
- this.tabList[activeIndex].activate({} /* previousIndicatorClientRect */);
+ // new DOMRect is not IE11 compatible
+ const defaultDOMRect = {
+ bottom: 0,
+ height: 0,
+ left: 0,
+ right: 0,
+ top: 0,
+ width: 0,
+ x: 0,
+ y: 0,
+ };
+ this.tabList[activeIndex].activate(defaultDOMRect /* previousIndicatorClientRect */);
}
this.foundation.scrollIntoView(indexInView);
}
diff --git a/packages/tab/README.md b/packages/tab/README.md
index c0a65e7e5..bd476348d 100644
--- a/packages/tab/README.md
+++ b/packages/tab/README.md
@@ -86,6 +86,7 @@ minWidth | boolean | If true will display the `` as narrow as possible.
isMinWidthIndicator | boolean | If true will display the `` to the size of the longest content element.
isIconIndicator | boolean | If true will display the indicator content in the center of the tab.
previousIndicatorClientRect | ClientRect | The indicator's clientRect that was previously activated.
+onInteraction | Function | The function is called if the tab receives any interaction
stacked | boolean | If true will display the tab icon and label to flow vertically instead of horizontally.
onTransitionEnd | function | transitionend event callback handler.
diff --git a/packages/tab/index.tsx b/packages/tab/index.tsx
index f9c9104db..76e9ab96d 100644
--- a/packages/tab/index.tsx
+++ b/packages/tab/index.tsx
@@ -24,8 +24,8 @@ import * as React from 'react';
import classnames from 'classnames';
import TabIndicator from '@material/react-tab-indicator';
-// @ts-ignore No mdc .d.ts files
-import {MDCTabFoundation} from '@material/tab/dist/mdc.tab';
+import {MDCTabFoundation} from '@material/tab/foundation';
+import {MDCTabAdapter} from '@material/tab/adapter';
import TabRipple, {TabRippleProps} from './TabRipple';
@@ -38,10 +38,11 @@ export interface TabProps extends React.HTMLProps {
isMinWidthIndicator?: boolean;
stacked?: boolean;
previousIndicatorClientRect?: ClientRect;
+ onInteraction?: () => void;
}
interface MDCTabElementAttributes {
- 'aria-selected': boolean;
+ 'aria-selected'?: 'false' | 'true';
tabIndex?: number;
}
@@ -52,7 +53,7 @@ interface TabState extends MDCTabElementAttributes {
}
export default class Tab extends React.Component {
- foundation?: MDCTabFoundation;
+ foundation!: MDCTabFoundation;
tabRef: React.RefObject = React.createRef();
tabContentRef: React.RefObject = React.createRef();
tabIndicatorRef: React.RefObject = React.createRef();
@@ -67,11 +68,12 @@ export default class Tab extends React.Component {
minWidth: false,
isMinWidthIndicator: false,
stacked: false,
+ onInteraction: () => null,
};
state: TabState = {
'classList': new Set(),
- 'aria-selected': false,
+ 'aria-selected': 'false',
'activateIndicator': false,
'previousIndicatorClientRect': this.props.previousIndicatorClientRect,
'tabIndex': -1,
@@ -81,7 +83,7 @@ export default class Tab extends React.Component {
const {active, focusOnActivate} = this.props;
this.foundation = new MDCTabFoundation(this.adapter);
this.foundation.init();
- this.foundation.setFocusOnActivate(focusOnActivate);
+ this.foundation.setFocusOnActivate(focusOnActivate!);
if (active) {
this.foundation.activate();
}
@@ -94,7 +96,7 @@ export default class Tab extends React.Component {
componentDidUpdate(prevProps: TabProps) {
const {active, focusOnActivate, previousIndicatorClientRect} = this.props;
if (focusOnActivate !== prevProps.focusOnActivate) {
- this.foundation.setFocusOnActivate(focusOnActivate);
+ this.foundation.setFocusOnActivate(focusOnActivate!);
}
if (active !== prevProps.active) {
if (active) {
@@ -115,7 +117,7 @@ export default class Tab extends React.Component {
});
}
- get adapter() {
+ get adapter(): MDCTabAdapter {
return {
addClass: (className: string) => {
const classList = new Set(this.state.classList);
@@ -136,12 +138,15 @@ export default class Tab extends React.Component {
getOffsetWidth: () =>
Number(this.tabRef.current && this.tabRef.current.offsetWidth),
getContentOffsetLeft: () =>
- this.tabContentRef.current &&
- this.tabContentRef.current.offsetLeft,
+ this.tabContentRef.current ?
+ this.tabContentRef.current.offsetLeft :
+ 0,
getContentOffsetWidth: () =>
- this.tabContentRef.current &&
- this.tabContentRef.current.offsetWidth,
+ this.tabContentRef.current ?
+ this.tabContentRef.current.offsetWidth :
+ 0,
focus: () => this.tabRef.current && this.tabRef.current.focus(),
+ notifyInteracted: this.props.onInteraction!,
activateIndicator: (previousIndicatorClientRect: ClientRect) =>
this.setState({
activateIndicator: true,
@@ -151,7 +156,7 @@ export default class Tab extends React.Component {
};
}
- activate(computeIndicatorClientRect?: ClientRect | {}) {
+ activate(computeIndicatorClientRect?: ClientRect) {
this.foundation.activate(computeIndicatorClientRect);
}
@@ -190,6 +195,7 @@ export default class Tab extends React.Component {
isFadingIndicator,
indicatorContent,
minWidth,
+ onInteraction,
stacked,
/* eslint-enable */
children,
diff --git a/packages/tab/package.json b/packages/tab/package.json
index c1154af88..95ecc2aea 100644
--- a/packages/tab/package.json
+++ b/packages/tab/package.json
@@ -19,7 +19,7 @@
"dependencies": {
"@material/react-ripple": "^0.10.0",
"@material/react-tab-indicator": "^0.8.0",
- "@material/tab": "^0.41.0",
+ "@material/tab": "^1.0.0",
"classnames": "^2.2.6",
"react": "^16.3.2"
},
diff --git a/test/unit/tab/index.test.tsx b/test/unit/tab/index.test.tsx
index 5b2ff48b6..0493bdd18 100644
--- a/test/unit/tab/index.test.tsx
+++ b/test/unit/tab/index.test.tsx
@@ -4,6 +4,7 @@ import * as td from 'testdouble';
import {mount, shallow} from 'enzyme';
import Tab from '../../../packages/tab/index';
import TabIndicatorRef from '../../../packages/tab-indicator/index';
+import {MDCTabDimensions} from '@material/tab/types';
import {coerceForTesting} from '../helpers/types';
suite('Tab');
@@ -67,14 +68,14 @@ test('if props.active updates to false, foundation.deactivate is called', () =>
test('calls foundation.setFocusOnActivate when props.focusOnActivate changes from false to true', () => {
const wrapper = shallow();
- wrapper.instance().foundation.setFocusOnActivate = td.func();
+ wrapper.instance().foundation.setFocusOnActivate = td.func<(focusOnActivate: boolean) => null>();
wrapper.setProps({focusOnActivate: true});
td.verify(wrapper.instance().foundation.setFocusOnActivate(true), {times: 1});
});
test('calls foundation.setFocusOnActivate when props.focusOnActivate changes from true to false', () => {
const wrapper = shallow();
- wrapper.instance().foundation.setFocusOnActivate = td.func();
+ wrapper.instance().foundation.setFocusOnActivate = td.func<(focusOnActivate: boolean) => null>();
wrapper.setProps({focusOnActivate: false});
td.verify(wrapper.instance().foundation.setFocusOnActivate(false), {times: 1});
});
@@ -149,8 +150,8 @@ test('#adapter.setAttr sets tabIndex on state', () => {
test('#adapter.setAttr sets aria-selected on state', () => {
const wrapper = shallow();
- wrapper.instance().adapter.setAttr('aria-selected', true);
- assert.isTrue(wrapper.state()['aria-selected']);
+ wrapper.instance().adapter.setAttr('aria-selected', 'true');
+ assert.equal(wrapper.state()['aria-selected'], 'true');
});
test('#adapter.getOffsetLeft returns tabRef.offsetLeft', () => {
@@ -199,14 +200,14 @@ test('#adapter.deactivateIndicator sets state.activateIndicator', () => {
test('#activate calls foundation.activate', () => {
const clientRect = {test: 1} as unknown as ClientRect; ;
const wrapper = shallow();
- wrapper.instance().foundation.activate = td.func();
+ wrapper.instance().foundation.activate = td.func<(previousIndicatorClientRect?: ClientRect) => null>();
wrapper.instance().activate(clientRect);
td.verify(wrapper.instance().foundation.activate(clientRect), {times: 1});
});
test('#deactivate calls foundation.deactivate', () => {
const wrapper = shallow();
- wrapper.instance().foundation.deactivate = td.func();
+ wrapper.instance().foundation.deactivate = td.func<() => null>();
wrapper.instance().deactivate();
td.verify(wrapper.instance().foundation.deactivate(), {times: 1});
});
@@ -220,7 +221,7 @@ test('#computeIndicatorClientRect returns the tabIndicatorRef clientRect', () =>
test('#computeDimensions calls foundation.computeDimensions', () => {
const wrapper = shallow();
- wrapper.instance().foundation.computeDimensions = td.func();
+ wrapper.instance().foundation.computeDimensions = td.func<() => MDCTabDimensions>();
wrapper.instance().computeDimensions();
td.verify(wrapper.instance().foundation.computeDimensions(), {times: 1});
});
@@ -362,7 +363,7 @@ test('props.isMinWidthIndicator renders indicator within the content element', (
test('#componentWillUnmount destroys foundation', () => {
const wrapper = shallow();
const foundation = wrapper.instance().foundation;
- foundation.destroy = td.func();
+ foundation.destroy = td.func<() => null>();
wrapper.unmount();
td.verify(foundation.destroy(), {times: 1});
});