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

Self documented Storybook (A.K.A Addon Stories) #2885

Merged
merged 40 commits into from
Feb 18, 2018
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
a1f54bc
First addon stories integration
igor-dv Jan 31, 2018
65e4ea2
Add stories addon to angular
igor-dv Jan 31, 2018
c7b07bb
Add react-syntax-highlighter to highlight the story code
igor-dv Feb 1, 2018
c34ea8a
Merge branch 'master' into addon-stories
igor-dv Feb 1, 2018
b96b1da
Add to vue
igor-dv Feb 1, 2018
53d3bf3
Add to polymer
igor-dv Feb 1, 2018
06a2a8c
Merge branch 'master' into addon-stories
igor-dv Feb 1, 2018
e940e88
Change loader to parse the source with acorn and estraverse
igor-dv Feb 1, 2018
9ef5660
Merge branch 'master' into addon-stories
ndelangen Feb 2, 2018
a9d15d0
Add specific stories highlighting
igor-dv Feb 2, 2018
fe80cc1
Minor
igor-dv Feb 2, 2018
fdec309
Extract methods
igor-dv Feb 2, 2018
5733d43
Find related story kind from the AST. Only for "Literal" argument a.k…
igor-dv Feb 2, 2018
70a1723
Update snapshot
igor-dv Feb 2, 2018
c64ed23
When a kind is not extracted, we should try to get the location based…
igor-dv Feb 2, 2018
9d3c3d1
Merge branch 'master' into addon-stories
igor-dv Feb 2, 2018
a55bd44
Merge remote-tracking branch 'origin/master' into addon-stories
igor-dv Feb 4, 2018
aee3f9b
Merge branch 'master' into addon-stories
igor-dv Feb 4, 2018
3428d9e
Merge branch 'master' into addon-stories
igor-dv Feb 5, 2018
4eedfde
Create "addsMap" without unneeded indexes
igor-dv Feb 5, 2018
9c17215
Change addon name to "addon-storysource"
igor-dv Feb 5, 2018
a8b7985
Merge branch 'master' into addon-stories
igor-dv Feb 6, 2018
e060647
Merge branch 'master' into addon-stories
igor-dv Feb 6, 2018
5084477
Merge branch 'master' into addon-stories
igor-dv Feb 6, 2018
5d454d8
Merge branch 'master' into addon-stories
igor-dv Feb 7, 2018
ae8e133
Merge branch 'master' into addon-stories
igor-dv Feb 7, 2018
c16b36c
Merge branch 'master' into addon-stories
igor-dv Feb 8, 2018
249e335
Merge branch 'master' into addon-stories
igor-dv Feb 8, 2018
cb061ed
Merge remote-tracking branch 'origin/master' into addon-stories
igor-dv Feb 13, 2018
28cf468
Merge branch 'master' into addon-stories
ndelangen Feb 13, 2018
a57feee
Merge branch 'master' into addon-stories
igor-dv Feb 16, 2018
a9b9824
Merge remote-tracking branch 'origin/master' into addon-stories
igor-dv Feb 17, 2018
54e017a
Merge branch 'master' into addon-stories
Hypnosphi Feb 17, 2018
f9e6bdc
Add acorn-es7 plugin to parse decorators
igor-dv Feb 17, 2018
70ed244
Use " enforce: 'pre' ", in custom webpack configs
igor-dv Feb 17, 2018
c297e27
Add README
igor-dv Feb 17, 2018
6e50e16
Merge branch 'master' into addon-stories
igor-dv Feb 18, 2018
4aac4b2
Update integration screenshots
Hypnosphi Feb 18, 2018
603a09c
Merge branch 'master' into addon-stories
igor-dv Feb 18, 2018
e69de5a
Merge branch 'master' into addon-stories
Hypnosphi Feb 18, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions __mocks__/inject-decorator.angular-stories.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import { storiesOf } from '@storybook/angular';

@Component({
selector: 'storybook-with-ng-content',
template: `<div style="color: #1e88e5;"><ng-content></ng-content></div>`,
})
class WithNgContentComponent {}

