Merge branch 'master' of github.com:storybooks/storybook into select-knob-ordering

This commit is contained in:
Simon Knox 2018-01-15 21:28:49 +11:00
commit 320a3d812e
427 changed files with 10420 additions and 6014 deletions

View File

@ -58,6 +58,14 @@ jobs:
name: "Link packages"
command: |
yarn install
- run:
name: Workaround for https://github.com/GoogleChrome/puppeteer/issues/290
command: sh ./scripts/workaround-puppeteer-issue-290.sh
- run:
name: "Build official-storybook"
command: |
cd examples/official-storybook
yarn build-storybook
- run:
name: "Build react kitchen-sink"
command: |
@ -73,34 +81,33 @@ jobs:
command: |
cd examples/angular-cli
yarn build-storybook
- run:
name: "Run react kitchen-sink"
name: "Run react kitchen-sink (smoke test)"
command: |
cd examples/cra-kitchen-sink
yarn storybook
background: true
yarn storybook --smoke-test
- run:
name: "Run vue kitchen-sink"
name: "Run vue kitchen-sink (smoke test)"
command: |
cd examples/vue-kitchen-sink
yarn storybook
background: true
yarn storybook --smoke-test
- run:
name: "Run angular-cli"
name: "Run angular-cli (smoke test)"
command: |
cd examples/angular-cli
yarn storybook
background: true
yarn storybook --smoke-test
- run:
name: Workaround for https://github.com/GoogleChrome/puppeteer/issues/290
command: sh ./scripts/workaround-puppeteer-issue-290.sh
name: "Run image snapshots"
command: yarn test --image
- run:
name: Integration Test - Kichen sinks
command: yarn test --integration
- store_artifacts:
path: integration/__image_snapshots__
destination: integration_image_snapshots
- store_artifacts:
path: examples/official-storybook/image-snapshots/__image_snapshots__
destination: official_storybook_image_snapshots
react-native:
<<: *defaults
steps:

View File

@ -3,6 +3,6 @@ root = true
[*]
end_of_line = lf
[*.{js,json,ts}]
[*.{js,json,ts,html}]
indent_style = space
indent_size = 2

1
.gitignore vendored
View File

@ -21,3 +21,4 @@ package-lock.json
storybook-static
integration/__image_snapshots__/__diff_output__
.jest-test-results.json
/examples/cra-kitchen-sink/src/__image_snapshots__/__diff_output__/

View File

@ -1,4 +1,3 @@
/src/
/example/
/demo/
/docs/

View File

