├── .babelrc
├── .gitignore
├── .npmignore
├── .storybook
├── addons.js
└── config.js
├── README.md
├── example
└── basicUsage.story.js
├── index.js
├── package.json
├── register.js
└── src
├── index.js
└── register.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-2", "react"]
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .babelrc
2 |
--------------------------------------------------------------------------------
/.storybook/addons.js:
--------------------------------------------------------------------------------
1 | import '../src/register';
2 |
--------------------------------------------------------------------------------
/.storybook/config.js:
--------------------------------------------------------------------------------
1 | import { configure, setAddon } from '@storybook/react'
2 |
3 | import staticMarkup from '../src/'
4 |
5 | setAddon(staticMarkup) // to use addWithStaticMarkup method
6 |
7 | const req = require.context('../example', true, /.story.js$/)
8 |
9 | configure(() => {
10 | req.keys().forEach((filename) => req(filename))
11 | }, module)
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://badge.fury.io/js/react-storybook-addon-static-markup)
2 |
3 | # Static Markup addon for [React Storybook](https://github.com/storybooks/react-storybook)
4 |
5 | Displays a panel with an "html version" of a story, as suggested in [this](https://github.com/storybooks/react-storybook/issues/617) thread.
6 |
7 | ### [Live demo](https://evgenykochetkov.github.io/react-storybook-addon-static-markup/)
8 |
9 | ## Installation
10 |
11 | Install the package:
12 |
13 | ```sh
14 | npm i -D react-storybook-addon-static-markup
15 | ```
16 |
17 | Then set the addon in your `.storybook/config.js`:
18 |
19 | ```js
20 | import { configure, setAddon } from '@storybook/react'
21 |
22 | import staticMarkup from 'react-storybook-addon-static-markup'
23 |
24 | setAddon(staticMarkup)
25 |
26 | configure(() => {
27 | // ...
28 | }, module)
29 | ```
30 |
31 | ...and register it in your `.storybook/addons.js`:
32 | ```js
33 | import 'react-storybook-addon-static-markup/register';
34 | ```
35 |
36 |
37 | ## Usage
38 |
39 | ```js
40 | import React from 'react';
41 | import { storiesOf } from '@storybook/react';
42 |
43 | import { ShowStaticMarkup } from '../src'
44 |
45 | storiesOf('Usage examples', module)
46 | .add(
47 | 'with HOC',
48 | () => (
49 |
50 |
53 |
54 | )
55 | )
56 | .addWithStaticMarkup(
57 | 'with a "shortcut" method',
58 | () => (
59 |
60 | hello
61 |
64 |
65 | )
66 | )
67 | ```
68 |
--------------------------------------------------------------------------------
/example/basicUsage.story.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 |
4 | import { ShowStaticMarkup } from '../src'
5 |
6 | storiesOf('Usage examples', module)
7 | .add(
8 | 'with HOC',
9 | () => (
10 |
11 |
14 |
15 | )
16 | )
17 | .addWithStaticMarkup(
18 | 'with a "shortcut" method',
19 | () => (
20 |
21 | hello
22 |
25 |
26 | )
27 | )
28 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.ShowStaticMarkup = undefined;
7 |
8 | var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
9 |
10 | var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
11 |
12 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
13 |
14 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
15 |
16 | var _createClass2 = require('babel-runtime/helpers/createClass');
17 |
18 | var _createClass3 = _interopRequireDefault(_createClass2);
19 |
20 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
21 |
22 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
23 |
24 | var _inherits2 = require('babel-runtime/helpers/inherits');
25 |
26 | var _inherits3 = _interopRequireDefault(_inherits2);
27 |
28 | var _react = require('react');
29 |
30 | var _react2 = _interopRequireDefault(_react);
31 |
32 | var _addons = require('@storybook/addons');
33 |
34 | var _addons2 = _interopRequireDefault(_addons);
35 |
36 | var _pretty = require('pretty');
37 |
38 | var _pretty2 = _interopRequireDefault(_pretty);
39 |
40 | var _server = require('react-dom/server');
41 |
42 | var _server2 = _interopRequireDefault(_server);
43 |
44 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
45 |
46 | var ShowStaticMarkup = exports.ShowStaticMarkup = function (_React$Component) {
47 | (0, _inherits3.default)(ShowStaticMarkup, _React$Component);
48 |
49 | function ShowStaticMarkup() {
50 | (0, _classCallCheck3.default)(this, ShowStaticMarkup);
51 | return (0, _possibleConstructorReturn3.default)(this, (ShowStaticMarkup.__proto__ || (0, _getPrototypeOf2.default)(ShowStaticMarkup)).apply(this, arguments));
52 | }
53 |
54 | (0, _createClass3.default)(ShowStaticMarkup, [{
55 | key: 'render',
56 | value: function render() {
57 | var children = this.props.children;
58 |
59 |
60 | var markup = (0, _pretty2.default)(_server2.default.renderToStaticMarkup(children));
61 |
62 | var channel = _addons2.default.getChannel();
63 | channel.emit('evgenykochetkov/static-markup/show-markup', markup);
64 |
65 | return children;
66 | }
67 | }]);
68 | return ShowStaticMarkup;
69 | }(_react2.default.Component);
70 |
71 | exports.default = {
72 | addWithStaticMarkup: function addWithStaticMarkup(storyName, story) {
73 | this.add(storyName, function () {
74 | return _react2.default.createElement(
75 | ShowStaticMarkup,
76 | null,
77 | story()
78 | );
79 | });
80 | }
81 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-storybook-addon-static-markup",
3 | "version": "0.1.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "storybook": "start-storybook -p 9001 -c .storybook",
8 | "deploy-storybook": "storybook-to-ghpages",
9 | "transpile": "babel --plugins \"transform-runtime\" ./src --out-dir ."
10 | },
11 | "keywords": [
12 | "react",
13 | "storybook",
14 | "react-storybook",
15 | "addon",
16 | "plugin"
17 | ],
18 | "author": "Evgeny Kochetkov",
19 | "repository": {
20 | "type": "git",
21 | "url": "https://github.com/evgenykochetkov/react-storybook-addon-static-markup.git"
22 | },
23 | "license": "ISC",
24 | "devDependencies": {
25 | "@kadira/storybook-deployer": "^1.2.0",
26 | "babel-cli": "^6.18.0",
27 | "babel-core": "^6.18.2",
28 | "babel-plugin-transform-runtime": "^6.15.0",
29 | "babel-polyfill": "^6.16.0",
30 | "babel-preset-es2015": "^6.18.0",
31 | "babel-preset-react": "^6.16.0",
32 | "babel-preset-stage-2": "^6.18.0",
33 | "react": "^15.4.1",
34 | "react-dom": "^15.4.1",
35 | "@storybook/react": "3.1.3"
36 | },
37 | "dependencies": {
38 | "pretty": "^2.0.0"
39 | },
40 | "peerDependencies": {
41 | "react": "^0.14.7 || ^15.0.0",
42 | "react-dom": "^0.14.7 || ^15.0.0"
43 | },
44 | "engines": {
45 | "npm": "^3.0.0"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/register.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
4 |
5 | var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
6 |
7 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
8 |
9 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
10 |
11 | var _createClass2 = require('babel-runtime/helpers/createClass');
12 |
13 | var _createClass3 = _interopRequireDefault(_createClass2);
14 |
15 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
16 |
17 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
18 |
19 | var _inherits2 = require('babel-runtime/helpers/inherits');
20 |
21 | var _inherits3 = _interopRequireDefault(_inherits2);
22 |
23 | var _react = require('react');
24 |
25 | var _react2 = _interopRequireDefault(_react);
26 |
27 | var _addons = require('@storybook/addons');
28 |
29 | var _addons2 = _interopRequireDefault(_addons);
30 |
31 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
32 |
33 | var styles = {
34 | markupPanel: {
35 | margin: 10,
36 | fontFamily: 'monospace',
37 | whiteSpace: 'pre',
38 | fontSize: 14,
39 | color: '#444',
40 | width: '100%',
41 | overflow: 'auto'
42 | }
43 | };
44 |
45 | var StaticMarkup = function (_React$Component) {
46 | (0, _inherits3.default)(StaticMarkup, _React$Component);
47 |
48 | function StaticMarkup() {
49 | var _ref;
50 |
51 | (0, _classCallCheck3.default)(this, StaticMarkup);
52 |
53 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
54 | args[_key] = arguments[_key];
55 | }
56 |
57 | var _this = (0, _possibleConstructorReturn3.default)(this, (_ref = StaticMarkup.__proto__ || (0, _getPrototypeOf2.default)(StaticMarkup)).call.apply(_ref, [this].concat(args)));
58 |
59 | _this.state = {
60 | markup: ''
61 | };
62 |
63 | _this.onShowStaticMarkup = _this.onShowStaticMarkup.bind(_this);
64 | return _this;
65 | }
66 |
67 | (0, _createClass3.default)(StaticMarkup, [{
68 | key: 'onShowStaticMarkup',
69 | value: function onShowStaticMarkup(markup) {
70 | this.setState({ markup: markup });
71 | }
72 | }, {
73 | key: 'componentDidMount',
74 | value: function componentDidMount() {
75 | var _this2 = this;
76 |
77 | var _props = this.props,
78 | channel = _props.channel,
79 | api = _props.api;
80 |
81 | channel.on('evgenykochetkov/static-markup/show-markup', this.onShowStaticMarkup);
82 |
83 | // Clear the current state on every story change.
84 | this.stopListeningOnStory = api.onStory(function () {
85 | _this2.onShowStaticMarkup('');
86 | });
87 | }
88 | }, {
89 | key: 'render',
90 | value: function render() {
91 | var markup = this.state.markup;
92 |
93 |
94 | return _react2.default.createElement(
95 | 'div',
96 | { style: styles.markupPanel },
97 | markup
98 | );
99 | }
100 |
101 | // This is some cleanup tasks when the StaticMarkup panel is unmounting.
102 |
103 | }, {
104 | key: 'componentWillUnmount',
105 | value: function componentWillUnmount() {
106 | if (this.stopListeningOnStory) {
107 | this.stopListeningOnStory();
108 | }
109 |
110 | this.unmounted = true;
111 | var _props2 = this.props,
112 | channel = _props2.channel,
113 | api = _props2.api;
114 |
115 | channel.removeListener('evgenykochetkov/static-markup/show-markup', this.onShowStaticMarkup);
116 | }
117 | }]);
118 | return StaticMarkup;
119 | }(_react2.default.Component);
120 |
121 | // Register the addon with a unique name.
122 |
123 |
124 | _addons2.default.register('evgenykochetkov/static-markup', function (api) {
125 | // Also need to set a unique name to the panel.
126 | _addons2.default.addPanel('evgenykochetkov/static-markup/panel', {
127 | title: 'Static Markup',
128 | render: function render() {
129 | return _react2.default.createElement(StaticMarkup, { channel: _addons2.default.getChannel(), api: api });
130 | }
131 | });
132 | });
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import addons from '@storybook/addons';
3 | import pretty from 'pretty';
4 |
5 | import ReactDOMServer from 'react-dom/server'
6 |
7 | export class ShowStaticMarkup extends React.Component {
8 | render() {
9 | const { children } = this.props;
10 |
11 | const markup = pretty(ReactDOMServer.renderToStaticMarkup(children));
12 |
13 | const channel = addons.getChannel();
14 | channel.emit('evgenykochetkov/static-markup/show-markup', markup);
15 |
16 | return children;
17 | }
18 | }
19 |
20 | export default {
21 | addWithStaticMarkup (storyName, story) {
22 | this.add(storyName, () => (
23 |
24 | { story() }
25 |
26 | ))
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/register.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import addons from '@storybook/addons';
3 |
4 | const styles = {
5 | markupPanel: {
6 | margin: 10,
7 | fontFamily: 'monospace',
8 | whiteSpace: 'pre',
9 | fontSize: 14,
10 | color: '#444',
11 | width: '100%',
12 | overflow: 'auto',
13 | }
14 | };
15 |
16 | class StaticMarkup extends React.Component {
17 | constructor(...args) {
18 | super(...args);
19 |
20 | this.state = {
21 | markup: ''
22 | };
23 |
24 | this.onShowStaticMarkup = this.onShowStaticMarkup.bind(this);
25 | }
26 |
27 | onShowStaticMarkup(markup) {
28 | this.setState({markup});
29 | }
30 |
31 | componentDidMount() {
32 | const { channel, api } = this.props;
33 | channel.on('evgenykochetkov/static-markup/show-markup', this.onShowStaticMarkup);
34 |
35 | // Clear the current state on every story change.
36 | this.stopListeningOnStory = api.onStory(() => {
37 | this.onShowStaticMarkup('');
38 | });
39 | }
40 |
41 | render() {
42 | const { markup } = this.state;
43 |
44 | return (
45 |
46 | { markup }
47 |
48 | );
49 | }
50 |
51 | // This is some cleanup tasks when the StaticMarkup panel is unmounting.
52 | componentWillUnmount() {
53 | if(this.stopListeningOnStory) {
54 | this.stopListeningOnStory();
55 | }
56 |
57 | this.unmounted = true;
58 | const { channel, api } = this.props;
59 | channel.removeListener('evgenykochetkov/static-markup/show-markup', this.onShowStaticMarkup);
60 | }
61 | }
62 |
63 | // Register the addon with a unique name.
64 | addons.register('evgenykochetkov/static-markup', (api) => {
65 | // Also need to set a unique name to the panel.
66 | addons.addPanel('evgenykochetkov/static-markup/panel', {
67 | title: 'Static Markup',
68 | render: () => (
69 |
70 | ),
71 | })
72 | })
73 |
--------------------------------------------------------------------------------