Skip to content
This repository was archived by the owner on Jan 14, 2025. It is now read-only.

Commit 9b86474

Browse files
guguMatt Goo
authored and
Matt Goo
committed
fix(tab): mdc-web v1.0.0 upgrade (#748)
1 parent a8c64b5 commit 9b86474

File tree

7 files changed

+135
-51
lines changed

7 files changed

+135
-51
lines changed

package-lock.json

Lines changed: 92 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
"@material/select": "^0.40.1",
8383
"@material/snackbar": "^0.43.0",
8484
"@material/switch": "^0.41.0",
85-
"@material/tab": "^0.41.0",
85+
"@material/tab": "^1.0.0",
8686
"@material/tab-bar": "^0.41.0",
8787
"@material/tab-indicator": "^1.0.0",
8888
"@material/tab-scroller": "^1.0.0",

packages/tab-bar/index.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,18 @@ class TabBar extends React.Component<
4747
this.foundation.init();
4848
const {activeIndex, indexInView} = this.props;
4949
if (this.tabList[activeIndex]) {
50-
this.tabList[activeIndex].activate({} /* previousIndicatorClientRect */);
50+
// new DOMRect is not IE11 compatible
51+
const defaultDOMRect = {
52+
bottom: 0,
53+
height: 0,
54+
left: 0,
55+
right: 0,
56+
top: 0,
57+
width: 0,
58+
x: 0,
59+
y: 0,
60+
};
61+
this.tabList[activeIndex].activate(defaultDOMRect /* previousIndicatorClientRect */);
5162
}
5263
this.foundation.scrollIntoView(indexInView);
5364
}