@ -1,3 +1,431 @@
# 3.4.0-alpha.4
2018-January-13
Republish `3.4.0-alpha.3` due to potential publishing errors
# 3.4.0-alpha.3
2018-January-13
#### Features
- Polymer 2 support [#2225](https://github.com/storybooks/storybook/pull/2225)
- Add image snapshots to addon-storyshots [#2413](https://github.com/storybooks/storybook/pull/2413)
- Angular template support for Storybook [#2690](https://github.com/storybooks/storybook/pull/2690)
#### Bug Fixes
- Remove polymer-cli dependency [#2741](https://github.com/storybooks/storybook/pull/2741)
- Add scss for components in angular apps by default. [#2703](https://github.com/storybooks/storybook/pull/2703)
#### Maintenance
- Change ng stories dir [#2672](https://github.com/storybooks/storybook/pull/2672)
#### Dependency Upgrades
<details>
<summary>
54 Upgrades
</summary>
- Upgraded `jest-image-snapshot` in `/` from "2.2.1" to "2.3.0" [#2740](https://github.com/storybooks/storybook/pull/2740)
- Upgraded `polymer-webpack-loader` in `app/polymer` from "2.0.0" to "2.0.1" [#2740](https://github.com/storybooks/storybook/pull/2740)
- Upgraded `jest-image-snapshot` in `addons/storyshots` from "2.2.1" to "2.3.0" [#2740](https://github.com/storybooks/storybook/pull/2740)
- Upgraded `shelljs` in `/` from "0.7.8" to "0.8.0" [#2734](https://github.com/storybooks/storybook/pull/2734)
- Upgraded `shelljs` in `addons/links` from "0.7.8" to "0.8.0" [#2734](https://github.com/storybooks/storybook/pull/2734)
- Upgraded `autoprefixer` in `app/react` from "7.2.4" to "7.2.5" [#2734](https://github.com/storybooks/storybook/pull/2734)
- Upgraded `shelljs` in `app/react` from "0.7.8" to "0.8.0" [#2734](https://github.com/storybooks/storybook/pull/2734)
- Upgraded `autoprefixer` in `app/angular` from "7.2.4" to "7.2.5" [#2734](https://github.com/storybooks/storybook/pull/2734)
- Upgraded `shelljs` in `app/angular` from "0.7.8" to "0.8.0" [#2734](https://github.com/storybooks/storybook/pull/2734)
- Upgraded `autoprefixer` in `app/react-native` from "7.2.4" to "7.2.5" [#2734](https://github.com/storybooks/storybook/pull/2734)
- Upgraded `shelljs` in `app/react-native` from "0.7.8" to "0.8.0" [#2734](https://github.com/storybooks/storybook/pull/2734)
- Upgraded `autoprefixer` in `app/vue` from "7.2.4" to "7.2.5" [#2734](https://github.com/storybooks/storybook/pull/2734)
- Upgraded `shelljs` in `app/vue` from "0.7.8" to "0.8.0" [#2734](https://github.com/storybooks/storybook/pull/2734)
- Upgraded `shelljs` in `lib/cli` from "0.7.8" to "0.8.0" [#2734](https://github.com/storybooks/storybook/pull/2734)
- Update gatsby in /docs from 1.9.153 to 1.9.154 [#2733](https://github.com/storybooks/storybook/pull/2733)
- Update @angular/cli in examples/angular-cli from 1.6.3 to 1.6.4 [#2726](https://github.com/storybooks/storybook/pull/2726)
- Upgraded `commander` in `/` from "2.12.2" to "2.13.0" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `jest` in `/` from "22.0.5" to "22.0.6" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `jest-cli` in `/` from "22.0.5" to "22.0.6" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `jest-config` in `/` from "22.0.5" to "22.0.6" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `jest-diff` in `/` from "22.0.5" to "22.0.6" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `jest-environment-jsdom` in `/` from "22.0.5" to "22.0.6" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `jest-jasmine2` in `/` from "22.0.5" to "22.0.6" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `nodemon` in `/` from "1.14.10" to "1.14.11" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `prettier` in `/` from "1.9.2" to "1.10.2" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `tslint` in `/` from "5.8.0" to "5.9.1" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `commander` in `app/react` from "2.12.2" to "2.13.0" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `common-tags` in `app/react` from "1.7.0" to "1.7.2" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `nodemon` in `app/react` from "1.14.10" to "1.14.11" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `commander` in `app/angular` from "2.12.2" to "2.13.0" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `common-tags` in `app/angular` from "1.7.0" to "1.7.2" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `zone.js` in `app/angular` from "0.8.19" to "0.8.20" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `nodemon` in `app/angular` from "1.14.10" to "1.14.11" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `commander` in `app/react-native` from "2.12.2" to "2.13.0" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `commander` in `app/vue` from "2.12.2" to "2.13.0" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `common-tags` in `app/vue` from "1.7.0" to "1.7.2" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `nodemon` in `app/vue` from "1.14.10" to "1.14.11" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `babel-jest` in `examples/cra-kitchen-sink` from "22.0.4" to "22.0.6" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `jest` in `examples/cra-kitchen-sink` from "22.0.5" to "22.0.6" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `commander` in `lib/cli` from "2.12.2" to "2.13.0" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `zone.js` in `examples/angular-cli` from "0.8.19" to "0.8.20" [#2724](https://github.com/storybooks/storybook/pull/2724)
- Upgraded `@storybook/addon-actions` in `/docs` from "3.3.7" to "3.3.8" [#2722](https://github.com/storybooks/storybook/pull/2722)
- Upgraded `@storybook/addon-links` in `/docs` from "3.3.7" to "3.3.8" [#2722](https://github.com/storybooks/storybook/pull/2722)
- Upgraded `@storybook/addons` in `/docs` from "3.3.7" to "3.3.8" [#2722](https://github.com/storybooks/storybook/pull/2722)
- Upgraded `@storybook/react` in `/docs` from "3.3.7" to "3.3.8" [#2722](https://github.com/storybooks/storybook/pull/2722)
- Upgraded `gatsby-transformer-remark` in `/docs` from "1.7.27" to "1.7.28" [#2722](https://github.com/storybooks/storybook/pull/2722)
- Upgraded `gatsby` in `/docs` from "1.9.151" to "1.9.153" [#2722](https://github.com/storybooks/storybook/pull/2722)
- Upgraded `@storybook/addon-actions` in `/docs` from "3.3.6" to "3.3.7" [#2710](https://github.com/storybooks/storybook/pull/2710)
- Upgraded `@storybook/addon-links` in `/docs` from "3.3.6" to "3.3.7" [#2710](https://github.com/storybooks/storybook/pull/2710)
- Upgraded `@storybook/addons` in `/docs` from "3.3.6" to "3.3.7" [#2710](https://github.com/storybooks/storybook/pull/2710)
- Upgraded `@storybook/react` in `/docs` from "3.3.6" to "3.3.7" [#2710](https://github.com/storybooks/storybook/pull/2710)
- Upgraded `gatsby-link` in `/docs` from "1.6.33" to "1.6.34" [#2710](https://github.com/storybooks/storybook/pull/2710)
- Upgraded `gatsby-transformer-remark` in `/docs` from "1.7.26" to "1.7.27" [#2710](https://github.com/storybooks/storybook/pull/2710)
- Upgraded `gatsby` in `/docs` from "1.9.150" to "1.9.151" [#2710](https://github.com/storybooks/storybook/pull/2710)
</details>
# 3.3.9
2018-January-13
#### Bug Fixes
- Start haul/react-native using named binaries instead of cli.js [#2715](https://github.com/storybooks/storybook/pull/2715)
- Reflect the new peer dependencies in docs and CLI templates [#2714](https://github.com/storybooks/storybook/pull/2714)
- Don't mangle function names for production builds [#2705](https://github.com/storybooks/storybook/pull/2705)
# 3.4.0-alpha.2
2018-January-11
This is a duplicate of `3.4.0-alpha.1`, re-published because I accidentally published `3.4.0-alpha.1` on the `latest` NPM tag.
# 3.3.8
2018-January-11
This is a duplicate of `3.3.7`, re-published because I accidentally published `3.4.0-alpha.1` on the `latest` NPM tag.
# 3.4.0-alpha.1
2018-January-10
In addition to the changes listed here, also contains fixes from [3.3.5](#335) and [3.3.6](#336) and [3.3.7](#337).
#### Features
- Custom tsconfig.json for angular apps. [#2669](https://github.com/storybooks/storybook/pull/2669)
#### Dependency Upgrades
<details>
<summary>
105 Upgrades
</summary>
- Upgraded `babel-eslint` in `/` from "8.1.2" to "8.2.1" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `eslint-plugin-jest` in `/` from "21.5.0" to "21.6.1" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `jest` in `/` from "22.0.4" to "22.0.5" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `jest-cli` in `/` from "22.0.4" to "22.0.5" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `jest-config` in `/` from "22.0.4" to "22.0.5" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `jest-diff` in `/` from "22.0.3" to "22.0.5" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `jest-environment-jsdom` in `/` from "22.0.4" to "22.0.5" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `jest-jasmine2` in `/` from "22.0.4" to "22.0.5" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `lerna` in `/` from "2.5.1" to "2.6.0" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `nodemon` in `/` from "1.14.9" to "1.14.10" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `common-tags` in `app/react` from "1.6.0" to "1.7.0" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `nodemon` in `app/react` from "1.14.9" to "1.14.10" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `common-tags` in `app/angular` from "1.6.0" to "1.7.0" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `nodemon` in `app/angular` from "1.14.9" to "1.14.10" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `common-tags` in `app/vue` from "1.6.0" to "1.7.0" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `nodemon` in `app/vue` from "1.14.9" to "1.14.10" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `vue-loader` in `app/vue` from "13.6.2" to "13.7.0" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `jest` in `examples/cra-kitchen-sink` from "22.0.4" to "22.0.5" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `vue-loader` in `examples/vue-kitchen-sink` from "13.6.2" to "13.7.0" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from "2.10.0" to "2.10.1" [#2700](https://github.com/storybooks/storybook/pull/2700)
- Upgraded `marked` in `/docs` from "0.3.7" to "0.3.12" [#2699](https://github.com/storybooks/storybook/pull/2699)
- Upgraded `react-stack-grid` in `/docs` from "0.7.0" to "0.7.1" [#2699](https://github.com/storybooks/storybook/pull/2699)
- Upgraded `@storybook/addon-actions` in `/docs` from "3.3.4" to "3.3.6" [#2686](https://github.com/storybooks/storybook/pull/2686)
- Upgraded `@storybook/addon-links` in `/docs` from "3.3.4" to "3.3.6" [#2686](https://github.com/storybooks/storybook/pull/2686)
- Upgraded `@storybook/addons` in `/docs` from "3.3.4" to "3.3.6" [#2686](https://github.com/storybooks/storybook/pull/2686)
- Upgraded `@storybook/react` in `/docs` from "3.3.4" to "3.3.6" [#2686](https://github.com/storybooks/storybook/pull/2686)
- Upgraded `gatsby-link` in `/docs` from "1.6.32" to "1.6.33" [#2686](https://github.com/storybooks/storybook/pull/2686)
- Upgraded `gatsby` in `/docs` from "1.9.149" to "1.9.150" [#2686](https://github.com/storybooks/storybook/pull/2686)
- Upgraded `nodemon` in `/` from "1.14.8" to "1.14.9" [#2687](https://github.com/storybooks/storybook/pull/2687)
- Upgraded `markdown-loader` in `app/react` from "2.0.1" to "2.0.2" [#2687](https://github.com/storybooks/storybook/pull/2687)
- Upgraded `nodemon` in `app/react` from "1.14.8" to "1.14.9" [#2687](https://github.com/storybooks/storybook/pull/2687)
- Upgraded `nodemon` in `app/angular` from "1.14.8" to "1.14.9" [#2687](https://github.com/storybooks/storybook/pull/2687)
- Upgraded `react-native` in `app/react-native` from "0.51.0" to "0.52.0" [#2687](https://github.com/storybooks/storybook/pull/2687)
- Upgraded `nodemon` in `app/vue` from "1.14.8" to "1.14.9" [#2687](https://github.com/storybooks/storybook/pull/2687)
- Upgraded `@storybook/addon-actions` in `/docs` from "3.3.3" to "3.3.4" [#2674](https://github.com/storybooks/storybook/pull/2674)
- Upgraded `@storybook/addon-links` in `/docs` from "3.3.3" to "3.3.4" [#2674](https://github.com/storybooks/storybook/pull/2674)
- Upgraded `@storybook/addons` in `/docs` from "3.3.3" to "3.3.4" [#2674](https://github.com/storybooks/storybook/pull/2674)
- Upgraded `@storybook/react` in `/docs` from "3.3.3" to "3.3.4" [#2674](https://github.com/storybooks/storybook/pull/2674)
- Update eslint in / from 4.14.0 to 4.15.0 [#2673](https://github.com/storybooks/storybook/pull/2673)
- Upgraded `nodemon` in `/` from "1.14.7" to "1.14.8" [#2664](https://github.com/storybooks/storybook/pull/2664)
- Upgraded `marksy` in `addons/info` from "6.0.2" to "6.0.3" [#2664](https://github.com/storybooks/storybook/pull/2664)
- Upgraded `nodemon` in `app/react` from "1.14.7" to "1.14.8" [#2664](https://github.com/storybooks/storybook/pull/2664)
- Upgraded `nodemon` in `app/angular` from "1.14.7" to "1.14.8" [#2664](https://github.com/storybooks/storybook/pull/2664)
- Upgraded `nodemon` in `app/vue` from "1.14.7" to "1.14.8" [#2664](https://github.com/storybooks/storybook/pull/2664)
- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from "2.9.7" to "2.10.0" [#2664](https://github.com/storybooks/storybook/pull/2664)
- Upgraded `@types/lodash` in `/` from "4.14.91" to "4.14.92" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `marksy` in `addons/info` from "6.0.1" to "6.0.2" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `app/react` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `html-loader` in `app/react` from "0.5.1" to "0.5.4" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `uglifyjs-webpack-plugin` in `app/react` from "1.1.5" to "1.1.6" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `app/angular` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `uglifyjs-webpack-plugin` in `app/angular` from "1.1.5" to "1.1.6" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `app/react-native` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `uglifyjs-webpack-plugin` in `app/react-native` from "1.1.5" to "1.1.6" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `app/vue` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `uglifyjs-webpack-plugin` in `app/vue` from "1.1.5" to "1.1.6" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `@types/node` in `examples/angular-cli` from "6.0.95" to "6.0.96" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `examples/vue-kitchen-sink` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `@angular/animations` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/common` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/compiler` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/core` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/forms` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/http` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/platform-browser` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/router` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/language-service` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `postcss-loader` in `app/react` from "2.0.9" to "2.0.10" [#2637](https://github.com/storybooks/storybook/pull/2637)
- Upgraded `postcss-loader` in `app/angular` from "2.0.9" to "2.0.10" [#2637](https://github.com/storybooks/storybook/pull/2637)
- Upgraded `postcss-loader` in `app/react-native` from "2.0.9" to "2.0.10" [#2637](https://github.com/storybooks/storybook/pull/2637)
- Upgraded `postcss-loader` in `app/vue` from "2.0.9" to "2.0.10" [#2637](https://github.com/storybooks/storybook/pull/2637)
- Update inquirer in / from 4.0.1 to 4.0.2 [#2632](https://github.com/storybooks/storybook/pull/2632)
- Upgraded `danger` in `/` from "2.1.8" to "2.1.10" [#2618](https://github.com/storybooks/storybook/pull/2618)
- Upgraded `autoprefixer` in `app/react` from "7.2.3" to "7.2.4" [#2618](https://github.com/storybooks/storybook/pull/2618)
- Upgraded `autoprefixer` in `app/angular` from "7.2.3" to "7.2.4" [#2618](https://github.com/storybooks/storybook/pull/2618)
- Upgraded `autoprefixer` in `app/react-native` from "7.2.3" to "7.2.4" [#2618](https://github.com/storybooks/storybook/pull/2618)
- Upgraded `autoprefixer` in `app/vue` from "7.2.3" to "7.2.4" [#2618](https://github.com/storybooks/storybook/pull/2618)
- Upgraded `nodemon` in `/` from "1.14.6" to "1.14.7" [#2612](https://github.com/storybooks/storybook/pull/2612)
- Upgraded `nodemon` in `app/react` from "1.14.6" to "1.14.7" [#2612](https://github.com/storybooks/storybook/pull/2612)
- Upgraded `nodemon` in `app/angular` from "1.14.6" to "1.14.7" [#2612](https://github.com/storybooks/storybook/pull/2612)
- Upgraded `nodemon` in `app/vue` from "1.14.6" to "1.14.7" [#2612](https://github.com/storybooks/storybook/pull/2612)
- Upgraded `vue-loader` in `app/vue` from "13.6.1" to "13.6.2" [#2611](https://github.com/storybooks/storybook/pull/2611)
- Upgraded `vue-loader` in `examples/vue-kitchen-sink` from "13.6.1" to "13.6.2" [#2611](https://github.com/storybooks/storybook/pull/2611)
- Upgraded `nodemon` in `/` from "1.14.5" to "1.14.6" [#2609](https://github.com/storybooks/storybook/pull/2609)
- Upgraded `nodemon` in `app/react` from "1.14.5" to "1.14.6" [#2609](https://github.com/storybooks/storybook/pull/2609)
- Upgraded `nodemon` in `app/angular` from "1.14.5" to "1.14.6" [#2609](https://github.com/storybooks/storybook/pull/2609)
- Upgraded `nodemon` in `app/vue` from "1.14.5" to "1.14.6" [#2609](https://github.com/storybooks/storybook/pull/2609)
- Upgraded `enzyme` in `/` from "3.2.0" to "3.3.0" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `nodemon` in `/` from "1.14.3" to "1.14.5" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `graphiql` in `addons/graphql` from "0.11.10" to "0.11.11" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `enzyme` in `addons/links` from "3.2.0" to "3.3.0" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `nodemon` in `app/react` from "1.14.3" to "1.14.5" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `nodemon` in `app/angular` from "1.14.3" to "1.14.5" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `nodemon` in `app/vue` from "1.14.3" to "1.14.5" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `enzyme` in `examples/cra-kitchen-sink` from "3.2.0" to "3.3.0" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `enzyme` in `examples/official-storybook` from "3.2.0" to "3.3.0" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Update 2 dependencies from npm [#2597](https://github.com/storybooks/storybook/pull/2597)
- Upgraded `@storybook/addon-actions` in `/docs` from "3.3.1" to "3.3.3" [#2598](https://github.com/storybooks/storybook/pull/2598)
- Upgraded `@storybook/addon-links` in `/docs` from "3.3.1" to "3.3.3" [#2598](https://github.com/storybooks/storybook/pull/2598)
- Upgraded `@storybook/addons` in `/docs` from "3.3.1" to "3.3.3" [#2598](https://github.com/storybooks/storybook/pull/2598)
- Upgraded `@storybook/react` in `/docs` from "3.3.1" to "3.3.3" [#2598](https://github.com/storybooks/storybook/pull/2598)
- Upgraded `danger` in `/` from "2.1.6" to "2.1.8" [#2599](https://github.com/storybooks/storybook/pull/2599)
- Upgraded `axe-core` in `addons/a11y` from "2.6.0" to "2.6.1" [#2599](https://github.com/storybooks/storybook/pull/2599)
</details>
# 3.3.7
2018-January-10
#### Maintenance
- Extract tslint exclusions out of package.json scripts [#2684](https://github.com/storybooks/storybook/pull/2684)
- Add tslint to the linting pipe [#2682](https://github.com/storybooks/storybook/pull/2682)
#### Bug Fixes
- Angular: add entry components to modulemetadata - #2701 [#2702](https://github.com/storybooks/storybook/pull/2702)
- Add html and markup loaders to angular and vue apps [#2692](https://github.com/storybooks/storybook/pull/2692)
# 3.3.6
2018-January-08
#### Bug Fixes
- Remove `src/` from remaining `.npmignore`s [#2678](https://github.com/storybooks/storybook/pull/2678)
# 3.3.5
2018-January-08
#### Bug Fixes
- Remove src from individual .npmignore files [#2677](https://github.com/storybooks/storybook/pull/2677)
# 3.4.0-alpha.0
2018-January-07
#### Features
- Multiple hierarchies [#2452](https://github.com/storybooks/storybook/pull/2452)
- Change template story files extension to .ts [#2594](https://github.com/storybooks/storybook/pull/2594)
- Use store revisions to ensure that stories re-render on HMR. [#2605](https://github.com/storybooks/storybook/pull/2605)
- Ability to force re-render a story [#2463](https://github.com/storybooks/storybook/pull/2463)
- Introduce framework-independent core library [#2241](https://github.com/storybooks/storybook/pull/2241)
#### Documentation
<details>
<summary>
4 PRs
</summary>
- Update webpack extend warning. [#2660](https://github.com/storybooks/storybook/pull/2660)
- ADD demo images to a new img folder with the documentation site [#2644](https://github.com/storybooks/storybook/pull/2644)
- write doc about .css/.scss rules for Angular [#2634](https://github.com/storybooks/storybook/pull/2634)
- Updated documentation wrt ejs exclusion [#2633](https://github.com/storybooks/storybook/pull/2633)
</details>
#### Maintenance
<details>
<summary>
4 PRs
</summary>
- Only update CLI snapsots on postpublish script, skip smoke tests [#2671](https://github.com/storybooks/storybook/pull/2671)
- Fix the timezone for example dates [#2654](https://github.com/storybooks/storybook/pull/2654)
- Update prereq yarn install level [#2638](https://github.com/storybooks/storybook/pull/2638)
- Separate stories in angular-cli example [#2592](https://github.com/storybooks/storybook/pull/2592)
</details>
#### Dependency Upgrades
<details>
<summary>
66 Upgrades
</summary>
- Upgraded `nodemon` in `/` from "1.14.7" to "1.14.8" [#2664](https://github.com/storybooks/storybook/pull/2664)
- Upgraded `marksy` in `addons/info` from "6.0.2" to "6.0.3" [#2664](https://github.com/storybooks/storybook/pull/2664)
- Upgraded `nodemon` in `app/react` from "1.14.7" to "1.14.8" [#2664](https://github.com/storybooks/storybook/pull/2664)
- Upgraded `nodemon` in `app/angular` from "1.14.7" to "1.14.8" [#2664](https://github.com/storybooks/storybook/pull/2664)
- Upgraded `nodemon` in `app/vue` from "1.14.7" to "1.14.8" [#2664](https://github.com/storybooks/storybook/pull/2664)
- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from "2.9.7" to "2.10.0" [#2664](https://github.com/storybooks/storybook/pull/2664)
- Upgraded `@types/lodash` in `/` from "4.14.91" to "4.14.92" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `marksy` in `addons/info` from "6.0.1" to "6.0.2" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `app/react` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `html-loader` in `app/react` from "0.5.1" to "0.5.4" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `uglifyjs-webpack-plugin` in `app/react` from "1.1.5" to "1.1.6" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `app/angular` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `uglifyjs-webpack-plugin` in `app/angular` from "1.1.5" to "1.1.6" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `app/react-native` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `uglifyjs-webpack-plugin` in `app/react-native` from "1.1.5" to "1.1.6" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `app/vue` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `uglifyjs-webpack-plugin` in `app/vue` from "1.1.5" to "1.1.6" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `@types/node` in `examples/angular-cli` from "6.0.95" to "6.0.96" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `examples/vue-kitchen-sink` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `@angular/animations` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/common` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/compiler` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/core` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/forms` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/http` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/platform-browser` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/router` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `@angular/language-service` in `examples/angular-cli` from "5.1.2" to "5.1.3" [#2648](https://github.com/storybooks/storybook/pull/2648)
- Upgraded `postcss-loader` in `app/react` from "2.0.9" to "2.0.10" [#2637](https://github.com/storybooks/storybook/pull/2637)
- Upgraded `postcss-loader` in `app/angular` from "2.0.9" to "2.0.10" [#2637](https://github.com/storybooks/storybook/pull/2637)
- Upgraded `postcss-loader` in `app/react-native` from "2.0.9" to "2.0.10" [#2637](https://github.com/storybooks/storybook/pull/2637)
- Upgraded `postcss-loader` in `app/vue` from "2.0.9" to "2.0.10" [#2637](https://github.com/storybooks/storybook/pull/2637)
- Update inquirer in / from 4.0.1 to 4.0.2 [#2632](https://github.com/storybooks/storybook/pull/2632)
- Upgraded `danger` in `/` from "2.1.8" to "2.1.10" [#2618](https://github.com/storybooks/storybook/pull/2618)
- Upgraded `autoprefixer` in `app/react` from "7.2.3" to "7.2.4" [#2618](https://github.com/storybooks/storybook/pull/2618)
- Upgraded `autoprefixer` in `app/angular` from "7.2.3" to "7.2.4" [#2618](https://github.com/storybooks/storybook/pull/2618)
- Upgraded `autoprefixer` in `app/react-native` from "7.2.3" to "7.2.4" [#2618](https://github.com/storybooks/storybook/pull/2618)
- Upgraded `autoprefixer` in `app/vue` from "7.2.3" to "7.2.4" [#2618](https://github.com/storybooks/storybook/pull/2618)
- Upgraded `nodemon` in `/` from "1.14.6" to "1.14.7" [#2612](https://github.com/storybooks/storybook/pull/2612)
- Upgraded `nodemon` in `app/react` from "1.14.6" to "1.14.7" [#2612](https://github.com/storybooks/storybook/pull/2612)
- Upgraded `nodemon` in `app/angular` from "1.14.6" to "1.14.7" [#2612](https://github.com/storybooks/storybook/pull/2612)
- Upgraded `nodemon` in `app/vue` from "1.14.6" to "1.14.7" [#2612](https://github.com/storybooks/storybook/pull/2612)
- Upgraded `vue-loader` in `app/vue` from "13.6.1" to "13.6.2" [#2611](https://github.com/storybooks/storybook/pull/2611)
- Upgraded `vue-loader` in `examples/vue-kitchen-sink` from "13.6.1" to "13.6.2" [#2611](https://github.com/storybooks/storybook/pull/2611)
- Upgraded `nodemon` in `/` from "1.14.5" to "1.14.6" [#2609](https://github.com/storybooks/storybook/pull/2609)
- Upgraded `nodemon` in `app/react` from "1.14.5" to "1.14.6" [#2609](https://github.com/storybooks/storybook/pull/2609)
- Upgraded `nodemon` in `app/angular` from "1.14.5" to "1.14.6" [#2609](https://github.com/storybooks/storybook/pull/2609)
- Upgraded `nodemon` in `app/vue` from "1.14.5" to "1.14.6" [#2609](https://github.com/storybooks/storybook/pull/2609)
- Upgraded `enzyme` in `/` from "3.2.0" to "3.3.0" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `nodemon` in `/` from "1.14.3" to "1.14.5" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `graphiql` in `addons/graphql` from "0.11.10" to "0.11.11" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `enzyme` in `addons/links` from "3.2.0" to "3.3.0" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `nodemon` in `app/react` from "1.14.3" to "1.14.5" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `nodemon` in `app/angular` from "1.14.3" to "1.14.5" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `nodemon` in `app/vue` from "1.14.3" to "1.14.5" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `enzyme` in `examples/cra-kitchen-sink` from "3.2.0" to "3.3.0" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Upgraded `enzyme` in `examples/official-storybook` from "3.2.0" to "3.3.0" [#2608](https://github.com/storybooks/storybook/pull/2608)
- Update 2 dependencies from npm [#2597](https://github.com/storybooks/storybook/pull/2597)
- Upgraded `@storybook/addon-actions` in `/docs` from "3.3.1" to "3.3.3" [#2598](https://github.com/storybooks/storybook/pull/2598)
- Upgraded `@storybook/addon-links` in `/docs` from "3.3.1" to "3.3.3" [#2598](https://github.com/storybooks/storybook/pull/2598)
- Upgraded `@storybook/addons` in `/docs` from "3.3.1" to "3.3.3" [#2598](https://github.com/storybooks/storybook/pull/2598)
- Upgraded `@storybook/react` in `/docs` from "3.3.1" to "3.3.3" [#2598](https://github.com/storybooks/storybook/pull/2598)
- Upgraded `danger` in `/` from "2.1.6" to "2.1.8" [#2599](https://github.com/storybooks/storybook/pull/2599)
- Upgraded `axe-core` in `addons/a11y` from "2.6.0" to "2.6.1" [#2599](https://github.com/storybooks/storybook/pull/2599)
</details>
# 3.3.4
2018-January-07
#### Bug Fixes
- Fix config dir detection [#2666](https://github.com/storybooks/storybook/pull/2666)
- Removed lowercase-only restriction for knobs [#2646](https://github.com/storybooks/storybook/pull/2646)
- Add IE11 compatibility meta tag [#2650](https://github.com/storybooks/storybook/pull/2650)
- Allow transparency in color knob [#2624](https://github.com/storybooks/storybook/pull/2624)
- RN: Use haul/bin/cli.js for cross-platform support [#2577](https://github.com/storybooks/storybook/pull/2577)
- Publish package sources along with transpiled files [#2604](https://github.com/storybooks/storybook/pull/2604)
- Fixed all peerDependencies for apps. [#2601](https://github.com/storybooks/storybook/pull/2601)
- Renamed angular root node to avoid name collisions [#2657](https://github.com/storybooks/storybook/pull/2657)
- Add .ts compatibility to storyshots [#2639](https://github.com/storybooks/storybook/pull/2639)
- Remove @angular/core dep from knobs peer. [#2640](https://github.com/storybooks/storybook/pull/2640)
- Angular: Change template story files extension .ts [#2594](https://github.com/storybooks/storybook/pull/2594)
- Skip serializing (Synthetic)Events [#2626](https://github.com/storybooks/storybook/pull/2626)
#### Maintenance
- Separate stories in angular-cli example [#2592](https://github.com/storybooks/storybook/pull/2592)
#### Dependency Upgrades
<details>
<summary>
13 Upgrades
</summary>
- Upgraded `@types/lodash` in `/` from "4.14.91" to "4.14.92" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `marksy` in `addons/info` from "6.0.1" to "6.0.2" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `app/react` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `html-loader` in `app/react` from "0.5.1" to "0.5.4" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `uglifyjs-webpack-plugin` in `app/react` from "1.1.5" to "1.1.6" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `app/angular` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `uglifyjs-webpack-plugin` in `app/angular` from "1.1.5" to "1.1.6" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `app/react-native` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `uglifyjs-webpack-plugin` in `app/react-native` from "1.1.5" to "1.1.6" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `app/vue` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `uglifyjs-webpack-plugin` in `app/vue` from "1.1.5" to "1.1.6" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `@types/node` in `examples/angular-cli` from "6.0.95" to "6.0.96" [#2659](https://github.com/storybooks/storybook/pull/2659)
- Upgraded `css-loader` in `examples/vue-kitchen-sink` from "0.28.7" to "0.28.8" [#2659](https://github.com/storybooks/storybook/pull/2659)
</details>
# 3.3.3
2017-December-29

View File

@ -4,7 +4,7 @@ Thanks for your interest in improving Storybook! We are a community-driven proje
Please review this document to help to streamline the process and save everyone's precious time.
This repo uses yarn workspaces, so you should `yarn@1.0.0` or higher as package manager. See [installation guide](https://yarnpkg.com/en/docs/install).
This repo uses yarn workspaces, so you should install `yarn@1.3.2` or higher as package manager. See [installation guide](https://yarnpkg.com/en/docs/install).
## Issues
@ -31,7 +31,7 @@ yarn install
yarn bootstrap --core
```
The bootstrap command will ask which sections of the codebase you want to bootstrap. Unless you're going to work with ReactNative or the Documentation, you can keep the default.
The bootstrap command might ask which sections of the codebase you want to bootstrap. Unless you're going to work with ReactNative or the Documentation, you can keep the default.
You can also pick directly from CLI:
@ -57,25 +57,33 @@ You can also pick suites from CLI. Suites available are listed below.
`yarn test --core`
This option executes test from `<rootdir>/app/react`, `<rootdir>/app/vue`, and `<rootdir>/lib`
This option executes test from `<rootdir>/app/react`, `<rootdir>/app/vue`, and `<rootdir>/lib`.
Before the tests are ran, the project must be bootstrapped with core. You can accomplish this with `yarn bootstrap --core`
##### React-Native example Tests
`yarn test --reactnative`
This option executes tests from `<rootdir>/app/react-native`
This option executes tests from `<rootdir>/app/react-native`.
Before these tests are ran, the project must be bootstrapped with the React Native example enabled. You can accomplish this by running `yarn bootstrap --reactnative`
##### Integration Tests (Screenshots of running apps)
`yarn test --integration`
This option executes tests from `<rootdir>/integration`
This option executes tests from `<rootdir>/integration`.
In order for the snapshot-integration tests to be executed properly, examples being tested must be running on their defaults ports, as declared in `integration/examples.test.js`
Puppeteer is used to launch and grab screenshots of example pages, while jest is used to assert matching images.
##### CRA-kitchen-sink - Image snapshots using Storyshots
`yarn test --image`
This option executes tests from `<rootdir>/examples/cra-kitchen-sink`
In order for the image snapshots to be correctly generated, you must have static build of the storybook up-to-date.
Puppeteer is used to launch and grab screenshots of example pages, while jest is used to assert matching images. (just like integration tests)
#### 2b. Run e2e tests for CLI
@ -95,23 +103,23 @@ In that case, please check the git diff before commiting to make sure it only co
If you want to test your own existing project using the github version of storybook, you need to `link` the packages you use in your project.
````sh
```sh
cd app/react
yarn link
cd <your-project>
yarn link @storybook/react
# repeat with whichever other parts of the monorepo you are using.
```
# repeat with whichever other parts of the monorepo you are using.
```
### Reproductions
### Reproductions
The best way to help figure out an issue you are having is to produce a minimal reproduction against the `master` branch.
The best way to help figure out an issue you are having is to produce a minimal reproduction against the `master` branch.
A good way to do that is using the example `cra-kitchen-sink` app embedded in this repository:
A good way to do that is using the example `cra-kitchen-sink` app embedded in this repository:
```sh
```sh
# Download and build this repository:
git clone https://github.com/storybooks/storybook.git
cd storybook
@ -130,7 +138,7 @@ If you want to test your own existing project using the github version of storyb
# fork the storybook repo to your account, then add the resulting remote
git remote add <your-username> https://github.com/<your-username>/storybook.git
git push -u <your-username> master
````
```
If you follow that process, you can then link to the github repository in the issue. See <https://github.com/storybooks/storybook/issues/708#issuecomment-290589886> for an example.
@ -217,7 +225,7 @@ Please have the **_latest_** stable versions of the following on your machine
### Initial Setup
If you run into trouble here, make sure your node, npm, and **_yarn_** are on the latest versions (yarn at least v1.0.0).
If you run into trouble here, make sure your node, npm, and **_yarn_** are on the latest versions (yarn at least v1.3.2).
1. `cd ~` (optional)
2. `git clone https://github.com/storybooks/storybook.git` _bonus_: use your own fork for this step
@ -296,7 +304,7 @@ If you don't see the changes rerun `yarn storybook` again in your sandbox app
This section is for Storybook maintainers who will be creating releases. It assumes:
- yarn >= 1.0.0
- yarn >= 1.3.2
- you've yarn linked `pr-log` from <https://github.com/storybooks/pr-log/pull/2>
The current manual release sequence is as follows:
@ -360,4 +368,4 @@ npm run publish -- --concurrency 1 --force-publish=*
# update the release page
open https://github.com/storybooks/storybook/releases
```
```

View File

@ -18,7 +18,20 @@
## From version 3.2.x to 3.3.x
There should be no breaking changes in this release, but read on if you're using `addon-knobs`: we advise an update to your code for efficiency's sake.
There wasn't expected be any breaking changes in this release, but unfortunately it turned out that there are some. We're revisiting our [release strategy](https://github.com/storybooks/storybook/blob/master/RELEASES.md) to follow semver more strictly.
Also read on if you're using `addon-knobs`: we advise an update to your code for efficiency's sake.
### `babel-core` is now a peer dependency ([#2494](https://github.com/storybooks/storybook/pull/2494))
This affects you if you don't use babel in your project. You may need to add `babel-core` as dev dependency:
```
npm install --save-dev babel-core
```
This was done to support different major versions of babel.
### Base webpack config now contains vital plugins ([#1775](https://github.com/storybooks/storybook/pull/1775))
This affects you if you use custom webpack config in [Full Control Mode](https://storybook.js.org/configurations/custom-webpack-config/#full-control-mode) while not preserving the plugins from `storybookBaseConfig`. Before `3.3`, preserving them was just a reccomendation, but now it [became](https://github.com/storybooks/storybook/pull/2578) a requirement.
### Refactored Knobs

View File

@ -60,6 +60,8 @@ It runs a codemod to update all package names. Read all migration details in our
For full documentation on using Storybook visit: [storybook.js.org](https://storybook.js.org)
For additional help, join us [in our Slack](https://now-examples-slackin-rrirkqohko.now.sh/)
## Projects
### Main Projects

View File

@ -116,3 +116,4 @@ in a patch release.
- For PATCH PR's, any maintainer can review, test, approve, and merge it.
- For MINOR/MAJOR PR's, once a maintainer reviews, tests, and approves it, s/he should clear it with the other maintainers before merging it into the release branch.

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-a11y",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "a11y addon for storybook",
"keywords": [
"a11y",
@ -25,8 +25,9 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/components": "^3.3.3",
"@storybook/components": "^3.4.0-alpha.4",
"axe-core": "^2.6.1",
"glamorous": "^4.11.2",
"prop-types": "^15.6.0"
},
"peerDependencies": {

View File

@ -6,10 +6,10 @@ import Report from './Report';
const styles = {
passes: {
color: '#2ecc71',
color: '#0D6731',
},
violations: {
color: '#e74c3c',
color: '#AC2300',
},
};
@ -47,11 +47,11 @@ class Panel extends Component {
<Tabs
tabs={[
{
label: <span style={styles.violations}>Violations</span>,
label: <span style={styles.violations}>{violations.length} Violations</span>,
panel: <Report passes={false} items={violations} empty="No a11y violations found." />,
},
{
label: <span style={styles.passes}>Passes</span>,
label: <span style={styles.passes}>{passes.length} Passes</span>,
panel: <Report passes items={passes} empty="No a11y check passed" />,
},
]}

View File

@ -0,0 +1,17 @@
import glamorous from 'glamorous';
const RerunButton = glamorous.button({
position: 'absolute',
bottom: 0,
right: 0,
border: 'none',
borderTop: 'solid 1px rgba(0, 0, 0, 0.2)',
borderLeft: 'solid 1px rgba(0, 0, 0, 0.2)',
background: 'rgba(255, 255, 255, 0.5)',
padding: '5px 10px',
borderRadius: '4px 0 0 0',
color: 'rgba(0, 0, 0, 0.5)',
textTransform: 'uppercase',
});
export default RerunButton;

View File

@ -1,6 +1,7 @@
import React from 'react';
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import addons from '@storybook/addons';
import RerunButton from './RerunButton';
import Item from './Item';
const styles = {
@ -17,17 +18,23 @@ const styles = {
},
};
function Report({ items, empty, passes }) {
if (items.length) {
return (
function onRerunClick() {
const channel = addons.getChannel();
channel.emit('addon:a11y:rerun');
}
const Report = ({ items, empty, passes }) => (
<Fragment>
{items.length ? (
<div style={styles.container}>
{items.map(item => <Item passes={passes} item={item} key={item.id} />)}
</div>
);
}
return <span style={styles.empty}>{empty}</span>;
}
) : (
<span style={styles.empty}>{empty}</span>
)}
<RerunButton onClick={onRerunClick}>Re-run tests</RerunButton>
</Fragment>
);
Report.propTypes = {
items: PropTypes.arrayOf(

View File

@ -5,6 +5,7 @@ import { baseFonts } from '@storybook/components';
const styles = {
container: {
width: '100%',
position: 'relative',
...baseFonts,
},
tabs: {

View File

@ -15,8 +15,24 @@ class WrapStory extends Component {
channel: {},
};
/* eslint-disable react/no-find-dom-node */
constructor(props) {
super(props);
this.runA11yCheck = this.runA11yCheck.bind(this);
}
componentDidMount() {
const { channel } = this.props;
channel.on('addon:a11y:rerun', this.runA11yCheck);
this.runA11yCheck();
}
componentWillUnmount() {
const { channel } = this.props;
channel.removeListener('addon:a11y:rerun', this.runA11yCheck);
}
/* eslint-disable react/no-find-dom-node */
runA11yCheck() {
const { channel } = this.props;
const wrapper = findDOMNode(this);

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-actions",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "Action Logger addon for storybook",
"keywords": [
"storybook"

View File

@ -2,5 +2,6 @@ export canConfigureName from './canConfigureName.js';
export getPropertiesList from './getPropertiesList.js';
export isObject from './isObject.js';
export muteProperty from './muteProperty.js';
export prepareArguments from './prepareArguments';
export typeReviver from './typeReviver.js';
export typeReplacer from './typeReplacer.js';

View File

@ -0,0 +1,13 @@
import { decycle } from '../index';
export default function prepareArguments(arg) {
if (arg && typeof arg.preventDefault !== 'undefined') {
return JSON.stringify(`[${arg.constructor.name}]`);
}
try {
return JSON.stringify(decycle(arg));
} catch (error) {
return error.toString(); // IE still cyclic.
}
}

View File

@ -3,25 +3,12 @@
import addons from '@storybook/addons';
import uuid from 'uuid/v1';
import { EVENT_ID } from './';
import { decycle } from './lib';
import { canConfigureName } from './lib/util';
import { canConfigureName, prepareArguments } from './lib/util';
export function action(name) {
// eslint-disable-next-line no-shadow
const handler = function action(..._args) {
const args = _args.map(arg => {
let result;
try {
result = JSON.stringify(decycle(arg));
} catch (error) {
// IE still cyclic.
return JSON.stringify(error.toString());
}
return result;
});
const args = _args.map(prepareArguments);
const channel = addons.getChannel();
const id = uuid();
channel.emit(EVENT_ID, {

View File

@ -1,15 +1,30 @@
# addon-backgrounds
# Storybook Addon Backgrounds
[![Build Status](https://travis-ci.org/storybooks/addon-backgrounds.svg?branch=travis)](https://travis-ci.org/storybooks/addon-backgrounds)
[![Build Status on CircleCI](https://circleci.com/gh/storybooks/storybook.svg?style=shield)](https://circleci.com/gh/storybooks/storybook)
[![CodeFactor](https://www.codefactor.io/repository/github/storybooks/storybook/badge)](https://www.codefactor.io/repository/github/storybooks/storybook)
[![Known Vulnerabilities](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847/badge.svg)](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
![React Storybook Screenshot](./.storybook/backgrounds.gif)
* * *
### Getting Started
Storybook Centered Decorator can be used to center components inside the preview in [Storybook](https://storybook.js.org).
This addon works with Storybook for:
- [React](https://github.com/storybooks/storybook/tree/master/app/react)
![React Storybook Screenshot](https://storybook.js.org/img/addon-backgrounds.gif)
## Installation
```sh
npm i --save @storybook/addon-backgrounds
```
## Configuration
Then create a file called `addons.js` in your storybook config.
Add following content to it:
@ -18,6 +33,8 @@ Add following content to it:
import '@storybook/addon-backgrounds/register';
```
## Usage
Then write your stories like this:
```js
@ -33,23 +50,24 @@ storiesOf("Button", module)
.add("with text", () => <button>Click me</button>);
```
### Development
Of course it's easy to create a library module so you can re-use:
This project is built using typescript and is tested with jest. To get started, clone this repo and run the following command:
```js
import addonBackgrounds from "@storybook/addon-backgrounds";
```bash
$ npm install # install node deps
export const backgrounds = addonBackgrounds([
{ name: "twitter", value: "#00aced", default: true },
{ name: "facebook", value: "#3b5998" },
]);
```
To run the project locally, run:
```js
import React from 'react';
import { storiesOf } from "@storybook/react";
```bash
$ npm run storybook # for storybook testing
# (coming soon) $ npm run test-watch # for testing
```
To test the project run:
```bash
$ npm test
import { backgrounds } from "./my-lib";
storiesOf("Button", module)
.addDecorator(backgrounds)
.add("with text", () => <button>Click me</button>);
```

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-backgrounds",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "A storybook addon to show different backgrounds for your preview",
"keywords": [
"addon",

View File

@ -5,7 +5,7 @@ import addons from '@storybook/addons';
const style = {
wrapper: {
overflow: 'scroll',
overflow: 'auto',
position: 'fixed',
top: 0,
bottom: 0,

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-centered",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "Storybook decorator to center components",
"license": "MIT",
"author": "Muhammed Thanish <mnmtanish@gmail.com>",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-events",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "Add events to your Storybook stories.",
"keywords": [
"addon",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-graphql",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "Storybook addon to display the GraphiQL IDE",
"keywords": [
"storybook"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 160 KiB

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-info",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "A Storybook addon to show additional information for your stories.",
"license": "MIT",
"main": "dist/index.js",
@ -15,11 +15,12 @@
"storybook": "start-storybook -p 9010"
},
"dependencies": {
"@storybook/client-logger": "^3.3.3",
"@storybook/components": "^3.3.3",
"@storybook/client-logger": "^3.4.0-alpha.4",
"@storybook/components": "^3.4.0-alpha.4",
"babel-runtime": "^6.26.0",
"glamorous": "^4.11.2",
"global": "^4.3.2",
"marksy": "^6.0.1",
"marksy": "^6.0.3",
"nested-object-assign": "^1.0.1",
"prop-types": "^15.6.0",
"react-addons-create-fragment": "^15.5.3",

File diff suppressed because it is too large Load Diff

View File

@ -1,46 +1,47 @@
import React from 'react';
import PropTypes from 'prop-types';
import { withTheme } from 'glamorous';
import createFragment from 'react-addons-create-fragment';
const valueStyles = {
const getValueStyles = (codeColors = {}) => ({
func: {
color: '#170',
color: codeColors.func || '#170',
},
attr: {
color: '#666',
color: codeColors.attr || '#666',
},
object: {
color: '#666',
color: codeColors.object || '#666',
},
array: {
color: '#666',
color: codeColors.array || '#666',
},
number: {
color: '#a11',
color: codeColors.number || '#a11',
},
string: {
color: '#22a',
color: codeColors.string || '#22a',
wordBreak: 'break-word',
},
bool: {
color: '#a11',
color: codeColors.bool || '#a11',
},
empty: {
color: '#777',
},
};
});
function previewArray(val, maxPropArrayLength) {
function previewArray(val, maxPropArrayLength, valueStyles) {
const items = {};
val.slice(0, maxPropArrayLength).forEach((item, i) => {
items[`n${i}`] = <PropVal val={item} />;
items[`n${i}`] = <PropVal val={item} valueStyles={valueStyles} />;
items[`c${i}`] = ', ';
});
if (val.length > maxPropArrayLength) {
@ -51,13 +52,13 @@ function previewArray(val, maxPropArrayLength) {
return <span style={valueStyles.array}>[{createFragment(items)}]</span>;
}
function previewObject(val, maxPropObjectKeys) {
function previewObject(val, maxPropObjectKeys, valueStyles) {
const names = Object.keys(val);
const items = {};
names.slice(0, maxPropObjectKeys).forEach((name, i) => {
items[`k${i}`] = <span style={valueStyles.attr}>{name}</span>;
items[`c${i}`] = ': ';
items[`v${i}`] = <PropVal val={val[name]} />;
items[`v${i}`] = <PropVal val={val[name]} valueStyles={valueStyles} />;
items[`m${i}`] = ', ';
});
if (names.length > maxPropObjectKeys) {
@ -74,11 +75,13 @@ function previewObject(val, maxPropObjectKeys) {
);
}
export default function PropVal(props) {
const { maxPropObjectKeys, maxPropArrayLength, maxPropStringLength } = props;
function PropVal(props) {
const { maxPropObjectKeys, maxPropArrayLength, maxPropStringLength, theme } = props;
let { val } = props;
const { codeColors } = theme || {};
let braceWrap = true;
let content = null;
const valueStyles = props.valueStyles || getValueStyles(codeColors);
if (typeof val === 'number') {
content = <span style={valueStyles.number}>{val}</span>;
@ -91,7 +94,7 @@ export default function PropVal(props) {
} else if (typeof val === 'boolean') {
content = <span style={valueStyles.bool}>{`${val}`}</span>;
} else if (Array.isArray(val)) {
content = previewArray(val, maxPropArrayLength);
content = previewArray(val, maxPropArrayLength, valueStyles);
} else if (typeof val === 'function') {
content = <span style={valueStyles.func}>{val.name ? `${val.name}()` : 'anonymous()'}</span>;
} else if (!val) {
@ -105,7 +108,7 @@ export default function PropVal(props) {
</span>
);
} else {
content = previewObject(val, maxPropObjectKeys);
content = previewObject(val, maxPropObjectKeys, valueStyles);
}
if (!braceWrap) return content;
@ -118,6 +121,8 @@ PropVal.defaultProps = {
maxPropObjectKeys: 3,
maxPropArrayLength: 3,
maxPropStringLength: 50,
theme: {},
valueStyles: null,
};
PropVal.propTypes = {
@ -125,4 +130,19 @@ PropVal.propTypes = {
maxPropObjectKeys: PropTypes.number,
maxPropArrayLength: PropTypes.number,
maxPropStringLength: PropTypes.number,
theme: PropTypes.shape({
codeColors: PropTypes.object,
}),
valueStyles: PropTypes.shape({
func: PropTypes.object,
attr: PropTypes.object,
object: PropTypes.object,
array: PropTypes.object,
number: PropTypes.object,
string: PropTypes.object,
bool: PropTypes.object,
empty: PropTypes.object,
}),
};
export default withTheme(PropVal);

View File

@ -4,6 +4,7 @@ import React, { createElement } from 'react';
import PropTypes from 'prop-types';
import global from 'global';
import { baseFonts } from '@storybook/components';
import { ThemeProvider } from 'glamorous';
import marksy from 'marksy';
@ -364,11 +365,11 @@ export default class Story extends React.Component {
}
render() {
if (this.props.showInline) {
return this._renderInline();
}
return this._renderOverlay();
return (
<ThemeProvider theme={this.state.stylesheet}>
{this.props.showInline ? this._renderInline() : this._renderOverlay()}
</ThemeProvider>
);
}
}

View File

@ -52,21 +52,6 @@ Code.defaultProps = {
code: null,
};
export function Pre(props) {
const style = {
fontSize: '.88em',
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
backgroundColor: '#fafafa',
padding: '.5rem',
lineHeight: 1.5,
overflowX: 'scroll',
};
return <pre style={style}>{props.children}</pre>;
}
Pre.propTypes = { children: PropTypes.node };
Pre.defaultProps = { children: null };
export function Blockquote(props) {
const style = {
fontSize: '1.88em',
@ -79,3 +64,5 @@ export function Blockquote(props) {
Blockquote.propTypes = { children: PropTypes.node };
Blockquote.defaultProps = { children: null };
export { default as Pre } from './pre/pre';

View File

@ -0,0 +1,13 @@
/* eslint-disable no-undef */
export default function copy(str) {
const tmp = document.createElement('TEXTAREA');
const focus = document.activeElement;
tmp.value = str;
document.body.appendChild(tmp);
tmp.select();
document.execCommand('copy');
document.body.removeChild(tmp);
focus.focus();
}

View File

@ -0,0 +1,68 @@
import React from 'react';
import PropTypes from 'prop-types';
import glamorous, { withTheme } from 'glamorous';
const Button = glamorous.button(
{
overflow: 'hidden',
border: '1px solid #eee',
borderRadius: 3,
backgroundColor: '#FFFFFF',
cursor: 'pointer',
fontSize: 13,
padding: '3px 10px',
alignSelf: 'flex-start',
':hover': {
backgroundColor: '#f4f7fa',
borderColor: '#ddd',
},
':active': {
backgroundColor: '#e9ecef',
borderColor: '#ccc',
},
},
props => props.styles
);
const ContentWrapper = glamorous.div(
{
transition: 'transform .2s ease',
height: 16,
},
props => ({
...props.styles,
transform: props.toggled ? 'translateY(0px)' : 'translateY(-100%) translateY(-6px)',
})
);
function CopyButton(props) {
const { copyButton = {}, copyButtonContent } = props.theme;
const { toggleText = 'Copied!', text = 'Copy', ...copyButtonStyles } = copyButton;
return (
<Button onClick={props.onClick} styles={copyButtonStyles}>
<ContentWrapper styles={copyButtonContent} toggled={props.toggled}>
<div style={{ marginBottom: 6 }}>{toggleText}</div>
<div>{text}</div>
</ContentWrapper>
</Button>
);
}
CopyButton.propTypes = {
onClick: PropTypes.func,
toggled: PropTypes.bool,
theme: PropTypes.shape({
copyButton: PropTypes.object,
}),
};
CopyButton.defaultProps = {
onClick: () => {},
toggled: false,
theme: {},
};
export default withTheme(CopyButton);

View File

@ -0,0 +1,75 @@
import React from 'react';
import PropTypes from 'prop-types';
import glamorous, { withTheme } from 'glamorous';
import CopyButton from './copyButton';
import copy from './copy';
const TOGGLE_TIMEOUT = 1800;
const StyledPre = glamorous.pre(
{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
fontSize: '.88em',
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
backgroundColor: '#fafafa',
padding: '.5rem',
lineHeight: 1.5,
overflowX: 'scroll',
},
props => props.styles
);
class Pre extends React.Component {
state = {
copied: false,
};
setRef = elem => {
this.pre = elem;
};
handleClick = () => {
const text = this.pre && this.pre.innerText;
if (!text) {
return;
}
copy(text);
this.setState({ copied: true });
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.setState({ copied: false });
}, TOGGLE_TIMEOUT);
};
render() {
const { pre } = this.props.theme;
return (
<StyledPre styles={pre}>
<div ref={this.setRef}>{this.props.children}</div>
<CopyButton onClick={this.handleClick} toggled={this.state.copied} />
</StyledPre>
);
}
}
Pre.propTypes = {
children: PropTypes.node,
theme: PropTypes.shape({
pre: PropTypes.object,
}),
};
Pre.defaultProps = {
children: null,
theme: {},
};
export default withTheme(Pre);

View File

@ -8,13 +8,13 @@ const OneOfType = ({ propType }) => {
return (
<span>
{propType.value
.map((value, i) => [
<PrettyPropType
key={`${value.name}${value.value ? `-${value.value}` : ''}`}
propType={value}
/>,
i < length - 1 ? <span> | </span> : null,
])
.map((value, i) => {
const key = `${value.name}${value.value ? `-${value.value}` : ''}`;
return [
<PrettyPropType key={key} propType={value} />,
i < length - 1 ? <span key={`${key}-separator`}> | </span> : null,
];
})
.reduce((acc, tuple) => acc.concat(tuple), [])}
</span>
);

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-jest",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "React storybook addon that show component jest report",
"keywords": [
"addon",
@ -25,7 +25,7 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/components": "^3.3.3",
"@storybook/components": "^3.4.0-alpha.4",
"glamor": "^2.20.40",
"glamorous": "^4.11.2",
"global": "^4.3.2",

View File

@ -1,2 +1 @@
src
.babelrc

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-knobs",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "Storybook Addon Prop Editor Component",
"license": "MIT",
"main": "dist/index.js",
@ -33,7 +33,6 @@
"vue": "^2.5.13"
},
"peerDependencies": {
"@angular/core": ">=4.0.0",
"@storybook/addons": "^3.3.0",
"react": "*",
"react-dom": "*"

1
addons/knobs/polymer.js Normal file
View File

@ -0,0 +1 @@
module.exports = require('./dist/polymer');

View File

@ -1,9 +1,9 @@
/* eslint no-underscore-dangle: 0 */
// eslint-disable-next-line import/no-extraneous-dependencies
import { Component, SimpleChange, ChangeDetectorRef } from '@angular/core';
import { getParameters, getAnnotations, getPropMetadata } from './utils';
const getComponentMetadata = ({ component, props = {}, moduleMetadata = {} }) => {
const getComponentMetadata = ({ component, props = {}, moduleMetadata = {}, template = '' }) => {
if (!component || typeof component !== 'function') throw new Error('No valid component provided');
const componentMeta = getAnnotations(component)[0] || {};
@ -16,6 +16,7 @@ const getComponentMetadata = ({ component, props = {}, moduleMetadata = {} }) =>
componentMeta,
propsMeta,
moduleMetadata,
template,
params: paramsMetadata,
};
};
@ -29,8 +30,8 @@ const getAnnotatedComponent = ({ componentMeta, component, params, knobStore, ch
};
KnobWrapperComponent.prototype = Object.create(component.prototype);
KnobWrapperComponent.__annotations__ = [new Component(componentMeta)];
KnobWrapperComponent.__parameters__ = [[ChangeDetectorRef], ...params];
KnobWrapperComponent.annotations = [new Component(componentMeta)];
KnobWrapperComponent.parameters = [[ChangeDetectorRef], ...params];
KnobWrapperComponent.prototype.constructor = KnobWrapperComponent;
KnobWrapperComponent.prototype.ngOnInit = function onInit() {
@ -73,11 +74,10 @@ const getAnnotatedComponent = ({ componentMeta, component, params, knobStore, ch
const oldValue = knobOptions.value;
knobOptions.value = value;
knobStore.markAllUnused();
const lowercasedName = name.toLocaleLowerCase();
this[lowercasedName] = value;
this[name] = value;
this.cd.detectChanges();
this.ngOnChanges({
[lowercasedName]: new SimpleChange(oldValue, value, false),
[name]: new SimpleChange(oldValue, value, false),
});
};

View File

@ -1,5 +1,6 @@
/* eslint-disable no-param-reassign */
/* globals window */
/* eslint-disable no-param-reassign */
// eslint-disable-next-line import/no-extraneous-dependencies
import { ɵReflectionCapabilities } from '@angular/core';
// eslint-disable-next-line new-cap

View File

@ -84,7 +84,12 @@ class ColorType extends React.Component {
this.popover = e;
}}
>
<SketchPicker color={knob.value} onChange={color => onChange(color.hex)} />
<SketchPicker
color={knob.value}
onChange={color =>
onChange(`rgba(${color.rgb.r},${color.rgb.g},${color.rgb.b},${color.rgb.a})`)
}
/>
</div>
),
() => null

View File

@ -0,0 +1,87 @@
<dom-module id="wrap-story">
<script>
class WrapStory extends HTMLElement {
static get is() {
return 'wrap-story';
}
constructor(component, channel, context, storyFn, knobStore) {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = '<div id="wrapper"></div>';
this.channel = channel;
this.context = context;
this.storyFn = storyFn;
this.knobStore = knobStore;
this.knobChanged = this.knobChanged.bind(this);
this.knobClicked = this.knobClicked.bind(this);
this.resetKnobs = this.resetKnobs.bind(this);
this.setPaneKnobs = this.setPaneKnobs.bind(this);
this.connectChannel(this.channel);
this.knobStore.subscribe(this.setPaneKnobs);
this.render(component);
}
disconnectedCallback() {
this.disconnectChannel(this.channel);
this.knobStore.unsubscribe(this.setPaneKnobs);
}
connectChannel(channel) {
channel.on('addon:knobs:knobChange', this.knobChanged);
channel.on('addon:knobs:knobClick', this.knobClicked);
channel.on('addon:knobs:reset', this.resetKnobs);
}
disconnectChannel(channel) {
channel.removeListener('addon:knobs:knobChange', this.knobChanged);
channel.removeListener('addon:knobs:knobClick', this.knobClicked);
channel.removeListener('addon:knobs:reset', this.resetKnobs);
}
knobChanged(change) {
const { name, value } = change;
const { knobStore, storyFn, context } = this;
// Update the related knob and it's value.
const knobOptions = knobStore.get(name);
knobOptions.value = value;
knobStore.markAllUnused();
this.render(storyFn(context));
}
knobClicked(clicked) {
const knobOptions = this.knobStore.get(clicked.name);
knobOptions.callback();
}
resetKnobs() {
const { knobStore, storyFn, context } = this;
knobStore.reset();
this.render(storyFn(context));
this.setPaneKnobs(this.channel, this.knobStore, false);
}
setPaneKnobs(timestamp = +new Date()) {
const { channel, knobStore } = this;
channel.emit('addon:knobs:setKnobs', { knobs: knobStore.getAll(), timestamp });
}
render(component) {
const wrapper = this.shadowRoot.querySelector('div#wrapper');
if (typeof component === 'string') {
wrapper.innerHTML = component;
} else {
wrapper.innerHTML = '';
wrapper.appendChild(component);
}
}
}
customElements.define(WrapStory.is, WrapStory);
</script>
</dom-module>

View File

@ -0,0 +1,36 @@
import addons from '@storybook/addons';
import window from 'global';
import './WrapStory.html';
import { knob, text, boolean, number, color, object, array, date, select, manager } from '../base';
export { knob, text, boolean, number, color, object, array, date, select };
export function button(name, callback) {
return manager.knob(name, { type: 'button', value: Date.now(), callback, hideLabel: true });
}
function prepareComponent({ getStory, context, channel, knobStore }) {
const WrapStory = window.customElements.get('wrap-story');
return new WrapStory(getStory(context), channel, context, getStory, knobStore);
}
export const polymerHandler = (channel, knobStore) => getStory => context =>
prepareComponent({ getStory, context, channel, knobStore });
function wrapperKnobs(options) {
const channel = addons.getChannel();
manager.setChannel(channel);
if (options) channel.emit('addon:knobs:setOptions', options);
return polymerHandler(channel, manager.knobStore);
}
export function withKnobs(storyFn, context) {
return wrapperKnobs()(storyFn)(context);
}
export function withKnobsOptions(options = {}) {
return (storyFn, context) => wrapperKnobs(options)(storyFn)(context);
}

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-links",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "Story Links addon for storybook",
"keywords": [
"storybook"
@ -22,7 +22,7 @@
"storybook": "start-storybook -p 9001"
},
"dependencies": {
"@storybook/components": "^3.3.3",
"@storybook/components": "^3.4.0-alpha.4",
"global": "^4.3.2",
"prop-types": "^15.5.10"
},
@ -30,7 +30,7 @@
"enzyme": "^3.3.0",
"react": "^16.1.0",
"react-dom": "^16.1.0",
"shelljs": "^0.7.8"
"shelljs": "^0.8.0"
},
"peerDependencies": {
"@storybook/addons": "^3.3.0",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-notes",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "Write notes for your Storybook stories.",
"keywords": [
"addon",

View File

@ -90,13 +90,19 @@ setOptions({
* @type {Regex}
*/
hierarchySeparator: null,
/**
* regex for finding the hierarchy root separator
* @example:
* null - turn off mulitple hierarchy roots
* /\|/ - split by `|`
* @type {Regex}
*/
hierarchyRootSeparator: null,
/**
* sidebar tree animations
* @type {Boolean}
*/
sidebarAnimations: true,
/**
* id to select an addon panel
* @type {String}

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-options",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "Options addon for storybook",
"keywords": [
"storybook"

View File

@ -13,6 +13,14 @@ function regExpStringify(exp) {
return null;
}
function hasOwnProp(object, propName) {
return Object.prototype.hasOwnProperty.call(object, propName);
}
function withRegexProp(object, propName) {
return hasOwnProp(object, propName) ? { [propName]: regExpStringify(object[propName]) } : {};
}
// setOptions function will send Storybook UI options when the channel is
// ready. If called before, options will be cached until it can be sent.
export function setOptions(newOptions) {
@ -23,16 +31,13 @@ export function setOptions(newOptions) {
);
}
let options = newOptions;
// since 'undefined' and 'null' are the valid values we don't want to
// override the hierarchySeparator if the prop is missing
if (Object.prototype.hasOwnProperty.call(newOptions, 'hierarchySeparator')) {
options = {
...newOptions,
hierarchySeparator: regExpStringify(newOptions.hierarchySeparator),
};
}
// override the hierarchySeparator or hierarchyRootSeparator if the prop is missing
const options = {
...newOptions,
...withRegexProp(newOptions, 'hierarchySeparator'),
...withRegexProp(newOptions, 'hierarchyRootSeparator'),
};
channel.emit(EVENT_ID, { options });
}

View File

@ -1,2 +1 @@
src
.babelrc

View File

@ -36,7 +36,7 @@ Usually, you might already have completed this step. If not, here are some resou
> Note: If you use React 16, you'll need to follow [these additional instructions](https://github.com/facebook/react/issues/9102#issuecomment-283873039).
## Configure Storyshots
## Configure Storyshots for HTML snapshots
Create a new test file with the name `Storyshots.test.js`. (Or whatever the name you prefer, as long as it matches Jest's config [`testMatch`](http://facebook.github.io/jest/docs/en/configuration.html#testmatch-array-string)).
Then add following content to it:
@ -53,6 +53,103 @@ Now run your Jest test command. (Usually, `npm test`.) Then you can see all of y
![Screenshot](docs/storyshots.png)
## Configure Storyshots for image snapshots
/*\ **React-native** is **not supported** by this test function.
Internally, it uses [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot).
When willing to generate and compare image snapshots for your stories, you have to two options:
- Have a storybook running (ie. accessible via http(s):// , for instance using `yarn run storybook`)
- Have a static build of the storybook (for instance, using `yarn run build-storybook`)
Then you will need to reference the storybook URL (`file://...` if local, `http(s)://...` if served)
### Using default values for _imageSnapshots_
Then you can either create a new Storyshots instance or edit the one you previously used:
```js
import initStoryshots, { imageSnapshot } from '@storybook/addon-storyshots';
initStoryshots({suite: 'Image storyshots', test: imageSnapshot});
```
This will assume you have a storybook running on at _http://localhost:6006_.
Internally here are the steps:
- Launches a Chrome headless using [puppeteer](https://github.com/GoogleChrome/puppeteer)
- Browses each stories (calling _http://localhost:6006/iframe.html?..._ URL),
- Take screenshots & save all images under _\_image_snapshots\__ folder.
### Specifying the storybook URL
If you want to set specific storybook URL, you can specify via the `storybookUrl` parameter, see below:
```js
import initStoryshots, { imageSnapshot } from '@storybook/addon-storyshots';
initStoryshots({suite: 'Image storyshots', test: imageSnapshot({storybookUrl: 'http://my-specific-domain.com:9010'})});
```
The above config will use _https://my-specific-domain.com:9010_ for screenshots.
You may also use a local static build of storybook if you do not want to run the webpack dev-server:
```js
import initStoryshots, { imageSnapshot } from '@storybook/addon-storyshots';
initStoryshots({suite: 'Image storyshots', test: imageSnapshot({storybookUrl: 'file:///path/to/my/storybook-static'})});
```
### Specifying options to _jest-image-snapshots_
If you wish to customize [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot), then you can provide a `getMatchOptions` parameter that should return the options config object.
```js
import initStoryshots, { imageSnapshot } from '@storybook/addon-storyshots';
const getMatchOptions = ({context : {kind, story}, url}) => {
return {
failureThreshold: 0.2,
failureThresholdType: 'percent',
}
}
initStoryshots({suite: 'Image storyshots', test: imageSnapshot({storybookUrl: 'http://localhost:6006', getMatchOptions})});
```
`getMatchOptions` receives an object: `{ context: {kind, story}, url}`. _kind_ is the kind of the story and the _story_ its name. _url_ is the URL the browser will use to screenshot.
### Integrate image storyshots with regular app
You may want to use another Jest project to run your image snapshots as they require more resources: Chrome and Storybook built/served.
You can find a working example of this in the [official-storybook](https://github.com/storybooks/storybook/tree/master/examples/official-storybook) example.
### Integrate image storyshots with [Create React App](https://github.com/facebookincubator/create-react-app)
You have two options here, you can either:
- Simply add the storyshots configuration inside any of your `test.js` file. You must ensure you have either a running storybook or a static build available.
- Create a custom test file using Jest outside of the CRA scope:
A more robust approach would be to separate existing test files ran by create-react-app (anything `(test|spec).js` suffixed files) from the test files to run storyshots with image snapshots.
This use case can be achieved by using a custom name for the test file, ie something like `image-storyshots.runner.js`. This file will contains the `initStoryshots` call with image snapshots configuration.
Then you will create a separate script entry in your package.json, for instance
```json
{
"scripts": {
"image-snapshots" : "jest image-storyshots.runner.js --config path/to/custom/jest.config.json"
}
}
```
Note that you will certainly need a custom config file for Jest as you run it outside of the CRA scope and thus you do not have the built-in config.
Once that's setup, you can run `yarn run image-snapshots` (or `npm run image-snapshots`).
### Reminder
An image snapshot is simply a screenshot taken by a web browser (in our case, Chrome).
The browser opens a page (either using the static build of storybook or a running instance of Storybook)
If you run your test without either the static build or a running instance, this wont work.
To make sure your screenshots are taken from latest changes of your Storybook, you must keep your static build or running Storybook up-to-date.
This can be achieved by adding a step before running the test ie: `yarn run build-storybook && yarn run image-snapshots`.
If you run the image snapshots against a running Storybook in dev mode, you don't have to care about being up-to-date because the dev-server is watching changes and rebuilds automatically.
## Options
### `configPath`

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-storyshots",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "StoryShots is a Jest Snapshot Testing Addon for Storybook.",
"license": "MIT",
"main": "dist/index.js",
@ -16,17 +16,19 @@
"example": "jest storyshot.test"
},
"dependencies": {
"@storybook/channels": "^3.3.3",
"@storybook/channels": "^3.4.0-alpha.4",
"babel-runtime": "^6.26.0",
"glob": "^7.1.2",
"global": "^4.3.2",
"jest-image-snapshot": "^2.3.0",
"jest-specific-snapshot": "^0.3.0",
"prop-types": "^15.6.0",
"puppeteer": "^0.13.0",
"read-pkg-up": "^3.0.0"
},
"devDependencies": {
"@storybook/addons": "^3.3.3",
"@storybook/react": "^3.3.3",
"@storybook/addons": "^3.4.0-alpha.4",
"@storybook/react": "^3.4.0-alpha.4",
"babel-cli": "^6.26.0",
"babel-jest": "^20.0.3",
"babel-plugin-transform-runtime": "^6.23.0",
@ -40,7 +42,7 @@
"react-dom": "^16.1.0"
},
"peerDependencies": {
"@storybook/addons": "^3.3.3",
"@storybook/addons": "^3.4.0-alpha.4",
"babel-core": "^6.26.0 || ^7.0.0-0",
"react": "*",
"react-test-renderer": "*"

View File

@ -1,7 +1,7 @@
import path from 'path';
import fs from 'fs';
import glob from 'glob';
import global, { describe, it } from 'global';
import global, { describe, it, beforeEach, afterEach } from 'global';
import readPkgUp from 'read-pkg-up';
import addons from '@storybook/addons';
@ -18,6 +18,8 @@ export {
renderOnly,
} from './test-bodies';
export { imageSnapshot } from './test-body-image-snapshot';
export { getSnapshotFileName };
let storybook;
@ -100,6 +102,20 @@ export default function testStorySnapshots(options = {}) {
}
describe(suite, () => {
beforeEach(() => {
if (typeof options.test.beforeEach === 'function') {
return options.test.beforeEach();
}
return Promise.resolve();
});
afterEach(() => {
if (typeof options.test.afterEach === 'function') {
return options.test.afterEach();
}
return Promise.resolve();
});
describe(kind, () => {
// eslint-disable-next-line
for (const story of group.stories) {
@ -109,7 +125,7 @@ export default function testStorySnapshots(options = {}) {
}
it(story.name, () => {
const context = { fileName, kind, story: story.name };
const context = { fileName, kind, story: story.name, isRNStorybook };
return options.test({
story,
context,
@ -122,14 +138,13 @@ export default function testStorySnapshots(options = {}) {
}
describe('Storyshots Integrity', () => {
describe('Abandoned Storyshots', () => {
test('Abandoned Storyshots', () => {
const storyshots = glob.sync('**/*.storyshot');
const abandonedStoryshots = storyshots.filter(fileName => {
const possibleStoriesFiles = getPossibleStoriesFiles(fileName);
return !possibleStoriesFiles.some(fs.existsSync);
});
expect(abandonedStoryshots).toHaveLength(0);
});
});

View File

@ -0,0 +1,67 @@
import puppeteer from 'puppeteer';
import { toMatchImageSnapshot } from 'jest-image-snapshot';
expect.extend({ toMatchImageSnapshot });
export const imageSnapshot = ({
storybookUrl = 'http://localhost:6006',
getMatchOptions = () => {},
}) => {
let browser; // holds ref to browser. (ie. Chrome)
let page; // Hold ref to the page to screenshot.
const testFn = ({ context }) => {
if (context.isRNStorybook) {
// Skip tests since we de not support RN image snapshots.
console.error(
"It seems you are running imageSnapshot on RN app and it's not supported. Skipping test."
);
return Promise.resolve();
}
const encodedKind = encodeURIComponent(context.kind);
const encodedStoryName = encodeURIComponent(context.story);
const storyUrl = `/iframe.html?selectedKind=${encodedKind}&selectedStory=${encodedStoryName}`;
const url = storybookUrl + storyUrl;
if (!browser || !page) {
console.error(
`Error when generating image snapshot for test ${context.kind} - ${
context.story
} : It seems the headless browser is not running.`
);
return Promise.reject(new Error('no-headless-browser-running'));
}
expect.assertions(1);
return page
.goto(url)
.catch(e => {
console.error(
`ERROR WHILE CONNECTING TO ${url}, did you start or build the storybook first ? A storybook instance should be running or a static version should be built when using image snapshot feature.`,
e
);
throw e;
})
.then(() =>
page.screenshot().then(image => {
expect(image).toMatchImageSnapshot(getMatchOptions({ context, url }));
})
);
};
testFn.beforeEach = () =>
puppeteer
// add some options "no-sandbox" to make it work properly on some Linux systems as proposed here: https://github.com/Googlechrome/puppeteer/issues/290#issuecomment-322851507
.launch({ args: ['--no-sandbox ', '--disable-setuid-sandbox'] })
.then(b => {
browser = b;
})
.then(() => browser.newPage())
.then(p => {
page = p;
});
testFn.afterEach = () => browser.close();
return testFn;
};

View File

@ -11,6 +11,8 @@ export function getPossibleStoriesFiles(storyshotFile) {
return [
path.format({ dir: path.dirname(dir), name, ext: '.js' }),
path.format({ dir: path.dirname(dir), name, ext: '.jsx' }),
path.format({ dir: path.dirname(dir), name, ext: '.ts' }),
path.format({ dir: path.dirname(dir), name, ext: '.tsx' }),
];
}

View File

@ -4,7 +4,7 @@ Storybook Viewport Addon allows your stories to be displayed in different sizes
This addon works with Storybook for: [React](https://github.com/storybooks/storybook/tree/master/app/react) and [Vue](https://github.com/storybooks/storybook/tree/master/app/vue).
![Screenshot](https://github.com/storybooks/storybook/blob/master/docs/viewport.png)
![Screenshot](https://github.com/storybooks/storybook/blob/master/addons/viewport/docs/viewport.png)
## Installation

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-viewport",
"version": "3.3.3",
"version": "3.4.0-alpha.4",
"description": "Storybook addon to change the viewport size to mobile",
"main": "register.js",
"keywords": [
@ -11,7 +11,7 @@
},
"license": "MIT",
"dependencies": {
"@storybook/components": "^3.3.3",
"@storybook/components": "^3.4.0-alpha.4",
"global": "^4.3.2",
"prop-types": "^15.5.10"
},

View File

@ -1,3 +1,2 @@
docs
src
.babelrc

View File

@ -1,6 +1,6 @@
# Storybook for Angular
Storybook for Angular is a UI development environment for your React components.
Storybook for Angular is a UI development environment for your Angular components.
With it, you can visualize different states of your UI components and develop them interactively.
[![Greenkeeper badge](https://badges.greenkeeper.io/storybooks/storybook.svg)](https://greenkeeper.io/)

View File

@ -1,4 +1,4 @@
declare module '@storybook/angular/demo' {
export const Button: any;
export const Welcome: any;
}
export const Button: any;
export const Welcome: any;
}

View File

@ -1,31 +1,32 @@
import {NgModuleMetadata, ICollection} from './dist/client/preview/angular/types';
import { NgModuleMetadata, ICollection } from './dist/client/preview/angular/types';
export interface IStorybookStory {
name: string,
render: () => any
name: string;
render: () => any;
}
export interface IStoribookSection {
kind: string,
stories: IStorybookStory[]
kind: string;
stories: IStorybookStory[];
}
export type IGetStory = () => {
props?: ICollection;
moduleMetadata?: Partial<NgModuleMetadata>;
component: any
props?: ICollection;
moduleMetadata?: Partial<NgModuleMetadata>;
component?: any;
template?: string;
};
export interface IApi {
kind: string;
addDecorator: (decorator: any) => IApi;
add: (storyName: string, getStory: IGetStory ) => IApi;
kind: string;
addDecorator: (decorator: any) => IApi;
add: (storyName: string, getStory: IGetStory) => IApi;
}
declare module '@storybook/angular' {
export function storiesOf(kind: string, module: NodeModule): IApi;
export function setAddon(addon: any): void;
export function addDecorator(decorator: any): IApi;
export function configure(loaders: () => NodeRequire, module: NodeModule): void;
export function getStorybook(): IStoribookSection[];
export function storiesOf(kind: string, module: NodeModule): IApi;
export function setAddon(addon: any): void;
export function addDecorator(decorator: any): IApi;
export function configure(loaders: () => NodeRequire, module: NodeModule): void;
export function getStorybook(): IStoribookSection[];
}

View File

@ -1,7 +1,7 @@
{
"name": "@storybook/angular",
"version": "3.3.3",
"description": "Storybook for Anglar: Develop Angular Components in isolation with Hot Reloading.",
"version": "3.4.0-alpha.4",
"description": "Storybook for Angular: Develop Angular Components in isolation with Hot Reloading.",
"homepage": "https://github.com/storybooks/storybook/tree/master/apps/angular",
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
@ -23,14 +23,15 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addon-actions": "^3.3.3",
"@storybook/addon-links": "^3.3.3",
"@storybook/addons": "^3.3.3",
"@storybook/channel-postmessage": "^3.3.3",
"@storybook/ui": "^3.3.3",
"@storybook/addon-actions": "^3.4.0-alpha.4",
"@storybook/addon-links": "^3.4.0-alpha.4",
"@storybook/addons": "^3.4.0-alpha.4",
"@storybook/channel-postmessage": "^3.4.0-alpha.4",
"@storybook/core": "^3.4.0-alpha.4",
"@storybook/ui": "^3.4.0-alpha.4",
"airbnb-js-shims": "^1.1.1",
"angular2-template-loader": "^0.6.2",
"autoprefixer": "^7.1.1",
"autoprefixer": "^7.2.5",
"babel-core": "^6.26.0",
"babel-loader": "^7.0.0",
"babel-plugin-react-docgen": "^1.6.0",
@ -41,25 +42,28 @@
"babel-runtime": "^6.23.0",
"case-sensitive-paths-webpack-plugin": "^2.0.0",
"chalk": "^2.1.0",
"commander": "^2.11.0",
"common-tags": "^1.4.0",
"commander": "^2.13.0",
"common-tags": "^1.7.2",
"configstore": "^3.1.0",
"core-js": "^2.4.1",
"cross-env": "^5.1.1",
"css-loader": "^0.28.1",
"css-loader": "^0.28.8",
"express": "^4.15.3",
"file-loader": "^0.11.1",
"find-cache-dir": "^1.0.0",
"global": "^4.3.2",
"html-loader": "^0.5.4",
"html-webpack-plugin": "^2.30.1",
"json-loader": "^0.5.4",
"json-stringify-safe": "^5.0.1",
"json5": "^0.5.1",
"lodash.pick": "^4.4.0",
"markdown-loader": "^2.0.2",
"node-sass": "^4.7.2",
"postcss-flexbugs-fixes": "^3.0.0",
"postcss-loader": "^2.0.5",
"postcss-loader": "^2.0.10",
"prop-types": "^15.5.10",
"qs": "^6.4.0",
"qs": "^6.5.1",
"raw-loader": "^0.5.1",
"react": "^16.0.0",
"react-dom": "^16.0.0",
@ -67,18 +71,19 @@
"redux": "^3.6.0",
"request": "^2.81.0",
"rxjs": "^5.4.2",
"sass-loader": "^6.0.6",
"serve-favicon": "^2.4.3",
"shelljs": "^0.7.8",
"shelljs": "^0.8.0",
"style-loader": "^0.18.2",
"ts-loader": "^2.2.2",
"uglifyjs-webpack-plugin": "^1.1.5",
"uglifyjs-webpack-plugin": "^1.1.6",
"url-loader": "^0.5.8",
"util-deprecate": "^1.0.2",
"uuid": "^3.1.0",
"webpack": "^2.5.1 || ^3.0.0",
"webpack-dev-middleware": "^1.10.2",
"webpack-hot-middleware": "^2.18.0",
"zone.js": "^0.8.19"
"zone.js": "^0.8.20"
},
"devDependencies": {
"babel-cli": "^6.26.0",
@ -86,7 +91,7 @@
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"codelyzer": "^3.1.2",
"mock-fs": "^4.3.0",
"nodemon": "^1.14.5",
"nodemon": "^1.14.11",
"typescript": "^2.4.0"
},
"peerDependencies": {

View File

@ -1,4 +1,4 @@
import { InjectionToken } from "@angular/core";
import { NgStory } from "./types";
import { InjectionToken } from '@angular/core';
import { NgStory } from './types';
export const STORY = new InjectionToken<NgStory>("story");
export const STORY = new InjectionToken<NgStory>('story');

View File

@ -2,35 +2,31 @@
// to provide @Inputs and subscribe to @Outputs, see
// https://github.com/angular/angular/issues/15360
// For the time being, the ViewContainerRef approach works pretty well.
import * as _ from 'lodash';
import {
Component,
Inject,
AfterViewInit,
OnInit,
ViewChild,
ViewContainerRef,
ComponentFactoryResolver,
OnDestroy,
EventEmitter,
SimpleChanges,
SimpleChange
SimpleChange,
} from '@angular/core';
import { STORY } from '../app.token';
import { NgStory, ICollection } from '../types';
@Component({
selector: 'app-root',
template: '<ng-template #target></ng-template>'
selector: 'storybook-dynamic-app-root',
template: '<ng-template #target></ng-template>',
})
export class AppComponent implements AfterViewInit, OnDestroy {
export class AppComponent implements OnInit, OnDestroy {
@ViewChild('target', { read: ViewContainerRef })
target: ViewContainerRef;
constructor(
private cfr: ComponentFactoryResolver,
@Inject(STORY) private data: NgStory
) {}
constructor(private cfr: ComponentFactoryResolver, @Inject(STORY) private data: NgStory) {}
ngAfterViewInit(): void {
ngOnInit(): void {
this.putInMyHtml();
}
@ -49,20 +45,20 @@ export class AppComponent implements AfterViewInit, OnDestroy {
/**
* Set inputs and outputs
*/
private setProps(instance: any, {props = {}, propsMeta = {}}: NgStory): void {
private setProps(instance: any, { props = {} }: NgStory): void {
const changes: SimpleChanges = {};
const hasNgOnChangesHook = _.has(instance, 'ngOnChanges');
const hasNgOnChangesHook = !!instance['ngOnChanges'];
_.forEach(propsMeta, (meta, key) => {
Object.keys(props).map((key: string) => {
const value = props[key];
const instanceProperty = <any>_.get(instance, key);
const instanceProperty = instance[key];
if (!(instanceProperty instanceof EventEmitter) && !_.isUndefined(value)) {
_.set(instance, key, value);
if (!(instanceProperty instanceof EventEmitter) && !!value) {
instance[key] = value;
if (hasNgOnChangesHook) {
changes[key] = new SimpleChange(undefined, value, instanceProperty === undefined);
}
} else if (_.isFunction(value) && (key !== 'ngModelChange')) {
} else if (typeof value === 'function' && key !== 'ngModelChange') {
instanceProperty.subscribe(value);
}
});
@ -76,8 +72,8 @@ export class AppComponent implements AfterViewInit, OnDestroy {
* Issue: [https://github.com/angular/angular/issues/8903]
*/
private callNgOnChangesHook(instance: any, changes: SimpleChanges): void {
if (!_.isEmpty(changes)) {
_.invoke(instance, 'ngOnChanges', changes);
if (!!Object.keys(changes).length) {
instance.ngOnChanges(changes);
}
}
@ -85,12 +81,12 @@ export class AppComponent implements AfterViewInit, OnDestroy {
* If component implements ControlValueAccessor interface try to set ngModel
*/
private setNgModel(instance: any, props: ICollection): void {
if (_.has(props, 'ngModel')) {
_.invoke(instance, 'writeValue', props.ngModel);
if (!!props['ngModel']) {
instance.writeValue(props.ngModel);
}
if (_.isFunction(props.ngModelChange)) {
_.invoke(instance, 'registerOnChange', props.ngModelChange);
if (typeof props.ngModelChange === 'function') {
instance.registerOnChange(props.ngModelChange);
}
}
}

View File

@ -1,9 +1,9 @@
import { Component, Inject } from "@angular/core";
import { STORY } from "../app.token";
import { NgError } from "../types";
import { Component, Inject } from '@angular/core';
import { STORY } from '../app.token';
import { NgError } from '../types';
@Component({
selector: "app-root",
selector: 'storybook-dynamic-app-root',
template: `
<div class="main">
<h1>{{ error.message }}</h1>
@ -40,9 +40,9 @@ import { NgError } from "../types";
width: 100vw;
overflow: auto;
}
`
]
`,
],
})
export class ErrorComponent {
constructor(@Inject(STORY) public error: NgError) {}
}
}

View File

@ -1,7 +1,7 @@
import { Component } from "@angular/core";
import { Component } from '@angular/core';
@Component({
selector: "app-root",
template: "<p>No Preview Available!</p>"
selector: 'storybook-dynamic-app-root',
template: '<p>No Preview Available!</p>',
})
export class NoPreviewComponent {}

View File

@ -1,45 +1,35 @@
import {
Type,
enableProdMode,
NgModule,
Component,
NgModuleRef
} from '@angular/core';
import {FormsModule} from '@angular/forms'
import { enableProdMode, NgModule, Component, NgModuleRef, Type } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './components/app.component';
import { ErrorComponent } from './components/error.component';
import { NoPreviewComponent } from './components/no-preview.component';
import { STORY } from './app.token';
import { getAnnotations, getParameters, getPropMetadata } from './utils';
import { NgModuleMetadata, NgStory, IGetStoryWithContext, IContext, NgProvidedData } from './types';
import {
NgModuleMetadata,
IGetStoryWithContext,
IContext,
NgProvidedData,
IRenderErrorFn,
IRenderStoryFn,
} from './types';
let platform: any = null;
let promises: Promise<NgModuleRef<any>>[] = [];
type IRenderStoryFn = (story: IGetStoryWithContext, context: IContext, reRender?: boolean) => void;
type IRenderErrorFn = (error: Error) => void;
interface IModule extends Type<any> {
annotations: any[];
}
interface IComponent extends Type<any> {
annotations: any[];
parameters: any[];
propsMetadata: any[]
}
// Taken from https://davidwalsh.name/javascript-debounce-function
// We don't want to pull underscore
const debounce = (func: IRenderStoryFn | IRenderErrorFn,
wait: number = 100,
immediate: boolean = false): () => void => {
const debounce = (
func: IRenderStoryFn | IRenderErrorFn,
wait: number = 100,
immediate: boolean = false
): (() => void) => {
let timeout: any;
return function () {
const context = this, args = arguments;
const later = function () {
return function() {
const context = this,
args = arguments;
const later = function() {
timeout = null;
if (!immediate) {
func.apply(context, args);
@ -54,113 +44,57 @@ const debounce = (func: IRenderStoryFn | IRenderErrorFn,
};
};
const getComponentMetadata = (
{ component, props = {}, propsMeta = {}, moduleMetadata = {
imports: [],
schemas: [],
declarations: [],
providers: []
} }: NgStory
const getModule = (
declarations: Array<Type<any> | any[]>,
entryComponents: Array<Type<any> | any[]>,
bootstrap: Array<Type<any> | any[]>,
data: NgProvidedData,
moduleMetadata: NgModuleMetadata
) => {
if (!component || typeof component !== 'function') {
throw new Error('No valid component provided');
}
const componentMetadata = getAnnotations(component)[0] || {};
const propsMetadata = getPropMetadata(component);
const paramsMetadata = getParameters(component);
Object.keys(propsMeta).map(key => {
(<any>propsMetadata)[key] = (<any>propsMeta)[key];
});
const {
imports = [],
schemas = [],
declarations = [],
providers = []
} = moduleMetadata;
return {
component,
props,
componentMeta: componentMetadata,
propsMeta: propsMetadata,
params: paramsMetadata,
moduleMeta: {
imports,
schemas,
declarations,
providers
}
};
};
const getAnnotatedComponent = (meta: NgModule,
component: any,
propsMeta: { [p: string]: any },
params: any[]): IComponent => {
const NewComponent: any = function NewComponent(...args: any[]) {
component.call(this, ...args);
const moduleMeta = {
declarations: [...declarations, ...(moduleMetadata.declarations || [])],
imports: [BrowserModule, FormsModule, ...(moduleMetadata.imports || [])],
providers: [
{ provide: STORY, useValue: Object.assign({}, data) },
...(moduleMetadata.providers || []),
],
entryComponents: [...entryComponents, ...(moduleMetadata.entryComponents || [])],
schemas: [...(moduleMetadata.schemas || [])],
bootstrap: [...bootstrap],
};
NewComponent.prototype = Object.create(component.prototype);
NewComponent.annotations = [new Component(meta)];
NewComponent.parameters = params;
NewComponent.propsMetadata = propsMeta;
const moduleClass = class DynamicModule {};
return NewComponent;
return NgModule(moduleMeta)(moduleClass);
};
const getModule = (declarations: Array<Type<any> | any[]>,
entryComponents: Array<Type<any> | any[]>,
bootstrap: Array<Type<any> | any[]>,
data: NgProvidedData,
moduleMetadata: NgModuleMetadata = {
imports: [],
schemas: [],
declarations: [],
providers: []
}): IModule => {
const moduleMeta = new NgModule({
declarations: [...declarations, ...moduleMetadata.declarations],
imports: [BrowserModule, FormsModule, ...moduleMetadata.imports],
providers: [{ provide: STORY, useValue: Object.assign({}, data) }, ...moduleMetadata.providers],
entryComponents: [...entryComponents],
schemas: [...moduleMetadata.schemas],
bootstrap: [...bootstrap]
});
const createComponentFromTemplate = (template: string): Function => {
const componentClass = class DynamicComponent {};
const NewModule: any = function NewModule() {};
(<IModule>NewModule).annotations = [moduleMeta];
return NewModule;
return Component({
template: template,
})(componentClass);
};
const initModule = (currentStory: IGetStoryWithContext, context: IContext, reRender: boolean): IModule => {
const {
component,
componentMeta,
props,
propsMeta,
params,
moduleMeta
} = getComponentMetadata(currentStory(context));
const initModule = (
currentStory: IGetStoryWithContext,
context: IContext,
reRender: boolean
): Function => {
const storyObj = currentStory(context);
const { component, template, props, moduleMetadata = {} } = storyObj;
if (!componentMeta) {
throw new Error('No component metadata available');
let AnnotatedComponent;
if (template) {
AnnotatedComponent = createComponentFromTemplate(template);
} else {
AnnotatedComponent = component;
}
const AnnotatedComponent = getAnnotatedComponent(
componentMeta,
component,
propsMeta,
[...params, ...moduleMeta.providers.map(provider => [provider])]
);
const story = {
component: AnnotatedComponent,
props,
propsMeta
};
return getModule(
@ -168,39 +102,38 @@ const initModule = (currentStory: IGetStoryWithContext, context: IContext, reRen
[AnnotatedComponent],
[AppComponent],
story,
moduleMeta
moduleMetadata
);
};
const draw = (newModule: IModule, reRender: boolean = true): void => {
const draw = (newModule: Function, reRender: boolean = true): void => {
if (!platform) {
try {
enableProdMode();
} catch (e) {}
platform = platformBrowserDynamic();
promises.push(platform.bootstrapModule(newModule))
promises.push(platform.bootstrapModule(newModule));
} else {
Promise.all(promises)
.then((modules) => {
modules.forEach(mod => mod.destroy());
Promise.all(promises).then(modules => {
modules.forEach(mod => mod.destroy());
const body = document.body;
const app = document.createElement('app-root');
body.appendChild(app);
promises = [];
promises.push(platform.bootstrapModule(newModule));
});
const body = document.body;
const app = document.createElement('storybook-dynamic-app-root');
body.appendChild(app);
promises = [];
promises.push(platform.bootstrapModule(newModule));
});
}
};
export const renderNgError = debounce((error: Error) => {
const errorData = {
message: error.message,
stack: error.stack
stack: error.stack,
};
const Module = getModule([ErrorComponent], [], [ErrorComponent], errorData);
const Module = getModule([ErrorComponent], [], [ErrorComponent], errorData, {});
draw(Module);
});
@ -212,8 +145,9 @@ export const renderNoPreview = debounce(() => {
[NoPreviewComponent],
{
message: 'No Preview available.',
stack: ''
}
stack: '',
},
{}
);
draw(Module);

View File

@ -1,28 +1,39 @@
export interface NgModuleMetadata {
declarations: Array<any>,
imports: Array<any>,
schemas: Array<any>,
providers: Array<any>,
declarations?: Array<any>;
entryComponents?: Array<any>;
imports?: Array<any>;
schemas?: Array<any>;
providers?: Array<any>;
}
export interface ICollection {[p: string]: any}
export interface ICollection {
[p: string]: any;
}
export interface NgStory {
component: any,
props: ICollection,
propsMeta: ICollection,
moduleMetadata?: NgModuleMetadata
component?: any;
props: ICollection;
propsMeta?: ICollection;
moduleMetadata?: NgModuleMetadata;
template?: string;
}
export interface NgError {
message: string,
stack: string
message: string;
stack: string;
}
export type NgProvidedData = NgStory | NgError;
export interface IContext {
[p: string]: any
[p: string]: any;
}
export type IGetStoryWithContext = (context: IContext) => NgStory
export type IGetStoryWithContext = (context: IContext) => NgStory;
export type IRenderStoryFn = (
story: IGetStoryWithContext,
context: IContext,
reRender?: boolean
) => void;
export type IRenderErrorFn = (error: Error) => void;

View File

@ -1,38 +0,0 @@
import { ɵReflectionCapabilities } from '@angular/core';
const reflectionCapabilities = new ɵReflectionCapabilities();
function getMeta(component: any, [name1, name2]: any, defaultValue: any) {
if (!name2) {
name2 = name1;
name1 = `__${name1}__`;
}
if (component[name1]) {
return component[name1];
}
if (component[name2]) {
return component[name2];
}
return (<any>window)['Reflect'].getMetadata(name2, component) || defaultValue;
}
export function getAnnotations(component: any) {
return getMeta(component, ['annotations'], []);
}
export function getPropMetadata(component: any) {
return getMeta(component, ['__prop__metadata__', 'propMetadata'], {});
}
export function getParameters(component: any) {
const params = reflectionCapabilities.parameters(component);
if (!params || !params[0]) {
return getMeta(component, ['parameters'], []);
}
return params;
}

View File

@ -1,94 +0,0 @@
/* eslint-disable no-underscore-dangle */
export default class ClientApi {
constructor({ channel, storyStore }) {
// channel can be null when running in node
// always check whether channel is available
this._channel = channel;
this._storyStore = storyStore;
this._addons = {};
this._globalDecorators = [];
}
setAddon(addon) {
this._addons = {
...this._addons,
...addon,
};
}
addDecorator(decorator) {
this._globalDecorators.push(decorator);
}
clearDecorators() {
this._globalDecorators = [];
}
storiesOf(kind, m) {
if (!kind && typeof kind !== 'string') {
throw new Error('Invalid or missing kind provided for stories, should be a string');
}
if (m && m.hot) {
m.hot.dispose(() => {
this._storyStore.removeStoryKind(kind);
});
}
const localDecorators = [];
const api = {
kind,
};
// apply addons
Object.keys(this._addons).forEach(name => {
const addon = this._addons[name];
api[name] = (...args) => {
addon.apply(api, args);
return api;
};
});
api.add = (storyName, getStory) => {
if (typeof storyName !== 'string') {
throw new Error(`Invalid or missing storyName provided for a "${kind}" story.`);
}
if (this._storyStore.hasStory(kind, storyName)) {
throw new Error(`Story of "${kind}" named "${storyName}" already exists`);
}
// Wrap the getStory function with each decorator. The first
// decorator will wrap the story function. The second will
// wrap the first decorator and so on.
const decorators = [...localDecorators, ...this._globalDecorators];
const getDecoratedStory = decorators.reduce(
(decorated, decorator) => context => decorator(() => decorated(context), context),
getStory
);
// Add the fully decorated getStory function.
this._storyStore.addStory(kind, storyName, getDecoratedStory);
return api;
};
api.addDecorator = decorator => {
localDecorators.push(decorator);
return api;
};
return api;
}
getStorybook() {
return this._storyStore.getStoryKinds().map(kind => {
const stories = this._storyStore.getStories(kind).map(name => {
const render = this._storyStore.getStory(kind, name);
return { name, render };
});
return { kind, stories };
});
}
}

View File

@ -1,250 +0,0 @@
/* eslint-disable no-underscore-dangle */
import ClientAPI from './client_api';
class StoryStore {
constructor() {
this.stories = [];
}
addStory(kind, story, fn) {
this.stories.push({ kind, story, fn });
}
getStoryKinds() {
return this.stories.reduce((kinds, info) => {
if (kinds.indexOf(info.kind) === -1) {
kinds.push(info.kind);
}
return kinds;
}, []);
}
getStories(kind) {
return this.stories.reduce((stories, info) => {
if (info.kind === kind) {
stories.push(info.story);
}
return stories;
}, []);
}
getStory(kind, name) {
return this.stories.reduce((fn, info) => {
if (!fn && info.kind === kind && info.story === name) {
return info.fn;
}
return fn;
}, null);
}
hasStory(kind, name) {
return Boolean(this.getStory(kind, name));
}
}
describe('preview.client_api', () => {
describe('setAddon', () => {
it('should register addons', () => {
const api = new ClientAPI({});
let data;
api.setAddon({
aa() {
data = 'foo';
},
});
api.storiesOf('none').aa();
expect(data).toBe('foo');
});
it('should not remove previous addons', () => {
const api = new ClientAPI({});
const data = [];
api.setAddon({
aa() {
data.push('foo');
},
});
api.setAddon({
bb() {
data.push('bar');
},
});
api
.storiesOf('none')
.aa()
.bb();
expect(data).toEqual(['foo', 'bar']);
});
it('should call with the api context', () => {
const api = new ClientAPI({});
let data;
api.setAddon({
aa() {
data = typeof this.add;
},
});
api.storiesOf('none').aa();
expect(data).toBe('function');
});
it('should be able to access addons added previously', () => {
const api = new ClientAPI({});
let data;
api.setAddon({
aa() {
data = 'foo';
},
});
api.setAddon({
bb() {
this.aa();
},
});
api.storiesOf('none').bb();
expect(data).toBe('foo');
});
it('should be able to access the current kind', () => {
const api = new ClientAPI({});
const kind = 'dfdwf3e3';
let data;
api.setAddon({
aa() {
data = this.kind;
},
});
api.storiesOf(kind).aa();
expect(data).toBe(kind);
});
});
describe('addDecorator', () => {
it('should add local decorators', () => {
const storyStore = new StoryStore();
const api = new ClientAPI({ storyStore });
const localApi = api.storiesOf('none');
localApi.addDecorator(fn => `aa-${fn()}`);
localApi.add('storyName', () => 'Hello');
expect(storyStore.stories[0].fn()).toBe('aa-Hello');
});
it('should add global decorators', () => {
const storyStore = new StoryStore();
const api = new ClientAPI({ storyStore });
api.addDecorator(fn => `bb-${fn()}`);
const localApi = api.storiesOf('none');
localApi.add('storyName', () => 'Hello');
expect(storyStore.stories[0].fn()).toBe('bb-Hello');
});
it('should utilize both decorators at once', () => {
const storyStore = new StoryStore();
const api = new ClientAPI({ storyStore });
const localApi = api.storiesOf('none');
api.addDecorator(fn => `aa-${fn()}`);
localApi.addDecorator(fn => `bb-${fn()}`);
localApi.add('storyName', () => 'Hello');
expect(storyStore.stories[0].fn()).toBe('aa-bb-Hello');
});
it('should pass the context', () => {
const storyStore = new StoryStore();
const api = new ClientAPI({ storyStore });
const localApi = api.storiesOf('none');
localApi.addDecorator(fn => `aa-${fn()}`);
localApi.add('storyName', ({ kind, story }) => `${kind}-${story}`);
const kind = 'dfdfd';
const story = 'ef349ff';
const result = storyStore.stories[0].fn({ kind, story });
expect(result).toBe(`aa-${kind}-${story}`);
});
it('should have access to the context', () => {
const storyStore = new StoryStore();
const api = new ClientAPI({ storyStore });
const localApi = api.storiesOf('none');
localApi.addDecorator((fn, { kind, story }) => `${kind}-${story}-${fn()}`);
localApi.add('storyName', () => 'Hello');
const kind = 'dfdfd';
const story = 'ef349ff';
const result = storyStore.stories[0].fn({ kind, story });
expect(result).toBe(`${kind}-${story}-Hello`);
});
});
describe('clearDecorators', () => {
it('should remove all global decorators', () => {
const api = new ClientAPI({});
api._globalDecorators = 1234;
api.clearDecorators();
expect(api._globalDecorators).toEqual([]);
});
});
describe('getStorybook', () => {
it('should return storybook when empty', () => {
const storyStore = new StoryStore();
const api = new ClientAPI({ storyStore });
const book = api.getStorybook();
expect(book).toEqual([]);
});
it('should return storybook with stories', () => {
const storyStore = new StoryStore();
const api = new ClientAPI({ storyStore });
const functions = {
'story-1.1': () => 'story-1.1',
'story-1.2': () => 'story-1.2',
'story-2.1': () => 'story-2.1',
'story-2.2': () => 'story-2.2',
};
const kind1 = api.storiesOf('kind-1');
kind1.add('story-1.1', functions['story-1.1']);
kind1.add('story-1.2', functions['story-1.2']);
const kind2 = api.storiesOf('kind-2');
kind2.add('story-2.1', functions['story-2.1']);
kind2.add('story-2.2', functions['story-2.2']);
const book = api.getStorybook();
expect(book).toEqual([
{
kind: 'kind-1',
stories: [
{ name: 'story-1.1', render: functions['story-1.1'] },
{ name: 'story-1.2', render: functions['story-1.2'] },
],
},
{
kind: 'kind-2',
stories: [
{ name: 'story-2.1', render: functions['story-2.1'] },
{ name: 'story-2.2', render: functions['story-2.2'] },
],
},
]);
});
});
});

View File

@ -1,67 +0,0 @@
/* eslint-disable no-underscore-dangle */
import { location } from 'global';
import { setInitialStory, setError, clearError } from './actions';
import { clearDecorators } from './';
export default class ConfigApi {
constructor({ channel, storyStore, reduxStore }) {
// channel can be null when running in node
// always check whether channel is available
this._channel = channel;
this._storyStore = storyStore;
this._reduxStore = reduxStore;
}
_renderMain(loaders) {
if (loaders) loaders();
const stories = this._storyStore.dumpStoryBook();
// send to the parent frame.
this._channel.emit('setStories', { stories });
// clear the error if exists.
this._reduxStore.dispatch(clearError());
this._reduxStore.dispatch(setInitialStory(stories));
}
_renderError(e) {
const { stack, message } = e;
const error = { stack, message };
this._reduxStore.dispatch(setError(error));
}
configure(loaders, module) {
const render = () => {
try {
this._renderMain(loaders);
} catch (error) {
if (module.hot && module.hot.status() === 'apply') {
// We got this issue, after webpack fixed it and applying it.
// Therefore error message is displayed forever even it's being fixed.
// So, we'll detect it reload the page.
location.reload();
} else {
// If we are accessing the site, but the error is not fixed yet.
// There we can render the error.
this._renderError(error);
}
}
};
if (module.hot) {
module.hot.accept(() => {
setTimeout(render);
});
module.hot.dispose(() => {
clearDecorators();
});
}
if (this._channel) {
render();
} else {
loaders();
}
}
}

View File

@ -2,14 +2,16 @@ import { window, navigator } from 'global';
import { createStore } from 'redux';
import addons from '@storybook/addons';
import createChannel from '@storybook/channel-postmessage';
import qs from 'qs';
import StoryStore from './story_store';
import ClientApi from './client_api';
import ConfigApi from './config_api';
import { handleKeyboardShortcuts } from '@storybook/ui/dist/libs/key_events';
import {
StoryStore,
ClientApi,
ConfigApi,
Actions,
reducer,
syncUrlWithStore,
} from '@storybook/core/client';
import render from './render';
import init from './init';
import { selectStory } from './actions';
import reducer from './reducer';
// check whether we're running on node/browser
const isBrowser =
@ -24,26 +26,25 @@ const reduxStore = createStore(reducer);
const context = { storyStore, reduxStore };
if (isBrowser) {
const queryParams = qs.parse(window.location.search.substring(1));
// create preview channel
const channel = createChannel({ page: 'preview' });
channel.on('setCurrentStory', data => {
reduxStore.dispatch(selectStory(data.kind, data.story));
reduxStore.dispatch(Actions.selectStory(data.kind, data.story));
});
Object.assign(context, { channel, window, queryParams });
addons.setChannel(channel);
init(context);
Object.assign(context, { channel });
syncUrlWithStore(reduxStore);
// Handle keyboard shortcuts
window.onkeydown = handleKeyboardShortcuts(channel);
}
const clientApi = new ClientApi(context);
const configApi = new ConfigApi(context);
export const { storiesOf, setAddon, addDecorator, clearDecorators, getStorybook } = clientApi;
// do exports
export const storiesOf = clientApi.storiesOf.bind(clientApi);
export const setAddon = clientApi.setAddon.bind(clientApi);
export const addDecorator = clientApi.addDecorator.bind(clientApi);
export const clearDecorators = clientApi.clearDecorators.bind(clientApi);
export const getStorybook = clientApi.getStorybook.bind(clientApi);
export const configure = configApi.configure.bind(configApi);
const configApi = new ConfigApi({ ...context, clearDecorators });
export const { configure } = configApi;
// initialize the UI
const renderUI = () => {

View File

@ -1,33 +0,0 @@
import keyEvents from '@storybook/ui/dist/libs/key_events';
import qs from 'qs';
import { selectStory } from './actions';
export default function(context) {
const { queryParams, reduxStore, window, channel } = context;
// set the story if correct params are loaded via the URL.
if (queryParams.selectedKind) {
reduxStore.dispatch(selectStory(queryParams.selectedKind, queryParams.selectedStory));
}
// Keep whichever of these are set that we don't override when stories change
const originalQueryParams = queryParams;
reduxStore.subscribe(() => {
const { selectedKind, selectedStory } = reduxStore.getState();
const queryString = qs.stringify({
...originalQueryParams,
selectedKind,
selectedStory,
});
window.history.pushState({}, '', `?${queryString}`);
});
// Handle keyEvents and pass them to the parent.
window.onkeydown = e => {
const parsedEvent = keyEvents(e);
if (parsedEvent) {
channel.emit('applyShortcut', { event: parsedEvent });
}
};
}

View File

@ -1,89 +0,0 @@
/* eslint-disable no-underscore-dangle */
let count = 0;
function getId() {
count += 1;
return count;
}
export default class StoryStore {
constructor() {
this._data = {};
}
addStory(kind, name, fn) {
if (!this._data[kind]) {
this._data[kind] = {
kind,
index: getId(),
stories: {},
};
}
this._data[kind].stories[name] = {
name,
index: getId(),
fn,
};
}
getStoryKinds() {
return Object.keys(this._data)
.map(key => this._data[key])
.filter(kind => Object.keys(kind.stories).length > 0)
.sort((info1, info2) => info1.index - info2.index)
.map(info => info.kind);
}
getStories(kind) {
if (!this._data[kind]) {
return [];
}
return Object.keys(this._data[kind].stories)
.map(name => this._data[kind].stories[name])
.sort((info1, info2) => info1.index - info2.index)
.map(info => info.name);
}
getStory(kind, name) {
const storiesKind = this._data[kind];
if (!storiesKind) {
return null;
}
const storyInfo = storiesKind.stories[name];
if (!storyInfo) {
return null;
}
return storyInfo.fn;
}
removeStoryKind(kind) {
this._data[kind].stories = {};
}
hasStoryKind(kind) {
return Boolean(this._data[kind]);
}
hasStory(kind, name) {
return Boolean(this.getStory(kind, name));
}
dumpStoryBook() {
const data = this.getStoryKinds().map(kind => ({ kind, stories: this.getStories(kind) }));
return data;
}
size() {
return Object.keys(this._data).length;
}
clean() {
this.getStoryKinds().forEach(kind => delete this._data[kind]);
}
}

View File

@ -1,12 +1,12 @@
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'button-component',
selector: 'storybook-button-component',
template: `
<button (click)="onClick.emit($event);">{{ text }}</button>
`,
styles: [
`
`
button {
border: 1px solid #eee;
border-radius: 3px;
@ -16,10 +16,10 @@ import { Component, Input, Output, EventEmitter } from '@angular/core';
padding: 3px 10px;
margin: 10px;
}
`
]
`,
],
})
export default class ButtonComponent {
@Input() text = '';
@Output() onClick = new EventEmitter<any>();
}
@Input() text = '';
@Output() onClick = new EventEmitter<any>();
}

View File

@ -1,7 +1,7 @@
import { Component } from '@angular/core';
@Component({
selector: 'welcome-component',
selector: 'storybook-welcome-component',
template: `
<main>
<h1>Welcome to storybook</h1>
@ -15,7 +15,8 @@ import { Component } from '@angular/core';
(Basically a story is like a visual test case.)
</p>
<p>
See these sample <a (click)="showApp();" role="button" tabIndex="0">stories</a> for a component called <span class="inline-code">Button</span> .
See these sample <a (click)="showApp();" role="button" tabIndex="0">stories</a> for a component called
<span class="inline-code">Button</span> .
</p>
<p>
Just like that, you can add your own components as stories.
@ -38,12 +39,13 @@ import { Component } from '@angular/core';
<p class="note">
<b>NOTE:</b>
<br />
Have a look at the <span class="inline-code">.storybook/webpack.config.js</span> to add webpack loaders and plugins you are using in this project.
Have a look at the <span class="inline-code">.storybook/webpack.config.js</span>
to add webpack loaders and plugins you are using in this project.
</p>
</main>
`,
styles: [
`
`
main {
margin: 15px;
max-width: 600;
@ -71,9 +73,9 @@ import { Component } from '@angular/core';
border-bottom: 1px solid #1474f3;
padding-bottom: 2px;
}
`
]
`,
],
})
export default class WelcomeComponent {
displayName = 'Welcome';
}
displayName = 'Welcome';
}

View File

@ -56,7 +56,7 @@ shelljs.cp(path.resolve(__dirname, 'public/favicon.ico'), outputDir);
// Build the webpack configuration using the `baseConfig`
// custom `.babelrc` file and `webpack.config.js` files
// NOTE changes to env should be done before calling `getBaseConfig`
const config = loadConfig('PRODUCTION', getBaseConfig(), configDir);
const config = loadConfig('PRODUCTION', getBaseConfig(configDir), configDir);
config.output.path = path.resolve(outputDir);
// copy all static files

View File

@ -2,6 +2,7 @@
import fs from 'fs';
import path from 'path';
import loadBabelConfig from './babel_config';
import loadTsConfig from './ts_config';
// avoid ESLint errors
const logger = console;
@ -15,6 +16,9 @@ export default function(configType, baseConfig, configDir) {
const babelConfig = loadBabelConfig(configDir);
config.module.rules[0].query = babelConfig;
const tsOptions = loadTsConfig(configDir);
config.module.rules[1].loaders[0].options = tsOptions;
// Check whether a config.js file exists inside the storybook
// config directory and throw an error if it's not.
const storybookConfigPath = path.resolve(configDir, 'config.js');

View File

@ -33,5 +33,3 @@ export function loadEnv(options = {}) {
'process.env': env,
};
}
export const getConfigDir = () => process.env.SBCONFIG_CONFIG_DIR || './.storybook';

View File

@ -4,19 +4,12 @@ import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import WatchMissingNodeModulesPlugin from './WatchMissingNodeModulesPlugin';
import {
getConfigDir,
includePaths,
excludePaths,
nodeModulesPaths,
loadEnv,
nodePaths,
} from './utils';
import { includePaths, excludePaths, nodeModulesPaths, loadEnv, nodePaths } from './utils';
import babelLoaderConfig from './babel';
import { getPreviewHeadHtml, getManagerHeadHtml } from '../utils';
import { version } from '../../../package.json';
export default function() {
export default function(configDir) {
const config = {
devtool: 'cheap-module-source-map',
entry: {
@ -37,7 +30,7 @@ export default function() {
filename: 'index.html',
chunks: ['manager'],
data: {
managerHead: getManagerHeadHtml(getConfigDir()),
managerHead: getManagerHeadHtml(configDir),
version,
},
template: require.resolve('../index.html.ejs'),
@ -46,7 +39,7 @@ export default function() {
filename: 'iframe.html',
excludeChunks: ['manager'],
data: {
previewHead: getPreviewHeadHtml(getConfigDir()),
previewHead: getPreviewHeadHtml(configDir),
},
template: require.resolve('../iframe.html.ejs'),
}),
@ -71,12 +64,21 @@ export default function() {
},
{
test: /\.ts?$/,
loaders: [require.resolve('ts-loader'), require.resolve('angular2-template-loader')],
loaders: [
{
loader: require.resolve('ts-loader'),
},
require.resolve('angular2-template-loader'),
],
},
{
test: /\.(html|css)$/,
test: /\.html$/,
loader: 'raw-loader',
exclude: /\.async\.(html|css)$/,
exclude: /\.async\.css$/,
},
{
test: /\.scss$/,
loaders: [require.resolve('raw-loader'), require.resolve('sass-loader')],
},
{
test: /\.md$/,

View File

@ -4,11 +4,11 @@ import UglifyJsPlugin from 'uglifyjs-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import babelLoaderConfig from './babel.prod';
import { getConfigDir, includePaths, excludePaths, loadEnv, nodePaths } from './utils';
import { includePaths, excludePaths, loadEnv, nodePaths } from './utils';
import { getPreviewHeadHtml, getManagerHeadHtml } from '../utils';
import { version } from '../../../package.json';
export default function() {
export default function(configDir) {
const entries = {
preview: [require.resolve('./polyfills'), require.resolve('./globals')],
manager: [require.resolve('./polyfills'), path.resolve(__dirname, '../../client/manager')],
@ -32,7 +32,7 @@ export default function() {
filename: 'index.html',
chunks: ['manager'],
data: {
managerHead: getManagerHeadHtml(getConfigDir()),
managerHead: getManagerHeadHtml(configDir),
version,
},
template: require.resolve('../index.html.ejs'),
@ -41,7 +41,7 @@ export default function() {
filename: 'iframe.html',
excludeChunks: ['manager'],
data: {
previewHead: getPreviewHeadHtml(getConfigDir()),
previewHead: getPreviewHeadHtml(configDir),
},
template: require.resolve('../iframe.html.ejs'),
}),
@ -52,6 +52,9 @@ export default function() {
ie8: false,
mangle: false,
warnings: false,
compress: {
keep_fnames: true,
},
output: {
comments: false,
},
@ -73,12 +76,21 @@ export default function() {
},
{
test: /\.ts?$/,
loaders: [require.resolve('ts-loader'), require.resolve('angular2-template-loader')],
loaders: [
{
loader: require.resolve('ts-loader'),
},
require.resolve('angular2-template-loader'),
],
},
{
test: /\.(html|css)$/,
test: /\.html$/,
loader: 'raw-loader',
exclude: /\.async\.(html|css)$/,
exclude: /\.async\.html$/,
},
{
test: /\.scss$/,
loaders: [require.resolve('raw-loader'), require.resolve('sass-loader')],
},
],
},

View File

@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta content="IE=edge" http-equiv="X-UA-Compatible" />
<base target="_parent">
<script>
if (window.parent !== window) {
@ -13,6 +14,6 @@
<%= htmlWebpackPlugin.options.data.previewHead %>
</head>
<body>
<app-root></app-root>
<storybook-dynamic-app-root></storybook-dynamic-app-root>
</body>
</html>

View File

@ -120,8 +120,6 @@ if (!hasCustomFavicon) {
app.use(favicon(path.resolve(__dirname, 'public/favicon.ico')));
}
// Build the webpack configuration using the `baseConfig`
// custom `.babelrc` file and `webpack.config.js` files
const configDir = program.configDir || './.storybook';
// The repository info is sent to the storybook while running on

View File

@ -17,7 +17,7 @@ export const webpackValid = new Promise((resolve, reject) => {
export default function(configDir) {
// Build the webpack configuration using the `getBaseConfig`
// custom `.babelrc` file and `webpack.config.js` files
const config = loadConfig('DEVELOPMENT', getBaseConfig(), configDir);
const config = loadConfig('DEVELOPMENT', getBaseConfig(configDir), configDir);
const middlewareFn = getMiddleware(configDir);
// remove the leading '/'

27
app/angular/src/server/ts_config.js vendored Normal file
View File

@ -0,0 +1,27 @@
import fs from 'fs';
import path from 'path';
// avoid ESLint errors
const logger = console;
function resolveTsConfig(tsConfigPath) {
if (!fs.existsSync(tsConfigPath)) {
return null;
}
logger.info('=> Found custom tsconfig.json');
return tsConfigPath;
}
export default function(configDir) {
const configFile = resolveTsConfig(path.resolve(configDir, 'tsconfig.json'));
if (!configFile) {
return {};
}
return {
configFile,
};
}

View File

@ -0,0 +1,32 @@
import loadTsConfig from './ts_config';
// eslint-disable-next-line global-require
jest.mock('fs', () => require('../../../../__mocks__/fs'));
jest.mock('path', () => ({
resolve: () => 'tsconfig.json',
}));
const setupFiles = files => {
// eslint-disable-next-line no-underscore-dangle, global-require
require('fs').__setMockFiles(files);
};
describe('ts_config', () => {
it('should return the config with the path to the tsconfig.json', () => {
setupFiles({ 'tsconfig.json': '{}' });
const config = loadTsConfig('.foo');
expect(config).toEqual({
configFile: 'tsconfig.json',
});
});
it('should return empty object when there is no tsconfig.json', () => {
setupFiles({});
const config = loadTsConfig('.foo');
expect(config).toEqual({});
});
});

View File

@ -1,135 +0,0 @@
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs"
],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
"static-before-instance",
"variables-before-functions"
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"typeof-compare": true,
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true,
"no-access-missing-member": true,
"templates-use-public": true,
"invoke-injectable": true
}
}

3
app/polymer/.babelrc Normal file
View File

@ -0,0 +1,3 @@
{
"presets": ["env", "stage-0", "react"]
}

3
app/polymer/.npmignore Normal file
View File

@ -0,0 +1,3 @@
docs
src
.babelrc

41
app/polymer/README.md Normal file
View File

@ -0,0 +1,41 @@
# Storybook for Polymer
[![Build Status on CircleCI](https://circleci.com/gh/storybooks/storybook.svg?style=shield)](https://circleci.com/gh/storybooks/storybook)
[![CodeFactor](https://www.codefactor.io/repository/github/storybooks/storybook/badge)](https://www.codefactor.io/repository/github/storybooks/storybook)
[![Known Vulnerabilities](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847/badge.svg)](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-nqnzoygycp.now.sh/badge.svg)](https://now-examples-slackin-nqnzoygycp.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
* * *
Storybook for polymer is a UI development environment for your Polymer components.
With it, you can visualize different states of your UI components and develop them interactively.
> Storybook for Polymer is at the **EXPERIMENTAL** stage!
![Storybook Screenshot](https://github.com/storybooks/storybook/blob/master/app/polymer/docs/demo.gif)
Storybook runs outside of your app.
So you can develop UI components in isolation without worrying about app specific dependencies and requirements.
## Getting Started
```sh
npm i -g @storybook/cli
cd my-polymer-app
getstorybook
```
For more information visit: [storybook.js.org](https://storybook.js.org)
* * *
Storybook also comes with a lot of [addons](https://storybook.js.org/addons/introduction) and a great API to customize as you wish.
You can also build a [static version](https://storybook.js.org/basics/exporting-storybook) of your storybook and deploy it anywhere you want.
## Polymer Notes
- This is super super experimental, if you want to use this, expect some bugs, and missing features.
- We're looking for help to support this. If you're a member of the Polymer community and like this project, please help us!
If you need any onboarding from us, we're happy to help you in any way!

3
app/polymer/bin/build.js Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env node
require('../dist/server/build');

3
app/polymer/bin/index.js Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env node
require('../dist/server');

BIN
app/polymer/docs/demo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

87
app/polymer/package.json Normal file
View File

@ -0,0 +1,87 @@
{
"name": "@storybook/polymer",
"version": "3.4.0-alpha.4",
"description": "Storybook for Polymer: Develop Polymer components in isolation with Hot Reloading.",
"homepage": "https://github.com/storybooks/storybook/tree/master/apps/polymer",
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"license": "MIT",
"main": "dist/client/index.js",
"bin": {
"build-storybook": "./bin/build.js",
"start-storybook": "./bin/index.js",
"storybook-server": "./bin/index.js"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
},
"scripts": {
"dev": "DEV_BUILD=1 nodemon --watch ./src --exec 'yarn prepare'",
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "^3.4.0-alpha.4",
"@storybook/channel-postmessage": "^3.4.0-alpha.4",
"@storybook/client-logger": "^3.4.0-alpha.4",
"@storybook/core": "^3.4.0-alpha.4",
"@storybook/node-logger": "^3.4.0-alpha.4",
"@storybook/ui": "^3.4.0-alpha.4",
"@webcomponents/webcomponentsjs": "^1.0.17",
"airbnb-js-shims": "^1.3.0",
"autoprefixer": "^7.1.6",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-react-docgen": "^1.8.0",
"babel-plugin-transform-regenerator": "^6.26.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.6.0",
"babel-preset-minify": "^0.2.0",
"babel-preset-react": "^6.24.1",
"babel-preset-react-app": "^3.1.0",
"babel-preset-stage-0": "^6.24.1",
"babel-runtime": "^6.26.0",
"case-sensitive-paths-webpack-plugin": "^2.1.1",
"chalk": "^2.3.0",
"commander": "^2.11.0",
"common-tags": "^1.4.0",
"configstore": "^3.1.1",
"copy-webpack-plugin": "^4.2.0",
"core-js": "^2.5.1",
"css-loader": "^0.28.7",
"express": "^4.16.2",
"file-loader": "^0.11.2",
"find-cache-dir": "^1.0.0",
"global": "^4.3.2",
"html-webpack-plugin": "^2.30.1",
"json-loader": "^0.5.7",
"json-stringify-safe": "^5.0.1",
"json5": "^0.5.1",
"lodash.pick": "^4.4.0",
"polymer-webpack-loader": "2.0.1",
"postcss-flexbugs-fixes": "^3.2.0",
"postcss-loader": "^2.0.8",
"prop-types": "^15.6.0",
"qs": "^6.5.1",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-modal": "^2.4.1",
"redux": "^3.7.2",
"request": "^2.83.0",
"serve-favicon": "^2.4.5",
"shelljs": "^0.7.8",
"style-loader": "^0.18.2",
"url-loader": "^0.6.2",
"util-deprecate": "^1.0.2",
"uuid": "^3.1.0",
"webpack": "^3.6.0",
"webpack-dev-middleware": "^1.12.0",
"webpack-hot-middleware": "^2.20.0"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"nodemon": "^1.12.1"
}
}

View File

@ -0,0 +1,17 @@
// import deprecate from 'util-deprecate';
// NOTE export these to keep backwards compatibility
// import { action as deprecatedAction } from '@storybook/addon-actions';
// import { linkTo as deprecatedLinkTo } from '@storybook/addon-links';
export { storiesOf, setAddon, addDecorator, configure, getStorybook } from './preview';
// export const action = deprecate(
// deprecatedAction,
// '@storybook/react action is deprecated. See: https://github.com/storybooks/storybook/tree/master/addons/actions'
// );
// export const linkTo = deprecate(
// deprecatedLinkTo,
// '@storybook/react linkTo is deprecated. See: https://github.com/storybooks/storybook/tree/master/addons/links'
// );

View File

@ -0,0 +1,7 @@
/* global document */
import renderStorybookUI from '@storybook/ui';
import Provider from './provider';
const rootEl = document.getElementById('root');
renderStorybookUI(rootEl, new Provider());

View File

@ -0,0 +1,39 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
const iframeStyle = {
width: '100%',
height: '100%',
border: 0,
margin: 0,
padding: 0,
};
class Preview extends Component {
shouldComponentUpdate() {
// When the manager is re-rendered, due to changes in the layout (going full screen / changing
// addon panel to right) Preview section will update. If its re-rendered the whole html page
// inside the html is re-rendered making the story to re-mount.
// We dont have to re-render this component for any reason since changes are communicated to
// story using the channel and necessary changes are done by it.
return false;
}
render() {
return (
<iframe
id="storybook-preview-iframe"
title="preview"
style={iframeStyle}
src={this.props.url}
allowFullScreen
/>
);
}
}
Preview.propTypes = {
url: PropTypes.string.isRequired,
};
export default Preview;

Some files were not shown because too many files have changed in this diff Show More