Skip to content

Commit afdf90f

Browse files
Merge branch 'master' of github.com:salesforce-ux/design-system-react
2 parents 7700ab0 + 0fe0035 commit afdf90f

File tree

10 files changed

+128
-33
lines changed

10 files changed

+128
-33
lines changed

CONTRIBUTING.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ We'll review your code, suggest any needed changes, and merge it in. Thank you.
1717

1818
## Concepts and Best Practices
1919

20-
- <a name="approved-slds-patterns" href="#approved-slds-patterns">#</a> This library should include only components which have approved patterns in SLDS.
20+
- <a name="not-bootstrap" href="#not-bootstrap">#</a> This project is not Bootstrap. The primary audience for this project is software engineers. Yes, contributors should over-document and explain as you need to, but you do not need to have components just work when you drop them on the page. New components should always start out as controlled by their parent and only be uncontrolled (that is have state) if a use case presents itself. In short, it's better to have a component that needs 20 props set and outputs the correct SLDS markup, than to have a component that works with no props set. Think of this project as SLDS templates with minimal logic that happen to work with the React framework.
21+
- <a name="approved-slds-patterns" href="#approved-slds-patterns">#</a> This library should include only components which have approved patterns in SLDS. If there is a use case from a designer that conforms to an SLDS pattern, that component should be able to be implemented with this library.
2122
- <a name="controlled-component" href="#controlled-component">#</a> Know what a [controlled component](#understanding-controlled-and-uncontrolled-components) is.
2223
- <a name="familiarize" href="#familiarize">#</a> Familiarize yourself with concepts used in the rest of the library.
2324
- <a name="eslint-all-files-touched" href="#eslint-all-files-touched">#</a> If a file is touched that has outstanding ESlint errors, please fix the ESlint errors first (and in a separate commit). Sometimes special cases require an `eslint-disable` comment for a particular rule and/or line. Please use sparingly.
@@ -34,6 +35,7 @@ We'll review your code, suggest any needed changes, and merge it in. Thank you.
3435
- <a name="event-callbacks" href="#event-callbacks">#</a> Event callbacks should pass in the synthetic event, then a data object with contents that relate to the event.
3536
- <a name="boolean-prop-prefix" href="#boolean-prop-prefix">#</a> If a prop is a boolean, please prefix with `is` or `can` or suffix it with `-able`. Never default a prop to `true`.
3637
- <a name="use-checkprops" href="#use-checkprops">#</a> Add as many prop checking tests that will _only run in development_ as needed via `checkProp`. If the test can become an independent module and work in multiple components, add it to the `utilities` folder.
38+
- <a name="no-window-events" href="#no-window-events">#</a> Global window events like `resize` or external DOM nodes should not be accessed from the component. If needed, `body` can be used for additional mount nodes. If a menu needs to be smaller to be responsive, consuming applications should listen for the resize event and change the correct props to make the component responsive--or a CSS solution should be found. The component should not be listening to the event directly. Global key press or mouse clicks are fine if used appropriately.
3739
- <a name="all-text-can-be-internationalized" href="#all-text-can-be-internationalized">#</a> Any text the user can read (including text for screenreaders) should be able to be set via a prop for internationalization.
3840
- <a name="avoid-css" href="#avoid-css">#</a> Avoid use of inline styles and additional CSS classes not present in SLDS.
3941
- <a name="different-react-component-hierarchy" href="#different-react-component-hierarchy">#</a> React component hierarchy doesn't always mean HTML tag hierarchy. Sometimes children become the wrapping component.
@@ -44,8 +46,8 @@ We'll review your code, suggest any needed changes, and merge it in. Thank you.
4446
## Understanding Controlled and Uncontrolled Components
4547
- All new components should be controlled at first and then uncontrolled support added later if needed.
4648
- All Design System React components should be able to be "controlled"--that is expose a callback and expect their parent to control them with props.
47-
- Please note that if controlled by its parent, a component will appear broken if just copied and pasted into an application without a parent to control its value.
48-
- Controlled components can be stateless components.
49+
- Please note that if controlled by its parent, a component will appear broken if just copied and pasted into an application without a parent to control its props.
50+
- Controlled components can be stateless components, but entirely stateless components do complicate DOM selectors for the consuming applications.
4951

5052
A **controlled** `<input>` has a `value` prop. Rendering a controlled `<input>` will reflect the value of the `value` prop.
5153

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
# Salesforce Design System
2-
### Interactive and accessible components for React
1+
# Salesforce Lightning Design System for JavaScript
2+
### Lightweight and accessible React components
33

