├── .babelrc
├── .gitignore
├── .npmignore
├── .storybook
├── addons.js
├── config.js
└── webpack.config.js
├── CHANGELOG.md
├── LICENSE
├── README.md
├── assets
├── diagram.png
├── info.gif
└── info2.gif
├── examples
├── Button.js
├── index.js
└── style.css
├── npm-debug.log
├── package.json
├── press
├── article.md
└── article.pdf
├── register.js
├── src
├── index.js
└── register.js
├── typings
└── index.d.ts
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env",
4 | "@babel/preset-react"
5 | ]
6 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | yarn-error.log
3 | dist
4 | npm-debug.log
5 | .cache
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | node_modules
3 | examples
4 | .storybook
--------------------------------------------------------------------------------
/.storybook/addons.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
2 |
3 | import '@storybook/addon-actions/register';
4 | import '@storybook/addon-links/register';
5 | import * as CodeAddon from '../src/register';
6 | CodeAddon.setTabs([
7 | { label: 'Css', type: 'css' },
8 | { label: 'JavaScript', type: 'js' }
9 | ]);
--------------------------------------------------------------------------------
/.storybook/config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
2 |
3 | import { configure } from '@storybook/react';
4 |
5 | function loadStories() {
6 | require('../examples');
7 | }
8 |
9 | configure(loadStories, module);
10 |
--------------------------------------------------------------------------------
/.storybook/webpack.config.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | module: {
4 | rules: [
5 | {
6 | test: /\.tsx$/,
7 | loader: "raw-loader"
8 | },
9 | {
10 | test: /\.css?$/,
11 | loaders: ['style-loader', 'raw-loader']
12 | }],
13 | }
14 |
15 | };
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | #Version 0.0.1
2 |
3 | Initial release
4 |
5 | #Version 0.1.0
6 |
7 | - Fix typings
8 | - Fix imports in register
9 |
10 | #Version 0.1.1
11 | - Fix typings
12 | - Add README.MD
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 SOFTVISION University
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # storybook-addon-code
2 | 
3 |
4 |
5 | A Storybook addon enabling to show off code samples in the Storybook panel for your stories in [Storybook](https://storybook.js.org).
6 |
7 | ### Getting Started
8 |
9 | ```sh
10 | npm i --save-dev storybook-addon-code
11 | ```
12 | ### Usage
13 |
14 | Create a file called `addons.js` in your storybook config.
15 |
16 | Add following content to it:
17 |
18 | ```js
19 | import * as CodeAddon from '../src/register';
20 | CodeAddon.setTabs(
21 | [{ label: 'Sass', type: 'sass' }, {label: 'TypeScript', type: 'typescript'}]
22 | );
23 | ```
24 | setTab function accept and object like {label: 'Sass', type:'sass'} or if you want to have multiple tabs you can pass an array with multiple objects. The label will pe displayed in the Storybook panel.
25 |
26 |
27 | Then write your stories like this:
28 |
29 | ```js
30 | import { storiesOf } from '@storybook/react';
31 | import withCode from 'storybook-addon-code';
32 | import Button from './Button';
33 |
34 | const styleFile = require('raw-loader!./style.scss');
35 | const typescriptFile = require('./test.tsx');
36 |
37 | storiesOf('Button', module)
38 | .addDecorator(withCode(typescriptFile, 'typescript'))
39 | .addDecorator(withCode(styleFile, 'sass'))
40 | .add('with text', () =>
41 |
42 | )
43 | ```
44 | ### Available list of format's for withCode function
45 | 1. clike (withCode(YourCFile, 'clike'))
46 | 2. css (withCode(YourCssFile, 'css'))
47 | 3. html (withCode(YourHtmlFile, 'html'))
48 | 4. js | javascript (withCode(YourJavascriptFile, 'js'))
49 | 5. markup (withCode(YourMarkupFile, 'js'))
50 | 6. mathml (withCode(YourMatHmlFile, 'mathml'))
51 | 7. sass (withCode(YourSassFile, 'sass'))
52 | 8. svg (withCode(YourSvgFile, 'svg'))
53 | 9. ts (withCode(YourTsFile, 'ts'))
54 | 10. typescript (withCode(YourTypescriptFile, 'typescript'))
55 | 11. xml (withCode(YourXmlFile, 'xml'))
56 |
57 | > Have a look at [this example](examples/index.js) stories to learn more about the `withCode` API
58 |
59 |
60 |
--------------------------------------------------------------------------------
/assets/diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SOFTVISION-University/storybook-addon-code/b56323c2ff1ac670c32c25844650a9ff265af663/assets/diagram.png
--------------------------------------------------------------------------------
/assets/info.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SOFTVISION-University/storybook-addon-code/b56323c2ff1ac670c32c25844650a9ff265af663/assets/info.gif
--------------------------------------------------------------------------------
/assets/info2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SOFTVISION-University/storybook-addon-code/b56323c2ff1ac670c32c25844650a9ff265af663/assets/info2.gif
--------------------------------------------------------------------------------
/examples/Button.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export const Button = (props) =>
4 | (
5 |
8 | )
--------------------------------------------------------------------------------
/examples/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { storiesOf } from '@storybook/react';
4 | import { action } from '@storybook/addon-actions';
5 | import withCode from '../src';
6 | import './style.css';
7 | import { Button } from './Button';
8 | const style = require('!raw-loader!./style.css');
9 | const javascriptCode = require('!raw-loader!./Button.js');
10 |
11 | storiesOf('Button', module)
12 | .addDecorator(withCode(javascriptCode, 'js'))
13 | .addDecorator(withCode(style, 'css'))
14 | .add('with text', () =>
15 |
16 | )
17 | .add('with some emoji', () => );
18 |
--------------------------------------------------------------------------------
/examples/style.css:
--------------------------------------------------------------------------------
1 |
2 | .button {
3 | color: blue;
4 | }
5 |
--------------------------------------------------------------------------------
/npm-debug.log:
--------------------------------------------------------------------------------
1 | 0 info it worked if it ends with ok
2 | 1 verbose cli [ '/x/s/node-v6.7.0-linux-x64/bin/node',
3 | 1 verbose cli '/x/s/node/bin/npm',
4 | 1 verbose cli 'run',
5 | 1 verbose cli 'commit',
6 | 1 verbose cli '-m',
7 | 1 verbose cli 'Add article' ]
8 | 2 info using npm@3.10.3
9 | 3 info using node@v6.7.0
10 | 4 verbose stack Error: missing script: commit
11 | 4 verbose stack at run (/x/s/node-v6.7.0-linux-x64/lib/node_modules/npm/lib/run-script.js:151:19)
12 | 4 verbose stack at /x/s/node-v6.7.0-linux-x64/lib/node_modules/npm/lib/run-script.js:61:5
13 | 4 verbose stack at /x/s/node-v6.7.0-linux-x64/lib/node_modules/npm/node_modules/read-package-json/read-json.js:356:5
14 | 4 verbose stack at checkBinReferences_ (/x/s/node-v6.7.0-linux-x64/lib/node_modules/npm/node_modules/read-package-json/read-json.js:320:45)
15 | 4 verbose stack at final (/x/s/node-v6.7.0-linux-x64/lib/node_modules/npm/node_modules/read-package-json/read-json.js:354:3)
16 | 4 verbose stack at then (/x/s/node-v6.7.0-linux-x64/lib/node_modules/npm/node_modules/read-package-json/read-json.js:124:5)
17 | 4 verbose stack at /x/s/node-v6.7.0-linux-x64/lib/node_modules/npm/node_modules/read-package-json/read-json.js:311:12
18 | 4 verbose stack at /x/s/node-v6.7.0-linux-x64/lib/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:78:16
19 | 4 verbose stack at tryToString (fs.js:455:3)
20 | 4 verbose stack at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:442:12)
21 | 5 verbose cwd /home/cosminionascu/workspace/storybook-addon
22 | 6 error Linux 4.4.0-92-generic
23 | 7 error argv "/x/s/node-v6.7.0-linux-x64/bin/node" "/x/s/node/bin/npm" "run" "commit" "-m" "Add article"
24 | 8 error node v6.7.0
25 | 9 error npm v3.10.3
26 | 10 error missing script: commit
27 | 11 error If you need help, you may report this error at:
28 | 11 error
29 | 12 verbose exit [ 1, true ]
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "storybook-addon-code",
3 | "version": "0.1.3",
4 | "description": "A storybook addon that display any type of code highlighted with Prismjs",
5 | "keywords": [
6 | "addon",
7 | "storybook",
8 | "code"
9 | ],
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/SOFTVISION-University/storybook-addon-code.git"
13 | },
14 | "main": "./dist/index.js",
15 | "types": "./typings/index.d.ts",
16 | "scripts": {
17 | "test": "echo \"Error: no test specified\" && exit 1",
18 | "storybook": "start-storybook -p 6006",
19 | "build-storybook": "build-storybook",
20 | "build": "npm run clean & babel -d ./dist ./src",
21 | "clean": "rm -rf ./dist",
22 | "prepublish": "npm run build"
23 | },
24 | "author": "SoftVision",
25 | "license": "MIT",
26 | "devDependencies": {
27 | "@babel/cli": "^7.1.5",
28 | "@babel/core": "^7.1.5",
29 | "@babel/preset-env": "^7.1.5",
30 | "@babel/preset-react": "^7.0.0",
31 | "@storybook/addon-actions": "4.0.0",
32 | "@storybook/addon-links": "4.0.0",
33 | "@storybook/react": "4.0.0",
34 | "babel-loader": "^8.0.4",
35 | "raw-loader": "^0.5.1",
36 | "react": "^16.3.2",
37 | "react-dom": "^16.3.2",
38 | "style-loader": "^0.23.1"
39 | },
40 | "dependencies": {
41 | "@storybook/addons": "4.0.0",
42 | "prismjs": "^1.15.0"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/press/article.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | [React Storybook](https://storybook.js.org/) is a javascript library for React, React Native and Vue js where the engineers can develop,design and test the UI components outside your app in an isolated environment.In the recent React project we needed the advantages that Storybook offer and we decided to use it.
4 | The major advantage was that this allows us to develop UI components outside the app and allow other people in our team to work on them.
5 | In this article we are offering the details of a solution we created for a need that is not covered by React Storybook - offering a preview of the styling code used inside various components.
6 |
7 | React Storybook ,for those who don't know, has many features including::
8 | 1. Completely isolate the environment for your components
9 | 2. HMR — hot module replacement
10 | 3. Clean and fast user interface
11 | 4. Multiple add-ons like:
12 | + [Accessibility](https://github.com/joscha/storybook-addon-i18n-tools)
13 | + [CSS regression](https://github.com/tsuyoshiwada/storybook-chrome-screenshot)
14 | + [Snapshot testing of React components](https://github.com/storybooks/storybook/tree/master/addons/storyshots)
15 | + [Knobs allow you to edit React props dynamically](https://github.com/storybooks/storybook/tree/master/addons/knobs)
16 |
17 | Just visit the [React Storybook](https://storybook.js.org/addons/addon-gallery/) for full list of features.
18 |
19 | # Why another add-on
20 |
21 | Recently, on our current, project we come up with a needed to display the CSS code samples inside the Storybook panel along with the React component. After doing our fair share of research into existing add-ons mentioned earlier we've come up empty.
22 | So we decided to create our own add-on called [storybook-addon-code](https://github.com/SOFTVISION-University/storybook-addon-code) that not only displays CSS code but support other languages like javascript, HTML, typescript etc.
23 |
24 | # How it works
25 |
26 | Before we get started, you need to install react storybook and storybook-addon-code.
27 |
28 | In your Storybook config folder create a addons.js and add the following code:
29 |
30 | ```js
31 | import '@storybook/addon-actions/register';
32 | import * as CodeAddon from '../src/register';
33 | CodeAddon.setTabs([
34 | { label: 'Css', type: 'css' },
35 | { label: 'JavaScript', type: 'js' }
36 | ]);
37 | ```
38 | ### Note:
39 | ``setTab`` function accept and object like ``{label: 'Sass', type:'sass'}`` or if you want to have multiple tabs you can pass an array with multiple objects. The label will pe displayed in the Storybook panel.
40 |
41 |
42 | Then write your stories like this:
43 | ```js
44 | import { storiesOf } from '@storybook/react';
45 | import withCode from 'storybook-addon-code';
46 | import Button from './Button';
47 |
48 | const styleFile = require('raw-loader!./style.scss');
49 | const typescriptFile = require('./test.tsx');
50 |
51 | storiesOf('Button', module)
52 | .addDecorator(withCode(typescriptFile, 'typescript'))
53 | .addDecorator(withCode(styleFile, 'sass'))
54 | .add('with text', () =>
55 |
56 | )
57 | ```
58 | 
59 |
60 | # Supported languages
61 | The plugin has a wide variety of built-in support for common Web programming languages. The most common built-in languages includes:
62 |
63 | + css
64 | + html
65 | + javascript
66 | + scss
67 | + mathml
68 | + sass
69 | + svg
70 | + typescript
71 | + xml
72 |
73 | # Anatomy of a Storybook plugin
74 |
75 | It turns out developing our custom React Storybook plugin wasn’t that all complicated. You can too, very easily, build your own plugins if you feel the need to.
76 |
77 | On a high level, this is how we've build our own:
78 | 1. We've created a top level React component ``Code Addon`` that gets displayed in Storybook panel and shows off the code samples.
79 | 2. Created a decorator function ``withCode``.This function is used to decorate any stories that need source code info being displayed along side them. ``withCode`` has 2 parameter, source code of the file to display and the type of the file. When is called the function emit a message through a channel that is created dynamically based on the language type.
80 | 4. ``Code Addon`` component listens to that specific channel name and calls a function that renders a text with the received code properly formatted.
81 | 5.We used [PrismJS](http://prismjs.com/) for code highlighting and because it can be used with various code samples like CSS, Typescript, Javascript, HTML etc.
82 |
83 | 
84 |
85 | For more details on how to build a Storybook addon, access the official [tutorial](https://storybook.js.org/addons/writing-addons/) .
86 |
87 |
88 |
89 | # Future development
90 | We would like to see at least 2 features added to it in the near and medium term:
91 |
92 | 1. Support for displaying markdown content alongside the component. Usefull for displaying extra info alongside the component being showcased, it would allow us to get rid of an extra plugin like [withReadme](https://github.com/tuchk4/storybook-readme).
93 | 2. Extend the built in language collection with additional languages
94 | We are opened to [Pull Requests](https://github.com/SOFTVISION-University/storybook-addon-code), so please don’t hesitate to get involved!
95 |
96 | If you like this plugin and find it useful in your day to day work please don’t hesitate to give us a little [Github](https://github.com/SOFTVISION-University/storybook-addon-code) star or tweet about it!
97 |
--------------------------------------------------------------------------------
/press/article.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SOFTVISION-University/storybook-addon-code/b56323c2ff1ac670c32c25844650a9ff265af663/press/article.pdf
--------------------------------------------------------------------------------
/register.js:
--------------------------------------------------------------------------------
1 | require('./dist/register');
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import addons from '@storybook/addons';
3 |
4 | const withCode = function(code, type , storyFn = null) {
5 | const emitAddCode = ({ kind, story }) => {
6 | addons.getChannel().emit(`soft/code/add_${type}`, { code, type });
7 | };
8 | return (storyFn, { kind, story }) => {
9 | emitAddCode({ kind, story });
10 | return storyFn();
11 | };
12 | };
13 |
14 | export default withCode;
--------------------------------------------------------------------------------
/src/register.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import addons from '@storybook/addons';
3 | import Prism from 'prismjs';
4 | import 'prismjs/components/prism-typescript.js';
5 | import 'prismjs/components/prism-sass.js';
6 |
7 | import 'prismjs/themes/prism.css';
8 |
9 | class Code extends React.Component {
10 | constructor(props, context) {
11 | super(props, context);
12 | this.state = {code: ''};
13 | this.channelName = `soft/code/add_${props.type}`;
14 | this.onSelectTab = this.onSelectTab.bind(this);
15 | }
16 |
17 | onSelectTab({code, type}) {
18 | const formattedCode = type && code && Prism.highlight(code, Prism.languages[type]);
19 |
20 | this.setState({code: formattedCode});
21 | }
22 |
23 | componentDidMount() {
24 | const { channel, api } = this.props;
25 | channel.on(this.channelName, this.onSelectTab);
26 |
27 | this.stopListeningOnStory = api.onStory(() => {
28 | this.onSelectTab('');
29 | });
30 | }
31 |
32 | render() {
33 | const { code } = this.state;
34 | const { type } = this.props;
35 | return (
36 |