diff --git a/.eslintignore b/.eslintignore
index 9cf3facc95c4..455ccfd84808 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -15,3 +15,6 @@ tests/coverage
/html
/docs/js
node_modules
+
+# TODO: Upgrade to ESLint4 so we can apply a specific rule (one for CJS code) for below files
+src/**/*.config.js
diff --git a/.gitignore b/.gitignore
index 891c48069f21..47700dbd4da7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,3 +38,6 @@ tests/coverage
# a11y testing
.aat.yml
+
+# Generated by npm@5, but project currently uses Yarn
+package-lock.json
diff --git a/demo/.babelrc b/demo/.babelrc
index 0bcbdc77956a..f4f9840193db 100644
--- a/demo/.babelrc
+++ b/demo/.babelrc
@@ -11,5 +11,5 @@
],
"react"
],
- "plugins": ["transform-class-properties", "dev-expression"]
+ "plugins": ["transform-class-properties", "transform-object-rest-spread", "dev-expression"]
}
diff --git a/demo/js/components/CodePage/CodePage.js b/demo/js/components/CodePage/CodePage.js
index c4ba57eb618a..2400ae35d716 100644
--- a/demo/js/components/CodePage/CodePage.js
+++ b/demo/js/components/CodePage/CodePage.js
@@ -4,60 +4,36 @@ import Markdown from 'markdown-it';
import ComponentExample from '../ComponentExample/ComponentExample';
-/**
- * @param {ComponentCollection|Component} metadata The component data.
- * @returns {string} The HTML snippet for the component.
- */
-const getContent = metadata => {
- const { variants = {} } = metadata;
- const { items = [] } = variants;
- const variant = items[0];
- return metadata.content || (variant && variant.content) || '';
-};
-
-/**
- * @param {ComponentCollection|Component} metadata The component data.
- * @returns {Component[]|Variant[]} The data of the component variants.
- */
-const getSubItems = metadata => {
- if (metadata.isCollection) {
- return metadata.items;
- }
- if (!metadata.isCollated) {
- return metadata.variants.items;
- }
- return [];
-};
-
/**
* The page to show the component demo, its code as well as its README.
*/
const CodePage = ({ metadata, hideViewFullRender }) => {
const md = new Markdown({ html: true });
- const subItems = getSubItems(metadata).filter(item => !item.isHidden);
+ const subItems = (metadata.items || []).filter(item => !item.isHidden);
+ /* eslint-disable react/no-danger */
const componentContent =
!metadata.isCollection && subItems.length <= 1 ? (
) : (
subItems.map(item => (
{componentContent}
diff --git a/demo/js/components/ComponentExample/ComponentExample.js b/demo/js/components/ComponentExample/ComponentExample.js
index 8838c47d8372..a5e37fbb96e2 100644
--- a/demo/js/components/ComponentExample/ComponentExample.js
+++ b/demo/js/components/ComponentExample/ComponentExample.js
@@ -134,7 +134,8 @@ class ComponentExample extends Component {
});
const codepenLink = codepenSlug && `https://codepen.io/team/carbon/full/${codepenSlug}/`;
- const componentLink = variant ? `/component/${component}/${variant}` : `/component/${component}`;
+ const variantSuffix = (component === variant && '--default') || '';
+ const componentLink = variant ? `/component/${variant}${variantSuffix}` : `/component/${component}`;
const viewFullRender = hideViewFullRender ? null : (
diff --git a/demo/js/components/RootPage.js b/demo/js/components/RootPage.js
index ce47f3d02ed1..76e039e3899e 100644
--- a/demo/js/components/RootPage.js
+++ b/demo/js/components/RootPage.js
@@ -6,6 +6,67 @@ import SideNav from './SideNav';
import PageHeader from './PageHeader/PageHeader';
import SideNavToggle from './SideNavToggle/SideNavToggle';
+const checkStatus = response => {
+ if (response.status >= 200 && response.status < 400) {
+ return response;
+ }
+
+ const error = new Error(response.statusText);
+ error.response = response;
+ throw error;
+};
+
+const load = (componentItems, selectedNavItemId) => {
+ const metadata = componentItems && componentItems.find(item => item.id === selectedNavItemId);
+ const subItems = metadata.items || [];
+ const hasRenderedContent =
+ !metadata.isCollection && subItems.length <= 1 ? metadata.renderedContent : subItems.every(item => item.renderedContent);
+ if (!hasRenderedContent) {
+ return fetch(`/code/${metadata.name}`)
+ .then(checkStatus)
+ .then(response => {
+ const contentType = response.headers.get('content-type');
+ return contentType && contentType.includes('application/json') ? response.json() : response.text();
+ })
+ .then(responseContent => {
+ if (Object(responseContent) === responseContent) {
+ return componentItems.map(item => {
+ if (item.id !== selectedNavItemId) {
+ return item;
+ }
+ return !item.items
+ ? {
+ ...item,
+ renderedContent: responseContent[`${item.handle}--default`],
+ }
+ : {
+ ...item,
+ items: item.items.map(
+ subItem =>
+ !responseContent[subItem.handle]
+ ? subItem
+ : {
+ ...subItem,
+ renderedContent: responseContent[subItem.handle],
+ }
+ ),
+ };
+ });
+ }
+ return componentItems.map(
+ item =>
+ item.id !== selectedNavItemId
+ ? item
+ : {
+ ...item,
+ renderedContent: responseContent,
+ }
+ );
+ });
+ }
+ return Promise.resolve(null);
+};
+
/**
* The top-most React component for dev env page.
*/
@@ -22,9 +83,19 @@ class RootPage extends Component {
docItems: PropTypes.arrayOf(PropTypes.shape()).isRequired, // eslint-disable-line react/no-unused-prop-types
};
- constructor() {
+ constructor(props) {
super();
- this.state = {};
+
+ const { componentItems } = props;
+
+ this.state = {
+ /**
+ * The array of component data.
+ * @type {Object[]}
+ */
+ componentItems,
+ };
+
window.addEventListener('popstate', evt => {
this.switchTo(evt.state.name);
});
@@ -42,6 +113,13 @@ class RootPage extends Component {
}
}
+ componentWillReceiveProps(props) {
+ const { componentItems } = props;
+ if (this.props.componentItems !== componentItems) {
+ this.setState({ componentItems });
+ }
+ }
+
/**
* The handler for changing in the state of side nav's toggle button.
*/
@@ -53,7 +131,7 @@ class RootPage extends Component {
* The handler for the `click` event on the side nav for changing selection.
*/
onSideNavItemClick = evt => {
- const { componentItems } = this.props;
+ const { componentItems } = this.state;
const selectedNavItem = componentItems && componentItems.find(item => item.id === evt.target.dataset.navId);
if (selectedNavItem) {
this.switchTo(selectedNavItem.id);
@@ -64,7 +142,7 @@ class RootPage extends Component {
* @returns The component data that is currently selected.
*/
getCurrentComponentItem() {
- const { componentItems } = this.props;
+ const { componentItems } = this.state;
return componentItems && componentItems.find(item => item.id === this.state.selectedNavItemId);
}
@@ -74,17 +152,22 @@ class RootPage extends Component {
*/
switchTo(selectedNavItemId) {
this.setState({ selectedNavItemId }, () => {
- const { componentItems } = this.props;
+ const { componentItems } = this.state;
const selectedNavItem = componentItems && componentItems.find(item => item.id === selectedNavItemId);
const { name } = selectedNavItem || {};
if (name) {
history.pushState({ name }, name, `/demo/${name}`);
}
+ load(componentItems, selectedNavItemId).then(newComponentItems => {
+ if (newComponentItems) {
+ this.setState({ componentItems: newComponentItems });
+ }
+ });
});
}
render() {
- const { componentItems } = this.props;
+ const { componentItems } = this.state;
const metadata = this.getCurrentComponentItem();
const { name, label } = metadata || {};
const classNames = classnames({
diff --git a/demo/polyfills/devenv.js b/demo/polyfills/devenv.js
index 6c1134ce080e..4511996f6c5e 100644
--- a/demo/polyfills/devenv.js
+++ b/demo/polyfills/devenv.js
@@ -1,4 +1,14 @@
// Polyfill for dev env UI based on `carbon-components-react`
-/* eslint-disable import/no-extraneous-dependencies */
+/* eslint-disable import/no-extraneous-dependencies, global-require */
+import 'core-js/modules/es6.string.includes';
import 'core-js/modules/es7.object.values';
-/* eslint-enable import/no-extraneous-dependencies */
+import 'whatwg-fetch';
+
+if (typeof Promise === 'undefined') {
+ // Rejection tracking prevents a common issue where React gets into an
+ // inconsistent state due to an error, but it gets swallowed by a Promise,
+ // and the user has no idea what causes React's erratic future behavior.
+ require('promise/lib/rejection-tracking').enable();
+ window.Promise = require('promise/lib/es6-extensions.js');
+}
+/* eslint-enable import/no-extraneous-dependencies, global-require */
diff --git a/demo/scss/_page.scss b/demo/scss/_page.scss
index e9aca5fb302c..3c4de6665625 100644
--- a/demo/scss/_page.scss
+++ b/demo/scss/_page.scss
@@ -75,12 +75,12 @@ td {
}
}
- button {
- border-radius: 0;
- }
-
& > *:not(.component-example):not(.component-variation),
- & > {
+ & > {
+ button {
+ border-radius: 0;
+ }
+
.page__divider-heading {
@include typescale('zeta');
font-weight: 600;
diff --git a/demo/views/demo-live.dust b/demo/views/demo-live.dust
deleted file mode 100644
index 45a176744f7b..000000000000
--- a/demo/views/demo-live.dust
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
-
-
-
Carbon Components
-
-
-
-
-
- {content|s}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/demo/views/demo-nav-data.hbs b/demo/views/demo-nav-data.hbs
new file mode 100644
index 000000000000..29c2b10805e7
--- /dev/null
+++ b/demo/views/demo-nav-data.hbs
@@ -0,0 +1,15 @@
+
diff --git a/demo/views/demo-nav.dust b/demo/views/layouts/demo-nav.hbs
similarity index 61%
rename from demo/views/demo-nav.dust
rename to demo/views/layouts/demo-nav.hbs
index f1c83565abdb..764c63e77974 100644
--- a/demo/views/demo-nav.dust
+++ b/demo/views/layouts/demo-nav.hbs
@@ -23,21 +23,7 @@
-
+ {{{body}}}