storiesOf('Custom|ng-content', module).add('Default', () => ({
template: `<storybook-with-ng-content><h1>This is rendered in ng-content</h1></storybook-with-ng-content>`,
moduleMetadata: {
declarations: [WithNgContentComponent],
},
}));
3 changes: 3 additions & 0 deletions __mocks__/inject-decorator.no-stories.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
while(true) {
console.log("it's a kind of magic");
}
153 changes: 153 additions & 0 deletions __mocks__/inject-decorator.stories.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import { withInfo } from '@storybook/addon-info';
import { action } from '@storybook/addon-actions';

import DocgenButton from '../components/DocgenButton';
import FlowTypeButton from '../components/FlowTypeButton';
import BaseButton from '../components/BaseButton';
import TableComponent from '../components/TableComponent';

storiesOf('Addons|Info.React Docgen', module)
.add(
'Comments from PropType declarations',
withInfo(
'Comments above the PropType declarations should be extracted from the React component file itself and rendered in the Info Addon prop table'
)(() => <DocgenButton onClick={action('clicked')} label="Docgen Button" />)
)
.add(
'Comments from Flow declarations',
withInfo(
'Comments above the Flow declarations should be extracted from the React component file itself and rendered in the Info Addon prop table'
)(() => <FlowTypeButton onClick={action('clicked')} label="Flow Typed Button" />)
)
.add(
'Comments from component declaration',
withInfo(
'Comments above the component declaration should be extracted from the React component file itself and rendered below the Info Addon heading'
)(() => <BaseButton onClick={action('clicked')} label="Button" />)
);

const markdownDescription = `
#### You can use markdown in your withInfo() description.

Sometimes you might want to manually include some code examples:
~~~js
const Button = () => <button />;
~~~

Maybe include a [link](http://storybook.js.org) to your project as well.
`;

storiesOf('Addons|Info.Markdown', module).add(
'Displays Markdown in description',
withInfo(markdownDescription)(() => <BaseButton onClick={action('clicked')} label="Button" />)
);

storiesOf('Addons|Info.Options.inline', module).add(
'Inlines component inside story',
withInfo({
text: 'Component should be inlined between description and PropType table',
inline: true, // Displays info inline vs click button to view
})(() => <BaseButton label="Button" />)
);

storiesOf('Addons|Info.Options.header', module).add(
'Shows or hides Info Addon header',
withInfo({
text: 'The Info Addon header should be hidden',
header: false, // Toggles display of header with component name and description
})(() => <BaseButton label="Button" />)
);

storiesOf('Addons|Info.Options.source', module).add(
'Shows or hides Info Addon source',
withInfo({
text: 'The Info Addon source section should be hidden',
source: false, // Displays the source of story Component
})(() => <BaseButton label="Button" />)
);

storiesOf('Addons|Info.Options.propTables', module).add(
'Shows additional component prop tables',
withInfo({
text: 'There should be a prop table added for a component not included in the story',
propTables: [FlowTypeButton],
})(() => <BaseButton label="Button" />)
);

storiesOf('Addons|Info.Options.propTablesExclude', module).add(
'Exclude component from prop tables',
withInfo({
text: 'This can exclude extraneous components from being displayed in prop tables.',
propTablesExclude: [FlowTypeButton],
})(() => (
<div>
<BaseButton label="Button" />
<FlowTypeButton label="Flow Typed Button" />
</div>
))
);

storiesOf('Addons|Info.Options.styles', module)
.add(
'Extend info styles with an object',
withInfo({
styles: {
button: {
base: {
background: 'purple',
},
},
header: {
h1: {
color: 'green',
},
},
},
})(() => <BaseButton label="Button" />)
)
.add(
'Full control over styles using a function',
withInfo({
styles: stylesheet => ({
...stylesheet,
header: {
...stylesheet.header,
h1: {
...stylesheet.header.h1,
color: 'red',
},
},
}),
})(() => <BaseButton label="Button" />)
);

storiesOf('Addons|Info.Options.TableComponent', module).add(
'Use a custom component for the table',
withInfo({
TableComponent,
})(() => <BaseButton label="Button" />)
);

storiesOf('Addons|Info.Decorator', module)
.addDecorator((story, context) =>
withInfo('Info could be used as a global or local decorator as well.')(story)(context)
)
.add('Use Info as story decorator', () => <BaseButton label="Button" />);

const hoc = WrapComponent => ({ ...props }) => <WrapComponent {...props} />;

const Input = hoc(() => <input type="text" />);

