Merge remote-tracking branch 'storybooks' into addon-actions

This commit is contained in:
Rob Halff 2018-03-02 16:41:41 +00:00
commit a0d5fad45f
786 changed files with 18522 additions and 8512 deletions

View File

@ -1,6 +1,7 @@
{
"presets": ["env", "stage-0", "react"],
"plugins": [
"babel-plugin-macros",
["transform-runtime", {
"polyfill": false,
"regenerator": true

View File

@ -33,8 +33,11 @@ jobs:
key: core-dependencies-{{ checksum "yarn.lock" }}
paths:
- node_modules
- example/cra-kitchen-sink/node_modules
- example/vue-kitchen-sink/node_modules
- examples/angular-cli/node_modules
- examples/cra-kitchen-sink/node_modules
- examples/official-storybook/node_modules
- examples/polymer-cli/node_modules
- examples/vue-kitchen-sink/node_modules
- save_cache:
name: "Cache core dist"
key: core-dist-{{ .Revision }}
@ -54,10 +57,6 @@ jobs:
name: "Restore core dist cache"
keys:
- core-dist-{{ .Revision }}
- run:
name: "Link packages"
command: |
yarn install
- run:
name: "Build react kitchen-sink"
command: |
@ -73,34 +72,64 @@ jobs:
command: |
cd examples/angular-cli
yarn build-storybook
- run:
name: "Build polymer-cli"
command: |
cd examples/polymer-cli
yarn build-storybook
- run:
name: "Build official-storybook"
command: |
cd examples/official-storybook
yarn build-storybook
- run:
name: "Visually test storybook"
command: |
yarn chromatic
- run:
name: "Run image snapshots"
command: yarn test --image
- store_artifacts:
path: examples/official-storybook/image-snapshots/__image_snapshots__
destination: official_storybook_image_snapshots
smoke-tests:
<<: *defaults
steps:
- checkout
- restore_cache:
name: "Restore core dependencies cache"
keys:
- core-dependencies-{{ checksum "yarn.lock" }}
- restore_cache:
name: "Restore core dist cache"
keys:
- core-dist-{{ .Revision }}
- run:
name: "Run react kitchen-sink"
name: "Run react kitchen-sink (smoke test)"
command: |
cd examples/cra-kitchen-sink
yarn storybook
background: true
yarn storybook --smoke-test
- run:
name: "Run vue kitchen-sink"
name: "Run vue kitchen-sink (smoke test)"
command: |
cd examples/vue-kitchen-sink
yarn storybook
background: true
yarn storybook --smoke-test
- run:
name: "Run angular-cli"
name: "Run angular-cli (smoke test)"
command: |
cd examples/angular-cli
yarn storybook
background: true
yarn storybook --smoke-test
- run:
name: Workaround for https://github.com/GoogleChrome/puppeteer/issues/290
command: sh ./scripts/workaround-puppeteer-issue-290.sh
name: "Run polymer-cli (smoke test)"
command: |
cd examples/polymer-cli
yarn storybook --smoke-test
- run:
name: Integration Test - Kichen sinks
command: yarn test --integration
- store_artifacts:
path: integration/__image_snapshots__
destination: integration_image_snapshots
name: "Run official-storybook (smoke test)"
command: |
cd examples/official-storybook
yarn storybook --smoke-test
react-native:
<<: *defaults
steps:
@ -171,10 +200,6 @@ jobs:
name: "Restore core dist cache"
keys:
- core-dist-{{ .Revision }}
- run:
name: "Link packages"
command: |
yarn install
- run:
name: "Lint"
command: |
@ -191,35 +216,11 @@ jobs:
name: "Restore core dist cache"
keys:
- core-dist-{{ .Revision }}
- run:
name: "Link packages"
command: |
yarn install
- run:
name: "Run unit tests"
command: |
yarn test --coverage --runInBand --core
yarn coverage
storybook:
<<: *defaults
steps:
- checkout
- restore_cache:
name: "Restore core dependencies cache"
keys:
- core-dependencies-{{ checksum "yarn.lock" }}
- restore_cache:
name: "Restore core dist cache"
keys:
- core-dist-{{ .Revision }}
- run:
name: "Link packages"
command: |
yarn install
- run:
name: "Visually test storybook"
command: |
yarn chromatic
cli:
working_directory: /tmp/storybook
docker:
@ -275,19 +276,20 @@ workflows:
- example-kitchen-sinks:
requires:
- build
- smoke-tests:
requires:
- build
- react-native:
requires:
- build
- docs
- lint:
requires:
- docs
- build
- unit-test:
requires:
- build
- storybook:
requires:
- build
- cli:
requires:
- build

View File

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

View File

@ -2,8 +2,6 @@ dist
build
coverage
node_modules
addons/**/example/**
app/**/demo/**
docs/public
lib/cli/test
*.bundle.js
@ -13,3 +11,4 @@ lib/cli/test
!.eslintrc.js
!.eslintrc-markdown.js
!.jest.config.js
!.storybook

View File

@ -1,59 +0,0 @@
const error = 2;
const warn = 1;
const ignore = 0;
module.exports = {
root: true,
extends: ['eslint-config-airbnb', 'plugin:jest/recommended', 'prettier'],
plugins: ['prettier', 'jest', 'react'],
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module',
},
env: {
es6: true,
node: true,
'jest/globals': true,
},
globals: {
storiesOf: true,
addonAPI: true,
__DEV__: true,
fetch: true,
},
rules: {
strict: [error, 'never'],
'prettier/prettier': [
warn,
{
printWidth: 100,
tabWidth: 2,
bracketSpacing: true,
trailingComma: 'es5',
singleQuote: true,
},
],
'no-console': ignore,
'global-require': ignore,
quotes: [warn, 'single'],
'no-unused-vars': ignore,
'class-methods-use-this': ignore,
'arrow-parens': [warn, 'as-needed'],
'space-before-function-paren': ignore,
'import/no-unresolved': ignore,
'import/extensions': ignore,
'import/no-extraneous-dependencies': ignore,
'import/prefer-default-export': ignore,
'react/prop-types': ignore,
'react/jsx-wrap-multilines': ignore,
'react/jsx-uses-react': error,
'react/jsx-uses-vars': error,
'react/react-in-jsx-scope': ignore,
'react/jsx-filename-extension': ignore,
'jsx-a11y/accessible-emoji': ignore,
'jsx-a11y/href-no-hash': ignore,
'jsx-a11y/label-has-for': ignore,
'jsx-a11y/anchor-is-valid': ['warn', { aspects: ['invalidHref'] }],
'react/no-unescaped-entities': ignore,
},
};

View File

@ -4,8 +4,14 @@ const ignore = 0;
module.exports = {
root: true,
extends: ['eslint-config-airbnb', 'plugin:jest/recommended', 'prettier'],
plugins: ['prettier', 'jest', 'react', 'json'],
extends: [
'airbnb',
'plugin:jest/recommended',
'plugin:import/react-native',
'prettier',
'prettier/react',
],
plugins: ['prettier', 'jest', 'import', 'react', 'jsx-a11y', 'json'],
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module',
@ -18,9 +24,13 @@ module.exports = {
settings: {
'import/core-modules': ['enzyme'],
'import/ignore': ['node_modules\\/(?!@storybook)'],
'import/resolver': {
node: {
extensions: ['.js', '.ts'],
},
},
},
rules: {
strict: [error, 'never'],
'prettier/prettier': [
warn,
{
@ -32,16 +42,13 @@ module.exports = {
},
],
'no-debugger': process.env.NODE_ENV === 'production' ? error : ignore,
quotes: [warn, 'single', { avoidEscape: true }],
'class-methods-use-this': ignore,
'arrow-parens': [warn, 'as-needed'],
'space-before-function-paren': ignore,
'import/no-unresolved': error,
'import/extensions': [
error,
'always',
{
js: 'never',
json: 'always',
ts: 'never',
},
],
'import/no-extraneous-dependencies': [
@ -56,6 +63,7 @@ module.exports = {
'**/scripts/*.js',
'**/stories/**/*.js',
'**/__tests__/**/*.js',
'**/.storybook/**/*.js',
],
peerDependencies: true,
},
@ -64,24 +72,47 @@ module.exports = {
'import/default': error,
'import/named': error,
'import/namespace': error,
'react/jsx-wrap-multilines': ignore,
'react/jsx-indent': ignore,
'react/jsx-indent-props': ignore,
'react/jsx-closing-bracket-location': ignore,
'react/jsx-uses-react': error,
'react/jsx-uses-vars': error,
'react/react-in-jsx-scope': error,
'react/jsx-filename-extension': [
warn,
{
extensions: ['.js', '.jsx'],
},
],
'jsx-a11y/accessible-emoji': ignore,
'jsx-a11y/href-no-hash': ignore,
'jsx-a11y/label-has-for': ignore,
'jsx-a11y/click-events-have-key-events': error,
'jsx-a11y/anchor-is-valid': [warn, { aspects: ['invalidHref'] }],
'react/no-unescaped-entities': ignore,
'jsx-a11y/label-has-for': [
error,
{
required: {
some: ['nesting', 'id'],
},
},
],
'jsx-a11y/anchor-is-valid': [
error,
{
components: ['RoutedLink', 'MenuLink', 'LinkTo', 'Link'],
specialLink: ['overrideParams', 'kind', 'story', 'to'],
},
],
'no-underscore-dangle': [
error,
{
allow: ['__STORYBOOK_CLIENT_API__'],
},
],
},
overrides: [
{
files: ['**/react-native*/**', '**/REACT_NATIVE*/**', '**/crna*/**'],
rules: {
'jsx-a11y/accessible-emoji': ignore,
},
},
{
files: '**/.storybook/config.js',
rules: {
'global-require': ignore,
},
},
],
};

24
.github/autolabeler.yml vendored Normal file
View File

@ -0,0 +1,24 @@
'addon: a11y': ["addons/a11y/**"]
'addon: actions': ["addons/actions/**"]
'addon: backgrounds': ["addons/backgrounds/**"]
'addon: centered': ["addons/centered/**"]
'addon: events ': ["addons/events/**"]
'addon: graphql ': ["addons/graphql/**"]
'addon: info': ["addons/info/**"]
'addon: jest': ["addons/jest/**"]
'addon: knobs': ["addons/knobs/**"]
'addon: links': ["addons/links/**"]
'addon: notes': ["addons/notes/**"]
'addon: options': ["addons/options/**"]
'addon: storyshots': ["addons/storyshots/**"]
'addon: viewport': ["addons/viewport/**"]
'app: angular': ["app/angular/**"]
'app: polymer ': ["app/polymer/**"]
'app: react-native': ["app/react-native/**"]
'app: react': ["app/react/**"]
'app: vue': ["app/vue/**"]
'babel / webpack': ["webpack", "babel"]
'cli': ["lib/cli/**"]
'compatibility with other tools': []
'documentation': ["docs", "*.md"]
'ui': ["lib/ui"]

1
.github/stale.yml vendored
View File

@ -10,6 +10,7 @@ exemptLabels:
- 'do not merge'
- 'needs review'
- 'high priority'
- dependencies:update
# Label to use when marking an issue as stale
staleLabel: inactive

1
.gitignore vendored
View File

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

View File

@ -1,18 +1,3 @@
module.exports = {
plugins: [
'remark-preset-lint-recommended',
['remark-lint-list-item-indent', false],
[
'remark-lint-code',
{
js: {
module: 'node_modules/remark-lint-code-eslint',
options: {
fix: true,
configFile: '.eslintrc-markdown.js',
},
},
},
],
],
plugins: ['remark-preset-lint-recommended', ['remark-lint-list-item-indent', false]],
};

19
ADDONS_SUPPORT.md Normal file
View File

@ -0,0 +1,19 @@
## Addon / Framework Support Table
| |[React](app/react)|[React Native](app/react-native)|[Vue](app/vue)|[Angular](app/angular)| [Polymer](app/polymer)|
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|
|[a11y](addons/a11y) |+| | | | |
|[actions](addons/actions) |+|+|+|+|+|
|[background](addons/background) |+| | | | |
|[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) |+| |+|+|+|

File diff suppressed because it is too large Load Diff

View File

@ -41,7 +41,7 @@ You can also pick directly from CLI:
You can use one of the example projects in `examples/` to develop on.
This command will list all the suites and options for running tests.
This command will list all the suites and options for running tests.
```sh
yarn test
@ -58,7 +58,7 @@ You can also pick suites from CLI. Suites available are listed below.
`yarn test --core`
This option executes test from `<rootdir>/app/react`, `<rootdir>/app/vue`, and `<rootdir>/lib`.
Before the tests are ran, the project must be bootstrapped with core. You can accomplish this with `yarn bootstrap --core`
Before the tests are ran, the project must be bootstrapped with core. You can accomplish this with `yarn bootstrap --core`
##### React-Native example Tests
@ -67,15 +67,14 @@ Before the tests are ran, the project must be bootstrapped with core. You can ac
This option executes tests from `<rootdir>/app/react-native`.
Before these tests are ran, the project must be bootstrapped with the React Native example enabled. You can accomplish this by running `yarn bootstrap --reactnative`
##### Integration Tests (Screenshots of running apps)
##### CRA-kitchen-sink - Image snapshots using Storyshots
`yarn test --integration`
`yarn test --image`
This option executes tests from `<rootdir>/integration`.
In order for the snapshot-integration tests to be executed properly, examples being tested must be running on their defaults ports, as declared in `integration/examples.test.js`
Puppeteer is used to launch and grab screenshots of example pages, while jest is used to assert matching images.
This option executes tests from `<rootdir>/examples/cra-kitchen-sink`
In order for the image snapshots to be correctly generated, you must have static build of the storybook up-to-date.
Puppeteer is used to launch and grab screenshots of example pages, while jest is used to assert matching images. (just like integration tests)
#### 2b. Run e2e tests for CLI
@ -265,7 +264,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 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.
1. `getstorybook`
2. `yarn storybook`
@ -275,7 +274,7 @@ First we are going to install storyboook, then we are going to link `@storybook/
**_Note_**: This process is the same for `@storybook/vue`, `@storybook/addon-foo`, etc
1. Go to your storybook _root_ directory
1. Go to your storybook _root_ directory
2. `yarn dev`
3. Wait until the output stops (changes you make will be transpiled into dist and logged here)
4. Go to your storybook-sandbox-app directory

View File

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

View File

@ -3,7 +3,7 @@
[![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)
[![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)
@ -26,9 +26,10 @@ Storybook comes with a lot of [addons](https://storybook.js.org/addons/introduct
- [Getting Started](#getting-started)
- [Projects](#projects)
- [Main Projects](#main-projects)
- [Supported Frameworks](#supported-frameworks)
- [Sub Projects](#sub-projects)
- [Addons](#addons)
- [Live Examples](#live-examples) 💪
- [Contributing](#contributing)
- [Development scripts](#development-scripts)
- [Backers](#backers)
@ -60,14 +61,17 @@ It runs a codemod to update all package names. Read all migration details in our
For full documentation on using Storybook visit: [storybook.js.org](https://storybook.js.org)
For additional help, join us [in our Slack](https://now-examples-slackin-rrirkqohko.now.sh/)
## Projects
### Main Projects
### Supported Frameworks
- [Storybook for react](app/react) - Storybook for React components
- [Storybook for vue](app/vue) - Storybook for Vue components
- [Storybook for angular](app/angular) - Storybook for Angular components
- [Storybook for react-native](app/react-native) - Storybook for React-Native components
- [React](app/react)
- [React Native](app/react-native)
- [Vue](app/vue)
- [Angular](app/angular)
- [Polymer](app/polymer) <sup>alpha</sup>
### Sub Projects
@ -76,15 +80,38 @@ For full documentation on using Storybook visit: [storybook.js.org](https://stor
### Addons
- [storyshots](addons/storyshots) - Easy snapshot testing for storybook
- [actions](addons/actions/) - Log actions as users interact with components in storybook
- [links](addons/links/) - Create links between stories
- [comments](addons/comments/) - Comment on storybook stories
- [a11y](addons/a11y/) - Test components for user accessibility in Storybook
- [actions](addons/actions/) - Log actions as users interact with components in the Storybook UI
- [background](addons/background/) - Let users choose backgrounds in the Storybook UI
- [centered](addons/centered/) - Center the alignment of your components within the Storybook UI
- [events](addons/events/) - Interactively fire events to components that respond to EventEmitter
- [graphql](addons/graphql/) - Query a GraphQL server within Storybook stories
- [info](addons/info/) - Annotate stories with extra component usage information
- [jest](addons/jest/) - View the results of components' unit tests in Storybook
- [knobs](addons/knobs/) - Interactively edit component prop data in the Storybook UI
- [notes](addons/notes/) - Annotate storybook stories with notes
- [options](addons/options/) - Customize the storybook UI in code
- [links](addons/links/) - Create links between stories
- [notes](addons/notes/) - Annotate Storybook stories with notes
- [options](addons/options/) - Customize the Storybook UI in code
- [storyshots](addons/storyshots/) - Easy snapshot testing for components in Storybook
- [storysource](addons/storysource/) - View the code of your stories within the Storybook UI
- [viewport](addons/viewport/) - Change display sizes and layouts for responsive components using Storybook
See [Addon / Framework Support Table](ADDONS_SUPPORT.md)
## Live Examples
### 3.4.alpha
> Note, this is an Alpha version. Some of the features still might not be released
- [React Official](https://storybooks-official.netlify.com)
- [Vue](https://storybooks-vue.netlify.com/)
- [Angular](https://storybooks-angular.netlify.com/)
- [Polymer](https://storybooks-polymer.netlify.com/)
### 3.3
- [React Official](https://release-3-3--storybooks-official.netlify.com)
- [Vue](https://release-3-3--storybooks-vue.netlify.com/)
- [Angular](https://release-3-3--storybooks-angular.netlify.com/)
## Contributing

View File

@ -86,7 +86,7 @@ addressed before a release can go out by adding them to the milestone. For examp
Adding bugs to the milestone helps people looking for good ways to contribute,
or to understand what is blocking the release so they can actually do something
about it. Discussion about which bugs are critical happens in the `#maintenance`
channel [in our Slack](https://now-examples-slackin-rrirkqohko.now.sh/) [![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)].(https://now-examples-slackin-rrirkqohko.now.sh/)
channel [in our Slack](https://now-examples-slackin-rrirkqohko.now.sh/) [![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/)
If you're experiencing a bug, the best way to make sure that it gets attention
@ -116,3 +116,4 @@ in a patch release.
- For PATCH PR's, any maintainer can review, test, approve, and merge it.
- For MINOR/MAJOR PR's, once a maintainer reviews, tests, and approves it, s/he should clear it with the other maintainers before merging it into the release branch.

View File

@ -2,22 +2,22 @@
## Table of contents
* [New features](#new-features)
+ [Responsive + multi-device viewports preview.](#responsive--multi-device-viewports-preview)
+ [Automatic story detection](#automatic-story-detection)
+ [Theme ability and override core UI components](#theme-ability-and-override-core-ui-components)
+ [Add a playground addon](#add-a-playground-addon)
+ [See multiple (or all) stories in 1 preview.](#see-multiple--or-all--stories-in-1-preview)
* [Supporting other frameworks and libraries](#supporting-other-frameworks-and-libraries)
+ [Polymer & Webcomponents](#polymer---webcomponents)
+ [Aurelia](#aurelia)
+ [Ember](#ember)
* [Breaking changes](#breaking-changes)
+ [Addon API](#addon-api)
+ [API for adding stories](#api-for-adding-stories)
* [Documentation](#documentation)
+ [Better design](#better-design)
+ [Record videos and write blog post on how to use, tweak & develop storybook](#record-videos-and-write-blog-post-on-how-to-use--tweak---develop-storybook)
* [New features](#new-features)
+ [Responsive + multi-device viewports preview.](#responsive--multi-device-viewports-preview)
+ [Automatic story detection](#automatic-story-detection)
+ [Theme ability and override core UI components](#theme-ability-and-override-core-ui-components)
+ [Add a playground addon](#add-a-playground-addon)
+ [See multiple (or all) stories in 1 preview.](#see-multiple--or-all--stories-in-1-preview)
* [Supporting other frameworks and libraries](#supporting-other-frameworks-and-libraries)
+ [Polymer & Webcomponents](#polymer---webcomponents)
+ [Aurelia](#aurelia)
+ [Ember](#ember)
* [Breaking changes](#breaking-changes)
+ [Addon API](#addon-api)
+ [API for adding stories](#api-for-adding-stories)
* [Documentation](#documentation)
+ [Better design](#better-design)
+ [Record videos and write blog post on how to use, tweak & develop storybook](#record-videos-and-write-blog-post-on-how-to-use--tweak---develop-storybook)
## New features
@ -57,7 +57,7 @@ That way you can write your stories how they are best, and preview them how you
We believe in the power of react, and think it's the right choice for a lot of projects.
But it's up to you and your team to decide your stack.
Unfortunately if you choose anything other then React or React-Native you can not use storybook.
Unfortunately if you choose anything not from the list of [supported frameworks](README.md#supported-frameworks) you can not use storybook.
We want you to be able to use storybook with the framework / library of your choice.

View File

@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import { storiesOf } from '@storybook/angular';
@Component({
selector: 'storybook-with-ng-content',
template: `<div style="color: #1e88e5;"><ng-content></ng-content></div>`,
})
class WithNgContentComponent {}
storiesOf('Custom|ng-content', module).add('Default', () => ({
template: `<storybook-with-ng-content><h1>This is rendered in ng-content</h1></storybook-with-ng-content>`,
moduleMetadata: {
declarations: [WithNgContentComponent],
},
}));

View File

@ -0,0 +1,3 @@
while(true) {
console.log("it's a kind of magic");
}

View File

@ -0,0 +1,153 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import { withInfo } from '@storybook/addon-info';
import { action } from '@storybook/addon-actions';
import DocgenButton from '../components/DocgenButton';
import FlowTypeButton from '../components/FlowTypeButton';
import BaseButton from '../components/BaseButton';
import TableComponent from '../components/TableComponent';
storiesOf('Addons|Info.React Docgen', module)
.add(
'Comments from PropType declarations',
withInfo(
'Comments above the PropType declarations should be extracted from the React component file itself and rendered in the Info Addon prop table'
)(() => <DocgenButton onClick={action('clicked')} label="Docgen Button" />)
)
.add(
'Comments from Flow declarations',
withInfo(
'Comments above the Flow declarations should be extracted from the React component file itself and rendered in the Info Addon prop table'
)(() => <FlowTypeButton onClick={action('clicked')} label="Flow Typed Button" />)
)
.add(
'Comments from component declaration',
withInfo(
'Comments above the component declaration should be extracted from the React component file itself and rendered below the Info Addon heading'
)(() => <BaseButton onClick={action('clicked')} label="Button" />)
);
const markdownDescription = `
#### You can use markdown in your withInfo() description.
Sometimes you might want to manually include some code examples:
~~~js
const Button = () => <button />;
~~~
Maybe include a [link](http://storybook.js.org) to your project as well.
`;
storiesOf('Addons|Info.Markdown', module).add(
'Displays Markdown in description',
withInfo(markdownDescription)(() => <BaseButton onClick={action('clicked')} label="Button" />)
);
storiesOf('Addons|Info.Options.inline', module).add(
'Inlines component inside story',
withInfo({
text: 'Component should be inlined between description and PropType table',
inline: true, // Displays info inline vs click button to view
})(() => <BaseButton label="Button" />)
);
storiesOf('Addons|Info.Options.header', module).add(
'Shows or hides Info Addon header',
withInfo({
text: 'The Info Addon header should be hidden',
header: false, // Toggles display of header with component name and description
})(() => <BaseButton label="Button" />)
);
storiesOf('Addons|Info.Options.source', module).add(
'Shows or hides Info Addon source',
withInfo({
text: 'The Info Addon source section should be hidden',
source: false, // Displays the source of story Component
})(() => <BaseButton label="Button" />)
);
storiesOf('Addons|Info.Options.propTables', module).add(
'Shows additional component prop tables',
withInfo({
text: 'There should be a prop table added for a component not included in the story',
propTables: [FlowTypeButton],
})(() => <BaseButton label="Button" />)
);
storiesOf('Addons|Info.Options.propTablesExclude', module).add(
'Exclude component from prop tables',
withInfo({
text: 'This can exclude extraneous components from being displayed in prop tables.',
propTablesExclude: [FlowTypeButton],
})(() => (
<div>
<BaseButton label="Button" />
<FlowTypeButton label="Flow Typed Button" />
</div>
))
);
storiesOf('Addons|Info.Options.styles', module)
.add(
'Extend info styles with an object',
withInfo({
styles: {
button: {
base: {
background: 'purple',
},
},
header: {
h1: {
color: 'green',
},
},
},
})(() => <BaseButton label="Button" />)
)
.add(
'Full control over styles using a function',
withInfo({
styles: stylesheet => ({
...stylesheet,
header: {
...stylesheet.header,
h1: {
...stylesheet.header.h1,
color: 'red',
},
},
}),
})(() => <BaseButton label="Button" />)
);
storiesOf('Addons|Info.Options.TableComponent', module).add(
'Use a custom component for the table',
withInfo({
TableComponent,
})(() => <BaseButton label="Button" />)
);
storiesOf('Addons|Info.Decorator', module)
.addDecorator((story, context) =>
withInfo('Info could be used as a global or local decorator as well.')(story)(context)
)
.add('Use Info as story decorator', () => <BaseButton label="Button" />);
const hoc = WrapComponent => ({ ...props }) => <WrapComponent {...props} />;
const Input = hoc(() => <input type="text" />);
const TextArea = hoc(({ children }) => <textarea>{children}</textarea>);
storiesOf('Addons|Info.GitHub issues', module).add(
'#1814',
withInfo('Allow Duplicate DisplayNames for HOC #1814')(() => (
<div>
<Input />
<TextArea />
</div>
))
);

View File

@ -0,0 +1,23 @@
/* global window */
/* eslint-disable global-require, import/no-dynamic-require */
import React from 'react';
/*
eslint-disable some kind
of multi line ignore, though
I'm not sure it's possible.
*/
import { storiesOf } from '@storybook/react';
/* eslint-disable-line */ const x = 0;
// eslint-disable-line
storiesOf('Foo', module)
.add('bar', () => <div>baz</div>);
/*
This is actually a good comment that will help
users to understand what's going on here.
*/

View File

@ -15,10 +15,10 @@ const styles = {
wrong: {
color: '#ffffff',
backgroundColor: '#4caf50',
}
}
},
};
function Button({ label, content, disabled, contrast }) {
function Button({ content, disabled, contrast }) {
return (
<button
style={{
@ -27,19 +27,19 @@ function Button({ label, content, disabled, contrast }) {
}}
disabled={disabled}
>
{ content }
{content}
</button>
)
);
}
Button.propTypes = {
label: PropTypes.string,
content: PropTypes.string,
disabled: PropTypes.bool,
contrast: PropTypes.oneOf(['ok', 'wrong'])
contrast: PropTypes.oneOf(['ok', 'wrong']),
};
Button.defaultProps = {
content: 'null',
disabled: false,
contrast: 'ok',
};

View File

@ -1,34 +1,17 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import Faker from 'faker';
import { checkA11y } from './../../../src';
import Button from './component';
import Faker from 'faker';
const text = Faker.lorem.words();
storiesOf('<Button />', module)
.addDecorator(checkA11y)
.add('Default', () => (
<Button />
))
.add('Content', () => (
<Button content={text} />
))
.add('Label', () => (
<Button label={text} />
))
.add('Disabled', () => (
<Button
disabled
content={text}
/>
))
.add('Invalid contrast', () => (
<Button
contrast="wrong"
content={Faker.lorem.words()}
/>
));
.add('Default', () => <Button />)
.add('Content', () => <Button content={text} />)
.add('Label', () => <Button label={text} />)
.add('Disabled', () => <Button disabled content={text} />)
.add('Invalid contrast', () => <Button contrast="wrong" content={Faker.lorem.words()} />);

View File

@ -2,14 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
function Input({ id, value, type, placeholder }) {
return (
<input
id={id}
value={value}
placeholder={placeholder}
type={type}
/>
);
return <input id={id} value={value} placeholder={placeholder} type={type} />;
}
Input.propTypes = {
@ -17,6 +10,13 @@ Input.propTypes = {
id: PropTypes.string,
value: PropTypes.string,
placeholder: PropTypes.string,
}
};
Input.defaultProps = {
type: null,
id: null,
value: null,
placeholder: null,
};
export default Input;

View File

@ -5,22 +5,19 @@ const styles = {
label: {
padding: '0 6px',
},
}
};
function Label({ id, content }) {
return (
<label
style={styles.label}
htmlFor={id}
>
{ content }
<label style={styles.label} htmlFor={id}>
{content}
</label>
)
);
}
Label.propTypes = {
content: PropTypes.string,
id: PropTypes.string,
content: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
};
export default Label;

View File

@ -15,7 +15,11 @@ function Row({ label, input }) {
Row.propTypes = {
label: PropTypes.instanceOf(Label),
input: PropTypes.instanceOf(Input),
}
input: PropTypes.instanceOf(Input).isRequired,
};
Row.defaultProps = {
label: null,
};
export default Row;

View File

@ -2,8 +2,4 @@ import Input from './Input';
import Label from './Label';
import Row from './Row';
export {
Input,
Label,
Row,
};
export { Input, Label, Row };

View File

@ -1,36 +1,20 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import Faker from 'faker';
import * as Form from './components';
import { storiesOf } from '@storybook/react';
import { checkA11y } from './../../../src';
import Faker from 'faker';
const label = Faker.lorem.word();
const placeholder = Faker.lorem.word();
storiesOf('<Form />', module)
.addDecorator(checkA11y)
.add('Without Label', () => (
<Form.Row
input={<Form.Input />}
/>
))
.add ('With label', () => (
<Form.Row
label={<Form.Label
content={label}
id="1"
/>}
input={<Form.Input id="1" />}
/>
))
.add ('With placeholder', () => (
<Form.Row
input={<Form.Input
id="1"
placeholder={placeholder}
/>}
/>
.add('Without Label', () => <Form.Row input={<Form.Input />} />)
.add('With label', () => (
<Form.Row label={<Form.Label content={label} id="1" />} input={<Form.Input id="1" />} />
))
.add('With placeholder', () => (
<Form.Row input={<Form.Input id="1" placeholder={placeholder} />} />
));

View File

@ -2,13 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
function Image({ src, alt, presentation }) {
return (
<img
src={src}
alt={alt}
role={presentation && 'presentation'}
/>
);
return <img src={src} alt={alt} role={presentation && 'presentation'} />;
}
Image.propTypes = {
@ -17,4 +11,9 @@ Image.propTypes = {
presentation: PropTypes.bool,
};
Image.defaultProps = {
alt: null,
presentation: false,
};
export default Image;

View File

@ -1,29 +1,16 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import Faker from 'faker';
import { checkA11y } from './../../../src';
import Image from './component';
import Faker from 'faker';
const image = Faker.image.animals();
const alt = Faker.lorem.words();
storiesOf('<Image />', module)
.addDecorator(checkA11y)
.add('Without alt', () => (
<Image src={image} />
))
.add('With alt', () => (
<Image
src={image}
alt={alt}
/>
))
.add('Presentation', () => (
<Image
presentation
src={image}
/>
));
.add('Without alt', () => <Image src={image} />)
.add('With alt', () => <Image src={image} alt={alt} />)
.add('Presentation', () => <Image presentation src={image} />);

View File

@ -1,20 +1,20 @@
import React, { cloneElement } from 'react';
import { createElement } from 'react';
import PropTypes from 'prop-types';
const headings = {
1: (<h1 />),
2: (<h2 />),
3: (<h3 />),
4: (<h4 />),
1: 'h1',
2: 'h2',
3: 'h3',
4: 'h4',
};
function Heading({ level, children }) {
return cloneElement(headings[level], {}, children)
return createElement(headings[level], {}, children);
}
Heading.propTypes = {
level: PropTypes.oneOf([1, 2, 3, 4]),
children: PropTypes.any,
children: PropTypes.node,
};
Heading.defaultProps = {

View File

@ -2,16 +2,12 @@ import React from 'react';
import PropTypes from 'prop-types';
function Link({ href, content }) {
return (
<a href={href}>
{ content }
</a>
);
return <a href={href}>{content}</a>;
}
Link.propTypes = {
href: PropTypes.string,
content: PropTypes.string,
href: PropTypes.string.isRequired,
content: PropTypes.string.isRequired,
};
export default Link;

View File

@ -2,15 +2,11 @@ import React from 'react';
import PropTypes from 'prop-types';
function Text({ children }) {
return (
<p>
{children}
</p>
);
return <p>{children}</p>;
}
Text.propTypes = {
children: PropTypes.any,
children: PropTypes.node.isRequired,
};
export default Text;

View File

@ -2,8 +2,4 @@ import Heading from './Heading';
import Link from './Link';
import Text from './Text';
export {
Heading,
Link,
Text,
};
export { Heading, Link, Text };

View File

@ -1,41 +1,26 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import Faker from 'faker';
import { checkA11y } from './../../../src';
import * as Typography from './components';
import Faker from 'faker';
const href = "javascript:void 0";
// eslint-disable-next-line no-script-url
const href = 'javascript:void 0';
storiesOf('<Typography />', module)
.addDecorator(checkA11y)
.add('Correct', () => (
<div>
<Typography.Heading level={1}>
{Faker.lorem.sentence()}
</Typography.Heading>
<Typography.Heading level={1}>{Faker.lorem.sentence()}</Typography.Heading>
<Typography.Text>
{Faker.lorem.paragraph()}
</Typography.Text>
<Typography.Text>{Faker.lorem.paragraph()}</Typography.Text>
<Typography.Link
content={`${Faker.lorem.words(4)}...`}
href={href}
/>
<Typography.Link content={`${Faker.lorem.words(4)}...`} href={href} />
</div>
))
.add('Empty Heading', () => (
<Typography.Heading level={2} />
))
.add('Empty Paragraph', () => (
<Typography.Text />
))
.add('Empty Link', () => (
<Typography.Link href={href} />
))
.add('Link without href', () => (
<Typography.Link content={`${Faker.lorem.words(4)}...`} />
));
.add('Empty Heading', () => <Typography.Heading level={2} />)
.add('Empty Paragraph', () => <Typography.Text />)
.add('Empty Link', () => <Typography.Link href={href} />)
.add('Link without href', () => <Typography.Link content={`${Faker.lorem.words(4)}...`} />);

View File

@ -1,9 +1,7 @@
import * as storybook from '@storybook/react';
const req = require.context('./components/', true, /stories\.js$/)
const req = require.context('./components/', true, /stories\.js$/);
const loadStories = () =>
req.keys().forEach(req);
const loadStories = () => req.keys().forEach(req);
storybook.configure(loadStories, module)
storybook.configure(loadStories, module);

View File

@ -2,6 +2,8 @@
This storybook addon can be helpfull to make your UI components more accessibile.
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
![](docs/screenshot.png)
## Getting started

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-a11y",
"version": "3.4.0-alpha.0",
"version": "3.4.0-alpha.9",
"description": "a11y addon for storybook",
"keywords": [
"a11y",
@ -25,9 +25,16 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/components": "^3.4.0-alpha.0",
"@storybook/components": "^3.4.0-alpha.9",
"axe-core": "^2.6.1",
"prop-types": "^15.6.0"
"babel-runtime": "^6.26.0",
"glamor": "^2.20.40",
"glamorous": "^4.11.6",
"prop-types": "^15.6.1"
},
"devDependencies": {
"@storybook/react": "^3.4.0-alpha.9",
"faker": "^4.1.0"
},
"peerDependencies": {
"@storybook/addons": "^3.3.0",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,10 +11,7 @@
Storybook Addon Actions can be used to display data received by event handlers in [Storybook](https://storybook.js.org).
This addon works with Storybook for:
- [React](https://github.com/storybooks/storybook/tree/master/app/react)
- [React Native](https://github.com/storybooks/storybook/tree/master/app/react-native)
- [Vue](https://github.com/storybooks/storybook/tree/master/app/vue).
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
![Screenshot](docs/screenshot.png)

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-actions",
"version": "3.4.0-alpha.0",
"version": "3.4.0-alpha.9",
"description": "Action Logger addon for storybook",
"keywords": [
"storybook"
@ -20,12 +20,16 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/components": "^3.4.0-alpha.9",
"babel-runtime": "^6.26.0",
"deep-equal": "^1.0.1",
"glamor": "^2.20.40",
"glamorous": "^4.11.6",
"global": "^4.3.2",
"make-error": "^1.3.2",
"prop-types": "^15.6.0",
"make-error": "^1.3.4",
"prop-types": "^15.6.1",
"react-inspector": "^2.2.2",
"uuid": "^3.1.0"
"uuid": "^3.2.1"
},
"peerDependencies": {
"@storybook/addons": "^3.3.0",

View File

@ -1 +1 @@
require('./dist').register();
require('./dist/manager').register();

View File

@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Inspector from 'react-inspector';
import style from './style';
import { Actions, Action, Button, Wrapper, InspectorContainer, Countwrap, Counter } from './style';
class ActionLogger extends Component {
getActionData() {
@ -9,30 +9,28 @@ class ActionLogger extends Component {
}
renderAction(action) {
const counter = <div style={style.counter}>{action.count}</div>;
const counter = <Counter>{action.count}</Counter>;
return (
<div key={action.id} style={style.action}>
<div style={style.countwrap}>{action.count > 1 && counter}</div>
<div style={style.inspector}>
<Action key={action.id}>
<Countwrap>{action.count > 1 && counter}</Countwrap>
<InspectorContainer>
<Inspector
sortObjectKeys
showNonenumerable={false}
name={action.data.name}
data={action.data.args || action.data}
/>
</div>
</div>
</InspectorContainer>
</Action>
);
}
render() {
return (
<div style={style.wrapper}>
<pre style={style.actions}>{this.getActionData()}</pre>
<button style={style.button} onClick={this.props.onClear}>
CLEAR
</button>
</div>
<Wrapper>
<Actions>{this.getActionData()}</Actions>
<Button onClick={this.props.onClear}>Clear</Button>
</Wrapper>
);
}
}

View File

@ -1,49 +1,53 @@
export default {
wrapper: {
flex: 1,
display: 'flex',
position: 'relative',
},
actions: {
flex: 1,
margin: 0,
padding: '8px 2px 20px 0',
overflowY: 'auto',
color: '#666',
},
action: {
display: 'flex',
padding: '3px 3px 3px 0',
borderLeft: '5px solid white',
borderBottom: '1px solid #fafafa',
transition: 'all 0.1s',
alignItems: 'start',
},
countwrap: {
paddingBottom: 2,
},
counter: {
margin: '0 5px 0 5px',
backgroundColor: '#777777',
color: '#ffffff',
padding: '1px 5px',
borderRadius: '20px',
},
inspector: {
flex: 1,
padding: '0 0 0 5px',
},
button: {
position: 'absolute',
bottom: 0,
right: 0,
border: 'none',
borderTop: 'solid 1px rgba(0, 0, 0, 0.2)',
borderLeft: 'solid 1px rgba(0, 0, 0, 0.2)',
background: 'rgba(255, 255, 255, 0.5)',
padding: '5px 10px',
borderRadius: '4px 0 0 0',
color: 'rgba(0, 0, 0, 0.5)',
outline: 'none',
},
};
import glamorous from 'glamorous';
import { Button as BaseButton } from '@storybook/components';
export const Actions = glamorous.pre({
flex: 1,
margin: 0,
padding: '8px 2px 20px 0',
overflowY: 'auto',
color: '#666',
});
export const Action = glamorous.div({
display: 'flex',
padding: '3px 3px 3px 0',
borderLeft: '5px solid white',
borderBottom: '1px solid #fafafa',
transition: 'all 0.1s',
alignItems: 'start',
});
export const Button = glamorous(BaseButton)({
position: 'absolute',
bottom: 0,
right: 0,
borderRadius: '4px 0 0 0',
textTransform: 'uppercase',
letterSpacing: 1,
paddingTop: 5,
paddingBootom: 5,
});
export const Counter = glamorous.div({
margin: '0 5px 0 5px',
backgroundColor: '#777777',
color: '#ffffff',
padding: '1px 5px',
borderRadius: '20px',
});
export const Countwrap = glamorous.div({
paddingBottom: 2,
});
export const InspectorContainer = glamorous.div({
flex: 1,
padding: '0 0 0 5px',
});
export const Wrapper = glamorous.div({
flex: 1,
display: 'flex',
position: 'relative',
});

View File

@ -3,5 +3,4 @@ export const ADDON_ID = 'storybook/actions';
export const PANEL_ID = `${ADDON_ID}/actions-panel`;
export const EVENT_ID = `${ADDON_ID}/action-event`;
export { register } from './manager';
export { action, decorateAction } from './preview';

View File

@ -1,7 +1,7 @@
export canConfigureName from './canConfigureName.js';
export getPropertiesList from './getPropertiesList.js';
export isObject from './isObject.js';
export muteProperty from './muteProperty.js';
export canConfigureName from './canConfigureName';
export getPropertiesList from './getPropertiesList';
export isObject from './isObject';
export muteProperty from './muteProperty';
export prepareArguments from './prepareArguments';
export typeReviver from './typeReviver.js';
export typeReplacer from './typeReplacer.js';
export typeReviver from './typeReviver';
export typeReplacer from './typeReplacer';

View File

@ -1,5 +1,3 @@
/* eslint-disable no-underscore-dangle */
import addons from '@storybook/addons';
import uuid from 'uuid/v1';
import { EVENT_ID } from './';
@ -24,11 +22,9 @@ export function action(name) {
}
export function decorateAction(decorators) {
// eslint-disable-next-line no-unused-vars, func-names
return function(name) {
return name => {
const callAction = action(name);
// eslint-disable-next-line no-unused-vars, func-names
return function(..._args) {
return (..._args) => {
const decorated = decorators.reduce((args, fn) => fn(args), _args);
callAction(...decorated);
};

View File

@ -3,24 +3,22 @@
[![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)
[![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).
Storybook Background Addon can be used to change background colors inside the preview in [Storybook](https://storybook.js.org).
This addon works with Storybook for:
- [React](https://github.com/storybooks/storybook/tree/master/app/react)
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
![React Storybook Screenshot](https://storybook.js.org/img/addon-backgrounds.gif)
## Installation
```sh
npm i --save @storybook/addon-backgrounds
npm i -D @storybook/addon-backgrounds
```
## Configuration

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-backgrounds",
"version": "3.4.0-alpha.0",
"version": "3.4.0-alpha.9",
"description": "A storybook addon to show different backgrounds for your preview",
"keywords": [
"addon",
@ -24,7 +24,9 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"prop-types": "^15.6.0"
"babel-runtime": "^6.26.0",
"global": "^4.3.2",
"prop-types": "^15.6.1"
},
"peerDependencies": {
"@storybook/addons": "^3.3.0",

View File

@ -1,15 +1,21 @@
import { document } from 'global';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import addons from '@storybook/addons';
import Swatch from './Swatch';
const storybookIframe = 'storybook-preview-iframe';
const style = {
font: {
fontFamily:
"-apple-system,'.SFNSText-Regular', 'San Francisco', Roboto, 'Segoe UI', 'Helvetica Neue', 'Lucida Grande', sans-serif",
fontSize: '14px',
},
iframe: {
transition: 'background 0.25s ease-in-out',
},
};
const defaultBackground = {
@ -73,10 +79,10 @@ export default class BackgroundPanel extends Component {
const currentBackground = api.getQueryParam('background');
if (currentBackground) {
this.setBackgroundInPreview(currentBackground);
this.updateIframe(currentBackground);
} else if (backgrounds.filter(x => x.default).length) {
const defaultBgs = backgrounds.filter(x => x.default);
this.setBackgroundInPreview(defaultBgs[0].value);
this.updateIframe(defaultBgs[0].value);
}
});
@ -86,13 +92,27 @@ export default class BackgroundPanel extends Component {
});
}
setBackgroundInPreview = background => this.channel.emit('background', background);
componentDidMount() {
this.iframe = document.getElementById(storybookIframe);
if (!this.iframe) {
throw new Error('Cannot find Storybook iframe');
}
Object.keys(style.iframe).forEach(prop => {
this.iframe.style[prop] = style.iframe[prop];
});
}
setBackgroundFromSwatch = background => {
this.setBackgroundInPreview(background);
this.updateIframe(background);
this.props.api.setQueryParams({ background });
};
updateIframe(background) {
this.iframe.style.background = background;
}
render() {
const backgrounds = [...this.state.backgrounds];

View File

@ -17,6 +17,16 @@ const mockedApi = {
};
const channel = new EventEmitter();
jest.mock('global', () => ({
document: {
getElementById() {
return {
style: {},
};
},
},
}));
describe('Background Panel', () => {
it('should exist', () => {
const backgroundPanel = shallow(<BackgroundPanel channel={channel} api={mockedApi} />);
@ -105,19 +115,18 @@ describe('Background Panel', () => {
expect(backgroundPanel.state('backgrounds')).toHaveLength(0);
});
it('should pass the event from swatch clicks through the provided channel', () => {
it('should set iframe background', () => {
const SpiedChannel = new EventEmitter();
const backgroundPanel = mount(<BackgroundPanel channel={SpiedChannel} api={mockedApi} />);
backgroundPanel.setState({ backgrounds }); // force re-render
const spy = jest.fn();
SpiedChannel.on('background', spy);
backgroundPanel
.find('h4')
.first()
.simulate('click');
expect(spy).toBeCalledWith(backgrounds[0].value);
expect(backgroundPanel.instance().iframe.style).toMatchObject({
background: backgrounds[0].value,
});
});
});

View File

@ -16,34 +16,6 @@ describe('Background Decorator', () => {
expect(backgroundDecorator).toBeDefined();
});
it('should initially have a transparent background state', () => {
const SpiedChannel = new EventEmitter();
const backgroundDecorator = shallow(
<BackgroundDecorator story={testStory} channel={SpiedChannel} />
);
expect(backgroundDecorator.state().background).toBe('transparent');
});
it('should have a background matching its state', () => {
const SpiedChannel = new EventEmitter();
const backgroundDecorator = shallow(
<BackgroundDecorator story={testStory} channel={SpiedChannel} />
);
expect(backgroundDecorator.html().match(/background:transparent/gim)).toHaveLength(1);
});
it('should set internal state when background event called', () => {
const SpiedChannel = new EventEmitter();
const backgroundDecorator = shallow(
<BackgroundDecorator story={testStory} channel={SpiedChannel} />
);
SpiedChannel.emit('background', '#123456');
expect(backgroundDecorator.state().background).toBe('#123456');
});
it('should send background-unset event when the component unmounts', () => {
const SpiedChannel = new EventEmitter();
const backgroundDecorator = shallow(

View File

@ -3,21 +3,6 @@ import PropTypes from 'prop-types';
import addons from '@storybook/addons';
const style = {
wrapper: {
overflow: 'scroll',
position: 'fixed',
top: 0,
bottom: 0,
right: 0,
left: 0,
transition: 'background 0.25s ease-in-out',
backgroundPosition: 'center',
backgroundSize: 'cover',
background: 'transparent',
},
};
export class BackgroundDecorator extends React.Component {
constructor(props) {
super(props);
@ -31,13 +16,10 @@ export class BackgroundDecorator extends React.Component {
this.channel = addons.getChannel();
}
this.state = { background: 'transparent' };
this.story = story();
}
componentWillMount() {
this.channel.on('background', this.setBackground);
this.channel.emit('background-set', this.props.backgrounds);
}
@ -48,16 +30,11 @@ export class BackgroundDecorator extends React.Component {
}
componentWillUnmount() {
this.channel.removeListener('background', this.setBackground);
this.channel.emit('background-unset');
}
setBackground = background => this.setState({ background });
render() {
const styles = style.wrapper;
styles.background = this.state.background;
return <div style={Object.assign({}, styles)}>{this.story}</div>;
return this.story;
}
}
BackgroundDecorator.propTypes = {

View File

@ -11,10 +11,7 @@
Storybook Centered Decorator can be used to center components inside the preview in [Storybook](https://storybook.js.org).
This addon works with Storybook for:
- [React](https://github.com/storybooks/storybook/tree/master/app/react)
- [Vue](https://github.com/storybooks/storybook/tree/master/app/vue)
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
### Usage

View File

@ -1,6 +1,7 @@
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import decorator from '../index';
import { document } from 'global';
import decorator from '../src';
const content = decorator(() => 'Hello World!');
const wrapper = document.querySelector('#content');

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-centered",
"version": "3.4.0-alpha.0",
"version": "3.4.0-alpha.9",
"description": "Storybook decorator to center components",
"license": "MIT",
"author": "Muhammed Thanish <mnmtanish@gmail.com>",
@ -10,8 +10,12 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"babel-runtime": "^6.26.0",
"global": "^4.3.2"
},
"devDependencies": {
"react-dom": "^16.2.0"
},
"peerDependencies": {
"react": "*"
}

View File

@ -11,6 +11,8 @@
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)
![Storybook Addon Events Example](docs/demo1.png)
[Storybook Addon Events Live Demo](https://z4o4z.github.io/storybook-addon-events/index.html)
@ -25,8 +27,8 @@ Then create a file called `addons.js` in your storybook config.
Add following content to it:
```js
import '@storybook/addon-actions';
import '@storybook/addon-links';
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
import '@storybook/addon-events/register';
```

Binary file not shown.

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-events",
"version": "3.4.0-alpha.0",
"version": "3.4.0-alpha.9",
"description": "Add events to your Storybook stories.",
"keywords": [
"addon",
@ -23,9 +23,8 @@
"dependencies": {
"babel-runtime": "^6.26.0",
"format-json": "^1.0.3",
"prop-types": "^15.6.0",
"react-textarea-autosize": "^5.2.1",
"uuid": "^3.1.0"
"prop-types": "^15.6.1",
"react-textarea-autosize": "^5.2.1"
},
"peerDependencies": {
"@storybook/addons": "^3.3.0",

View File

@ -1 +1 @@
require('./dist').register();
require('./dist/manager').register();

View File

@ -145,7 +145,9 @@ export default class Item extends Component {
disabled={failed}
title="Submit event"
>
📢
<span role="img" aria-label="loudspeaker">
📢
</span>
</button>
<Textarea
id={`addon-event-${name}`}
@ -155,11 +157,15 @@ export default class Item extends Component {
/>
{isTextAreaShowed ? (
<button style={styles.button} onClick={this.onToggleEditClick} title="Close editing">
<span role="img" aria-label="cross">
</span>
</button>
) : (
<button style={styles.button} onClick={this.onToggleEditClick} title="Edit event payload">
<span role="img" aria-label="pencil">
</span>
</button>
)}
</div>

View File

@ -66,7 +66,7 @@ export default class Events extends Component {
const { events } = this.state;
return (
<div style={styles.wrapper}>
{events.map(event => <Event key={event.id} {...event} onEmit={this.onEmit} />)}
{events.map(event => <Event key={event.name} {...event} onEmit={this.onEmit} />)}
</div>
);
}

View File

@ -1,3 +1 @@
export default from './preview';
export { register } from './manager';

View File

@ -1,2 +1,3 @@
import * as storybook from '@storybook/react';
storybook.configure(() => require('./stories'), module);

View File

@ -1,13 +1,14 @@
import React from 'react';
import { storiesOf } from '@storybook/react'
import { setupGraphiQL } from '../src'
import { storiesOf } from '@storybook/react';
import { setupGraphiQL } from '../src';
// setup the graphiql helper which can be used with the add method later
const graphiql = setupGraphiQL({ url: 'http://localhost:3000/graphql' });
storiesOf('GraphQL Demo', module)
.add('get user info', graphiql(`{
storiesOf('GraphQL Demo', module).add(
'get user info',
graphiql(`{
user(id: "1") {
name
}
}`));
}`)
);

View File

@ -11,8 +11,7 @@
Storybook GraphQL Addon can be used to display the GraphiQL IDE with example queries in [Storybook](https://storybook.js.org).
This addon works with Storybook for:
- [React](https://github.com/storybooks/storybook/tree/master/app/react)
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
![Screenshot](docs/screenshot.png)

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-graphql",
"version": "3.4.0-alpha.0",
"version": "3.4.0-alpha.9",
"description": "Storybook addon to display the GraphiQL IDE",
"keywords": [
"storybook"
@ -22,10 +22,14 @@
"storybook": "start-storybook -p 9001"
},
"dependencies": {
"babel-runtime": "^6.26.0",
"global": "^4.3.2",
"graphiql": "^0.11.11",
"graphql": "^0.12.3",
"prop-types": "^15.6.0"
"graphql": "^0.13.1",
"prop-types": "^15.6.1"
},
"devDependencies": {
"@storybook/react": "^3.4.0-alpha.9"
},
"peerDependencies": {
"react": "*"

View File

@ -2,14 +2,10 @@ import React from 'react';
import { configure, setAddon, addDecorator } from '@storybook/react';
import InfoAddon from '../src/';
addDecorator((story) => (
<div style={{padding: 20}}>
{story()}
</div>
));
addDecorator(story => <div style={{ padding: 20 }}>{story()}</div>);
setAddon(InfoAddon);
configure(function () {
configure(() => {
require('../example/story');
}, module);

View File

@ -1,4 +1,4 @@
module.exports = function (config) {
module.exports = () => {
// This is the default webpack config defined in the `../webpack.config.js`
// modify as you need.
};

View File

@ -19,7 +19,7 @@ const config = {
test: /\.json?$/,
loaders: ['json'],
include: path.resolve(__dirname, '../'),
}
},
],
},
};

View File

@ -12,8 +12,7 @@
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.
This addon works with Storybook for:
- [React](https://github.com/storybooks/storybook/tree/master/app/react)
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
![Screenshot](docs/home-screenshot.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 160 KiB

View File

@ -1,20 +1,21 @@
import PropTypes from 'prop-types';
import React from 'react';
const Button = ({ disabled, label, style, onClick }) => (
const Button = ({ disabled, label, onClick }) => (
<button disabled={disabled} onClick={onClick}>
{label}
</button>
);
Object.assign(Button, {
displayName: 'Button',
propTypes: {
label: PropTypes.string.isRequired,
style: PropTypes.object,
disabled: PropTypes.bool,
onClick: PropTypes.func,
},
});
Button.propTypes = {
label: PropTypes.string.isRequired,
disabled: PropTypes.bool,
onClick: PropTypes.func,
};
Button.defaultProps = {
disabled: false,
onClick() {},
};
export default Button;

View File

@ -1,21 +1,18 @@
import React from 'react';
import Button from './Button';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
storiesOf(
'Button'
).addWithInfo(
import Button from './Button';
storiesOf('Button').addWithInfo(
'simple usage',
'This is the basic usage with the button with providing a label to show the text.',
() => (
<div>
<Button label="The Button" onClick={action('onClick')} />
<br />
<p>
Click the "?" mark at top-right to view the info.
</p>
<p>Click the "?" mark at top-right to view the info.</p>
</div>
)
);
@ -88,27 +85,22 @@ storiesOf('Button').addWithInfo(
<div>
<h2>This is a JSX info section</h2>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed ornare massa rutrum metus commodo, a mattis velit dignissim.
Fusce vestibulum turpis sed massa egestas pharetra. Sed at libero
nulla.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ornare massa rutrum metus
commodo, a mattis velit dignissim. Fusce vestibulum turpis sed massa egestas pharetra. Sed at
libero nulla.
</p>
<p>
<a href="https://github.com/storybooks/react-storybook-addon-info">
This is a link
</a>
<a href="https://github.com/storybooks/react-storybook-addon-info">This is a link</a>
</p>
<p>
<img src="http://placehold.it/350x150" />
<img alt="350x150" src="http://placehold.it/350x150" />
</p>
</div>,
() => (
<div>
<Button label="The Button" onClick={action('onClick')} />
<br />
<p>
Click the "?" mark at top-right to view the info.
</p>
<p>Click the "?" mark at top-right to view the info.</p>
</div>
)
);
@ -118,18 +110,15 @@ storiesOf('Button').addWithInfo(
<div>
<h2>This is a JSX info section</h2>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed ornare massa rutrum metus commodo, a mattis velit dignissim.
Fusce vestibulum turpis sed massa egestas pharetra. Sed at libero
nulla.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ornare massa rutrum metus
commodo, a mattis velit dignissim. Fusce vestibulum turpis sed massa egestas pharetra. Sed at
libero nulla.
</p>
<p>
<a href="https://github.com/storybooks/react-storybook-addon-info">
This is a link
</a>
<a href="https://github.com/storybooks/react-storybook-addon-info">This is a link</a>
</p>
<p>
<img src="http://placehold.it/350x150" />
<img alt="350x150" src="http://placehold.it/350x150" />
</p>
</div>,
() => <Button label="The Button" onClick={action('onClick')} />,
@ -182,11 +171,11 @@ storiesOf('Button').addWithInfo(
() => <Button label="The Button" onClick={action('onClick')} />,
{
inline: true,
styles: stylesheet => {
stylesheet.infoPage = {
styles: stylesheet => ({
...stylesheet,
infoPage: {
backgroundColor: '#ccc',
};
return stylesheet;
},
},
}),
}
);

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-info",
"version": "3.4.0-alpha.0",
"version": "3.4.0-alpha.9",
"description": "A Storybook addon to show additional information for your stories.",
"license": "MIT",
"main": "dist/index.js",
@ -15,17 +15,21 @@
"storybook": "start-storybook -p 9010"
},
"dependencies": {
"@storybook/client-logger": "^3.4.0-alpha.0",
"@storybook/components": "^3.4.0-alpha.0",
"@storybook/client-logger": "^3.4.0-alpha.9",
"@storybook/components": "^3.4.0-alpha.9",
"babel-runtime": "^6.26.0",
"glamor": "^2.20.40",
"glamorous": "^4.11.6",
"global": "^4.3.2",
"marksy": "^6.0.3",
"nested-object-assign": "^1.0.1",
"prop-types": "^15.6.0",
"prop-types": "^15.6.1",
"react-addons-create-fragment": "^15.5.3",
"util-deprecate": "^1.0.2"
},
"devDependencies": {
"@storybook/addon-actions": "^3.4.0-alpha.9",
"@storybook/react": "^3.4.0-alpha.9",
"react-test-renderer": "^16.1.0"
},
"peerDependencies": {

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,3 @@
/* eslint-disable no-underscore-dangle */
import PropTypes from 'prop-types';
import React from 'react';

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +0,0 @@
// TODO remove this file once https://github.com/yannickcr/eslint-plugin-react/issues/1389 is solved
const warn = 1;
module.exports = {
rules: { 'react/no-typos': warn },
};

View File

@ -1,13 +1,13 @@
import React from 'react';
import PrettyPropType from './PrettyPropType';
import { TypeInfo } from './proptypes';
import { TypeInfo, getPropTypes } from './proptypes';
const ArrayOf = ({ propType }) => (
<span>
<span>[</span>
<span>
<PrettyPropType propType={propType.value} />
<PrettyPropType propType={getPropTypes(propType)} />
</span>
<span>]</span>
</span>

View File

@ -1,7 +1,13 @@
import React from 'react';
import { TypeInfo } from './proptypes';
import { TypeInfo, getPropTypes } from './proptypes';
const Enum = ({ propType }) => <span>{propType.value.map(({ value }) => value).join(' | ')}</span>;
const Enum = ({ propType }) => (
<span>
{getPropTypes(propType)
.map(({ value }) => value)
.join(' | ')}
</span>
);
Enum.propTypes = {
propType: TypeInfo.isRequired,

View File

@ -1,7 +1,7 @@
import React from 'react';
import { TypeInfo } from './proptypes';
import { TypeInfo, getPropTypes } from './proptypes';
const InstanceOf = ({ propType }) => <span>{propType.value}</span>;
const InstanceOf = ({ propType }) => <span>{getPropTypes(propType)}</span>;
InstanceOf.propTypes = {
propType: TypeInfo.isRequired,

View File

@ -0,0 +1,10 @@
import React from 'react';
import { TypeInfo } from './proptypes';
const Literal = ({ propType }) => <span>{propType.value}</span>;
Literal.propTypes = {
propType: TypeInfo.isRequired,
};
export default Literal;

View File

@ -1,12 +1,12 @@
import React from 'react';
import PrettyPropType from './PrettyPropType';
import { TypeInfo } from './proptypes';
import { TypeInfo, getPropTypes } from './proptypes';
const ObjectOf = ({ propType }) => (
<span>
{'{[<key>]: '}
<PrettyPropType propType={propType.value} />
<PrettyPropType propType={getPropTypes(propType)} />
{'}'}
</span>
);

View File

@ -1,7 +1,12 @@
import React from 'react';
import { TypeInfo } from './proptypes';
import { TypeInfo, getPropTypes } from './proptypes';
const OneOf = ({ propType }) => <span>{propType.value.map(({ value }) => value).join(' | ')}</span>;
const joinValues = propTypes => propTypes.map(({ value }) => value).join(' | ');
const OneOf = ({ propType }) => {
const propTypes = getPropTypes(propType);
return <span>{`oneOf ${Array.isArray(propTypes) ? joinValues(propTypes) : propTypes}`}</span>;
};
OneOf.propTypes = {
propType: TypeInfo.isRequired,

View File

@ -1,20 +1,20 @@
import React from 'react';
import PrettyPropType from './PrettyPropType';
import { TypeInfo } from './proptypes';
import { TypeInfo, getPropTypes } from './proptypes';
const OneOfType = ({ propType }) => {
const { length } = propType.value;
const propTypes = getPropTypes(propType);
return (
<span>
{propType.value
.map((value, i) => [
<PrettyPropType
key={`${value.name}${value.value ? `-${value.value}` : ''}`}
propType={value}
/>,
i < length - 1 ? <span> | </span> : null,
])
{propTypes
.map((value, i) => {
const key = `${value.name}${value.value ? `-${value.value}` : ''}`;
return [
<PrettyPropType key={key} propType={value} />,
i < propTypes.length - 1 ? <span key={`${key}-separator`}> | </span> : null,
];
})
.reduce((acc, tuple) => acc.concat(tuple), [])}
</span>
);

View File

@ -9,6 +9,7 @@ import ObjectOf from './ObjectOf';
import OneOf from './OneOf';
import InstanceOf from './InstanceOf';
import Signature from './Signature';
import Literal from './Literal';
import { TypeInfo } from './proptypes';
@ -20,6 +21,7 @@ const propTypeComponentMap = new Map([
['objectOf', ObjectOf],
// Might be overkill to have below proptypes as separate components *shrug*
['object', ObjectType],
['literal', Literal],
['enum', OneOf],
['instanceOf', InstanceOf],
['signature', Signature],

View File

@ -5,7 +5,7 @@ import { HighlightButton } from '@storybook/components';
import PrettyPropType from './PrettyPropType';
import PropertyLabel from './PropertyLabel';
import { TypeInfo } from './proptypes';
import { TypeInfo, getPropTypes } from './proptypes';
const MARGIN_SIZE = 15;
@ -33,6 +33,7 @@ class Shape extends React.Component {
render() {
const { propType, depth } = this.props;
const propTypes = getPropTypes(propType);
return (
<span>
<HighlightButton
@ -45,13 +46,13 @@ class Shape extends React.Component {
</HighlightButton>
<HighlightButton onClick={this.handleToggle}>...</HighlightButton>
{!this.state.minimized &&
Object.keys(propType.value).map(childProperty => (
Object.keys(propTypes).map(childProperty => (
<div key={childProperty} style={{ marginLeft: depth * MARGIN_SIZE }}>
<PropertyLabel
property={childProperty}
required={propType.value[childProperty].required}
required={propTypes[childProperty].required}
/>
<PrettyPropType depth={depth + 1} propType={propType.value[childProperty]} />
<PrettyPropType depth={depth + 1} propType={propTypes[childProperty]} />
,
</div>
))}

View File

@ -7,3 +7,5 @@ export const TypeInfo = oneOfType([
}),
PropTypes.string,
]);
export const getPropTypes = propType => propType.value || propType.elements;

View File

@ -2,6 +2,8 @@
Brings Jest results in storybook.
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
[![Storybook Jest Addon Demo](@storybook/addon-jest.gif)](https://storybook-addon-jest-example.herokuapp.com/)
> Checkout the above [Live Storybook](https://storybook-addon-jest-example.herokuapp.com/).
@ -113,8 +115,8 @@ storiesOf('MyComponent', module)
### withTests(options)
- **options.results**: [OBJECT] jest output results. *mandatory*
- **filteExt**: [STRING] test file extention. *optionnal*. This allow you to write "MyComponent" and not "MyComponent.test.js". It will be used as regex to find your file results. Default value is `((\\.specs?)|(\\.tests?))?(\\.js)?$`. That mean it will match: MyComponent.js, MyComponent.test.js, MyComponent.tests.js, MyComponent.spec.js, MyComponent.specs.js...
- **options.results**: OBJECT jest output results. *mandatory*
- **filteExt**: STRING test file extention. *optionnal*. This allow you to write "MyComponent" and not "MyComponent.test.js". It will be used as regex to find your file results. Default value is `((\\.specs?)|(\\.tests?))?(\\.js)?$`. That mean it will match: MyComponent.js, MyComponent.test.js, MyComponent.tests.js, MyComponent.spec.js, MyComponent.specs.js...
## TODO

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-jest",
"version": "3.4.0-alpha.0",
"version": "3.4.0-alpha.9",
"description": "React storybook addon that show component jest report",
"keywords": [
"addon",
@ -25,11 +25,12 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/components": "^3.4.0-alpha.0",
"@storybook/components": "^3.4.0-alpha.9",
"babel-runtime": "^6.26.0",
"glamor": "^2.20.40",
"glamorous": "^4.11.2",
"glamorous": "^4.11.6",
"global": "^4.3.2",
"prop-types": "^15.6.0"
"prop-types": "^15.6.1"
},
"peerDependencies": {
"@storybook/addons": "^3.3.0",

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