mirror of
https://github.com/storybookjs/storybook.git
synced 2025-03-28 05:10:17 +08:00
Merge remote-tracking branch 'storybooks' into addon-actions
This commit is contained in:
commit
a0d5fad45f
1
.babelrc
1
.babelrc
@ -1,6 +1,7 @@
|
||||
{
|
||||
"presets": ["env", "stage-0", "react"],
|
||||
"plugins": [
|
||||
"babel-plugin-macros",
|
||||
["transform-runtime", {
|
||||
"polyfill": false,
|
||||
"regenerator": true
|
||||
|
@ -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
|
||||
|
@ -3,6 +3,6 @@ root = true
|
||||
[*]
|
||||
end_of_line = lf
|
||||
|
||||
[*.{js,json,ts}]
|
||||
[*.{js,json,ts,vue,html}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
71
.eslintrc.js
71
.eslintrc.js
@ -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
24
.github/autolabeler.yml
vendored
Normal 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
1
.github/stale.yml
vendored
@ -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
1
.gitignore
vendored
@ -21,3 +21,4 @@ package-lock.json
|
||||
storybook-static
|
||||
integration/__image_snapshots__/__diff_output__
|
||||
.jest-test-results.json
|
||||
/examples/cra-kitchen-sink/src/__image_snapshots__/__diff_output__/
|
||||
|
17
.remarkrc.js
17
.remarkrc.js
@ -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
19
ADDONS_SUPPORT.md
Normal 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) |+| |+|+|+|
|
1015
CHANGELOG.md
1015
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
15
MIGRATION.md
15
MIGRATION.md
@ -18,7 +18,20 @@
|
||||
|
||||
## From version 3.2.x to 3.3.x
|
||||
|
||||
There should be no breaking changes in this release, but read on if you're using `addon-knobs`: we advise an update to your code for efficiency's sake.
|
||||
There wasn't expected be any breaking changes in this release, but unfortunately it turned out that there are some. We're revisiting our [release strategy](https://github.com/storybooks/storybook/blob/master/RELEASES.md) to follow semver more strictly.
|
||||
Also read on if you're using `addon-knobs`: we advise an update to your code for efficiency's sake.
|
||||
|
||||
### `babel-core` is now a peer dependency ([#2494](https://github.com/storybooks/storybook/pull/2494))
|
||||
|
||||
This affects you if you don't use babel in your project. You may need to add `babel-core` as dev dependency:
|
||||
```
|
||||
npm install --save-dev babel-core
|
||||
```
|
||||
This was done to support different major versions of babel.
|
||||
|
||||
### Base webpack config now contains vital plugins ([#1775](https://github.com/storybooks/storybook/pull/1775))
|
||||
|
||||
This affects you if you use custom webpack config in [Full Control Mode](https://storybook.js.org/configurations/custom-webpack-config/#full-control-mode) while not preserving the plugins from `storybookBaseConfig`. Before `3.3`, preserving them was just a reccomendation, but now it [became](https://github.com/storybooks/storybook/pull/2578) a requirement.
|
||||
|
||||
### Refactored Knobs
|
||||
|
||||
|
53
README.md
53
README.md
@ -3,7 +3,7 @@
|
||||
[](https://circleci.com/gh/storybooks/storybook)
|
||||
[](https://www.codefactor.io/repository/github/storybooks/storybook)
|
||||
[](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
|
||||
[](https://bettercodehub.com/results/storybooks/storybook) [](https://codecov.io/gh/storybooks/storybook)
|
||||
[](https://bettercodehub.com/results/storybooks/storybook) [](https://codecov.io/gh/storybooks/storybook)
|
||||
[](https://now-examples-slackin-rrirkqohko.now.sh/)
|
||||
[](#backers) [](#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
|
||||
|
||||
|
@ -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/) [].(https://now-examples-slackin-rrirkqohko.now.sh/)
|
||||
channel [in our Slack](https://now-examples-slackin-rrirkqohko.now.sh/) [](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.
|
||||
|
||||
|
34
ROADMAP.md
34
ROADMAP.md
@ -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.
|
||||
|
||||
|
15
__mocks__/inject-decorator.angular-stories.txt
Normal file
15
__mocks__/inject-decorator.angular-stories.txt
Normal 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],
|
||||
},
|
||||
}));
|
3
__mocks__/inject-decorator.no-stories.txt
Normal file
3
__mocks__/inject-decorator.no-stories.txt
Normal file
@ -0,0 +1,3 @@
|
||||
while(true) {
|
||||
console.log("it's a kind of magic");
|
||||
}
|
153
__mocks__/inject-decorator.stories.txt
Normal file
153
__mocks__/inject-decorator.stories.txt
Normal 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>
|
||||
))
|
||||
);
|
23
__mocks__/inject-decorator.ugly-comments-stories.txt
Normal file
23
__mocks__/inject-decorator.ugly-comments-stories.txt
Normal 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.
|
||||
*/
|
@ -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',
|
||||
};
|
||||
|
@ -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()} />);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -2,8 +2,4 @@ import Input from './Input';
|
||||
import Label from './Label';
|
||||
import Row from './Row';
|
||||
|
||||
export {
|
||||
Input,
|
||||
Label,
|
||||
Row,
|
||||
};
|
||||
export { Input, Label, Row };
|
||||
|
@ -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} />} />
|
||||
));
|
||||
|
@ -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;
|
||||
|
@ -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} />);
|
||||
|
@ -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 = {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -2,8 +2,4 @@ import Heading from './Heading';
|
||||
import Link from './Link';
|
||||
import Text from './Text';
|
||||
|
||||
export {
|
||||
Heading,
|
||||
Link,
|
||||
Text,
|
||||
};
|
||||
export { Heading, Link, Text };
|
||||
|
@ -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)}...`} />);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
||||

|
||||
|
||||
## Getting started
|
||||
|
@ -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",
|
||||
|
@ -6,10 +6,10 @@ import Report from './Report';
|
||||
|
||||
const styles = {
|
||||
passes: {
|
||||
color: '#2ecc71',
|
||||
color: '#0D6731',
|
||||
},
|
||||
violations: {
|
||||
color: '#e74c3c',
|
||||
color: '#AC2300',
|
||||
},
|
||||
};
|
||||
|
||||
@ -47,11 +47,11 @@ class Panel extends Component {
|
||||
<Tabs
|
||||
tabs={[
|
||||
{
|
||||
label: <span style={styles.violations}>Violations</span>,
|
||||
label: <span style={styles.violations}>{violations.length} Violations</span>,
|
||||
panel: <Report passes={false} items={violations} empty="No a11y violations found." />,
|
||||
},
|
||||
{
|
||||
label: <span style={styles.passes}>Passes</span>,
|
||||
label: <span style={styles.passes}>{passes.length} Passes</span>,
|
||||
panel: <Report passes items={passes} empty="No a11y check passed" />,
|
||||
},
|
||||
]}
|
||||
|
17
addons/a11y/src/components/Report/RerunButton.js
Normal file
17
addons/a11y/src/components/Report/RerunButton.js
Normal file
@ -0,0 +1,17 @@
|
||||
import glamorous from 'glamorous';
|
||||
|
||||
const RerunButton = glamorous.button({
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
border: 'none',
|
||||
borderTop: 'solid 1px rgba(0, 0, 0, 0.2)',
|
||||
borderLeft: 'solid 1px rgba(0, 0, 0, 0.2)',
|
||||
background: 'rgba(255, 255, 255, 0.5)',
|
||||
padding: '5px 10px',
|
||||
borderRadius: '4px 0 0 0',
|
||||
color: 'rgba(0, 0, 0, 0.5)',
|
||||
textTransform: 'uppercase',
|
||||
});
|
||||
|
||||
export default RerunButton;
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import addons from '@storybook/addons';
|
||||
import RerunButton from './RerunButton';
|
||||
import Item from './Item';
|
||||
|
||||
const styles = {
|
||||
@ -17,17 +18,23 @@ const styles = {
|
||||
},
|
||||
};
|
||||
|
||||
function Report({ items, empty, passes }) {
|
||||
if (items.length) {
|
||||
return (
|
||||
function onRerunClick() {
|
||||
const channel = addons.getChannel();
|
||||
channel.emit('addon:a11y:rerun');
|
||||
}
|
||||
|
||||
const Report = ({ items, empty, passes }) => (
|
||||
<Fragment>
|
||||
{items.length ? (
|
||||
<div style={styles.container}>
|
||||
{items.map(item => <Item passes={passes} item={item} key={item.id} />)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <span style={styles.empty}>{empty}</span>;
|
||||
}
|
||||
) : (
|
||||
<span style={styles.empty}>{empty}</span>
|
||||
)}
|
||||
<RerunButton onClick={onRerunClick}>Re-run tests</RerunButton>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
Report.propTypes = {
|
||||
items: PropTypes.arrayOf(
|
||||
|
@ -5,6 +5,7 @@ import { baseFonts } from '@storybook/components';
|
||||
const styles = {
|
||||
container: {
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
...baseFonts,
|
||||
},
|
||||
tabs: {
|
||||
|
@ -15,8 +15,24 @@ class WrapStory extends Component {
|
||||
channel: {},
|
||||
};
|
||||
|
||||
/* eslint-disable react/no-find-dom-node */
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.runA11yCheck = this.runA11yCheck.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { channel } = this.props;
|
||||
channel.on('addon:a11y:rerun', this.runA11yCheck);
|
||||
this.runA11yCheck();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { channel } = this.props;
|
||||
channel.removeListener('addon:a11y:rerun', this.runA11yCheck);
|
||||
}
|
||||
|
||||
/* eslint-disable react/no-find-dom-node */
|
||||
runA11yCheck() {
|
||||
const { channel } = this.props;
|
||||
const wrapper = findDOMNode(this);
|
||||
|
||||
|
@ -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)
|
||||
|
||||

|
||||
|
||||
|
@ -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",
|
||||
|
@ -1 +1 @@
|
||||
require('./dist').register();
|
||||
require('./dist/manager').register();
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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',
|
||||
});
|
||||
|
@ -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';
|
||||
|
@ -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';
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -3,24 +3,22 @@
|
||||
[](https://circleci.com/gh/storybooks/storybook)
|
||||
[](https://www.codefactor.io/repository/github/storybooks/storybook)
|
||||
[](https://snyk.io/test/github/storybooks/storybook/8f36abfd6697e58cd76df3526b52e4b9dc894847)
|
||||
[](https://bettercodehub.com/results/storybooks/storybook) [](https://codecov.io/gh/storybooks/storybook)
|
||||
[](https://bettercodehub.com/results/storybooks/storybook) [](https://codecov.io/gh/storybooks/storybook)
|
||||
[](https://now-examples-slackin-rrirkqohko.now.sh/)
|
||||
[](#backers) [](#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)
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm i --save @storybook/addon-backgrounds
|
||||
npm i -D @storybook/addon-backgrounds
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
@ -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",
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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(
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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');
|
||||
|
@ -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": "*"
|
||||
}
|
||||
|
@ -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 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';
|
||||
```
|
||||
|
||||
|
BIN
addons/events/docs/.DS_Store
vendored
BIN
addons/events/docs/.DS_Store
vendored
Binary file not shown.
@ -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",
|
||||
|
@ -1 +1 @@
|
||||
require('./dist').register();
|
||||
require('./dist/manager').register();
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -1,3 +1 @@
|
||||
export default from './preview';
|
||||
|
||||
export { register } from './manager';
|
||||
|
@ -1,2 +1,3 @@
|
||||
import * as storybook from '@storybook/react';
|
||||
|
||||
storybook.configure(() => require('./stories'), module);
|
||||
|
@ -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
|
||||
}
|
||||
}`));
|
||||
}`)
|
||||
);
|
||||
|
@ -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)
|
||||
|
||||

