mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-08 11:11:53 +08:00
Merge branch 'master' of github.com:storybooks/storybook into select-knob-ordering
This commit is contained in:
commit
320a3d812e
@ -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:
|
||||
|
@ -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
1
.gitignore
vendored
@ -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__/
|
||||
|
@ -1,4 +1,3 @@
|
||||
/src/
|
||||
/example/
|
||||
/demo/
|
||||
/docs/
|
||||
|
428
CHANGELOG.md
428
CHANGELOG.md
@ -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
|
||||
|
@ -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
|
||||
```
|
||||
```
|
||||
|
15
MIGRATION.md
15
MIGRATION.md
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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": {
|
||||
|
@ -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" />,
|
||||
},
|
||||
]}
|
||||
|
17
addons/a11y/src/components/Report/RerunButton.js
Normal file
17
addons/a11y/src/components/Report/RerunButton.js
Normal 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;
|
@ -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(
|
||||
|
@ -5,6 +5,7 @@ import { baseFonts } from '@storybook/components';
|
||||
const styles = {
|
||||
container: {
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
...baseFonts,
|
||||
},
|
||||
tabs: {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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';
|
||||
|
13
addons/actions/src/lib/util/prepareArguments.js
Normal file
13
addons/actions/src/lib/util/prepareArguments.js
Normal 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.
|
||||
}
|
||||
}
|
@ -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, {
|
||||
|
@ -1,15 +1,30 @@
|
||||
# addon-backgrounds
|
||||
# Storybook Addon Backgrounds
|
||||
|
||||
[](https://travis-ci.org/storybooks/addon-backgrounds)
|
||||
[](https://circleci.com/gh/storybooks/storybook)
|
||||
[](https://www.codefactor.io/repository/github/storybooks/storybook)
|
||||
[](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
|
||||
[](https://bettercodehub.com/results/storybooks/storybook) [](https://codecov.io/gh/storybooks/storybook)
|
||||
[](https://now-examples-slackin-rrirkqohko.now.sh/)
|
||||
[](#backers) [](#sponsors)
|
||||
|
||||

|
||||
* * *
|
||||
|
||||
### 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)
|
||||
|
||||

|
||||
|
||||
## 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>);
|
||||
```
|
||||
|
@ -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",
|
||||
|
@ -5,7 +5,7 @@ import addons from '@storybook/addons';
|
||||
|
||||
const style = {
|
||||
wrapper: {
|
||||
overflow: 'scroll',
|
||||
overflow: 'auto',
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
|
@ -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>",
|
||||
|
@ -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",
|
||||
|
@ -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 |
@ -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
@ -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);
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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';
|
||||
|
13
addons/info/src/components/markdown/pre/copy.js
Normal file
13
addons/info/src/components/markdown/pre/copy.js
Normal 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();
|
||||
}
|
68
addons/info/src/components/markdown/pre/copyButton.js
Normal file
68
addons/info/src/components/markdown/pre/copyButton.js
Normal 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);
|
75
addons/info/src/components/markdown/pre/pre.js
Normal file
75
addons/info/src/components/markdown/pre/pre.js
Normal 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);
|
@ -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>
|
||||
);
|
||||
|
@ -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",
|
||||
|
@ -1,2 +1 @@
|
||||
src
|
||||
.babelrc
|
||||
|
@ -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
1
addons/knobs/polymer.js
Normal file
@ -0,0 +1 @@
|
||||
module.exports = require('./dist/polymer');
|
14
addons/knobs/src/angular/helpers.js
vendored
14
addons/knobs/src/angular/helpers.js
vendored
@ -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),
|
||||
});
|
||||
};
|
||||
|
||||
|
3
addons/knobs/src/angular/utils.js
vendored
3
addons/knobs/src/angular/utils.js
vendored
@ -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
|
||||
|
@ -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
|
||||
|
87
addons/knobs/src/polymer/WrapStory.html
Normal file
87
addons/knobs/src/polymer/WrapStory.html
Normal 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>
|
36
addons/knobs/src/polymer/index.js
Normal file
36
addons/knobs/src/polymer/index.js
Normal 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);
|
||||
}
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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}
|
||||
|
@ -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"
|
||||
|
@ -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 });
|
||||
}
|
||||
|
@ -1,2 +1 @@
|
||||
src
|
||||
.babelrc
|
||||
|
@ -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
|
||||
|
||||

|
||||
|
||||
|
||||
## 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`
|
||||
|
@ -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": "*"
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
67
addons/storyshots/src/test-body-image-snapshot.js
Normal file
67
addons/storyshots/src/test-body-image-snapshot.js
Normal 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;
|
||||
};
|
@ -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' }),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -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).
|
||||
|
||||

|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -1,3 +1,2 @@
|
||||
docs
|
||||
src
|
||||
.babelrc
|
||||
|
@ -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.
|
||||
|
||||
[](https://greenkeeper.io/)
|
||||
|
6
app/angular/demo.d.ts
vendored
6
app/angular/demo.d.ts
vendored
@ -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;
|
||||
}
|
||||
|
33
app/angular/index.d.ts
vendored
33
app/angular/index.d.ts
vendored
@ -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[];
|
||||
}
|
||||
|
@ -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": {
|
||||
|
@ -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');
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {}
|
||||
}
|
||||
}
|
||||
|
@ -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 {}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
94
app/angular/src/client/preview/client_api.js
vendored
94
app/angular/src/client/preview/client_api.js
vendored
@ -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 };
|
||||
});
|
||||
}
|
||||
}
|
@ -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'] },
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
67
app/angular/src/client/preview/config_api.js
vendored
67
app/angular/src/client/preview/config_api.js
vendored
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
39
app/angular/src/client/preview/index.js
vendored
39
app/angular/src/client/preview/index.js
vendored
@ -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 = () => {
|
||||
|
33
app/angular/src/client/preview/init.js
vendored
33
app/angular/src/client/preview/init.js
vendored
@ -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 });
|
||||
}
|
||||
};
|
||||
}
|
89
app/angular/src/client/preview/story_store.js
vendored
89
app/angular/src/client/preview/story_store.js
vendored
@ -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]);
|
||||
}
|
||||
}
|
@ -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>();
|
||||
}
|
||||
|
@ -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';
|
||||
}
|
||||
|
2
app/angular/src/server/build.js
vendored
2
app/angular/src/server/build.js
vendored
@ -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
|
||||
|
4
app/angular/src/server/config.js
vendored
4
app/angular/src/server/config.js
vendored
@ -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');
|
||||
|
2
app/angular/src/server/config/utils.js
vendored
2
app/angular/src/server/config/utils.js
vendored
@ -33,5 +33,3 @@ export function loadEnv(options = {}) {
|
||||
'process.env': env,
|
||||
};
|
||||
}
|
||||
|
||||
export const getConfigDir = () => process.env.SBCONFIG_CONFIG_DIR || './.storybook';
|
||||
|
@ -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$/,
|
||||
|
@ -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')],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -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>
|
||||
|
2
app/angular/src/server/index.js
vendored
2
app/angular/src/server/index.js
vendored
@ -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
|
||||
|
2
app/angular/src/server/middleware.js
vendored
2
app/angular/src/server/middleware.js
vendored
@ -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
27
app/angular/src/server/ts_config.js
vendored
Normal 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,
|
||||
};
|
||||
}
|
32
app/angular/src/server/ts_config.test.js
Normal file
32
app/angular/src/server/ts_config.test.js
Normal 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({});
|
||||
});
|
||||
});
|
@ -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
3
app/polymer/.babelrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["env", "stage-0", "react"]
|
||||
}
|
3
app/polymer/.npmignore
Normal file
3
app/polymer/.npmignore
Normal file
@ -0,0 +1,3 @@
|
||||
docs
|
||||
src
|
||||
.babelrc
|
41
app/polymer/README.md
Normal file
41
app/polymer/README.md
Normal file
@ -0,0 +1,41 @@
|
||||
# Storybook for Polymer
|
||||
|
||||
[](https://circleci.com/gh/storybooks/storybook)
|
||||
[](https://www.codefactor.io/repository/github/storybooks/storybook)
|
||||
[](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
|
||||
[](https://bettercodehub.com/results/storybooks/storybook) [](https://codecov.io/gh/storybooks/storybook)
|
||||
[](https://now-examples-slackin-nqnzoygycp.now.sh/)
|
||||
[](#backers) [](#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 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
3
app/polymer/bin/build.js
Executable file
@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('../dist/server/build');
|
3
app/polymer/bin/index.js
Executable file
3
app/polymer/bin/index.js
Executable file
@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('../dist/server');
|
BIN
app/polymer/docs/demo.gif
Normal file
BIN
app/polymer/docs/demo.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 MiB |
BIN
app/polymer/docs/react_storybook_screenshot.png
Normal file
BIN
app/polymer/docs/react_storybook_screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 245 KiB |
BIN
app/polymer/docs/storybooks_io_logo.png
Normal file
BIN
app/polymer/docs/storybooks_io_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
87
app/polymer/package.json
Normal file
87
app/polymer/package.json
Normal 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"
|
||||
}
|
||||
}
|
17
app/polymer/src/client/index.js
Normal file
17
app/polymer/src/client/index.js
Normal 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'
|
||||
// );
|
7
app/polymer/src/client/manager/index.js
Normal file
7
app/polymer/src/client/manager/index.js
Normal 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());
|
39
app/polymer/src/client/manager/preview.js
Normal file
39
app/polymer/src/client/manager/preview.js
Normal 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
Loading…
x
Reference in New Issue
Block a user