Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addon-docs: Basic skeleton, UI viewMode handling #7107

Merged
merged 4 commits into from Jun 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions addons/docs/README.md
@@ -0,0 +1,3 @@
# Storybook Docs

Living documentation for your components.
39 changes: 39 additions & 0 deletions addons/docs/package.json
@@ -0,0 +1,39 @@
{
"name": "@storybook/addon-docs",
"version": "5.2.0-alpha.23",
"description": "Superior documentation for your components",
"keywords": [
"addon",
"notes",
"storybook"
],
"homepage": "https://github.com/storybookjs/storybook/tree/master/addons/docs",
"bugs": {
"url": "https://github.com/storybookjs/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybookjs/storybook.git",
"directory": "addons/docs"
},
"license": "MIT",
"main": "dist/public_api.js",
"types": "dist/public_api.d.ts",
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23"
},
"devDependencies": {
"@types/util-deprecate": "^1.0.0",
"@types/webpack-env": "^1.13.7"
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}
1 change: 1 addition & 0 deletions addons/docs/register.js
@@ -0,0 +1 @@
require('./dist/register.js');
Empty file added addons/docs/src/public_api.ts
Empty file.
12 changes: 12 additions & 0 deletions addons/docs/src/register.ts
@@ -0,0 +1,12 @@
import addons, { types } from '@storybook/addons';
import { ADDON_ID, PANEL_ID } from './shared';