|
||||
|
||||
|
@ -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": "*"
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
};
|
||||
|
@ -19,7 +19,7 @@ const config = {
|
||||
test: /\.json?$/,
|
||||
loaders: ['json'],
|
||||
include: path.resolve(__dirname, '../'),
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -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)
|
||||
|
||||

|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 160 KiB |
@ -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;
|
||||
|
@ -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;
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
@ -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
@ -1,5 +1,3 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
|
@ -1,46 +1,47 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withTheme } from 'glamorous';
|
||||
import createFragment from 'react-addons-create-fragment';
|
||||
|
||||
const valueStyles = {
|
||||
const getValueStyles = (codeColors = {}) => ({
|
||||
func: {
|
||||
color: '#170',
|
||||
color: codeColors.func || '#170',
|
||||
},
|
||||
|
||||
attr: {
|
||||
color: '#666',
|
||||
color: codeColors.attr || '#666',
|
||||
},
|
||||
|
||||
object: {
|
||||
color: '#666',
|
||||
color: codeColors.object || '#666',
|
||||
},
|
||||
|
||||
array: {
|
||||
color: '#666',
|
||||
color: codeColors.array || '#666',
|
||||
},
|
||||
|
||||
number: {
|
||||
color: '#a11',
|
||||
color: codeColors.number || '#a11',
|
||||
},
|
||||
|
||||
string: {
|
||||
color: '#22a',
|
||||
color: codeColors.string || '#22a',
|
||||
wordBreak: 'break-word',
|
||||
},
|
||||
|
||||
bool: {
|
||||
color: '#a11',
|
||||
color: codeColors.bool || '#a11',
|
||||
},
|
||||
|
||||
empty: {
|
||||
color: '#777',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
function previewArray(val, maxPropArrayLength) {
|
||||
function previewArray(val, maxPropArrayLength, valueStyles) {
|
||||
const items = {};
|
||||
val.slice(0, maxPropArrayLength).forEach((item, i) => {
|
||||
items[`n${i}`] = <PropVal val={item} />;
|
||||
items[`n${i}`] = <PropVal val={item} valueStyles={valueStyles} />;
|
||||
items[`c${i}`] = ', ';
|
||||
});
|
||||
if (val.length > maxPropArrayLength) {
|
||||
@ -51,13 +52,13 @@ function previewArray(val, maxPropArrayLength) {
|
||||
return <span style={valueStyles.array}>[{createFragment(items)}]</span>;
|
||||
}
|
||||
|
||||
function previewObject(val, maxPropObjectKeys) {
|
||||
function previewObject(val, maxPropObjectKeys, valueStyles) {
|
||||
const names = Object.keys(val);
|
||||
const items = {};
|
||||
names.slice(0, maxPropObjectKeys).forEach((name, i) => {
|
||||
items[`k${i}`] = <span style={valueStyles.attr}>{name}</span>;
|
||||
items[`c${i}`] = ': ';
|
||||
items[`v${i}`] = <PropVal val={val[name]} />;
|
||||
items[`v${i}`] = <PropVal val={val[name]} valueStyles={valueStyles} />;
|
||||
items[`m${i}`] = ', ';
|
||||
});
|
||||
if (names.length > maxPropObjectKeys) {
|
||||
@ -74,11 +75,13 @@ function previewObject(val, maxPropObjectKeys) {
|
||||
);
|
||||
}
|
||||
|
||||
export default function PropVal(props) {
|
||||
const { maxPropObjectKeys, maxPropArrayLength, maxPropStringLength } = props;
|
||||
function PropVal(props) {
|
||||
const { maxPropObjectKeys, maxPropArrayLength, maxPropStringLength, theme } = props;
|
||||
let { val } = props;
|
||||
const { codeColors } = theme || {};
|
||||
let braceWrap = true;
|
||||
let content = null;
|
||||
const valueStyles = props.valueStyles || getValueStyles(codeColors);
|
||||
|
||||
if (typeof val === 'number') {
|
||||
content = <span style={valueStyles.number}>{val}</span>;
|
||||
@ -91,7 +94,7 @@ export default function PropVal(props) {
|
||||
} else if (typeof val === 'boolean') {
|
||||
content = <span style={valueStyles.bool}>{`${val}`}</span>;
|
||||
} else if (Array.isArray(val)) {
|
||||
content = previewArray(val, maxPropArrayLength);
|
||||
content = previewArray(val, maxPropArrayLength, valueStyles);
|
||||
} else if (typeof val === 'function') {
|
||||
content = <span style={valueStyles.func}>{val.name ? `${val.name}()` : 'anonymous()'}</span>;
|
||||
} else if (!val) {
|
||||
@ -105,7 +108,7 @@ export default function PropVal(props) {
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
content = previewObject(val, maxPropObjectKeys);
|
||||
content = previewObject(val, maxPropObjectKeys, valueStyles);
|
||||
}
|
||||
|
||||
if (!braceWrap) return content;
|
||||
@ -118,6 +121,8 @@ PropVal.defaultProps = {
|
||||
maxPropObjectKeys: 3,
|
||||
maxPropArrayLength: 3,
|
||||
maxPropStringLength: 50,
|
||||
theme: {},
|
||||
valueStyles: null,
|
||||
};
|
||||
|
||||
PropVal.propTypes = {
|
||||
@ -125,4 +130,19 @@ PropVal.propTypes = {
|
||||
maxPropObjectKeys: PropTypes.number,
|
||||
maxPropArrayLength: PropTypes.number,
|
||||
maxPropStringLength: PropTypes.number,
|
||||
theme: PropTypes.shape({
|
||||
codeColors: PropTypes.object,
|
||||
}),
|
||||
valueStyles: PropTypes.shape({
|
||||
func: PropTypes.object,
|
||||
attr: PropTypes.object,
|
||||
object: PropTypes.object,
|
||||
array: PropTypes.object,
|
||||
number: PropTypes.object,
|
||||
string: PropTypes.object,
|
||||
bool: PropTypes.object,
|
||||
empty: PropTypes.object,
|
||||
}),
|
||||
};
|
||||
|
||||
export default withTheme(PropVal);
|
||||
|
@ -4,6 +4,7 @@ import React, { createElement } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import global from 'global';
|
||||
import { baseFonts } from '@storybook/components';
|
||||
import { ThemeProvider } from 'glamorous';
|
||||
|
||||
import marksy from 'marksy';
|
||||
|
||||
@ -364,11 +365,11 @@ export default class Story extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.showInline) {
|
||||
return this._renderInline();
|
||||
}
|
||||
|
||||
return this._renderOverlay();
|
||||
return (
|
||||
<ThemeProvider theme={this.state.stylesheet}>
|
||||
{this.props.showInline ? this._renderInline() : this._renderOverlay()}
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,21 +52,6 @@ Code.defaultProps = {
|
||||
code: null,
|
||||
};
|
||||
|
||||
export function Pre(props) {
|
||||
const style = {
|
||||
fontSize: '.88em',
|
||||
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
|
||||
backgroundColor: '#fafafa',
|
||||
padding: '.5rem',
|
||||
lineHeight: 1.5,
|
||||
overflowX: 'scroll',
|
||||
};
|
||||
return <pre style={style}>{props.children}</pre>;
|
||||
}
|
||||
|
||||
Pre.propTypes = { children: PropTypes.node };
|
||||
Pre.defaultProps = { children: null };
|
||||
|
||||
export function Blockquote(props) {
|
||||
const style = {
|
||||
fontSize: '1.88em',
|
||||
@ -79,3 +64,5 @@ export function Blockquote(props) {
|
||||
|
||||
Blockquote.propTypes = { children: PropTypes.node };
|
||||
Blockquote.defaultProps = { children: null };
|
||||
|
||||
export { default as Pre } from './pre/pre';
|
||||
|
13
addons/info/src/components/markdown/pre/copy.js
Normal file
13
addons/info/src/components/markdown/pre/copy.js
Normal file
@ -0,0 +1,13 @@
|
||||
/* eslint-disable no-undef */
|
||||
export default function copy(str) {
|
||||
const tmp = document.createElement('TEXTAREA');
|
||||
const focus = document.activeElement;
|
||||
|
||||
tmp.value = str;
|
||||
|
||||
document.body.appendChild(tmp);
|
||||
tmp.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(tmp);
|
||||
focus.focus();
|
||||
}
|
68
addons/info/src/components/markdown/pre/copyButton.js
Normal file
68
addons/info/src/components/markdown/pre/copyButton.js
Normal file
@ -0,0 +1,68 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import glamorous, { withTheme } from 'glamorous';
|
||||
|
||||
const Button = glamorous.button(
|
||||
{
|
||||
overflow: 'hidden',
|
||||
border: '1px solid #eee',
|
||||
borderRadius: 3,
|
||||
backgroundColor: '#FFFFFF',
|
||||
cursor: 'pointer',
|
||||
fontSize: 13,
|
||||
padding: '3px 10px',
|
||||
alignSelf: 'flex-start',
|
||||
|
||||
':hover': {
|
||||
backgroundColor: '#f4f7fa',
|
||||
borderColor: '#ddd',
|
||||
},
|
||||
|
||||
':active': {
|
||||
backgroundColor: '#e9ecef',
|
||||
borderColor: '#ccc',
|
||||
},
|
||||
},
|
||||
props => props.styles
|
||||
);
|
||||
|
||||
const ContentWrapper = glamorous.div(
|
||||
{
|
||||
transition: 'transform .2s ease',
|
||||
height: 16,
|
||||
},
|
||||
props => ({
|
||||
...props.styles,
|
||||
transform: props.toggled ? 'translateY(0px)' : 'translateY(-100%) translateY(-6px)',
|
||||
})
|
||||
);
|
||||
|
||||
function CopyButton(props) {
|
||||
const { copyButton = {}, copyButtonContent } = props.theme;
|
||||
const { toggleText = 'Copied!', text = 'Copy', ...copyButtonStyles } = copyButton;
|
||||
|
||||
return (
|
||||
<Button onClick={props.onClick} styles={copyButtonStyles}>
|
||||
<ContentWrapper styles={copyButtonContent} toggled={props.toggled}>
|
||||
<div style={{ marginBottom: 6 }}>{toggleText}</div>
|
||||
<div>{text}</div>
|
||||
</ContentWrapper>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
CopyButton.propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
toggled: PropTypes.bool,
|
||||
theme: PropTypes.shape({
|
||||
copyButton: PropTypes.object,
|
||||
}),
|
||||
};
|
||||
|
||||
CopyButton.defaultProps = {
|
||||
onClick: () => {},
|
||||
toggled: false,
|
||||
theme: {},
|
||||
};
|
||||
|
||||
export default withTheme(CopyButton);
|
75
addons/info/src/components/markdown/pre/pre.js
Normal file
75
addons/info/src/components/markdown/pre/pre.js
Normal file
@ -0,0 +1,75 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import glamorous, { withTheme } from 'glamorous';
|
||||
|
||||
import CopyButton from './copyButton';
|
||||
import copy from './copy';
|
||||
|
||||
const TOGGLE_TIMEOUT = 1800;
|
||||
|
||||
const StyledPre = glamorous.pre(
|
||||
{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
fontSize: '.88em',
|
||||
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
|
||||
backgroundColor: '#fafafa',
|
||||
padding: '.5rem',
|
||||
lineHeight: 1.5,
|
||||
overflowX: 'scroll',
|
||||
},
|
||||
props => props.styles
|
||||
);
|
||||
|
||||
class Pre extends React.Component {
|
||||
state = {
|
||||
copied: false,
|
||||
};
|
||||
|
||||
setRef = elem => {
|
||||
this.pre = elem;
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
const text = this.pre && this.pre.innerText;
|
||||
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
|
||||
copy(text);
|
||||
this.setState({ copied: true });
|
||||
|
||||
clearTimeout(this.timeout);
|
||||
|
||||
this.timeout = setTimeout(() => {
|
||||
this.setState({ copied: false });
|
||||
}, TOGGLE_TIMEOUT);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { pre } = this.props.theme;
|
||||
|
||||
return (
|
||||
<StyledPre styles={pre}>
|
||||
<div ref={this.setRef}>{this.props.children}</div>
|
||||
<CopyButton onClick={this.handleClick} toggled={this.state.copied} />
|
||||
</StyledPre>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Pre.propTypes = {
|
||||
children: PropTypes.node,
|
||||
theme: PropTypes.shape({
|
||||
pre: PropTypes.object,
|
||||
}),
|
||||
};
|
||||
|
||||
Pre.defaultProps = {
|
||||
children: null,
|
||||
theme: {},
|
||||
};
|
||||
|
||||
export default withTheme(Pre);
|
@ -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 },
|
||||
};
|
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
10
addons/info/src/components/types/Literal.js
Normal file
10
addons/info/src/components/types/Literal.js
Normal 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;
|
@ -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>
|
||||
);
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
);
|
||||
|
@ -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],
|
||||
|
@ -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>
|
||||
))}
|
||||
|
@ -7,3 +7,5 @@ export const TypeInfo = oneOfType([
|
||||
}),
|
||||
PropTypes.string,
|
||||
]);
|
||||
|
||||
export const getPropTypes = propType => propType.value || propType.elements;
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
Brings Jest results in storybook.
|
||||
|
||||
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
|
||||
|
||||
[](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
|
||||
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user