Merge branch 'master' into babel-7

# Conflicts:
#	MIGRATION.md
#	addons/backgrounds/package.json
#	addons/events/package.json
#	addons/info/package.json
#	addons/info/src/__snapshots__/index.test.js.snap
#	addons/jest/package.json
#	addons/knobs/package.json
#	addons/links/package.json
#	addons/notes/package.json
#	addons/options/package.json
#	addons/storyshots/storyshots-core/package.json
#	addons/storyshots/storyshots-puppeteer/package.json
#	addons/storysource/package.json
#	addons/viewport/package.json
#	app/angular/package.json
#	app/html/package.json
#	app/marko/package.json
#	app/mithril/package.json
#	app/polymer/package.json
#	app/react/package.json
#	app/vue/package.json
#	examples/angular-cli/package.json
#	examples/cra-kitchen-sink/package.json
#	examples/html-kitchen-sink/package.json
#	examples/marko-cli/package.json
#	examples/mithril-kitchen-sink/package.json
#	examples/official-storybook/package.json
#	examples/official-storybook/stories/__snapshots__/addon-info.stories.storyshot
#	examples/official-storybook/stories/__snapshots__/other-dirname.stories.storyshot
#	examples/polymer-cli/package.json
#	examples/vue-kitchen-sink/package.json
#	jest.config.js
#	lib/cli/package.json
#	lib/cli/test/snapshots/angular-cli/package.json
#	lib/cli/test/snapshots/marko/package.json
#	lib/cli/test/snapshots/meteor/package.json
#	lib/cli/test/snapshots/mithril/package.json
#	lib/cli/test/snapshots/polymer/package.json
#	lib/cli/test/snapshots/react/package.json
#	lib/cli/test/snapshots/react_project/package.json
#	lib/cli/test/snapshots/react_scripts/package.json
#	lib/cli/test/snapshots/sfc_vue/package.json
#	lib/cli/test/snapshots/update_package_organisations/package.json
#	lib/cli/test/snapshots/vue/package.json
#	lib/cli/test/snapshots/webpack_react/package.json
#	lib/codemod/package.json
#	lib/components/src/layout/__snapshots__/index.stories.storyshot
#	lib/core/package.json
#	lib/core/src/server/config/webpack.config.prod.js
#	package.json
#	yarn.lock
This commit is contained in:
Norbert de Langen 2018-08-15 00:01:36 +02:00
commit a039c96426
No known key found for this signature in database
GPG Key ID: 976651DA156C2825
450 changed files with 8370 additions and 5711 deletions

View File

@ -8,7 +8,9 @@ languages:
- .*\.test\.js
- .*\/__test__\/.*\.js
- .*\/__mock__\/.*\.js
- .*\.stories\.js
test:
include:
- .*\.test\.js
- .*\/__test__\/.*\.js
- .*\.storyshot

View File

@ -39,6 +39,7 @@ jobs:
- examples/official-storybook/node_modules
- examples/polymer-cli/node_modules
- examples/vue-kitchen-sink/node_modules
- examples/svelte-kitchen-sink/node_modules
- examples/marko-cli/node_modules
- save_cache:
name: "Cache core dist"
@ -72,6 +73,11 @@ jobs:
command: |
cd examples/vue-kitchen-sink
yarn build-storybook
- run:
name: "Build svelte kitchen-sink"
command: |
cd examples/svelte-kitchen-sink
yarn build-storybook
- run:
name: "Build angular-cli"
command: |
@ -126,6 +132,11 @@ jobs:
command: |
cd examples/vue-kitchen-sink
yarn storybook --smoke-test
- run:
name: "Run svelte kitchen-sink (smoke test)"
command: |
cd examples/svelte-kitchen-sink
yarn storybook --smoke-test
- run:
name: "Run angular-cli (smoke test)"
command: |

View File

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

View File

