Skip to content

Commit

Permalink
Add "disabled" prop and Preact support to Tabs component (#265)
Browse files Browse the repository at this point in the history
  • Loading branch information
somepedro authored and sawyerh committed Jun 28, 2018
1 parent d3d9228 commit 5675f0b
Show file tree
Hide file tree
Showing 11 changed files with 56 additions and 10 deletions.
8 changes: 5 additions & 3 deletions packages/core/dist/components/Tabs/Tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,13 @@ var Tab = exports.Tab = function (_React$PureComponent) {
'a',
{
'aria-selected': String(this.props.selected),
'aria-disabled': String(this.props.disabled),
'aria-controls': this.props.panelId,
className: classes,
href: this.href,
id: this.props.id,
onClick: this.handleClick,
onKeyDown: this.handleKeyDown,
onClick: this.props.disabled ? undefined : this.handleClick,
onKeyDown: this.props.disabled ? undefined : this.handleKeyDown,
role: 'tab',
ref: function ref(tab) {
_this2.tab = tab;
Expand Down Expand Up @@ -127,7 +128,8 @@ Tab.propTypes = {
* The `id` of the associated `TabPanel`. Used for the `aria-controls` attribute.
*/
panelId: _propTypes2.default.string.isRequired,
selected: _propTypes2.default.bool
selected: _propTypes2.default.bool,
disabled: _propTypes2.default.bool
};

exports.default = Tab;
2 changes: 2 additions & 0 deletions packages/core/dist/components/Tabs/TabPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ function TabPanel(props) {
{
'aria-labelledby': props.tabId,
'aria-hidden': String(!props.selected),
'aria-disabled': String(props.disabled),
className: classes,
id: props.id,
role: 'tabpanel'
Expand All @@ -54,6 +55,7 @@ TabPanel.propTypes = {
*/
id: _propTypes2.default.string.isRequired,
selected: _propTypes2.default.bool,
disabled: _propTypes2.default.bool,
/* eslint-disable react/no-unused-prop-types */
/**
* The associated tab's label. Only applicable when the panel is a
Expand Down
2 changes: 1 addition & 1 deletion packages/core/dist/components/Tabs/Tabs.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion packages/core/dist/components/Tabs/Tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ function panelTabId(panel) {
* @return {Boolean} Is this a TabPanel component?
*/
function isTabPanel(child) {
return child != null && child.type === _TabPanel2.default;
// Preact doesn't support child.type, React doesn't support child.nodeName
return child != null && (child.type === _TabPanel2.default || child.nodeName && child.nodeName.prototype && child.nodeName.prototype.displayName === 'TabPanel');
}

/**
Expand Down Expand Up @@ -205,6 +206,7 @@ var Tabs = exports.Tabs = function (_React$PureComponent) {
{
className: panel.props.tabClassName,
href: panel.props.tabHref,
disabled: panel.props.disabled,
id: panelTabId(panel),
key: panel.key,
onClick: _this3.handleTabClick,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/dist/index.css

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions packages/core/src/components/Tabs/Tab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ export class Tab extends React.PureComponent {
return (
<a
aria-selected={String(this.props.selected)}
aria-disabled={String(this.props.disabled)}
aria-controls={this.props.panelId}
className={classes}
href={this.href}
id={this.props.id}
onClick={this.handleClick}
onKeyDown={this.handleKeyDown}
onClick={this.props.disabled ? undefined : this.handleClick}
onKeyDown={this.props.disabled ? undefined : this.handleKeyDown}
role="tab"
ref={tab => {
this.tab = tab;
Expand Down Expand Up @@ -86,7 +87,8 @@ Tab.propTypes = {
* The `id` of the associated `TabPanel`. Used for the `aria-controls` attribute.
*/
panelId: PropTypes.string.isRequired,
selected: PropTypes.bool
selected: PropTypes.bool,
disabled: PropTypes.bool
};

export default Tab;
10 changes: 10 additions & 0 deletions packages/core/src/components/Tabs/Tab.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ describe('Tab', function() {
expect(onClickMock.mock.calls[0][3]).toBe(`#${data.props.panelId}`);
});

it("doesn't call onClick when disabled", () => {
const onClickMock = jest.fn();
const data = shallowRender({ onClick: onClickMock, disabled: true });

data.wrapper.simulate('click');
data.wrapper.simulate('onKeyDown');

expect(onClickMock.mock.calls.length).toBe(0);
});

it('is selected', () => {
const wrapper = shallowRender({ selected: true }).wrapper;
expect(wrapper.prop('aria-selected')).toBe('true');
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/components/Tabs/TabPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function TabPanel(props) {
<div
aria-labelledby={props.tabId}
aria-hidden={String(!props.selected)}
aria-disabled={String(props.disabled)}
className={classes}
id={props.id}
role="tabpanel"
Expand All @@ -37,6 +38,7 @@ TabPanel.propTypes = {
*/
id: PropTypes.string.isRequired,
selected: PropTypes.bool,
disabled: PropTypes.bool,
/* eslint-disable react/no-unused-prop-types */
/**
* The associated tab's label. Only applicable when the panel is a
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/components/Tabs/Tabs.example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ ReactDOM.render(
<li>Congressional pay raises</li>
</ol>
</TabPanel>
<TabPanel id="disabled" tab="Disabled" disabled>
You should not see this.
</TabPanel>
</Tabs>,
document.getElementById('js-example')
);
10 changes: 9 additions & 1 deletion packages/core/src/components/Tabs/Tabs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ function panelTabId(panel) {
* @return {Boolean} Is this a TabPanel component?
*/
function isTabPanel(child) {
return child != null && child.type === TabPanel;
// Preact doesn't support child.type, React doesn't support child.nodeName
return (
child != null &&
(child.type === TabPanel ||
(child.nodeName &&
child.nodeName.prototype &&
child.nodeName.prototype.displayName === 'TabPanel'))
);
}

/**
Expand Down Expand Up @@ -150,6 +157,7 @@ export class Tabs extends React.PureComponent {
<Tab
className={panel.props.tabClassName}
href={panel.props.tabHref}
disabled={panel.props.disabled}
id={panelTabId(panel)}
key={panel.key}
onClick={this.handleTabClick}
Expand Down
15 changes: 15 additions & 0 deletions packages/core/src/components/Tabs/Tabs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,21 @@ Style guide: components.tabs.react-tab
}
}

&[aria-disabled='true'] {
background-color: $color-gray-lighter;
border-color: $color-gray-lighter;
color: $color-gray-dark;
pointer-events: none;

&:hover,
&:active,
&:focus {
background-color: $color-gray-lighter;
border-color: $color-gray-lighter;
color: $color-gray-dark;
}
}

&:focus,
&:hover {
color: $color-primary;
Expand Down

0 comments on commit 5675f0b

Please sign in to comment.