packages/tab/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ indicatorContent | element | Element that will appear within the `<TabIndicator
8585
minWidth | boolean | If true will display the `<Tab />` as narrow as possible.
8686
isMinWidthIndicator | boolean | If true will display the `<TabIndicator />` to the size of the longest content element.
8787
previousIndicatorClientRect | ClientRect | The indicator's clientRect that was previously activated.
88+
onInteraction | Function | The function is called if the tab receives any interaction
8889
stacked | boolean | If true will display the tab icon and label to flow vertically instead of horizontally.
8990

9091
## Sass Mixins

packages/tab/index.tsx

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ import * as React from 'react';
2424
import classnames from 'classnames';
2525

2626
import TabIndicator from '@material/react-tab-indicator';
27-
// @ts-ignore No mdc .d.ts files
28-
import {MDCTabFoundation} from '@material/tab/dist/mdc.tab';
27+
import {MDCTabFoundation} from '@material/tab/foundation';
28+
import {MDCTabAdapter} from '@material/tab/adapter';
2929

3030
import TabRipple, {TabRippleProps} from './TabRipple';
3131

@@ -38,10 +38,11 @@ export interface TabProps extends React.HTMLProps<HTMLButtonElement> {
3838
isMinWidthIndicator?: boolean;
3939
stacked?: boolean;
4040
previousIndicatorClientRect?: ClientRect;
41+
onInteraction?: () => void;
4142
}
4243

4344
interface MDCTabElementAttributes {
44-
'aria-selected': boolean;
45+
'aria-selected'?: 'false' | 'true';
4546
tabIndex?: number;
4647
}
4748

@@ -52,7 +53,7 @@ interface TabState extends MDCTabElementAttributes {
5253
}
5354

5455
export default class Tab extends React.Component<TabProps, TabState> {
55-
foundation?: MDCTabFoundation;
56+
foundation!: MDCTabFoundation;
5657
tabRef: React.RefObject<HTMLButtonElement> = React.createRef();
5758
tabContentRef: React.RefObject<HTMLSpanElement> = React.createRef();
5859
tabIndicatorRef: React.RefObject<TabIndicator> = React.createRef();
@@ -67,11 +68,12 @@ export default class Tab extends React.Component<TabProps, TabState> {
6768
minWidth: false,
6869
isMinWidthIndicator: false,
6970
stacked: false,
71+
onInteraction: () => null,
7072
};
7173

7274
state: TabState = {
7375
'classList': new Set(),
74-
'aria-selected': false,
76+
'aria-selected': 'false',
7577
'activateIndicator': false,
7678
'previousIndicatorClientRect': this.props.previousIndicatorClientRect,
7779
'tabIndex': -1,
@@ -81,7 +83,7 @@ export default class Tab extends React.Component<TabProps, TabState> {
8183
const {active, focusOnActivate} = this.props;
8284
this.foundation = new MDCTabFoundation(this.adapter);
8385
this.foundation.init();
84-
this.foundation.setFocusOnActivate(focusOnActivate);
86+
this.foundation.setFocusOnActivate(focusOnActivate!);
8587
if (active) {
8688
this.foundation.activate();
8789
}
@@ -94,7 +96,7 @@ export default class Tab extends React.Component<TabProps, TabState> {
9496
componentDidUpdate(prevProps: TabProps) {
9597
const {active, focusOnActivate, previousIndicatorClientRect} = this.props;
9698
if (focusOnActivate !== prevProps.focusOnActivate) {
97-
this.foundation.setFocusOnActivate(focusOnActivate);
99+
this.foundation.setFocusOnActivate(focusOnActivate!);
98100
}
99101
if (active !== prevProps.active) {
100102
if (active) {
@@ -115,7 +117,7 @@ export default class Tab extends React.Component<TabProps, TabState> {
115117
});
116118
}
117119

118-
get adapter() {
120+
get adapter(): MDCTabAdapter {
119121
return {
120122
addClass: (className: string) => {
121123
const classList = new Set(this.state.classList);
@@ -136,12 +138,15 @@ export default class Tab extends React.Component<TabProps, TabState> {
136138
getOffsetWidth: () =>
137139
Number(this.tabRef.current && this.tabRef.current.offsetWidth),
138140
getContentOffsetLeft: () =>
139-
this.tabContentRef.current &&
140-
this.tabContentRef.current.offsetLeft,
141+
this.tabContentRef.current ?
142+
this.tabContentRef.current.offsetLeft :
143+
0,
141144
getContentOffsetWidth: () =>
142-
this.tabContentRef.current &&
143-
this.tabContentRef.current.offsetWidth,
145+
this.tabContentRef.current ?
146+
this.tabContentRef.current.offsetWidth :
147+
0,
144148
focus: () => this.tabRef.current && this.tabRef.current.focus(),
149+
notifyInteracted: this.props.onInteraction!,
145150
activateIndicator: (previousIndicatorClientRect: ClientRect) =>
146151
this.setState({
147152
activateIndicator: true,
@@ -151,7 +156,7 @@ export default class Tab extends React.Component<TabProps, TabState> {
151156
};
152157
}
153158

154-
activate(computeIndicatorClientRect?: ClientRect | {}) {
159+
activate(computeIndicatorClientRect?: ClientRect) {
155160
this.foundation.activate(computeIndicatorClientRect);
156161
}
157162

@@ -190,6 +195,7 @@ export default class Tab extends React.Component<TabProps, TabState> {
190195
isFadingIndicator,
191196
indicatorContent,
192197
minWidth,
198+
onInteraction,
193199
stacked,
194200
/* eslint-enable */
195201
children,

packages/tab/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"dependencies": {
2020
"@material/react-ripple": "^0.11.0",
2121
"@material/react-tab-indicator": "^0.11.0",
22-
"@material/tab": "^0.41.0",
22+
"@material/tab": "^1.0.0",
2323
"classnames": "^2.2.6",
2424
"react": "^16.3.2"
2525
},

test/unit/tab/index.test.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as td from 'testdouble';
44
import {mount, shallow} from 'enzyme';
55
import Tab from '../../../packages/tab/index';
66
import TabIndicatorRef from '../../../packages/tab-indicator/index';
7+
import {MDCTabDimensions} from '@material/tab/types';
78
import {coerceForTesting} from '../helpers/types';
89

910
suite('Tab');
@@ -67,14 +68,14 @@ test('if props.active updates to false, foundation.deactivate is called', () =>
6768

6869
test('calls foundation.setFocusOnActivate when props.focusOnActivate changes from false to true', () => {
6970
const wrapper = shallow<Tab>(<Tab focusOnActivate={false} />);
70-
wrapper.instance().foundation.setFocusOnActivate = td.func();
71+
wrapper.instance().foundation.setFocusOnActivate = td.func<(focusOnActivate: boolean) => null>();
7172
wrapper.setProps({focusOnActivate: true});
7273
td.verify(wrapper.instance().foundation.setFocusOnActivate(true), {times: 1});
7374
});
7475

7576
test('calls foundation.setFocusOnActivate when props.focusOnActivate changes from true to false', () => {
7677
const wrapper = shallow<Tab>(<Tab focusOnActivate />);
77-
wrapper.instance().foundation.setFocusOnActivate = td.func();
78+
wrapper.instance().foundation.setFocusOnActivate = td.func<(focusOnActivate: boolean) => null>();
7879
wrapper.setProps({focusOnActivate: false});
7980
td.verify(wrapper.instance().foundation.setFocusOnActivate(false), {times: 1});
8081
});
@@ -149,8 +150,8 @@ test('#adapter.setAttr sets tabIndex on state', () => {
149150

150151
test('#adapter.setAttr sets aria-selected on state', () => {
151152
const wrapper = shallow<Tab>(<Tab />);
152-
wrapper.instance().adapter.setAttr('aria-selected', true);
153-
assert.isTrue(wrapper.state()['aria-selected']);
153+
wrapper.instance().adapter.setAttr('aria-selected', 'true');
154+
assert.equal(wrapper.state()['aria-selected'], 'true');
154155
});
155156

156157
test('#adapter.getOffsetLeft returns tabRef.offsetLeft', () => {
@@ -199,14 +200,14 @@ test('#adapter.deactivateIndicator sets state.activateIndicator', () => {
199200
test('#activate calls foundation.activate', () => {
200201
const clientRect = {test: 1} as unknown as ClientRect; ;
201202
const wrapper = shallow<Tab>(<Tab />);
202-
wrapper.instance().foundation.activate = td.func();
203+
wrapper.instance().foundation.activate = td.func<(previousIndicatorClientRect?: ClientRect) => null>();
203204
wrapper.instance().activate(clientRect);
204205
td.verify(wrapper.instance().foundation.activate(clientRect), {times: 1});
205206
});
206207

207208
test('#deactivate calls foundation.deactivate', () => {
208209
const wrapper = shallow<Tab>(<Tab />);
209-
wrapper.instance().foundation.deactivate = td.func();
210+
wrapper.instance().foundation.deactivate = td.func<() => null>();
210211
wrapper.instance().deactivate();
211212
td.verify(wrapper.instance().foundation.deactivate(), {times: 1});
212213
});
@@ -220,7 +221,7 @@ test('#computeIndicatorClientRect returns the tabIndicatorRef clientRect', () =>
220221

221222
test('#computeDimensions calls foundation.computeDimensions', () => {
222223
const wrapper = shallow<Tab>(<Tab />);
223-
wrapper.instance().foundation.computeDimensions = td.func();
224+
wrapper.instance().foundation.computeDimensions = td.func<() => MDCTabDimensions>();
224225
wrapper.instance().computeDimensions();
225226
td.verify(wrapper.instance().foundation.computeDimensions(), {times: 1});
226227
});
@@ -362,7 +363,7 @@ test('props.isMinWidthIndicator renders indicator within the content element', (
362363
test('#componentWillUnmount destroys foundation', () => {
363364
const wrapper = shallow<Tab>(<Tab />);
364365
const foundation = wrapper.instance().foundation;
365-
foundation.destroy = td.func();
366+
foundation.destroy = td.func<() => null>();
366367
wrapper.unmount();
367368
td.verify(foundation.destroy(), {times: 1});
368369
});

0 commit comments

Comments
 (0)