Migrate from a handrolled interface for building examples to using React Components directly. (#10452)

Backports PR #10259

**Commit 1:**
Migrate from a handrolled interface for building examples to using React Components directly.

* Original sha: e662aaa086
* Authored by CJ Cenizal <cj@cenizal.com> on 2017-02-08T23:39:24Z

**Commit 2:**
Wrap components with containers instead of passing down state and actions via context.

* Original sha: eb5d684979
* Authored by CJ Cenizal <cj@cenizal.com> on 2017-02-10T02:09:21Z

**Commit 3:**
Simplify containers.

* Original sha: 5b155022c9
* Authored by CJ Cenizal <cj@cenizal.com> on 2017-02-17T22:09:52Z
This commit is contained in:
jasper 2017-02-17 19:15:44 -05:00 committed by CJ Cenizal
parent 9b8e40111d
commit fa68183be0
58 changed files with 1957 additions and 930 deletions

View file

@ -5,9 +5,10 @@ export default keyMirror({
// Source code viewer actions // Source code viewer actions
OPEN_CODE_VIEWER: null, OPEN_CODE_VIEWER: null,
UPDATE_CODE_VIEWER: null,
CLOSE_CODE_VIEWER: null, CLOSE_CODE_VIEWER: null,
REGISTER_CODE: null,
UNREGISTER_CODE: null, // Example nav actions
REGISTER_SECTION: null,
UNREGISTER_SECTION: null,
}); });

View file

@ -1,30 +0,0 @@
import ActionTypes from '../action_types';
export default {
openCodeViewer: slug => ({
type: ActionTypes.OPEN_CODE_VIEWER,
slug,
}),
updateCodeViewer: slug => ({
type: ActionTypes.UPDATE_CODE_VIEWER,
slug,
}),
closeCodeViewer: () => ({
type: ActionTypes.CLOSE_CODE_VIEWER,
}),
registerCode: code => ({
type: ActionTypes.REGISTER_CODE,
code,
}),
unregisterCode: code => ({
type: ActionTypes.UNREGISTER_CODE,
code
}),
};

View file

@ -0,0 +1,10 @@
import ActionTypes from './action_types';
export const openCodeViewer = source => ({
type: ActionTypes.OPEN_CODE_VIEWER,
source,
});
export const closeCodeViewer = () => ({
type: ActionTypes.CLOSE_CODE_VIEWER,
});

View file

@ -0,0 +1,12 @@
import ActionTypes from './action_types';
export const registerSection = (id, name) => ({
type: ActionTypes.REGISTER_SECTION,
id,
name,
});
export const unregisterSection = id => ({
type: ActionTypes.UNREGISTER_SECTION,
id,
});

View file

@ -1,4 +1,9 @@
export {
openCodeViewer,
closeCodeViewer,
} from './code_viewer_actions';
export { export {
default as CodeViewerActions, registerSection,
} from './code_viewer/code_viewer_actions'; unregisterSection,
} from './example_nav_actions';

View file

@ -0,0 +1,6 @@
.guideCode {
padding: 2px 4px;
font-family: 'Ubuntu Mono', monospace;
background-color: #e8e8e8;
color: #565656;
}

View file

@ -0,0 +1,5 @@
import React from 'react';
export const GuideCode = props => (
<code className="guideCode">{props.children}</code>
);

View file

@ -1,10 +1,3 @@
.guideCode {
padding: 2px 4px;
font-family: 'Ubuntu Mono', monospace;
background-color: #e8e8e8;
color: #565656;
}
.guideCodeViewer { .guideCodeViewer {
position: fixed; position: fixed;
top: $guideNavHeight; top: $guideNavHeight;

View file

@ -1,4 +1,3 @@
import React, { import React, {
Component, Component,
PropTypes, PropTypes,
@ -7,8 +6,7 @@ import React, {
import classNames from 'classnames'; import classNames from 'classnames';
import hljs from 'highlight.js'; import hljs from 'highlight.js';
export default class GuideCodeViewer extends Component { export class GuideCodeViewer extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
} }
@ -23,19 +21,26 @@ export default class GuideCodeViewer extends Component {
} }
} }
renderSection(title, content, codeClass) { renderSection(type, code) {
if (content) { const typeToCodeClassMap = {
JavaScript: 'javascript',
HTML: 'html',
};
const codeClass = typeToCodeClassMap[type];
if (code) {
return ( return (
<div className="guideCodeViewer__section"> <div className="guideCodeViewer__section" key={type}>
<div className="guideCodeViewer__title"> <div className="guideCodeViewer__title">
{title} {type}
</div> </div>
<pre className="guideCodeViewer__content"> <pre className="guideCodeViewer__content">
<code <code
ref={codeClass} ref={codeClass}
className={codeClass} className={codeClass}
> >
{content} {code}
</code> </code>
</pre> </pre>
</div> </div>
@ -48,6 +53,10 @@ export default class GuideCodeViewer extends Component {
'is-code-viewer-open': this.props.isOpen, 'is-code-viewer-open': this.props.isOpen,
}); });
const codeSections = this.props.source.map(sourceObject => (
this.renderSection(sourceObject.type, sourceObject.code)
));
return ( return (
<div className={classes}> <div className={classes}>
<div className="guideCodeViewer__header"> <div className="guideCodeViewer__header">
@ -59,18 +68,15 @@ export default class GuideCodeViewer extends Component {
onClick={this.props.onClose} onClick={this.props.onClose}
/> />
{this.renderSection('HTML', this.props.html, 'html')} {codeSections}
{this.renderSection('JavaScript', this.props.js, 'javascript')}
</div> </div>
); );
} }
} }
GuideCodeViewer.propTypes = { GuideCodeViewer.propTypes = {
isOpen: PropTypes.bool, isOpen: PropTypes.bool,
onClose: PropTypes.func, onClose: PropTypes.func,
title: PropTypes.string, title: PropTypes.string,
html: PropTypes.string, source: PropTypes.array,
js: PropTypes.string,
}; };

View file

@ -0,0 +1,11 @@
$guideVerticalRhythm: 20px;
@import "guide_code/guide_code";
@import "guide_code_viewer/guide_code_viewer";
@import "guide_demo/guide_demo";
@import "guide_link/guide_link";
@import "guide_nav/guide_nav";
@import "guide_page/guide_page";
@import "guide_page_side_nav/guide_page_side_nav";
@import "guide_section/guide_section";
@import "guide_text/guide_text";

View file

@ -0,0 +1,3 @@
.guideDemo {
margin-top: $guideVerticalRhythm;
}

View file

@ -0,0 +1,60 @@
import React, {
Component,
PropTypes,
} from 'react';
import classNames from 'classnames';
export class GuideDemo extends Component {
componentDidMount() {
this.update();
}
componentDidUpdate() {
this.update();
}
update() {
// Inject HTML
this.content.innerHTML = this.props.html;
// Inject JS
const js = document.createElement('script');
js.type = 'text/javascript';
js.innerHTML = this.props.js;
this.content.appendChild(js);
// Inject CSS
const css = document.createElement('style');
css.innerHTML = this.props.css;
this.content.appendChild(css);
}
render() {
const classes = classNames('guideDemo', {
'theme-dark': this.props.isDarkTheme,
});
return (
<div className={classes}>
<div
ref={c => (this.content = c)}
/>
</div>
);
}
}
GuideDemo.propTypes = {
js: PropTypes.string.isRequired,
html: PropTypes.string.isRequired,
css: PropTypes.string.isRequired,
isDarkTheme: PropTypes.bool.isRequired,
};
GuideDemo.defaultProps = {
js: '',
html: '',
css: '',
isDarkTheme: false,
};

View file

@ -1,3 +0,0 @@
.guideExample {
}

View file

@ -1,78 +0,0 @@
import React, {
Component,
PropTypes,
} from 'react';
import {
Slugify,
} from '../../services';
import {
GuidePage,
GuidePageSection,
} from '../';
export default class GuideExample extends Component {
constructor(props, sections) {
super(props);
this.sections = sections.map(section => Object.assign({}, section, {
slug: Slugify.one(section.title),
}));
}
componentWillMount() {
this.sections.forEach(section => {
this.context.registerCode(section);
});
}
componentWillUnmount() {
this.sections.forEach(section => {
this.context.unregisterCode(section);
});
}
renderSections() {
return this.sections.map((section, index) => (
<GuidePageSection
key={index}
title={section.title}
slug={section.slug}
html={section.html}
js={section.js}
hasDarkTheme={section.hasDarkTheme}
>
{section.description}
</GuidePageSection>
));
}
render() {
return (
<GuidePage
title={this.props.route.name}
>
{this.renderSections()}
</GuidePage>
);
}
}
GuideExample.contextTypes = {
registerCode: PropTypes.func,
unregisterCode: PropTypes.func,
};
GuideExample.propTypes = {
route: PropTypes.object.isRequired,
sections: PropTypes.arrayOf(React.PropTypes.shape({
title: React.PropTypes.string.isRequired,
description: React.PropTypes.any,
html: React.PropTypes.string.isRequired,
js: React.PropTypes.string,
hasDarkTheme: React.PropTypes.bool,
})),
};

View file

@ -0,0 +1,11 @@
import React from 'react';
export const GuideLink = props => (
<a
href={props.href}
target={props.target}
className="guideLink"
>
{props.children}
</a>
);

View file

@ -1,4 +1,3 @@
import React, { import React, {
PropTypes, PropTypes,
} from 'react'; } from 'react';
@ -9,7 +8,7 @@ import {
import classNames from 'classnames'; import classNames from 'classnames';
const GuideNav = props => { export const GuideNav = props => {
const classes = classNames('guideNav', { const classes = classNames('guideNav', {
'is-guide-nav-open': props.isNavOpen, 'is-guide-nav-open': props.isNavOpen,
}); });
@ -64,4 +63,3 @@ GuideNav.propTypes = {
items: PropTypes.array, items: PropTypes.array,
}; };
export default GuideNav;

View file

@ -1,4 +1,3 @@
import React, { import React, {
Component, Component,
PropTypes, PropTypes,
@ -13,34 +12,30 @@ import {
GuidePageSideNavItem, GuidePageSideNavItem,
} from '../'; } from '../';
export default class GuidePage extends Component { export class GuidePage extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.onClickLink = this.onClickLink.bind(this); this.onClickLink = this.onClickLink.bind(this);
} }
onClickLink(slug) { onClickLink(id) {
// Scroll to element. // Scroll to element.
$('html, body').animate({ $('html, body').animate({
scrollTop: $(`#${slug}`).offset().top - 100 scrollTop: $(`#${id}`).offset().top - 100
}, 250); }, 250);
// Load in code viewer.
this.context.updateCodeViewer(slug);
} }
renderSideNavMenu() { renderSideNavMenu() {
// Traverse children and build side nav from it. // Traverse sections and build side nav from it.
return this.props.children.map((section, index) => { return this.props.sections.map((section, index) => {
return ( return (
<GuidePageSideNavItem <GuidePageSideNavItem
key={index} key={index}
slug={Slugify.one(section.props.title)} id={section.id}
onClick={this.onClickLink} onClick={this.onClickLink}
> >
{section.props.title} {section.name}
</GuidePageSideNavItem> </GuidePageSideNavItem>
); );
}); });
@ -59,14 +54,10 @@ export default class GuidePage extends Component {
</div> </div>
); );
} }
} }
GuidePage.contextTypes = {
updateCodeViewer: PropTypes.func,
};
GuidePage.propTypes = { GuidePage.propTypes = {
children: PropTypes.any, children: PropTypes.any,
title: PropTypes.string, title: PropTypes.string,
sections: PropTypes.array,
}; };

