mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-03 05:04:51 +08:00
Merge branch 'master' into files-knob
This commit is contained in:
commit
ab8a5662dc
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 }}
|
||||
@ -42,6 +45,21 @@ jobs:
|
||||
- addons
|
||||
- app
|
||||
- lib
|
||||
danger:
|
||||
<<: *defaults
|
||||
environment:
|
||||
- TOKEN_HEAD: 49aa9a6549007391dfcef9c76fca32a73560fd8
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
name: "Restore core dependencies cache"
|
||||
keys:
|
||||
- core-dependencies-{{ checksum "yarn.lock" }}
|
||||
- run:
|
||||
name: "Danger"
|
||||
command: |
|
||||
echo $DANGER_GITHUB_API_TOKEN
|
||||
DANGER_GITHUB_API_TOKEN=${TOKEN_HEAD}3 yarn danger ci
|
||||
example-kitchen-sinks:
|
||||
<<: *defaults
|
||||
steps:
|
||||
@ -54,18 +72,9 @@ jobs:
|
||||
name: "Restore core dist cache"
|
||||
keys:
|
||||
- core-dist-{{ .Revision }}
|
||||
- run:
|
||||
name: "Link packages"
|
||||
command: |
|
||||
yarn install
|
||||
- run:
|
||||
name: Workaround for https://github.com/GoogleChrome/puppeteer/issues/290
|
||||
command: sh ./scripts/workaround-puppeteer-issue-290.sh
|
||||
- run:
|
||||
name: "Build official-storybook"
|
||||
command: |
|
||||
cd examples/official-storybook
|
||||
yarn build-storybook
|
||||
- run:
|
||||
name: "Build react kitchen-sink"
|
||||
command: |
|
||||
@ -81,6 +90,39 @@ 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 (smoke test)"
|
||||
command: |
|
||||
@ -97,17 +139,15 @@ jobs:
|
||||
cd examples/angular-cli
|
||||
yarn storybook --smoke-test
|
||||
- run:
|
||||
name: "Run image snapshots"
|
||||
command: yarn test --image
|
||||
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
|
||||
- store_artifacts:
|
||||
path: examples/official-storybook/image-snapshots/__image_snapshots__
|
||||
destination: official_storybook_image_snapshots
|
||||
name: "Run official-storybook (smoke test)"
|
||||
command: |
|
||||
cd examples/official-storybook
|
||||
yarn storybook --smoke-test
|
||||
react-native:
|
||||
<<: *defaults
|
||||
steps:
|
||||
@ -178,10 +218,6 @@ jobs:
|
||||
name: "Restore core dist cache"
|
||||
keys:
|
||||
- core-dist-{{ .Revision }}
|
||||
- run:
|
||||
name: "Link packages"
|
||||
command: |
|
||||
yarn install
|
||||
- run:
|
||||
name: "Lint"
|
||||
command: |
|
||||
@ -198,35 +234,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:
|
||||
@ -279,22 +291,26 @@ workflows:
|
||||
build_accept_deploy:
|
||||
jobs:
|
||||
- build
|
||||
- danger:
|
||||
requires:
|
||||
- build
|
||||
- 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
|
||||
|
@ -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__', '__STORYBOOK_ADDONS_CHANNEL__'],
|
||||
},
|
||||
],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/react-native*/**', '**/REACT_NATIVE*/**', '**/crna*/**'],
|
||||
rules: {
|
||||
'jsx-a11y/accessible-emoji': ignore,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: '**/.storybook/config.js',
|
||||
rules: {
|
||||
'global-require': ignore,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
23
.github/ISSUE_TEMPLATE.md
vendored
23
.github/ISSUE_TEMPLATE.md
vendored
@ -1,4 +1,5 @@
|
||||
### Issue details
|
||||
If you are reporting a bug or requesting support, start here:
|
||||
### Bug or support request summary
|
||||
|
||||
_Please provide issue details here - What did you expect to happen? What happened instead?_
|
||||
|
||||
@ -24,3 +25,23 @@ _(A screencast can be useful for visual bugs, but it is not a substitute for a t
|
||||
```js
|
||||
// code here
|
||||
```
|
||||
End bug report support request - delete the rest below
|
||||
|
||||
|
||||
If you are creating a issue to track work to be completed, start here:
|
||||
### Work summary
|
||||
|
||||
_Please provide a description of the work to be completed here - Include some context as to why something needs to be done and link any related tickets._
|
||||
|
||||
### Where to start
|
||||
|
||||
_Please list the file(s) a contributor needs to figure out where to start work and include any docs or tutorials that may be applicable._
|
||||
|
||||
### Acceptance criteria
|
||||
|
||||
_Please include a checklist of the requirements necessary to close this ticket. The work should be narrowly scoped and limited to a few hours worth by an experienced developer at the most._
|
||||
|
||||
### Who to contact
|
||||
|
||||
_Add yourself and/or people who are familiar with the code changes and requirements. These people should be able to review the completed code._
|
||||
End work issue - please tag this issue with the correct status and type labels
|
||||
|
7
.github/stale.yml
vendored
7
.github/stale.yml
vendored
@ -1,7 +1,7 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 45
|
||||
daysUntilStale: 21
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 15
|
||||
daysUntilClose: 30
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- todo
|
||||
@ -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
|
||||
@ -19,7 +20,7 @@ markComment: >
|
||||
If there are still questions, comments, or bugs, please feel free to continue
|
||||
the discussion. Unfortunately, we don't have time to get to every issue. We
|
||||
are always open to contributions so please send us a pull request if you would
|
||||
like to help. Inactive issues will be closed after 60 days. Thanks!
|
||||
like to help. Inactive issues will be closed after 30 days. Thanks!
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: >
|
||||
Hey there, it's me again! I am going close this issue to help our maintainers
|
||||
|
2
.mailmap
2
.mailmap
@ -12,7 +12,7 @@ Aaron Mc Adam <aaron@aaronmcadam.com>
|
||||
Aruna Herath <aruna@kadira.io> <arunabherath@gmail.com>
|
||||
Arunoda Susiripala <arunoda.susiripala@gmail.com> Arunoda Susiripala <arunoda.susiripala@gmail.com>
|
||||
Benedikt D Valdez <benediktvaldez@users.noreply.github.com> Benedikt D Valdez <benediktvaldez@users.noreply.github.com>
|
||||
Daniel Duan <dduan@squarespace.com> <dduan@yahoo.com>
|
||||
Daniel Duan <dduan@squarespace.com> <dduan@yahoo.com> # github:danielduan, npm:danielduan, twitter:danduan
|
||||
Daniel James <daniel@thzinc.com> <djames@syncromatics.com>
|
||||
Danny Andrews <danny-andrews@users.noreply.github.com> danny@ownlocal.com>
|
||||
Dustin Kane <dkane@athenahealth.com> <dustinpkane@gmail.com>
|
||||
|
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) |+| |+|+|+|
|
1061
CHANGELOG.md
1061
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,6 @@ 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)
|
||||
|
||||
`yarn test --integration`
|
||||
|
||||
This option executes tests from `<rootdir>/integration`.
|
||||
In order for the snapshot-integration tests to be executed properly, examples being tested must be running on their defaults ports, as declared in `integration/examples.test.js`
|
||||
|
||||
Puppeteer is used to launch and grab screenshots of example pages, while jest is used to assert matching images.
|
||||
|
||||
##### CRA-kitchen-sink - Image snapshots using Storyshots
|
||||
|
||||
`yarn test --image`
|
||||
@ -273,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`
|
||||
@ -283,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
|
||||
|
59
README.md
59
README.md
@ -2,8 +2,8 @@
|
||||
|
||||
[](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://snyk.io/test/github/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)
|
||||
@ -64,12 +65,13 @@ For additional help, join us [in our Slack](https://now-examples-slackin-rrirkqo
|
||||
|
||||
## 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
|
||||
|
||||
@ -78,15 +80,44 @@ For additional help, join us [in our Slack](https://now-examples-slackin-rrirkqo
|
||||
|
||||
### 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
|
||||
|
||||
### 4.0.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.4
|
||||
- [React Official](https://release-3-4--storybooks-official.netlify.com)
|
||||
- [Vue](https://release-3-4--storybooks-vue.netlify.com/)
|
||||
- [Angular](https://release-3-4--storybooks-angular.netlify.com/)
|
||||
- [Polymer](https://release-3-4--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
|
||||
|
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>
|
||||
))
|
||||
);
|
32
__mocks__/inject-decorator.ts.txt
Normal file
32
__mocks__/inject-decorator.ts.txt
Normal file
@ -0,0 +1,32 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Store, StoreModule } from '@ngrx/store';
|
||||
import { storiesOf, moduleMetadata } from '@storybook/angular';
|
||||
|
||||
@Component({
|
||||
selector: 'storybook-comp-with-store',
|
||||
template: '<div>{{this.getSotreState()}}</div>',
|
||||
})
|
||||
class WithStoreComponent {
|
||||
private store: Store<any>;
|
||||
|
||||
constructor(store: Store<any>) {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
getSotreState(): string {
|
||||
return this.store === undefined ? 'Store is NOT injected' : 'Store is injected';
|
||||
}
|
||||
}
|
||||
|
||||
storiesOf('ngrx|Store', module)
|
||||
.addDecorator(
|
||||
moduleMetadata({
|
||||
imports: [StoreModule.forRoot({})],
|
||||
declarations: [WithStoreComponent],
|
||||
})
|
||||
)
|
||||
.add('With component', () => {
|
||||
return {
|
||||
component: WithStoreComponent,
|
||||
};
|
||||
});
|
39
__mocks__/inject-decorator.ts.ugly-comments-stories.txt
Normal file
39
__mocks__/inject-decorator.ts.ugly-comments-stories.txt
Normal file
@ -0,0 +1,39 @@
|
||||
/* global window */
|
||||
/* eslint-disable global-require, import/no-dynamic-require */
|
||||
|
||||
import React from 'react';
|
||||
|
||||
@Component({
|
||||
selector: 'storybook-comp-with-store',
|
||||
template: '<div>{{this.getSotreState()}}</div>',
|
||||
})
|
||||
class WithStoreComponent {
|
||||
private store: Store<any>;
|
||||
|
||||
constructor(store: Store<any>) {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
getSotreState(): string {
|
||||
return this.store === undefined ? 'Store is NOT injected' : 'Store is injected';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
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.5",
|
||||
"version": "3.4.0-rc.3",
|
||||
"description": "a11y addon for storybook",
|
||||
"keywords": [
|
||||
"a11y",
|
||||
@ -25,10 +25,16 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/components": "^3.4.0-alpha.5",
|
||||
"@storybook/components": "3.4.0-rc.3",
|
||||
"axe-core": "^2.6.1",
|
||||
"glamorous": "^4.11.4",
|
||||
"prop-types": "^15.6.0"
|
||||
"babel-runtime": "^6.26.0",
|
||||
"glamor": "^2.20.40",
|
||||
"glamorous": "^4.12.1",
|
||||
"prop-types": "^15.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/react": "3.4.0-rc.3",
|
||||
"faker": "^4.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@storybook/addons": "^3.3.0",
|
||||
|
@ -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.5",
|
||||
"version": "3.4.0-rc.3",
|
||||
"description": "Action Logger addon for storybook",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -20,10 +20,14 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/components": "3.4.0-rc.3",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"deep-equal": "^1.0.1",
|
||||
"glamor": "^2.20.40",
|
||||
"glamorous": "^4.12.1",
|
||||
"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.2.1"
|
||||
},
|
||||
|
@ -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';
|
||||
|
@ -2,6 +2,7 @@ import reviver from './reviver';
|
||||
import { muteProperty } from './util';
|
||||
import { CYCLIC_KEY } from './';
|
||||
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const pathReg = /^\$(?:\[(?:\d+|"(?:[^\\"\u0000-\u001f]|\\([\\"/bfnrt]|u[0-9a-zA-Z]{4}))*")])*$/;
|
||||
|
||||
export default function retrocycle(json) {
|
||||
|
@ -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.5",
|
||||
"version": "3.4.0-rc.3",
|
||||
"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,26 +79,41 @@ 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);
|
||||
}
|
||||
});
|
||||
|
||||
this.channel.on('background-unset', () => {
|
||||
this.setState({ backgrounds: [] });
|
||||
api.setQueryParams({ background: null });
|
||||
this.updateIframe('none');
|
||||
});
|
||||
}
|
||||
|
||||
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: 'auto',
|
||||
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.5",
|
||||
"version": "3.4.0-rc.3",
|
||||
"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.5",
|
||||
"version": "3.4.0-rc.3",
|
||||
"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.2.1"
|
||||
"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.5",
|
||||
"version": "3.4.0-rc.3",
|
||||
"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.2",
|
||||
"prop-types": "^15.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/react": "3.4.0-rc.3"
|
||||
},
|
||||
"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)
|
||||
|
||||

|
||||
|
||||
|
@ -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.5",
|
||||
"version": "3.4.0-rc.3",
|
||||
"description": "A Storybook addon to show additional information for your stories.",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
@ -15,18 +15,21 @@
|
||||
"storybook": "start-storybook -p 9010"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/client-logger": "^3.4.0-alpha.5",
|
||||
"@storybook/components": "^3.4.0-alpha.5",
|
||||
"@storybook/client-logger": "3.4.0-rc.3",
|
||||
"@storybook/components": "3.4.0-rc.3",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"glamorous": "^4.11.4",
|
||||
"glamor": "^2.20.40",
|
||||
"glamorous": "^4.12.1",
|
||||
"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-rc.3",
|
||||
"@storybook/react": "3.4.0-rc.3",
|
||||
"react-test-renderer": "^16.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -1,5 +1,3 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
|
@ -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,5 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
const ObjectType = () => <span>{}</span>;
|
||||
|
||||
export default ObjectType;
|
@ -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,5 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
const ObjectType = () => <span>{}</span>;
|
||||
|
||||
export default ObjectType;
|
@ -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,18 +1,18 @@
|
||||
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
|
||||
{propTypes
|
||||
.map((value, i) => {
|
||||
const key = `${value.name}${value.value ? `-${value.value}` : ''}`;
|
||||
return [
|
||||
<PrettyPropType key={key} propType={value} />,
|
||||
i < length - 1 ? <span key={`${key}-separator`}> | </span> : null,
|
||||
i < propTypes.length - 1 ? <span key={`${key}-separator`}> | </span> : null,
|
||||
];
|
||||
})
|
||||
.reduce((acc, tuple) => acc.concat(tuple), [])}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
import ObjectType from './ObjectType';
|
||||
import Shape from './Shape';
|
||||
import OneOfType from './OneOfType';
|
||||
import ArrayOf from './ArrayOf';
|
||||
@ -9,6 +8,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';
|
||||
|
||||
@ -19,7 +19,7 @@ const propTypeComponentMap = new Map([
|
||||
['arrayOf', ArrayOf],
|
||||
['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.5",
|
||||
"version": "3.4.0-rc.3",
|
||||
"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.5",
|
||||
"@storybook/components": "3.4.0-rc.3",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"glamor": "^2.20.40",
|
||||
"glamorous": "^4.11.4",
|
||||
"glamorous": "^4.12.1",
|
||||
"global": "^4.3.2",
|
||||
"prop-types": "^15.6.0"
|
||||
"prop-types": "^15.6.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@storybook/addons": "^3.3.0",
|
||||
|
@ -98,7 +98,7 @@ const Content = glamorous(({ tests, className }) => (
|
||||
<div className={className}>
|
||||
{tests.map(({ name, result }) => {
|
||||
if (!result) {
|
||||
return <NoTests>This story has tests configured, but no file was found</NoTests>;
|
||||
return <NoTests key={name}>This story has tests configured, but no file was found</NoTests>;
|
||||
}
|
||||
|
||||
const successNumber = result.assertionResults.filter(({ status }) => status === 'passed')
|
||||
|
@ -35,7 +35,8 @@ const StackTrace = glamorous(({ trace, className }) => (
|
||||
.join('')
|
||||
.trim()
|
||||
.split(/\n/)
|
||||
.map(i => <div>{i.trim()}</div>)}
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
.map((traceLine, traceLineIndex) => <div key={traceLineIndex}>{traceLine.trim()}</div>)}
|
||||
</details>
|
||||
))({
|
||||
background: 'silver',
|
||||
@ -80,6 +81,11 @@ const createSubgroup = (acc, item, i, list) => {
|
||||
if (!acc.grouped) {
|
||||
acc.grouped = [];
|
||||
}
|
||||
if (!('grouperIndex' in acc)) {
|
||||
acc.grouperIndex = 0;
|
||||
} else {
|
||||
acc.grouperIndex += 1;
|
||||
}
|
||||
|
||||
// start or stop extraction
|
||||
if (acc.startTrigger(item)) {
|
||||
@ -100,15 +106,22 @@ const createSubgroup = (acc, item, i, list) => {
|
||||
|
||||
// on last iteration inject at detected injectionpoint, and group
|
||||
if (i === list.length - 1) {
|
||||
// Provide a "safety net" when Jest returns a partially recognized "group"
|
||||
// (recognized by acc.startTrigger but acc.endTrigger was never found) and
|
||||
// it's the only group in output for a test result. In that case, acc.list
|
||||
// will be empty, so return whatever was found, even if it will be unstyled
|
||||
// and prevent next createSubgroup calls from throwing due to empty lists.
|
||||
acc.list.push(null);
|
||||
|
||||
return acc.list.reduce((eacc, el, ei) => {
|
||||
switch (true) {
|
||||
case acc.injectionPoint === 0 && ei === 0: {
|
||||
// at index 0, inject before
|
||||
return eacc.concat(acc.grouper(acc.grouped)).concat(el);
|
||||
return eacc.concat(acc.grouper(acc.grouped, acc.grouperIndex)).concat(el);
|
||||
}
|
||||
case acc.injectionPoint > 0 && acc.injectionPoint === ei + 1: {
|
||||
// at index > 0, and next index WOULD BE injectionPoint, inject after
|
||||
return eacc.concat(el).concat(acc.grouper(acc.grouped));
|
||||
return eacc.concat(el).concat(acc.grouper(acc.grouped, acc.grouperIndex));
|
||||
}
|
||||
default: {
|
||||
// do not inject
|
||||
@ -150,7 +163,7 @@ const Message = ({ msg }) => {
|
||||
.reduce(createSubgroup, {
|
||||
startTrigger: e => typeof e === 'string' && e.indexOf('Error: ') === 0,
|
||||
endTrigger: e => typeof e === 'string' && e.match('Expected '),
|
||||
grouper: list => <Main msg={list} />,
|
||||
grouper: (list, key) => <Main key={key} msg={list} />,
|
||||
})
|
||||
.reduce(
|
||||
(acc, it) =>
|
||||
@ -161,12 +174,12 @@ const Message = ({ msg }) => {
|
||||
.reduce(createSubgroup, {
|
||||
startTrigger: e => typeof e === 'string' && e.indexOf('Expected ') !== -1,
|
||||
endTrigger: e => typeof e === 'string' && e.match(/^at/),
|
||||
grouper: list => <Sub msg={list} />,
|
||||
grouper: (list, key) => <Sub key={key} msg={list} />,
|
||||
})
|
||||
.reduce(createSubgroup, {
|
||||
startTrigger: e => typeof e === 'string' && e.match(/at(.|\n)+\d+:\d+\)/),
|
||||
endTrigger: () => false,
|
||||
grouper: list => <StackTrace trace={list} />,
|
||||
grouper: (list, key) => <StackTrace key={key} trace={list} />,
|
||||
});
|
||||
|
||||
return <Pre>{data}</Pre>;
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-disable react/no-danger */
|
||||
import React from 'react';
|
||||
import addons from '@storybook/addons';
|
||||
|
||||
|
@ -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.
|
||||
};
|
||||
|
@ -7,20 +7,12 @@
|
||||
[](https://now-examples-slackin-rrirkqohko.now.sh/)
|
||||
[](#backers) [](#sponsors)
|
||||
|
||||
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).
|
||||
|
||||
* * *
|
||||
|
||||
Storybook Addon Knobs allow you to edit React props dynamically using the Storybook UI.
|
||||
You can also use Knobs as a dynamic variable inside stories in [Storybook](https://storybook.js.org).
|
||||
|
||||
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)
|
||||
|
||||
This is how Knobs look like:
|
||||
|
||||
@ -44,6 +36,7 @@ import '@storybook/addon-knobs/register'
|
||||
|
||||
Now, write your stories with knobs.
|
||||
|
||||
### With React
|
||||
```js
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { withKnobs, text, boolean, number } from '@storybook/addon-knobs/react';
|
||||
@ -71,6 +64,40 @@ stories.add('as dynamic variables', () => {
|
||||
});
|
||||
```
|
||||
|
||||
### With Angular
|
||||
```js
|
||||
import { storiesOf } from '@storybook/angular';
|
||||
import { boolean, number, text, withKnobs } from '@storybook/addon-knobs/angular';
|
||||
|
||||
import { Button } from '@storybook/angular/demo';
|
||||
|
||||
const stories = storiesOf('Storybook Knobs', module);
|
||||
|
||||
// "withKnobs" decorator should be applied before the stories using knobs
|
||||
stories.addDecorator(withKnobs);
|
||||
|
||||
// Knobs for Angular props
|
||||
stories.add('with text', () => ({
|
||||
component: Button,
|
||||
props: {
|
||||
text: text('text', 'Hello Button'), // The first param of the knob function has to be exactly the same as the component input.
|
||||
},
|
||||
}));
|
||||
|
||||
```
|
||||
|
||||
Categorize your knobs by assigning them a `groupId`. When a `groupId` exists, tabs will appear in the knobs storybook panel to filter between the groups. Knobs without a `groupId` are automatically categorized into the `ALL` group.
|
||||
```
|
||||
// Knob assigned a groupId.
|
||||
stories.add('as dynamic variables', () => {
|
||||
const groupId = 'GROUP-ID1'
|
||||
const name = text('Name', 'Arunoda Susiripala', groupId);
|
||||
|
||||
const content = `My name is ${name}.`;
|
||||
return (<div>{content}</div>);
|
||||
});
|
||||
```
|
||||
|
||||
> In the case of Vue, use these imports:
|
||||
>
|
||||
> ```js
|
||||
@ -123,10 +150,10 @@ import { text } from '@storybook/addon-knobs/react';
|
||||
|
||||
const label = 'Your Name';
|
||||
const defaultValue = 'Arunoda Susiripala';
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
const value = text(label, defaultValue);
|
||||
const value = text(label, defaultValue, groupId);
|
||||
```
|
||||
|
||||
### boolean
|
||||
|
||||
Allows you to get a boolean value from the user.
|
||||
@ -136,10 +163,10 @@ import { boolean } from '@storybook/addon-knobs/react';
|
||||
|
||||
const label = 'Agree?';
|
||||
const defaultValue = false;
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
const value = boolean(label, defaultValue);
|
||||
const value = boolean(label, defaultValue, groupId);
|
||||
```
|
||||
|
||||
### number
|
||||
|
||||
Allows you to get a number from the user.
|
||||
@ -149,10 +176,15 @@ import { number } from '@storybook/addon-knobs/react';
|
||||
|
||||
const label = 'Age';
|
||||
const defaultValue = 78;
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
const value = number(label, defaultValue);
|
||||
```
|
||||
|
||||
For use with `groupId`, pass the default `options` as the third argument
|
||||
```
|
||||
const value = number(label, defaultValue, {}, groupId);
|
||||
```
|
||||
### number bound by range
|
||||
|
||||
Allows you to get a number from the user using a range slider.
|
||||
@ -168,8 +200,9 @@ const options = {
|
||||
max: 90,
|
||||
step: 1,
|
||||
};
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
const value = number(label, defaultValue, options);
|
||||
const value = number(label, defaultValue, options, groupId);
|
||||
```
|
||||
|
||||
### color
|
||||
@ -181,8 +214,9 @@ import { color } from '@storybook/addon-knobs/react';
|
||||
|
||||
const label = 'Color';
|
||||
const defaultValue = '#ff00ff';
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
const value = color(label, defaultValue);
|
||||
const value = color(label, defaultValue, groupId);
|
||||
```
|
||||
|
||||
### object
|
||||
@ -196,8 +230,9 @@ const label = 'Styles';
|
||||
const defaultValue = {
|
||||
backgroundColor: 'red'
|
||||
};
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
const value = object(label, defaultValue);
|
||||
const value = object(label, defaultValue, groupId);
|
||||
```
|
||||
|
||||
> Make sure to enter valid JSON syntax while editing values inside the knob.
|
||||
@ -210,7 +245,8 @@ Allows you to get an array of strings from the user.
|
||||
import { array } from '@storybook/addon-knobs/react';
|
||||
|
||||
const label = 'Styles';
|
||||
const defaultValue = ['Red']
|
||||
const defaultValue = ['Red'];
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
const value = array(label, defaultValue);
|
||||
```
|
||||
@ -227,6 +263,11 @@ const value = array(label, defaultValue);
|
||||
> const value = array(label, defaultValue, separator);
|
||||
> ```
|
||||
|
||||
For use with `groupId`, pass the default `separator` as the third argument
|
||||
```
|
||||
const value = array(label, defaultValue, ',', groupId);
|
||||
```
|
||||
|
||||
### select
|
||||
|
||||
Allows you to get a value from a select box from the user.
|
||||
@ -241,12 +282,34 @@ const options = {
|
||||
yellow: 'Yellow',
|
||||
};
|
||||
const defaultValue = 'red';
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
const value = select(label, options, defaultValue);
|
||||
const value = select(label, options, defaultValue, groupId);
|
||||
```
|
||||
|
||||
> You can also provide options as an array like this: `['red', 'blue', 'yellow']`
|
||||
|
||||
### selectV2
|
||||
|
||||
In v4 this will replace `select`. The value from the select now uses the values from the `options` object.
|
||||
|
||||
```js
|
||||
import { selectV2 } from '@storybook/addon-knobs';
|
||||
|
||||
const label = 'Colors';
|
||||
const options = {
|
||||
Red: 'red',
|
||||
Blue: 'blue',
|
||||
Yellow: 'yellow',
|
||||
Rainbow: ['red', 'orange', 'etc'],
|
||||
None: null,
|
||||
};
|
||||
const defaultValue = 'Red';
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
const value = selectV2(label, options, defaultValue, groupId);
|
||||
```
|
||||
|
||||
### files
|
||||
|
||||
Allows you to get a value from a file input from the user.
|
||||
@ -271,7 +334,9 @@ import { date } from '@storybook/addon-knobs/react';
|
||||
|
||||
const label = 'Event Date';
|
||||
const defaultValue = new Date('Jan 20 2017');
|
||||
const value = date(label, defaultValue);
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
const value = date(label, defaultValue, groupId);
|
||||
```
|
||||
|
||||
> Note: the default value must not change - e.g., do not do `date('Label', new Date())` or `date('Label')`
|
||||
@ -279,7 +344,7 @@ const value = date(label, defaultValue);
|
||||
The `date` knob returns the selected date as stringified Unix timestamp (e.g. `"1510913096516"`).
|
||||
If your component needs the date in a different form you can wrap the `date` function:
|
||||
|
||||
```
|
||||
```js
|
||||
function myDateKnob(name, defaultValue) {
|
||||
const stringTimestamp = date(name, defaultValue)
|
||||
return new Date(stringTimestamp)
|
||||
@ -295,7 +360,9 @@ import { button } from '@storybook/addon-knobs';
|
||||
|
||||
const label = 'Do Something';
|
||||
const handler = () => doSomething('foobar');
|
||||
button(label, handler);
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
button(label, handler, groupId);
|
||||
```
|
||||
|
||||
### withKnobs vs withKnobsOptions
|
||||
|
@ -36,8 +36,8 @@ stories.add('with all knobs', () => {
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
I'm {name} and I was born on "{moment(dob).format('DD MMM YYYY')}"
|
||||
I like: <ul>{passions.map((p, i) => <li key={i}>{p}</li>)}</ul>
|
||||
I'm {name} and I was born on "{moment(dob).format('DD MMM YYYY')}" I like:{' '}
|
||||
<ul>{passions.map(p => <li key={p}>{p}</li>)}</ul>
|
||||
<p>My favorite number is {favoriteNumber}.</p>
|
||||
<p>My most comfortable room temperature is {comfortTemp} degrees Fahrenheit.</p>
|
||||
<p>When I am happy I look like this: <img src={images[0]} /></p>
|
||||
@ -53,25 +53,33 @@ stories.add('dates Knob', () => {
|
||||
return (
|
||||
<ul style={{ listStyleType: 'none', listStyle: 'none', paddingLeft: '15px' }}>
|
||||
<li>
|
||||
<p><b>Javascript Date</b> default value, passes date value</p>
|
||||
<p>
|
||||
<b>Javascript Date</b> default value, passes date value
|
||||
</p>
|
||||
<blockquote>
|
||||
<code>const myDob = date('My DOB', new Date('July 07 1993'));</code>
|
||||
<pre>// I was born in: "{moment(myDob).format('DD MMM YYYY')}"</pre>
|
||||
<pre>{`// I was born in: "${moment(myDob).format('DD MMM YYYY')}"`}</pre>
|
||||
</blockquote>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>undefined</b> default value passes today's date</p>
|
||||
<p>
|
||||
<b>undefined</b> default value passes today's date
|
||||
</p>
|
||||
<blockquote>
|
||||
<code>const today = date('today');</code>
|
||||
<pre>// Today's date is: "{moment(today).format('DD MMM YYYY')}"</pre>
|
||||
<pre>{`// Today's date is: "${moment(today).format('DD MMM YYYY')}"`}</pre>
|
||||
</blockquote>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>null</b> default value passes null value</p>
|
||||
<p>
|
||||
<b>null</b> default value passes null value
|
||||
</p>
|
||||
<blockquote>
|
||||
<code>const dob = date('DOB', null);</code>
|
||||
<pre>
|
||||
// You were born in: "{dob ? moment(dob).format('DD MMM YYYY') : 'Please select date.'}"
|
||||
{`// You were born in: "${
|
||||
dob ? moment(dob).format('DD MMM YYYY') : 'Please select date.'
|
||||
}"`}
|
||||
</pre>
|
||||
</blockquote>
|
||||
</li>
|
||||
@ -83,9 +91,7 @@ stories.add('dynamic knobs', () => {
|
||||
const showOptional = select('Show optional', ['yes', 'no'], 'yes');
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
{text('compulsary', 'I must be here')}
|
||||
</div>
|
||||
<div>{text('compulsary', 'I must be here')}</div>
|
||||
{showOptional === 'yes' ? <div>{text('optional', 'I can disapear')}</div> : null}
|
||||
</div>
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-knobs",
|
||||
"version": "3.4.0-alpha.5",
|
||||
"version": "3.4.0-rc.3",
|
||||
"description": "Storybook Addon Prop Editor Component",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
@ -15,22 +15,24 @@
|
||||
"storybook": "start-storybook -p 9010"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/components": "3.4.0-rc.3",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"deep-equal": "^1.0.1",
|
||||
"global": "^4.3.2",
|
||||
"insert-css": "^2.0.0",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"moment": "^2.20.1",
|
||||
"prop-types": "^15.6.0",
|
||||
"react-color": "^2.11.4",
|
||||
"react-datetime": "^2.11.1",
|
||||
"moment": "^2.21.0",
|
||||
"prop-types": "^15.6.1",
|
||||
"react-color": "^2.14.0",
|
||||
"react-datetime": "^2.14.0",
|
||||
"react-textarea-autosize": "^5.2.1",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/react": "3.4.0-rc.3",
|
||||
"raw-loader": "^0.5.1",
|
||||
"style-loader": "^0.19.1",
|
||||
"vue": "^2.5.13"
|
||||
"style-loader": "^0.20.3",
|
||||
"vue": "^2.5.16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@storybook/addons": "^3.3.0",
|
||||
|
@ -11,6 +11,7 @@ export default class KnobStore {
|
||||
set(key, value) {
|
||||
this.store[key] = value;
|
||||
this.store[key].used = true;
|
||||
this.store[key].groupId = value.groupId;
|
||||
this.callbacks.forEach(cb => cb());
|
||||
}
|
||||
|
||||
|
7
addons/knobs/src/angular/helpers.js
vendored
7
addons/knobs/src/angular/helpers.js
vendored
@ -86,11 +86,12 @@ const getAnnotatedComponent = ({ componentMeta, component, params, knobStore, ch
|
||||
return KnobWrapperComponent;
|
||||
};
|
||||
|
||||
const createComponentFromTemplate = template => {
|
||||
const createComponentFromTemplate = (template, styles) => {
|
||||
const componentClass = class DynamicComponent {};
|
||||
|
||||
return Component({
|
||||
template,
|
||||
styles,
|
||||
})(componentClass);
|
||||
};
|
||||
|
||||
@ -106,10 +107,10 @@ export function prepareComponent({ getStory, context, channel, knobStore }) {
|
||||
resetKnobs(knobStore, channel);
|
||||
const story = getStory(context);
|
||||
let { component } = story;
|
||||
const { template } = story;
|
||||
const { template, styles } = story;
|
||||
|
||||
if (!component) {
|
||||
component = createComponentFromTemplate(template);
|
||||
component = createComponentFromTemplate(template, styles);
|
||||
}
|
||||
|
||||
const { componentMeta, props, params, moduleMetadata } = getComponentMetadata({
|
||||
|
3
addons/knobs/src/angular/index.js
vendored
3
addons/knobs/src/angular/index.js
vendored
@ -12,12 +12,13 @@ import {
|
||||
array,
|
||||
date,
|
||||
select,
|
||||
selectV2,
|
||||
button,
|
||||
files,
|
||||
manager,
|
||||
} from '../base';
|
||||
|
||||
export { knob, text, boolean, number, color, object, array, date, select, button, files };
|
||||
export { knob, text, boolean, number, color, object, array, date, select, selectV2, button, files };
|
||||
|
||||
export const angularHandler = (channel, knobStore) => getStory => context =>
|
||||
prepareComponent({ getStory, context, channel, knobStore });
|
||||
|
@ -1,3 +1,4 @@
|
||||
import deprecate from 'util-deprecate';
|
||||
import KnobManager from './KnobManager';
|
||||
|
||||
export const manager = new KnobManager();
|
||||
@ -6,15 +7,15 @@ export function knob(name, options) {
|
||||
return manager.knob(name, options);
|
||||
}
|
||||
|
||||
export function text(name, value) {
|
||||
return manager.knob(name, { type: 'text', value });
|
||||
export function text(name, value, groupId) {
|
||||
return manager.knob(name, { type: 'text', value, groupId });
|
||||
}
|
||||
|
||||
export function boolean(name, value) {
|
||||
return manager.knob(name, { type: 'boolean', value });
|
||||
export function boolean(name, value, groupId) {
|
||||
return manager.knob(name, { type: 'boolean', value, groupId });
|
||||
}
|
||||
|
||||
export function number(name, value, options = {}) {
|
||||
export function number(name, value, options = {}, groupId) {
|
||||
const rangeDefaults = {
|
||||
min: 0,
|
||||
max: 10,
|
||||
@ -32,34 +33,41 @@ export function number(name, value, options = {}) {
|
||||
...mergedOptions,
|
||||
type: 'number',
|
||||
value,
|
||||
groupId,
|
||||
};
|
||||
|
||||
return manager.knob(name, finalOptions);
|
||||
}
|
||||
|
||||
export function color(name, value) {
|
||||
return manager.knob(name, { type: 'color', value });
|
||||
export function color(name, value, groupId) {
|
||||
return manager.knob(name, { type: 'color', value, groupId });
|
||||
}
|
||||
|
||||
export function object(name, value) {
|
||||
return manager.knob(name, { type: 'object', value });
|
||||
export function object(name, value, groupId) {
|
||||
return manager.knob(name, { type: 'object', value, groupId });
|
||||
}
|
||||
|
||||
export function select(name, options, value) {
|
||||
return manager.knob(name, { type: 'select', options, value });
|
||||
export const select = deprecate(
|
||||
(name, options, value, groupId) =>
|
||||
manager.knob(name, { type: 'select', options, value, groupId }),
|
||||
'in v4 keys/values of the options argument are reversed'
|
||||
);
|
||||
|
||||
export function selectV2(name, options, value, groupId) {
|
||||
return manager.knob(name, { type: 'select', selectV2: true, options, value, groupId });
|
||||
}
|
||||
|
||||
export function array(name, value, separator = ',') {
|
||||
return manager.knob(name, { type: 'array', value, separator });
|
||||
export function array(name, value, separator = ',', groupId) {
|
||||
return manager.knob(name, { type: 'array', value, separator, groupId });
|
||||
}
|
||||
|
||||
export function date(name, value = new Date()) {
|
||||
export function date(name, value = new Date(), groupId) {
|
||||
const proxyValue = value ? value.getTime() : null;
|
||||
return manager.knob(name, { type: 'date', value: proxyValue });
|
||||
return manager.knob(name, { type: 'date', value: proxyValue, groupId });
|
||||
}
|
||||
|
||||
export function button(name, callback) {
|
||||
return manager.knob(name, { type: 'button', callback, hideLabel: true });
|
||||
export function button(name, callback, groupId) {
|
||||
return manager.knob(name, { type: 'button', callback, hideLabel: true, groupId });
|
||||
}
|
||||
|
||||
export function files(name, accept, value = []) {
|
||||
|
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