@ -14,6 +14,7 @@ module.exports = {
plugins: ['prettier', 'jest', 'import', 'react', 'jsx-a11y', 'json'],
parser: 'babel-eslint',
parserOptions: {
ecmaVersion: 8,
sourceType: 'module',
},
env: {

6
.github/CODEOWNERS vendored
View File

@ -13,7 +13,7 @@
/addons/links/ @hypnosphi @ndelangen
/addons/notes/ @alexandrebodin
/addons/options/ @danielduan @UsulPro
/addons/storyshots/ @igor-dv @thomasbertet @hypnosphi
/addons/storyshots/ @igor-dv @thomasbertet @hypnosphi
/addons/storysource/ @igor-dv
/addons/viewport/ @saponifi3d
@ -22,16 +22,18 @@
/app/react/ @xavcz @shilman @thomasbertet
/app/react-native/ @rmevans9 @danielduan @Gongreg @tmeasday
/app/vue/ @thomasbertet @kazupon
/app/svelte/ @plumpNation
/docs/ @ndelangen @shilman @hypnosphi
/examples/angular-cli/ @igor-dv @alterx
/examples/cra-kitchen-sink/ @ndelangen @UsulPro @hypnosphi
/examples/cra-kitchen-sink/ @ndelangen @UsulPro @hypnosphi
/examples/crna-kitchen-sink/ @Gongreg @danielduan
/examples/official-storybook/ @hypnosphi @danielduan @UsulPro
/examples/polymer-cli/ @naipath @igor-dv
/examples/react-native-vanilla/ @tmeasday @danielduan
/examples/vue-kitchen-sink/ @igor-dv @alexandrebodin
/examples/svelte-kitchen-sink/ @plumpNation
/lib/addons/ @ndelangen @theinterned
/lib/channel-postmessage/ @mnmtanish @ndelangen

View File

@ -17,6 +17,7 @@
'app: react-native': ["app/react-native/**"]
'app: react': ["app/react/**"]
'app: vue': ["app/vue/**"]
'app: svelte': ["app/svelte/**"]
'app: mithril': ["app/mithril/**"]
'babel / webpack': ["webpack", "babel"]
'cli': ["lib/cli/**"]

View File

@ -1,6 +1,7 @@
/example/
/demo/
/docs/
/media/
/node_modules/
/.storybook/

View File

@ -6,6 +6,7 @@
addon
1
vue
svelte
webcomponents
aurelia
iframe

View File

@ -15,7 +15,7 @@ enum class StorybookApp(val appName: String, val exampleDir: String, val merged:
HTML("HTML", "html-kitchen-sink"),
MARKO("Marko", "marko-cli"),
HYPERAPP("Hyperapp", "hyperapp-kitchen-sink", false),
SVELTE("Svelte", "svelte-kitchen-sink", false);
SVELTE("Svelte", "svelte-kitchen-sink");
val lowerName = appName.toLowerCase()

View File

@ -0,0 +1,107 @@
package OpenSourceProjects_Storybook.patches.projects
import jetbrains.buildServer.configs.kotlin.v2017_2.*
import jetbrains.buildServer.configs.kotlin.v2017_2.Project
import jetbrains.buildServer.configs.kotlin.v2017_2.ProjectFeature
import jetbrains.buildServer.configs.kotlin.v2017_2.ui.*
/*
This patch script was generated by TeamCity on settings change in UI.
To apply the patch, change the project with uuid = '69382d9b-7791-418a-9ff6-1c83b86ed6b5' (id = 'OpenSourceProjects_Storybook')
accordingly, and delete the patch script.
*/
changeProject("69382d9b-7791-418a-9ff6-1c83b86ed6b5") {
features {
val feature1 = find<ProjectFeature> {
feature {
type = "project-graphs"
id = "PROJECT_EXT_306"
param("format", "duration")
param("series", """
[
{
"type": "valueType",
"title": "Build Duration (all stages)",
"sourceBuildTypeId": "OpenSourceProjects_Storybook_Build_2",
"key": "BuildDuration"
}
]
""".trimIndent())
param("seriesTitle", "Serie")
param("title", "New chart title")
}
}
feature1.apply {
param("hideFilters", "")
param("title", "Build Duration (all stages)")
param("defaultFilters", "")
}
val feature2 = find<ProjectFeature> {
feature {
type = "project-graphs"
id = "PROJECT_EXT_307"
param("defaultFilters", "")
param("format", "percent")
param("hideFilters", "")
param("series", """
[
{
"type": "valueType",
"title": "Covered Percentage of JS Lines",
"sourceBuildTypeId": "OpenSourceProjects_Storybook_Test",
"key": "Covered Percentage of JS Lines"
}
]
""".trimIndent())
param("seriesTitle", "Serie")
param("title", "New chart title")
}
}
feature2.apply {
param("title", "Covered Percentage of JS Lines")
}
val feature3 = find<ProjectFeature> {
feature {
type = "project-graphs"
id = "PROJECT_EXT_308"
param("format", "integer")
param("series", """
[
{
"type": "valueType",
"title": "Total Number of JS Statements",
"sourceBuildTypeId": "OpenSourceProjects_Storybook_Test",
"key": "Total Number of JS Statements"
}
]
""".trimIndent())
param("seriesTitle", "Serie")
param("title", "New chart title")
}
}
feature3.apply {
param("hideFilters", "")
param("title", "Total Number of JS Statements")
param("defaultFilters", "")
}
add {
feature {
type = "project-graphs"
id = "PROJECT_EXT_117"
param("series", """
[
{
"type": "valueType",
"title": "Total Artifacts Size",
"sourceBuildTypeId": "OpenSourceProjects_Storybook_CliTestLatestCra",
"key": "ArtifactsSize"
}
]
""".trimIndent())
param("format", "text")
param("title", "Total Artifacts Size")
param("seriesTitle", "Serie")
}
}
}
}

View File

@ -1,19 +1,19 @@
## Addon / Framework Support Table
| |[React](app/react)|[React Native](app/react-native)|[Vue](app/vue)|[Angular](app/angular)| [Polymer](app/polymer)| [Mithril](app/mithril)| [HTML](app/html)| [Marko](app/marko)|
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|[a11y](addons/a11y) |+| |+|+|+|+|+|+|
|[actions](addons/actions) |+|+|+|+|+|+|+|+|
|[backgrounds](addons/backgrounds) |+| |+|+|+|+|+|+|
|[centered](addons/centered) |+| |+|+| |+|+| |
|[events](addons/events) |+| |+|+|+|+|+|+|
|[graphql](addons/graphql) |+| | | | | | | |
|[info](addons/info) |+| | | | | | | |
|[jest](addons/jest) |+| | |+| | |+| |
|[knobs](addons/knobs) |+|+|+|+|+|+|+|+|
|[links](addons/links) |+|+|+|+|+|+|+| |
|[notes](addons/notes) |+| |+|+|+|+|+| |
|[options](addons/options) |+|+|+|+|+|+|+| |
|[storyshots](addons/storyshots) |+|+|+|+| | |+| |
|[storysource](addons/storysource)|+| |+|+|+|+|+|+|
|[viewport](addons/viewport) |+| |+|+|+|+|+|+|
| |[React](app/react)|[React Native](app/react-native)|[Vue](app/vue)|[Angular](app/angular)| [Polymer](app/polymer)| [Mithril](app/mithril)| [HTML](app/html)| [Marko](app/marko)| [Svelte](app/svelte)|
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|[a11y](addons/a11y) |+| |+|+|+|+|+|+| |
|[actions](addons/actions) |+|+|+|+|+|+|+|+|+|
|[backgrounds](addons/backgrounds) |+| |+|+|+|+|+|+|+|
|[centered](addons/centered) |+| |+|+| |+|+| |+|
|[events](addons/events) |+| |+|+|+|+|+|+| |
|[graphql](addons/graphql) |+| | | | | | | | |
|[info](addons/info) |+| | | | | | | | |
|[jest](addons/jest) |+| | |+| | |+| | |
|[knobs](addons/knobs) |+|+|+|+|+|+|+|+|+|
|[links](addons/links) |+|+|+|+|+|+|+| |+|
|[notes](addons/notes) |+| |+|+|+|+|+| |+|
|[options](addons/options) |+|+|+|+|+|+|+| |+|
|[storyshots](addons/storyshots) |+|+|+|+| | |+| |+|
|[storysource](addons/storysource)|+| |+|+|+|+|+|+|+|
|[viewport](addons/viewport) |+| |+|+|+|+|+|+|+|

View File

@ -1,3 +1,67 @@
# 4.0.0-alpha.16
2018-August-06
#### Features
- Make addon-options work with story parameters [#3958](https://github.com/storybooks/storybook/pull/3958)
#### Bug Fixes
- [BUG FIX] Use fixed version of react-dev-utils [#3959](https://github.com/storybooks/storybook/pull/3959)
- Inline emotion css calls that require theme to avoid using state [#3950](https://github.com/storybooks/storybook/pull/3950)
#### Dependency Upgrades
- Upgrade even more dependencies [#3964](https://github.com/storybooks/storybook/pull/3964)
- More dependency upgrades (major version bumps) [#3957](https://github.com/storybooks/storybook/pull/3957)
- UPGRADE all minor dependencies [#3954](https://github.com/storybooks/storybook/pull/3954)
# 4.0.0-alpha.15
2018-August-03
#### Breaking Changes
- dependencies(vue): Update vue-loader to 15.x.x [#3911](https://github.com/storybooks/storybook/pull/3911)
#### Features
- Horizontal display for addon-knobs radios UI [#3922](https://github.com/storybooks/storybook/pull/3922)
- Add customizePage method to imageSnapshot [#3930](https://github.com/storybooks/storybook/pull/3930)
- Add additional device options to addon-viewport [#3918](https://github.com/storybooks/storybook/pull/3918)
- Support different extensions for "config" and "addons" files [#3913](https://github.com/storybooks/storybook/pull/3913)
- Add radio buttons knob type #3872 [#3894](https://github.com/storybooks/storybook/pull/3894)
- Added arrow to a11y addon HeaderBar [#3788](https://github.com/storybooks/storybook/pull/3788)
- Fix addons panel when using preact [#3882](https://github.com/storybooks/storybook/pull/3882)
#### Bug Fixes
- Fix typo in addon-viewport [#3942](https://github.com/storybooks/storybook/pull/3942)
- Fix knobs for React < 16.3 [#3866](https://github.com/storybooks/storybook/pull/3866)
#### Maintenance
- Improve BettercodeHub [#3941](https://github.com/storybooks/storybook/pull/3941)
- REFACTOR layout and REMOVE usplit component [#3914](https://github.com/storybooks/storybook/pull/3914)
- Group deprecated stories [#3846](https://github.com/storybooks/storybook/pull/3846)
- MOVE ui into it's own group [#3884](https://github.com/storybooks/storybook/pull/3884)
#### Dependency Upgrades
- Use react-dev-utils@next [#3852](https://github.com/storybooks/storybook/pull/3852)
# 3.4.10
2018-August-03
NOTE: `3.4.9` publish failed
#### Bug Fixes
- addons-jest: bug with the jest parameter [#3923](https://github.com/storybooks/storybook/pull/3923)
- addon-info: fix copy button styling [#3896](https://github.com/storybooks/storybook/pull/3896)
# 4.0.0-alpha.14
2018-July-11
@ -302,9 +366,12 @@
2018-May-17
NOTE: As part of the generic addon decorators, we've reversed the order of addon-knob's `select` knob keys/values, which had been called `selectV2` prior to this breaking change.
#### Breaking Changes
- Support webpack4 modules format [#3576](https://github.com/storybooks/storybook/pull/3576)
- Generic addon decorators [#3555](https://github.com/storybooks/storybook/pull/3555)
#### Features
@ -312,7 +379,6 @@
#### Maintenance
- Generic addon decorators [#3555](https://github.com/storybooks/storybook/pull/3555)
- Refactor transitional decorator from addon-notes [#3559](https://github.com/storybooks/storybook/pull/3559)
# 3.4.5

View File

@ -8,11 +8,11 @@ This repo uses yarn workspaces, so you should install `yarn@1.3.2` or higher as
## Issues
No software is bug free. So, if you got an issue, follow these steps:
No software is bug-free. So, if you got an issue, follow these steps:
- Search the [issue list](https://github.com/storybooks/storybook/issues?utf8=%E2%9C%93&q=) for current and old issues.
- If you find an existing issue, please UPVOTE the issue by adding a "thumbs-up reaction". We use this to help prioritize issues!
- If none of that is helping, create an issue with with following information:
- If none of that is helping, create an issue with the following information:
- Clear title (shorter is better).
- Describe the issue in clear language.
- Share error logs, screenshots and etc.
@ -53,7 +53,7 @@ You can use the `--update` flag to update snapshots or screenshots as needed.
You can also pick suites from CLI. Suites available are listed below.
##### Core & React & Vue Tests
##### Core & React & Vue & Svelte Tests
`yarn test --core`
@ -71,8 +71,15 @@ Before these tests are ran, the project must be bootstrapped with the React Nati
`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.
This option executes tests from `<rootdir>/examples/official-storybook`
In order for the image snapshots to be correctly generated, you must have static build of the storybook up-to-date :
```javascript
cd examples/official-storybook
yarn build-storybook
cd ../..
yarn test --image
```
Puppeteer is used to launch and grab screenshots of example pages, while jest is used to assert matching images. (just like integration tests)
@ -88,7 +95,7 @@ After that, the `run` directory content will be compared with `snapshots`. You c
yarn test --cli --update
In that case, please check the git diff before commiting to make sure it only contains the intended changes.
In that case, please check the git diff before committing to make sure it only contains the intended changes.
#### 2c. Link `storybook` and any other required dependencies:
@ -133,7 +140,7 @@ A good way to do that is using the example `cra-kitchen-sink` app embedded in th
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.
**NOTE**: If your issue involves a webpack config, create-react-app will prevent you from modifying the _app's_ webpack config, however you can still modify storybook's to mirror your app's version of storybook. Alternatively, use `yarn eject` in the CRA app to get a modifiable webpack config.
**NOTE**: If your issue involves a webpack config, create-react-app will prevent you from modifying the _app's_ webpack config, however you can still modify storybook's to mirror your app's version of the storybook. Alternatively, use `yarn eject` in the CRA app to get a modifiable webpack config.
### Updating Tests
@ -157,7 +164,7 @@ We welcome your contributions. There are many ways you can help us. This is few
- Work on [API](https://github.com/storybooks/storybook/labels/enhancement%3A%20api), [Addons](https://github.com/storybooks/storybook/labels/enhancement%3A%20addons), [UI](https://github.com/storybooks/storybook/labels/enhancement%3A%20ui) or [Webpack](https://github.com/storybooks/storybook/labels/enhancement%3A%20webpack) use enhancements and new [features](https://github.com/storybooks/storybook/labels/feature%20request).
- Add more [tests](https://codecov.io/gh/storybooks/storybook/tree/master/packages) (specially for the [UI](https://codecov.io/gh/storybooks/storybook/tree/master/packages/storybook-ui/src)).
Before you submit a new PR, make you to run `yarn test`. Do not submit a PR if tests are failing. If you need any help, create an issue and ask.
Before you submit a new PR, make sure you run `yarn test`. Do not submit a PR if tests are failing. If you need any help, create an issue and ask.
### Reviewing PRs
@ -238,7 +245,7 @@ _This method is slow_
Within the `examples` folder of the Storybook repo, you will find kitchen sink examples of storybook implementations for the various platforms that storybook supports.
Not only do these show many of the options and addons available, they are also automatically linked to all the development packages. We highly encourage you to use these to develop/test contributions on.
Not only do these show many of the options and add-ons available, they are also automatically linked to all the development packages. We highly encourage you to use these to develop/test contributions on.
#### React and Vue
@ -249,8 +256,8 @@ Not only do these show many of the options and addons available, they are also a
#### Linking Storybook
Storybook is broken up into sub-projects that you can install as you need them. For this example we will be working with `@storybook/react`.
**Note:** You need to `yarn link` from inside the sub project you are working on **_NOT_** the storybook root directory
Storybook is broken up into sub-projects that you can install as you need them. For this example, we will be working with `@storybook/react`.
**Note:** You need to `yarn link` from inside the subproject you are working on **_NOT_** the storybook root directory
1. `cd app/react`
2. `yarn link`
@ -264,7 +271,7 @@ _Make sure `yarn dev` is running_
##### 1. Setup storybook in your project
First we are going to install storyboook, then we are going to link `@storybook/react` into our project. This will replace `node_modules/@storybook/react` with a symlink to our local version of storybook.
First we are going to install storybook, then we are going to link `@storybook/react` into our project. This will replace `node_modules/@storybook/react` with a symlink to our local version of storybook.
1. `getstorybook`
2. `yarn storybook`
@ -302,7 +309,7 @@ The current manual release sequence is as follows:
- Generate a changelog and verify the release by hand
- Push the changelog to master or the release branch
- Clean, build, and publish the release
- Clean, build and publish the release
- Cut and paste the changelog to the github release page, and mark it as a (pre-) release
This sequence applies to both releases and pre-releases, but differs slightly between the two.

View File

@ -2,38 +2,56 @@
## Table of contents
- [From version 3.4.x to 4.0.x](#from-version-34x-to-40x)
- [Keyboard shortcuts moved](#keyboard-shortcuts-moved)
- [Removed addWithInfo](#removed-add-with-info)
- [Removed RN addons](#removed-rn-addons)
- [Storyshots changes](#storyshots-changes)
- [Webpack 4](#webpack-4)
- [Babel 7](#babel-7)
- [From version 3.3.x to 3.4.x](#from-version-33x-to-34x)
- [From version 3.2.x to 3.3.x](#from-version-32x-to-33x)
- [Refactored Knobs](#refactored-knobs)
- [Storyshots Jest configuration](#storyshots-jest-configuration)
- [From version 3.1.x to 3.2.x](#from-version-31x-to-32x)
- [Moved TypeScript addons definitions](#moved-typescript-addons-definitions)
- [Updated Addons API](#updated-addons-api)
- [From version 3.0.x to 3.1.x](#from-version-30x-to-31x)
- [Moved TypeScript definitions](#moved-typescript-definitions)
- [Deprecated head.html](#deprecated-headhtml)
- [From version 2.x.x to 3.x.x](#from-version-2xx-to-3xx)
- [Webpack upgrade](#webpack-upgrade)
- [Packages renaming](#packages-renaming)
- [Deprecated embedded addons](#deprecated-embedded-addons)
- [From version 3.4.x to 4.0.x](#from-version-34x-to-40x)
- [Keyboard shortcuts moved](#keyboard-shortcuts-moved)
- [Removed addWithInfo](#removed-add-with-info)
- [Removed RN addons](#removed-rn-addons)
- [Storyshots changes](#storyshots-changes)
- [Webpack 4](#webpack-4)
- [Babel 7](#babel-7)
- [From version 3.3.x to 3.4.x](#from-version-33x-to-34x)
- [From version 3.2.x to 3.3.x](#from-version-32x-to-33x)
- [Refactored Knobs](#refactored-knobs)
- [Storyshots Jest configuration](#storyshots-jest-configuration)
- [From version 3.1.x to 3.2.x](#from-version-31x-to-32x)
- [Moved TypeScript addons definitions](#moved-typescript-addons-definitions)
- [Updated Addons API](#updated-addons-api)
- [From version 3.0.x to 3.1.x](#from-version-30x-to-31x)
- [Moved TypeScript definitions](#moved-typescript-definitions)
- [Deprecated head.html](#deprecated-headhtml)
- [From version 2.x.x to 3.x.x](#from-version-2xx-to-3xx)
- [Webpack upgrade](#webpack-upgrade)
- [Packages renaming](#packages-renaming)
- [Deprecated embedded addons](#deprecated-embedded-addons)
## From 3.4.x to 4.0
With 4.0 as our first major release in over a year, we've collected a lot of cleanup tasks. All deprecations have been marked for months, so we hope that there will be no significant impact on your project.
### Generic addons
4.x introduces generic addon decorators that are not tied to specific view layers [#3555](https://github.com/storybooks/storybook/pull/3555). So for example:
```js
import { number } from "@storybook/addon-knobs/react";
```
Becomes:
```js
import { number } from "@storybook/addon-knobs";
```
### Knobs select ordering
4.0 also reversed the order of addon-knob's `select` knob keys/values, which had been called `selectV2` prior to this breaking change. See the knobs [package README](https://github.com/storybooks/storybook/blob/master/addons/knobs/README.md#select) for usage.
### Keyboard shortcuts moved
- Addon Panel to `Z`
- Stories Panel to `X`
- Show Search to `O`
- Addon Panel right side to `G`
- Addon Panel to `Z`
- Stories Panel to `X`
- Show Search to `O`
- Addon Panel right side to `G`
### Removed addWithInfo
@ -45,16 +63,16 @@ The `@storybook/react-native` had built-in addons (`addon-actions` and `addon-li
### Storyshots Changes
1. `imageSnapshot` test function was extracted from `addon-storyshots`
and moved to a new package - `addon-storyshots-puppeteer` that now will
be dependant on puppeteer. [README](https://github.com/storybooks/storybook/tree/master/addons/storyshots/storyshots-puppeteer)
2. `getSnapshotFileName` export was replaced with the `Stories2SnapsConverter`
class that now can be overridden for a custom implementation of the
snapshot-name generation. [README](https://github.com/storybooks/storybook/tree/master/addons/storyshots/storyshots-core#stories2snapsconverter)
3. Storybook that was configured with Webpack's `require.context()` feature
will need to add a babel plugin to polyfill this functionality.
A possible plugin might be [babel-plugin-require-context-hook](https://github.com/smrq/babel-plugin-require-context-hook).
[README](https://github.com/storybooks/storybook/tree/master/addons/storyshots/storyshots-core#configure-jest-to-work-with-webpacks-requirecontext)
1. `imageSnapshot` test function was extracted from `addon-storyshots`
and moved to a new package - `addon-storyshots-puppeteer` that now will
be dependant on puppeteer. [README](https://github.com/storybooks/storybook/tree/master/addons/storyshots/storyshots-puppeteer)
2. `getSnapshotFileName` export was replaced with the `Stories2SnapsConverter`
class that now can be overridden for a custom implementation of the
snapshot-name generation. [README](https://github.com/storybooks/storybook/tree/master/addons/storyshots/storyshots-core#stories2snapsconverter)
3. Storybook that was configured with Webpack's `require.context()` feature
will need to add a babel plugin to polyfill this functionality.
A possible plugin might be [babel-plugin-require-context-hook](https://github.com/smrq/babel-plugin-require-context-hook).
[README](https://github.com/storybooks/storybook/tree/master/addons/storyshots/storyshots-core#configure-jest-to-work-with-webpacks-requirecontext)
### Webpack 4
@ -82,9 +100,11 @@ Also read on if you're using `addon-knobs`: we advise an update to your code for
### `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))
@ -98,7 +118,7 @@ Knobs users: there was a bug in 3.2.x where using the knobs addon imported all f
In the case of React or React-Native, import knobs like this:
```js
import { withKnobs, text, boolean, number } from '@storybook/addon-knobs/react';
import { withKnobs, text, boolean, number } from "@storybook/addon-knobs/react";
```
In the case of Vue: `import { ... } from '@storybook/addon-knobs/vue';`
@ -126,14 +146,14 @@ We're in the process of upgrading our addons APIs. As a first step, we've upgrad
Here's an example of using Notes and Info in 3.2 with the new API.
```js
storiesOf('composition', module)
.add('new addons api',
withInfo('see Notes panel for composition info')(
withNotes({ text: 'Composition: Info(Notes())' })(context =>
<MyComponent name={context.story} />
)
)
);
storiesOf("composition", module).add(
"new addons api",
withInfo("see Notes panel for composition info")(
withNotes({ text: "Composition: Info(Notes())" })(context => (
<MyComponent name={context.story} />
))
)
);
```
It's not beautiful, but we'll be adding a more convenient/idiomatic way of using these [withX primitives](https://gist.github.com/shilman/792dc25550daa9c2bf37238f4ef7a398) in Storybook 3.3.
@ -156,8 +176,8 @@ We have deprecated the use of `head.html` for including scripts/styles/etc. into
Now we use:
- `preview-head.html` for including extra content into the preview pane.
- `manager-head.html` for including extra content into the manager window.
- `preview-head.html` for including extra content into the preview pane.
- `manager-head.html` for including extra content into the manager window.
[Read our docs](https://storybook.js.org/configurations/add-custom-head-tags/) for more details.
@ -239,17 +259,17 @@ We used to ship 2 addons with every single installation of storybook: `actions`
If you **are** using these addons, migrating is simple:
- add the addons you use to your `package.json`.
- update your code:
change `addons.js` like so:
```js
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
```
change `x.story.js` like so:
```js
import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';
```
- add the addons you use to your `package.json`.
- update your code:
change `addons.js` like so:
```js
import "@storybook/addon-actions/register";
import "@storybook/addon-links/register";
```
change `x.story.js` like so:
```js
import React from "react";
import { storiesOf } from "@storybook/react";
import { action } from "@storybook/addon-actions";
import { linkTo } from "@storybook/addon-links";
```

View File

@ -7,7 +7,7 @@
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
[![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=<badge_key>)](https://www.browserstack.com/automate/public-build/<badge_key>)
<!-- [![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=<badge_key>)](https://www.browserstack.com/automate/public-build/<badge_key>) -->
* * *
@ -16,7 +16,7 @@ It allows you to browse a component library, view the different states of each c
## Intro
![Storybook Screenshot](app/react/docs/demo.gif)
![Storybook Screenshot](media/demo.gif)
Storybook runs outside of your app. This allows you to develop UI components in isolation, which can improve component reuse, testability, and development speed. You can build quickly without having to worry about application-specific dependencies.
@ -77,6 +77,7 @@ For additional help, join us [in our Slack](https://now-examples-slackin-rrirkqo
- [Mithril](app/mithril) <sup>alpha</sup>
- [Marko](app/marko) <sup>alpha</sup>
- [HTML](app/html) <sup>alpha</sup>
- [Svelte](app/svelte) <sup>alpha</sup>
### Sub Projects
@ -115,6 +116,7 @@ See [Addon / Framework Support Table](ADDONS_SUPPORT.md)
- [Mithril](https://storybooks-mithril.netlify.com/)
- [Marko](https://storybooks-marko.netlify.com/)
- [HTML](https://storybooks-html.netlify.com/)
- [Svelte](https://storybooks-svelte.netlify.com/)
### 3.4
- [React Official](https://release-3-4--storybooks-official.netlify.com)

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-a11y",
"version": "4.0.0-alpha.14",
"version": "4.0.0-alpha.16",
"description": "a11y addon for storybook",
"keywords": [
"a11y",
@ -25,14 +25,14 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-alpha.14",
"@storybook/client-logger": "4.0.0-alpha.14",
"@storybook/components": "4.0.0-alpha.14",
"@storybook/core-events": "4.0.0-alpha.14",
"@storybook/addons": "4.0.0-alpha.16",
"@storybook/client-logger": "4.0.0-alpha.16",
"@storybook/components": "4.0.0-alpha.16",
"@storybook/core-events": "4.0.0-alpha.16",
"axe-core": "^3.0.3",
"global": "^4.3.2",
"prop-types": "^15.6.1",
"react-emotion": "^9.1.3"
"prop-types": "^15.6.2",
"react-emotion": "^9.2.6"
},
"peerDependencies": {
"react": "*",

View File

@ -35,21 +35,27 @@ class Panel extends Component {
};
componentDidMount() {
this.props.channel.on(CHECK_EVENT_ID, this.onUpdate);
this.props.channel.on(STORY_RENDERED, this.requestCheck);
this.props.channel.on(RERUN_EVENT_ID, this.requestCheck);
const { channel } = this.props;
channel.on(CHECK_EVENT_ID, this.onUpdate);
channel.on(STORY_RENDERED, this.requestCheck);
channel.on(RERUN_EVENT_ID, this.requestCheck);
}
componentDidUpdate(prevProps) {
if (!prevProps.active && this.props.active) {
const { active } = this.props;
if (!prevProps.active && active) {
this.requestCheck();
}
}
componentWillUnmount() {
this.props.channel.removeListener(CHECK_EVENT_ID, this.onUpdate);
this.props.channel.removeListener(STORY_RENDERED, this.requestCheck);
this.props.channel.removeListener(RERUN_EVENT_ID, this.requestCheck);
const { channel } = this.props;
channel.removeListener(CHECK_EVENT_ID, this.onUpdate);
channel.removeListener(STORY_RENDERED, this.requestCheck);
channel.removeListener(RERUN_EVENT_ID, this.requestCheck);
}
onUpdate = ({ passes, violations }) => {
@ -60,8 +66,10 @@ class Panel extends Component {
};
requestCheck = () => {
if (this.props.active) {
this.props.channel.emit(REQUEST_CHECK_EVENT_ID);
const { channel, active } = this.props;
if (active) {
channel.emit(REQUEST_CHECK_EVENT_ID);
}
};

View File

@ -40,7 +40,9 @@ Element.propTypes = {
/* eslint-disable react/no-array-index-key */
const Elements = ({ elements, passes }) => (
<ol>
{elements.map((element, index) => <Element passes={passes} element={element} key={index} />)}
{elements.map((element, index) => (
<Element passes={passes} element={element} key={index} />
))}
</ol>
);

View File

@ -2,6 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styled from 'react-emotion';
import { Icons } from '@storybook/components';
import Info from './Info';
import Tags from './Tags';
@ -55,7 +56,19 @@ class Item extends Component {
return (
<Wrapper>
<HeaderBar onClick={this.onToggle}>{item.description}</HeaderBar>
<HeaderBar onClick={this.onToggle}>
<Icons.ChevronRight
size={10}
color="#9DA5AB"
style={{
marginRight: '5px',
marginBottom: '2px',
transform: `rotate(${open ? 90 : 0}deg)`,
transition: 'transform 0.3s ease-in-out',
}}
/>
{item.description}
</HeaderBar>
{open && <Info item={item} />}
{open && <Elements elements={item.nodes} passes={passes} />}
{open && <Tags tags={item.tags} />}

View File

@ -61,7 +61,11 @@ Rule.propTypes = {
/* eslint-disable react/no-array-index-key */
function Rules({ rules, passes }) {
return (
<List>{rules.map((rule, index) => <Rule passes={passes} rule={rule} key={index} />)}</List>
<List>
{rules.map((rule, index) => (
<Rule passes={passes} rule={rule} key={index} />
))}
</List>
);
}
Rules.propTypes = {

View File

@ -17,7 +17,13 @@ const Item = styled('div')(({ theme }) => ({
}));
function Tags({ tags }) {
return <Wrapper>{tags.map(tag => <Item key={tag}>{tag}</Item>)}</Wrapper>;
return (
<Wrapper>
{tags.map(tag => (
<Item key={tag}>{tag}</Item>
))}
</Wrapper>
);
}
Tags.propTypes = {
tags: PropTypes.arrayOf(PropTypes.node).isRequired,

View File

@ -1,14 +1,5 @@
# Storybook Addon Actions
[![Build Status on CircleCI](https://circleci.com/gh/storybooks/storybook.svg?style=shield)](https://circleci.com/gh/storybooks/storybook)
[![CodeFactor](https://www.codefactor.io/repository/github/storybooks/storybook/badge)](https://www.codefactor.io/repository/github/storybooks/storybook)
[![Known Vulnerabilities](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847/badge.svg)](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
---
Storybook Addon Actions can be used to display data received by event handlers in [Storybook](https://storybook.js.org).
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-actions",
"version": "4.0.0-alpha.14",
"version": "4.0.0-alpha.16",
"description": "Action Logger addon for storybook",
"keywords": [
"storybook"
@ -20,19 +20,19 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-alpha.14",
"@storybook/components": "4.0.0-alpha.14",
"@storybook/core-events": "4.0.0-alpha.14",
"@storybook/addons": "4.0.0-alpha.16",
"@storybook/components": "4.0.0-alpha.16",
"@storybook/core-events": "4.0.0-alpha.16",
"babel-runtime": "^6.26.0",
"deep-equal": "^1.0.1",
"emotion-theming": "^9.1.2",
"emotion-theming": "^9.2.6",
"global": "^4.3.2",
"lodash.isequal": "^4.5.0",
"make-error": "^1.3.4",
"prop-types": "^15.6.1",
"react-emotion": "^9.1.3",
"prop-types": "^15.6.2",
"react-emotion": "^9.2.6",
"react-inspector": "^2.3.0",
"uuid": "^3.2.1"
"uuid": "^3.3.2"
},
"peerDependencies": {
"react": "*"

View File

@ -0,0 +1,4 @@
export const ADDON_ID = 'storybook/actions';
export const PANEL_ID = `${ADDON_ID}/actions-panel`;
export const EVENT_ID = `${ADDON_ID}/action-event`;
export const CYCLIC_KEY = '$___storybook.isCyclic';

View File

@ -6,8 +6,8 @@ import deepEqual from 'deep-equal';
import { CYCLIC_KEY, retrocycle } from '../../lib';
import { isObject } from '../../lib/util';
import ActionLoggerComponent from '../../components/ActionLogger/';
import { EVENT_ID } from '../../';
import ActionLoggerComponent from '../../components/ActionLogger';
import { EVENT_ID } from '../..';
export default class ActionLogger extends React.Component {
constructor(props, ...args) {
@ -18,12 +18,16 @@ export default class ActionLogger extends React.Component {
}
componentDidMount() {
this.props.channel.on(EVENT_ID, this._actionListener);
this.stopListeningOnStory = this.props.api.onStory(this._storyChangeListener);
const { channel, api } = this.props;
channel.on(EVENT_ID, this._actionListener);
this.stopListeningOnStory = api.onStory(this._storyChangeListener);
}
componentWillUnmount() {
this.props.channel.removeListener(EVENT_ID, this._actionListener);
const { channel } = this.props;
channel.removeListener(EVENT_ID, this._actionListener);
if (this.stopListeningOnStory) {
this.stopListeningOnStory();
}
@ -37,9 +41,11 @@ export default class ActionLogger extends React.Component {
}
addAction(action) {
let { actions = [] } = this.state;
actions = [...actions];
action.data.args = action.data.args.map(arg => retrocycle(arg)); // eslint-disable-line
const isCyclic = !!action.data.args.find(arg => isObject(arg) && arg[CYCLIC_KEY]);
const actions = [...this.state.actions];
const previous = actions.length && actions[0];
if (previous && !isCyclic && deepEqual(previous.data, action.data, { strict: true })) {
@ -56,9 +62,10 @@ export default class ActionLogger extends React.Component {
}
render() {
const { actions = [] } = this.state;
const { active } = this.props;
const props = {
actions: this.state.actions,
actions,
onClear: () => this.clearActions(),
};
return active ? <ActionLoggerComponent {...props} /> : null;

View File

@ -8,8 +8,16 @@ import {
} from './preview';
// addons, panels and events get unique names using a prefix
export const ADDON_ID = 'storybook/actions';
export const PANEL_ID = `${ADDON_ID}/actions-panel`;
export const EVENT_ID = `${ADDON_ID}/action-event`;
import { ADDON_ID, PANEL_ID, EVENT_ID } from './constants';
export { action, actions, decorate, configureActions, decorateAction, withActions };
export {
action,
actions,
decorate,
configureActions,
decorateAction,
withActions,
ADDON_ID,
PANEL_ID,
EVENT_ID,
};

View File

@ -2,7 +2,7 @@ import { DecycleError } from './errors';
import { getPropertiesList, typeReplacer, omitProperty } from './util';
import { CYCLIC_KEY } from './';
import { CYCLIC_KEY } from '../constants';
import { objectType } from './types';

View File

@ -1,6 +1,6 @@
import reviver from './reviver';
import { muteProperty } from './util';
import { CYCLIC_KEY } from './';
import { CYCLIC_KEY } from '../constants';
// eslint-disable-next-line no-control-regex
const pathReg = /^\$(?:\[(?:\d+|"(?:[^\\"\u0000-\u001f]|\\([\\"/bfnrt]|u[0-9a-zA-Z]{4}))*")])*$/;

View File

@ -1,4 +1,4 @@
import dateType from '../';
import dateType from '..';
const date = new Date(1512137134873);
const isoString = date.toISOString();

View File

@ -1,4 +1,4 @@
import functionType from '../';
import functionType from '..';
import reservedKeywords from '../reservedKeywords';
import createFunction from '../createFunction';
import createBoundFunction from '../createBoundFunction';

View File

@ -1,4 +1,4 @@
import infinityType from '../';
import infinityType from '..';
describe('Infinity', () => {
it('Recognizes Infinity', () => {

View File

@ -1,4 +1,4 @@
import nanType from '../';
import nanType from '..';
describe('NaN', () => {
it('Recognizes NaN', () => {

View File

@ -1,4 +1,4 @@
import objectType from '../';
import objectType from '..';
import { DEPTH_KEY } from '../configureDepth';
describe('Object', () => {

View File

@ -1,4 +1,4 @@
import regExpType from '../';
import regExpType from '..';
const regExp = /aRegExp/g;

View File

@ -1,4 +1,4 @@
import symbolType from '../';
import symbolType from '..';
const symbol = Symbol('S');

View File

@ -1,4 +1,4 @@
import undefinedType from '../';
import undefinedType from '..';
describe('undefined', () => {
it('Recognizes undefined', () => {

View File

@ -1,7 +1,7 @@
import React from 'react';
import addons from '@storybook/addons';
import ActionLogger from './containers/ActionLogger';
import { ADDON_ID, PANEL_ID } from './';
import { ADDON_ID, PANEL_ID } from '.';
export function register() {
addons.register(ADDON_ID, api => {

View File

@ -1,5 +1,5 @@
import addons from '@storybook/addons';
import { action, configureActions } from '../../';
import { action, configureActions } from '../..';
jest.mock('@storybook/addons');

View File

@ -1,5 +1,5 @@
import { config } from '../configureActions';
import { configureActions } from '../../';
import { configureActions } from '../..';
describe('Configure Actions', () => {
it('can configure actions', () => {

View File

@ -1,6 +1,6 @@
import addons from '@storybook/addons';
import uuid from 'uuid/v1';
import { action } from '../';
import { action } from '..';
import { undefinedType, symbolType } from '../../lib/types';
jest.mock('uuid/v1');

View File

@ -1,6 +1,6 @@
import uuid from 'uuid/v1';
import addons from '@storybook/addons';
import { EVENT_ID } from '../';
import { EVENT_ID } from '../constants';
import { canConfigureName, prepareArguments } from '../lib/util';
import { config } from './configureActions';

View File

@ -1,14 +1,5 @@
# Storybook Addon Backgrounds
[![Build Status on CircleCI](https://circleci.com/gh/storybooks/storybook.svg?style=shield)](https://circleci.com/gh/storybooks/storybook)
[![CodeFactor](https://www.codefactor.io/repository/github/storybooks/storybook/badge)](https://www.codefactor.io/repository/github/storybooks/storybook)
[![Known Vulnerabilities](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847/badge.svg)](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
---
Storybook Background Addon can be used to change background colors inside the preview in [Storybook](https://storybook.js.org).
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-backgrounds",
"version": "4.0.0-alpha.14",
"version": "4.0.0-alpha.16",
"description": "A storybook addon to show different backgrounds for your preview",
"keywords": [
"addon",
@ -24,15 +24,15 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-alpha.14",
"@storybook/core-events": "4.0.0-alpha.14",
"@storybook/addons": "4.0.0-alpha.16",
"@storybook/core-events": "4.0.0-alpha.16",
"global": "^4.3.2",
"prop-types": "^15.6.1",
"react-emotion": "^9.1.3",
"prop-types": "^15.6.2",
"react-emotion": "^9.2.6",
"util-deprecate": "^1.0.2"
},
"devDependencies": {
"vue": "^2.5.16"
"vue": "^2.5.17"
},
"peerDependencies": {
"react": "*"

View File

@ -1,11 +1,10 @@
import { document } from 'global';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import addons from '@storybook/addons';
import styled from 'react-emotion';
import Events from './events';
import Events from './constants';
import Swatch from './Swatch';
const Wrapper = styled('div')({
@ -76,19 +75,11 @@ export default class BackgroundPanel extends Component {
constructor(props) {
super(props);
const { channel } = props;
// A channel is explicitly passed in for testing
if (channel) {
this.channel = channel;
} else {
this.channel = addons.getChannel();
}
this.state = { backgrounds: [] };
}
componentDidMount() {
const { api, channel } = this.props;
this.iframe = document.getElementById(storybookIframe);
if (!this.iframe) {
@ -99,29 +90,33 @@ export default class BackgroundPanel extends Component {
this.iframe.style[prop] = style.iframe[prop];
});
const { api } = this.props;
channel.on(Events.SET, data => {
const backgrounds = [...data];
this.channel.on(Events.SET, backgrounds => {
this.setState({ backgrounds });
const currentBackground = api.getQueryParam('background');
const current = api.getQueryParam('background');
const defaultOrFirst = backgrounds.find(x => x.default) || backgrounds[0];
if (currentBackground && backgrounds.some(bg => bg.value === currentBackground)) {
this.updateIframe(currentBackground);
} else if (backgrounds.filter(x => x.default).length) {
const defaultBgs = backgrounds.filter(x => x.default);
this.updateIframe(defaultBgs[0].value);
// debugger;
if (current && backgrounds.find(bg => bg.value === current)) {
this.updateIframe(current);
} else if (defaultOrFirst) {
this.updateIframe(defaultOrFirst.value);
api.setQueryParams({ background: defaultOrFirst.value });
}
});
this.channel.on(Events.UNSET, () => {
channel.on(Events.UNSET, () => {
this.setState({ backgrounds: [] });
this.updateIframe('none');
});
}
setBackgroundFromSwatch = background => {
const { api } = this.props;
this.updateIframe(background);
this.props.api.setQueryParams({ background });
api.setQueryParams({ background });
};
updateIframe(background) {
@ -130,7 +125,8 @@ export default class BackgroundPanel extends Component {
render() {
const { active } = this.props;
const backgrounds = [...this.state.backgrounds];
const { backgrounds = [] } = this.state;
if (!active) {
return null;
}

View File

@ -3,10 +3,10 @@ import { shallow, mount } from 'enzyme';
import EventEmitter from 'events';
import BackgroundPanel from '../BackgroundPanel';
import Events from '../events';
import Events from '../constants';
const backgrounds = [
{ name: 'black', value: '#000000' },
{ name: 'black', value: '#000000', default: true },
{ name: 'secondary', value: 'rgb(123,123,123)' },
{ name: 'tertiary', value: 'rgba(123,123,123,.5)' },
{ name: 'An image', value: 'url(http://placehold.it/350x150)' },

View File

@ -0,0 +1,7 @@
export const ADDON_ID = 'storybook-addon-background';
export const PANEL_ID = `${ADDON_ID}/background-panel`;
export default {
SET: `${ADDON_ID}:set`,
UNSET: `${ADDON_ID}:unset`,
};

View File

@ -1,6 +0,0 @@
const ADDON_ID = 'backgrounds';
export default {
SET: `${ADDON_ID}:set`,
UNSET: `${ADDON_ID}:unset`,
};

View File

@ -2,7 +2,7 @@ import addons, { makeDecorator } from '@storybook/addons';
import CoreEvents from '@storybook/core-events';
import deprecate from 'util-deprecate';
import Events from './events';
import Events from './constants';
let prevBackgrounds;
@ -12,12 +12,13 @@ const subscription = () => () => {
};
export const withBackgrounds = makeDecorator({
name: 'backgrounds',
name: 'withBackgrounds',
parameterName: 'backgrounds',
skipIfNoParametersOrOptions: true,
allowDeprecatedUsage: true,
wrapper: (getStory, context, { options, parameters }) => {
const backgrounds = parameters || options;
const data = parameters || options || [];
const backgrounds = Array.isArray(data) ? data : Object.values(data);
if (backgrounds.length === 0) {
return getStory(context);

View File

@ -1,11 +1,9 @@
import React from 'react';
import addons from '@storybook/addons';
import { ADDON_ID, PANEL_ID } from './constants';
import BackgroundPanel from './BackgroundPanel';
const ADDON_ID = 'storybook-addon-background';
const PANEL_ID = `${ADDON_ID}/background-panel`;
addons.register(ADDON_ID, api => {
const channel = addons.getChannel();
addons.addPanel(PANEL_ID, {

View File

@ -1,14 +1,5 @@
# Storybook Centered Decorator
[![Build Status on CircleCI](https://circleci.com/gh/storybooks/storybook.svg?style=shield)](https://circleci.com/gh/storybooks/storybook)
[![CodeFactor](https://www.codefactor.io/repository/github/storybooks/storybook/badge)](https://www.codefactor.io/repository/github/storybooks/storybook)
[![Known Vulnerabilities](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847/badge.svg)](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
* * *
Storybook Centered Decorator can be used to center components inside the preview in [Storybook](https://storybook.js.org).
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
@ -56,6 +47,25 @@ storiesOf('MyComponent', module)
}));
```
example for Svelte:
```js
import { storiesOf } from '@storybook/svelte';
import Centered from '@storybook/addon-centered/svelte';
import Component from '../Component.svelte';
storiesOf('Addon|Centered', module)
.addDecorator(Centered)
.add('rounded', () => ({
Component,
data: {
rounded: true,
text: "Look, I'm centered!",
},
}))
```
example for Mithril:
```js
@ -105,7 +115,7 @@ storiesOf('Addon|Centered', module)
)
.addDecorator(centered)
.add('centered template', () => ({
template: `<storybook-button-component
template: `<storybook-button-component
[text]="text" (onClick)="onClick($event)">
</storybook-button-component>`,
props: {
@ -146,6 +156,19 @@ configure(function () {
}, module);
```
example for Svelte:
```js
import { configure, addDecorator } from '@storybook/svelte';
import Centered from '@storybook/addon-centered/svelte';
addDecorator(Centered);
configure(function () {
//...
}, module);
```
example for Mithril:
```js

View File

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

View File

@ -0,0 +1,16 @@
<div class="svelte-centered-wrapper" style="{style}">
<div class="svelte-centered-container" style="{innerStyle}">
<slot></slot>
</div>
</div>
<script>
export default {
data() {
return {
style: '',
innerStyle: ''
};
}
};
</script>

View File

@ -0,0 +1,21 @@
import { document } from 'global';
/**
* Not all frameworks support an object for the style attribute but we want all to
* consume `styles.json`. Since `styles.json` uses standard style properties for keys,
* we can just set them on an element and then get the string result of that element's
* `style` attribute. This also means that invalid styles are filtered out.
*
* @param {Object} jsonStyles
* @returns {string}
* @see https://stackoverflow.com/questions/38533544/jsx-css-to-inline-styles
*/
export default function jsonToCss(jsonStyles) {
const frag = document.createElement('div');
Object.keys(jsonStyles).forEach(key => {
frag.style[key] = jsonStyles[key];
});
return frag.getAttribute('style');
}

View File

@ -0,0 +1,25 @@
import Centered from './components/Centered.svelte';
import styles from './styles';
import json2CSS from './helpers/json2CSS';
const centeredStyles = {
/** @type {string} */
style: json2CSS(styles.style),
/** @type {string} */
innerStyle: json2CSS(styles.innerStyle),
};
/**
* This functionality works by passing the svelte story component into another
* svelte component that has the single purpose of centering the story component
* using a wrapper and container.
*
* We use the special element <svelte:component /> to achieve this.
*
* @see https://svelte.technology/guide#svelte-component
*/
export default function(storyFn) {
const { Component: OriginalComponent, data, on } = storyFn();
return { Component: OriginalComponent, data, on, Wrapper: Centered, WrapperData: centeredStyles };
}

View File

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

View File

@ -1,14 +1,5 @@
# Storybook Addon Events
[![Build Status on CircleCI](https://circleci.com/gh/storybooks/storybook.svg?style=shield)](https://circleci.com/gh/storybooks/storybook)
[![CodeFactor](https://www.codefactor.io/repository/github/storybooks/storybook/badge)](https://www.codefactor.io/repository/github/storybooks/storybook)
[![Known Vulnerabilities](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847/badge.svg)](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
* * *
This [storybook](https://storybooks.js.org) ([source](https://github.com/storybooks/storybook)) addon allows you to add events for your stories.
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-events",
"version": "4.0.0-alpha.14",
"version": "4.0.0-alpha.16",
"description": "Add events to your Storybook stories.",
"keywords": [
"addon",
@ -19,13 +19,13 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-alpha.14",
"@storybook/core-events": "4.0.0-alpha.14",
"@storybook/addons": "4.0.0-alpha.16",
"@storybook/core-events": "4.0.0-alpha.16",
"format-json": "^1.0.3",
"prop-types": "^15.6.1",
"react-emotion": "^9.1.3",
"prop-types": "^15.6.2",
"react-emotion": "^9.2.6",
"react-lifecycles-compat": "^3.0.4",
"react-textarea-autosize": "^6.1.0",
"react-textarea-autosize": "^7.0.4",
"util-deprecate": "^1.0.2"
},
"peerDependencies": {

View File

@ -101,20 +101,6 @@ class Item extends Component {
isTextAreaShowed: false,
};
static getDerivedStateFromProps = ({ payload }, { prevPayload }) => {
if (payload !== prevPayload) {
const payloadString = json.plain(payload);
return {
failed: false,
payload: getJSONFromString(payloadString),
payloadString,
prevPayload,
};
}
return null;
};
onChange = ({ target: { value } }) => {
const newState = {
payloadString: value,
@ -131,9 +117,12 @@ class Item extends Component {
};
onEmitClick = () => {
this.props.onEmit({
name: this.props.name,
payload: this.state.payload,
const { onEmit, name } = this.props;
const { payload } = this.state;
onEmit({
name,
payload,
});
};
@ -143,9 +132,23 @@ class Item extends Component {
}));
};
static getDerivedStateFromProps = ({ payload }, { prevPayload }) => {
if (payload !== prevPayload) {
const payloadString = json.plain(payload);
return {
failed: false,
payload: getJSONFromString(payloadString),
payloadString,
prevPayload,
};
}
return null;
};
render() {
const { title, name } = this.props;
const { failed, isTextAreaShowed } = this.state;
const { failed, isTextAreaShowed, payloadString } = this.state;
return (
<Wrapper>
@ -158,7 +161,7 @@ class Item extends Component {
<StyledTextarea
shown={isTextAreaShowed}
failed={failed}
value={this.state.payloadString}
value={payloadString}
onChange={this.onChange}
/>
{isTextAreaShowed ? (

View File

@ -28,11 +28,15 @@ export default class Events extends Component {
};
componentDidMount() {
this.props.channel.on(EVENTS.ADD, this.onAdd);
const { channel } = this.props;
channel.on(EVENTS.ADD, this.onAdd);
}
componentWillUnmount() {
this.props.channel.removeListener(EVENTS.ADD, this.onAdd);
const { channel } = this.props;
channel.removeListener(EVENTS.ADD, this.onAdd);
}
onAdd = events => {
@ -40,7 +44,9 @@ export default class Events extends Component {
};
onEmit = event => {
this.props.channel.emit(EVENTS.EMIT, event);
const { channel } = this.props;
channel.emit(EVENTS.EMIT, event);
};
render() {
@ -48,7 +54,9 @@ export default class Events extends Component {
const { active } = this.props;
return active ? (
<Wrapper>
{events.map(event => <Event key={event.name} {...event} onEmit={this.onEmit} />)}
{events.map(event => (
<Event key={event.name} {...event} onEmit={this.onEmit} />
))}
</Wrapper>
) : null;
}

View File

@ -1,14 +1,5 @@
# Storybook GraphiQL Addon
[![Build Status on CircleCI](https://circleci.com/gh/storybooks/storybook.svg?style=shield)](https://circleci.com/gh/storybooks/storybook)
[![CodeFactor](https://www.codefactor.io/repository/github/storybooks/storybook/badge)](https://www.codefactor.io/repository/github/storybooks/storybook)
[![Known Vulnerabilities](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847/badge.svg)](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
* * *
Storybook GraphQL Addon can be used to display the GraphiQL IDE with example queries in [Storybook](https://storybook.js.org).
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-graphql",
"version": "4.0.0-alpha.14",
"version": "4.0.0-alpha.16",
"description": "Storybook addon to display the GraphiQL IDE",
"keywords": [
"storybook"
@ -23,7 +23,7 @@
"global": "^4.3.2",
"graphiql": "^0.11.11",
"graphql": "^0.13.2",
"prop-types": "^15.6.1"
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": "*"

View File

@ -2,8 +2,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import style from './style';
export default function FullScreen(props) {
return <div style={style.wrapper}>{props.children}</div>;
export default function FullScreen({ children }) {
return <div style={style.wrapper}>{children}</div>;
}
FullScreen.defaultProps = { children: null };

View File

@ -1,14 +1,5 @@
# Storybook Info Addon
[![Build Status on CircleCI](https://circleci.com/gh/storybooks/storybook.svg?style=shield)](https://circleci.com/gh/storybooks/storybook)
[![CodeFactor](https://www.codefactor.io/repository/github/storybooks/storybook/badge)](https://www.codefactor.io/repository/github/storybooks/storybook)
[![Known Vulnerabilities](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847/badge.svg)](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
---
Storybook Info Addon will show additional information for your stories in [Storybook](https://storybook.js.org).
Useful when you want to display usage or other types of documentation alongside your story.

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-info",
"version": "4.0.0-alpha.14",
"version": "4.0.0-alpha.16",
"description": "A Storybook addon to show additional information for your stories.",
"repository": {
"type": "git",
@ -13,21 +13,21 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-alpha.14",
"@storybook/client-logger": "4.0.0-alpha.14",
"@storybook/components": "4.0.0-alpha.14",
"@storybook/addons": "4.0.0-alpha.16",
"@storybook/client-logger": "4.0.0-alpha.16",
"@storybook/components": "4.0.0-alpha.16",
"core-js": "2.5.7",
"global": "^4.3.2",
"marksy": "^6.0.3",
"nested-object-assign": "^1.0.1",
"prop-types": "^15.6.1",
"prop-types": "^15.6.2",
"react-addons-create-fragment": "^15.5.3",
"react-emotion": "^9.1.3",
"react-emotion": "^9.2.6",
"react-lifecycles-compat": "^3.0.4",
"util-deprecate": "^1.0.2"
},
"devDependencies": {
"react-test-renderer": "^16.4.0"
"react-test-renderer": "^16.4.2"
},
"peerDependencies": {
"react": "*"

View File

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`addon Info should render <Info /> and external markdown 1`] = `
.emotion-4 {
.emotion-2 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -22,7 +22,7 @@ exports[`addon Info should render <Info /> and external markdown 1`] = `
overflow-x: scroll;
}
.emotion-2 {
.emotion-1 {
overflow: hidden;
border: 1px solid #eee;
border-radius: 3px;
@ -38,12 +38,12 @@ exports[`addon Info should render <Info /> and external markdown 1`] = `
flex-shrink: 0;
}
.emotion-2:hover {
.emotion-1:hover {
background-color: #f4f7fa;
border-color: #ddd;
}
.emotion-2:active {
.emotion-1:active {
background-color: #e9ecef;
border-color: #ccc;
}
@ -124,8 +124,8 @@ exports[`addon Info should render <Info /> and external markdown 1`] = `
<div>
<h1>
function func(x) {
return x + 1;
}
return x + 1;
}
</h1>
<h2>
[object Object]
@ -307,7 +307,7 @@ exports[`addon Info should render <Info /> and external markdown 1`] = `
>
<Styled(pre)>
<pre
className="emotion-4 emotion-5"
className="emotion-2"
>
<div>
<Node
@ -1220,14 +1220,14 @@ exports[`addon Info should render <Info /> and external markdown 1`] = `
styles={Object {}}
>
<button
className="emotion-2 emotion-3"
className="emotion-1"
onClick={[Function]}
>
<Styled(div)
toggled={false}
>
<div
className="emotion-0 emotion-1"
className="emotion-0"
>
<div
style={
@ -1250,55 +1250,6 @@ exports[`addon Info should render <Info /> and external markdown 1`] = `
</Styled(pre)>
</Pre>
</div>
<div>
<h1
style={
Object {
"borderBottom": "1px solid #EEE",
"fontSize": "25px",
"margin": "20px 0 0 0",
"padding": "0 0 5px 0",
}
}
>
Prop Types
</h1>
<div
key="TestComponent_0"
>
<h2
style={
Object {
"margin": "20px 0 0 0",
}
}
>
"
TestComponent
" Component
</h2>
<Component
excludedPropTypes={Array []}
maxPropArrayLength={3}
maxPropObjectKeys={3}
maxPropStringLength={50}
type={[Function]}
>
<PropTable
excludedPropTypes={Array []}
maxPropArrayLength={3}
maxPropObjectKeys={3}
maxPropStringLength={50}
propDefinitions={Array []}
type={[Function]}
>
<small>
No propTypes defined!
</small>
</PropTable>
</Component>
</div>
</div>
</div>
</div>
</div>
@ -1308,7 +1259,7 @@ exports[`addon Info should render <Info /> and external markdown 1`] = `
`;
exports[`addon Info should render <Info /> and markdown 1`] = `
.emotion-4 {
.emotion-2 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -1329,7 +1280,7 @@ exports[`addon Info should render <Info /> and markdown 1`] = `
overflow-x: scroll;
}
.emotion-2 {
.emotion-1 {
overflow: hidden;
border: 1px solid #eee;
border-radius: 3px;
@ -1345,12 +1296,12 @@ exports[`addon Info should render <Info /> and markdown 1`] = `
flex-shrink: 0;
}
.emotion-2:hover {
.emotion-1:hover {
background-color: #f4f7fa;
border-color: #ddd;
}
.emotion-2:active {
.emotion-1:active {
background-color: #e9ecef;
border-color: #ccc;
}
@ -1433,8 +1384,8 @@ containing **bold**, *cursive* text, \`code\` and [a link](https://github.com)"
<div>
<h1>
function func(x) {
return x + 1;
}
return x + 1;
}
</h1>
<h2>
[object Object]
@ -1707,7 +1658,7 @@ containing **bold**, *cursive* text, \`code\` and [a link](https://github.com)"
>
<Styled(pre)>
<pre
className="emotion-4 emotion-5"
className="emotion-2"
>
<div>
<Node
@ -2620,14 +2571,14 @@ containing **bold**, *cursive* text, \`code\` and [a link](https://github.com)"
styles={Object {}}
>
<button
className="emotion-2 emotion-3"
className="emotion-1"
onClick={[Function]}
>
<Styled(div)
toggled={false}
>
<div
className="emotion-0 emotion-1"
className="emotion-0"
>
<div
style={
@ -2650,55 +2601,6 @@ containing **bold**, *cursive* text, \`code\` and [a link](https://github.com)"
</Styled(pre)>
</Pre>
</div>
<div>
<h1
style={
Object {
"borderBottom": "1px solid #EEE",
"fontSize": "25px",
"margin": "20px 0 0 0",
"padding": "0 0 5px 0",
}
}
>
Prop Types
</h1>
<div
key="TestComponent_0"
>
<h2
style={
Object {
"margin": "20px 0 0 0",
}
}
>
"
TestComponent
" Component
</h2>
<Component
excludedPropTypes={Array []}
maxPropArrayLength={3}
maxPropObjectKeys={3}
maxPropStringLength={50}
type={[Function]}
>
<PropTable
excludedPropTypes={Array []}
maxPropArrayLength={3}
maxPropObjectKeys={3}
maxPropStringLength={50}
propDefinitions={Array []}
type={[Function]}
>
<small>
No propTypes defined!
</small>
</PropTable>
</Component>
</div>
</div>
</div>
</div>
</div>

View File

@ -76,7 +76,10 @@ export default function Node(props) {
if (!children) {
return (
<div style={containerStyleCopy}>
<span style={tagStyle}>&lt;{name}</span>
<span style={tagStyle}>
&lt;
{name}
</span>
<Props
node={node}
singleLine
@ -94,7 +97,10 @@ export default function Node(props) {
return (
<div>
<div style={containerStyleCopy}>
<span style={tagStyle}>&lt;{name}</span>
<span style={tagStyle}>
&lt;
{name}
</span>
<Props
node={node}
maxPropsIntoLine={maxPropsIntoLine}
@ -115,7 +121,11 @@ export default function Node(props) {
/>
))}
<div style={containerStyleCopy}>
<span style={tagStyle}>&lt;/{name}&gt;</span>
<span style={tagStyle}>
&lt;/
{name}
&gt;
</span>
</div>
</div>
);

View File

@ -9,9 +9,16 @@ const stylesheet = {
};
export default function Props(props) {
const { maxPropsIntoLine, maxPropArrayLength, maxPropObjectKeys, maxPropStringLength } = props;
const nodeProps = props.node.props;
const { defaultProps } = props.node.type;
const {
maxPropsIntoLine,
maxPropArrayLength,
maxPropObjectKeys,
maxPropStringLength,
node,
singleLine,
} = props;
const nodeProps = node.props;
const { defaultProps } = node.type;
if (!nodeProps || typeof nodeProps !== 'object') {
return <span />;
}
@ -26,7 +33,7 @@ export default function Props(props) {
);
const breakIntoNewLines = names.length > maxPropsIntoLine;
const endingSpace = props.singleLine ? ' ' : '';
const endingSpace = singleLine ? ' ' : '';
const items = [];
names.forEach((name, i) => {
@ -34,7 +41,8 @@ export default function Props(props) {
<span key={name}>
{breakIntoNewLines ? (
<span>
<br />&nbsp;&nbsp;
<br />
&nbsp;&nbsp;
</span>
) : (
' '

View File

@ -1,6 +1,6 @@
/* eslint no-underscore-dangle: 0 */
import React, { createElement } from 'react';
import React, { Component, createElement } from 'react';
import { polyfill } from 'react-lifecycles-compat';
import PropTypes from 'prop-types';
import global from 'global';
@ -16,7 +16,7 @@ const { STORYBOOK_REACT_CLASSES } = global;
const getName = type => type.displayName || type.name;
const stylesheet = {
const stylesheetBase = {
button: {
base: {
fontFamily: 'sans-serif',
@ -101,29 +101,34 @@ const stylesheet = {
},
};
class Story extends React.Component {
constructor(...args) {
super(...args);
class Story extends Component {
constructor(props, ...args) {
super(props, ...args);
this.state = {
open: false,
};
this.marksy = marksy({
createElement,
elements: this.props.components,
elements: props.components,
});
}
_renderStory() {
return <div style={this.state.stylesheet.infoStory}>{this.props.children}</div>;
const { stylesheet } = this.state;
const { children } = this.props;
return <div style={stylesheet.infoStory}>{children}</div>;
}
_renderInline() {
const { stylesheet } = this.state;
return (
<div>
{this._renderInlineHeader()}
{this._renderStory()}
<div style={this.state.stylesheet.infoPage}>
<div style={this.state.stylesheet.infoBody}>
<div style={stylesheet.infoPage}>
<div style={stylesheet.infoBody}>
{this._getInfoContent()}
{this._getComponentDescription()}
{this._getSourceCode()}
@ -135,25 +140,30 @@ class Story extends React.Component {
}
_renderInlineHeader() {
const { stylesheet } = this.state;
const infoHeader = this._getInfoHeader();
return (
infoHeader && (
<div style={this.state.stylesheet.infoPage}>
<div style={this.state.stylesheet.infoBody}>{infoHeader}</div>
<div style={stylesheet.infoPage}>
<div style={stylesheet.infoBody}>{infoHeader}</div>
</div>
)
);
}
_renderOverlay() {
const { stylesheet, open } = this.state;
const { children } = this.props;
const buttonStyle = {
...this.state.stylesheet.button.base,
...this.state.stylesheet.button.topRight,
...stylesheet.button.base,
...stylesheet.button.topRight,
};
const infoStyle = Object.assign({}, this.state.stylesheet.info);
if (!this.state.open) {
const infoStyle = Object.assign({}, stylesheet.info);
if (!open) {
infoStyle.display = 'none';
}
@ -169,7 +179,7 @@ class Story extends React.Component {
return (
<div>
<div style={this.state.stylesheet.children}>{this.props.children}</div>
<div style={stylesheet.children}>{children}</div>
<button type="button" style={buttonStyle} onClick={openOverlay}>
Show Info
</button>
@ -177,8 +187,8 @@ class Story extends React.Component {
<button type="button" style={buttonStyle} onClick={closeOverlay}>
×
</button>
<div style={this.state.stylesheet.infoPage}>
<div style={this.state.stylesheet.infoBody}>
<div style={stylesheet.infoPage}>
<div style={stylesheet.infoBody}>
{this._getInfoHeader()}
{this._getInfoContent()}
{this._getComponentDescription()}
@ -192,38 +202,36 @@ class Story extends React.Component {
}
_getInfoHeader() {
if (!this.props.context || !this.props.showHeader) {
const { stylesheet } = this.state;
const { context, showHeader } = this.props;
if (!context || !showHeader) {
return null;
}
return (
<div style={this.state.stylesheet.header.body}>
<h1 style={this.state.stylesheet.header.h1}>{this.props.context.kind}</h1>
<h2 style={this.state.stylesheet.header.h2}>{this.props.context.story}</h2>
<div style={stylesheet.header.body}>
<h1 style={stylesheet.header.h1}>{context.kind}</h1>
<h2 style={stylesheet.header.h2}>{context.story}</h2>
</div>
);
}
_getInfoContent() {
if (!this.props.info) {
const { info, showInline } = this.props;
const { stylesheet } = this.state;
if (!info) {
return '';
}
if (React.isValidElement(this.props.info)) {
if (React.isValidElement(info)) {
return (
<div
style={
this.props.showInline
? this.state.stylesheet.jsxInfoContent
: this.state.stylesheet.infoContent
}
>
{this.props.info}
</div>
<div style={showInline ? stylesheet.jsxInfoContent : stylesheet.infoContent}>{info}</div>
);
}
const lines = this.props.info.split('\n');
const lines = info.split('\n');
while (lines[0].trim() === '') {
lines.shift();
}
@ -233,15 +241,16 @@ class Story extends React.Component {
padding = matches[0].length;
}
const source = lines.map(s => s.slice(padding)).join('\n');
return <div style={this.state.stylesheet.infoContent}>{this.marksy(source).tree}</div>;
return <div style={stylesheet.infoContent}>{this.marksy(source).tree}</div>;
}
_getComponentDescription() {
const { context } = this.props;
let retDiv = null;
if (Object.keys(STORYBOOK_REACT_CLASSES).length) {
Object.keys(STORYBOOK_REACT_CLASSES).forEach(key => {
if (STORYBOOK_REACT_CLASSES[key].name === this.props.context.story) {
if (STORYBOOK_REACT_CLASSES[key].name === context.story) {
retDiv = <div>{STORYBOOK_REACT_CLASSES[key].docgenInfo.description}</div>;
}
});
@ -251,22 +260,25 @@ class Story extends React.Component {
}
_getSourceCode() {
if (!this.props.showSource) {
return null;
}
const {
showSource,
maxPropsIntoLine,
maxPropObjectKeys,
maxPropArrayLength,
maxPropStringLength,
children,
} = this.props;
const { stylesheet } = this.state;
if (!showSource) {
return null;
}
return (
<div>
<h1 style={this.state.stylesheet.source.h1}>Story Source</h1>
<h1 style={stylesheet.source.h1}>Story Source</h1>
<Pre>
{React.Children.map(this.props.children, (root, idx) => (
{React.Children.map(children, (root, idx) => (
<Node
key={idx}
node={root}
@ -283,63 +295,67 @@ class Story extends React.Component {
}
_getPropTables() {
const types = new Map();
if (this.props.propTables === null) {
return null;
}
if (!this.props.children) {
return null;
}
if (this.props.propTables) {
this.props.propTables.forEach(type => {
types.set(type, true);
});
}
// depth-first traverse and collect types
const extract = children => {
if (!children) {
return;
}
if (Array.isArray(children)) {
children.forEach(extract);
return;
}
if (children.props && children.props.children) {
extract(children.props.children);
}
if (
typeof children === 'string' ||
typeof children.type === 'string' ||
(Array.isArray(this.props.propTablesExclude) && // also ignore excluded types
~this.props.propTablesExclude.indexOf(children.type)) // eslint-disable-line no-bitwise
) {
return;
}
if (children.type && !types.has(children.type)) {
types.set(children.type, true);
}
};
// extract components from children
extract(this.props.children);
const array = Array.from(types.keys());
array.sort((a, b) => getName(a) > getName(b));
const {
children,
propTablesExclude,
maxPropObjectKeys,
maxPropArrayLength,
maxPropStringLength,
excludedPropTypes,
} = this.props;
const propTables = array.map((type, i) => (
let { propTables } = this.props;
const { stylesheet } = this.state;
const types = new Map();
if (propTables === null) {
return null;
}
if (!children) {
return null;
}
if (propTables) {
propTables.forEach(type => {
types.set(type, true);
});
}
// depth-first traverse and collect types
const extract = innerChildren => {
if (!innerChildren) {
return;
}
if (Array.isArray(innerChildren)) {
innerChildren.forEach(extract);
return;
}
if (innerChildren.props && innerChildren.props.innerChildren) {
extract(innerChildren.props.innerChildren);
}
if (
typeof innerChildren === 'string' ||
typeof innerChildren.type === 'string' ||
(Array.isArray(propTablesExclude) && // also ignore excluded types
~propTablesExclude.indexOf(innerChildren.type)) // eslint-disable-line no-bitwise
) {
return;
}
if (innerChildren.type && !types.has(innerChildren.type)) {
types.set(innerChildren.type, true);
}
};
// extract components from children
extract(children);
const array = Array.from(types.keys());
array.sort((a, b) => getName(a) > getName(b));
propTables = array.map((type, i) => (
// eslint-disable-next-line react/no-array-index-key
<div key={`${getName(type)}_${i}`}>
<h2 style={this.state.stylesheet.propTableHead}>"{getName(type)}" Component</h2>
<h2 style={stylesheet.propTableHead}>"{getName(type)}" Component</h2>
<this.props.PropTable
type={type}
maxPropObjectKeys={maxPropObjectKeys}
@ -356,19 +372,20 @@ class Story extends React.Component {
return (
<div>
<h1 style={this.state.stylesheet.source.h1}>Prop Types</h1>
<h1 style={stylesheet.source.h1}>Prop Types</h1>
{propTables}
</div>
);
}
render() {
// <ThemeProvider theme={this.state.stylesheet}></ThemeProvider>
return this.props.showInline ? this._renderInline() : this._renderOverlay();
const { showInline } = this.props;
// <ThemeProvider theme={stylesheet}></ThemeProvider>
return showInline ? this._renderInline() : this._renderOverlay();
}
}
Story.getDerivedStateFromProps = ({ styles }) => ({ stylesheet: styles(stylesheet) });
Story.getDerivedStateFromProps = ({ styles }) => ({ stylesheet: styles(stylesheetBase) });
Story.displayName = 'Story';

View File

@ -67,10 +67,12 @@ const propsFromPropTypes = type => {
return;
}
// eslint-disable-next-line react/destructuring-assignment
if (!props[property]) {
props[property] = { property };
}
// eslint-disable-next-line react/destructuring-assignment
props[property].defaultValue = value;
});
}
@ -84,10 +86,12 @@ export default function makeTableComponent(Component) {
return null;
}
/* eslint-disable react/destructuring-assignment */
const propDefinitionsMap = hasDocgen(props.type)
? propsFromDocgen(props.type)
: propsFromPropTypes(props.type);
const propDefinitions = Object.values(propDefinitionsMap);
/* eslint-enable react/destructuring-assignment */
return <Component propDefinitions={propDefinitions} {...props} />;
};

View File

@ -18,6 +18,7 @@ export class Code extends React.Component {
}
render() {
const { language, code } = this.props;
const codeStyle = {
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
backgroundColor: '#fafafa',
@ -31,12 +32,12 @@ export class Code extends React.Component {
overflowX: 'scroll',
};
const className = this.props.language ? `language-${this.props.language}` : '';
const className = language ? `language-${language}` : '';
return (
<pre style={preStyle} className={className}>
<code style={codeStyle} className={className}>
{this.props.code}
{code}
</code>
</pre>
);
@ -52,14 +53,14 @@ Code.defaultProps = {
code: null,
};
export function Blockquote(props) {
export function Blockquote({ children }) {
const style = {
fontSize: '1.88em',
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
borderLeft: '8px solid #fafafa',
padding: '1rem',
};
return <blockquote style={style}>{props.children}</blockquote>;
return <blockquote style={style}>{children}</blockquote>;
}
Blockquote.propTypes = { children: PropTypes.node };

View File

@ -11,7 +11,7 @@ const propTypes = {
id: PropTypes.string,
};
export function H1(props) {
export function H1({ id, children }) {
const styles = {
...baseFonts,
borderBottom: '1px solid #eee',
@ -21,8 +21,8 @@ export function H1(props) {
fontSize: '40px',
};
return (
<h1 id={props.id} style={styles}>
{props.children}
<h1 id={id} style={styles}>
{children}
</h1>
);
}
@ -30,7 +30,7 @@ export function H1(props) {
H1.defaultProps = defaultProps;
H1.propTypes = propTypes;
export function H2(props) {
export function H2({ id, children }) {
const styles = {
...baseFonts,
fontWeight: 600,
@ -39,8 +39,8 @@ export function H2(props) {
fontSize: '30px',
};
return (
<h2 id={props.id} style={styles}>
{props.children}
<h2 id={id} style={styles}>
{children}
</h2>
);
}
@ -48,7 +48,7 @@ export function H2(props) {
H2.defaultProps = defaultProps;
H2.propTypes = propTypes;
export function H3(props) {
export function H3({ id, children }) {
const styles = {
...baseFonts,
fontWeight: 600,
@ -58,8 +58,8 @@ export function H3(props) {
textTransform: 'uppercase',
};
return (
<h3 id={props.id} style={styles}>
{props.children}
<h3 id={id} style={styles}>
{children}
</h3>
);
}
@ -67,7 +67,7 @@ export function H3(props) {
H3.defaultProps = defaultProps;
H3.propTypes = propTypes;
export function H4(props) {
export function H4({ id, children }) {
const styles = {
...baseFonts,
fontWeight: 600,
@ -76,8 +76,8 @@ export function H4(props) {
fontSize: '20px',
};
return (
<h4 id={props.id} style={styles}>
{props.children}
<h4 id={id} style={styles}>
{children}
</h4>
);
}
@ -85,7 +85,7 @@ export function H4(props) {
H4.defaultProps = defaultProps;
H4.propTypes = propTypes;
export function H5(props) {
export function H5({ id, children }) {
const styles = {
...baseFonts,
fontWeight: 600,
@ -94,8 +94,8 @@ export function H5(props) {
fontSize: '18px',
};
return (
<h5 id={props.id} style={styles}>
{props.children}
<h5 id={id} style={styles}>
{children}
</h5>
);
}
@ -103,7 +103,7 @@ export function H5(props) {
H5.defaultProps = defaultProps;
H5.propTypes = propTypes;
export function H6(props) {
export function H6({ id, children }) {
const styles = {
...baseFonts,
fontWeight: 400,
@ -112,8 +112,8 @@ export function H6(props) {
fontSize: '18px',
};
return (
<h6 id={props.id} style={styles}>
{props.children}
<h6 id={id} style={styles}>
{children}
</h6>
);
}

View File

@ -24,7 +24,7 @@ const Button = styled('button')(
borderColor: '#ccc',
},
},
props => props.styles
({ styles }) => styles
);
const ContentWrapper = styled('div')(
@ -32,19 +32,19 @@ const ContentWrapper = styled('div')(
transition: 'transform .2s ease',
height: 16,
},
props => ({
...props.styles,
transform: props.toggled ? 'translateY(0px)' : 'translateY(-100%) translateY(-6px)',
({ styles, toggled }) => ({
...styles,
transform: toggled ? 'translateY(0px)' : 'translateY(-100%) translateY(-6px)',
})
);
function CopyButton(props) {
const { copyButton = {}, copyButtonContent } = props.theme;
function CopyButton({ theme, onClick, toggled }) {
const { copyButton = {}, copyButtonContent } = theme;
const { toggleText = 'Copied!', text = 'Copy', ...copyButtonStyles } = copyButton;
return (
<Button onClick={props.onClick} styles={copyButtonStyles}>
<ContentWrapper styles={copyButtonContent} toggled={props.toggled}>
<Button onClick={onClick} styles={copyButtonStyles}>
<ContentWrapper styles={copyButtonContent} toggled={toggled}>
<div style={{ marginBottom: 6 }}>{toggleText}</div>
<div>{text}</div>
</ContentWrapper>

View File

@ -19,7 +19,7 @@ const StyledPre = styled('pre')(
lineHeight: 1.5,
overflowX: 'scroll',
},
props => props.styles
({ styles }) => styles
);
class Pre extends React.Component {
@ -49,12 +49,14 @@ class Pre extends React.Component {
};
render() {
const { pre } = this.props.theme;
const { theme, children } = this.props;
const { pre } = theme;
const { copied } = this.state;
return (
<StyledPre styles={pre}>
<div ref={this.setRef}>{this.props.children}</div>
<CopyButton onClick={this.handleClick} toggled={this.state.copied} />
<div ref={this.setRef}>{children}</div>
<CopyButton onClick={this.handleClick} toggled={copied} />
</StyledPre>
);
}

View File

@ -5,7 +5,7 @@ import { baseFonts } from '@storybook/components';
const defaultProps = { children: null };
const propTypes = { children: PropTypes.node };
export function P(props) {
export function P({ children }) {
const style = {
...baseFonts,
fontSize: '15px',
@ -15,41 +15,41 @@ export function P(props) {
// <a> and <pre> elements, which is why <div>
// is used as the outputted element when parsing
// marksy content rather than <p>.
return <div style={style}>{props.children}</div>;
return <div style={style}>{children}</div>;
}
P.defaultProps = defaultProps;
P.propTypes = propTypes;
export function LI(props) {
export function LI({ children }) {
const style = {
...baseFonts,
fontSize: '15px',
};
return <li style={style}>{props.children}</li>;
return <li style={style}>{children}</li>;
}
LI.defaultProps = defaultProps;
LI.propTypes = propTypes;
export function UL(props) {
export function UL({ children }) {
const style = {
...baseFonts,
fontSize: '15px',
};
return <ul style={style}>{props.children}</ul>;
return <ul style={style}>{children}</ul>;
}
UL.defaultProps = defaultProps;
UL.propTypes = propTypes;
export function A(props) {
export function A({ href, children }) {
const style = {
color: '#3498db',
};
return (
<a href={props.href} target="_blank" rel="noopener noreferrer" style={style}>
{props.children}
<a href={href} target="_blank" rel="noopener noreferrer" style={style}>
{children}
</a>
);
}

View File

@ -1,5 +1,6 @@
import React from 'react';
// eslint-disable-next-line import/no-cycle
import PrettyPropType from './PrettyPropType';
import { TypeInfo, getPropTypes } from './proptypes';

View File

@ -1,5 +1,6 @@
import React from 'react';
// eslint-disable-next-line import/no-cycle
import PrettyPropType from './PrettyPropType';
import { TypeInfo, getPropTypes } from './proptypes';

View File

@ -1,5 +1,6 @@
import React from 'react';
// eslint-disable-next-line import/no-cycle
import PrettyPropType from './PrettyPropType';
import { TypeInfo, getPropTypes } from './proptypes';

View File

@ -1,6 +1,8 @@
import PropTypes from 'prop-types';
import React from 'react';
// TODO: FIX this dependency cycle
/* eslint-disable import/no-cycle */
import Shape from './Shape';
import OneOfType from './OneOfType';
import ArrayOf from './ArrayOf';
@ -9,6 +11,7 @@ import OneOf from './OneOf';
import InstanceOf from './InstanceOf';
import Signature from './Signature';
import Literal from './Literal';
/* eslint-enable import/no-cycle */
import { TypeInfo } from './proptypes';

View File

@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import { HighlightButton } from '@storybook/components';
// eslint-disable-next-line import/no-cycle
import PrettyPropType from './PrettyPropType';
import PropertyLabel from './PropertyLabel';
@ -18,8 +19,9 @@ class Shape extends React.Component {
}
handleToggle = () => {
const { minimized } = this.state;
this.setState({
minimized: !this.state.minimized,
minimized: !minimized,
});
};
@ -33,34 +35,35 @@ class Shape extends React.Component {
render() {
const { propType, depth } = this.props;
const { hover, minimized } = this.state;
const propTypes = getPropTypes(propType);
return (
<span>
<HighlightButton
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
highlight={this.state.hover}
highlight={hover}
onClick={this.handleToggle}
>
{'{'}
</HighlightButton>
<HighlightButton onClick={this.handleToggle}>...</HighlightButton>
{!this.state.minimized &&
{!minimized &&
Object.keys(propTypes).map(childProperty => (
<div key={childProperty} style={{ marginLeft: depth * MARGIN_SIZE }}>
<PropertyLabel
property={childProperty}
required={propTypes[childProperty].required}
/>
<PrettyPropType depth={depth + 1} propType={propTypes[childProperty]} />
,
<PrettyPropType depth={depth + 1} propType={propTypes[childProperty]} />,
</div>
))}
<HighlightButton
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
highlight={this.state.hover}
highlight={hover}
onClick={this.handleToggle}
>
{'}'}

View File

@ -1,7 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import { withInfo, setDefaults } from './';
import { withInfo, setDefaults } from '.';
import externalMdDocs from '../README.md';
/* eslint-disable */
@ -30,9 +30,10 @@ const testMarkdown = `# Test story
containing **bold**, *cursive* text, \`code\` and [a link](https://github.com)`;
describe('addon Info', () => {
const story = context => (
// eslint-disable-next-line react/prop-types
const storyFn = ({ story }) => (
<div>
It's a {context.story} story:
It's a {story} story:
<TestComponent
func={x => x + 1}
obj={{ a: 'a', b: 'b' }}
@ -44,22 +45,22 @@ describe('addon Info', () => {
</div>
);
it('should render <Info /> and markdown', () => {
const Info = withInfo(testMarkdown)(story);
const Info = withInfo(testMarkdown)(storyFn);
expect(mount(<Info />)).toMatchSnapshot();
});
it('should render <Info /> and external markdown', () => {
const Info = withInfo(externalMdDocs)(story);
const Info = withInfo(externalMdDocs)(storyFn);
expect(mount(<Info />)).toMatchSnapshot();
});
it('should render with text options', () => {
const Info = withInfo({ text: 'some text here' })(story);
const Info = withInfo({ text: 'some text here' })(storyFn);
mount(<Info />);
});
it('should render with missed info', () => {
setDefaults(testOptions);
const Info = withInfo()(story);
const Info = withInfo()(storyFn);
mount(<Info />);
});
});

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-jest",
"version": "4.0.0-alpha.14",
"version": "4.0.0-alpha.16",
"description": "React storybook addon that show component jest report",
"keywords": [
"addon",
@ -25,11 +25,11 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-alpha.14",
"@storybook/components": "4.0.0-alpha.14",
"@storybook/addons": "4.0.0-alpha.16",
"@storybook/components": "4.0.0-alpha.16",
"global": "^4.3.2",
"prop-types": "^15.6.1",
"react-emotion": "^9.1.3",
"prop-types": "^15.6.2",
"react-emotion": "^9.2.6",
"util-deprecate": "^1.0.2"
},
"peerDependencies": {

View File

@ -45,7 +45,10 @@ const SuiteTotals = styled(({ successNumber, failedNumber, result, className })
{failedNumber > 0 && <div style={{ color: colors.error }}>{failedNumber} failed</div>}
<div>{result.assertionResults.length} total</div>
<div>
<strong>{result.endTime - result.startTime}ms</strong>
<strong>
{result.endTime - result.startTime}
ms
</strong>
</div>
</div>
))({

View File

@ -35,8 +35,10 @@ const StackTrace = styled(({ trace, className }) => (
.join('')
.trim()
.split(/\n/)
// eslint-disable-next-line react/no-array-index-key
.map((traceLine, traceLineIndex) => <div key={traceLineIndex}>{traceLine.trim()}</div>)}
.map((traceLine, traceLineIndex) => (
// eslint-disable-next-line react/no-array-index-key
<div key={traceLineIndex}>{traceLine.trim()}</div>
))}
</details>
))({
background: 'silver',
@ -217,7 +219,9 @@ export const FailedResult = styled(({ fullName, title, status, failureMessages,
</Indicator>
</Head>
{/* eslint-disable react/no-array-index-key */}
{failureMessages.map((msg, i) => <Message msg={msg} key={i} />)}
{failureMessages.map((msg, i) => (
<Message msg={msg} key={i} />
))}
</div>
))({
display: 'block',

View File

@ -13,6 +13,7 @@ const provideTests = Component =>
}).isRequired,
active: PropTypes.bool,
};
static defaultProps = {
active: true,
};
@ -30,10 +31,12 @@ const provideTests = Component =>
}
componentWillUnmount() {
const { channel } = this.props;
if (this.stopListeningOnStory) {
this.stopListeningOnStory();
}
this.props.channel.removeListener('storybook/tests/add_tests', this.onAddTests);
channel.removeListener('storybook/tests/add_tests', this.onAddTests);
}
onAddTests = ({ kind, storyName, tests }) => {

View File

@ -2,7 +2,7 @@ import addons from '@storybook/addons';
import deprecate from 'util-deprecate';
const findTestResults = (testFiles, jestTestResults, jestTestFilesExt) =>
Array.from(testFiles).map(name => {
Object.values(testFiles).map(name => {
if (jestTestResults && jestTestResults.testResults) {
return {
name,

View File

@ -1,14 +1,5 @@
# Storybook Addon Knobs
[![Build Status on CircleCI](https://circleci.com/gh/storybooks/storybook.svg?style=shield)](https://circleci.com/gh/storybooks/storybook)
[![CodeFactor](https://www.codefactor.io/repository/github/storybooks/storybook/badge)](https://www.codefactor.io/repository/github/storybooks/storybook)
[![Known Vulnerabilities](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847/badge.svg)](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
* * *
Storybook Addon Knobs allow you to edit React props dynamically using the Storybook UI.
You can also use Knobs as a dynamic variable inside stories in [Storybook](https://storybook.js.org).
@ -264,6 +255,23 @@ const value = select(label, options, defaultValue, groupId);
> You can also provide options as an array like this: `['red', 'blue', 'yellow']`
### radio buttons
Allows you to get a value from a list of radio buttons from the user.
```js
import { radios } from '@storybook/addon-knobs';
const options = {
Kiwi: 'kiwi',
Guava: 'guava',
Watermelon: 'watermelon',
};
const = radios(name, options, defaultValue);
```
### files
Allows you to get a value from a file input from the user.

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-knobs",
"version": "4.0.0-alpha.14",
"version": "4.0.0-alpha.16",
"description": "Storybook Addon Prop Editor Component",
"repository": {
"type": "git",
@ -13,23 +13,23 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-alpha.14",
"@storybook/components": "4.0.0-alpha.14",
"@storybook/core-events": "4.0.0-alpha.14",
"@storybook/addons": "4.0.0-alpha.16",
"@storybook/components": "4.0.0-alpha.16",
"@storybook/core-events": "4.0.0-alpha.16",
"copy-to-clipboard": "^3.0.8",
"escape-html": "^1.0.3",
"fast-deep-equal": "^2.0.1",
"global": "^4.3.2",
"prop-types": "^15.6.1",
"prop-types": "^15.6.2",
"qs": "^6.5.2",
"react-color": "^2.14.1",
"react-datetime": "^2.14.0",
"react-emotion": "^9.1.3",
"react-datetime": "^2.15.0",
"react-emotion": "^9.2.6",
"react-lifecycles-compat": "^3.0.4",
"util-deprecate": "^1.0.2"
},
"devDependencies": {
"vue": "^2.5.16"
"vue": "^2.5.17"
},
"peerDependencies": {
"react": "*"

View File

@ -27,18 +27,22 @@ export default class Panel extends PureComponent {
this.lastEdit = getTimestamp();
this.loadedFromUrl = false;
}
componentDidMount() {
this.props.channel.on('addon:knobs:setKnobs', this.setKnobs);
this.props.channel.on('addon:knobs:setOptions', this.setOptions);
this.stopListeningOnStory = this.props.api.onStory(() => {
componentDidMount() {
const { channel, api } = this.props;
channel.on('addon:knobs:setKnobs', this.setKnobs);
channel.on('addon:knobs:setOptions', this.setOptions);
this.stopListeningOnStory = api.onStory(() => {
this.setState({ knobs: {} });
this.props.channel.emit('addon:knobs:reset');
channel.emit('addon:knobs:reset');
});
}
componentWillUnmount() {
this.props.channel.removeListener('addon:knobs:setKnobs', this.setKnobs);
const { channel } = this.props;
channel.removeListener('addon:knobs:setKnobs', this.setKnobs);
this.stopListeningOnStory();
}
@ -75,7 +79,9 @@ export default class Panel extends PureComponent {
};
reset = () => {
this.props.channel.emit('addon:knobs:reset');
const { channel } = this.props;
channel.emit('addon:knobs:reset');
};
copy = () => {
@ -93,7 +99,9 @@ export default class Panel extends PureComponent {
};
emitChange = changedKnob => {
this.props.channel.emit('addon:knobs:knobChange', changedKnob);
const { channel } = this.props;
channel.emit('addon:knobs:knobChange', changedKnob);
};
handleChange = changedKnob => {
@ -110,7 +118,9 @@ export default class Panel extends PureComponent {
};
handleClick = knob => {
this.props.channel.emit('addon:knobs:knobClick', knob);
const { channel } = this.props;
channel.emit('addon:knobs:knobClick', knob);
};
render() {

View File

@ -15,14 +15,16 @@ const InvalidType = () => <span>Invalid Type</span>;
export default class PropForm extends Component {
makeChangeHandler(name, type) {
const { onFieldChange } = this.props;
return value => {
const change = { name, type, value };
this.props.onFieldChange(change);
onFieldChange(change);
};
}
render() {
const { knobs } = this.props;
const { knobs, onFieldClick } = this.props;
return (
<Form>
@ -32,7 +34,7 @@ export default class PropForm extends Component {
return (
<Field key={knob.name} label={!knob.hideLabel && `${knob.name}`}>
<InputType knob={knob} onChange={changeHandler} onClick={this.props.onFieldClick} />
<InputType knob={knob} onChange={changeHandler} onClick={onFieldClick} />
</Field>
);
})}

View File

@ -0,0 +1,44 @@
import React from 'react';
import { shallow } from 'enzyme';
import RadioType from '../types/Radio';
describe('Radio', () => {
let knob;
beforeEach(() => {
knob = {
name: 'Color',
value: '#319C16',
options: {
Green: '#319C16',
Red: '#FF2B2B',
},
};
});
describe('displays value of button input', () => {
it('correctly renders labels', () => {
const wrapper = shallow(<RadioType knob={knob} />);
const greenLabel = wrapper.find('label').first();
expect(greenLabel.text()).toEqual('Green');
});
it('sets value on the radio buttons', () => {
const wrapper = shallow(<RadioType knob={knob} />);
const greenInput = wrapper.find('input').first();
expect(greenInput.prop('value')).toEqual('#319C16');
});
it('marks the correct checkbox as checked', () => {
const wrapper = shallow(<RadioType knob={knob} />);
const greenInput = wrapper.find('input').first();
const redInput = wrapper.find('input').last();
expect(greenInput.prop('checked')).toEqual(true);
expect(redInput.prop('checked')).toEqual(false);
});
});
});

View File

@ -12,14 +12,17 @@ function formatArray(value, separator) {
class ArrayType extends React.Component {
shouldComponentUpdate(nextProps) {
return nextProps.knob.value !== this.props.knob.value;
const { knob } = this.props;
return nextProps.knob.value !== knob.value;
}
handleChange = e => {
const { knob } = this.props;
const { knob, onChange } = this.props;
const { value } = e.target;
const newVal = formatArray(value, knob.separator);
this.props.onChange(newVal);
onChange(newVal);
};
render() {

View File

@ -27,16 +27,22 @@ class ColorType extends React.Component {
componentDidMount() {
document.addEventListener('mousedown', this.handleWindowMouseDown);
}
shouldComponentUpdate(nextProps) {
return nextProps.knob.value !== this.props.knob.value;
const { knob } = this.props;
return nextProps.knob.value !== knob.value;
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleWindowMouseDown);
}
handleWindowMouseDown = e => {
if (!this.state.displayColorPicker) return;
if (this.popover.contains(e.target)) return;
const { displayColorPicker } = this.state;
if (!displayColorPicker || this.popover.contains(e.target)) {
return;
}
this.setState({
displayColorPicker: false,
@ -44,13 +50,17 @@ class ColorType extends React.Component {
};
handleClick = () => {
const { displayColorPicker } = this.state;
this.setState({
displayColorPicker: !this.state.displayColorPicker,
displayColorPicker: !displayColorPicker,
});
};
handleChange = color => {
this.props.onChange(`rgba(${color.rgb.r},${color.rgb.g},${color.rgb.b},${color.rgb.a})`);
const { onChange } = this.props;
onChange(`rgba(${color.rgb.r},${color.rgb.g},${color.rgb.b},${color.rgb.a})`);
};
render() {

View File

@ -10,12 +10,16 @@ const DateInput = styled(Datetime)(style);
class DateType extends React.Component {
shouldComponentUpdate(nextProps) {
return nextProps.knob.value !== this.props.knob.value;
const { knob } = this.props;
return nextProps.knob.value !== knob.value;
}
handleChange = date => {
const { onChange } = this.props;
const value = date.valueOf();
this.props.onChange(value);
onChange(value);
};
render() {

View File

@ -34,10 +34,13 @@ const RangeWrapper = styled('div')({
class NumberType extends React.Component {
shouldComponentUpdate(nextProps) {
return nextProps.knob.value !== this.props.knob.value;
const { knob } = this.props;
return nextProps.knob.value !== knob.value;
}
handleChange = event => {
const { onChange } = this.props;
const { value } = event.target;
let parsedValue = Number(value);
@ -46,7 +49,7 @@ class NumberType extends React.Component {
parsedValue = null;
}
this.props.onChange(parsedValue);
onChange(parsedValue);
};
render() {

View File

@ -22,6 +22,8 @@ class ObjectType extends Component {
handleChange = e => {
const { value } = e.target;
const { json: stateJson } = this.state;
const { knob, onChange } = this.props;
try {
const json = JSON.parse(value.trim());
@ -30,8 +32,8 @@ class ObjectType extends Component {
json,
failed: false,
});
if (deepEqual(this.props.knob.value, this.state.json)) {
this.props.onChange(json);
if (deepEqual(knob.value, stateJson)) {
onChange(json);
}
} catch (err) {
this.setState({

View File

@ -0,0 +1,71 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
const styles = {
label: {
fontSize: 11,
padding: '5px',
},
group: {
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
},
};
class RadiosType extends Component {
renderRadioButtonList({ options }) {
if (Array.isArray(options)) {
return options.map(val => this.renderRadioButton(val, val));
}
return Object.keys(options).map(key => this.renderRadioButton(key, options[key]));
}
renderRadioButton(label, value) {
const opts = { label, value };
const { onChange, knob } = this.props;
const { name } = knob;
const id = `${name}-${opts.value}`;
return (
<div key={id}>
<input
type="radio"
id={id}
name={name}
value={opts.value}
onChange={e => onChange(e.target.value)}
checked={value === knob.value}
/>
<label style={styles.label} htmlFor={id}>
{label}
</label>
</div>
);
}
render() {
const { knob } = this.props;
return <div style={styles.group}>{this.renderRadioButtonList(knob)}</div>;
}
}
RadiosType.defaultProps = {
knob: {},
onChange: value => value,
};
RadiosType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.string,
options: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
}),
onChange: PropTypes.func,
};
RadiosType.serialize = value => value;
RadiosType.deserialize = value => value;
export default RadiosType;

View File

@ -5,12 +5,16 @@ import { Textarea } from '@storybook/components';
class TextType extends React.Component {
shouldComponentUpdate(nextProps) {
return nextProps.knob.value !== this.props.knob.value;
const { knob } = this.props;
return nextProps.knob.value !== knob.value;
}
handleChange = event => {
const { onChange } = this.props;
const { value } = event.target;
this.props.onChange(value);
onChange(value);
};
render() {

View File

@ -4,6 +4,7 @@ import ColorType from './Color';
import BooleanType from './Boolean';
import ObjectType from './Object';
import SelectType from './Select';
import RadiosType from './Radio';
import ArrayType from './Array';
import DateType from './Date';
import ButtonType from './Button';
@ -16,6 +17,7 @@ export default {
boolean: BooleanType,
object: ObjectType,
select: SelectType,
radios: RadiosType,
array: ArrayType,
date: DateType,
button: ButtonType,

View File

@ -52,6 +52,10 @@ export function select(name, options, value, groupId) {
return manager.knob(name, { type: 'select', selectV2: true, options, value, groupId });
}
export function radios(name, options, value, groupId) {
return manager.knob(name, { type: 'radios', options, value, groupId });
}
export function array(name, value, separator = ',', groupId) {
return manager.knob(name, { type: 'array', value, separator, groupId });
}

View File

@ -1,14 +1,5 @@
# Story Links Addon
[![Build Status on CircleCI](https://circleci.com/gh/storybooks/storybook.svg?style=shield)](https://circleci.com/gh/storybooks/storybook)
[![CodeFactor](https://www.codefactor.io/repository/github/storybooks/storybook/badge)](https://www.codefactor.io/repository/github/storybooks/storybook)
[![Known Vulnerabilities](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847/badge.svg)](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook) [![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
* * *
The Storybook Links addon can be used to create links that navigate between stories in [Storybook](https://storybook.js.org).
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)

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