Skip to content

Commit 50ee8f6

Browse files
Merge pull request #756 from chriscorwin/GH-733---tabs--add-scoped-flavor
Add scoped variant to Tabs
2 parents 2df5d6f + f1b472c commit 50ee8f6

File tree

6 files changed

+104
-21
lines changed

6 files changed

+104
-21
lines changed

components/tabs/index.jsx

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ function isTabDisabled (node) {
6262
return node.getAttribute('aria-disabled') === 'true';
6363
}
6464

65-
6665
/**
6766
* Tabs keeps related content in a single container that is shown and hidden through navigation.
6867
*/
@@ -124,6 +123,11 @@ const Tabs = React.createClass({
124123
*/
125124
onSelect: PropTypes.func,
126125

126+
/**
127+
* If the Tabs should be scopped, defaults to false
128+
*/
129+
variant: React.PropTypes.oneOf(['default', 'scoped']),
130+
127131
/**
128132
* The Tab (and corresponding TabPanel) that is currently selected.
129133
*/
@@ -132,7 +136,8 @@ const Tabs = React.createClass({
132136

133137
getDefaultProps () {
134138
return {
135-
defaultSelectedIndex: 0
139+
defaultSelectedIndex: 0,
140+
variant: 'default'
136141
};
137142
},
138143

@@ -143,12 +148,16 @@ const Tabs = React.createClass({
143148
componentWillMount () {
144149
// If no `id` is supplied in the props we generate one. An HTML ID is _required_ for several elements in a tabs component in order to leverage ARIA attributes for accessibility.
145150
this.generatedId = shortid.generate();
146-
151+
this.flavor = this.getVariant();
147152
this.setState({
148153
selectedIndex: this.props.defaultSelectedIndex
149154
});
150155
},
151156

157+
getVariant () {
158+
return this.props.variant === 'scoped' ? 'scoped' : 'default';
159+
},
160+
152161
handleClick (e) {
153162
let node = e.target;
154163
/* eslint-disable no-cond-assign */
@@ -308,13 +317,14 @@ const Tabs = React.createClass({
308317

309318
return (
310319
// `parentId` gets consumed by TabsList, adding a suffix of `-tabs__nav`
311-
<TabsList id={parentId}>
320+
<TabsList id={parentId} variant={this.getVariant()}>
312321
{children.map((child, index) => {
313322
const ref = `tabs-${index}`;
314323
const id = `${parentId}-slds-tabs--tab-${index}`;
315324
const panelId = `${parentId}-slds-tabs--panel-${index}`;
316325
const selected = this.getSelectedIndex() === index;
317326
const focus = selected && this.state.focus;
327+
const variant = this.getVariant();
318328
return (
319329
<Tab
320330
key={index}
@@ -324,6 +334,7 @@ const Tabs = React.createClass({
324334
id={id}
325335
panelId={panelId}
326336
disabled={child.props.disabled}
337+
variant={variant}
327338
>
328339
{child.props.label}
329340
</Tab>
@@ -342,6 +353,7 @@ const Tabs = React.createClass({
342353
const tabId = `${parentId}-slds-tabs--tab-${index}`;
343354
const id = `${parentId}-slds-tabs--panel-${index}`;
344355
const selected = selectedIndex === index;
356+
const variant = this.getVariant();
345357

346358
return (
347359
<TabPanel
@@ -350,6 +362,7 @@ const Tabs = React.createClass({
350362
selected={selected}
351363
id={id}
352364
tabId={tabId}
365+
variant={variant}
353366
>
354367
{children[index]}
355368
</TabPanel>
@@ -363,6 +376,7 @@ const Tabs = React.createClass({
363376
const {
364377
className,
365378
id = this.generatedId,
379+
variant = this.getVariant,
366380
...attributes
367381
} = this.props;
368382

@@ -381,12 +395,16 @@ const Tabs = React.createClass({
381395
<div
382396
id={id}
383397
className={classNames(
384-
'slds-tabs--default',
398+
{
399+
'slds-tabs--default': variant === 'default',
400+
'slds-tabs--scoped': variant === 'scoped'
401+
},
385402
className
386403
)}
387404
onClick={this.handleClick}
388405
onKeyDown={this.handleKeyDown}
389406
data-tabs
407+
variant={variant}
390408
{...attributes}
391409
>
392410
{this.renderTabsList(id)}

components/tabs/tab-panel.jsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,23 @@ import React, { PropTypes } from 'react';
2222
import classNames from 'classnames';
2323
import { TAB_PANEL } from '../../utilities/constants';
2424

25-
const TabPanel = ({ className, children, selected, id, tabId, ...attributes }) => (
25+
const TabPanel = ({ className, children, variant, selected, id, tabId, ...attributes }) => (
2626
<div
2727
{...attributes}
2828
className={classNames(
29-
'slds-tabs--default__content',
3029
className,
3130
{
3231
'slds-show': selected,
33-
'slds-hide': !selected
32+
'slds-hide': !selected,
33+
'slds-tabs--default__content': variant === 'default',
34+
'slds-tabs--scoped__content': variant === 'scoped'
3435
}
3536
)}
3637
role="tabpanel"
3738
id={id}
3839
aria-selected={selected ? 'true' : 'false'}
3940
aria-labelledby={tabId}
41+
variant={variant}
4042
>
4143
{children.props.children}
4244
</div>
@@ -89,13 +91,19 @@ TabPanel.propTypes = {
8991
*/
9092
selected: PropTypes.bool,
9193

94+
/**
95+
* If the Tabs should be scopped, defaults to false
96+
*/
97+
variant: React.PropTypes.oneOf(['default', 'scoped']),
98+
9299
/**
93100
* The HTML ID of the `<Tab />` that controls this panel.
94101
*/
95102
tabId: PropTypes.string
96103
};
97104

98105
TabPanel.defaultProps = {
106+
variant: 'default',
99107
selected: false
100108
};
101109

components/tabs/tab.jsx

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,21 @@ const Tab = React.createClass({
7373
/**
7474
* The string that is shown as both the title and the label for this tab.
7575
*/
76-
children: PropTypes.string
76+
children: PropTypes.string,
77+
78+
/**
79+
* If the Tabs should be scopped, defaults to false
80+
*/
81+
variant: React.PropTypes.oneOf(['default', 'scoped'])
7782
},
7883

7984
getDefaultProps () {
8085
return {
8186
focus: false,
8287
selected: false,
8388
activeTabClassName: 'slds-active',
84-
disabledTabClassName: 'slds-disabled'
89+
disabledTabClassName: 'slds-disabled',
90+
variant: 'default'
8591
};
8692
},
8793

@@ -109,20 +115,21 @@ const Tab = React.createClass({
109115
className,
110116
children,
111117
id,
118+
variant,
112119
...attributes } = this.props;
113120

114121
delete attributes.focus;
115-
116122
return (
117123
<li
118124
{...attributes}
119125
className={classNames(
120-
'slds-tabs--default__item',
121126
'slds-text-title--caps',
122127
className,
123128
{
124129
[activeTabClassName]: selected,
125-
[disabledTabClassName]: disabled
130+
[disabledTabClassName]: disabled,
131+
'slds-tabs--default__item': variant === 'default',
132+
'slds-tabs--scoped__item': variant === 'scoped'
126133
}
127134
)}
128135
role="tab"
@@ -134,7 +141,14 @@ const Tab = React.createClass({
134141
title={children}
135142
>
136143
<a
137-
className="slds-tabs--default__link"
144+
className={classNames(
145+
{
146+
[activeTabClassName]: selected,
147+
[disabledTabClassName]: disabled,
148+
'slds-tabs--default__link': variant === 'default',
149+
'slds-tabs--scoped__link': variant === 'scoped'
150+
}
151+
)}
138152
href="javascript:void(0);" // eslint-disable-line no-script-url
139153
role="presentation"
140154
tabIndex="-1"

components/tabs/tabs-list.jsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,21 @@ const TabsList = ({
2727
id,
2828
className,
2929
children,
30+
variant,
3031
...attributes
3132
}) => (
3233
<ul
3334
id={`${id}-slds-tabs__nav`}
3435
{...attributes}
3536
className={classNames(
36-
'slds-tabs--default__nav',
37-
className
37+
className,
38+
{
39+
'slds-tabs--default__nav': variant === 'default',
40+
'slds-tabs--scoped__nav': variant === 'scoped'
41+
}
3842
)}
3943
role="tablist"
44+
variant={variant}
4045
>
4146
{children}
4247
</ul>
@@ -65,7 +70,12 @@ TabsList.propTypes = {
6570
children: PropTypes.oneOfType([
6671
PropTypes.object,
6772
PropTypes.array
68-
])
73+
]),
74+
75+
/**
76+
* If the Tabs should be scopped, defaults to false
77+
*/
78+
variant: React.PropTypes.oneOf(['default', 'scoped'])
6979
};
7080

7181
module.exports = TabsList;

stories/tabs/index.jsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,32 @@ const getTabsNested = () => (
126126
);
127127
/* eslint-enable react/display-name */
128128

129+
/* eslint-disable react/display-name */
130+
const getTabsScoped = () => (
131+
<div>
132+
<h2 className="slds-text-heading--large">Scoped Tabs Demo</h2>
133+
<Tabs id="scoped-tabs-demo" variant="scoped">
134+
<Panel label="Tab 1">
135+
<h2 className="slds-text-heading--medium">This is my tab 1 contents!</h2>
136+
<p>And they&rsquo;re amazing.</p>
137+
<p>It's awesome.</p>
138+
<p>You can use your <var>TAB</var> and <var>ARROW</var> keys to navigate around. Try it!</p>
139+
<p className="slds-box slds-theme--info slds-m-top--large">
140+
(You might have to hit shift+tab to put the focus onto the tab bar ;)
141+
</p>
142+
</Panel>
143+
<Panel label="Tab 2">
144+
<h2 className="slds-text-heading--medium">This is my tab 2 contents!</h2>
145+
<p>And they&rsquo;re also amazing.</p>
146+
</Panel>
147+
<Panel label="Tab 3">
148+
<h2 className="slds-text-heading--medium">This is my tab 3 contents!</h2>
149+
<p>And they&rsquo;re quite spectacular.</p>
150+
</Panel>
151+
</Tabs>
152+
</div>
153+
);
154+
/* eslint-enable react/display-name */
129155

130156
const DemoTabsConditional = React.createClass({
131157
displayName: 'DemoTabsConditional',
@@ -448,6 +474,7 @@ storiesOf(TABS, module)
448474
.add('Outside Control', () => <DemoTabsOutsideControl className="controlled-yo" />)
449475
.add('Conditional', () => <DemoTabsConditional className="conditional-yo" />)
450476
.add('Unique Generated IDs', () => getTabsMoreThanOneAllowGeneratedID())
477+
.add('Scoped', () => getTabsScoped())
451478
;
452479

453480
module.exports = getTabs;

styles/tabs/tab.css

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
1-
.slds-tabs--default .slds-tabs--default__item.slds-disabled {
1+
.slds-tabs--default .slds-tabs--default__item.slds-disabled,
2+
.slds-tabs--scoped .slds-tabs--scoped__item.slds-disabled {
23
opacity: 0.5;
34
}
4-
.slds-tabs--default .slds-tabs--default__item.slds-disabled > a:hover, .slds-tabs--default .slds-tabs--default__item.slds-disabled > a.slds-tabs--default__link:focus {
5+
.slds-tabs--default .slds-tabs--default__item.slds-disabled > a:hover,
6+
.slds-tabs--scoped .slds-tabs--scoped__item.slds-disabled > a:hover,
7+
.slds-tabs--default .slds-tabs--default__item.slds-disabled > a.slds-tabs--default__link:focus,
8+
.slds-tabs--scoped .slds-tabs--scoped__item.slds-disabled > a.slds-tabs--scoped__link:focus {
59
cursor: not-allowed;
610
text-decoration: none;
711
border-color: transparent;
812
color: inherit;
913
}
10-
.slds-tabs--default .slds-tabs--default__item.slds-disabled.slds-active a.slds-tabs--default__link {
14+
.slds-tabs--default .slds-tabs--default__item.slds-disabled.slds-active a.slds-tabs--default__link,
15+
.slds-tabs--scoped .slds-tabs--scoped__item.slds-disabled.slds-active a.slds-tabs--scoped__link {
1116
cursor: not-allowed;
1217
border-color: transparent;
1318
color: inherit;
1419
}
15-
.slds-tabs--default .slds-tabs--default__item.slds-disabled.slds-active a.slds-tabs--default__link:focus {
20+
.slds-tabs--default .slds-tabs--default__item.slds-disabled.slds-active a.slds-tabs--default__link:focus,
21+
.slds-tabs--scoped .slds-tabs--scoped__item.slds-disabled.slds-active a.slds-tabs--scoped__link:focus {
1622
cursor: not-allowed;
1723
color: inherit;
1824
}

0 commit comments

Comments
 (0)