View file

@ -0,0 +1,9 @@
import { connect } from 'react-redux';
import { getSections } from '../../store';
import { GuidePage } from './guide_page.jsx';
const mapStateToProps = state => ({
sections: getSections(state),
});
export const GuidePageContainer = connect(mapStateToProps)(GuidePage);

View file

@ -1,139 +0,0 @@
import React, {
Component,
PropTypes,
} from 'react';
import classNames from 'classnames';
import {
JsInjector,
} from '../../services';
export default class GuidePageSection extends Component {
constructor(props) {
super(props);
this.onClickSource = this.onClickSource.bind(this);
}
componentDidMount() {
// NOTE: This will cause a race condition if a GuidePage adds and removes
// GuidePageSection instances during its lifetime (e.g. if a user is allowed
// to click "add" and "delete" buttons to add and remove GuidePageSections).
//
// In such a race condition, we could end up with GuidePageSections with
// identical id values.
//
// As long as all GuidePageSection instances are added when a GuidePage
// is instantiated, and then they're all removed when a GuidePage is
// removed, we won't encounter this race condition.
if (this.props.js) {
this.scriptId = `${GuidePageSection.SCRIPT_ID}${GuidePageSection.count}`;
GuidePageSection.count++;
// JS injection must occur _after_ the component has been mounted, so
// the component DOM is available for the JS to manipulate.
JsInjector.inject(this.props.js, this.scriptId);
}
function trimChildren(node) {
if (node.children.length > 0) {
[...node.children].forEach(trimChildren);
return;
}
node.textContent = node.textContent.trim();
}
trimChildren(this.refs.html);
if (this.refs.htmlDarkTheme) {
trimChildren(this.refs.htmlDarkTheme);
}
}
componentWillUnmount() {
JsInjector.remove(this.scriptId);
GuidePageSection.count--;
}
onClickSource() {
this.context.openCodeViewer(this.props.slug);
}
render() {
const exampleClasses = classNames('guidePageSection__example', {
'guidePageSection__example--standalone': !this.props.children,
});
let description;
if (this.props.children) {
description = (
<div className="guidePageSection__description">
{this.props.children}
</div>
);
}
let darkThemeExample;
if (this.props.hasDarkTheme) {
darkThemeExample = (
<div
ref="htmlDarkTheme"
className={`${exampleClasses} theme-dark`}
dangerouslySetInnerHTML={{ __html: this.props.html }}
/>
);
} else {
darkThemeExample = (
<div className="guideWarning">This component is missing Dark Theme variations.</div>
);
}
return (
<div
id={this.props.slug}
className="guidePageSection"
>
<div className="guidePageSection__header">
<div className="guidePageSection__title">
{this.props.title}
</div>
<div
className="guidePageSection__sourceButton fa fa-code"
onClick={this.onClickSource}
/>
</div>
{description}
<div
ref="html"
className={exampleClasses}
dangerouslySetInnerHTML={{ __html: this.props.html }}
/>
{darkThemeExample}
</div>
);
}
}
GuidePageSection.count = 0;
GuidePageSection.SCRIPT_ID = 'EXAMPLE_SCRIPT';
GuidePageSection.contextTypes = {
openCodeViewer: PropTypes.func,
};
GuidePageSection.propTypes = {
title: PropTypes.string,
slug: PropTypes.string,
html: PropTypes.string,
js: PropTypes.string,
children: PropTypes.any,
hasDarkTheme: PropTypes.bool,
};

View file

