From 49631b2af81a300cf1daacd469abfa357babd2a5 Mon Sep 17 00:00:00 2001 From: stepancar Date: Tue, 9 Jan 2018 23:17:33 +0300 Subject: [PATCH 01/26] feat(*): allow to show one component per page --- loaders/styleguide-loader.js | 1 + scripts/schemas/config.js | 4 ++++ .../ComponentsList/ComponentsListRenderer.js | 14 ++++++++++++-- .../__snapshots__/ComponentsList.spec.js.snap | 6 +++--- src/rsg-components/StyleGuide/StyleGuide.js | 16 +++++++++++++--- src/rsg-components/StyleGuide/StyleGuide.spec.js | 8 +++++++- .../__snapshots__/StyleGuide.spec.js.snap | 1 + .../TableOfContents/TableOfContents.js | 9 +++++---- .../__snapshots__/TableOfContents.spec.js.snap | 4 ++++ .../__snapshots__/renderStyleguide.spec.js.snap | 1 + src/utils/getRouteData.js | 6 +++++- src/utils/renderStyleguide.js | 2 ++ 12 files changed, 58 insertions(+), 14 deletions(-) diff --git a/loaders/styleguide-loader.js b/loaders/styleguide-loader.js index 7ce57f362..abc91d3ee 100644 --- a/loaders/styleguide-loader.js +++ b/loaders/styleguide-loader.js @@ -25,6 +25,7 @@ const CLIENT_CONFIG_OPTIONS = [ 'styles', 'compilerConfig', 'editorConfig', + 'oneComponentPerPage', ]; module.exports = function() {}; diff --git a/scripts/schemas/config.js b/scripts/schemas/config.js index 453b0cdaa..c75a41b60 100644 --- a/scripts/schemas/config.js +++ b/scripts/schemas/config.js @@ -290,4 +290,8 @@ module.exports = { }, }, }, + oneComponentPerPage: { + type: 'boolean', + default: false, + }, }; diff --git a/src/rsg-components/ComponentsList/ComponentsListRenderer.js b/src/rsg-components/ComponentsList/ComponentsListRenderer.js index 900aa1fd6..9ec956604 100644 --- a/src/rsg-components/ComponentsList/ComponentsListRenderer.js +++ b/src/rsg-components/ComponentsList/ComponentsListRenderer.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import cx from 'classnames'; import Link from 'rsg-components/Link'; import Styled from 'rsg-components/Styled'; +import getUrl from '../../utils/getUrl'; const styles = ({ color, fontFamily, fontSize, space, mq }) => ({ list: { @@ -33,7 +34,7 @@ const styles = ({ color, fontFamily, fontSize, space, mq }) => ({ }, }); -export function ComponentsListRenderer({ classes, items }) { +export function ComponentsListRenderer({ classes, items, oneComponentPerPage }) { items = items.filter(item => item.name); if (!items.length) { @@ -47,7 +48,15 @@ export function ComponentsListRenderer({ classes, items }) { className={cx(classes.item, (!content || !content.props.items.length) && classes.isChild)} key={name} > - + {name} {content} @@ -60,6 +69,7 @@ export function ComponentsListRenderer({ classes, items }) { ComponentsListRenderer.propTypes = { items: PropTypes.array.isRequired, classes: PropTypes.object.isRequired, + oneComponentPerPage: PropTypes.bool, }; export default Styled(styles)(ComponentsListRenderer); diff --git a/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap b/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap index 9a2fae296..7cee21796 100644 --- a/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap +++ b/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap @@ -8,7 +8,7 @@ exports[`should ignore items without name 1`] = ` > Button @@ -24,7 +24,7 @@ exports[`should render sections with nested components 1`] = ` > Button @@ -35,7 +35,7 @@ exports[`should render sections with nested components 1`] = ` > Input diff --git a/src/rsg-components/StyleGuide/StyleGuide.js b/src/rsg-components/StyleGuide/StyleGuide.js index 7b63f7a98..85107401a 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.js +++ b/src/rsg-components/StyleGuide/StyleGuide.js @@ -17,6 +17,8 @@ export default class StyleGuide extends Component { welcomeScreen: PropTypes.bool, patterns: PropTypes.array, displayMode: PropTypes.string, + allSections: PropTypes.array.isRequired, + oneComponentPerPage: PropTypes.bool, }; static childContextTypes = { @@ -52,7 +54,15 @@ export default class StyleGuide extends Component { } render() { - const { config, sections, welcomeScreen, patterns, displayMode } = this.props; + const { + config, + sections, + welcomeScreen, + patterns, + displayMode, + allSections, + oneComponentPerPage, + } = this.props; if (this.state.error) { return ; @@ -66,8 +76,8 @@ export default class StyleGuide extends Component { } - hasSidebar={config.showSidebar && displayMode === DisplayModes.all} + toc={} + hasSidebar={config.showSidebar && (oneComponentPerPage || displayMode === DisplayModes.all)} > diff --git a/src/rsg-components/StyleGuide/StyleGuide.spec.js b/src/rsg-components/StyleGuide/StyleGuide.spec.js index aa9e01f25..fce2fc38e 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.spec.js +++ b/src/rsg-components/StyleGuide/StyleGuide.spec.js @@ -33,7 +33,13 @@ const config = { it('should render components list', () => { const actual = shallow( - + ); expect(actual).toMatchSnapshot(); diff --git a/src/rsg-components/StyleGuide/__snapshots__/StyleGuide.spec.js.snap b/src/rsg-components/StyleGuide/__snapshots__/StyleGuide.spec.js.snap index 79a0dbd9b..6db4e35ed 100644 --- a/src/rsg-components/StyleGuide/__snapshots__/StyleGuide.spec.js.snap +++ b/src/rsg-components/StyleGuide/__snapshots__/StyleGuide.spec.js.snap @@ -74,6 +74,7 @@ exports[`should render components list 1`] = ` title="Hello" toc={ { const children = [...(section.sections || []), ...(section.components || [])]; return Object.assign({}, section, { @@ -20,19 +21,19 @@ export default class TableOfContents extends Component { content: children.length > 0 && this.renderLevel(children), }); }); - return ; + return ; } renderSections() { const { searchTerm } = this.state; - const { sections } = this.props; + const { sections, oneComponentPerPage } = this.props; // If there is only one section, we treat it as a root section // In this case the name of the section won't be rendered and it won't get left padding const firstLevel = sections.length === 1 ? sections[0].components : sections; const filtered = filterSectionsByName(firstLevel, searchTerm); - return this.renderLevel(filtered); + return this.renderLevel(filtered, oneComponentPerPage); } render() { diff --git a/src/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.js.snap b/src/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.js.snap index fa9b98ca1..2a60373ed 100644 --- a/src/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.js.snap +++ b/src/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.js.snap @@ -108,6 +108,7 @@ exports[`should filter section names 1`] = ` }, ] } + oneComponentPerPage={undefined} />, "heading": true, "name": "Buttons", @@ -142,6 +143,7 @@ exports[`should filter section names 1`] = ` }, ] } + oneComponentPerPage={undefined} />, "heading": true, "name": "Forms", @@ -248,6 +250,7 @@ exports[`should render renderer with sections with nested components 1`] = ` }, ] } + oneComponentPerPage={undefined} />, "heading": true, "name": "Buttons", @@ -282,6 +285,7 @@ exports[`should render renderer with sections with nested components 1`] = ` }, ] } + oneComponentPerPage={undefined} />, "heading": true, "name": "Forms", diff --git a/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap b/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap index d0ead0d44..56f8c6dcd 100644 --- a/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap +++ b/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap @@ -6,6 +6,7 @@ exports[`renderStyleguide should render StyleGuide component 1`] = ` title="My Style Guide" toc={ ); } From 80135ba14598b23483e2d7d8604f55290cdf367d Mon Sep 17 00:00:00 2001 From: stepancar Date: Tue, 9 Jan 2018 23:49:06 +0300 Subject: [PATCH 02/26] fix(*): fix according sapegin recomendations --- src/rsg-components/StyleGuide/StyleGuide.js | 17 +++++------------ .../__snapshots__/StyleGuide.spec.js.snap | 1 - .../TableOfContents/TableOfContents.js | 5 ++--- .../__snapshots__/renderStyleguide.spec.js.snap | 1 - src/utils/renderStyleguide.js | 1 - 5 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/rsg-components/StyleGuide/StyleGuide.js b/src/rsg-components/StyleGuide/StyleGuide.js index 85107401a..02ff3f209 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.js +++ b/src/rsg-components/StyleGuide/StyleGuide.js @@ -18,7 +18,6 @@ export default class StyleGuide extends Component { patterns: PropTypes.array, displayMode: PropTypes.string, allSections: PropTypes.array.isRequired, - oneComponentPerPage: PropTypes.bool, }; static childContextTypes = { @@ -54,15 +53,7 @@ export default class StyleGuide extends Component { } render() { - const { - config, - sections, - welcomeScreen, - patterns, - displayMode, - allSections, - oneComponentPerPage, - } = this.props; + const { config, sections, welcomeScreen, patterns, displayMode, allSections } = this.props; if (this.state.error) { return ; @@ -76,8 +67,10 @@ export default class StyleGuide extends Component { } - hasSidebar={config.showSidebar && (oneComponentPerPage || displayMode === DisplayModes.all)} + toc={} + hasSidebar={ + config.showSidebar && (config.oneComponentPerPage || displayMode === DisplayModes.all) + } > diff --git a/src/rsg-components/StyleGuide/__snapshots__/StyleGuide.spec.js.snap b/src/rsg-components/StyleGuide/__snapshots__/StyleGuide.spec.js.snap index 6db4e35ed..79a0dbd9b 100644 --- a/src/rsg-components/StyleGuide/__snapshots__/StyleGuide.spec.js.snap +++ b/src/rsg-components/StyleGuide/__snapshots__/StyleGuide.spec.js.snap @@ -74,7 +74,6 @@ exports[`should render components list 1`] = ` title="Hello" toc={ ); } From b546d05c558cbe35cc447d315ee67dd5842ee4f1 Mon Sep 17 00:00:00 2001 From: stepancar Date: Wed, 10 Jan 2018 00:09:50 +0300 Subject: [PATCH 03/26] docs(*): add docs for oneComponentPerPage prop --- docs/Configuration.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/Configuration.md b/docs/Configuration.md index 589642b47..f93007e31 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -20,6 +20,7 @@ By default, Styleguidist will look for `styleguide.config.js` file in your proje * [`handlers`](#handlers) * [`ignore`](#ignore) * [`logger`](#logger) +* [`oneComponentPerPage`](#oneComponentPerPage) * [`previewDelay`](#previewdelay) * [`propsParser`](#propsparser) * [`require`](#require) @@ -259,6 +260,12 @@ module.exports = { } ``` +#### `oneComponentPerPage` + +Type: `Boolean`, default: `false` + +Render one component per page. + #### `previewDelay` Type: `Number`, default: 500 From 9a2f8cbf4c08142452fa557faa08a71265b2a0db Mon Sep 17 00:00:00 2001 From: stepancar Date: Wed, 10 Jan 2018 01:01:58 +0300 Subject: [PATCH 04/26] test(*): add tests for oneComponentPerPage functionality --- .../ComponentsList/ComponentsList.spec.js | 17 +++++++++ .../__snapshots__/ComponentsList.spec.js.snap | 16 ++++++++ .../StyleGuide/StyleGuide.spec.js | 38 +++++++++++++++++-- .../__snapshots__/getRouteData.spec.js.snap | 22 +++++++++++ src/utils/__tests__/getRouteData.spec.js | 5 +++ src/utils/getRouteData.js | 10 ++++- 6 files changed, 104 insertions(+), 4 deletions(-) diff --git a/src/rsg-components/ComponentsList/ComponentsList.spec.js b/src/rsg-components/ComponentsList/ComponentsList.spec.js index a6fa3168c..3dc7aa4c6 100644 --- a/src/rsg-components/ComponentsList/ComponentsList.spec.js +++ b/src/rsg-components/ComponentsList/ComponentsList.spec.js @@ -37,3 +37,20 @@ it('should ignore items without name', () => { expect(actual).toMatchSnapshot(); }); + +it('should render links to isolated component page if oneComponentPerPage passed', () => { + const components = [ + { + name: 'Button', + slug: 'button', + }, + { + slug: 'input', + }, + ]; + const actual = shallow( + + ); + + expect(actual).toMatchSnapshot(); +}); diff --git a/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap b/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap index 7cee21796..cd3b525c4 100644 --- a/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap +++ b/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap @@ -16,6 +16,22 @@ exports[`should ignore items without name 1`] = ` `; +exports[`should render links to isolated component page if oneComponentPerPage passed 1`] = ` +
    +
  • + + Button + +
  • +
+`; + exports[`should render sections with nested components 1`] = `
  • { it('should render welcome screen', () => { const actual = shallow( - + ); expect(actual).toMatchSnapshot(); }); it('should render an error when componentDidCatch() is triggered', () => { - const wrapper = shallow(); + const wrapper = shallow( + + ); wrapper .instance() .componentDidCatch({ toString: () => 'error' }, { componentStack: { toString: () => 'info' } }); @@ -65,7 +74,13 @@ it('should render an error when componentDidCatch() is triggered', () => { describe('sidebar rendering', () => { it('renderer should have sidebar if showSidebar is not set', () => { const wrapper = shallow( - + ); expect(wrapper.prop('hasSidebar')).toEqual(true); @@ -80,6 +95,7 @@ describe('sidebar rendering', () => { showSidebar: false, }} sections={sections} + allSections={sections} slots={{}} /> ); @@ -93,6 +109,7 @@ describe('sidebar rendering', () => { codeRevision={1} config={config} sections={sections} + allSections={sections} slots={{}} displayMode={DisplayModes.component} /> @@ -100,6 +117,21 @@ describe('sidebar rendering', () => { expect(wrapper.prop('hasSidebar')).toEqual(false); }); + + it('renderer should have sidebar if oneComponentPerPage is true', () => { + const wrapper = shallow( + + ); + + expect(wrapper.prop('hasSidebar')).toEqual(true); + }); }); it('renderer should render logo, table of contents and passed children', () => { diff --git a/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap b/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap index a4df1d182..11b82de51 100644 --- a/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap +++ b/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap @@ -1,5 +1,27 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`getRouteData should return first component if oneComponentPerPage and hash is empty 1`] = ` +Object { + "displayMode": "all", + "sections": Array [ + Object { + "components": Object { + "module": 1, + "name": "Button", + "props": Object { + "displayName": "Button", + "examples": Array [ + "example 0", + "example 1", + ], + }, + }, + "sections": Array [], + }, + ], +} +`; + exports[`getRouteData should return one component 1`] = ` Object { "displayMode": "component", diff --git a/src/utils/__tests__/getRouteData.spec.js b/src/utils/__tests__/getRouteData.spec.js index b7fce1d70..fa8af04d3 100644 --- a/src/utils/__tests__/getRouteData.spec.js +++ b/src/utils/__tests__/getRouteData.spec.js @@ -60,4 +60,9 @@ describe('getRouteData', () => { const result = getRouteData(sections, '#!/Section/1'); expect(result).toMatchSnapshot(); }); + + it('should return first component if oneComponentPerPage and hash is empty', () => { + const result = getRouteData(sections, '', true); + expect(result).toMatchSnapshot(); + }); }); diff --git a/src/utils/getRouteData.js b/src/utils/getRouteData.js index 9f90d1e13..57962f13f 100644 --- a/src/utils/getRouteData.js +++ b/src/utils/getRouteData.js @@ -53,8 +53,16 @@ export default function getRouteData(sections, hash, oneComponentPerPage) { } } else if (oneComponentPerPage) { // If one component per page mode then show demos for first component - sections = [{ components: [sections[0].components[0]] }]; + sections = [getFirstSectionWithFirstComponent(sections)]; } return { sections, displayMode }; } + +function getFirstSectionWithFirstComponent(sections) { + const firstSection = sections[0]; + if (firstSection.components) { + return { ...firstSection, components: firstSection.components[0] }; + } + return getFirstSectionWithFirstComponent(firstSection.sections); +} From 15975dc28159f9b70def20c5505a60e832614ae3 Mon Sep 17 00:00:00 2001 From: bitionaire Date: Wed, 21 Feb 2018 15:29:37 +0100 Subject: [PATCH 05/26] Replaced 'oneComponentPerPage' with 'pagePerSection' property and added few tweaks --- docs/Configuration.md | 8 ++++--- loaders/styleguide-loader.js | 2 +- scripts/schemas/config.js | 8 +++---- .../ComponentsList/ComponentsListRenderer.js | 8 +++---- .../__snapshots__/ComponentsList.spec.js.snap | 2 +- src/rsg-components/StyleGuide/StyleGuide.js | 5 +++-- .../StyleGuide/StyleGuide.spec.js | 4 ++-- .../__snapshots__/StyleGuide.spec.js.snap | 1 + .../TableOfContents/TableOfContents.js | 11 +++++----- .../TableOfContents.spec.js.snap | 14 ++++++++---- .../__snapshots__/getRouteData.spec.js.snap | 22 ++++++++++--------- .../renderStyleguide.spec.js.snap | 1 + src/utils/getRouteData.js | 16 +++++++------- src/utils/renderStyleguide.js | 6 ++++- 14 files changed, 63 insertions(+), 45 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 2c7cc8626..d3f5e055e 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -20,7 +20,7 @@ By default, Styleguidist will look for `styleguide.config.js` file in your proje * [`handlers`](#handlers) * [`ignore`](#ignore) * [`logger`](#logger) -* [`oneComponentPerPage`](#oneComponentPerPage) +* [`pagePerSection`](#pagepersection) * [`previewDelay`](#previewdelay) * [`propsParser`](#propsparser) * [`require`](#require) @@ -260,11 +260,13 @@ module.exports = { } ``` -#### `oneComponentPerPage` +#### `pagePerSection` Type: `Boolean`, default: `false` -Render one component per page. +Render one section or component per page. + +If set to `true`, the sidebar will be visible on each page, except for the examples. #### `previewDelay` diff --git a/loaders/styleguide-loader.js b/loaders/styleguide-loader.js index a1c49ed66..6ae370241 100644 --- a/loaders/styleguide-loader.js +++ b/loaders/styleguide-loader.js @@ -24,7 +24,7 @@ const CLIENT_CONFIG_OPTIONS = [ 'styles', 'compilerConfig', 'editorConfig', - 'oneComponentPerPage', + 'pagePerSection', ]; module.exports = function() {}; diff --git a/scripts/schemas/config.js b/scripts/schemas/config.js index c75a41b60..1de8dd5a6 100644 --- a/scripts/schemas/config.js +++ b/scripts/schemas/config.js @@ -124,6 +124,10 @@ module.exports = { logger: { type: 'object', }, + pagePerSection: { + type: 'boolean', + default: false, + }, previewDelay: { type: 'number', default: 500, @@ -290,8 +294,4 @@ module.exports = { }, }, }, - oneComponentPerPage: { - type: 'boolean', - default: false, - }, }; diff --git a/src/rsg-components/ComponentsList/ComponentsListRenderer.js b/src/rsg-components/ComponentsList/ComponentsListRenderer.js index 9ec956604..1cbd19196 100644 --- a/src/rsg-components/ComponentsList/ComponentsListRenderer.js +++ b/src/rsg-components/ComponentsList/ComponentsListRenderer.js @@ -34,7 +34,7 @@ const styles = ({ color, fontFamily, fontSize, space, mq }) => ({ }, }); -export function ComponentsListRenderer({ classes, items, oneComponentPerPage }) { +export function ComponentsListRenderer({ classes, items, useIsolatedLinks }) { items = items.filter(item => item.name); if (!items.length) { @@ -53,8 +53,8 @@ export function ComponentsListRenderer({ classes, items, oneComponentPerPage }) href={getUrl({ name, slug, - anchor: !oneComponentPerPage, - isolated: oneComponentPerPage, + anchor: !useIsolatedLinks, + isolated: useIsolatedLinks, })} > {name} @@ -69,7 +69,7 @@ export function ComponentsListRenderer({ classes, items, oneComponentPerPage }) ComponentsListRenderer.propTypes = { items: PropTypes.array.isRequired, classes: PropTypes.object.isRequired, - oneComponentPerPage: PropTypes.bool, + useIsolatedLinks: PropTypes.bool, }; export default Styled(styles)(ComponentsListRenderer); diff --git a/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap b/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap index cd3b525c4..667663ba6 100644 --- a/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap +++ b/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap @@ -24,7 +24,7 @@ exports[`should render links to isolated component page if oneComponentPerPage p > Button diff --git a/src/rsg-components/StyleGuide/StyleGuide.js b/src/rsg-components/StyleGuide/StyleGuide.js index 02ff3f209..fa41295cb 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.js +++ b/src/rsg-components/StyleGuide/StyleGuide.js @@ -67,9 +67,10 @@ export default class StyleGuide extends Component { } + toc={} hasSidebar={ - config.showSidebar && (config.oneComponentPerPage || displayMode === DisplayModes.all) + (config.pagePerSection && displayMode !== DisplayModes.example) || + (config.showSidebar && displayMode === DisplayModes.all) } > diff --git a/src/rsg-components/StyleGuide/StyleGuide.spec.js b/src/rsg-components/StyleGuide/StyleGuide.spec.js index 69ee0f307..0b1ea97a2 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.spec.js +++ b/src/rsg-components/StyleGuide/StyleGuide.spec.js @@ -118,11 +118,11 @@ describe('sidebar rendering', () => { expect(wrapper.prop('hasSidebar')).toEqual(false); }); - it('renderer should have sidebar if oneComponentPerPage is true', () => { + it('renderer should have sidebar if pagePerSection is true', () => { const wrapper = shallow( } > diff --git a/src/rsg-components/TableOfContents/TableOfContents.js b/src/rsg-components/TableOfContents/TableOfContents.js index 709452151..fea2d8dfc 100644 --- a/src/rsg-components/TableOfContents/TableOfContents.js +++ b/src/rsg-components/TableOfContents/TableOfContents.js @@ -7,32 +7,33 @@ import filterSectionsByName from '../../utils/filterSectionsByName'; export default class TableOfContents extends Component { static propTypes = { sections: PropTypes.array.isRequired, + useIsolatedLinks: PropTypes.bool, }; state = { searchTerm: '', }; - renderLevel(sections, oneComponentPerPage) { + renderLevel(sections, useIsolatedLinks = false) { const items = sections.map(section => { const children = [...(section.sections || []), ...(section.components || [])]; return Object.assign({}, section, { heading: !!section.name && children.length > 0, - content: children.length > 0 && this.renderLevel(children), + content: children.length > 0 && this.renderLevel(children, useIsolatedLinks), }); }); - return ; + return ; } renderSections() { const { searchTerm } = this.state; const { sections } = this.props; - const oneComponentPerPage = (this.context.config || {}).oneComponentPerPage; + const useIsolatedLinks = (this.context.config || {}).useIsolatedLinks; // If there is only one section, we treat it as a root section // In this case the name of the section won't be rendered and it won't get left padding const firstLevel = sections.length === 1 ? sections[0].components : sections; const filtered = filterSectionsByName(firstLevel, searchTerm); - return this.renderLevel(filtered, oneComponentPerPage); + return this.renderLevel(filtered, useIsolatedLinks); } render() { diff --git a/src/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.js.snap b/src/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.js.snap index 2a60373ed..4b7c35baf 100644 --- a/src/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.js.snap +++ b/src/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.js.snap @@ -48,6 +48,7 @@ exports[`should filter list when search field contains a query 1`] = ` }, ] } + useIsolatedLinks={false} /> `; @@ -70,6 +71,7 @@ exports[`should filter list when search field contains a query 2`] = ` }, ] } + useIsolatedLinks={false} /> `; @@ -108,7 +110,7 @@ exports[`should filter section names 1`] = ` }, ] } - oneComponentPerPage={undefined} + useIsolatedLinks={false} />, "heading": true, "name": "Buttons", @@ -143,7 +145,7 @@ exports[`should filter section names 1`] = ` }, ] } - oneComponentPerPage={undefined} + useIsolatedLinks={false} />, "heading": true, "name": "Forms", @@ -152,6 +154,7 @@ exports[`should filter section names 1`] = ` }, ] } + useIsolatedLinks={false} /> `; @@ -174,6 +177,7 @@ exports[`should filter section names 2`] = ` }, ] } + useIsolatedLinks={false} /> `; @@ -212,6 +216,7 @@ exports[`should render a renderer 1`] = ` }, ] } + useIsolatedLinks={false} /> `; @@ -250,7 +255,7 @@ exports[`should render renderer with sections with nested components 1`] = ` }, ] } - oneComponentPerPage={undefined} + useIsolatedLinks={false} />, "heading": true, "name": "Buttons", @@ -285,7 +290,7 @@ exports[`should render renderer with sections with nested components 1`] = ` }, ] } - oneComponentPerPage={undefined} + useIsolatedLinks={false} />, "heading": true, "name": "Forms", @@ -294,6 +299,7 @@ exports[`should render renderer with sections with nested components 1`] = ` }, ] } + useIsolatedLinks={false} /> `; diff --git a/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap b/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap index 11b82de51..4eb876c4f 100644 --- a/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap +++ b/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap @@ -5,17 +5,19 @@ Object { "displayMode": "all", "sections": Array [ Object { - "components": Object { - "module": 1, - "name": "Button", - "props": Object { - "displayName": "Button", - "examples": Array [ - "example 0", - "example 1", - ], + "components": Array [ + Object { + "module": 1, + "name": "Button", + "props": Object { + "displayName": "Button", + "examples": Array [ + "example 0", + "example 1", + ], + }, }, - }, + ], "sections": Array [], }, ], diff --git a/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap b/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap index d0ead0d44..a2416be1b 100644 --- a/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap +++ b/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap @@ -31,6 +31,7 @@ exports[`renderStyleguide should render StyleGuide component 1`] = ` }, ] } + useIsolatedLinks={undefined} /> } > diff --git a/src/utils/getRouteData.js b/src/utils/getRouteData.js index 57962f13f..ed2fbf995 100644 --- a/src/utils/getRouteData.js +++ b/src/utils/getRouteData.js @@ -15,10 +15,10 @@ import { DisplayModes } from '../consts'; * * @param {object} sections * @param {string} hash - * @param {bool} oneComponentPerPage + * @param {bool} pagePerSection * @returns {object} */ -export default function getRouteData(sections, hash, oneComponentPerPage) { +export default function getRouteData(sections, hash, pagePerSection) { // Parse URL hash to check if the components list must be filtered const { // Name of the filtered component/section to show isolated (/#!/Button → Button) @@ -51,18 +51,18 @@ export default function getRouteData(sections, hash, oneComponentPerPage) { displayMode = DisplayModes.example; } } - } else if (oneComponentPerPage) { + } else if (pagePerSection) { // If one component per page mode then show demos for first component - sections = [getFirstSectionWithFirstComponent(sections)]; + sections = [getFirstSectionOrComponent(sections)]; } return { sections, displayMode }; } -function getFirstSectionWithFirstComponent(sections) { +function getFirstSectionOrComponent(sections) { const firstSection = sections[0]; - if (firstSection.components) { - return { ...firstSection, components: firstSection.components[0] }; + if (firstSection.components && firstSection.components.length > 0) { + return { ...firstSection, components: [firstSection.components[0]] }; } - return getFirstSectionWithFirstComponent(firstSection.sections); + return getFirstSectionOrComponent(firstSection.sections); } diff --git a/src/utils/renderStyleguide.js b/src/utils/renderStyleguide.js index cda26e238..170615d97 100644 --- a/src/utils/renderStyleguide.js +++ b/src/utils/renderStyleguide.js @@ -27,7 +27,11 @@ export default function renderStyleguide( // all components accessible to all examples globalizeComponents(allSections); - const { sections, displayMode } = getRouteData(allSections, loc.hash); + const { sections, displayMode } = getRouteData( + allSections, + loc.hash, + styleguide.config.pagePerSection + ); // Update page title doc.title = getPageTitle(sections, styleguide.config.title, displayMode); From b4a6780d14afaaa399d471d49bd05c30cd8dd071 Mon Sep 17 00:00:00 2001 From: bitionaire Date: Wed, 21 Feb 2018 17:04:47 +0100 Subject: [PATCH 06/26] Changed test name --- src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap | 2 +- src/utils/__tests__/getRouteData.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap b/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap index 4eb876c4f..ec4312cac 100644 --- a/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap +++ b/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`getRouteData should return first component if oneComponentPerPage and hash is empty 1`] = ` +exports[`getRouteData should return first component if pagePerSection and hash is empty 1`] = ` Object { "displayMode": "all", "sections": Array [ diff --git a/src/utils/__tests__/getRouteData.spec.js b/src/utils/__tests__/getRouteData.spec.js index fa8af04d3..69d35cd5c 100644 --- a/src/utils/__tests__/getRouteData.spec.js +++ b/src/utils/__tests__/getRouteData.spec.js @@ -61,7 +61,7 @@ describe('getRouteData', () => { expect(result).toMatchSnapshot(); }); - it('should return first component if oneComponentPerPage and hash is empty', () => { + it('should return first component if pagePerSection and hash is empty', () => { const result = getRouteData(sections, '', true); expect(result).toMatchSnapshot(); }); From 98931f42904592f21c14247f1cc86f5ba147cb9c Mon Sep 17 00:00:00 2001 From: bitionaire Date: Wed, 21 Feb 2018 17:25:57 +0100 Subject: [PATCH 07/26] Fixed section route --- .../__snapshots__/getRouteData.spec.js.snap | 42 ++++++++++++++----- src/utils/getRouteData.js | 2 +- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap b/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap index ec4312cac..23ca8222d 100644 --- a/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap +++ b/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap @@ -5,20 +5,40 @@ Object { "displayMode": "all", "sections": Array [ Object { - "components": Array [ + "sections": Array [ Object { - "module": 1, - "name": "Button", - "props": Object { - "displayName": "Button", - "examples": Array [ - "example 0", - "example 1", - ], - }, + "components": Array [ + Object { + "module": 1, + "name": "Button", + "props": Object { + "displayName": "Button", + "examples": Array [ + "example 0", + "example 1", + ], + }, + }, + Object { + "module": 2, + "name": "Image", + "props": Object { + "displayName": "Image", + }, + }, + ], + "sections": Array [], + }, + Object { + "components": Array [], + "content": Array [ + "example 0", + "example 1", + ], + "name": "Section", + "sections": Array [], }, ], - "sections": Array [], }, ], } diff --git a/src/utils/getRouteData.js b/src/utils/getRouteData.js index ed2fbf995..c85b1706b 100644 --- a/src/utils/getRouteData.js +++ b/src/utils/getRouteData.js @@ -64,5 +64,5 @@ function getFirstSectionOrComponent(sections) { if (firstSection.components && firstSection.components.length > 0) { return { ...firstSection, components: [firstSection.components[0]] }; } - return getFirstSectionOrComponent(firstSection.sections); + return firstSection; } From 48a585b9076d1cec59998acb6286ec1c14ba4ba3 Mon Sep 17 00:00:00 2001 From: bitionaire Date: Wed, 21 Feb 2018 17:42:06 +0100 Subject: [PATCH 08/26] Use isolated links extracted from props instead of context --- src/rsg-components/TableOfContents/TableOfContents.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/rsg-components/TableOfContents/TableOfContents.js b/src/rsg-components/TableOfContents/TableOfContents.js index fea2d8dfc..01b6dc423 100644 --- a/src/rsg-components/TableOfContents/TableOfContents.js +++ b/src/rsg-components/TableOfContents/TableOfContents.js @@ -26,8 +26,7 @@ export default class TableOfContents extends Component { renderSections() { const { searchTerm } = this.state; - const { sections } = this.props; - const useIsolatedLinks = (this.context.config || {}).useIsolatedLinks; + const { sections, useIsolatedLinks } = this.props; // If there is only one section, we treat it as a root section // In this case the name of the section won't be rendered and it won't get left padding const firstLevel = sections.length === 1 ? sections[0].components : sections; From fca7e0cdb68437c1f6ba7e54b245527893f76e9f Mon Sep 17 00:00:00 2001 From: bitionaire Date: Wed, 21 Feb 2018 21:28:00 +0100 Subject: [PATCH 09/26] Added option to configure pagePerSection as function --- Readme.md | 3 +-- docs/Configuration.md | 12 ++++++++++-- docs/Cookbook.md | 1 - scripts/schemas/config.js | 2 +- src/utils/renderStyleguide.js | 4 +++- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Readme.md b/Readme.md index f564a9d22..2b874edfd 100644 --- a/Readme.md +++ b/Readme.md @@ -4,8 +4,7 @@ **Isolated React component development environment with a living style guide** -[![Build Status](https://travis-ci.org/styleguidist/react-styleguidist.svg)](https://travis-ci.org/styleguidist/react-styleguidist) [![npm](https://img.shields.io/npm/v/react-styleguidist.svg)](https://www.npmjs.com/package/react-styleguidist) [![Join the chat at https://gitter.im/styleguidist/styleguidist](https://badges.gitter.im/styleguidist/styleguidist.svg)](https://gitter.im/styleguidist/styleguidist?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/styleguidist) [![Codecov](https://codecov.io/gh/styleguidist/react-styleguidist/branch/master/graph/badge.svg)](https://codecov.io/gh/styleguidist/react-styleguidist) -[![Open Source Helpers](https://www.codetriage.com/styleguidist/react-styleguidist/badges/users.svg)](https://www.codetriage.com/styleguidist/react-styleguidist) +[![Build Status](https://travis-ci.org/styleguidist/react-styleguidist.svg)](https://travis-ci.org/styleguidist/react-styleguidist) [![npm](https://img.shields.io/npm/v/react-styleguidist.svg)](https://www.npmjs.com/package/react-styleguidist) [![Join the chat at https://gitter.im/styleguidist/styleguidist](https://badges.gitter.im/styleguidist/styleguidist.svg)](https://gitter.im/styleguidist/styleguidist?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/styleguidist) [![Codecov](https://codecov.io/gh/styleguidist/react-styleguidist/branch/master/graph/badge.svg)](https://codecov.io/gh/styleguidist/react-styleguidist) [![Open Source Helpers](https://www.codetriage.com/styleguidist/react-styleguidist/badges/users.svg)](https://www.codetriage.com/styleguidist/react-styleguidist) diff --git a/docs/Configuration.md b/docs/Configuration.md index d3f5e055e..efa9fc445 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -262,12 +262,20 @@ module.exports = { #### `pagePerSection` -Type: `Boolean`, default: `false` +Type: `Boolean` or `Function`, default: `false` -Render one section or component per page. +Render one section or component per page. Can be set by a function in order to control the behaviour for different environments. If set to `true`, the sidebar will be visible on each page, except for the examples. +```javascript +module.exports = { + pagePerSection: function() { + return process.env.NODE_ENV !== 'production' + } +} +``` + #### `previewDelay` Type: `Number`, default: 500 diff --git a/docs/Cookbook.md b/docs/Cookbook.md index 6f1184d4f..2d45fa74b 100644 --- a/docs/Cookbook.md +++ b/docs/Cookbook.md @@ -114,7 +114,6 @@ const iconElements = Object.keys(icons).map(iconName => { ) }) - ;
    {iconElements}
    ``` diff --git a/scripts/schemas/config.js b/scripts/schemas/config.js index 1de8dd5a6..6d8b0687d 100644 --- a/scripts/schemas/config.js +++ b/scripts/schemas/config.js @@ -125,7 +125,7 @@ module.exports = { type: 'object', }, pagePerSection: { - type: 'boolean', + type: ['boolean', 'function'], default: false, }, previewDelay: { diff --git a/src/utils/renderStyleguide.js b/src/utils/renderStyleguide.js index 170615d97..bddb894f7 100644 --- a/src/utils/renderStyleguide.js +++ b/src/utils/renderStyleguide.js @@ -1,3 +1,4 @@ +import { isFunction } from 'lodash'; import React from 'react'; import slots from 'rsg-components/slots'; import StyleGuide from 'rsg-components/StyleGuide'; @@ -27,10 +28,11 @@ export default function renderStyleguide( // all components accessible to all examples globalizeComponents(allSections); + const { pagePerSection } = styleguide.config; const { sections, displayMode } = getRouteData( allSections, loc.hash, - styleguide.config.pagePerSection + isFunction(pagePerSection) ? pagePerSection() : pagePerSection ); // Update page title From 12d823c2f02de60bf82e0dbbf23ac9a89533e34c Mon Sep 17 00:00:00 2001 From: bitionaire Date: Wed, 21 Feb 2018 21:29:37 +0100 Subject: [PATCH 10/26] Added scrollTo(0,0) on sections change --- examples/sections/styleguide.config.js | 1 + src/rsg-components/StyleGuide/StyleGuide.js | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/examples/sections/styleguide.config.js b/examples/sections/styleguide.config.js index 32e66fadb..d5e89f51c 100644 --- a/examples/sections/styleguide.config.js +++ b/examples/sections/styleguide.config.js @@ -2,6 +2,7 @@ const path = require('path'); module.exports = { title: 'React Style Guide Example', + pagePerSection: true, sections: [ { name: 'Documentation', diff --git a/src/rsg-components/StyleGuide/StyleGuide.js b/src/rsg-components/StyleGuide/StyleGuide.js index fa41295cb..62de6b549 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.js +++ b/src/rsg-components/StyleGuide/StyleGuide.js @@ -1,3 +1,4 @@ +import { isEqual, isFunction } from 'lodash'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; import TableOfContents from 'rsg-components/TableOfContents'; @@ -45,6 +46,15 @@ export default class StyleGuide extends Component { }; } + componentDidUpdate(prevProps) { + // scroll to top of styleguide container when sections changed + if (!isEqual(this.props.sections, prevProps.sections)) { + if (window && isFunction(window.scrollTo)) { + window.scrollTo(0, 0); + } + } + } + componentDidCatch(error, info) { this.setState({ error, From fa0e3e8a0d7d1050aee57b76d4f41c33ff0a0b0d Mon Sep 17 00:00:00 2001 From: bitionaire Date: Wed, 21 Feb 2018 21:33:34 +0100 Subject: [PATCH 11/26] Forward props correctly --- src/rsg-components/StyleGuide/StyleGuide.js | 15 ++++++++++++--- src/utils/renderStyleguide.js | 8 +++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/rsg-components/StyleGuide/StyleGuide.js b/src/rsg-components/StyleGuide/StyleGuide.js index 62de6b549..4cf666ba5 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.js +++ b/src/rsg-components/StyleGuide/StyleGuide.js @@ -19,6 +19,7 @@ export default class StyleGuide extends Component { patterns: PropTypes.array, displayMode: PropTypes.string, allSections: PropTypes.array.isRequired, + pagePerSection: PropTypes.bool, }; static childContextTypes = { @@ -63,7 +64,15 @@ export default class StyleGuide extends Component { } render() { - const { config, sections, welcomeScreen, patterns, displayMode, allSections } = this.props; + const { + config, + sections, + welcomeScreen, + patterns, + displayMode, + allSections, + pagePerSection, + } = this.props; if (this.state.error) { return ; @@ -77,9 +86,9 @@ export default class StyleGuide extends Component { } + toc={} hasSidebar={ - (config.pagePerSection && displayMode !== DisplayModes.example) || + (pagePerSection && displayMode !== DisplayModes.example) || (config.showSidebar && displayMode === DisplayModes.all) } > diff --git a/src/utils/renderStyleguide.js b/src/utils/renderStyleguide.js index bddb894f7..70e97b41b 100644 --- a/src/utils/renderStyleguide.js +++ b/src/utils/renderStyleguide.js @@ -29,11 +29,8 @@ export default function renderStyleguide( globalizeComponents(allSections); const { pagePerSection } = styleguide.config; - const { sections, displayMode } = getRouteData( - allSections, - loc.hash, - isFunction(pagePerSection) ? pagePerSection() : pagePerSection - ); + const renderPagePerSection = isFunction(pagePerSection) ? pagePerSection() : pagePerSection; + const { sections, displayMode } = getRouteData(allSections, loc.hash, renderPagePerSection); // Update page title doc.title = getPageTitle(sections, styleguide.config.title, displayMode); @@ -55,6 +52,7 @@ export default function renderStyleguide( sections={sections} allSections={allSections} displayMode={displayMode} + pagePerSection={renderPagePerSection} /> ); } From b4f94fe62ce3676c49d4afbcd48e8b8bde371e03 Mon Sep 17 00:00:00 2001 From: bitionaire Date: Wed, 21 Feb 2018 21:34:23 +0100 Subject: [PATCH 12/26] Removed unintended change --- examples/sections/styleguide.config.js | 1 - src/rsg-components/StyleGuide/StyleGuide.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/sections/styleguide.config.js b/examples/sections/styleguide.config.js index d5e89f51c..32e66fadb 100644 --- a/examples/sections/styleguide.config.js +++ b/examples/sections/styleguide.config.js @@ -2,7 +2,6 @@ const path = require('path'); module.exports = { title: 'React Style Guide Example', - pagePerSection: true, sections: [ { name: 'Documentation', diff --git a/src/rsg-components/StyleGuide/StyleGuide.js b/src/rsg-components/StyleGuide/StyleGuide.js index 4cf666ba5..93ab7660b 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.js +++ b/src/rsg-components/StyleGuide/StyleGuide.js @@ -49,7 +49,7 @@ export default class StyleGuide extends Component { componentDidUpdate(prevProps) { // scroll to top of styleguide container when sections changed - if (!isEqual(this.props.sections, prevProps.sections)) { + if (this.props.pagePerSection && !isEqual(this.props.sections, prevProps.sections)) { if (window && isFunction(window.scrollTo)) { window.scrollTo(0, 0); } From 42396caa569292d460522aa419d956db4dc49c3c Mon Sep 17 00:00:00 2001 From: bitionaire Date: Wed, 21 Feb 2018 21:45:28 +0100 Subject: [PATCH 13/26] Fixed test --- src/rsg-components/StyleGuide/StyleGuide.spec.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rsg-components/StyleGuide/StyleGuide.spec.js b/src/rsg-components/StyleGuide/StyleGuide.spec.js index 0b1ea97a2..85780e287 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.spec.js +++ b/src/rsg-components/StyleGuide/StyleGuide.spec.js @@ -122,11 +122,12 @@ describe('sidebar rendering', () => { const wrapper = shallow( ); From 3f7c42a73221cd2b13785c48a755d5febd33b058 Mon Sep 17 00:00:00 2001 From: bitionaire Date: Thu, 22 Feb 2018 17:36:03 +0100 Subject: [PATCH 14/26] Added scroll tests --- .../StyleGuide/StyleGuide.spec.js | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/rsg-components/StyleGuide/StyleGuide.spec.js b/src/rsg-components/StyleGuide/StyleGuide.spec.js index 85780e287..5dd440f77 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.spec.js +++ b/src/rsg-components/StyleGuide/StyleGuide.spec.js @@ -71,6 +71,46 @@ it('should render an error when componentDidCatch() is triggered', () => { expect(wrapper).toMatchSnapshot(); }); +it('should scroll to top on sections change, when pagePerSections is true', () => { + const scrollTo = jest.fn(); + global.window.scrollTo = scrollTo; + + const props = { + codeRevision: 1, + config, + sections: [], + allSections: [], + slots: {}, + pagePerSection: true, + }; + + const wrapper = shallow(); + + wrapper.instance().componentDidUpdate({ ...props, sections }); + + expect(scrollTo.mock.calls.length).toBe(1); +}); + +it('should not scroll to top on sections change, when pagePerSections is false', () => { + const scrollTo = jest.fn(); + global.window.scrollTo = scrollTo; + + const props = { + codeRevision: 1, + config, + sections: [], + allSections: [], + slots: {}, + pagePerSection: false, + }; + + const wrapper = shallow(); + + wrapper.instance().componentDidUpdate({ ...props, sections }); + + expect(scrollTo.mock.calls.length).toBe(0); +}); + describe('sidebar rendering', () => { it('renderer should have sidebar if showSidebar is not set', () => { const wrapper = shallow( From fecaf2a175c14c97e5240b7554f4aa20c6745462 Mon Sep 17 00:00:00 2001 From: bitionaire Date: Thu, 22 Feb 2018 17:43:05 +0100 Subject: [PATCH 15/26] Added getRouteData test for single section --- .../__snapshots__/getRouteData.spec.js.snap | 20 +++++++++++++++++++ src/utils/__tests__/getRouteData.spec.js | 20 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap b/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap index 23ca8222d..a0963a7b4 100644 --- a/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap +++ b/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap @@ -44,6 +44,26 @@ Object { } `; +exports[`getRouteData should return first section if pagePerSection and hash is empty 1`] = ` +Object { + "displayMode": "all", + "sections": Array [ + Object { + "sections": Array [ + Object { + "components": Array [], + "content": Array [ + "Some content", + ], + "name": "Single section", + "sections": Array [], + }, + ], + }, + ], +} +`; + exports[`getRouteData should return one component 1`] = ` Object { "displayMode": "component", diff --git a/src/utils/__tests__/getRouteData.spec.js b/src/utils/__tests__/getRouteData.spec.js index 69d35cd5c..589bc5781 100644 --- a/src/utils/__tests__/getRouteData.spec.js +++ b/src/utils/__tests__/getRouteData.spec.js @@ -61,6 +61,26 @@ describe('getRouteData', () => { expect(result).toMatchSnapshot(); }); + it('should return first section if pagePerSection and hash is empty', () => { + const result = getRouteData( + [ + { + sections: [ + { + name: 'Single section', + content: ['Some content'], + components: [], + sections: [], + }, + ], + }, + ], + '', + true + ); + expect(result).toMatchSnapshot(); + }); + it('should return first component if pagePerSection and hash is empty', () => { const result = getRouteData(sections, '', true); expect(result).toMatchSnapshot(); From ad764460b94dd38349b81c0e43f273349a1b383a Mon Sep 17 00:00:00 2001 From: bitionaire Date: Thu, 22 Feb 2018 18:07:15 +0100 Subject: [PATCH 16/26] Coverage fix --- .../__snapshots__/getRouteData.spec.js.snap | 44 ++++++++++--------- src/utils/__tests__/getRouteData.spec.js | 19 +------- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap b/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap index a0963a7b4..9f866ecfd 100644 --- a/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap +++ b/src/utils/__tests__/__snapshots__/getRouteData.spec.js.snap @@ -1,6 +1,30 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`getRouteData should return first component if pagePerSection and hash is empty 1`] = ` +Object { + "displayMode": "all", + "sections": Array [ + Object { + "components": Array [ + Object { + "module": 1, + "name": "Button", + "props": Object { + "displayName": "Button", + "examples": Array [ + "example 0", + "example 1", + ], + }, + }, + ], + "sections": Array [], + }, + ], +} +`; + +exports[`getRouteData should return first section if pagePerSection and hash is empty 1`] = ` Object { "displayMode": "all", "sections": Array [ @@ -44,26 +68,6 @@ Object { } `; -exports[`getRouteData should return first section if pagePerSection and hash is empty 1`] = ` -Object { - "displayMode": "all", - "sections": Array [ - Object { - "sections": Array [ - Object { - "components": Array [], - "content": Array [ - "Some content", - ], - "name": "Single section", - "sections": Array [], - }, - ], - }, - ], -} -`; - exports[`getRouteData should return one component 1`] = ` Object { "displayMode": "component", diff --git a/src/utils/__tests__/getRouteData.spec.js b/src/utils/__tests__/getRouteData.spec.js index 589bc5781..7f37694bc 100644 --- a/src/utils/__tests__/getRouteData.spec.js +++ b/src/utils/__tests__/getRouteData.spec.js @@ -62,27 +62,12 @@ describe('getRouteData', () => { }); it('should return first section if pagePerSection and hash is empty', () => { - const result = getRouteData( - [ - { - sections: [ - { - name: 'Single section', - content: ['Some content'], - components: [], - sections: [], - }, - ], - }, - ], - '', - true - ); + const result = getRouteData(sections, '', true); expect(result).toMatchSnapshot(); }); it('should return first component if pagePerSection and hash is empty', () => { - const result = getRouteData(sections, '', true); + const result = getRouteData(sections[0].sections, '', true); expect(result).toMatchSnapshot(); }); }); From bfe0c4690c7ac920bcb3d939becefce97267f40d Mon Sep 17 00:00:00 2001 From: bitionaire Date: Fri, 23 Feb 2018 21:22:52 +0100 Subject: [PATCH 17/26] Modifications by PR review --- docs/Configuration.md | 10 +++---- scripts/schemas/config.js | 2 +- .../ComponentsList/ComponentsList.spec.js | 4 +-- .../__snapshots__/ComponentsList.spec.js.snap | 4 +-- src/rsg-components/StyleGuide/StyleGuide.js | 28 ++++++++++++++++--- src/utils/getRouteData.js | 2 +- src/utils/renderStyleguide.js | 10 +++---- 7 files changed, 39 insertions(+), 21 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index efa9fc445..a80fac050 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -262,17 +262,17 @@ module.exports = { #### `pagePerSection` -Type: `Boolean` or `Function`, default: `false` +Type: `Boolean`, default: `false` -Render one section or component per page. Can be set by a function in order to control the behaviour for different environments. +Render one section or component per page, starting with the first. If set to `true`, the sidebar will be visible on each page, except for the examples. +The value may be differ on each environment. + ```javascript module.exports = { - pagePerSection: function() { - return process.env.NODE_ENV !== 'production' - } + pagePerSection: process.env.NODE_ENV !== 'production' } ``` diff --git a/scripts/schemas/config.js b/scripts/schemas/config.js index 6d8b0687d..1de8dd5a6 100644 --- a/scripts/schemas/config.js +++ b/scripts/schemas/config.js @@ -125,7 +125,7 @@ module.exports = { type: 'object', }, pagePerSection: { - type: ['boolean', 'function'], + type: 'boolean', default: false, }, previewDelay: { diff --git a/src/rsg-components/ComponentsList/ComponentsList.spec.js b/src/rsg-components/ComponentsList/ComponentsList.spec.js index 3dc7aa4c6..21955e134 100644 --- a/src/rsg-components/ComponentsList/ComponentsList.spec.js +++ b/src/rsg-components/ComponentsList/ComponentsList.spec.js @@ -38,7 +38,7 @@ it('should ignore items without name', () => { expect(actual).toMatchSnapshot(); }); -it('should render links to isolated component page if oneComponentPerPage passed', () => { +it('should render links to isolated component page if useIsolatedLinks passed', () => { const components = [ { name: 'Button', @@ -49,7 +49,7 @@ it('should render links to isolated component page if oneComponentPerPage passed }, ]; const actual = shallow( - + ); expect(actual).toMatchSnapshot(); diff --git a/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap b/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap index 667663ba6..f8182e20f 100644 --- a/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap +++ b/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap @@ -16,7 +16,7 @@ exports[`should ignore items without name 1`] = `
`; -exports[`should render links to isolated component page if oneComponentPerPage passed 1`] = ` +exports[`should render links to isolated component page if useIsolatedLinks passed 1`] = `
  • Button diff --git a/src/rsg-components/StyleGuide/StyleGuide.js b/src/rsg-components/StyleGuide/StyleGuide.js index 93ab7660b..413618a3d 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.js +++ b/src/rsg-components/StyleGuide/StyleGuide.js @@ -9,6 +9,29 @@ import Error from 'rsg-components/Error'; import { HOMEPAGE } from '../../../scripts/consts'; import { DisplayModes } from '../../consts'; +/** + * This function will return true, if the sidebar should be visible and false otherwise. + * + * These sorted conditions (highest precedence first) define the visibility + * state of the sidebar. + * + * - Sidebar is hidden for isolated example views + * - Sidebar is always visible when pagePerSection + * - Sidebar is hidden when showSidebar is set to false + * - Sidebar is visible when showSidebar is set to true for non-isolated views + * + * @param {boolean} displayMode + * @param {boolean} showSidebar + * @param {boolean} pagePerSection + * @returns {boolean} + */ +function hasSidebar(displayMode, showSidebar, pagePerSection = false) { + return ( + (pagePerSection && displayMode !== DisplayModes.example) || + (showSidebar && displayMode === DisplayModes.all) + ); +} + export default class StyleGuide extends Component { static propTypes = { codeRevision: PropTypes.number.isRequired, @@ -87,10 +110,7 @@ export default class StyleGuide extends Component { title={config.title} homepageUrl={HOMEPAGE} toc={} - hasSidebar={ - (pagePerSection && displayMode !== DisplayModes.example) || - (config.showSidebar && displayMode === DisplayModes.all) - } + hasSidebar={hasSidebar(displayMode, config.showSidebar, pagePerSection)} > diff --git a/src/utils/getRouteData.js b/src/utils/getRouteData.js index c85b1706b..5c3a73b72 100644 --- a/src/utils/getRouteData.js +++ b/src/utils/getRouteData.js @@ -15,7 +15,7 @@ import { DisplayModes } from '../consts'; * * @param {object} sections * @param {string} hash - * @param {bool} pagePerSection + * @param {boolean} pagePerSection * @returns {object} */ export default function getRouteData(sections, hash, pagePerSection) { diff --git a/src/utils/renderStyleguide.js b/src/utils/renderStyleguide.js index 70e97b41b..1e1a154f6 100644 --- a/src/utils/renderStyleguide.js +++ b/src/utils/renderStyleguide.js @@ -1,4 +1,3 @@ -import { isFunction } from 'lodash'; import React from 'react'; import slots from 'rsg-components/slots'; import StyleGuide from 'rsg-components/StyleGuide'; @@ -28,12 +27,11 @@ export default function renderStyleguide( // all components accessible to all examples globalizeComponents(allSections); - const { pagePerSection } = styleguide.config; - const renderPagePerSection = isFunction(pagePerSection) ? pagePerSection() : pagePerSection; - const { sections, displayMode } = getRouteData(allSections, loc.hash, renderPagePerSection); + const { title, pagePerSection } = styleguide.config; + const { sections, displayMode } = getRouteData(allSections, loc.hash, pagePerSection); // Update page title - doc.title = getPageTitle(sections, styleguide.config.title, displayMode); + doc.title = getPageTitle(sections, title, displayMode); // If the current hash location was set to just `/` (e.g. when navigating back from isolated view to overview) // replace the URL with one without hash, to present the user with a single address of the overview screen @@ -52,7 +50,7 @@ export default function renderStyleguide( sections={sections} allSections={allSections} displayMode={displayMode} - pagePerSection={renderPagePerSection} + pagePerSection={pagePerSection} /> ); } From 26c56cf3a32232c3005e0a923fb042d4115b92ef Mon Sep 17 00:00:00 2001 From: bitionaire Date: Fri, 23 Feb 2018 22:36:12 +0100 Subject: [PATCH 18/26] Modifications by PR review --- src/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index f7e44ebcf..b6b97eb3e 100644 --- a/src/index.js +++ b/src/index.js @@ -6,12 +6,13 @@ import ReactDOM from 'react-dom'; import renderStyleguide from './utils/renderStyleguide'; // Examples code revision to rerender only code examples (not the whole page) when code changes +// eslint-disable-next-line no-unused-vars let codeRevision = 0; const render = () => { // eslint-disable-next-line import/no-unresolved const styleguide = require('!!../loaders/styleguide-loader!./index.js'); - ReactDOM.render(renderStyleguide(styleguide, codeRevision), document.getElementById('app')); + ReactDOM.render(renderStyleguide(styleguide, status), document.getElementById('app')); }; window.addEventListener('hashchange', render); From dd74215e0592cf4bb1fb18a9084cf99721084475 Mon Sep 17 00:00:00 2001 From: bitionaire Date: Mon, 26 Feb 2018 09:22:11 +0100 Subject: [PATCH 19/26] Splitted URL generation and renderer --- .../ComponentsList/ComponentsList.js | 25 ++++++++ .../ComponentsList/ComponentsList.spec.js | 40 +++++++++--- .../ComponentsList/ComponentsListRenderer.js | 15 +---- .../__snapshots__/ComponentsList.spec.js.snap | 62 +++++++++++++------ src/rsg-components/ComponentsList/index.js | 2 +- .../TableOfContents.spec.js.snap | 20 +++--- 6 files changed, 112 insertions(+), 52 deletions(-) create mode 100644 src/rsg-components/ComponentsList/ComponentsList.js diff --git a/src/rsg-components/ComponentsList/ComponentsList.js b/src/rsg-components/ComponentsList/ComponentsList.js new file mode 100644 index 000000000..743e443d9 --- /dev/null +++ b/src/rsg-components/ComponentsList/ComponentsList.js @@ -0,0 +1,25 @@ +import React from 'react'; +import ComponentsListRenderer from 'rsg-components/ComponentsList/ComponentsListRenderer'; +import PropTypes from 'prop-types'; +import getUrl from '../../utils/getUrl'; + +function ComponentsList({ classes, items, useIsolatedLinks = false }) { + const mappedItems = items.map(item => ({ + ...item, + href: getUrl({ + name: item.name, + slug: item.slug, + anchor: !useIsolatedLinks, + isolated: useIsolatedLinks, + }), + })); + return ; +} + +ComponentsList.propTypes = { + classes: PropTypes.object.isRequired, + items: PropTypes.array.isRequired, + useIsolatedLinks: PropTypes.bool, +}; + +export default ComponentsList; diff --git a/src/rsg-components/ComponentsList/ComponentsList.spec.js b/src/rsg-components/ComponentsList/ComponentsList.spec.js index 21955e134..c416d0b7c 100644 --- a/src/rsg-components/ComponentsList/ComponentsList.spec.js +++ b/src/rsg-components/ComponentsList/ComponentsList.spec.js @@ -1,7 +1,8 @@ import React from 'react'; +import ComponentsList from './ComponentsList'; import { ComponentsListRenderer } from './ComponentsListRenderer'; -it('should render sections with nested components', () => { +it('should set the correct href for items', () => { const components = [ { name: 'Button', @@ -12,25 +13,38 @@ it('should render sections with nested components', () => { slug: 'input', }, ]; - const actual = shallow(); + const actual = shallow(); expect(actual).toMatchSnapshot(); }); -it('should return null when the list is empty', () => { - const actual = shallow(); +it('should set the correct href for items when isolated links should be used', () => { + const components = [ + { + name: 'Button', + slug: 'button', + }, + { + name: 'Input', + slug: 'input', + }, + ]; - expect(actual.getElement()).toBe(null); + const actual = shallow(); + expect(actual).toMatchSnapshot(); }); -it('should ignore items without name', () => { +it('should render sections with nested components', () => { const components = [ { name: 'Button', slug: 'button', + href: '#button', }, { + name: 'Input', slug: 'input', + href: '#input', }, ]; const actual = shallow(); @@ -38,19 +52,25 @@ it('should ignore items without name', () => { expect(actual).toMatchSnapshot(); }); -it('should render links to isolated component page if useIsolatedLinks passed', () => { +it('should return null when the list is empty', () => { + const actual = shallow(); + + expect(actual.getElement()).toBe(null); +}); + +it('should ignore items without name', () => { const components = [ { name: 'Button', slug: 'button', + href: '#button', }, { slug: 'input', + href: '#input', }, ]; - const actual = shallow( - - ); + const actual = shallow(); expect(actual).toMatchSnapshot(); }); diff --git a/src/rsg-components/ComponentsList/ComponentsListRenderer.js b/src/rsg-components/ComponentsList/ComponentsListRenderer.js index 1cbd19196..4b376a223 100644 --- a/src/rsg-components/ComponentsList/ComponentsListRenderer.js +++ b/src/rsg-components/ComponentsList/ComponentsListRenderer.js @@ -3,7 +3,6 @@ import PropTypes from 'prop-types'; import cx from 'classnames'; import Link from 'rsg-components/Link'; import Styled from 'rsg-components/Styled'; -import getUrl from '../../utils/getUrl'; const styles = ({ color, fontFamily, fontSize, space, mq }) => ({ list: { @@ -34,7 +33,7 @@ const styles = ({ color, fontFamily, fontSize, space, mq }) => ({ }, }); -export function ComponentsListRenderer({ classes, items, useIsolatedLinks }) { +export function ComponentsListRenderer({ classes, items }) { items = items.filter(item => item.name); if (!items.length) { @@ -43,20 +42,12 @@ export function ComponentsListRenderer({ classes, items, useIsolatedLinks }) { return (
      - {items.map(({ heading, name, slug, content }) => ( + {items.map(({ heading, name, href, content }) => (
    • - + {name} {content} diff --git a/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap b/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap index f8182e20f..8eb43c4a9 100644 --- a/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap +++ b/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap @@ -8,23 +8,7 @@ exports[`should ignore items without name 1`] = ` > - Button - -
    • -
    -`; - -exports[`should render links to isolated component page if useIsolatedLinks passed 1`] = ` -
      -
    • - Button @@ -40,7 +24,7 @@ exports[`should render sections with nested components 1`] = ` > Button @@ -51,10 +35,50 @@ exports[`should render sections with nested components 1`] = ` > Input
    `; + +exports[`should set the correct href for items 1`] = ` + +`; + +exports[`should set the correct href for items when isolated links should be used 1`] = ` + +`; diff --git a/src/rsg-components/ComponentsList/index.js b/src/rsg-components/ComponentsList/index.js index 96588be8e..d3a857a30 100644 --- a/src/rsg-components/ComponentsList/index.js +++ b/src/rsg-components/ComponentsList/index.js @@ -1 +1 @@ -export { default } from 'rsg-components/ComponentsList/ComponentsListRenderer'; +export { default } from './ComponentsList.js'; diff --git a/src/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.js.snap b/src/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.js.snap index 4b7c35baf..027fda5da 100644 --- a/src/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.js.snap +++ b/src/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.js.snap @@ -19,7 +19,7 @@ exports[`should filter list when search field contains a query 1`] = ` onSearchTermChange={[Function]} searchTerm="" > - - - - - - Date: Mon, 26 Feb 2018 10:42:02 +0100 Subject: [PATCH 20/26] Replaced renderStyleguide SFC by and moved scrollTo logic into App --- src/index.js | 8 +- src/rsg-components/App/App.js | 78 ++++++++ src/rsg-components/App/App.spec.js | 180 ++++++++++++++++++ .../App/__snapshots__/App.spec.js.snap | 107 +++++++++++ src/rsg-components/App/index.js | 1 + .../ComponentsList/ComponentsList.js | 2 +- src/rsg-components/StyleGuide/StyleGuide.js | 10 - .../StyleGuide/StyleGuide.spec.js | 40 ---- src/utils/__tests__/renderStyleguide.spec.js | 88 --------- src/utils/renderStyleguide.js | 56 ------ 10 files changed, 373 insertions(+), 197 deletions(-) create mode 100644 src/rsg-components/App/App.js create mode 100644 src/rsg-components/App/App.spec.js create mode 100644 src/rsg-components/App/__snapshots__/App.spec.js.snap create mode 100644 src/rsg-components/App/index.js delete mode 100644 src/utils/__tests__/renderStyleguide.spec.js delete mode 100644 src/utils/renderStyleguide.js diff --git a/src/index.js b/src/index.js index b6b97eb3e..a51ef5bb9 100644 --- a/src/index.js +++ b/src/index.js @@ -2,8 +2,9 @@ import './polyfills'; import './styles'; +import React from 'react'; import ReactDOM from 'react-dom'; -import renderStyleguide from './utils/renderStyleguide'; +import App from './rsg-components/App'; // Examples code revision to rerender only code examples (not the whole page) when code changes // eslint-disable-next-line no-unused-vars @@ -12,7 +13,10 @@ let codeRevision = 0; const render = () => { // eslint-disable-next-line import/no-unresolved const styleguide = require('!!../loaders/styleguide-loader!./index.js'); - ReactDOM.render(renderStyleguide(styleguide, status), document.getElementById('app')); + ReactDOM.render( + , + document.getElementById('app') + ); }; window.addEventListener('hashchange', render); diff --git a/src/rsg-components/App/App.js b/src/rsg-components/App/App.js new file mode 100644 index 000000000..f29dc9e4c --- /dev/null +++ b/src/rsg-components/App/App.js @@ -0,0 +1,78 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { isFunction } from 'lodash'; +import slots from 'rsg-components/slots'; +import StyleGuide from 'rsg-components/StyleGuide'; +import getPageTitle from '../../utils/getPageTitle'; +import getRouteData from '../../utils/getRouteData'; +import globalizeComponents from '../../utils/globalizeComponents'; +import processSections from '../../utils/processSections'; + +export default class App extends Component { + static propTypes = { + /** Object returned by styleguide-loader */ + styleguide: PropTypes.object.isRequired, + codeRevision: PropTypes.number.isRequired, + loc: PropTypes.object, + doc: PropTypes.object, + hist: PropTypes.object, + }; + + static defaultProps = { + loc: window.location, + doc: document, + hist: window.history, + }; + + constructor(props) { + super(props); + this.lastHash = props.loc.hash; + } + + componentDidUpdate() { + // scroll to top of styleguide container when sections changed + if (this.props.styleguide.config.pagePerSection && this.props.loc.hash !== this.lastHash) { + if (window && isFunction(window.scrollTo)) { + window.scrollTo(0, 0); + } + } + this.currentHash = this.props.loc.hash; + } + + render() { + const { styleguide, codeRevision, loc, doc, hist } = this.props; + + const allSections = processSections(styleguide.sections); + + // Globalize all components, not just ones we see on the screen, to make + // all components accessible to all examples + globalizeComponents(allSections); + + const { title, pagePerSection } = styleguide.config; + const { sections, displayMode } = getRouteData(allSections, loc.hash, pagePerSection); + + // Update page title + doc.title = getPageTitle(sections, title, displayMode); + + // If the current hash location was set to just `/` (e.g. when navigating back from isolated view to overview) + // replace the URL with one without hash, to present the user with a single address of the overview screen + if (loc.hash === '#/') { + const url = loc.pathname + loc.search; + hist.replaceState('', doc.title, url); + } + + return ( + + ); + } +} diff --git a/src/rsg-components/App/App.spec.js b/src/rsg-components/App/App.spec.js new file mode 100644 index 000000000..3bc0872c9 --- /dev/null +++ b/src/rsg-components/App/App.spec.js @@ -0,0 +1,180 @@ +import React from 'react'; +import { cloneDeep } from 'lodash'; +import App from './App'; + +const styleguide = { + config: { + title: 'My Style Guide', + }, + sections: [ + { + components: [ + { + props: { + displayName: 'Button', + }, + module: 'ButtonModule', + }, + { + props: { + displayName: 'Image', + }, + module: 'ImageModule', + }, + ], + }, + ], + welcomeScreen: false, + patterns: ['button', 'input'], +}; +const codeRevision = 1; +const location = { + hash: '', +}; +const doc = { + title: () => {}, +}; +const history = { + replaceState: () => {}, +}; + +afterEach(() => { + delete global.Button; + delete global.Image; +}); + +describe('', () => { + it('should render StyleGuide component', () => { + const result = shallow( + + ); + expect(result).toMatchSnapshot(); + }); + + it('should globalize all components', () => { + shallow( + + ); + expect(global.Button).toBe('ButtonModule'); + expect(global.Image).toBe('ImageModule'); + }); + + it('should globalize all components in isolated mode', () => { + shallow( + + ); + expect(global.Button).toBe('ButtonModule'); + expect(global.Image).toBe('ImageModule'); + }); + + it('should change document title', () => { + const title = jest.fn(); + const location = { hash: '' }; + Object.defineProperty(location, 'title', { + set: title, + }); + shallow( + + ); + expect(title).toBeCalledWith('My Style Guide'); + }); + + it('should change document title in isolated mode', () => { + const title = jest.fn(); + const location = { hash: '#!/Button' }; + Object.defineProperty(location, 'title', { + set: title, + }); + shallow( + + ); + expect(title).toBeCalledWith('Button — My Style Guide'); + }); + + it('should remove #/ from the address bar', () => { + const location = { hash: '#/', pathname: '/pizza', search: '?foo=bar' }; + const history = { replaceState: jest.fn() }; + shallow( + + ); + expect(history.replaceState).toBeCalledWith('', 'My Style Guide', '/pizza?foo=bar'); + }); + + it('should scroll to top on sections change, when pagePerSections is true', () => { + const scrollTo = jest.fn(); + global.window.scrollTo = scrollTo; + + const styleguideCopy = cloneDeep(styleguide); + styleguideCopy.config.pagePerSection = true; + + const props = { + styleguide: styleguideCopy, + codeRevision, + loc: { hash: '#A' }, + doc, + hist: history, + }; + + const wrapper = shallow(); + wrapper.setProps({ ...props, loc: { hash: '#B' } }); + + expect(scrollTo).toHaveBeenCalled(); + }); + + it('should not scroll to top on sections change, when pagePerSections is false', () => { + const scrollTo = jest.fn(); + global.window.scrollTo = scrollTo; + + const styleguideCopy = cloneDeep(styleguide); + styleguideCopy.config.pagePerSection = false; + + const props = { + styleguide: styleguideCopy, + codeRevision, + loc: { hash: '#A' }, + doc, + hist: history, + }; + + const wrapper = shallow(); + wrapper.setProps({ ...props, loc: { hash: '#B' } }); + + expect(scrollTo).not.toHaveBeenCalled(); + }); +}); diff --git a/src/rsg-components/App/__snapshots__/App.spec.js.snap b/src/rsg-components/App/__snapshots__/App.spec.js.snap new file mode 100644 index 000000000..2a10d32f7 --- /dev/null +++ b/src/rsg-components/App/__snapshots__/App.spec.js.snap @@ -0,0 +1,107 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` should render StyleGuide component 1`] = ` + +`; diff --git a/src/rsg-components/App/index.js b/src/rsg-components/App/index.js new file mode 100644 index 000000000..7dd82298c --- /dev/null +++ b/src/rsg-components/App/index.js @@ -0,0 +1 @@ +export { default } from './App.js'; diff --git a/src/rsg-components/ComponentsList/ComponentsList.js b/src/rsg-components/ComponentsList/ComponentsList.js index 743e443d9..dcad24b95 100644 --- a/src/rsg-components/ComponentsList/ComponentsList.js +++ b/src/rsg-components/ComponentsList/ComponentsList.js @@ -17,8 +17,8 @@ function ComponentsList({ classes, items, useIsolatedLinks = false }) { } ComponentsList.propTypes = { - classes: PropTypes.object.isRequired, items: PropTypes.array.isRequired, + classes: PropTypes.object, useIsolatedLinks: PropTypes.bool, }; diff --git a/src/rsg-components/StyleGuide/StyleGuide.js b/src/rsg-components/StyleGuide/StyleGuide.js index 413618a3d..a2cd89547 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.js +++ b/src/rsg-components/StyleGuide/StyleGuide.js @@ -1,4 +1,3 @@ -import { isEqual, isFunction } from 'lodash'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; import TableOfContents from 'rsg-components/TableOfContents'; @@ -70,15 +69,6 @@ export default class StyleGuide extends Component { }; } - componentDidUpdate(prevProps) { - // scroll to top of styleguide container when sections changed - if (this.props.pagePerSection && !isEqual(this.props.sections, prevProps.sections)) { - if (window && isFunction(window.scrollTo)) { - window.scrollTo(0, 0); - } - } - } - componentDidCatch(error, info) { this.setState({ error, diff --git a/src/rsg-components/StyleGuide/StyleGuide.spec.js b/src/rsg-components/StyleGuide/StyleGuide.spec.js index 5dd440f77..85780e287 100644 --- a/src/rsg-components/StyleGuide/StyleGuide.spec.js +++ b/src/rsg-components/StyleGuide/StyleGuide.spec.js @@ -71,46 +71,6 @@ it('should render an error when componentDidCatch() is triggered', () => { expect(wrapper).toMatchSnapshot(); }); -it('should scroll to top on sections change, when pagePerSections is true', () => { - const scrollTo = jest.fn(); - global.window.scrollTo = scrollTo; - - const props = { - codeRevision: 1, - config, - sections: [], - allSections: [], - slots: {}, - pagePerSection: true, - }; - - const wrapper = shallow(); - - wrapper.instance().componentDidUpdate({ ...props, sections }); - - expect(scrollTo.mock.calls.length).toBe(1); -}); - -it('should not scroll to top on sections change, when pagePerSections is false', () => { - const scrollTo = jest.fn(); - global.window.scrollTo = scrollTo; - - const props = { - codeRevision: 1, - config, - sections: [], - allSections: [], - slots: {}, - pagePerSection: false, - }; - - const wrapper = shallow(); - - wrapper.instance().componentDidUpdate({ ...props, sections }); - - expect(scrollTo.mock.calls.length).toBe(0); -}); - describe('sidebar rendering', () => { it('renderer should have sidebar if showSidebar is not set', () => { const wrapper = shallow( diff --git a/src/utils/__tests__/renderStyleguide.spec.js b/src/utils/__tests__/renderStyleguide.spec.js deleted file mode 100644 index 3ed7dfba2..000000000 --- a/src/utils/__tests__/renderStyleguide.spec.js +++ /dev/null @@ -1,88 +0,0 @@ -import renderStyleguide from '../renderStyleguide'; - -const styleguide = { - config: { - title: 'My Style Guide', - }, - sections: [ - { - components: [ - { - props: { - displayName: 'Button', - }, - module: 'ButtonModule', - }, - { - props: { - displayName: 'Image', - }, - module: 'ImageModule', - }, - ], - }, - ], - welcomeScreen: false, - patterns: ['button', 'input'], -}; -const codeRevision = 1; -const location = { - hash: '', -}; -const doc = { - title: () => {}, -}; -const history = { - replaceState: () => {}, -}; - -afterEach(() => { - delete global.Button; - delete global.Image; -}); - -describe('renderStyleguide', () => { - it('should render StyleGuide component', () => { - const result = shallow(renderStyleguide(styleguide, codeRevision, location, doc, history)); - expect(result).toMatchSnapshot(); - }); - - it('should globalize all components', () => { - renderStyleguide(styleguide, codeRevision, location, doc, history); - expect(global.Button).toBe('ButtonModule'); - expect(global.Image).toBe('ImageModule'); - }); - - it('should globalize all components in isolated mode', () => { - renderStyleguide(styleguide, codeRevision, { hash: '#!/Button' }, doc, history); - expect(global.Button).toBe('ButtonModule'); - expect(global.Image).toBe('ImageModule'); - }); - - it('should change document title', () => { - const title = jest.fn(); - const location = { hash: '' }; - Object.defineProperty(location, 'title', { - set: title, - }); - renderStyleguide(styleguide, codeRevision, location, location, history); - expect(title).toBeCalledWith('My Style Guide'); - }); - - it('should change document title in isolated mode', () => { - const title = jest.fn(); - const location = { hash: '#!/Button' }; - Object.defineProperty(location, 'title', { - set: title, - }); - renderStyleguide(styleguide, codeRevision, location, location, history); - expect(title).toBeCalledWith('Button — My Style Guide'); - }); - - it('should remove #/ from the address bar', () => { - const location = { hash: '#/', pathname: '/pizza', search: '?foo=bar' }; - const history = { replaceState: jest.fn() }; - renderStyleguide(styleguide, codeRevision, location, location, history); - expect(history.replaceState).toBeCalledWith('', 'My Style Guide', '/pizza?foo=bar'); - }); -}); diff --git a/src/utils/renderStyleguide.js b/src/utils/renderStyleguide.js deleted file mode 100644 index 1e1a154f6..000000000 --- a/src/utils/renderStyleguide.js +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; -import slots from 'rsg-components/slots'; -import StyleGuide from 'rsg-components/StyleGuide'; -import getPageTitle from './getPageTitle'; -import getRouteData from './getRouteData'; -import globalizeComponents from './globalizeComponents'; -import processSections from './processSections'; - -/** - * @param {object} styleguide An object returned by styleguide-loader - * @param {number} codeRevision - * @param {Location} [loc] - * @param {Document} [doc] - * @param {History} [hist] - * @return {React.ReactElement} - */ -export default function renderStyleguide( - styleguide, - codeRevision, - loc = window.location, - doc = document, - hist = window.history -) { - const allSections = processSections(styleguide.sections); - - // Globalize all components, not just ones we see on the screen, to make - // all components accessible to all examples - globalizeComponents(allSections); - - const { title, pagePerSection } = styleguide.config; - const { sections, displayMode } = getRouteData(allSections, loc.hash, pagePerSection); - - // Update page title - doc.title = getPageTitle(sections, title, displayMode); - - // If the current hash location was set to just `/` (e.g. when navigating back from isolated view to overview) - // replace the URL with one without hash, to present the user with a single address of the overview screen - if (loc.hash === '#/') { - const url = loc.pathname + loc.search; - hist.replaceState('', doc.title, url); - } - - return ( - - ); -} From 5eb2744afac28bc4abd9e2a59958d0259d519e37 Mon Sep 17 00:00:00 2001 From: bitionaire Date: Mon, 26 Feb 2018 16:06:51 +0100 Subject: [PATCH 21/26] Removed unused snapshot file --- .../renderStyleguide.spec.js.snap | 67 ------------------- 1 file changed, 67 deletions(-) delete mode 100644 src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap diff --git a/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap b/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap deleted file mode 100644 index a2416be1b..000000000 --- a/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap +++ /dev/null @@ -1,67 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renderStyleguide should render StyleGuide component 1`] = ` - - } -> - - -`; From aaac44b314a233e2793667878eecb16cd46ffdde Mon Sep 17 00:00:00 2001 From: bitionaire Date: Fri, 2 Mar 2018 14:10:42 +0100 Subject: [PATCH 22/26] Reverted changes --- src/index.js | 12 +- src/rsg-components/App/App.js | 78 -------- src/rsg-components/App/App.spec.js | 180 ------------------ .../App/__snapshots__/App.spec.js.snap | 107 ----------- src/rsg-components/App/index.js | 1 - src/utils/__tests__/renderStyleguide.spec.js | 88 +++++++++ src/utils/renderStyleguide.js | 56 ++++++ 7 files changed, 150 insertions(+), 372 deletions(-) delete mode 100644 src/rsg-components/App/App.js delete mode 100644 src/rsg-components/App/App.spec.js delete mode 100644 src/rsg-components/App/__snapshots__/App.spec.js.snap delete mode 100644 src/rsg-components/App/index.js create mode 100644 src/utils/__tests__/renderStyleguide.spec.js create mode 100644 src/utils/renderStyleguide.js diff --git a/src/index.js b/src/index.js index a51ef5bb9..f4e6aaa65 100644 --- a/src/index.js +++ b/src/index.js @@ -2,9 +2,9 @@ import './polyfills'; import './styles'; -import React from 'react'; import ReactDOM from 'react-dom'; -import App from './rsg-components/App'; +import renderStyleguide from './utils/renderStyleguide'; +import { get } from 'lodash'; // Examples code revision to rerender only code examples (not the whole page) when code changes // eslint-disable-next-line no-unused-vars @@ -13,10 +13,10 @@ let codeRevision = 0; const render = () => { // eslint-disable-next-line import/no-unresolved const styleguide = require('!!../loaders/styleguide-loader!./index.js'); - ReactDOM.render( - , - document.getElementById('app') - ); + ReactDOM.render(renderStyleguide(styleguide, status), document.getElementById('app')); + if (get(window, 'location.hash', '').startsWith('#!/')) { + window.scrollTo(0, 0); + } }; window.addEventListener('hashchange', render); diff --git a/src/rsg-components/App/App.js b/src/rsg-components/App/App.js deleted file mode 100644 index f29dc9e4c..000000000 --- a/src/rsg-components/App/App.js +++ /dev/null @@ -1,78 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { isFunction } from 'lodash'; -import slots from 'rsg-components/slots'; -import StyleGuide from 'rsg-components/StyleGuide'; -import getPageTitle from '../../utils/getPageTitle'; -import getRouteData from '../../utils/getRouteData'; -import globalizeComponents from '../../utils/globalizeComponents'; -import processSections from '../../utils/processSections'; - -export default class App extends Component { - static propTypes = { - /** Object returned by styleguide-loader */ - styleguide: PropTypes.object.isRequired, - codeRevision: PropTypes.number.isRequired, - loc: PropTypes.object, - doc: PropTypes.object, - hist: PropTypes.object, - }; - - static defaultProps = { - loc: window.location, - doc: document, - hist: window.history, - }; - - constructor(props) { - super(props); - this.lastHash = props.loc.hash; - } - - componentDidUpdate() { - // scroll to top of styleguide container when sections changed - if (this.props.styleguide.config.pagePerSection && this.props.loc.hash !== this.lastHash) { - if (window && isFunction(window.scrollTo)) { - window.scrollTo(0, 0); - } - } - this.currentHash = this.props.loc.hash; - } - - render() { - const { styleguide, codeRevision, loc, doc, hist } = this.props; - - const allSections = processSections(styleguide.sections); - - // Globalize all components, not just ones we see on the screen, to make - // all components accessible to all examples - globalizeComponents(allSections); - - const { title, pagePerSection } = styleguide.config; - const { sections, displayMode } = getRouteData(allSections, loc.hash, pagePerSection); - - // Update page title - doc.title = getPageTitle(sections, title, displayMode); - - // If the current hash location was set to just `/` (e.g. when navigating back from isolated view to overview) - // replace the URL with one without hash, to present the user with a single address of the overview screen - if (loc.hash === '#/') { - const url = loc.pathname + loc.search; - hist.replaceState('', doc.title, url); - } - - return ( - - ); - } -} diff --git a/src/rsg-components/App/App.spec.js b/src/rsg-components/App/App.spec.js deleted file mode 100644 index 3bc0872c9..000000000 --- a/src/rsg-components/App/App.spec.js +++ /dev/null @@ -1,180 +0,0 @@ -import React from 'react'; -import { cloneDeep } from 'lodash'; -import App from './App'; - -const styleguide = { - config: { - title: 'My Style Guide', - }, - sections: [ - { - components: [ - { - props: { - displayName: 'Button', - }, - module: 'ButtonModule', - }, - { - props: { - displayName: 'Image', - }, - module: 'ImageModule', - }, - ], - }, - ], - welcomeScreen: false, - patterns: ['button', 'input'], -}; -const codeRevision = 1; -const location = { - hash: '', -}; -const doc = { - title: () => {}, -}; -const history = { - replaceState: () => {}, -}; - -afterEach(() => { - delete global.Button; - delete global.Image; -}); - -describe('', () => { - it('should render StyleGuide component', () => { - const result = shallow( - - ); - expect(result).toMatchSnapshot(); - }); - - it('should globalize all components', () => { - shallow( - - ); - expect(global.Button).toBe('ButtonModule'); - expect(global.Image).toBe('ImageModule'); - }); - - it('should globalize all components in isolated mode', () => { - shallow( - - ); - expect(global.Button).toBe('ButtonModule'); - expect(global.Image).toBe('ImageModule'); - }); - - it('should change document title', () => { - const title = jest.fn(); - const location = { hash: '' }; - Object.defineProperty(location, 'title', { - set: title, - }); - shallow( - - ); - expect(title).toBeCalledWith('My Style Guide'); - }); - - it('should change document title in isolated mode', () => { - const title = jest.fn(); - const location = { hash: '#!/Button' }; - Object.defineProperty(location, 'title', { - set: title, - }); - shallow( - - ); - expect(title).toBeCalledWith('Button — My Style Guide'); - }); - - it('should remove #/ from the address bar', () => { - const location = { hash: '#/', pathname: '/pizza', search: '?foo=bar' }; - const history = { replaceState: jest.fn() }; - shallow( - - ); - expect(history.replaceState).toBeCalledWith('', 'My Style Guide', '/pizza?foo=bar'); - }); - - it('should scroll to top on sections change, when pagePerSections is true', () => { - const scrollTo = jest.fn(); - global.window.scrollTo = scrollTo; - - const styleguideCopy = cloneDeep(styleguide); - styleguideCopy.config.pagePerSection = true; - - const props = { - styleguide: styleguideCopy, - codeRevision, - loc: { hash: '#A' }, - doc, - hist: history, - }; - - const wrapper = shallow(); - wrapper.setProps({ ...props, loc: { hash: '#B' } }); - - expect(scrollTo).toHaveBeenCalled(); - }); - - it('should not scroll to top on sections change, when pagePerSections is false', () => { - const scrollTo = jest.fn(); - global.window.scrollTo = scrollTo; - - const styleguideCopy = cloneDeep(styleguide); - styleguideCopy.config.pagePerSection = false; - - const props = { - styleguide: styleguideCopy, - codeRevision, - loc: { hash: '#A' }, - doc, - hist: history, - }; - - const wrapper = shallow(); - wrapper.setProps({ ...props, loc: { hash: '#B' } }); - - expect(scrollTo).not.toHaveBeenCalled(); - }); -}); diff --git a/src/rsg-components/App/__snapshots__/App.spec.js.snap b/src/rsg-components/App/__snapshots__/App.spec.js.snap deleted file mode 100644 index 2a10d32f7..000000000 --- a/src/rsg-components/App/__snapshots__/App.spec.js.snap +++ /dev/null @@ -1,107 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` should render StyleGuide component 1`] = ` - -`; diff --git a/src/rsg-components/App/index.js b/src/rsg-components/App/index.js deleted file mode 100644 index 7dd82298c..000000000 --- a/src/rsg-components/App/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './App.js'; diff --git a/src/utils/__tests__/renderStyleguide.spec.js b/src/utils/__tests__/renderStyleguide.spec.js new file mode 100644 index 000000000..3ed7dfba2 --- /dev/null +++ b/src/utils/__tests__/renderStyleguide.spec.js @@ -0,0 +1,88 @@ +import renderStyleguide from '../renderStyleguide'; + +const styleguide = { + config: { + title: 'My Style Guide', + }, + sections: [ + { + components: [ + { + props: { + displayName: 'Button', + }, + module: 'ButtonModule', + }, + { + props: { + displayName: 'Image', + }, + module: 'ImageModule', + }, + ], + }, + ], + welcomeScreen: false, + patterns: ['button', 'input'], +}; +const codeRevision = 1; +const location = { + hash: '', +}; +const doc = { + title: () => {}, +}; +const history = { + replaceState: () => {}, +}; + +afterEach(() => { + delete global.Button; + delete global.Image; +}); + +describe('renderStyleguide', () => { + it('should render StyleGuide component', () => { + const result = shallow(renderStyleguide(styleguide, codeRevision, location, doc, history)); + expect(result).toMatchSnapshot(); + }); + + it('should globalize all components', () => { + renderStyleguide(styleguide, codeRevision, location, doc, history); + expect(global.Button).toBe('ButtonModule'); + expect(global.Image).toBe('ImageModule'); + }); + + it('should globalize all components in isolated mode', () => { + renderStyleguide(styleguide, codeRevision, { hash: '#!/Button' }, doc, history); + expect(global.Button).toBe('ButtonModule'); + expect(global.Image).toBe('ImageModule'); + }); + + it('should change document title', () => { + const title = jest.fn(); + const location = { hash: '' }; + Object.defineProperty(location, 'title', { + set: title, + }); + renderStyleguide(styleguide, codeRevision, location, location, history); + expect(title).toBeCalledWith('My Style Guide'); + }); + + it('should change document title in isolated mode', () => { + const title = jest.fn(); + const location = { hash: '#!/Button' }; + Object.defineProperty(location, 'title', { + set: title, + }); + renderStyleguide(styleguide, codeRevision, location, location, history); + expect(title).toBeCalledWith('Button — My Style Guide'); + }); + + it('should remove #/ from the address bar', () => { + const location = { hash: '#/', pathname: '/pizza', search: '?foo=bar' }; + const history = { replaceState: jest.fn() }; + renderStyleguide(styleguide, codeRevision, location, location, history); + expect(history.replaceState).toBeCalledWith('', 'My Style Guide', '/pizza?foo=bar'); + }); +}); diff --git a/src/utils/renderStyleguide.js b/src/utils/renderStyleguide.js new file mode 100644 index 000000000..1e1a154f6 --- /dev/null +++ b/src/utils/renderStyleguide.js @@ -0,0 +1,56 @@ +import React from 'react'; +import slots from 'rsg-components/slots'; +import StyleGuide from 'rsg-components/StyleGuide'; +import getPageTitle from './getPageTitle'; +import getRouteData from './getRouteData'; +import globalizeComponents from './globalizeComponents'; +import processSections from './processSections'; + +/** + * @param {object} styleguide An object returned by styleguide-loader + * @param {number} codeRevision + * @param {Location} [loc] + * @param {Document} [doc] + * @param {History} [hist] + * @return {React.ReactElement} + */ +export default function renderStyleguide( + styleguide, + codeRevision, + loc = window.location, + doc = document, + hist = window.history +) { + const allSections = processSections(styleguide.sections); + + // Globalize all components, not just ones we see on the screen, to make + // all components accessible to all examples + globalizeComponents(allSections); + + const { title, pagePerSection } = styleguide.config; + const { sections, displayMode } = getRouteData(allSections, loc.hash, pagePerSection); + + // Update page title + doc.title = getPageTitle(sections, title, displayMode); + + // If the current hash location was set to just `/` (e.g. when navigating back from isolated view to overview) + // replace the URL with one without hash, to present the user with a single address of the overview screen + if (loc.hash === '#/') { + const url = loc.pathname + loc.search; + hist.replaceState('', doc.title, url); + } + + return ( + + ); +} From c2984df3a051b05e054841e188426e579c194167 Mon Sep 17 00:00:00 2001 From: bitionaire Date: Fri, 2 Mar 2018 15:45:09 +0100 Subject: [PATCH 23/26] Added snapshot --- .../renderStyleguide.spec.js.snap | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap diff --git a/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap b/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap new file mode 100644 index 000000000..a2416be1b --- /dev/null +++ b/src/utils/__tests__/__snapshots__/renderStyleguide.spec.js.snap @@ -0,0 +1,67 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renderStyleguide should render StyleGuide component 1`] = ` + + } +> + + +`; From 5bd367fabbfcb50a10ada53ca8d93dfe57c133fd Mon Sep 17 00:00:00 2001 From: bitionaire Date: Fri, 2 Mar 2018 19:56:39 +0100 Subject: [PATCH 24/26] Fixes by PR review --- src/index.js | 15 ++++++++------ src/rsg-components/ComponentsList/index.js | 2 +- src/utils/getRouteData.js | 23 ++++++++++++++-------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/index.js b/src/index.js index f4e6aaa65..ccaf2659b 100644 --- a/src/index.js +++ b/src/index.js @@ -1,25 +1,28 @@ /* eslint-disable import/first */ - import './polyfills'; import './styles'; import ReactDOM from 'react-dom'; import renderStyleguide from './utils/renderStyleguide'; -import { get } from 'lodash'; // Examples code revision to rerender only code examples (not the whole page) when code changes // eslint-disable-next-line no-unused-vars let codeRevision = 0; +/** Scrolls to origin when current window location hash points to an isolated view. */ +const scrollToOrigin = () => { + if (window.location.hash.startsWith('#!/')) { + window.scrollTo(0, 0); + } +}; + const render = () => { // eslint-disable-next-line import/no-unresolved const styleguide = require('!!../loaders/styleguide-loader!./index.js'); - ReactDOM.render(renderStyleguide(styleguide, status), document.getElementById('app')); - if (get(window, 'location.hash', '').startsWith('#!/')) { - window.scrollTo(0, 0); - } + ReactDOM.render(renderStyleguide(styleguide, codeRevision), document.getElementById('app')); }; window.addEventListener('hashchange', render); +window.addEventListener('hashchange', scrollToOrigin); /* istanbul ignore if */ if (module.hot) { diff --git a/src/rsg-components/ComponentsList/index.js b/src/rsg-components/ComponentsList/index.js index d3a857a30..564ab475c 100644 --- a/src/rsg-components/ComponentsList/index.js +++ b/src/rsg-components/ComponentsList/index.js @@ -1 +1 @@ -export { default } from './ComponentsList.js'; +export { default } from 'rsg-components/ComponentsList/ComponentsList'; diff --git a/src/utils/getRouteData.js b/src/utils/getRouteData.js index 5c3a73b72..23d8276f7 100644 --- a/src/utils/getRouteData.js +++ b/src/utils/getRouteData.js @@ -6,6 +6,21 @@ import findSection from './findSection'; import getInfoFromHash from './getInfoFromHash'; import { DisplayModes } from '../consts'; +/** + * Returns the first element of the sections, which can be one of section or + * component. + * + * @param {object} sections + * @returns {object} + */ +const getFirstSectionOrComponent = sections => { + const firstSection = sections[0]; + if (firstSection.components && firstSection.components.length > 0) { + return { ...firstSection, components: [firstSection.components[0]] }; + } + return firstSection; +}; + /** * Return sections / components / examples to show on a screen according to a current route. * @@ -58,11 +73,3 @@ export default function getRouteData(sections, hash, pagePerSection) { return { sections, displayMode }; } - -function getFirstSectionOrComponent(sections) { - const firstSection = sections[0]; - if (firstSection.components && firstSection.components.length > 0) { - return { ...firstSection, components: [firstSection.components[0]] }; - } - return firstSection; -} From 0c03a66e4bdbb7f14851b9a361ada240d7d5a5a8 Mon Sep 17 00:00:00 2001 From: bitionaire Date: Sat, 3 Mar 2018 16:06:53 +0100 Subject: [PATCH 25/26] Replaced startsWith with indexOf === 0 --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index ccaf2659b..fa6caa64b 100644 --- a/src/index.js +++ b/src/index.js @@ -10,7 +10,7 @@ let codeRevision = 0; /** Scrolls to origin when current window location hash points to an isolated view. */ const scrollToOrigin = () => { - if (window.location.hash.startsWith('#!/')) { + if (window.location.hash.indexOf('#!/') === 0) { window.scrollTo(0, 0); } }; From 6c6e5a7369a19b43d9caa536cd014b7a4e67e2cb Mon Sep 17 00:00:00 2001 From: bitionaire Date: Fri, 9 Mar 2018 10:52:20 +0100 Subject: [PATCH 26/26] Hide IsolateButton when pagePerSection is true --- .../Playground/Playground.spec.js | 2 +- src/rsg-components/slots/index.js | 60 ++++++++++--------- src/rsg-components/slots/index.spec.js | 18 ++++++ src/utils/renderStyleguide.js | 2 +- 4 files changed, 51 insertions(+), 31 deletions(-) create mode 100644 src/rsg-components/slots/index.spec.js diff --git a/src/rsg-components/Playground/Playground.spec.js b/src/rsg-components/Playground/Playground.spec.js index f02b2ced9..0df35c82c 100644 --- a/src/rsg-components/Playground/Playground.spec.js +++ b/src/rsg-components/Playground/Playground.spec.js @@ -23,7 +23,7 @@ const options = { highlightTheme: 'base16-light', }, codeRevision: 0, - slots, + slots: slots({}), }, childContextTypes: { slots: PropTypes.object.isRequired, diff --git a/src/rsg-components/slots/index.js b/src/rsg-components/slots/index.js index 838c4c68f..0301f39d8 100644 --- a/src/rsg-components/slots/index.js +++ b/src/rsg-components/slots/index.js @@ -7,34 +7,36 @@ import UsageTabButton from './UsageTabButton'; export const EXAMPLE_TAB_CODE_EDITOR = 'rsg-code-editor'; export const DOCS_TAB_USAGE = 'rsg-usage'; -const toolbar = [IsolateButton]; +export default ({ pagePerSection }) => { + const toolbar = pagePerSection ? [] : [IsolateButton]; -export default { - sectionToolbar: toolbar, - componentToolbar: toolbar, - exampleToolbar: toolbar, - exampleTabButtons: [ - { - id: EXAMPLE_TAB_CODE_EDITOR, - render: CodeTabButton, - }, - ], - exampleTabs: [ - { - id: EXAMPLE_TAB_CODE_EDITOR, - render: Editor, - }, - ], - docsTabButtons: [ - { - id: DOCS_TAB_USAGE, - render: UsageTabButton, - }, - ], - docsTabs: [ - { - id: DOCS_TAB_USAGE, - render: Usage, - }, - ], + return { + sectionToolbar: toolbar, + componentToolbar: toolbar, + exampleToolbar: toolbar, + exampleTabButtons: [ + { + id: EXAMPLE_TAB_CODE_EDITOR, + render: CodeTabButton, + }, + ], + exampleTabs: [ + { + id: EXAMPLE_TAB_CODE_EDITOR, + render: Editor, + }, + ], + docsTabButtons: [ + { + id: DOCS_TAB_USAGE, + render: UsageTabButton, + }, + ], + docsTabs: [ + { + id: DOCS_TAB_USAGE, + render: Usage, + }, + ], + }; }; diff --git a/src/rsg-components/slots/index.spec.js b/src/rsg-components/slots/index.spec.js new file mode 100644 index 000000000..eda6fe19a --- /dev/null +++ b/src/rsg-components/slots/index.spec.js @@ -0,0 +1,18 @@ +import slots from './index'; +import IsolateButton from './IsolateButton'; + +describe('slots', () => { + it('should contain IsolateButton in toolbars if pagePerSection is false', () => { + const config = slots({ pagePerSection: false }); + expect(config.componentToolbar).toContain(IsolateButton); + expect(config.exampleToolbar).toContain(IsolateButton); + expect(config.sectionToolbar).toContain(IsolateButton); + }); + + it('should not contain IsolateButton in toolbars if pagePerSection is true', () => { + const config = slots({ pagePerSection: true }); + expect(config.componentToolbar).not.toContain(IsolateButton); + expect(config.exampleToolbar).not.toContain(IsolateButton); + expect(config.sectionToolbar).not.toContain(IsolateButton); + }); +}); diff --git a/src/utils/renderStyleguide.js b/src/utils/renderStyleguide.js index 1e1a154f6..18d4c544f 100644 --- a/src/utils/renderStyleguide.js +++ b/src/utils/renderStyleguide.js @@ -44,7 +44,7 @@ export default function renderStyleguide(