addons.register(ADDON_ID, api => {
addons.add(PANEL_ID, {
type: types.TAB,
title: 'Docs',
route: ({ storyId }) => `/docs/${storyId}`,
match: ({ viewMode }) => viewMode === 'docs',
render: () => null,
});
});
3 changes: 3 additions & 0 deletions addons/docs/src/shared.ts
@@ -0,0 +1,3 @@
export const ADDON_ID = 'storybook/docs';
export const PANEL_ID = `${ADDON_ID}/panel`;
export const PARAM_KEY = `docs`;
9 changes: 9 additions & 0 deletions addons/docs/tsconfig.json
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"types": ["webpack-env"]
},
"include": ["src/**/*"],
"exclude": ["src/**.test.ts"]
}
1 change: 1 addition & 0 deletions examples/official-storybook/addons.js
@@ -1,5 +1,6 @@
import '@storybook/addon-storysource/register';
import '@storybook/addon-design-assets/register';
import '@storybook/addon-docs/register';
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
import '@storybook/addon-events/register';
Expand Down
1 change: 1 addition & 0 deletions examples/official-storybook/package.json
Expand Up @@ -22,6 +22,7 @@
"@storybook/addon-contexts": "5.2.0-alpha.23",
"@storybook/addon-cssresources": "5.2.0-alpha.23",
"@storybook/addon-design-assets": "5.2.0-alpha.23",
"@storybook/addon-docs": "5.2.0-alpha.23",
"@storybook/addon-events": "5.2.0-alpha.23",
"@storybook/addon-graphql": "5.2.0-alpha.23",
"@storybook/addon-info": "5.2.0-alpha.23",
Expand Down
@@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Storyshots Addons|Docs default 1`] = `
<div>
Click the docs tab to see the docs
</div>
`;
8 changes: 8 additions & 0 deletions examples/official-storybook/stories/addon-docs.stories.js
@@ -0,0 +1,8 @@
import React from 'react';
import { storiesOf } from '@storybook/react';

storiesOf('Addons|Docs', module)
.addParameters({
docs: () => <div>Hello docs</div>,
})
.add('default', () => <div>Click the docs tab to see the docs</div>);
4 changes: 2 additions & 2 deletions lib/client-api/src/story_store.js
Expand Up @@ -83,8 +83,8 @@ export default class StoryStore extends EventEmitter {
);
}

setSelection = ({ storyId }) => {
this._selection = { storyId };
setSelection = ({ storyId, viewMode }) => {
this._selection = { storyId, viewMode };
setTimeout(() => this.emit(Events.STORY_RENDER), 1);
};

Expand Down
79 changes: 45 additions & 34 deletions lib/core/src/client/preview/start.js
@@ -1,3 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';

import addons from '@storybook/addons';
import { navigator, window, document } from 'global';
import createChannel from '@storybook/channel-postmessage';
Expand Down Expand Up @@ -119,52 +122,60 @@ export default function start(render, { decorateStory } = {}) {
let previousKind = '';
let previousStory = '';
let previousRevision = -1;
let previousViewMode = '';

const renderMain = forceRender => {
const revision = storyStore.getRevision();
const { storyId } = storyStore.getSelection();

const { storyId, viewMode } = storyStore.getSelection();
const data = storyStore.fromId(storyId);

const { kind, name, getDecorated, id } = data || {};
const { kind, name, getDecorated, id, parameters } = data || {};

const renderContext = {
...context,
...data,
selectedKind: kind,
selectedStory: name,
parameters,
forceRender,
};

if (getDecorated) {
// Render story only if selectedKind or selectedStory have changed.
// However, we DO want the story to re-render if the store itself has changed
// (which happens at the moment when HMR occurs)
if (
!forceRender &&
revision === previousRevision &&
kind === previousKind &&
previousStory === name
) {
addons.getChannel().emit(Events.STORY_UNCHANGED, id);
return;
}

if (!forceRender && previousKind && previousStory) {
addons.getChannel().emit(Events.STORY_CHANGED, id);
}
// Render story only if selectedKind or selectedStory have changed.
// However, we DO want the story to re-render if the store itself has changed
// (which happens at the moment when HMR occurs)
if (
!forceRender &&
revision === previousRevision &&
viewMode === previousViewMode &&
kind === previousKind &&
name === previousStory
) {
addons.getChannel().emit(Events.STORY_UNCHANGED, id);
return;
}

previousRevision = revision;
previousKind = kind;
previousStory = name;
if (!forceRender && previousKind && previousStory) {
addons.getChannel().emit(Events.STORY_CHANGED, id);
}

render(renderContext);
addons.getChannel().emit(Events.STORY_RENDERED, id);
} else {
showNopreview();
addons.getChannel().emit(Events.STORY_MISSING, id);
if (viewMode === 'docs') {
const NoDocs = () => <div style={{ fontFamily: 'sans-serif' }}>No docs found</div>;
const StoryDocs = (parameters && parameters.docs) || NoDocs;
ReactDOM.render(<StoryDocs context={renderContext} />, document.getElementById('root'));
} else if (!viewMode || viewMode === 'story') {
if (getDecorated) {
render(renderContext);
addons.getChannel().emit(Events.STORY_RENDERED, id);
} else {
showNopreview();
addons.getChannel().emit(Events.STORY_MISSING, id);
}
}

previousRevision = revision;
previousKind = kind;
previousStory = name;
previousViewMode = viewMode;

if (!forceRender) {
document.documentElement.scrollTop = 0;
}
Expand All @@ -191,7 +202,7 @@ export default function start(render, { decorateStory } = {}) {
);

channel.on(Events.FORCE_RE_RENDER, forceReRender);
channel.on(Events.SET_CURRENT_STORY, ({ storyId: inputStoryId, name, kind }) => {
channel.on(Events.SET_CURRENT_STORY, ({ storyId: inputStoryId, name, kind, viewMode }) => {
let storyId = inputStoryId;
// For backwards compatibility
if (!storyId) {
Expand All @@ -201,8 +212,8 @@ export default function start(render, { decorateStory } = {}) {
storyId = deprecatedToId(kind, name);
}

storyStore.setSelection({ storyId });
setPath({ storyId });
storyStore.setSelection({ storyId, viewMode });
setPath({ storyId, viewMode });
});

// Handle keyboard shortcuts
Expand All @@ -218,8 +229,8 @@ export default function start(render, { decorateStory } = {}) {
}

storyStore.on(Events.STORY_INIT, () => {
const { storyId } = initializePath();
storyStore.setSelection({ storyId });
const { storyId, viewMode } = initializePath();
storyStore.setSelection({ storyId, viewMode });
});

storyStore.on(Events.STORY_RENDER, renderUI);
Expand Down
12 changes: 8 additions & 4 deletions lib/core/src/client/preview/url.js
Expand Up @@ -10,11 +10,15 @@ export function pathToId(path) {
return match[1];
}

export const setPath = ({ storyId }) => {
export const setPath = ({ storyId, viewMode }) => {
const { path, selectedKind, selectedStory, ...rest } = qs.parse(document.location.search, {
ignoreQueryPrefix: true,
});
const newPath = `${document.location.pathname}?${qs.stringify({ ...rest, id: storyId })}`;
const newPath = `${document.location.pathname}?${qs.stringify({
...rest,
id: storyId,
viewMode,
})}`;
history.replaceState({}, '', newPath);
};

Expand All @@ -28,11 +32,11 @@ export const parseQueryParameters = search => {

export const initializePath = () => {
const query = qs.parse(document.location.search, { ignoreQueryPrefix: true });
let { id: storyId } = query;
let { id: storyId, viewMode } = query; // eslint-disable-line prefer-const
if (!storyId) {
storyId = getIdFromLegacyQuery(query);
if (storyId) {
setPath({ storyId });
setPath({ storyId, viewMode });
}
}
return { storyId };
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/src/app.js
Expand Up @@ -66,7 +66,7 @@ const App = React.memo(({ viewMode, layout, size: { width, height } }) => {
);
});
App.propTypes = {
viewMode: PropTypes.oneOf(['story', 'info']),
viewMode: PropTypes.oneOf(['story', 'info', 'docs']),
layout: PropTypes.shape({}).isRequired,
size: PropTypes.shape({
width: PropTypes.number,
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/src/components/layout/container.js
Expand Up @@ -546,7 +546,7 @@ Layout.propTypes = {
showPanel: PropTypes.bool.isRequired,
panelPosition: PropTypes.string.isRequired,
}).isRequired,
viewMode: PropTypes.oneOf(['story', 'info']),
viewMode: PropTypes.oneOf(['story', 'info', 'docs']),
theme: PropTypes.shape({}).isRequired,
};
Layout.defaultProps = {
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/src/components/layout/desktop.js
Expand Up @@ -65,7 +65,7 @@ Desktop.propTypes = {
panelPosition: PropTypes.string.isRequired,
isToolshown: PropTypes.bool.isRequired,
}).isRequired,
viewMode: PropTypes.oneOf(['story', 'info']),
viewMode: PropTypes.oneOf(['story', 'info', 'docs']),
};
Desktop.defaultProps = {
viewMode: undefined,
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/src/components/layout/mobile.js
Expand Up @@ -201,7 +201,7 @@ Mobile.propTypes = {
render: PropTypes.func.isRequired,
})
).isRequired,
viewMode: PropTypes.oneOf(['story', 'info']),
viewMode: PropTypes.oneOf(['story', 'info', 'docs']),
options: PropTypes.shape({
initialActive: PropTypes.number,
}).isRequired,
Expand Down
Expand Up @@ -347,7 +347,7 @@ Array [
allowfullscreen=""
id="storybook-preview-iframe"
scrolling="yes"
src="http://example.com?id=string"
src="http://example.com?id=string&viewMode=story"
title="string"
/>
</div>
Expand Down Expand Up @@ -403,7 +403,7 @@ Array [
margin-left: 0;
}

.emotion-2 {
.emotion-0 {
white-space: normal;
display: -webkit-inline-box;
display: -webkit-inline-flex;
Expand Down Expand Up @@ -439,51 +439,6 @@ Array [
border-bottom-color: transparent;
}

.emotion-2:empty {
display: none;
}

.emotion-2:focus {
outline: 0 none;
border-bottom-color: #1EA7FD;
}

.emotion-0 {
white-space: normal;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
overflow: hidden;
vertical-align: top;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
text-align: center;
-webkit-text-decoration: none;
text-decoration: none;
padding: 0 15px;
text-transform: capitalize;
-webkit-transition: color 0.2s linear,border-bottom-color 0.2s linear;
transition: color 0.2s linear,border-bottom-color 0.2s linear;
height: 40px;
line-height: 12px;
cursor: pointer;
background: transparent;
border: 0 solid transparent;
border-top: 3px solid transparent;
border-bottom: 3px solid transparent;
font-weight: bold;
font-size: 13px;
color: #1EA7FD;
border-bottom-color: #1EA7FD;
}

.emotion-0:empty {
display: none;
}
Expand Down Expand Up @@ -644,7 +599,7 @@ Array [
href="/?path=/info/string"
>
<button
class="emotion-2"
class="emotion-0"
>
Notes
</button>
Expand Down Expand Up @@ -835,7 +790,7 @@ Array [
allowfullscreen=""
id="storybook-preview-iframe"
scrolling="yes"
src="http://example.com?id=string"
src="http://example.com?id=string&viewMode=story"
title="string"
/>
</div>
Expand Down