const TextArea = hoc(({ children }) => <textarea>{children}</textarea>);

storiesOf('Addons|Info.GitHub issues', module).add(
'#1814',
withInfo('Allow Duplicate DisplayNames for HOC #1814')(() => (
<div>
<Input />
<TextArea />
</div>
))
);
33 changes: 33 additions & 0 deletions addons/storysource/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Storybook Storysource Addon

This addon is used to show stories source in the addon panel.

## Getting Started

First, install the addon

```sh
npm install -D @storybook/addon-storysource
```

Add this line to your `addons.js` file

```js
import '@storybook/addon-storysource/register';
```

Use this hook to a custom webpack.config. This will generate a decorator call in every story:

```js
module.exports = {
module: {
rules: [
{
test: /\.stories\.jsx?$/,
loaders: [require.resolve('@storybook/addon-storysource/loader')],
enforce: 'pre',
},
],
},
};
```
1 change: 1 addition & 0 deletions addons/storysource/loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/loader');
37 changes: 37 additions & 0 deletions addons/storysource/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@storybook/addon-storysource",
"version": "3.4.0-alpha.8",
"description": "Stories addon for storybook",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/storysource",
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"license": "MIT",
"main": "dist/index.js",
"jsnext:main": "src/index.js",
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
},
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"acorn": "^5.3.0",
"acorn-es7": "^0.1.0",
"acorn-jsx": "^4.1.1",
"acorn-stage3": "^0.4.0",
"estraverse": "^4.2.0",
"line-column": "^1.0.2",
"prop-types": "^15.5.10",
"react-syntax-highlighter": "^7.0.0"
},
"peerDependencies": {
"@storybook/addons": "^3.3.0",
"react": "*",
"react-dom": "*"
}
}
1 change: 1 addition & 0 deletions addons/storysource/register.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require('./dist').register();
84 changes: 84 additions & 0 deletions addons/storysource/src/StoryPanel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import jsx from 'react-syntax-highlighter/languages/prism/jsx';
import { darcula } from 'react-syntax-highlighter/styles/prism';
import SyntaxHighlighter, { registerLanguage } from 'react-syntax-highlighter/prism-light';
import { createElement } from 'react-syntax-highlighter';
import { EVENT_ID } from './';

registerLanguage('jsx', jsx);

export default class StoryPanel extends Component {
constructor(props) {
super(props);

this.state = { source: '// Here will be dragons 🐉' };

const { channel } = props;

channel.on(EVENT_ID, ({ source, location }) => {
this.setState({
source,
location,
});
});

this.lineRenderer = this.lineRenderer.bind(this);
}

createPart(rows, stylesheet, useInlineStyles) {
return rows.map((node, i) =>
createElement({
node,
stylesheet,
useInlineStyles,
key: `code-segement${i}`,
})
);
}

lineRenderer({ rows, stylesheet, useInlineStyles }) {
const { location } = this.state;

if (location) {
const first = location.startLoc.line - 1;
const last = location.endLoc.line;

const start = this.createPart(rows.slice(0, first), stylesheet, useInlineStyles);
const selected = this.createPart(rows.slice(first, last), stylesheet, useInlineStyles);
const end = this.createPart(rows.slice(last), stylesheet, useInlineStyles);

return (
<span>
{start}
<div style={{ backgroundColor: 'rgba(255, 242, 60, 0.2)' }}>{selected}</div>
{end}
</span>
);
}

return this.createPart(rows, stylesheet, useInlineStyles);
}

render() {
return (
<SyntaxHighlighter
language="jsx"
showLineNumbers="true"
style={darcula}
renderer={this.lineRenderer}
customStyle={{ width: '100%' }}
>
{this.state.source}
</SyntaxHighlighter>
);
}
}

StoryPanel.propTypes = {
channel: PropTypes.shape({
emit: PropTypes.func,
on: PropTypes.func,
removeListener: PropTypes.func,
}).isRequired,
};
6 changes: 6 additions & 0 deletions addons/storysource/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const ADDON_ID = 'storybook/stories';
export const PANEL_ID = `${ADDON_ID}/stories-panel`;
export const EVENT_ID = `${ADDON_ID}/story-event`;

export { register } from './manager';
export { withStorySource } from './preview';
Loading