44
[![Build Status](https://travis-ci.com/salesforce-ux/design-system-react.svg?token=BMXxPFKR5GZuYsqAFsEf&branch=master)](https://travis-ci.com/salesforce-ux/design-system-react)
55

66
## Overview
7-
Please visit [Design System React](https://react.lightningdesignsystem.com/) for documentation and examples of using the Design System React components. The documentation site has a [Getting Started Guide](https://react.lightningdesignsystem.com/getting-started) and a [FAQ](https://react.lightningdesignsystem.com/faq) page.
7+
Welcome to the project! :wave: This is an internal open source project and contributions are expected from production teams consuming this library. There is only one engineer 100%-aligned to this project at this moment. All other contributors are on production teams that ship end-product with releases dates, too.
8+
9+
Please visit [Design System React](https://react.lightningdesignsystem.com/) for documentation and examples of using the Design System React components. The documentation site has a [Getting Started Guide](https://react.lightningdesignsystem.com/getting-started) and a [FAQ](https://react.lightningdesignsystem.com/faq) page. If you are new to this project or React, please review the [Concepts and Best Practices](https://react.lightningdesignsystem.com/contributing#concepts-and-best-practices) section of the [Contributing](https://react.lightningdesignsystem.com/contributing) page. It will help you with the approach of this library and offer some suggestions for your own components.
810

911
The Design System React library is the [React](https://facebook.github.io/react/) implementation of the [Lightning Design System](https://www.lightningdesignsystem.com/). Each Design System React component is a specific variant of a component from Lightning Design System. For example, `SLDSMenuDropdown` represents [Lightning Design System Menu > Dropdown](http://www.lightningdesignsystem.com/components/menus/#dropdown),
1012
and `SLDSLookup` represents [Lightning Design System Lookup > Base](http://www.lightningdesignsystem.com/components/lookups/#base).
@@ -38,7 +40,7 @@ Note: `design-system-react` is optimized for React 0.14.x and uses Lightning Des
3840

3941
### New to React?
4042

41-
Take a look at our [recommended reading list](https://react.lightningdesignsystem.com/resources) on the documentation site and level up on your knowledge. The reading list also includes helpful articles on Redux, Webpack, ES6, and structuring your app.
43+
Take a look at our [recommended reading list](https://react.lightningdesignsystem.com/resources) on the documentation site and level up on your knowledge. The reading list also includes helpful articles on Redux, Webpack, ES6, and structuring your app. The [Concepts and Best Practices](https://react.lightningdesignsystem.com/contributing#concepts-and-best-practices) section of the [Contributing](https://react.lightningdesignsystem.com/contributing) page will help you understand the approach of this library and offer some suggestions for your own components, too.
4244

4345
### NPM
4446

@@ -80,7 +82,7 @@ Read our [FAQ](https://react.lightningdesignsystem.com/faq) on the documentation
8082

8183
## Contributing to the code base
8284

83-
Please read the [CONTRIBUTING.md](CONTRIBUTING.md) first.
85+
Please read the [CONTRIBUTING.md](CONTRIBUTING.md) first. If you'd like to meet or discuss this project, please contact @interactivellama, so you can be invited to the Slack channel and/or the weekly Cross-Cloud Office Hours.
8486

8587
## Licenses
8688

components/menu-dropdown/menu-dropdown.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ const DropdownNubbinPositions = [
7878
];
7979

8080
/**
81-
* The MenuDropdown component is a variant of the Lightning Design System Menu component.
81+
* The MenuDropdown component is a variant of the Lightning Design System Menu component. This component
82+
* may require a polyfill such as [classList](https://github.com/yola/classlist-polyfill) due to
83+
* [react-onclickoutside](https://github.com/Pomax/react-onclickoutside) if Internet Explorer 11
84+
* support is needed.
8285
*/
8386
const MenuDropdown = React.createClass({
8487
// ### Display Name

components/menu-list/list-item.jsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,18 +147,23 @@ const ListItem = React.createClass({
147147
{
148148
'slds-has-divider--top-space': this.props.divider === 'top',
149149
'slds-has-divider--bottom-space': this.props.divider === 'bottom'
150-
}
150+
},
151+
this.props.className
151152
)}
152153
onMouseDown={this.handleMouseDown}
153154
role="separator"
154155
>
155-
<span className={classNames('slds-text-title--caps', this.props.className)}>{this.props.label}</span>
156+
<span className="slds-text-title--caps">{this.props.label}</span>
156157
</li>
157158
);
158159
}
159160
case 'divider': {
160161
return (
161-
<li className="slds-has-divider" onMouseDown={this.handleMouseDown} role="separator"></li>
162+
<li
163+
className={classNames('slds-has-divider', this.props.className)}
164+
onMouseDown={this.handleMouseDown}
165+
role="separator"
166+
></li>
162167
);
163168
}
164169
case 'link':

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;

0 commit comments

Comments
 (0)