@ -1,10 +1,9 @@
import React, { import React, {
Component, Component,
PropTypes, PropTypes,
} from 'react'; } from 'react';
export default class GuidePageSideNav extends Component { export class GuidePageSideNav extends Component {
constructor(props) { constructor(props) {
super(props); super(props);

View file

@ -1,10 +1,9 @@
import React, { import React, {
Component, Component,
PropTypes, PropTypes,
} from 'react'; } from 'react';
export default class GuidePageSideNavItem extends Component { export class GuidePageSideNavItem extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -13,7 +12,7 @@ export default class GuidePageSideNavItem extends Component {
} }
onClick() { onClick() {
this.props.onClick(this.props.slug); this.props.onClick(this.props.id);
} }
render() { render() {
@ -32,7 +31,7 @@ export default class GuidePageSideNavItem extends Component {
} }
GuidePageSideNavItem.propTypes = { GuidePageSideNavItem.propTypes = {
slug: PropTypes.string, id: PropTypes.string,
children: PropTypes.any, children: PropTypes.any,
onClick: PropTypes.func, onClick: PropTypes.func,
}; };

View file

@ -1,11 +1,11 @@
@import "../../variables"; @import "../../variables";
.guidePageSection { .guideSection {
margin-bottom: 40px; margin-bottom: 40px;
} }
.guidePageSection__header { .guideSection__header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
@ -14,12 +14,12 @@
border-bottom: 1px solid #d6d6d6; border-bottom: 1px solid #d6d6d6;
} }
.guidePageSection__title { .guideSection__title {
font-size: 18px; font-size: 18px;
font-weight: 700; font-weight: 700;
} }
.guidePageSection__sourceButton { .guideSection__sourceButton {
line-height: 10px; line-height: 10px;
padding: 4px 10px; padding: 4px 10px;
background-color: #19a8e0; background-color: #19a8e0;
@ -39,18 +39,3 @@
inset 0 2px 8px rgba(black, 0.2); inset 0 2px 8px rgba(black, 0.2);
} }
} }
.guidePageSection__description {
font-size: 14px;
line-height: 21px;
}
.guidePageSection__example {
& + & {
margin-top: 20px;
}
}
.guidePageSection__example--standalone {
margin-top: 10px;
}

View file

@ -0,0 +1,59 @@
import React, {
Component,
PropTypes,
} from 'react';
import Slugify from '../../services/string/slugify';
export class GuideSection extends Component {
constructor(props) {
super(props);
this.onClickSource = this.onClickSource.bind(this);
}
getId() {
return Slugify.one(this.props.title);
}
onClickSource() {
this.props.openCodeViewer(this.props.source);
}
componentWillMount() {
this.props.registerSection(this.getId(), this.props.title);
}
componentWillUnmount() {
this.props.unregisterSection(this.getId());
}
render() {
return (
<div
id={this.getId()}
className="guideSection"
>
<div className="guideSection__header">
<div className="guideSection__title">
{this.props.title}
</div>
<div
className="guideSection__sourceButton fa fa-code"
onClick={this.onClickSource}
/>
</div>
{this.props.children}
</div>
);
}
}
GuideSection.propTypes = {
title: PropTypes.string,
source: PropTypes.array,
children: PropTypes.any,
openCodeViewer: PropTypes.func,
registerSection: PropTypes.func,
unregisterSection: PropTypes.func,
};

View file

@ -0,0 +1,17 @@
import { connect } from 'react-redux';
import { GuideSection } from './guide_section.jsx';
import {
openCodeViewer,
registerSection,
unregisterSection,
} from '../../actions';
export const GuideSectionContainer = connect(
null,
{
openCodeViewer,
registerSection,
unregisterSection,
},
)(GuideSection);

View file

@ -0,0 +1,4 @@
export const GuideSectionTypes = {
JS: 'JavaScript',
HTML: 'HTML',
};

View file

@ -0,0 +1,5 @@
.guideText {
font-size: 14px;
line-height: 21px;
margin-top: $guideVerticalRhythm;
}

View file

@ -0,0 +1,5 @@
import React from 'react';
export const GuideText = props => (
<div className="guideText">{props.children}</div>
);

View file

@ -1,21 +1,11 @@
export { GuideCode } from './guide_code/guide_code.jsx';
export * from './guide_code_viewer/guide_code_viewer.jsx'; export { GuideCodeViewer } from './guide_code_viewer/guide_code_viewer.jsx';
export { default as GuideCodeViewer } from './guide_code_viewer/guide_code_viewer.jsx'; export { GuideDemo } from './guide_demo/guide_demo.jsx';
export { GuideLink } from './guide_link/guide_link.jsx';
export * from './guide_example/guide_example.jsx'; export { GuideNav } from './guide_nav/guide_nav.jsx';
export { default as GuideExample } from './guide_example/guide_example.jsx'; export { GuidePageContainer as GuidePage } from './guide_page/guide_page_container';
export { GuidePageSideNav } from './guide_page_side_nav/guide_page_side_nav.jsx';
export * from './guide_nav/guide_nav.jsx'; export { GuidePageSideNavItem } from './guide_page_side_nav/guide_page_side_nav_item.jsx';
export { default as GuideNav } from './guide_nav/guide_nav.jsx'; export { GuideSectionContainer as GuideSection } from './guide_section/guide_section_container';
export { GuideSectionTypes } from './guide_section/guide_section_types';
export * from './guide_page/guide_page.jsx'; export { GuideText } from './guide_text/guide_text.jsx';
export { default as GuidePage } from './guide_page/guide_page.jsx';
export * from './guide_page_section/guide_page_section.jsx';
export { default as GuidePageSection } from './guide_page_section/guide_page_section.jsx';
export * from './guide_page_side_nav/guide_page_side_nav.jsx';
export { default as GuidePageSideNav } from './guide_page_side_nav/guide_page_side_nav.jsx';
export * from './guide_page_side_nav/guide_page_side_nav_item.jsx';
export { default as GuidePageSideNavItem } from './guide_page_side_nav/guide_page_side_nav_item.jsx';

View file

@ -1,10 +1,6 @@
@import "../../dist/ui_framework.css"; @import "../../dist/ui_framework.css";
@import "./views/app"; @import "./views/app";
@import "./components/guide_code_viewer/guide_code_viewer"; @import "./components/guide_components";
@import "./components/guide_nav/guide_nav";
@import "./components/guide_page/guide_page";
@import "./components/guide_page_section/guide_page_section";
@import "./components/guide_page_side_nav/guide_page_side_nav";
* { * {
box-sizing: border-box; box-sizing: border-box;

View file

@ -1,4 +1,3 @@
import Slugify from '../string/slugify'; import Slugify from '../string/slugify';
import ActionItemExample import ActionItemExample

View file

@ -11,6 +11,7 @@ import {
} from 'react-router-redux'; } from 'react-router-redux';
import codeViewerReducer from './reducers/code_viewer_reducer'; import codeViewerReducer from './reducers/code_viewer_reducer';
import sectionsReducer from './reducers/sections_reducer';
/** /**
* @param {Object} initialState An object defining the application's initial * @param {Object} initialState An object defining the application's initial
@ -21,6 +22,7 @@ export default function configureStore(initialState) {
return { return {
routing: routerReducer(state.routing, action), routing: routerReducer(state.routing, action),
codeViewer: codeViewerReducer(state.codeViewer, action), codeViewer: codeViewerReducer(state.codeViewer, action),
sections: sectionsReducer(state.sections, action),
}; };
} }

View file

@ -0,0 +1,11 @@
export function getIsCodeViewerOpen(state) {
return state.codeViewer.isOpen
}
export function getSections(state) {
return state.sections.sections;
}
export function getSource(state) {
return state.codeViewer.source;
}

View file

@ -1,35 +1,34 @@
import ActionTypes from '../../actions/action_types'; import ActionTypes from '../../actions/action_types';
const defaultState = { const defaultState = {
isOpen: false, isOpen: false,
codesBySlug: {}, codesBySlug: {},
code: undefined, source: undefined,
}; };
export default function codeViewerReducer(state = defaultState, action) { export default function codeViewerReducer(state = defaultState, action) {
switch (action.type) { switch (action.type) {
case ActionTypes.OPEN_CODE_VIEWER: { case ActionTypes.OPEN_CODE_VIEWER: {
const newCode = state.codesBySlug[action.slug]; const source = action.source;
if (state.code === newCode) { if (state.code === source) {
// If we are opening the existing code, then close the viewer. // If we are opening the existing code, then close the viewer.
return Object.assign({}, state, { return Object.assign({}, state, {
isOpen: false, isOpen: false,
code: undefined, source: undefined,
}); });
} }
return Object.assign({}, state, { return Object.assign({}, state, {
isOpen: true, isOpen: true,
code: newCode, source: source,
}); });
} }
case ActionTypes.UPDATE_CODE_VIEWER: { case ActionTypes.UPDATE_CODE_VIEWER: {
if (state.isOpen) { if (state.isOpen) {
return Object.assign({}, state, { return Object.assign({}, state, {
code: state.codesBySlug[action.slug], source: state.codesBySlug[action.slug],
}); });
} }
return state; return state;
@ -38,7 +37,7 @@ export default function codeViewerReducer(state = defaultState, action) {
case ActionTypes.CLOSE_CODE_VIEWER: { case ActionTypes.CLOSE_CODE_VIEWER: {
return Object.assign({}, state, { return Object.assign({}, state, {
isOpen: false, isOpen: false,
code: undefined, source: undefined,
}); });
} }

View file

@ -0,0 +1,36 @@
import ActionTypes from '../../actions/action_types';
const defaultState = {
sections: [],
};
export default function sectionsReducer(state = defaultState, action) {
switch (action.type) {
case ActionTypes.REGISTER_SECTION: {
const sections = state.sections.slice();
sections.push({
id: action.id,
name: action.name,
});
return Object.assign({}, state, {
sections,
});
}
case ActionTypes.UNREGISTER_SECTION: {
const sections = state.sections.slice();
const index = sections.findIndex(section => section.id === action.id);
sections.splice(index, 1);
return Object.assign({}, state, {
sections,
});
}
default:
break;
}
return state;
}

View file

@ -1,15 +1,53 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideCode,
} from '../../services'; GuideDemo,
GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const actionItemHtml = require('./action_item.html');
title: 'ActionItem', const inMenuHtml = require('./action_items_in_menu.html');
html: require('./action_item.html'),
hasDarkTheme: false, export default props => (
}, { <GuidePage title={props.route.name}>
title: 'ActionItems in Menu', <GuideSection
html: require('./action_items_in_menu.html'), title="ActionItem"
hasDarkTheme: false, source={[{
}]); type: GuideSectionTypes.HTML,
code: actionItemHtml,
}]}
>
<GuideText>
Events can represent updates, logs, notifications, and status changes.
</GuideText>
<GuideDemo
html={actionItemHtml}
/>
</GuideSection>
<GuideSection
title="ActionItems in Menu"
source={[{
type: GuideSectionTypes.HTML,
code: inMenuHtml,
}]}
>
<GuideText>
You&rsquo;ll typically want to present them within a Menu.
</GuideText>
<GuideDemo
html={inMenuHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,27 +1,34 @@
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import AppView from './app_view.jsx';
import { import {
CodeViewerActions, getIsCodeViewerOpen,
getSections,
getSource,
} from '../store';
import { AppView } from './app_view.jsx';
import {
openCodeViewer,
closeCodeViewer,
registerSection,
unregisterSection,
} from '../actions'; } from '../actions';
function mapStateToProps(state, ownProps) { function mapStateToProps(state, ownProps) {
return { return {
routes: ownProps.routes, routes: ownProps.routes,
isCodeViewerOpen: state.codeViewer.isOpen, isCodeViewerOpen: getIsCodeViewerOpen(state),
code: state.codeViewer.code, source: getSource(state),
sections: getSections(state),
}; };
} }
function mapDispatchToProps(dispatch) { function mapDispatchToProps(dispatch) {
const actions = { const actions = {
openCodeViewer: CodeViewerActions.openCodeViewer, openCodeViewer,
updateCodeViewer: CodeViewerActions.updateCodeViewer, closeCodeViewer,
closeCodeViewer: CodeViewerActions.closeCodeViewer, registerSection,
registerCode: CodeViewerActions.registerCode, unregisterSection,
unregisterCode: CodeViewerActions.unregisterCode,
}; };
return bindActionCreators(actions, dispatch); return bindActionCreators(actions, dispatch);

View file

@ -1,4 +1,3 @@
import React, { import React, {
Component, Component,
PropTypes, PropTypes,
@ -18,8 +17,7 @@ import {
// Inject version into header. // Inject version into header.
const pkg = require('json!../../../../package.json'); const pkg = require('json!../../../../package.json');
export default class AppView extends Component { export class AppView extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -32,15 +30,6 @@ export default class AppView extends Component {
this.onCloseCodeViewer = this.onCloseCodeViewer.bind(this); this.onCloseCodeViewer = this.onCloseCodeViewer.bind(this);
} }
getChildContext() {
return {
openCodeViewer: this.props.openCodeViewer,
updateCodeViewer: this.props.updateCodeViewer,
registerCode: this.props.registerCode,
unregisterCode: this.props.unregisterCode,
};
}
onClickNavItem() { onClickNavItem() {
this.setState({ this.setState({
isNavOpen: false, isNavOpen: false,
@ -79,35 +68,26 @@ export default class AppView extends Component {
<GuideCodeViewer <GuideCodeViewer
isOpen={this.props.isCodeViewerOpen} isOpen={this.props.isCodeViewerOpen}
onClose={this.onCloseCodeViewer} onClose={this.onCloseCodeViewer}
title={this.props.code.title} title={'No title'}
html={this.props.code.html} source={this.props.source}
js={this.props.code.js}
/> />
</div> </div>
); );
} }
} }
AppView.childContextTypes = {
openCodeViewer: PropTypes.func,
updateCodeViewer: PropTypes.func,
registerCode: PropTypes.func,
unregisterCode: PropTypes.func,
};
AppView.propTypes = { AppView.propTypes = {
children: PropTypes.any, children: PropTypes.any,
routes: PropTypes.array.isRequired, routes: PropTypes.array.isRequired,
openCodeViewer: PropTypes.func, openCodeViewer: PropTypes.func,
updateCodeViewer: PropTypes.func,
closeCodeViewer: PropTypes.func, closeCodeViewer: PropTypes.func,
registerCode: PropTypes.func,
unregisterCode: PropTypes.func,
isCodeViewerOpen: PropTypes.bool, isCodeViewerOpen: PropTypes.bool,
code: PropTypes.object, registerSection: PropTypes.func,
unregisterSection: PropTypes.func,
sections: PropTypes.array,
source: PropTypes.array,
}; };
AppView.defaultProps = { AppView.defaultProps = {
code: {}, source: [],
}; };

View file

@ -1,31 +1,78 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideCode,
} from '../../services'; GuideDemo,
GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const barHtml = require('./bar.html');
title: 'Bar', const oneSectionHtml = require('./bar_one_section.html');
description: ( const threeSectionsHtml = require('./bar_three_sections.html');
<div>
<p>Use the Bar to organize controls in a horizontal layout. This is especially useful for surfacing controls in the corners of a view.</p> export default props => (
<p><strong>Note:</strong> Instead of using this component with a Table, try using the ControlledTable, ToolBar, and ToolBarFooter components.</p> <GuidePage title={props.route.name}>
</div> <GuideSection
), title="Bar"
html: require('./bar.html'), source={[{
hasDarkTheme: false, type: GuideSectionTypes.HTML,
}, { code: barHtml,
title: 'One section', }]}
description: ( >
<p>A Bar with one section will align it to the right, by default. To align it to the left, just add another section and leave it empty, or don't use a Bar at all.</p> <GuideText>
), Use the Bar to organize controls in a horizontal layout. This is especially useful for
html: require('./bar_one_section.html'), surfacing controls in the corners of a view.
hasDarkTheme: false, </GuideText>
}, {
title: 'Three sections', <GuideText>
description: ( <strong>Note:</strong> Instead of using this component with a Table, try using the
<p>Technically the Bar can contain three or more sections, but there's no established use-case for this.</p> ControlledTable, ToolBar, and ToolBarFooter components.
), </GuideText>
html: require('./bar_three_sections.html'),
hasDarkTheme: false, <GuideDemo
}]); html={barHtml}
/>
</GuideSection>
<GuideSection
title="One section"
source={[{
type: GuideSectionTypes.HTML,
code: oneSectionHtml,
}]}
>
<GuideText>
A Bar with one section will align it to the right, by default. To align it to the left,
just add another section and leave it empty, or don't use a Bar at all.
</GuideText>
<GuideDemo
html={oneSectionHtml}
/>
</GuideSection>
<GuideSection
title="Three sections"
source={[{
type: GuideSectionTypes.HTML,
code: threeSectionsHtml,
}]}
>
<GuideText>
Technically the Bar can contain three or more sections, but there's no established use-case
for this.
</GuideText>
<GuideDemo
html={threeSectionsHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,70 +1,178 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const basicHtml = require('./button_basic.html');
title: 'Basic Button', const hollowHtml = require('./button_hollow.html');
description: ( const primaryHtml = require('./button_primary.html');
<p>Use the basic Button in most situations.</p> const dangerHtml = require('./button_danger.html');
), const withIconHtml = require('./button_with_icon.html');
html: require('./button_basic.html'), const groupHtml = require('./button_group.html');
hasDarkTheme: false, const groupUnitedHtml = require('./button_group_united.html');
}, { const inToolBarHtml = require('./buttons_in_tool_bar.html');
title: 'Hollow Button', const elementsHtml = require('./button_elements.html');
description: (
<p>Use the hollow Button when presenting a neutral action, e.g. a "Cancel" button.</p> export default props => (
), <GuidePage title={props.route.name}>
html: require('./button_hollow.html'), <GuideSection
hasDarkTheme: false, title="Basic Button"
}, { source={[{
title: 'Primary Button', type: GuideSectionTypes.HTML,
description: ( code: basicHtml,
<p>Use the primary Button to represent the most common action. Generally, there won't be a need to present more than one of these at a time.</p> }]}
), >
html: require('./button_primary.html'), <GuideText>
hasDarkTheme: false, Use the basic Button in most situations.
}, { </GuideText>
title: 'Danger Button',
description: ( <GuideDemo
<p>Danger Buttons represent irreversible, potentially regrettable actions.</p> html={basicHtml}
), />
html: require('./button_danger.html'), </GuideSection>
hasDarkTheme: false,
}, { <GuideSection
title: 'Button with icon', title="Hollow Button"
description: ( source={[{
<p>You can toss an icon into a Button, with or without text.</p> type: GuideSectionTypes.HTML,
), code: hollowHtml,
html: require('./button_with_icon.html'), }]}
hasDarkTheme: false, >
}, { <GuideText>
title: 'ButtonGroup', Use the hollow Button when presenting a neutral action, e.g. a "Cancel" button.
html: require('./button_group.html'), </GuideText>
hasDarkTheme: false,
}, { <GuideDemo
title: 'United ButtonGroup', html={hollowHtml}
description: ( />
<div> </GuideSection>
<p>Use the united version of the ButtonGroup to emphasize the close relationship within a set of Buttons, and differentiate them from Buttons outside of the set.</p>
<p>They support containing a single Button, so that Buttons can be dynamically added and removed.</p> <GuideSection
</div> title="Primary Button"
), source={[{
html: require('./button_group_united.html'), type: GuideSectionTypes.HTML,
hasDarkTheme: false, code: primaryHtml,
}, { }]}
title: 'In ToolBar', >
description: ( <GuideText>
<p>This example verifies that Buttons are legible against the ToolBar's background.</p> Use the primary Button to represent the most common action. Generally, there won't be a
), need to present more than one of these at a time.
html: require('./buttons_in_tool_bar.html'), </GuideText>
hasDarkTheme: false,
}, { <GuideDemo
title: 'Element variations', html={primaryHtml}
description: ( />
<p>You can create a Button using a button element, link, or input[type="submit"].</p> </GuideSection>
),
html: require('./button_elements.html'), <GuideSection
hasDarkTheme: false, title="Danger Button"
}]); source={[{
type: GuideSectionTypes.HTML,
code: dangerHtml,
}]}
>
<GuideText>
Danger Buttons represent irreversible, potentially regrettable actions.
</GuideText>
<GuideDemo
html={dangerHtml}
/>
</GuideSection>
<GuideSection
title="Button with icon"
source={[{
type: GuideSectionTypes.HTML,
code: withIconHtml,
}]}
>
<GuideText>
You can toss an icon into a Button, with or without text.
</GuideText>
<GuideDemo
html={withIconHtml}
/>
</GuideSection>
<GuideSection
title="ButtonGroup"
source={[{
type: GuideSectionTypes.HTML,
code: groupHtml,
}]}
>
<GuideText>
</GuideText>
<GuideDemo
html={groupHtml}
/>
</GuideSection>
<GuideSection
title="United ButtonGroup"
source={[{
type: GuideSectionTypes.HTML,
code: groupUnitedHtml,
}]}
>
<GuideText>
Use the united version of the ButtonGroup to emphasize the close relationship within a set
of Buttons, and differentiate them from Buttons outside of the set.
</GuideText>
<GuideText>
They support containing a single Button, so that Buttons can be dynamically added and
removed.
</GuideText>
<GuideDemo
html={groupUnitedHtml}
/>
</GuideSection>
<GuideSection
title="In ToolBar"
source={[{
type: GuideSectionTypes.HTML,
code: inToolBarHtml,
}]}
>
<GuideText>
This example verifies that Buttons are legible against the ToolBar's background.
</GuideText>
<GuideDemo
html={inToolBarHtml}
/>
</GuideSection>
<GuideSection
title="Element variations"
source={[{
type: GuideSectionTypes.HTML,
code: elementsHtml,
}]}
>
<GuideText>
You can create a Button using a button element, link, or input[type="submit"].
</GuideText>
<GuideDemo
html={elementsHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,21 +1,53 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideCode,
} from '../../services'; GuideDemo,
GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const eventHtml = require('./event.html');
title: 'Event', const eventMenuHtml = require('./event_menu.html');
description: (
<p>Events can represent updates, logs, notifications, and status changes.</p> export default props => (
), <GuidePage title={props.route.name}>
html: require('./event.html'), <GuideSection
hasDarkTheme: false, title="Event"
}, { source={[{
title: 'Event Menu', type: GuideSectionTypes.HTML,
description: ( code: eventHtml,
<p>You&rsquo;ll typically want to present them within a Menu.</p> }]}
), >
html: require('./event_menu.html'), <GuideText>
hasDarkTheme: false, Events can represent updates, logs, notifications, and status changes.
}]); </GuideText>
<GuideDemo
html={eventHtml}
/>
</GuideSection>
<GuideSection
title="Event Menu"
source={[{
type: GuideSectionTypes.HTML,
code: eventMenuHtml,
}]}
>
<GuideText>
You&rsquo;ll typically want to present them within a Menu.
</GuideText>
<GuideDemo
html={eventMenuHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,34 +1,100 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const textInputHtml = require('./text_input.html');
title: 'TextInput', const staticInputHtml = require('./static_input.html');
html: require('./text_input.html'), const textAreaHtml = require('./text_area.html');
hasDarkTheme: false, const textAreaNonResizableHtml = require('./text_area_non_resizable.html');
}, { const checkBoxHtml = require('./check_box.html');
title: 'StaticInput', const selectHtml = require('./select.html');
description: (
<p>Use StaticInput to display dynamic content in a form which the user isn&rsquo;t allowed to edit.</p> export default props => (
), <GuidePage title={props.route.name}>
html: require('./static_input.html'), <GuideSection
hasDarkTheme: false, title="TextInput"
}, { source={[{
title: 'TextArea', type: GuideSectionTypes.HTML,
html: require('./text_area.html'), code: textInputHtml,
hasDarkTheme: false, }]}
}, { >
title: 'TextArea, non-resizable', <GuideDemo
html: require('./text_area_non_resizable.html'), html={textInputHtml}
hasDarkTheme: false, />
}, { </GuideSection>
title: 'CheckBox',
html: require('./check_box.html'), <GuideSection
hasDarkTheme: false, title="StaticInput"
}, { source={[{
title: 'Select', type: GuideSectionTypes.HTML,
html: require('./select.html'), code: staticInputHtml,
hasDarkTheme: false, }]}
}]); >
<GuideText>
Use StaticInput to display dynamic content in a form which the user isn&rsquo;t allowed to edit.
</GuideText>
<GuideDemo
html={staticInputHtml}
/>
</GuideSection>
<GuideSection
title="TextArea"
source={[{
type: GuideSectionTypes.HTML,
code: textAreaHtml,
}]}
>
<GuideDemo
html={textAreaHtml}
/>
</GuideSection>
<GuideSection
title="TextArea, non-resizable"
source={[{
type: GuideSectionTypes.HTML,
code: textAreaNonResizableHtml,
}]}
>
<GuideDemo
html={textAreaNonResizableHtml}
/>
</GuideSection>
<GuideSection
title="CheckBox"
source={[{
type: GuideSectionTypes.HTML,
code: checkBoxHtml,
}]}
>
<GuideDemo
html={checkBoxHtml}
/>
</GuideSection>
<GuideSection
title="Select"
source={[{
type: GuideSectionTypes.HTML,
code: selectHtml,
}]}
>
<GuideDemo
html={selectHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,15 +1,44 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideCode,
} from '../../services'; GuideDemo,
GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
} from '../../components';
export default createExample([{ const headerBarHtml = require('./header_bar.html');
title: 'Header Bar', const twoSectionsHtml = require('./header_bar_two_sections.html');
html: require('./header_bar.html'),
hasDarkTheme: false, export default props => (
}, { <GuidePage title={props.route.name}>
title: 'Two sections', <GuideSection
html: require('./header_bar_two_sections.html'), title="Header Bar"
hasDarkTheme: false, source={[{
}]); type: GuideSectionTypes.HTML,
code: headerBarHtml,
}]}
>
<GuideDemo
html={headerBarHtml}
/>
</GuideSection>
<GuideSection
title="Two sections"
source={[{
type: GuideSectionTypes.HTML,
code: twoSectionsHtml,
}]}
>
<GuideDemo
html={twoSectionsHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,55 +1,142 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideCode,
} from '../../services'; GuideDemo,
GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const iconHtml = require('./icon.html');
title: 'Icon', const infoHtml = require('./icon_info.html');
description: ( const basicHtml = require('./icon_basic.html');
<p>Use the <code className="guideCode">icon</code> class instead of the <code className="guideCode">fa</code> class for FontAwesome icons. This will make it easier for us to migrate away from FontAwesome.</p> const successHtml = require('./icon_success.html');
), const warningHtml = require('./icon_warning.html');
html: require('./icon.html'), const errorHtml = require('./icon_error.html');
hasDarkTheme: false, const inactiveHtml = require('./icon_inactive.html');
}, {
title: 'Info', export default props => (
description: ( <GuidePage title={props.route.name}>
<p>Use this Icon to denote useful information.</p> <GuideSection
), title="Icon"
html: require('./icon_info.html'), source={[{
}, { type: GuideSectionTypes.HTML,
title: 'Basic', code: iconHtml,
description: ( }]}
<p>Use this Icon when you don't want to communicate any particular meaning with the icon's color.</p> >
), <GuideText>
html: require('./icon_basic.html'), Use the <GuideCode>icon</GuideCode> class instead of the <GuideCode>fa</GuideCode> class for
hasDarkTheme: false, FontAwesome icons. This will make it easier for us to migrate away from FontAwesome.
}, { </GuideText>
title: 'Success',
description: ( <GuideDemo
<p>Use this Icon to denote the successful completion of an action, e.g. filling out a form field correctly or a successful API request.</p> html={iconHtml}
), />
html: require('./icon_success.html'), </GuideSection>
hasDarkTheme: false,
}, { <GuideSection
title: 'Warning', title="Info"
description: ( source={[{
<p>Use this Icon to denote an irregularity or potential problems.</p> type: GuideSectionTypes.HTML,
), code: infoHtml,
html: require('./icon_warning.html'), }]}
hasDarkTheme: false, >
}, { <GuideText>
title: 'Error', Use this Icon to denote useful information.
description: ( </GuideText>
<p>Use this Icon to denote a failed attempt at an action, e.g. an invalid form field or an API error.</p>
), <GuideDemo
html: require('./icon_error.html'), html={infoHtml}
hasDarkTheme: false, />
}, { </GuideSection>
title: 'Inactive',
description: ( <GuideSection
<p>Use this Icon to denote a disabled, inactive, off, offline, or asleep status.</p> title="Basic"
), source={[{
html: require('./icon_inactive.html'), type: GuideSectionTypes.HTML,
hasDarkTheme: false, code: basicHtml,
}, ]); }]}
>
<GuideText>
Use this Icon when you don't want to communicate any particular meaning with the icon's
color.
</GuideText>
<GuideDemo
html={basicHtml}
/>
</GuideSection>
<GuideSection
title="Success"
source={[{
type: GuideSectionTypes.HTML,
code: successHtml,
}]}
>
<GuideText>
Use this Icon to denote the successful completion of an action, e.g. filling out a form
field correctly or a successful API request.
</GuideText>
<GuideDemo
html={successHtml}
/>
</GuideSection>
<GuideSection
title="Warning"
source={[{
type: GuideSectionTypes.HTML,
code: warningHtml,
}]}
>
<GuideText>
Use this Icon to denote an irregularity or potential problems.
</GuideText>
<GuideDemo
html={warningHtml}
/>
</GuideSection>
<GuideSection
title="Error"
source={[{
type: GuideSectionTypes.HTML,
code: errorHtml,
}]}
>
<GuideText>
Use this Icon to denote a failed attempt at an action, e.g. an invalid form field or an API
error.
</GuideText>
<GuideDemo
html={errorHtml}
/>
</GuideSection>
<GuideSection
title="Inactive"
source={[{
type: GuideSectionTypes.HTML,
code: inactiveHtml,
}]}
>
<GuideText>
Use this Icon to denote a disabled, inactive, off, offline, or asleep status.
</GuideText>
<GuideDemo
html={inactiveHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,35 +1,86 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const infoHtml = require('./info_panel_info.html');
title: 'Info', const successHtml = require('./info_panel_success.html');
description: ( const warningHtml = require('./info_panel_warning.html');
<p>Use this InfoPanel to generally inform the user.</p> const errorHtml = require('./info_panel_error.html');
),
html: require('./info_panel_info.html'), export default props => (
hasDarkTheme: false, <GuidePage title={props.route.name}>
}, { <GuideSection
title: 'Success', title="Info"
description: ( source={[{
<p>Use this InfoPanel to notify the user of an action successfully completing.</p> type: GuideSectionTypes.HTML,
), code: infoHtml,
html: require('./info_panel_success.html'), }]}
hasDarkTheme: false, >
}, { <GuideText>
title: 'Warning', Use this InfoPanel to generally inform the user.
description: ( </GuideText>
<p>Use this InfoPanel to warn the user against decisions they might regret.</p>
), <GuideDemo
html: require('./info_panel_warning.html'), html={infoHtml}
hasDarkTheme: false, />
}, { </GuideSection>
title: 'Error',
description: ( <GuideSection
<p>Use this InfoPanel to let the user know something went wrong.</p> title="Success"
), source={[{
html: require('./info_panel_error.html'), type: GuideSectionTypes.HTML,
hasDarkTheme: false, code: successHtml,
}]); }]}
>
<GuideText>
Use this InfoPanel to notify the user of an action successfully completing.
</GuideText>
<GuideDemo
html={successHtml}
/>
</GuideSection>
<GuideSection
title="Warning"
source={[{
type: GuideSectionTypes.HTML,
code: warningHtml,
}]}
>
<GuideText>
Use this InfoPanel to warn the user against decisions they might regret.
</GuideText>
<GuideDemo
html={warningHtml}
/>
</GuideSection>
<GuideSection
title="Error"
source={[{
type: GuideSectionTypes.HTML,
code: errorHtml,
}]}
>
<GuideText>
Use this InfoPanel to let the user know something went wrong.
</GuideText>
<GuideDemo
html={errorHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,11 +1,31 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const linkHtml = require('./link.html');
title: 'Link',
html: require('./link.html'), export default props => (
hasDarkTheme: false, <GuidePage title={props.route.name}>
}]); <GuideSection
title="Link"
source={[{
type: GuideSectionTypes.HTML,
code: linkHtml,
}]}
>
<GuideDemo
html={linkHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,63 +1,196 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideCode,
} from '../../services'; GuideDemo,
GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
const simpleHtml = require('./local_nav_simple.html');
const breadcrumbsHtml = require('./local_nav_breadcrumbs.html');
const searchHtml = require('./local_nav_search.html');
const searchErrorHtml = require('./local_nav_search_error.html');
const menuItemStatesHtml = require('./local_nav_menu_item_states.html');
const dropdownHtml = require('./local_nav_dropdown.html');
const dropdownPanelsHtml = require('./local_nav_dropdown_panels.html');
const tabsHtml = require('./local_nav_tabs.html');
export default props => (
<GuidePage title={props.route.name}>
<GuideSection
title="Simple"
source={[{
type: GuideSectionTypes.HTML,
code: simpleHtml,
}]}
>
<GuideText>
Here's a simple LocalNav with a Title in the top left corner and Menu in the top right.
</GuideText>
<GuideDemo
html={simpleHtml}
/>
<GuideDemo
html={simpleHtml}
isDarkTheme={true}
/>
</GuideSection>
<GuideSection
title="Breadcrumbs"
source={[{
type: GuideSectionTypes.HTML,
code: breadcrumbsHtml,
}]}
>
<GuideText>
You can replace the Title with Breadcrumbs.
</GuideText>
<GuideDemo
html={breadcrumbsHtml}
/>
<GuideDemo
html={breadcrumbsHtml}
isDarkTheme={true}
/>
</GuideSection>
<GuideSection
title="Search"
source={[{
type: GuideSectionTypes.HTML,
code: searchHtml,
}]}
>
<GuideText>
You can add a Search component for filtering results.
</GuideText>
<GuideDemo
html={searchHtml}
/>
<GuideDemo
html={searchHtml}
isDarkTheme={true}
/>
</GuideSection>
<GuideSection
title="Invalid Search"
source={[{
type: GuideSectionTypes.HTML,
code: searchErrorHtml,
}]}
>
<GuideDemo
html={searchErrorHtml}
/>
<GuideDemo
html={searchErrorHtml}
isDarkTheme={true}
/>
</GuideSection>
<GuideSection
title="Selected and disabled Menu Item states"
source={[{
type: GuideSectionTypes.HTML,
code: menuItemStatesHtml,
}]}
>
<GuideText>
When the user selects a Menu Item, additional content can be displayed inside of a Dropdown.
</GuideText>
<GuideText>
Menu Items can also be disabled, in which case they become non-interactive.
</GuideText>
<GuideDemo
html={menuItemStatesHtml}
/>
<GuideDemo
html={menuItemStatesHtml}
isDarkTheme={true}
/>
</GuideSection>
<GuideSection
title="Dropdown"
source={[{
type: GuideSectionTypes.HTML,
code: dropdownHtml,
}]}
>
<GuideText>
Selecting a Menu Item will commonly result in an open Dropdown.
</GuideText>
<GuideDemo
html={dropdownHtml}
/>
<GuideDemo
html={dropdownHtml}
isDarkTheme={true}
/>
</GuideSection>
<GuideSection
title="Dropdown panels"
source={[{
type: GuideSectionTypes.HTML,
code: dropdownPanelsHtml,
}]}
>
<GuideText>
You can split the Dropdown into side-by-side Panels.
</GuideText>
<GuideDemo
html={dropdownPanelsHtml}
/>
<GuideDemo
html={dropdownPanelsHtml}
isDarkTheme={true}
/>
</GuideSection>
<GuideSection
title="Tabs"
source={[{
type: GuideSectionTypes.HTML,
code: tabsHtml,
}]}
>
<GuideText>
You can display Tabs for navigating local content.
</GuideText>
<GuideDemo
html={tabsHtml}
/>
<GuideDemo
html={tabsHtml}
isDarkTheme={true}
/>
</GuideSection>
</GuidePage>
);
export default createExample([{
title: 'Simple',
description: (
<p>Here's a simple LocalNav with a Title in the top left corner and Menu in the top right.</p>
),
html: require('./local_nav_simple.html'),
hasDarkTheme: true,
}, {
title: 'Breadcrumbs',
description: (
<p>You can replace the Title with Breadcrumbs.</p>
),
html: require('./local_nav_breadcrumbs.html'),
hasDarkTheme: true,
}, {
title: 'Search',
description: (
<p>You can add a Search component for filtering results.</p>
),
html: require('./local_nav_search.html'),
hasDarkTheme: true,
}, {
title: 'Invalid Search',
html: require('./local_nav_search_error.html'),
hasDarkTheme: true,
}, {
title: 'Selected and disabled Menu Item states',
description: (
<div>
<p>When the user selects a Menu Item, additional content can be displayed inside of a Dropdown.</p>
<p>Menu Items can also be disabled, in which case they become non-interactive.</p>
</div>
),
html: require('./local_nav_menu_item_states.html'),
hasDarkTheme: true,
}, {
title: 'Dropdown',
description: (
<p>Selecting a Menu Item will commonly result in an open Dropdown.</p>
),
html: require('./local_nav_dropdown.html'),
hasDarkTheme: true,
}, {
title: 'Dropdown panels',
description: (
<p>You can split the Dropdown into side-by-side Panels.</p>
),
html: require('./local_nav_dropdown_panels.html'),
hasDarkTheme: true,
}, {
title: 'Tabs',
description: (
<p>You can display Tabs for navigating local content.</p>
),
html: require('./local_nav_tabs.html'),
hasDarkTheme: true,
}]);

View file

@ -1,15 +1,44 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideCode,
} from '../../services'; GuideDemo,
GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
} from '../../components';
export default createExample([{ const menuHtml = require('./menu.html');
title: 'Menu', const menuContainedHtml = require('./menu_contained.html');
html: require('./menu.html'),
hasDarkTheme: false, export default props => (
}, { <GuidePage title={props.route.name}>
title: 'Menu, contained', <GuideSection
html: require('./menu_contained.html'), title="Menu"
hasDarkTheme: false, source={[{
}]); type: GuideSectionTypes.HTML,
code: menuHtml,
}]}
>
<GuideDemo
html={menuHtml}
/>
</GuideSection>
<GuideSection
title="Menu, contained"
source={[{
type: GuideSectionTypes.HTML,
code: menuContainedHtml,
}]}
>
<GuideDemo
html={menuContainedHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,26 +1,74 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const basicHtml = require('./menu_button_basic.html');
title: 'Basic MenuButton', const dangerHtml = require('./menu_button_danger.html');
html: require('./menu_button_basic.html'), const withIconHtml = require('./menu_button_with_icon.html');
hasDarkTheme: false, const groupHtml = require('./menu_button_group.html');
}, {
title: 'Danger MenuButton', export default props => (
html: require('./menu_button_danger.html'), <GuidePage title={props.route.name}>
hasDarkTheme: false, <GuideSection
}, { title="Basic MenuButton"
title: 'MenuButton with Icon', source={[{
description: ( type: GuideSectionTypes.HTML,
<p>You can use a MenuButton with an Icon, with or without text.</p> code: basicHtml,
), }]}
html: require('./menu_button_with_icon.html'), >
hasDarkTheme: false, <GuideDemo
}, { html={basicHtml}
title: 'MenuButtonGroup', />
html: require('./menu_button_group.html'), </GuideSection>
hasDarkTheme: false,
}]); <GuideSection
title="Danger MenuButton"
source={[{
type: GuideSectionTypes.HTML,
code: dangerHtml,
}]}
>
<GuideDemo
html={dangerHtml}
/>
</GuideSection>
<GuideSection
title="MenuButton with Icon"
source={[{
type: GuideSectionTypes.HTML,
code: withIconHtml,
}]}
>
<GuideText>
You can use a MenuButton with an Icon, with or without text.
</GuideText>
<GuideDemo
html={withIconHtml}
/>
</GuideSection>
<GuideSection
title="MenuButtonGroup"
source={[{
type: GuideSectionTypes.HTML,
code: groupHtml,
}]}
>
<GuideDemo
html={groupHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,28 +1,70 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const microButtonHtml = require('./micro_button.html');
title: 'MicroButton', const microButtonGroupHtml = require('./micro_button_group.html');
description: ( const microButtonElementsHtml = require('./micro_button_elements.html');
<p>Use MicroButtons for inline actions inside of Table rows.</p>
), export default props => (
html: require('./micro_button.html'), <GuidePage title={props.route.name}>
hasDarkTheme: false, <GuideSection
}, { title="MicroButton"
title: 'MicroButtonGroup', source={[{
description: ( type: GuideSectionTypes.HTML,
<p>Use the MicroButtonGroup to emphasize the relationships between a set of MicroButtons, and differentiate them from MicroButtons outside of the set.</p> code: microButtonHtml,
), }]}
html: require('./micro_button_group.html'), >
hasDarkTheme: false, <GuideText>
}, { Use MicroButtons for inline actions inside of Table rows.
title: 'Element variations', </GuideText>
description: (
<p>You can create a MicroButton using a button element or a link.</p> <GuideDemo
), html={microButtonHtml}
html: require('./micro_button_elements.html'), />
hasDarkTheme: false, </GuideSection>
}]);
<GuideSection
title="MicroButtonGroup"
source={[{
type: GuideSectionTypes.HTML,
code: microButtonGroupHtml,
}]}
>
<GuideText>
se the MicroButtonGroup to emphasize the relationships between a set of MicroButtons, and
differentiate them from MicroButtons outside of the set.
</GuideText>
<GuideDemo
html={microButtonGroupHtml}
/>
</GuideSection>
<GuideSection
title="Element variations"
source={[{
type: GuideSectionTypes.HTML,
code: microButtonElementsHtml,
}]}
>
<GuideText>
You can create a MicroButton using a button element or a link.
</GuideText>
<GuideDemo
html={microButtonElementsHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,16 +1,49 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const modalHtml = require('./modal.html');
title: 'Modal', const modalOverlayHtml = require('./modal_overlay.html');
html: require('./modal.html'), const modalOverlayJs = require('raw!./modal_overlay.js');
hasDarkTheme: false,
}, { export default props => (
title: 'ModalOverlay', <GuidePage title={props.route.name}>
html: require('./modal_overlay.html'), <GuideSection
js: require('raw!./modal_overlay.js'), title="Modal"
hasDarkTheme: false, source={[{
}]); type: GuideSectionTypes.HTML,
code: modalHtml,
}]}
>
<GuideDemo
html={modalHtml}
/>
</GuideSection>
<GuideSection
title="ModalOverlay"
source={[{
type: GuideSectionTypes.HTML,
code: modalOverlayHtml,
}, {
type: GuideSectionTypes.JS,
code: modalOverlayJs,
}]}
>
<GuideDemo
html={modalOverlayHtml}
js={modalOverlayJs}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,18 +1,48 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const panelHtml = require('./panel.html');
title: 'Panel', const panelWithHeaderHtml = require('./panel_with_header.html');
html: require('./panel.html'),
hasDarkTheme: false, export default props => (
}, { <GuidePage title={props.route.name}>
title: 'Panel with PanelHeader', <GuideSection
description: ( title="Panel"
<p>The Panel requires a special class when used with a PanelHeader.</p> source={[{
), type: GuideSectionTypes.HTML,
html: require('./panel_with_header.html'), code: panelHtml,
hasDarkTheme: false, }]}
}]); >
<GuideDemo
html={panelHtml}
/>
</GuideSection>
<GuideSection
title="Panel with PanelHeader"
source={[{
type: GuideSectionTypes.HTML,
code: panelWithHeaderHtml,
}]}
>
<GuideText>
The Panel requires a special class when used with a PanelHeader.
</GuideText>
<GuideDemo
html={panelWithHeaderHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,23 +1,69 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
} from '../../components';
export default createExample([{ const infoHtml = require('./status_text_info.html');
title: 'Info', const successHtml = require('./status_text_success.html');
html: require('./status_text_info.html'), const warningHtml = require('./status_text_warning.html');
hasDarkTheme: false, const errorHtml = require('./status_text_error.html');
}, {
title: 'Success', export default props => (
html: require('./status_text_success.html'), <GuidePage title={props.route.name}>
hasDarkTheme: false, <GuideSection
}, { title="Info"
title: 'Warning', source={[{
html: require('./status_text_warning.html'), type: GuideSectionTypes.HTML,
hasDarkTheme: false, code: infoHtml,
}, { }]}
title: 'Error', >
html: require('./status_text_error.html'), <GuideDemo
hasDarkTheme: false, html={infoHtml}
}]); />
</GuideSection>
<GuideSection
title="Success"
source={[{
type: GuideSectionTypes.HTML,
code: successHtml,
}]}
>
<GuideDemo
html={successHtml}
/>
</GuideSection>
<GuideSection
title="Warning"
source={[{
type: GuideSectionTypes.HTML,
code: warningHtml,
}]}
>
<GuideDemo
html={warningHtml}
/>
</GuideSection>
<GuideSection
title="Error"
source={[{
type: GuideSectionTypes.HTML,
code: errorHtml,
}]}
>
<GuideDemo
html={errorHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,28 +1,87 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
} from '../../components';
export default createExample([{ const tableHtml = require('./table.html');
title: 'Table', const tableJs = require('raw!./table.js');
html: require('./table.html'), const controlledTableHtml = require('./controlled_table.html');
js: require('raw!./table.js'), const controlledTableWithLoadingItemsHtml = require('./controlled_table_loading_items.html');
hasDarkTheme: false, const controlledTableWithNoItemsHtml = require('./controlled_table_no_items.html');
}, { const controlledTableWithPromptForItemsHtml = require('./controlled_table_prompt_for_items.html');
title: 'ControlledTable',
html: require('./controlled_table.html'), export default props => (
hasDarkTheme: false, <GuidePage title={props.route.name}>
}, { <GuideSection
title: 'ControlledTable with LoadingItems', title="Table"
html: require('./controlled_table_loading_items.html'), source={[{
hasDarkTheme: false, type: GuideSectionTypes.HTML,
}, { code: tableHtml,
title: 'ControlledTable with NoItems', }, {
html: require('./controlled_table_no_items.html'), type: GuideSectionTypes.JS,
hasDarkTheme: false, code: tableJs,
}, { }]}
title: 'ControlledTable with PromptForItems', >
html: require('./controlled_table_prompt_for_items.html'), <GuideDemo
hasDarkTheme: false, html={tableHtml}
}]); js={tableJs}
/>
</GuideSection>
<GuideSection
title="ControlledTable"
source={[{
type: GuideSectionTypes.HTML,
code: controlledTableHtml,
}]}
>
<GuideDemo
html={controlledTableHtml}
/>
</GuideSection>
<GuideSection
title="ControlledTable with LoadingItems"
source={[{
type: GuideSectionTypes.HTML,
code: controlledTableWithLoadingItemsHtml,
}]}
>
<GuideDemo
html={controlledTableWithLoadingItemsHtml}
/>
</GuideSection>
<GuideSection
title="ControlledTable with NoItems"
source={[{
type: GuideSectionTypes.HTML,
code: controlledTableWithNoItemsHtml,
}]}
>
<GuideDemo
html={controlledTableWithNoItemsHtml}
/>
</GuideSection>
<GuideSection
title="ControlledTable with PromptForItems"
source={[{
type: GuideSectionTypes.HTML,
code: controlledTableWithPromptForItemsHtml,
}]}
>
<GuideDemo
html={controlledTableWithPromptForItemsHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,12 +1,49 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const html = require('./tabs.html');
title: 'Tabs', const js = require('raw!./tabs.js');
html: require('./tabs.html'),
js: require('raw!./tabs.js'), export default class TabsExample extends Component {
hasDarkTheme: false, render() {
}]); return (
<GuidePage title={this.props.route.name}>
<GuideSection
title="Tabs"
source={[{
type: GuideSectionTypes.HTML,
code: html,
}, {
type: GuideSectionTypes.JS,
code: js,
}]}
>
<GuideText>
Wrap any series of components, e.g. Panel, in the VerticalRhythm component to space
them apart.
</GuideText>
<GuideDemo
html={html}
js={js}
/>
</GuideSection>
</GuidePage>
);
}
}
TabsExample.propTypes = {
route: PropTypes.object.isRequired,
};

View file

@ -1,25 +1,67 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const toolBarHtml = require('./tool_bar.html');
title: 'ToolBar', const toolBarSearchOnlyHtml = require('./tool_bar_search_only.html');
description: ( const toolBarFooterHtml = require('./tool_bar_footer.html');
<p>Use the ToolBar to surface controls for manipulating and filtering content, e.g. in a list, table, or menu.</p>
), export default props => (
html: require('./tool_bar.html'), <GuidePage title={props.route.name}>
hasDarkTheme: false, <GuideSection
}, { title="ToolBar"
title: 'ToolBar with Search only', source={[{
html: require('./tool_bar_search_only.html'), type: GuideSectionTypes.HTML,
hasDarkTheme: false, code: toolBarHtml,
}, { }]}
title: 'ToolBarFooter', >
description: ( <GuideText>
<p>Use the ToolBarFooter in conjunction with the ToolBar. It can surface secondary controls or a subset of the primary controls.</p> Use the ToolBar to surface controls for manipulating and filtering content, e.g. in a
), list, table, or menu.
html: require('./tool_bar_footer.html'), </GuideText>
hasDarkTheme: false,
}]); <GuideDemo
html={toolBarHtml}
/>
</GuideSection>
<GuideSection
title="ToolBar with Search only"
source={[{
type: GuideSectionTypes.HTML,
code: toolBarSearchOnlyHtml,
}]}
>
<GuideDemo
html={toolBarSearchOnlyHtml}
/>
</GuideSection>
<GuideSection
title="ToolBarFooter"
source={[{
type: GuideSectionTypes.HTML,
code: toolBarFooterHtml,
}]}
>
<GuideText>
Use the ToolBarFooter in conjunction with the ToolBar. It can surface secondary
controls or a subset of the primary controls.
</GuideText>
<GuideDemo
html={toolBarFooterHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,28 +1,70 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideCode,
} from '../../services'; GuideDemo,
GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const titleHtml = require('./title.html');
title: 'Title', const subTitleHtml = require('./sub_title.html');
description: ( const textHtml = require('./text.html');
<p>Works well with an <code className="guideCode">h1</code>.</p>
), export default props => (
html: require('./title.html'), <GuidePage title={props.route.name}>
hasDarkTheme: false, <GuideSection
}, { title="Title"
title: 'SubTitle', source={[{
description: ( type: GuideSectionTypes.HTML,
<p>Works well with an <code className="guideCode">h2</code>.</p> code: titleHtml,
), }]}
html: require('./sub_title.html'), >
hasDarkTheme: false, <GuideText>
}, { Works well with an <GuideCode>h1</GuideCode>.
title: 'Text', </GuideText>
description: (
<p>Works well with a <code className="guideCode">p</code>.</p> <GuideDemo
), html={titleHtml}
html: require('./text.html'), />
hasDarkTheme: false, </GuideSection>
}]);
<GuideSection
title="SubTitle"
source={[{
type: GuideSectionTypes.HTML,
code: subTitleHtml,
}]}
>
<GuideText>
Works well with an <GuideCode>h2</GuideCode>.
</GuideText>
<GuideDemo
html={subTitleHtml}
/>
</GuideSection>
<GuideSection
title="Text"
source={[{
type: GuideSectionTypes.HTML,
code: textHtml,
}]}
>
<GuideText>
Works well with a <GuideCode>p</GuideCode>.
</GuideText>
<GuideDemo
html={textHtml}
/>
</GuideSection>
</GuidePage>
);

View file

@ -1,31 +1,75 @@
import React from 'react'; import React, {
Component,
PropTypes,
} from 'react';
import { import {
createExample, GuideDemo,
} from '../../services'; GuideLink,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
export default createExample([{ const verticalRhythmHtml = require('./vertical_rhythm.html');
title: 'VerticalRhythm', const verticalRhythmAsWrapperHtml = require('./vertical_rhythm_as_wrapper.html');
description: ( const verticalRhythmOnComponentHtml = require('./vertical_rhythm_on_component.html');
<div>
<p>VerticalRhythm creates regular vertical spacing between elements.</p> export default props => (
<p><strong>Note:</strong> It only works if two adjacent elements have this class applied, in which case it will create space between them.</p> <GuidePage title={props.route.name}>
</div> <GuideSection
), title="VerticalRhythm"
html: require('./vertical_rhythm.html'), source={[{
hasDarkTheme: false, type: GuideSectionTypes.HTML,
}, { code: verticalRhythmHtml,
title: 'VerticalRhythm as wrapper', }]}
description: ( >
<p>Wrap any series of components, e.g. Panel, in the VerticalRhythm component to space them apart.</p> <GuideText>
), VerticalRhythm creates regular vertical spacing between elements.
html: require('./vertical_rhythm_as_wrapper.html'), </GuideText>
hasDarkTheme: false,
}, { <GuideText>
title: 'VerticalRhythm on component', <strong>Note:</strong> It only works if two adjacent elements have this class applied, in
description: ( which case it will create space between them.
<p>You can also apply the VerticalRhythm class directly to components.</p> </GuideText>
),
html: require('./vertical_rhythm_on_component.html'), <GuideDemo
hasDarkTheme: false, html={verticalRhythmHtml}
}]); />
</GuideSection>
<GuideSection
title="VerticalRhythm as wrapper"
source={[{
type: GuideSectionTypes.HTML,
code: verticalRhythmAsWrapperHtml,
}]}
>
<GuideText>
Wrap any series of components, e.g. Panel, in the VerticalRhythm component to space them
apart.
</GuideText>
<GuideDemo
html={verticalRhythmAsWrapperHtml}
/>
</GuideSection>
<GuideSection
title="VerticalRhythm on component"
source={[{
type: GuideSectionTypes.HTML,
code: verticalRhythmOnComponentHtml,
}]}
>
<GuideText>
You can also apply the VerticalRhythm class directly to components.
</GuideText>
<GuideDemo
html={verticalRhythmOnComponentHtml}
/>
</GuideSection>
</GuidePage>
);