mirror of
https://github.com/storybookjs/storybook.git
synced 2025-03-18 05:02:24 +08:00
Merge branch 'next' into pr/11936
This commit is contained in:
commit
618fc1c34b
55
.babelrc.js
55
.babelrc.js
@ -12,13 +12,30 @@ const withTests = {
|
||||
],
|
||||
};
|
||||
|
||||
// type BabelMode = 'cjs' | 'esm' | 'modern';
|
||||
|
||||
const modules = process.env.BABEL_MODE === 'cjs' ? 'auto' : false;
|
||||
|
||||
// FIXME: optional chaining introduced in chrome 80, not supported by wepback4
|
||||
// https://github.com/webpack/webpack/issues/10227#issuecomment-642734920
|
||||
const targets = process.env.BABEL_MODE === 'modern' ? { chrome: '79' } : 'defaults';
|
||||
|
||||
module.exports = {
|
||||
ignore: [
|
||||
'./lib/codemod/src/transforms/__testfixtures__',
|
||||
'./lib/postinstall/src/__testfixtures__',
|
||||
],
|
||||
presets: [
|
||||
['@babel/preset-env', { shippedProposals: true, useBuiltIns: 'usage', corejs: '3' }],
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
shippedProposals: true,
|
||||
useBuiltIns: 'usage',
|
||||
corejs: '3',
|
||||
targets,
|
||||
modules,
|
||||
},
|
||||
],
|
||||
'@babel/preset-typescript',
|
||||
'@babel/preset-react',
|
||||
'@babel/preset-flow',
|
||||
@ -52,7 +69,16 @@ module.exports = {
|
||||
{
|
||||
test: './lib',
|
||||
presets: [
|
||||
['@babel/preset-env', { shippedProposals: true, useBuiltIns: 'usage', corejs: '3' }],
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
shippedProposals: true,
|
||||
useBuiltIns: 'usage',
|
||||
corejs: '3',
|
||||
modules,
|
||||
targets,
|
||||
},
|
||||
],
|
||||
'@babel/preset-react',
|
||||
],
|
||||
plugins: [
|
||||
@ -71,6 +97,11 @@ module.exports = {
|
||||
{
|
||||
test: [
|
||||
'./lib/node-logger',
|
||||
'./lib/core',
|
||||
'./lib/core-common',
|
||||
'./lib/core-server',
|
||||
'./lib/builder-webpack4',
|
||||
'./lib/builder-webpack5',
|
||||
'./lib/codemod',
|
||||
'./addons/storyshots',
|
||||
'**/src/server/**',
|
||||
@ -83,8 +114,9 @@ module.exports = {
|
||||
shippedProposals: true,
|
||||
useBuiltIns: 'usage',
|
||||
targets: {
|
||||
node: '8.11',
|
||||
node: '10',
|
||||
},
|
||||
modules,
|
||||
corejs: '3',
|
||||
},
|
||||
],
|
||||
@ -104,5 +136,22 @@ module.exports = {
|
||||
test: withTests,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: ['**/virtualModuleEntry.template.js'],
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
shippedProposals: true,
|
||||
useBuiltIns: 'usage',
|
||||
targets: {
|
||||
node: '10',
|
||||
},
|
||||
corejs: '3',
|
||||
modules: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -1,16 +0,0 @@
|
||||
component_depth: 2
|
||||
languages:
|
||||
- javascript
|
||||
|
||||
- name: javascript
|
||||
production:
|
||||
exclude:
|
||||
- .*\.test\.js
|
||||
- .*\/__test__\/.*\.js
|
||||
- .*\/__mock__\/.*\.js
|
||||
- .*\.stories\.js
|
||||
test:
|
||||
include:
|
||||
- .*\.test\.js
|
||||
- .*\/__test__\/.*\.js
|
||||
- .*\.storyshot
|
@ -1,62 +1,116 @@
|
||||
version: 2.1
|
||||
|
||||
aliases:
|
||||
- &defaults
|
||||
executors:
|
||||
sb_node_12_classic:
|
||||
parameters:
|
||||
class:
|
||||
description: The Resource class
|
||||
type: enum
|
||||
enum: ['small', 'medium', 'large', 'xlarge']
|
||||
default: 'medium'
|
||||
working_directory: /tmp/storybook
|
||||
docker:
|
||||
- image: circleci/node:10-browsers
|
||||
- image: circleci/node:12
|
||||
environment:
|
||||
NODE_OPTIONS: --max_old_space_size=3076
|
||||
resource_class: <<parameters.class>>
|
||||
sb_node_12_browsers:
|
||||
parameters:
|
||||
class:
|
||||
description: The Resource class
|
||||
type: enum
|
||||
enum: ['small', 'medium', 'large', 'xlarge']
|
||||
default: 'medium'
|
||||
working_directory: /tmp/storybook
|
||||
docker:
|
||||
- image: circleci/node:12-browsers
|
||||
environment:
|
||||
NODE_OPTIONS: --max_old_space_size=3076
|
||||
resource_class: <<parameters.class>>
|
||||
sb_cypress_6_node_12:
|
||||
parameters:
|
||||
class:
|
||||
description: The Resource class
|
||||
type: enum
|
||||
enum: ['small', 'medium', 'large', 'xlarge']
|
||||
default: 'medium'
|
||||
working_directory: /tmp/storybook
|
||||
docker:
|
||||
# ⚠️ The Cypress docker image is based on Node.js one so be careful when updating it because it can also
|
||||
# cause an upgrade of the Node.
|
||||
- image: cypress/included:6.8.0
|
||||
environment:
|
||||
NODE_OPTIONS: --max_old_space_size=3076
|
||||
resource_class: <<parameters.class>>
|
||||
|
||||
orbs:
|
||||
git-shallow-clone: guitarrapc/git-shallow-clone@2.0.3
|
||||
|
||||
commands:
|
||||
ensure-pr-is-labeled-with:
|
||||
description: 'A command looking for the labels set on the PR associated to this workflow and checking it contains the label given as parameter'
|
||||
parameters:
|
||||
label:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: Check if PR is labeled with "<< parameters.label >>"
|
||||
command: |
|
||||
apt-get -y install jq
|
||||
|
||||
PR_NUMBER=$(echo "$CIRCLE_PULL_REQUEST" | sed "s/.*\/pull\///")
|
||||
echo "PR_NUMBER: $PR_NUMBER"
|
||||
|
||||
API_GITHUB="https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
|
||||
PR_REQUEST_URL="$API_GITHUB/pulls/$PR_NUMBER"
|
||||
PR_RESPONSE=$(curl -H "Authorization: token $GITHUB_TOKEN_STORYBOOK_BOT_READ_REPO" "$PR_REQUEST_URL")
|
||||
|
||||
|
||||
if [ $(echo $PR_RESPONSE | jq '.labels | map(select(.name == "<< parameters.label >>")) | length') -ge 1 ] ||
|
||||
( [ $(echo $PR_RESPONSE | jq '.labels | length') -ge 1 ] && [ "<< parameters.label >>" == "*" ])
|
||||
then
|
||||
echo "🚀 The PR is labelled with '<< parameters.label >>', job will continue!"
|
||||
else
|
||||
echo "🏁 The PR isn't labelled with '<< parameters.label >>' so this job will end at the current step."
|
||||
circleci-agent step halt
|
||||
fi
|
||||
|
||||
jobs:
|
||||
install:
|
||||
<<: *defaults
|
||||
build:
|
||||
executor:
|
||||
class: xlarge
|
||||
name: sb_node_12_classic
|
||||
steps:
|
||||
- checkout
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- restore_cache:
|
||||
name: Restore core dependencies cache
|
||||
name: Restore Yarn cache
|
||||
keys:
|
||||
- core-dependencies-v5-{{ checksum "yarn.lock" }}
|
||||
- core-dependencies-v5-
|
||||
- build-yarn-2-cache-v1--{{ checksum "yarn.lock" }}
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: yarn install
|
||||
- run:
|
||||
name: Check that yarn.lock is not corrupted
|
||||
command: yarn repo-dirty-check
|
||||
- save_cache:
|
||||
name: Cache core dependencies
|
||||
key: core-dependencies-v5-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- node_modules
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths:
|
||||
- node_modules
|
||||
- examples
|
||||
- addons
|
||||
- dev-kits
|
||||
- app
|
||||
- lib
|
||||
build:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
command: yarn install --immutable
|
||||
- run:
|
||||
name: Bootstrap
|
||||
command: yarn bootstrap --core
|
||||
- save_cache:
|
||||
name: Save Yarn cache
|
||||
key: build-yarn-2-cache-v1--{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- ~/.yarn/berry/cache
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths:
|
||||
- examples
|
||||
- node_modules
|
||||
- addons
|
||||
- dev-kits
|
||||
- app
|
||||
- lib
|
||||
chromatic:
|
||||
<<: *defaults
|
||||
parallelism: 11
|
||||
executor: sb_node_12_browsers
|
||||
parallelism: 4
|
||||
steps:
|
||||
# Keep using default checkout because Chromatic needs some git history to work properly
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
@ -65,9 +119,12 @@ jobs:
|
||||
command: |
|
||||
yarn run-chromatics
|
||||
packtracker:
|
||||
<<: *defaults
|
||||
executor:
|
||||
class: medium
|
||||
name: sb_node_12_browsers
|
||||
steps:
|
||||
- checkout
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
@ -76,10 +133,13 @@ jobs:
|
||||
cd examples/official-storybook
|
||||
yarn packtracker
|
||||
examples:
|
||||
<<: *defaults
|
||||
parallelism: 11
|
||||
executor:
|
||||
class: medium
|
||||
name: sb_node_12_browsers
|
||||
parallelism: 4
|
||||
steps:
|
||||
- checkout
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
@ -91,9 +151,12 @@ jobs:
|
||||
paths:
|
||||
- built-storybooks
|
||||
publish:
|
||||
<<: *defaults
|
||||
executor:
|
||||
class: medium
|
||||
name: sb_node_12_classic
|
||||
steps:
|
||||
- checkout
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
@ -103,15 +166,24 @@ jobs:
|
||||
root: .
|
||||
paths:
|
||||
- .verdaccio-cache
|
||||
examples-v2:
|
||||
docker:
|
||||
- image: cypress/included:4.7.0
|
||||
environment:
|
||||
TERM: xterm
|
||||
working_directory: /tmp/storybook
|
||||
parallelism: 10
|
||||
e2e-tests-extended:
|
||||
executor:
|
||||
class: medium
|
||||
name: sb_cypress_6_node_12
|
||||
parallelism: 4
|
||||
steps:
|
||||
- checkout
|
||||
- when:
|
||||
condition:
|
||||
and:
|
||||
- not:
|
||||
equal: [main, << pipeline.git.branch >>]
|
||||
- not:
|
||||
equal: [next, << pipeline.git.branch >>]
|
||||
steps:
|
||||
- ensure-pr-is-labeled-with:
|
||||
label: 'run e2e extended test suite'
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
@ -119,58 +191,95 @@ jobs:
|
||||
command: yarn local-registry --port 6000 --open
|
||||
background: true
|
||||
- run:
|
||||
name: wait for registry
|
||||
name: Wait for registry
|
||||
command: yarn wait-on http://localhost:6000
|
||||
- run:
|
||||
name: set registry
|
||||
command: yarn config set registry http://localhost:6000/
|
||||
- run:
|
||||
name: test local registry
|
||||
command: yarn info @storybook/core
|
||||
- run:
|
||||
name: run e2e tests
|
||||
command: yarn test:e2e-framework
|
||||
name: Run E2E tests
|
||||
command: yarn test:e2e-framework --clean --all --skip angular11 --skip angular --skip vue3 --skip web_components_typescript --skip cra
|
||||
no_output_timeout: 5m
|
||||
- store_artifacts:
|
||||
path: /tmp/storybook/cypress
|
||||
path: /tmp/cypress-record
|
||||
destination: cypress
|
||||
examples-v2-yarn-2:
|
||||
docker:
|
||||
- image: cypress/included:4.7.0
|
||||
environment:
|
||||
TERM: xterm
|
||||
working_directory: /tmp/storybook
|
||||
# parallelism: 10
|
||||
e2e-tests-core:
|
||||
executor:
|
||||
class: medium
|
||||
name: sb_cypress_6_node_12
|
||||
parallelism: 2
|
||||
steps:
|
||||
- checkout
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: running local registry
|
||||
name: Running local registry
|
||||
command: yarn local-registry --port 6000 --open
|
||||
background: true
|
||||
- run:
|
||||
name: wait for registry
|
||||
name: Wait for registry
|
||||
command: yarn wait-on http://localhost:6000
|
||||
- run:
|
||||
name: set registry
|
||||
command: yarn config set registry http://localhost:6000/
|
||||
name: Run E2E tests
|
||||
# Do not test CRA here because it's done in PnP part
|
||||
# TODO: Remove `web_components_typescript` as soon as Lit 2 stable is released
|
||||
command: yarn test:e2e-framework vue3 angular angular11 web_components_typescript web_components_lit2
|
||||
no_output_timeout: 5m
|
||||
- store_artifacts:
|
||||
path: /tmp/cypress-record
|
||||
destination: cypress
|
||||
cra-bench:
|
||||
executor:
|
||||
class: medium
|
||||
name: sb_cypress_6_node_12
|
||||
working_directory: /tmp/storybook
|
||||
steps:
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: test local registry
|
||||
command: yarn info @storybook/core
|
||||
name: Running local registry
|
||||
command: yarn local-registry --port 6000 --open
|
||||
background: true
|
||||
- run:
|
||||
name: Wait for registry
|
||||
command: yarn wait-on http://localhost:6000
|
||||
- run:
|
||||
name: Run @storybook/bench on a CRA project
|
||||
command: |
|
||||
cd ..
|
||||
npx create-react-app cra-bench
|
||||
cd cra-bench
|
||||
npx @storybook/bench 'npx sb init' --label cra --extra-flags "--modern"
|
||||
e2e-tests-pnp:
|
||||
executor:
|
||||
class: medium
|
||||
name: sb_cypress_6_node_12
|
||||
working_directory: /tmp/storybook
|
||||
steps:
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: Running local registry
|
||||
command: yarn local-registry --port 6000 --open
|
||||
background: true
|
||||
- run:
|
||||
name: Wait for registry
|
||||
command: yarn wait-on http://localhost:6000
|
||||
- run:
|
||||
name: run e2e tests
|
||||
command: yarn test:e2e-framework --use-yarn-2 cra
|
||||
command: yarn test:e2e-framework --pnp sfcVue cra
|
||||
- store_artifacts:
|
||||
path: /tmp/storybook/cypress
|
||||
path: /tmp/cypress-record
|
||||
destination: cypress
|
||||
e2e:
|
||||
working_directory: /tmp/storybook
|
||||
docker:
|
||||
- image: cypress/included:4.7.0
|
||||
environment:
|
||||
TERM: xterm
|
||||
e2e-tests-examples:
|
||||
executor:
|
||||
class: small
|
||||
name: sb_cypress_6_node_12
|
||||
steps:
|
||||
- checkout
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
@ -182,15 +291,21 @@ jobs:
|
||||
command: yarn await-serve-storybooks
|
||||
- run:
|
||||
name: cypress run
|
||||
command: yarn test:e2e
|
||||
command: yarn test:e2e-examples
|
||||
- store_artifacts:
|
||||
path: /tmp/storybook/cypress
|
||||
path: /tmp/cypress-record
|
||||
destination: cypress
|
||||
|
||||
smoke-tests:
|
||||
<<: *defaults
|
||||
executor:
|
||||
class: medium
|
||||
name: sb_node_12_browsers
|
||||
environment:
|
||||
# Disable ESLint when running smoke tests to improve perf + As of CRA 4.0.3, CRA kitchen sinks are throwing
|
||||
# because of some ESLint warnings, related to: https://github.com/facebook/create-react-app/pull/10590
|
||||
DISABLE_ESLINT_PLUGIN: 'true'
|
||||
steps:
|
||||
- checkout
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
@ -223,76 +338,65 @@ jobs:
|
||||
command: |
|
||||
cd examples/ember-cli
|
||||
yarn storybook --smoke-test --quiet
|
||||
- run:
|
||||
name: Run marko-cli (smoke test)
|
||||
command: |
|
||||
cd examples/marko-cli
|
||||
yarn storybook --smoke-test --quiet
|
||||
- run:
|
||||
name: Run official-storybook (smoke test)
|
||||
command: |
|
||||
cd examples/official-storybook
|
||||
yarn storybook --smoke-test --quiet
|
||||
- run:
|
||||
name: Run mithril kitchen-sink (smoke test)
|
||||
command: |
|
||||
cd examples/mithril-kitchen-sink
|
||||
yarn storybook --smoke-test --quiet
|
||||
- run:
|
||||
name: Run riot kitchen-sink (smoke test)
|
||||
command: |
|
||||
cd examples/riot-kitchen-sink
|
||||
yarn storybook --smoke-test --quiet
|
||||
- run:
|
||||
name: Run preact kitchen-sink (smoke test)
|
||||
command: |
|
||||
cd examples/preact-kitchen-sink
|
||||
yarn storybook --smoke-test --quiet
|
||||
- run:
|
||||
name: Run cra reac15 (smoke test)
|
||||
name: Run cra react15 (smoke test)
|
||||
command: |
|
||||
cd examples/cra-react15
|
||||
yarn storybook --smoke-test --quiet
|
||||
frontpage:
|
||||
<<: *defaults
|
||||
executor: sb_node_12_browsers
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
name: Restore core dependencies cache
|
||||
keys:
|
||||
- core-dependencies-v5-{{ checksum "yarn.lock" }}
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: yarn bootstrap --install
|
||||
command: yarn install --immutable
|
||||
- run:
|
||||
name: Trigger build
|
||||
command: ./scripts/build-frontpage.js
|
||||
lint:
|
||||
<<: *defaults
|
||||
executor:
|
||||
class: small
|
||||
name: sb_node_12_classic
|
||||
steps:
|
||||
- checkout
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: Lint
|
||||
command: yarn lint
|
||||
test:
|
||||
<<: *defaults
|
||||
unit-tests:
|
||||
executor: sb_node_12_browsers
|
||||
steps:
|
||||
- checkout
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: Test
|
||||
command: yarn test --coverage --w2 --core
|
||||
command: yarn test --coverage --runInBand --ci
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths:
|
||||
- coverage
|
||||
coverage:
|
||||
<<: *defaults
|
||||
executor:
|
||||
class: small
|
||||
name: sb_node_12_browsers
|
||||
steps:
|
||||
- checkout
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: '--depth 1 --verbose'
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
@ -302,17 +406,14 @@ jobs:
|
||||
workflows:
|
||||
test:
|
||||
jobs:
|
||||
- install
|
||||
- build:
|
||||
requires:
|
||||
- install
|
||||
- build
|
||||
- lint:
|
||||
requires:
|
||||
- build
|
||||
- examples:
|
||||
requires:
|
||||
- build
|
||||
- e2e:
|
||||
- e2e-tests-examples:
|
||||
requires:
|
||||
- examples
|
||||
- smoke-tests:
|
||||
@ -321,22 +422,28 @@ workflows:
|
||||
- packtracker:
|
||||
requires:
|
||||
- build
|
||||
- test:
|
||||
- unit-tests:
|
||||
requires:
|
||||
- build
|
||||
- coverage:
|
||||
requires:
|
||||
- test
|
||||
- unit-tests
|
||||
- chromatic:
|
||||
requires:
|
||||
- examples
|
||||
- publish:
|
||||
requires:
|
||||
- build
|
||||
- examples-v2:
|
||||
- e2e-tests-extended:
|
||||
requires:
|
||||
- publish
|
||||
- examples-v2-yarn-2:
|
||||
- e2e-tests-core:
|
||||
requires:
|
||||
- publish
|
||||
- e2e-tests-pnp:
|
||||
requires:
|
||||
- publish
|
||||
- cra-bench:
|
||||
requires:
|
||||
- publish
|
||||
deploy:
|
||||
|
@ -7,7 +7,11 @@ docs/public
|
||||
storybook-static
|
||||
built-storybooks
|
||||
lib/cli/test
|
||||
lib/manager-webpack4/prebuilt
|
||||
lib/manager-webpack5/prebuilt
|
||||
lib/core-server/prebuilt
|
||||
lib/codemod/src/transforms/__testfixtures__
|
||||
lib/components/src/controls/react-editable-json-tree
|
||||
scripts/storage
|
||||
*.bundle.js
|
||||
*.js.map
|
||||
@ -18,7 +22,6 @@ examples/cra-ts-kitchen-sink/*.json
|
||||
examples/cra-ts-kitchen-sink/public/*
|
||||
examples/cra-ts-essentials/*.json
|
||||
examples/cra-ts-essentials/public/*
|
||||
examples/rax-kitchen-sink/src/document/*
|
||||
ember-output
|
||||
.yarn
|
||||
!.remarkrc.js
|
||||
|
@ -1,6 +1,9 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ['@storybook/eslint-config-storybook'],
|
||||
rules: {
|
||||
'@typescript-eslint/ban-ts-comment': 'warn',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
@ -10,8 +13,6 @@ module.exports = {
|
||||
'**/*.test.*',
|
||||
'**/*.stories.*',
|
||||
'**/storyshots/**/stories/**',
|
||||
'docs/src/new-components/lib/StoryLinkWrapper.js',
|
||||
'docs/src/stories/**',
|
||||
],
|
||||
rules: {
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
@ -37,7 +38,9 @@ module.exports = {
|
||||
{
|
||||
files: ['**/*.tsx', '**/*.ts'],
|
||||
rules: {
|
||||
'react/require-default-props': 'off',
|
||||
'react/prop-types': 'off', // we should use types
|
||||
'react/forbid-prop-types': 'off', // we should use types
|
||||
'no-dupe-class-members': 'off', // this is called overloads in typescript
|
||||
},
|
||||
},
|
||||
|
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1 +1 @@
|
||||
.yarn/releases/yarn-*.js linguist-generated=true
|
||||
/.yarn/** linguist-generated
|
||||
|
47
.github/CODEOWNERS
vendored
47
.github/CODEOWNERS
vendored
@ -1,47 +0,0 @@
|
||||
.circleci/ @ndelangen
|
||||
.github/ @danielduan
|
||||
|
||||
/addons/a11y/ @jbovenschen @codebyalex
|
||||
/addons/actions/ @rhalff
|
||||
/addons/backgrounds/ @ndelangen
|
||||
/addons/events/ @z4o4z @ndelangen
|
||||
/addons/graphql/ @mnmtanish
|
||||
/addons/info/ @theinterned @z4o4z @UsulPro @dangreenisrael
|
||||
/addons/jest/ @renaudtertrais
|
||||
/addons/knobs/ @alexandrebodin @theinterned @leonrodenburg @alterx
|
||||
/addons/links/ @ndelangen
|
||||
/addons/notes/ @alexandrebodin
|
||||
/addons/options/ @UsulPro
|
||||
/addons/storyshots/ @igor-dv @thomasbertet
|
||||
/addons/storysource/ @igor-dv
|
||||
/addons/viewport/ @saponifi3d
|
||||
|
||||
/app/angular/ @alterx @igor-dv
|
||||
/app/react/ @xavcz @shilman @thomasbertet
|
||||
/app/vue/ @thomasbertet @kazupon
|
||||
/app/svelte/ @plumpNation
|
||||
|
||||
/docs/ @ndelangen @shilman
|
||||
|
||||
/examples/angular-cli/ @igor-dv @alterx
|
||||
/examples/cra-kitchen-sink/ @ndelangen @UsulPro
|
||||
/examples/cra-ts-kitchen-sink/ @mucsi96
|
||||
/examples/official-storybook/ @UsulPro
|
||||
/examples/vue-kitchen-sink/ @igor-dv @alexandrebodin
|
||||
/examples/svelte-kitchen-sink/ @plumpNation
|
||||
|
||||
/examples-native/crna-kitchen-sink/ @Gongreg
|
||||
|
||||
/lib/addons/ @ndelangen @theinterned
|
||||
/lib/channel-postmessage/ @mnmtanish @ndelangen
|
||||
/lib/channel-websocket/ @mnmtanish @ndelangen
|
||||
/lib/channels/ @mnmtanish @ndelangen
|
||||
/lib/cli/ @ndelangen @shilman @stijnkoopal
|
||||
/lib/client-logger/ @dangreenisrael
|
||||
/lib/codemod/ @aaronmcadam @ndelangen
|
||||
/lib/components/ @ndelangen @tmeasday
|
||||
/lib/core/ @tmeasday @igor-dv @alterx
|
||||
/lib/node-logger/ @dangreenisrael
|
||||
/lib/ui/ @tmeasday @igor-dv @ndelangen
|
||||
|
||||
/scripts/ @ndelangen @igor-dv
|
47
.github/ISSUE_TEMPLATE.md
vendored
47
.github/ISSUE_TEMPLATE.md
vendored
@ -1,47 +0,0 @@
|
||||
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?_
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
_Please provide necessary steps for reproduction of this issue. Describe the exact steps a maintainer has to take to make the problem occur. If the problem is non-trivial to reproduce, please link a repository or provide some code snippets._
|
||||
|
||||
_(A screencast can be useful for visual bugs, but it is not a substitute for a textual description.)_
|
||||
|
||||
### Please specify which version of Storybook and optionally any affected addons that you're running
|
||||
|
||||
- @storybook/react x.x.x
|
||||
- @storybook/addon-something x.x.x
|
||||
|
||||
### Affected platforms
|
||||
|
||||
- _If UI related, please indicate browser, OS, and version_
|
||||
- _If dependency related, please include relevant version numbers_
|
||||
- _If developer tooling related, please include the platform information_
|
||||
|
||||
### Screenshots / Screencast / Code Snippets (Optional)
|
||||
|
||||
```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
|
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,29 +1,17 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
name: Bug report 🐞
|
||||
about: Something is broken and you have a reliable reproduction? Let us know here. For questions, please use "Question" below.
|
||||
labels: needs triage, bug
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
Please create a reproduction by running `npx sb@next repro` and following the instructions. Read our [documentation](https://storybook.js.org/docs/react/contribute/how-to-reproduce) to learn more about creating reproductions.
|
||||
Paste your repository and deployed reproduction here. We prioritize issues with reproductions over those without.
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Code snippets**
|
||||
If applicable, add code samples to help explain your problem.
|
||||
|
||||
**System:**
|
||||
**System**
|
||||
Please paste the results of `npx sb@next info` here.
|
||||
|
||||
**Additional context**
|
||||
|
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Documentation 📚
|
||||
url: https://storybook.js.org/docs/
|
||||
about: Check out the official docs for answers to common questions
|
||||
- name: Questions & discussions 🤔
|
||||
url: https://github.com/storybookjs/storybook/discussions
|
||||
about: Ask questions, request features & discuss RFCs
|
||||
- name: Community Discord 💬
|
||||
url: https://discord.gg/storybook
|
||||
about: Community discussions, interactive support, contributor help
|
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,19 +1,19 @@
|
||||
---
|
||||
name: Feature request
|
||||
name: Feature request 💡
|
||||
about: Suggest an idea for this project
|
||||
|
||||
labels: needs triage, feature request
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
**Is your feature request related to a problem? Please describe**
|
||||
A clear and concise description of the problem. E.g. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
What would you like to see added to Storybook to solve problem?
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
Any alternative solutions or features you've considered.
|
||||
|
||||
**Are you able to assist bring the feature to reality?**
|
||||
**Are you able to assist to bring the feature to reality?**
|
||||
no | yes, I can...
|
||||
|
||||
**Additional context**
|
||||
|
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -12,7 +12,7 @@ If your answer is yes to any of these, please make sure to include it in your PR
|
||||
|
||||
<!--
|
||||
|
||||
Everybody: Please submit all PRs to the `next` branch unless they are specific to current release. Storybook maintainers cherry-pick bug and documentation fixes into the `master` branch as part of the release process, so you shouldn't need to worry about this.
|
||||
Everybody: Please submit all PRs to the `next` branch unless they are specific to the current release. Storybook maintainers cherry-pick bug and documentation fixes into the `master` branch as part of the release process, so you shouldn't need to worry about this.
|
||||
|
||||
Maintainers: Please tag your pull request with at least one of the following:
|
||||
`["cleanup", "BREAKING CHANGE", "feature request", "bug", "documentation", "maintenance", "dependencies", "other"]`
|
||||
|
24
.github/automention.yml
vendored
24
.github/automention.yml
vendored
@ -1,24 +0,0 @@
|
||||
'app: angular': ['kroeder', 'igor-dv', 'MaximSagan']
|
||||
'app: ember': ['gabrielcsapo']
|
||||
'app: html': ['Hypnosphi']
|
||||
'app: marko': ['nm123github']
|
||||
'app: preact': ['BartWaardenburg']
|
||||
'app: rax': ['SoloJiang']
|
||||
'app: svelte': ['rixo', 'plumpNation']
|
||||
'app: vue': ['backbone87', 'elevatebart', 'pksunkara', 'Aaron-Pool', 'pocka']
|
||||
'app: web-components': ['daKmoR']
|
||||
'api: addons': ['ndelangen']
|
||||
'addon: a11y': ['CodeByAlex', 'Armanio', 'jsomsanith']
|
||||
'addon: toolbars': ['shilman']
|
||||
'addon: docs': ['shilman', 'patricklafrance']
|
||||
'addon: knobs': ['leoyli', 'Armanio']
|
||||
'addon: storysource': ['igor-dv', 'libetl']
|
||||
typescript: ['kroeder', 'gaetanmaisse', 'ndelangen', 'emilio-martinez']
|
||||
theming: ['ndelangen', 'domyen']
|
||||
cra: ['mrmckeb']
|
||||
cli: ['Keraito']
|
||||
dependencies: ['ndelangen']
|
||||
'babel / webpack': ['ndelangen', 'igor-dv', 'shilman']
|
||||
'yarn / npm': ['ndelangen', 'tmeasday']
|
||||
'source-loader': ['libetl']
|
||||
documentation: ['jonniebigodes']
|
83
.github/renovate.json5
vendored
Normal file
83
.github/renovate.json5
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
{
|
||||
$schema: 'https://docs.renovatebot.com/renovate-schema.json',
|
||||
extends: ['config:base', 'group:allNonMajor'],
|
||||
prHourlyLimit: 1,
|
||||
prConcurrentLimit: 1,
|
||||
// Custom ignore paths to include our `examples/` directory
|
||||
ignorePaths: [
|
||||
'**/node_modules/**',
|
||||
'**/bower_components/**',
|
||||
'**/vendor/**',
|
||||
'**/__tests__/**',
|
||||
'**/test/**',
|
||||
'**/tests/**',
|
||||
'**/__fixtures__/**',
|
||||
],
|
||||
enabledManagers: ['npm'],
|
||||
// Ignore release notes for non-breaking changes
|
||||
fetchReleaseNotes: false,
|
||||
// Always bump minor/patch to latest
|
||||
rangeStrategy: 'bump',
|
||||
major: {
|
||||
// Replace ranges when there is a major
|
||||
rangeStrategy: 'replace',
|
||||
// Get us the release notes for breaking changes
|
||||
fetchReleaseNotes: true,
|
||||
},
|
||||
packageRules: [
|
||||
// Leave peerDependencies and engines alone
|
||||
{
|
||||
depTypeList: ['peerDependencies', 'engines'],
|
||||
enabled: false,
|
||||
},
|
||||
// Handle patch updates under 0.1.0 as potentially breaking
|
||||
// Workaround for https://github.com/renovatebot/renovate/issues/3588
|
||||
{
|
||||
managers: ['npm'],
|
||||
matchCurrentVersion: '<0.1.0',
|
||||
rangeStrategy: 'replace',
|
||||
groupName: 'maybe breaking patch updates',
|
||||
groupSlug: 'maybe-breaking-patch',
|
||||
// Get us the release notes for potentially breaking changes
|
||||
fetchReleaseNotes: true,
|
||||
},
|
||||
// Handle minor updates under 1.0.0 as potentially breaking
|
||||
// Workaround for https://github.com/renovatebot/renovate/issues/3588
|
||||
{
|
||||
managers: ['npm'],
|
||||
matchCurrentVersion: '<1.0.0 >=0.1.0',
|
||||
minor: {
|
||||
// FIXME: "rangeStrategy": "replace",
|
||||
groupName: 'maybe breaking minor updates',
|
||||
groupSlug: 'maybe-breaking-minor',
|
||||
// Get us the release notes for potentially breaking changes
|
||||
fetchReleaseNotes: true,
|
||||
},
|
||||
},
|
||||
// Group Storybook's linter configs together
|
||||
{
|
||||
packageNames: ['@storybook/eslint-config-storybook', '@storybook/linter-config'],
|
||||
groupName: 'storybook linting',
|
||||
},
|
||||
// Group Puppeteer packages together
|
||||
{
|
||||
packagePatterns: ['^puppeteer', '^@types/puppeteer'],
|
||||
groupName: 'puppeteer',
|
||||
},
|
||||
// Group Acorn packages together
|
||||
{
|
||||
packagePatterns: ['^acorn'],
|
||||
groupName: 'acorn',
|
||||
},
|
||||
// Group React packages together
|
||||
{
|
||||
packageNames: ['react', '@types/react', 'react-dom', '@types/react-dom'],
|
||||
groupName: 'react',
|
||||
},
|
||||
],
|
||||
// Simplifies the PR body
|
||||
prBodyTemplate: '{{{table}}}{{{notes}}}{{{changelogs}}}',
|
||||
prBodyColumns: ['Package', 'Change'],
|
||||
// https://docs.renovatebot.com/merge-confidence/#enabling-and-disabling
|
||||
ignorePresets: ['github>whitesource/merge-confidence:beta'],
|
||||
}
|
1
.github/stale.yml
vendored
1
.github/stale.yml
vendored
@ -11,7 +11,6 @@ exemptLabels:
|
||||
- 'needs review'
|
||||
- 'high priority'
|
||||
- 'good first issue'
|
||||
- dependencies:update
|
||||
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: inactive
|
||||
|
17
.github/workflows/danger-js.yml
vendored
Normal file
17
.github/workflows/danger-js.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled, unlabeled]
|
||||
|
||||
name: Danger JS
|
||||
jobs:
|
||||
dangerJS:
|
||||
name: Danger JS
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Danger JS
|
||||
uses: danger/danger-js@main
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
args: --dangerfile .ci/danger/dangerfile.ts
|
12
.github/workflows/issues.yml
vendored
12
.github/workflows/issues.yml
vendored
@ -1,12 +0,0 @@
|
||||
on: issues
|
||||
name: Automention Issues
|
||||
jobs:
|
||||
automention:
|
||||
name: Automention
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Automention
|
||||
uses: shilman/automention@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
14
.github/workflows/label.yml
vendored
14
.github/workflows/label.yml
vendored
@ -1,14 +0,0 @@
|
||||
on: label
|
||||
name: Dangerfile JS Label
|
||||
jobs:
|
||||
dangerJS:
|
||||
name: Danger JS
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Danger JS
|
||||
uses: danger/danger-js@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
args: --dangerfile .ci/danger/dangerfile.ts
|
@ -1,12 +0,0 @@
|
||||
on: pull_request
|
||||
name: Automention PRs
|
||||
jobs:
|
||||
automention:
|
||||
name: Automention
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Automention
|
||||
uses: shilman/automention@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
@ -1,14 +0,0 @@
|
||||
on: pull_request
|
||||
name: Dangerfile JS Pull
|
||||
jobs:
|
||||
dangerJS:
|
||||
name: Danger JS
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Danger JS
|
||||
uses: danger/danger-js@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
args: --dangerfile .ci/danger/dangerfile.ts
|
60
.github/workflows/tests-cli.yml
vendored
60
.github/workflows/tests-cli.yml
vendored
@ -1,60 +0,0 @@
|
||||
name: CLI tests
|
||||
|
||||
on:
|
||||
push
|
||||
# push:
|
||||
# disabled for now:
|
||||
# https://github.community/t5/GitHub-Actions/Preserve-status-from-previous-action-run/m-p/33821#M1661
|
||||
# paths:
|
||||
# - 'lib/**'
|
||||
# - 'app/**'
|
||||
|
||||
jobs:
|
||||
cli:
|
||||
name: CLI Fixtures
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '10.x'
|
||||
- name: increase filewatcher limit
|
||||
run: |
|
||||
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: node_modules
|
||||
key: build-v2-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
build-v2-${{ env.cache-name }}-
|
||||
build-v2-
|
||||
- name: install, bootstrap
|
||||
run: |
|
||||
yarn bootstrap --core
|
||||
- name: cli
|
||||
run: |
|
||||
yarn test --cli
|
||||
cli-yarn-2:
|
||||
name: CLI Fixtures with Yarn 2
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '10.x'
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: node_modules
|
||||
key: build-v2-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
build-v2-${{ env.cache-name }}-
|
||||
build-v2-
|
||||
- name: install, bootstrap
|
||||
run: |
|
||||
yarn bootstrap --core
|
||||
- name: cli with Yarn 2
|
||||
run: |
|
||||
cd lib/cli
|
||||
yarn test-yarn-2
|
30
.github/workflows/tests-unit.yml
vendored
30
.github/workflows/tests-unit.yml
vendored
@ -7,21 +7,15 @@ jobs:
|
||||
name: Core Unit Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '10.x'
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: node_modules
|
||||
key: build-v2-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
build-v2-${{ env.cache-name }}-
|
||||
build-v2-
|
||||
- name: install, bootstrap
|
||||
run: |
|
||||
yarn bootstrap --core
|
||||
- name: test
|
||||
run: |
|
||||
yarn test --core
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "12.x"
|
||||
cache: yarn
|
||||
- name: install, bootstrap
|
||||
run: |
|
||||
yarn install --immutable
|
||||
yarn bootstrap --core
|
||||
- name: test
|
||||
run: |
|
||||
yarn test --runInBand --ci
|
||||
|
21
.github/workflows/trigger-circle-ci-workflow.yml
vendored
Normal file
21
.github/workflows/trigger-circle-ci-workflow.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: Trigger CircleCI workflow
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
trigger:
|
||||
if: github.event.label.name == 'run e2e extended test suite' && github.event.pull_request.head.repo.fork == false
|
||||
name: Run workflow with all e2e tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Make request to CircleCI
|
||||
run: >
|
||||
curl --request POST
|
||||
--url https://circleci.com/api/v2/project/gh/storybookjs/storybook/pipeline
|
||||
--header 'Circle-Token: '"$CIRCLE_CI_TOKEN"' '
|
||||
--header 'content-type: application/json'
|
||||
--data '{"branch":"${{ github.event.pull_request.head.ref }}"}'
|
||||
env:
|
||||
CIRCLE_CI_TOKEN: ${{ secrets.CIRCLE_CI_TOKEN }}
|
12
.gitignore
vendored
12
.gitignore
vendored
@ -5,7 +5,6 @@ node_modules
|
||||
*.sw*
|
||||
npm-shrinkwrap.json
|
||||
dist
|
||||
ts3.5
|
||||
.tern-port
|
||||
*.DS_Store
|
||||
.cache
|
||||
@ -32,3 +31,14 @@ cypress/screenshots
|
||||
examples/ember-cli/ember-output
|
||||
.verdaccio-cache
|
||||
tsconfig.tsbuildinfo
|
||||
lib/manager-webpack4/prebuilt
|
||||
lib/manager-webpack5/prebuilt
|
||||
examples/angular-cli/addon-jest.testresults.json
|
||||
|
||||
# Yarn stuff
|
||||
/**/.yarn/*
|
||||
!/**/.yarn/releases
|
||||
!/**/.yarn/plugins
|
||||
!/**/.yarn/sdks
|
||||
!/**/.yarn/versions
|
||||
/**/.pnp.*
|
@ -71,7 +71,6 @@ storybook.js.org
|
||||
YuzuJS
|
||||
setImmediate
|
||||
Malte
|
||||
Ubl
|
||||
Katić
|
||||
Domenic
|
||||
Kowal
|
||||
|
31
.teamcity/patches/buildTypes/TestWorkflow.kts
vendored
Normal file
31
.teamcity/patches/buildTypes/TestWorkflow.kts
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
package patches.buildTypes
|
||||
|
||||
import jetbrains.buildServer.configs.kotlin.v2019_2.*
|
||||
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.VcsTrigger
|
||||
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
|
||||
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
|
||||
|
||||
/*
|
||||
This patch script was generated by TeamCity on settings change in UI.
|
||||
To apply the patch, change the buildType with id = 'TestWorkflow'
|
||||
accordingly, and delete the patch script.
|
||||
*/
|
||||
changeBuildType(RelativeId("TestWorkflow")) {
|
||||
triggers {
|
||||
val trigger1 = find<VcsTrigger> {
|
||||
vcs {
|
||||
quietPeriodMode = VcsTrigger.QuietPeriodMode.USE_DEFAULT
|
||||
triggerRules = "-:.teamcity/**"
|
||||
branchFilter = """
|
||||
+:<default>
|
||||
+:next
|
||||
+:main
|
||||
+:pull/*
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
trigger1.apply {
|
||||
quietPeriodMode = VcsTrigger.QuietPeriodMode.DO_NOT_USE
|
||||
}
|
||||
}
|
||||
}
|
154
.teamcity/settings.kts
vendored
154
.teamcity/settings.kts
vendored
@ -46,8 +46,6 @@ project {
|
||||
buildType(E2E)
|
||||
buildType(SmokeTests)
|
||||
buildType(Frontpage)
|
||||
buildType(Docs)
|
||||
buildType(Lint)
|
||||
buildType(Test)
|
||||
buildType(Coverage)
|
||||
|
||||
@ -59,8 +57,6 @@ project {
|
||||
RelativeId("E2E"),
|
||||
RelativeId("SmokeTests"),
|
||||
RelativeId("Frontpage"),
|
||||
RelativeId("Docs"),
|
||||
RelativeId("Lint"),
|
||||
RelativeId("Test"),
|
||||
RelativeId("Coverage")
|
||||
)
|
||||
@ -129,11 +125,10 @@ object Build : BuildType({
|
||||
#!/bin/bash
|
||||
set -e -x
|
||||
|
||||
yarn install
|
||||
yarn repo-dirty-check
|
||||
yarn install --immutable
|
||||
yarn bootstrap --core
|
||||
""".trimIndent()
|
||||
dockerImage = "node:10"
|
||||
dockerImage = "node:12"
|
||||
dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux
|
||||
}
|
||||
}
|
||||
@ -177,7 +172,7 @@ object ExamplesTemplate : Template({
|
||||
scriptContent = """
|
||||
#!/bin/bash
|
||||
set -e -x
|
||||
|
||||
|
||||
yarn install
|
||||
rm -rf built-storybooks
|
||||
mkdir -p built-storybooks
|
||||
@ -319,15 +314,15 @@ object E2E : BuildType({
|
||||
scriptContent = """
|
||||
#!/bin/bash
|
||||
set -e -x
|
||||
|
||||
yarn install
|
||||
|
||||
yarn install --immutable
|
||||
yarn cypress install
|
||||
yarn serve-storybooks &
|
||||
yarn await-serve-storybooks
|
||||
yarn cypress run --reporter teamcity || :
|
||||
yarn ts-node --transpile-only cypress/report-teamcity-metadata.ts || :
|
||||
""".trimIndent()
|
||||
dockerImage = "cypress/base:10.18.1"
|
||||
dockerImage = "cypress/base:12.19.0"
|
||||
dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux
|
||||
}
|
||||
}
|
||||
@ -361,51 +356,48 @@ object SmokeTests : BuildType({
|
||||
}
|
||||
}
|
||||
|
||||
params {
|
||||
// Disable ESLint when running smoke tests to improve perf and as of CRA 4.0.3, CRA kitchen sinks are throwing
|
||||
// because of some ESLint warnings, related to: https://github.com/facebook/create-react-app/pull/10590
|
||||
param("env.DISABLE_ESLINT_PLUGIN", "true")
|
||||
}
|
||||
|
||||
steps {
|
||||
script {
|
||||
scriptContent = """
|
||||
#!/bin/bash
|
||||
set -e -x
|
||||
|
||||
yarn install
|
||||
|
||||
|
||||
yarn install --immutable
|
||||
|
||||
cd examples/cra-kitchen-sink
|
||||
yarn storybook --smoke-test --quiet
|
||||
|
||||
|
||||
cd ../cra-ts-kitchen-sink
|
||||
yarn storybook --smoke-test --quiet
|
||||
|
||||
|
||||
cd ../vue-kitchen-sink
|
||||
yarn storybook --smoke-test --quiet
|
||||
|
||||
|
||||
cd ../svelte-kitchen-sink
|
||||
yarn storybook --smoke-test --quiet
|
||||
|
||||
|
||||
cd ../angular-cli
|
||||
yarn storybook --smoke-test --quiet
|
||||
|
||||
|
||||
cd ../ember-cli
|
||||
yarn storybook --smoke-test --quiet
|
||||
|
||||
cd ../marko-cli
|
||||
yarn storybook --smoke-test --quiet
|
||||
|
||||
|
||||
cd ../official-storybook
|
||||
yarn storybook --smoke-test --quiet
|
||||
|
||||
cd ../mithril-kitchen-sink
|
||||
yarn storybook --smoke-test --quiet
|
||||
|
||||
cd ../riot-kitchen-sink
|
||||
yarn storybook --smoke-test --quiet
|
||||
|
||||
|
||||
cd ../preact-kitchen-sink
|
||||
yarn storybook --smoke-test --quiet
|
||||
|
||||
|
||||
cd ../cra-react15
|
||||
yarn storybook --smoke-test --quiet
|
||||
""".trimIndent()
|
||||
dockerImage = "node:10"
|
||||
dockerImage = "node:12"
|
||||
dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux
|
||||
}
|
||||
}
|
||||
@ -420,11 +412,12 @@ object Frontpage : BuildType({
|
||||
scriptContent = """
|
||||
#!/bin/bash
|
||||
set -e -x
|
||||
|
||||
|
||||
yarn install --immutable
|
||||
yarn bootstrap --install
|
||||
node ./scripts/build-frontpage.js
|
||||
""".trimIndent()
|
||||
dockerImage = "node:10"
|
||||
dockerImage = "node:12"
|
||||
dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux
|
||||
}
|
||||
}
|
||||
@ -433,88 +426,7 @@ object Frontpage : BuildType({
|
||||
vcs {
|
||||
quietPeriodMode = VcsTrigger.QuietPeriodMode.USE_DEFAULT
|
||||
triggerRules = "-:.teamcity/**"
|
||||
branchFilter = "+:master"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
object Docs : BuildType({
|
||||
name = "Docs"
|
||||
type = Type.DEPLOYMENT
|
||||
|
||||
steps {
|
||||
script {
|
||||
workingDir = "docs"
|
||||
scriptContent = """
|
||||
#!/bin/bash
|
||||
set -e -x
|
||||
|
||||
yarn install
|
||||
yarn build
|
||||
""".trimIndent()
|
||||
dockerImage = "node:10"
|
||||
dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux
|
||||
}
|
||||
}
|
||||
|
||||
triggers {
|
||||
vcs {
|
||||
quietPeriodMode = VcsTrigger.QuietPeriodMode.USE_DEFAULT
|
||||
triggerRules = "-:.teamcity/**"
|
||||
branchFilter = """
|
||||
+:<default>
|
||||
+:next
|
||||
+:master
|
||||
+:pull/*
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
object Lint : BuildType({
|
||||
name = "Lint"
|
||||
|
||||
dependencies {
|
||||
dependency(Build) {
|
||||
snapshot {
|
||||
onDependencyFailure = FailureAction.CANCEL
|
||||
}
|
||||
artifacts {
|
||||
artifactRules = "dist.tar.gz!** => ."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
steps {
|
||||
script {
|
||||
scriptContent = """
|
||||
#!/bin/bash
|
||||
set -e -x
|
||||
|
||||
yarn install
|
||||
|
||||
# TODO remove after merging
|
||||
mkdir temp-eslint-teamcity
|
||||
cd temp-eslint-teamcity
|
||||
yarn init -y
|
||||
yarn add -D eslint-teamcity
|
||||
cd ..
|
||||
|
||||
yarn lint:js --format ./temp-eslint-teamcity/node_modules/eslint-teamcity/index.js .
|
||||
yarn lint:md .
|
||||
""".trimIndent()
|
||||
dockerImage = "node:10"
|
||||
dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux
|
||||
}
|
||||
}
|
||||
|
||||
failureConditions {
|
||||
failOnMetricChange {
|
||||
metric = BuildFailureOnMetric.MetricType.INSPECTION_ERROR_COUNT
|
||||
threshold = 0
|
||||
units = BuildFailureOnMetric.MetricUnit.DEFAULT_UNIT
|
||||
comparison = BuildFailureOnMetric.MetricComparison.MORE
|
||||
compareTo = value()
|
||||
branchFilter = "+:main"
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -545,12 +457,13 @@ object Test : BuildType({
|
||||
mkdir temp-jest-teamcity
|
||||
cd temp-jest-teamcity
|
||||
yarn init -y
|
||||
touch yarn.lock
|
||||
yarn add -D jest-teamcity
|
||||
cd ..
|
||||
|
||||
|
||||
yarn jest --coverage -w 2 --reporters=${'$'}PWD/temp-jest-teamcity/node_modules/jest-teamcity
|
||||
""".trimIndent()
|
||||
dockerImage = "node:10"
|
||||
dockerImage = "node:12"
|
||||
dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux
|
||||
}
|
||||
}
|
||||
@ -581,7 +494,7 @@ object Coverage : BuildType({
|
||||
yarn install
|
||||
yarn coverage
|
||||
""".trimIndent()
|
||||
dockerImage = "node:10"
|
||||
dockerImage = "node:12"
|
||||
dockerImagePlatform = ScriptBuildStep.ImagePlatform.Linux
|
||||
}
|
||||
}
|
||||
@ -595,7 +508,6 @@ object TestWorkflow : BuildType({
|
||||
dependencies {
|
||||
snapshot(E2E) {}
|
||||
snapshot(SmokeTests) {}
|
||||
snapshot(Lint) {}
|
||||
snapshot(Coverage) {}
|
||||
}
|
||||
|
||||
@ -606,7 +518,7 @@ object TestWorkflow : BuildType({
|
||||
branchFilter = """
|
||||
+:<default>
|
||||
+:next
|
||||
+:master
|
||||
+:main
|
||||
+:pull/*
|
||||
""".trimIndent()
|
||||
}
|
||||
|
14
.travis.yml
14
.travis.yml
@ -1,14 +0,0 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "10"
|
||||
|
||||
# install:
|
||||
# - yarn install
|
||||
# - yarn bootstrap --core
|
||||
|
||||
script:
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- script: echo "placeholder task"
|
||||
name: "Placeholder task"
|
8
.yarn/plugins/@yarnpkg/plugin-typescript.cjs
generated
vendored
Normal file
8
.yarn/plugins/@yarnpkg/plugin-typescript.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
622
.yarn/releases/yarn-sources.cjs
generated
vendored
Executable file
622
.yarn/releases/yarn-sources.cjs
generated
vendored
Executable file
File diff suppressed because one or more lines are too long
16
.yarnrc.yml
Normal file
16
.yarnrc.yml
Normal file
@ -0,0 +1,16 @@
|
||||
compressionLevel: 0
|
||||
|
||||
enableGlobalCache: true
|
||||
|
||||
nodeLinker: node-modules
|
||||
|
||||
npmRegistryServer: "https://registry.yarnpkg.com"
|
||||
|
||||
plugins:
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
|
||||
spec: "@yarnpkg/plugin-typescript"
|
||||
|
||||
unsafeHttpWhitelist:
|
||||
- localhost
|
||||
|
||||
yarnPath: .yarn/releases/yarn-sources.cjs
|
13180
CHANGELOG.md
13180
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
10235
CHANGELOG.v1-5.md
Normal file
10235
CHANGELOG.v1-5.md
Normal file
File diff suppressed because it is too large
Load Diff
438
CONTRIBUTING.md
438
CONTRIBUTING.md
@ -1,437 +1,5 @@
|
||||
# Contributing to Storybook
|
||||
<h1>Contributing to Storybook</h1>
|
||||
|
||||
Thanks for your interest in improving Storybook! We are a community-driven project and welcome contributions of all kinds: from discussion to documentation to bugfixes to feature improvements.
|
||||
Please refer to our [NEW contributing guide on the Storybook website](https://storybook.js.org/docs/react/contribute/how-to-contribute).
|
||||
|
||||
Please review this document to help to streamline the process and save everyone's precious time.
|
||||
|
||||
This repo uses yarn workspaces, so you should install `yarn` as the package manager. See [installation guide](https://yarnpkg.com/en/docs/install).
|
||||
|
||||
## Issues
|
||||
|
||||
No software is bug-free. So, if you got an issue, follow these steps:
|
||||
|
||||
- Search the [issue list](https://github.com/storybookjs/storybook/issues?utf8=%E2%9C%93&q=) for current and old issues.
|
||||
- If you find an existing issue, please UPVOTE the issue by adding a "thumbs-up reaction". We use this to help prioritize issues!
|
||||
- If none of that is helping, create an issue with the following information:
|
||||
- Clear title (shorter is better).
|
||||
- Describe the issue in clear language.
|
||||
- Share error logs, screenshots and etc.
|
||||
- To speed up the issue fixing process, send us a sample repo with the issue you faced:
|
||||
|
||||
### Testing against `master`
|
||||
|
||||
To test your project against the current latest version of storybook, you can clone the repository and link it with `yarn`. Try following these steps:
|
||||
|
||||
#### 1. Download the latest version of this project, and build it:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/storybookjs/storybook.git
|
||||
cd storybook
|
||||
yarn bootstrap
|
||||
```
|
||||
|
||||
> NOTE: on windows you may need to run `yarn` before `yarn bootstrap`!
|
||||
|
||||
The bootstrap command might ask which sections of the codebase you want to bootstrap. Unless you're going to work with ReactNative or the Documentation, you can keep the default.
|
||||
|
||||
You can also pick directly from CLI:
|
||||
|
||||
```sh
|
||||
yarn bootstrap --core
|
||||
```
|
||||
|
||||
#### 2a. Run unit tests
|
||||
|
||||
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.
|
||||
|
||||
```sh
|
||||
yarn test
|
||||
```
|
||||
|
||||
The options for running tests can be selected from the cli or be passed to `yarn test` with specific parameters. Available modes include `--watch`, `--coverage`, and `--runInBand`, which will respectively run tests in watch mode, output code coverage, and run selected test suites serially in the current process.
|
||||
|
||||
You can use the `--update` flag to update snapshots or screenshots as needed.
|
||||
|
||||
You can also pick suites from CLI. Suites available are listed below.
|
||||
|
||||
##### Core & Examples Tests
|
||||
|
||||
`yarn test --core`
|
||||
|
||||
This option executes tests from `<rootdir>/app/react`, `<rootdir>/app/vue`, and `<rootdir>/lib`.
|
||||
Before the tests are run, the project must be bootstrapped with core. You can accomplish this with `yarn bootstrap --core`
|
||||
|
||||
##### CRA-kitchen-sink - Image snapshots using Storyshots
|
||||
|
||||
`yarn test --image`
|
||||
|
||||
This option executes tests from `<rootdir>/examples/official-storybook`
|
||||
In order for the image snapshots to be correctly generated, you must have a static build of the storybook up-to-date :
|
||||
|
||||
```sh
|
||||
cd examples/official-storybook
|
||||
yarn build-storybook
|
||||
cd ../..
|
||||
yarn test --image
|
||||
```
|
||||
|
||||
Puppeteer is used to launch and grab screenshots of example pages, while jest is used to assert matching images. (just like integration tests)
|
||||
|
||||
#### 2b. Run e2e tests for CLI
|
||||
|
||||
If you made any changes to the `lib/cli` package, the easiest way to verify that it doesn't break anything is to run e2e tests:
|
||||
|
||||
```sh
|
||||
yarn test --cli
|
||||
```
|
||||
|
||||
This will run a bash script located at `lib/cli/test/run_tests.sh`. It will copy the contents of `fixtures` into a temporary `run` directory, run `getstorybook` in each of the subdirectories, and check that storybook starts successfully using `yarn storybook --smoke-test`.
|
||||
|
||||
After that, the `run` directory content will be compared with `snapshots`. You can update the snapshots by passing an `--update` flag:
|
||||
|
||||
```sh
|
||||
yarn test --cli --update
|
||||
```
|
||||
|
||||
In that case, please check the git diff before committing to make sure it only contains the intended changes.
|
||||
|
||||
#### 2c. Run Linter
|
||||
|
||||
We use eslint as a linter for all code (including typescript code).
|
||||
|
||||
All you have to run is:
|
||||
|
||||
```sh
|
||||
yarn lint
|
||||
```
|
||||
|
||||
It can be immensely helpful to get feedback in your editor, if you're using VsCode, you should install the `eslint` plugin and configure it with these settings:
|
||||
|
||||
```plaintext
|
||||
"eslint.autoFixOnSave": true,
|
||||
"eslint.packageManager": "yarn",
|
||||
"eslint.options": {
|
||||
"cache": true,
|
||||
"cacheLocation": ".cache/eslint",
|
||||
"extensions": [".js", ".jsx", ".mjs", ".json", ".ts", ".tsx"]
|
||||
},
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
{"language": "typescript", "autoFix": true },
|
||||
{"language": "typescriptreact", "autoFix": true }
|
||||
],
|
||||
"eslint.alwaysShowStatus": true
|
||||
```
|
||||
|
||||
This should enable auto-fix for all source files, and give linting warnings and errors within your editor.
|
||||
|
||||
### 2d. Run Cypress tests
|
||||
|
||||
First make sure the repo is bootstrapped.
|
||||
|
||||
Then run `yarn build-storybooks`, this creates a static website from all examples.
|
||||
|
||||
Then run `yarn serve-storybooks`, this will run the static site on the port cypress expects.
|
||||
|
||||
Then run `yarn add cypress -W --optional`. When this has completed cypress should be installed on your system. If it is already on your system, this step can be skipped.
|
||||
|
||||
Then run `yarn cypress open` if you want to see the tests run in the UI, or `yarn cypress run` to run the tests headless.
|
||||
|
||||
### Reproductions
|
||||
|
||||
#### In the monorepo
|
||||
|
||||
The best way to help figure out an issue you are having is to produce a minimal reproduction against the `master` branch.
|
||||
|
||||
A good way to do that is using the example `cra-kitchen-sink` app embedded in this repository:
|
||||
|
||||
```sh
|
||||
# Download and build this repository:
|
||||
git clone https://github.com/storybookjs/storybook.git
|
||||
cd storybook
|
||||
yarn bootstrap --core
|
||||
|
||||
# NOTE: on windows you may need to run `yarn` before `yarn bootstrap`!
|
||||
|
||||
# make changes to try and reproduce the problem, such as adding components + stories
|
||||
cd examples/cra-kitchen-sink
|
||||
yarn storybook
|
||||
|
||||
# see if you can see the problem, if so, commit it:
|
||||
git checkout "branch-describing-issue"
|
||||
git add -A
|
||||
git commit -m "reproduction for issue #123"
|
||||
|
||||
# fork the storybook repo to your account, then add the resulting remote
|
||||
git remote add <your-username> https://github.com/<your-username>/storybook.git
|
||||
git push -u <your-username> master
|
||||
```
|
||||
|
||||
If you follow that process, you can then link to the GitHub repository in the issue. See <https://github.com/storybookjs/storybook/issues/708#issuecomment-290589886> for an example.
|
||||
|
||||
**NOTE**: If your issue involves a webpack config, create-react-app will prevent you from modifying the _app's_ webpack config, however, you can still modify storybook's to mirror your app's version of the storybook. Alternatively, use `yarn eject` in the CRA app to get a modifiable webpack config.
|
||||
|
||||
#### Outside the monorepo
|
||||
|
||||
Sometimes your storybook is deeply ingrained in your own setup and it's hard to create a minimal viable reproduction somewhere else.
|
||||
|
||||
Inside the storybook repo we have a script that allows you to test the packages inside this repo in your own separate project.
|
||||
|
||||
You can use `npm link` on all packages, but npm linking is cumbersome and has subtle differences from what happens in a registry-based installation.
|
||||
So the way our script works is that it:
|
||||
|
||||
- sets up a npm registry running on your own local machine
|
||||
- changes your default registry to this local one
|
||||
- builds all packages in the storybook repo
|
||||
- publishes all packages as latest
|
||||
|
||||
Our script leaves the local registry running, for **as long as you keep it running** you can install storybook packages from this local registry.
|
||||
|
||||
- Navigate to your own project and then change `package.json` so the storybook packages match the version of the one you just published.
|
||||
- Then you can install using `yarn` or `npm`
|
||||
- Start using your storybook as normally.
|
||||
|
||||
If you've made a change to storybook's codebase and would want this change to be reflected in your app:
|
||||
|
||||
- Ensure the storybook packages are transpiled, by either having run `yarn dev` or `yarn bootstrap --core`.
|
||||
- Go to the terminal where the local regitry is running and press `<Enter>`. This will kick off a new publish.
|
||||
- Run the install procedure again in your local repo, (you may need to clean out node_modules first).
|
||||
- Restart your storybook.
|
||||
|
||||
### Updating Tests
|
||||
|
||||
Before any contributions are submitted in a PR, make sure to add or update meaningful tests. A PR that has failing tests will be regarded as a “Work in Progress” and will not be merged until all tests pass.
|
||||
When creating new unit test files, the tests should adhere to a particular folder structure and naming convention, as defined below.
|
||||
|
||||
```sh
|
||||
# Proper naming convention and structure for js tests files
|
||||
+-- parentFolder
|
||||
| +-- [filename].js
|
||||
| +-- [filename].test.js
|
||||
```
|
||||
|
||||
## Pull Requests (PRs)
|
||||
|
||||
We welcome all contributions. There are many ways you can help us. This is few of those ways:
|
||||
|
||||
Before you submit a new PR, make sure you run `yarn test`. Do not submit a PR if tests are failing. If you need any help, the best way is to [join the discord server and ask in the maintenance channel](https://discord.gg/sMFvFsG).
|
||||
|
||||
### Reviewing PRs
|
||||
|
||||
**As a PR submitter**, you should reference the issue if there is one, include a short description of what you contributed and, if it is a code change, instructions for how to manually test out the change. This is informally enforced by our [PR template](https://github.com/storybookjs/storybook/blob/master/.github/PULL_REQUEST_TEMPLATE.md). If your PR is reviewed as only needing trivial changes (e.g. small typos etc), and you have commit access then you can merge the PR after making those changes.
|
||||
|
||||
> NOTE: Although the latest stable version of storybook corresponds to the `master` branch, nearly all Storybook development happens in the `next` branch. If you submit a PR, branch off `next` and target your PR to `next`.
|
||||
|
||||
**As a PR reviewer**, you should read through the changes and comment on any potential problems. If you see something cool, a kind word never hurts either! Additionally, you should follow the testing instructions and manually test the changes. If the instructions are missing, unclear, or overly complex, feel free to request better instructions from the submitter. Unless the PR is tagged with the `do not merge` label, if you approve the review and there is no other required discussion or changes, you should also go ahead and merge the PR.
|
||||
|
||||
## Issue Triage
|
||||
|
||||
If you are looking for a way to help the project, triaging issues is a great place to start. Here's how you can help:
|
||||
|
||||
### Responding to issues
|
||||
|
||||
Issues that are tagged `question / support` or `needs reproduction` are great places to help. If you can answer a question, it will help the asker as well as anyone who has a similar question. Also in the future if anyone has that same question they can easily find it by searching. If an issue needs reproduction, you may be able to guide the reporter toward one, or even reproduce it yourself using [this technique](https://github.com/storybookjs/storybook/blob/master/CONTRIBUTING.md#reproductions).
|
||||
|
||||
### Triaging issues
|
||||
|
||||
Once you've helped out on a few issues, if you'd like triage access you can help label issues and respond to reporters.
|
||||
|
||||
We use the following label scheme to categorize issues:
|
||||
|
||||
- **type** - `bug`, `feature`, `question / support`, `discussion`, `dependencies`, `maintenance`.
|
||||
- **area** - `addon: x`, `addons-api`, `stories-api`, `ui`, etc.
|
||||
- **status** - `needs reproduction`, `needs PR`, `in progress`, etc.
|
||||
|
||||
All issues should have a `type` label. `bug`/`feature`/`question`/`discussion` are self-explanatory. `dependencies` is for keeping package dependencies up to date. `maintenance` is a catch-all for any kind of cleanup or refactoring.
|
||||
|
||||
They should also have one or more `area`/`status` labels. We use these labels to filter issues down so we can see all of the issues for a particular area, and keep the total number of open issues under control.
|
||||
|
||||
For example, here is the list of [open, untyped issues](https://github.com/storybookjs/storybook/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20-label%3A%22bug%22%20-label%3A%22discussion%22%20-label%3A%22feature%22%20-label%3A%22maintenance%22%20-label%3A%22question%20%2F%20support%22%20-label%3A%22documentation%22%20-label%3A%22greenkeeper%22), or here is a list of [bugs that have not been modified since 2017-04-01](https://github.com/storybookjs/storybook/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3A%22bug%22%20updated%3A%3C%3D2017-04-01%20). For more info see [searching issues](https://help.github.com/articles/searching-issues/) in the Github docs.
|
||||
|
||||
If an issue is a `bug`, and it doesn't have a clear reproduction that you have personally confirmed, label it `needs reproduction` and ask the author to try and create a reproduction, or have a go yourself.
|
||||
|
||||
### Closing issues
|
||||
|
||||
- Duplicate issues should be closed with a link to the original.
|
||||
- Unreproducible issues should be closed if it's not possible to reproduce them (if the reporter drops offline,
|
||||
it is reasonable to wait 2 weeks before closing).
|
||||
- `bug`s should be labelled `merged` when merged, and be closed when the issue is fixed and released.
|
||||
- `feature`s, `maintenance`s, `greenkeeper`s should be labelled `merged` when merged,
|
||||
and closed when released or if the feature is deemed not appropriate.
|
||||
- `question / support`s should be closed when the question has been answered.
|
||||
If the questioner drops offline, a reasonable period to wait is two weeks.
|
||||
- `discussion`s should be closed at a maintainer's discretion.
|
||||
|
||||
## Development Guide
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Please have the **_latest_** stable versions of the following on your machine
|
||||
|
||||
- node
|
||||
- yarn
|
||||
|
||||
### Initial Setup
|
||||
|
||||
If you run into trouble here, make sure your node, npm, and **_yarn_** are on the latest versions (yarn at least v1.3.2).
|
||||
|
||||
1. `cd ~` (optional)
|
||||
2. `git clone https://github.com/storybookjs/storybook.git` _bonus_: use your own fork for this step
|
||||
3. `cd storybook`
|
||||
4. `yarn bootstrap --core`
|
||||
5. `yarn test --core`
|
||||
6. `yarn dev` _You must have this running for your changes to show up_
|
||||
|
||||
> NOTE: on windows you may need to run `yarn` before `yarn bootstrap` (between steps 3 and 4).
|
||||
|
||||
#### Bootstrapping everything
|
||||
|
||||
_This method is slow_
|
||||
|
||||
1. `yarn bootstrap --all`
|
||||
2. Take a break 🍵
|
||||
3. `yarn test` (to verify everything worked)
|
||||
|
||||
#### Building specific packages
|
||||
|
||||
If you're working on one or a few packages, for every change that you make, you have to rebuild those packages. To make the process easier, there is a CLI command for that:
|
||||
|
||||
- Run `yarn build` to bring you a list of packages to select from. There will be also an option to run in watch mode.
|
||||
- Run `yarn build <package-name>` to build that package specifically. \
|
||||
For the package name, use its short version. Example: for `@storybook/addon-docs`, run `yarn build addon-docs`.
|
||||
- Run `yarn build --all` to build everything.
|
||||
- Add `--watch` to run automatically in watch more if you are either building a selection of packages by name or building all.
|
||||
Example: `yarn build core addon-docs --watch` or `yarn build --all --watch`.
|
||||
|
||||
### Working with the kitchen sink apps
|
||||
|
||||
Within the `examples` folder of the Storybook repo, you will find kitchen sink examples of storybook implementations for the various platforms that storybook supports.
|
||||
|
||||
Not only do these show many of the options and add-ons available, they are also automatically linked to all the development packages. We highly encourage you to use these to develop/test contributions on.
|
||||
|
||||
#### React and Vue
|
||||
|
||||
1. `cd examples/official-storybook`
|
||||
2. `yarn storybook`
|
||||
3. Verify that your local version works
|
||||
|
||||
### Working with your own app
|
||||
|
||||
#### Linking Storybook
|
||||
|
||||
Storybook is broken up into sub-projects that you can install as you need them. For this example, we will be working with `@storybook/react`.
|
||||
**Note:** You need to `yarn link` from inside the subproject you are working on **_NOT_** the storybook root directory
|
||||
|
||||
1. `cd app/react`
|
||||
2. `yarn link`
|
||||
|
||||
#### Connecting Your App To Storybook
|
||||
|
||||
**_Note:_** If you aren't seeing addons after linking storybook, you probably have a versioning issue which can be fixed by linking each addon you want to use.
|
||||
This applies for the kitchen sink apps as well as your own projects.
|
||||
|
||||
_Make sure `yarn dev` is running_
|
||||
|
||||
##### 1. Setup storybook in your project
|
||||
|
||||
First we are going to install storybook, then we are going to link `@storybook/react` into our project. This will replace `node_modules/@storybook/react` with a symlink to our local version of storybook.
|
||||
|
||||
1. `getstorybook`
|
||||
2. `yarn storybook`
|
||||
3. Verify that your local version works
|
||||
|
||||
##### 2. Link
|
||||
|
||||
**_Note_**: This process is the same for `@storybook/vue`, `@storybook/addon-foo`, etc
|
||||
|
||||
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
|
||||
5. `yarn link @storybook/react`
|
||||
6. `yarn storybook`
|
||||
|
||||
#### Verify your local version is working
|
||||
|
||||
You should now have a working storybook dev environment up and running.
|
||||
|
||||
Save and go to `http://localhost:9011` (or wherever storybook is running)
|
||||
|
||||
If you don't see the changes rerun `yarn storybook` again in your sandbox app
|
||||
|
||||
## Release Guide
|
||||
|
||||
This section is for Storybook maintainers who will be creating releases. It assumes:
|
||||
|
||||
- yarn >= 1.3.2
|
||||
- you've yarn linked `pr-log` from <https://github.com/storybookjs/pr-log/pull/2>
|
||||
|
||||
The current manual release sequence is as follows:
|
||||
|
||||
- Generate a changelog and verify the release by hand
|
||||
- Push the changelog to master or the release branch
|
||||
- Clean, build and publish the release
|
||||
- Cut and paste the changelog to the github release page, and mark it as a (pre-) release
|
||||
|
||||
**NOTE:** The very first time you publish a scoped package (`@storybook/x`) you need to make sure that it's package.json contains the following
|
||||
|
||||
```js
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
```
|
||||
|
||||
This sequence applies to both releases and pre-releases, but differs slightly between the two.
|
||||
|
||||
**NOTE: This is a work in progress. Don't try this unless you know what you're doing. We hope to automate this in CI, so this process is designed with that in mind.**
|
||||
|
||||
#### Prerelease:
|
||||
|
||||
```sh
|
||||
# make sure you current with origin/next.
|
||||
git checkout next
|
||||
git status
|
||||
|
||||
# generate changelog and edit as appropriate
|
||||
# generates a Next section
|
||||
yarn changelog:next x.y.z-alpha.a
|
||||
|
||||
# Edit the changelog/PRs as needed, then commit
|
||||
git commit -m "x.y.z-alpha.a changelog"
|
||||
|
||||
# clean build
|
||||
yarn bootstrap --reset --core
|
||||
|
||||
# publish and tag the release
|
||||
yarn run publish:next
|
||||
|
||||
# update the release page
|
||||
open https://github.com/storybookjs/storybook/releases
|
||||
```
|
||||
|
||||
#### Full release:
|
||||
|
||||
```sh
|
||||
# make sure you current with origin/master.
|
||||
git checkout master
|
||||
git status
|
||||
|
||||
# generate changelog and edit as appropriate
|
||||
# generates a vNext section
|
||||
yarn changelog x.y.z
|
||||
|
||||
# Edit the changelog/PRs as needed, then commit
|
||||
git commit -m "x.y.z changelog"
|
||||
|
||||
# clean build
|
||||
yarn bootstrap --reset --core
|
||||
|
||||
# publish and tag the release
|
||||
yarn run publish:latest
|
||||
|
||||
# update the release page
|
||||
open https://github.com/storybookjs/storybook/releases
|
||||
```
|
||||
During the transition, we're also preserving our [OLD, out of date contributing guide](./CONTRIBUTING.old.md) in parallel.
|
||||
|
450
CONTRIBUTING.old.md
Normal file
450
CONTRIBUTING.old.md
Normal file
@ -0,0 +1,450 @@
|
||||
<h1>Contributing to Storybook</h1>
|
||||
|
||||
- [Issues](#issues)
|
||||
- [Testing against `main`](#testing-against-main)
|
||||
- [1. Download the latest version of this project, and build it:](#1-download-the-latest-version-of-this-project-and-build-it)
|
||||
- [2a. Run unit tests](#2a-run-unit-tests)
|
||||
- [Core & Examples Tests](#core--examples-tests)
|
||||
- [2b. Run Linter](#2b-run-linter)
|
||||
- [2c. Run Cypress tests](#2c-run-cypress-tests)
|
||||
- [Reproductions](#reproductions)
|
||||
- [In the monorepo](#in-the-monorepo)
|
||||
- [Outside the monorepo](#outside-the-monorepo)
|
||||
- [Updating Tests](#updating-tests)
|
||||
- [Pull Requests (PRs)](#pull-requests-prs)
|
||||
- [Reviewing PRs](#reviewing-prs)
|
||||
- [Issue Triage](#issue-triage)
|
||||
- [Responding to issues](#responding-to-issues)
|
||||
- [Triaging issues](#triaging-issues)
|
||||
- [Closing issues](#closing-issues)
|
||||
- [Development Guide](#development-guide)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Initial Setup](#initial-setup)
|
||||
- [Bootstrapping everything](#bootstrapping-everything)
|
||||
- [Building specific packages](#building-specific-packages)
|
||||
- [Working with the kitchen sink apps](#working-with-the-kitchen-sink-apps)
|
||||
- [React and Vue](#react-and-vue)
|
||||
- [Working with your own app](#working-with-your-own-app)
|
||||
- [Linking Storybook](#linking-storybook)
|
||||
- [Connecting Your App To Storybook](#connecting-your-app-to-storybook)
|
||||
- [1. Setup storybook in your project](#1-setup-storybook-in-your-project)
|
||||
- [2. Link](#2-link)
|
||||
- [Verify your local version is working](#verify-your-local-version-is-working)
|
||||
- [Documentation](#documentation)
|
||||
- [Release Guide](#release-guide)
|
||||
- [Prerelease:](#prerelease)
|
||||
- [Full release:](#full-release)
|
||||
|
||||
Thanks for your interest in improving Storybook! We are a community-driven project and welcome contributions of all kinds: from discussion to documentation to bugfixes to feature improvements.
|
||||
|
||||
Please review this document to help to streamline the process and save everyone's precious time.
|
||||
|
||||
This repo uses yarn workspaces, so you should install `yarn` as the package manager. See [installation guide](https://yarnpkg.com/en/docs/install).
|
||||
|
||||
## Issues
|
||||
|
||||
No software is bug-free. So, if you got an issue, follow these steps:
|
||||
|
||||
- Search the [issue list](https://github.com/storybookjs/storybook/issues) for current and old issues.
|
||||
- If you find an existing issue, please UPVOTE the issue by adding a "thumbs-up reaction". We use this to help prioritize issues!
|
||||
- If none of that is helping, create an issue with the following information:
|
||||
- Clear title (shorter is better).
|
||||
- Describe the issue in clear language.
|
||||
- Share error logs, screenshots and etc.
|
||||
- To speed up the issue fixing process, send us a sample repo with the issue you faced:
|
||||
|
||||
### Testing against `main`
|
||||
|
||||
To test your project against the current latest version of storybook, you can clone the repository and link it with `yarn`. Try following these steps:
|
||||
|
||||
#### 1. Download the latest version of this project, and build it:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/storybookjs/storybook.git
|
||||
cd storybook
|
||||
yarn bootstrap
|
||||
```
|
||||
|
||||
> **_Note:_** On Windows, you may need to run `yarn` before `yarn bootstrap`!
|
||||
|
||||
The bootstrap command might ask which sections of the codebase you want to bootstrap. Unless you're doing something special you can keep the default.
|
||||
|
||||
You can also pick directly from CLI:
|
||||
|
||||
```sh
|
||||
yarn bootstrap --core
|
||||
```
|
||||
|
||||
#### 2a. Run unit tests
|
||||
|
||||
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.
|
||||
|
||||
```sh
|
||||
yarn test
|
||||
```
|
||||
|
||||
The options for running tests can be selected from the cli or be passed to `yarn test` with specific parameters. Available modes include `--watch`, `--coverage`, and `--runInBand`, which will respectively run tests in watch mode, output code coverage, and run selected test suites serially in the current process.
|
||||
|
||||
You can use the `--update` flag (or `jest -u`) to update snapshots or screenshots as needed.
|
||||
|
||||
> **_Note:_** On Windows, remember to make sure git config `core.autocrlf` is set to false, in order to not override EOL in snapshots ( `git config --global core.autocrlf false` to set it globally). It is also recommended to run tests from WSL2 to avoid errors with unix-style paths.
|
||||
|
||||
You can also pick suites from CLI. Suites available are listed below.
|
||||
|
||||
##### Core & Examples Tests
|
||||
|
||||
`yarn test`
|
||||
|
||||
This option executes tests from `<rootdir>/app/react`, `<rootdir>/app/vue`, and `<rootdir>/lib`.
|
||||
Before the tests are run, the project must be bootstrapped with core. You can accomplish this with `yarn bootstrap --core`
|
||||
|
||||
#### 2b. Run Linter
|
||||
|
||||
We use eslint as a linter for all code (including typescript code).
|
||||
|
||||
All you have to run is:
|
||||
|
||||
```sh
|
||||
yarn lint
|
||||
```
|
||||
|
||||
It can be immensely helpful to get feedback in your editor, if you're using VsCode, you should install the `eslint` plugin and configure it with these settings:
|
||||
|
||||
```json
|
||||
{
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"eslint.packageManager": "yarn",
|
||||
"eslint.options": {
|
||||
"cache": true,
|
||||
"cacheLocation": ".cache/eslint",
|
||||
"extensions": [".js", ".jsx", ".json", ".html", ".ts", ".tsx", ".mjs"]
|
||||
},
|
||||
"eslint.alwaysShowStatus": true
|
||||
}
|
||||
```
|
||||
|
||||
This should enable auto-fix for all source files, and give linting warnings and errors within your editor.
|
||||
|
||||
### 2c. Run Cypress tests
|
||||
|
||||
First make sure the repo is bootstrapped.
|
||||
|
||||
Then run `yarn build-storybooks`, this creates a static website from all examples.
|
||||
|
||||
Then run `yarn serve-storybooks`, this will run the static site on the port cypress expects.
|
||||
|
||||
Then run `yarn add cypress -W --optional`. When this has completed cypress should be installed on your system. If it is already on your system, this step can be skipped.
|
||||
|
||||
Then run `yarn cypress open` if you want to see the tests run in the UI, or `yarn cypress run` to run the tests headless.
|
||||
|
||||
### Reproductions
|
||||
|
||||
#### In the monorepo
|
||||
|
||||
The best way to help figure out an issue you are having is to produce a minimal reproduction against the `main` branch.
|
||||
|
||||
A good way to do that is using the example `cra-kitchen-sink` app embedded in this repository:
|
||||
|
||||
```sh
|
||||
# Download and build this repository:
|
||||
git clone https://github.com/storybookjs/storybook.git
|
||||
cd storybook
|
||||
yarn
|
||||
yarn bootstrap --core
|
||||
|
||||
# make changes to try and reproduce the problem, such as adding components + stories
|
||||
cd examples/cra-kitchen-sink
|
||||
yarn storybook
|
||||
|
||||
# see if you can see the problem, if so, commit it:
|
||||
git checkout "branch-describing-issue"
|
||||
git add -A
|
||||
git commit -m "reproduction for issue #123"
|
||||
|
||||
# fork the storybook repo to your account, then add the resulting remote
|
||||
git remote add <your-username> https://github.com/<your-username>/storybook.git
|
||||
git push -u <your-username> next
|
||||
```
|
||||
|
||||
If you follow that process, you can then link to the GitHub repository in the issue. See <https://github.com/storybookjs/storybook/issues/708#issuecomment-290589886> for an example.
|
||||
|
||||
**_Note:_** If your issue involves a webpack config, create-react-app will prevent you from modifying the _app's_ webpack config, however, you can still modify storybook's to mirror your app's version of the storybook. Alternatively, use `yarn eject` in the CRA app to get a modifiable webpack config.
|
||||
|
||||
#### Outside the monorepo
|
||||
|
||||
Sometimes your storybook is deeply ingrained in your own setup and it's hard to create a minimal viable reproduction somewhere else.
|
||||
|
||||
Inside the storybook repo we have a script that allows you to test the packages inside this repo in your own separate project.
|
||||
|
||||
You can use `npm link` on all packages, but npm linking is cumbersome and has subtle differences from what happens in a registry-based installation.
|
||||
So the way our script works is that it:
|
||||
|
||||
- sets up a npm registry running on your own local machine
|
||||
- changes your default registry to this local one
|
||||
- builds all packages in the storybook repo
|
||||
- publishes all packages as latest
|
||||
|
||||
Our script leaves the local registry running, for **as long as you keep it running** you can install storybook packages from this local registry.
|
||||
|
||||
- Navigate to your own project and then change `package.json` so the storybook packages match the version of the one you just published.
|
||||
- Then you can install using `yarn` or `npm`
|
||||
- Start using your storybook as normally.
|
||||
|
||||
If you've made a change to storybook's codebase and would want this change to be reflected in your app:
|
||||
|
||||
- Ensure the storybook packages are transpiled, by either having run `yarn dev` or `yarn bootstrap --core`.
|
||||
- Go to the terminal where the local registry is running and press `<Enter>`. This will kick off a new publish.
|
||||
- Run the install procedure again in your local repo, (you may need to clean out node_modules first).
|
||||
- Restart your storybook.
|
||||
|
||||
### Updating Tests
|
||||
|
||||
Before any contributions are submitted in a PR, make sure to add or update meaningful tests. A PR that has failing tests will be regarded as a “Work in Progress” and will not be merged until all tests pass.
|
||||
|
||||
When creating new unit test files, the tests should adhere to a particular folder structure and naming convention, as defined below.
|
||||
|
||||
```sh
|
||||
# Proper naming convention and structure for js tests files
|
||||
+-- parentFolder
|
||||
| +-- [filename].js
|
||||
| +-- [filename].test.js
|
||||
```
|
||||
|
||||
## Pull Requests (PRs)
|
||||
|
||||
We welcome all contributions. There are many ways you can help us. This is few of those ways:
|
||||
|
||||
Before you submit a new PR, make sure you run `yarn test`. Do not submit a PR if tests are failing. If you need any help, the best way is to [join the discord server and ask in the maintenance channel](https://discord.gg/storybook).
|
||||
|
||||
### Reviewing PRs
|
||||
|
||||
**As a PR submitter**, you should reference the issue if there is one, include a short description of what you contributed and, if it is a code change, instructions for how to manually test out the change. This is informally enforced by our [PR template](https://github.com/storybookjs/storybook/blob/main/.github/PULL_REQUEST_TEMPLATE.md). If your PR is reviewed as only needing trivial changes (e.g. small typos etc), and you have commit access then you can merge the PR after making those changes.
|
||||
|
||||
> **_Note:_** Although the latest stable version of storybook corresponds to the `main` branch, nearly all Storybook development happens in the `next` branch. If you submit a PR, branch off `next` and target your PR to `next`.
|
||||
|
||||
**As a PR reviewer**, you should read through the changes and comment on any potential problems. If you see something cool, a kind word never hurts either! Additionally, you should follow the testing instructions and manually test the changes. If the instructions are missing, unclear, or overly complex, feel free to request better instructions from the submitter. Unless the PR is tagged with the `do not merge` label, if you approve the review and there is no other required discussion or changes, you should also go ahead and merge the PR.
|
||||
|
||||
## Issue Triage
|
||||
|
||||
If you are looking for a way to help the project, triaging issues is a great place to start. Here's how you can help:
|
||||
|
||||
### Responding to issues
|
||||
|
||||
Issues that are tagged `question / support` or `needs reproduction` are great places to help. If you can answer a question, it will help the asker as well as anyone who has a similar question. Also in the future if anyone has that same question they can easily find it by searching. If an issue needs reproduction, you may be able to guide the reporter toward one, or even reproduce it yourself using [this technique](https://github.com/storybookjs/storybook/blob/main/CONTRIBUTING.md#reproductions).
|
||||
|
||||
### Triaging issues
|
||||
|
||||
Once you've helped out on a few issues, if you'd like triage access you can help label issues and respond to reporters.
|
||||
|
||||
We use the following label scheme to categorize issues:
|
||||
|
||||
- **type** - `bug`, `feature`, `question / support`, `discussion`, `dependencies`, `maintenance`.
|
||||
- **area** - `addon: x`, `addons-api`, `stories-api`, `ui`, etc.
|
||||
- **status** - `needs reproduction`, `needs PR`, `in progress`, etc.
|
||||
|
||||
All issues should have a `type` label. `bug`/`feature`/`question`/`discussion` are self-explanatory. `dependencies` is for keeping package dependencies up to date. `maintenance` is a catch-all for any kind of cleanup or refactoring.
|
||||
|
||||
They should also have one or more `area`/`status` labels. We use these labels to filter issues down so we can see all of the issues for a particular area, and keep the total number of open issues under control.
|
||||
|
||||
For example, here is the list of [open, untyped issues](https://github.com/storybookjs/storybook/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20-label%3A%22bug%22%20-label%3A%22discussion%22%20-label%3A%22feature%22%20-label%3A%22maintenance%22%20-label%3A%22question%20%2F%20support%22%20-label%3A%22documentation%22%20-label%3A%22greenkeeper%22), or here is a list of [bugs that have not been modified since 2017-04-01](https://github.com/storybookjs/storybook/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3A%22bug%22%20updated%3A%3C%3D2017-04-01%20). For more info see [searching issues](https://help.github.com/articles/searching-issues/) in the GitHub docs.
|
||||
|
||||
If an issue is a `bug`, and it doesn't have a clear reproduction that you have personally confirmed, label it `needs reproduction` and ask the author to try and create a reproduction, or have a go yourself.
|
||||
|
||||
### Closing issues
|
||||
|
||||
- Duplicate issues should be closed with a link to the original.
|
||||
- Unreproducible issues should be closed if it's not possible to reproduce them (if the reporter drops offline,
|
||||
it is reasonable to wait 2 weeks before closing).
|
||||
- `bug`s should be labelled `merged` when merged, and be closed when the issue is fixed and released.
|
||||
- `feature`s, `maintenance`s, `greenkeeper`s should be labelled `merged` when merged,
|
||||
and closed when released or if the feature is deemed not appropriate.
|
||||
- `question / support`s should be closed when the question has been answered.
|
||||
If the questioner drops offline, a reasonable period to wait is two weeks.
|
||||
- `discussion`s should be closed at a maintainer's discretion.
|
||||
|
||||
## Development Guide
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Please have the **_latest_** stable versions of the following on your machine
|
||||
|
||||
- node
|
||||
- yarn
|
||||
|
||||
### Initial Setup
|
||||
|
||||
If you run into trouble here, make sure your node, npm, and **_yarn_** are on the latest versions (yarn at least v1.3.2).
|
||||
|
||||
1. `cd ~` (optional)
|
||||
2. `git clone https://github.com/storybookjs/storybook.git` _bonus_: use your own fork for this step
|
||||
3. `cd storybook`
|
||||
4. `yarn bootstrap --core`
|
||||
|
||||
> **_Note:_** On Windows, you may need to run `yarn` before `yarn bootstrap` (between steps 3 and 4).
|
||||
|
||||
This builds the entire project statically, but when you're updating Storybook code it's nice to see those changes show up in the example apps under `examples`. There are two ways to do this:
|
||||
|
||||
1. `yarn dev`
|
||||
2. OR `yarn build <package1> <package2> --watch`
|
||||
|
||||
The former watches ALL packages, which is extremely slow. The latter only watches a fixed list of packages, e.g. `yarn build add-docs components --watch` to build `@storybook/addon-docs` and `@storybook/components`. This is much more practical on slower machines or if you know ahead of time the packages you'll be updating.
|
||||
|
||||
#### Bootstrapping everything
|
||||
|
||||
_This method is slow_
|
||||
|
||||
1. `yarn bootstrap --all`
|
||||
2. Take a break 🍵
|
||||
3. `yarn test` (to verify everything worked)
|
||||
|
||||
#### Building specific packages
|
||||
|
||||
If you're working on one or several packages, for every change that you make, you have to rebuild those packages. To make the process easier, there is a CLI command for that:
|
||||
|
||||
- Run `yarn build` to bring you a list of packages to select from. There will be also an option to run in watch mode.
|
||||
- Run `yarn build <package-name>` to build that package specifically. \
|
||||
For the package name, use its short version. Example: for `@storybook/addon-docs`, run `yarn build addon-docs`.
|
||||
- Run `yarn build --all` to build everything.
|
||||
- Add `--watch` to run automatically in watch mode if you are either building a selection of packages by name or building all.
|
||||
Example: `yarn build core addon-docs --watch` or `yarn build --all --watch`.
|
||||
|
||||
### Working with the kitchen sink apps
|
||||
|
||||
Within the `examples` folder of the Storybook repo, you will find kitchen sink examples of storybook implementations for the various platforms that storybook supports.
|
||||
|
||||
Not only do these show many of the options and add-ons available, they are also automatically linked to all the development packages. We highly encourage you to use these to develop/test contributions on.
|
||||
|
||||
#### React and Vue
|
||||
|
||||
1. `cd examples/official-storybook`
|
||||
2. `yarn storybook`
|
||||
3. Verify that your local version works
|
||||
|
||||
### Working with your own app
|
||||
|
||||
#### Linking Storybook
|
||||
|
||||
Storybook is broken up into sub-projects that you can install as you need them. For this example, we will be working with `@storybook/react`.
|
||||
|
||||
**_Note:_** You need to `yarn link` from inside the subproject you are working on **_NOT_** the storybook root directory.
|
||||
|
||||
1. `cd app/react`
|
||||
2. `yarn link`
|
||||
|
||||
#### Connecting Your App To Storybook
|
||||
|
||||
**_Note:_** If you aren't seeing addons after linking storybook, you probably have a versioning issue which can be fixed by linking each addon you want to use.
|
||||
This applies for the kitchen sink apps as well as your own projects.
|
||||
|
||||
_Make sure `yarn dev` is running_
|
||||
|
||||
##### 1. Setup storybook in your project
|
||||
|
||||
First we are going to install storybook, then we are going to link `@storybook/react` into our project. This will replace `node_modules/@storybook/react` with a symlink to our local version of storybook.
|
||||
|
||||
1. `getstorybook`
|
||||
2. `yarn storybook`
|
||||
3. Verify that your local version works
|
||||
|
||||
##### 2. Link
|
||||
|
||||
**_Note:_** This process is the same for `@storybook/vue`, `@storybook/addon-foo`, etc
|
||||
|
||||
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
|
||||
5. `yarn link @storybook/react`
|
||||
6. `yarn storybook`
|
||||
|
||||
#### Verify your local version is working
|
||||
|
||||
You should now have a working storybook dev environment up and running.
|
||||
|
||||
Save and go to `http://localhost:9011` (or wherever storybook is running).
|
||||
|
||||
If you don't see the changes rerun `yarn storybook` again in your sandbox app.
|
||||
|
||||
### Documentation
|
||||
|
||||
The documentation for Storybook is served by the [frontpage](https://github.com/storybookjs/frontpage), but the docs files are in this repository.
|
||||
|
||||
To see changes in a development version of the docs, use the "linking" method documented [here](https://github.com/storybookjs/frontpage#docs-content).
|
||||
|
||||
## Release Guide
|
||||
|
||||
This section is for Storybook maintainers who will be creating releases. It assumes:
|
||||
|
||||
- yarn >= 1.3.2
|
||||
- you've yarn linked `pr-log` from <https://github.com/storybookjs/pr-log/pull/2>
|
||||
|
||||
The current manual release sequence is as follows:
|
||||
|
||||
- Generate a changelog and verify the release by hand
|
||||
- Push the changelog to main or the release branch
|
||||
- Clean, build and publish the release
|
||||
- Cut and paste the changelog to the [GitHub release page](https://github.com/storybookjs/storybook/releases), and mark it as a (pre-) release
|
||||
|
||||
**_Note:_** The very first time you publish a scoped package (`@storybook/x`) you need to make sure that its package.json contains the following
|
||||
|
||||
```js
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
```
|
||||
|
||||
This sequence applies to both releases and pre-releases, but differs slightly between the two.
|
||||
|
||||
**_Note:_ This is a work in progress. Don't try this unless you know what you're doing. We hope to automate this in CI, so this process is designed with that in mind.**
|
||||
|
||||
#### Prerelease:
|
||||
|
||||
```sh
|
||||
# make sure you current with origin/next.
|
||||
git checkout next
|
||||
git status
|
||||
|
||||
# generate changelog and edit as appropriate
|
||||
# generates a Next section
|
||||
yarn changelog:next x.y.z-alpha.a
|
||||
|
||||
# Edit the changelog/PRs as needed, then commit
|
||||
git commit -m "x.y.z-alpha.a changelog"
|
||||
|
||||
# clean build
|
||||
yarn bootstrap --reset --core
|
||||
|
||||
# publish and tag the release
|
||||
yarn run publish:next
|
||||
|
||||
# update the release page
|
||||
open https://github.com/storybookjs/storybook/releases
|
||||
```
|
||||
|
||||
#### Full release:
|
||||
|
||||
```sh
|
||||
# make sure you current with origin/main.
|
||||
git checkout main
|
||||
git status
|
||||
|
||||
# generate changelog and edit as appropriate
|
||||
# generates a vNext section
|
||||
yarn changelog x.y.z
|
||||
|
||||
# Edit the changelog/PRs as needed, then commit
|
||||
git commit -m "x.y.z changelog"
|
||||
|
||||
# clean build
|
||||
yarn bootstrap --reset --core
|
||||
|
||||
# publish and tag the release
|
||||
yarn run publish:latest
|
||||
|
||||
# update the release page
|
||||
open https://github.com/storybookjs/storybook/releases
|
||||
```
|
117
MAINTAINERS.md
117
MAINTAINERS.md
@ -1,54 +1,77 @@
|
||||
This document will document some of the processes that members of the documentation team should adhere to.
|
||||
This document outlines some of the processes that the maintainers should adhere to.
|
||||
|
||||
# PR Process
|
||||
|
||||
1. Triage with the correct [label](#labels)
|
||||
2. If there is a change related to it ensure it has been published and tested before closing
|
||||
2. If there is a change related to it, ensure it has been published and tested before closing
|
||||
|
||||
# Labels
|
||||
|
||||
| label name | purpose |
|
||||
|:--------------:|:------------|
|
||||
| accessibility | |
|
||||
| addon:(name) | |
|
||||
| app:(name) | |
|
||||
| api:(name) | |
|
||||
| cleanup | Minor cleanup style change that won't show up in release changelog |
|
||||
| bug | |
|
||||
| cli | |
|
||||
| good first review | |
|
||||
| compatibility with other tools | |
|
||||
| patch | Bugfix & documentation PR that need to be picked to release branch |
|
||||
| picked | Patch PRs cherry-picked to master |
|
||||
| compatibility with other tools | |
|
||||
| components | |
|
||||
| core | |
|
||||
| decorators | |
|
||||
| dependencies:update | |
|
||||
| dependencies | |
|
||||
| discussion | |
|
||||
| do not merge | |
|
||||
| documentation | |
|
||||
| feature request | |
|
||||
| good first issue | |
|
||||
| has workaround | |
|
||||
| help wanted | |
|
||||
| high priority | |
|
||||
| in progress | |
|
||||
| inactive | |
|
||||
| maintenance | |
|
||||
| merged | |
|
||||
| needs example | |
|
||||
| needs more info | |
|
||||
| needs rebase | |
|
||||
| needs reproduction | |
|
||||
| needs review | |
|
||||
| performance issue | |
|
||||
| presets | |
|
||||
| question / support | |
|
||||
| ready | |
|
||||
| security | |
|
||||
| todo | |
|
||||
| typescript | |
|
||||
| ui | |
|
||||
| won't fix | |
|
||||
| label name | purpose |
|
||||
|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| accessibility | Issue, bug, or pull request related to accessibility |
|
||||
| addon:(name) | Issue, bug, or pull request related to Storybook addons (e.g., [Controls](/docs/essentials/controls.md)) |
|
||||
| app:(name) | Issue, bug, or pull request related to Storybook's supported frameworks (e.g., React) |
|
||||
| api:(name) | Issue, bug, or pull request related to Storybook's API (e.g.,[makeDecorator](/docs/addons/addons-api.md#makeDecorator-API)) |
|
||||
| args | Issue, bug, or pull request related to Storybook's [args](/docs/writing-stories/args.md) |
|
||||
| babel/webpack | Issue, bug, or pull request related to Storybook's build system (e.g., Webpack or Babel), for Webpack 5 issues see below |
|
||||
| block:(name) | Issue or bug within a certain surface are of Storybook (e.g., [argsTable](/docs/writing-docs/doc-blocks.md#argstable)) |
|
||||
| BREAKING CHANGE | Issue or pull request that introduces a breaking change within Storybook's ecosystem. |
|
||||
| BREAKING PRERELASE | Breaking, but only for prerelease users (not relative to the stable release) |
|
||||
| build-storybook | Issue, bug, or pull request related to Storybook's production build |
|
||||
| cleanup | Minor cleanup style change that won't show up in release changelog |
|
||||
| bug | A bug within Storybook |
|
||||
| cli | Issue, bug, or pull request that affects the Storybook's CLI |
|
||||
| compatibility with other tools | Issue, bug, or pull request between Storybook and other tools (e.g., [Nuxt](https://nuxtjs.org/)) |
|
||||
| components | Issue, bug, or pull request related to Storybook's internal components |
|
||||
| composition | Issue, bug, or pull request related to Storybook [Composition](/docs/workflows/storybook-composition.md) |
|
||||
| configuration | Issue, bug, or pull request related to Storybook [configuration](/docs/configure/overview.md) |
|
||||
| core | Issue, bug, or pull request related to Storybook's Core |
|
||||
| cra | Issue, bug, or pull request that affects Storybook's compatibility with Create React APP ([CRA](https://create-react-app.dev/docs/getting-started/))|
|
||||
| CSF | Issue, bug, or pull request related to Storybook's [Component Story Format (CSF)](/docs/api/csf.md) |
|
||||
| decorators | Issue, bug, or pull related to Storybook's [Decorators](/docs/writing-stories/decorators.md) |
|
||||
| dependencies | Issue, bug, or pull request that related to upstream dependencies |
|
||||
| discussion | Issue currently being discussed between the maintainers and community |
|
||||
| do not merge | Pull request that will introduce regressions and will not be merged |
|
||||
| documentation | Issue, bug, or pull request that affects Storybook's documentation |
|
||||
| duplicate | Question or issue already asked in the repo's issues |
|
||||
| feature request | Request for a new feature to be included in Storybook |
|
||||
| flow | Issue, bug, or pull request related to Storybook and Flow |
|
||||
| Funded on Issuehunt | Storybook issue funded on [IssueHunt](https://issuehunt.io/) |
|
||||
| gatsby | Issue, bug, or pull request that affects Storybook and [Gatsby](https://www.gatsbyjs.com/) |
|
||||
| good first issue | Low impact Storybook issues that help new members get involved and start contributing |
|
||||
| has workaround | Issue or bug that has an alternative way to be solved with Storybook |
|
||||
| help wanted | Issue, or bug that requires additional help from the community |
|
||||
| ie11 | Issue, bug, or pull request related to Storybook and IE11 |
|
||||
| in progress | Issue or pull request that is currently being reviewed or worked on with the author |
|
||||
| inactive | Issue, or pull request that has gone stale and no active development has been done |
|
||||
| maintenance | Issue, or pull request related to Storybook's internal maintenance |
|
||||
| mdx | Issue, bug, or pull request related to MDX and Storybook |
|
||||
| medium | Issue or pull request that involves a significant amount of work within Storybook |
|
||||
| monorepos | Issue, bug, or pull request related to Storybook and monorepos (e.g., [lerna](https://lerna.js.org/) ) |
|
||||
| mui | Issue, bug, or pull request that affects Storybook and [Material-UI](https://material-ui.com/) |
|
||||
| multiframework | Issue, bug, or pull request that affects multiple supported frameworks (e.g., React, Vue) |
|
||||
| needs more info | Issue, or bug that requires additional context from the author |
|
||||
| needs reproduction | Issue, or bug that requires a reproduction to be looked at |
|
||||
| needs triage | Issue, bug, or pull request that requires further investigation from the maintainers |
|
||||
| nextjs | Issue, bug, or pull request related to Storybook's integration with [Next.js](https://nextjs.org/) |
|
||||
| nx | Issue, bug, or pull request related to Storybook's integration with [NX](https://nx.dev/) |
|
||||
| other | Storybook's miscellaneous issue or pull request |
|
||||
| P(n) | Bug or issue priority. Ranges from `0` (most urgent) to `N` (least urgent) |
|
||||
| patch | Bug fix and documentation pull request that will be picked to the main branch |
|
||||
| performance issue | Issue, bug or pull request that affects Storybook's performance |
|
||||
| picked | Patch PRs cherry-picked to the main branch |
|
||||
| presets | Issue, bug, or pull requests that affect Storybook's presets |
|
||||
| question / support | General question about Storybook |
|
||||
| run e2e extended test suite | Pull request that affects Storybook's testing suite |
|
||||
| search | Issue, bug or pull request related to Storybook's search functionality |
|
||||
| security | Issue, bug, or pull request that addresses security with Storybook |
|
||||
| small | Issue or pull request that requires a small amount of work to be done |
|
||||
| source-loader | Issue, bug, or pull request related to code display within Storybook's stories |
|
||||
| theming | Issue, bug, or pull request related to Storybook customization (e.g., [theming](/docs/configure/theming.md)) |
|
||||
| todo | Issue or pull request currently being worked on |
|
||||
| typescript | Issue, bug, or pull request related to TypeScript |
|
||||
| ui | Issue, bug, or pull request related to Storybook's UI |
|
||||
| webpack5 | Issue, bug, or pull request related to Webpack 5 |
|
||||
| won't fix | Issue or pull request that won't be addressed by the maintainers (e.g., introduces a regression) |
|
||||
| yarn/npm | Issue or pull request related to node package managers |
|
||||
|
506
MIGRATION.md
506
MIGRATION.md
@ -1,5 +1,38 @@
|
||||
<h1>Migration</h1>
|
||||
|
||||
- [From version 6.2.x to 6.3.0](#from-version-62x-to-630)
|
||||
- [Webpack 5 manager build](#webpack-5-manager-build)
|
||||
- [Angular 12 upgrade](#angular-12-upgrade)
|
||||
- [Lit support](#lit-support)
|
||||
- [No longer inferring default values of args](#no-longer-inferring-default-values-of-args)
|
||||
- [6.3 deprecations](#63-deprecations)
|
||||
- [Deprecated addon-knobs](#deprecated-addon-knobs)
|
||||
- [Deprecated scoped blocks imports](#deprecated-scoped-blocks-imports)
|
||||
- [Deprecated layout URL params](#deprecated-layout-url-params)
|
||||
- [From version 6.1.x to 6.2.0](#from-version-61x-to-620)
|
||||
- [MDX pattern tweaked](#mdx-pattern-tweaked)
|
||||
- [6.2 Angular overhaul](#62-angular-overhaul)
|
||||
- [New Angular storyshots format](#new-angular-storyshots-format)
|
||||
- [Deprecated Angular story component](#deprecated-angular-story-component)
|
||||
- [New Angular renderer](#new-angular-renderer)
|
||||
- [Components without selectors](#components-without-selectors)
|
||||
- [Packages now available as ESModules](#packages-now-available-as-esmodules)
|
||||
- [6.2 Deprecations](#62-deprecations)
|
||||
- [Deprecated implicit PostCSS loader](#deprecated-implicit-postcss-loader)
|
||||
- [Deprecated default PostCSS plugins](#deprecated-default-postcss-plugins)
|
||||
- [Deprecated showRoots config option](#deprecated-showroots-config-option)
|
||||
- [Deprecated control.options](#deprecated-controloptions)
|
||||
- [Deprecated storybook components html entry point](#deprecated-storybook-components-html-entry-point)
|
||||
- [From version 6.0.x to 6.1.0](#from-version-60x-to-610)
|
||||
- [Addon-backgrounds preset](#addon-backgrounds-preset)
|
||||
- [Single story hoisting](#single-story-hoisting)
|
||||
- [React peer dependencies](#react-peer-dependencies)
|
||||
- [6.1 deprecations](#61-deprecations)
|
||||
- [Deprecated DLL flags](#deprecated-dll-flags)
|
||||
- [Deprecated storyFn](#deprecated-storyfn)
|
||||
- [Deprecated onBeforeRender](#deprecated-onbeforerender)
|
||||
- [Deprecated grid parameter](#deprecated-grid-parameter)
|
||||
- [Deprecated package-composition disabled parameter](#deprecated-package-composition-disabled-parameter)
|
||||
- [From version 5.3.x to 6.0.x](#from-version-53x-to-60x)
|
||||
- [Hoisted CSF annotations](#hoisted-csf-annotations)
|
||||
- [Zero config typescript](#zero-config-typescript)
|
||||
@ -14,6 +47,7 @@
|
||||
- [DocsPage slots removed](#docspage-slots-removed)
|
||||
- [React prop tables with Typescript](#react-prop-tables-with-typescript)
|
||||
- [ConfigureJSX true by default in React](#configurejsx-true-by-default-in-react)
|
||||
- [User babelrc disabled by default in MDX](#user-babelrc-disabled-by-default-in-mdx)
|
||||
- [Docs description parameter](#docs-description-parameter)
|
||||
- [6.0 Inline stories](#60-inline-stories)
|
||||
- [New addon presets](#new-addon-presets)
|
||||
@ -33,6 +67,7 @@
|
||||
- [6.0 Addon API changes](#60-addon-api-changes)
|
||||
- [Consistent local addon paths in main.js](#consistent-local-addon-paths-in-mainjs)
|
||||
- [Deprecated setAddon](#deprecated-setaddon)
|
||||
- [Deprecated disabled parameter](#deprecated-disabled-parameter)
|
||||
- [Actions addon uses parameters](#actions-addon-uses-parameters)
|
||||
- [Removed action decorator APIs](#removed-action-decorator-apis)
|
||||
- [Removed withA11y decorator](#removed-witha11y-decorator)
|
||||
@ -113,8 +148,8 @@
|
||||
- [Addon story parameters](#addon-story-parameters)
|
||||
- [From version 3.3.x to 3.4.x](#from-version-33x-to-34x)
|
||||
- [From version 3.2.x to 3.3.x](#from-version-32x-to-33x)
|
||||
- [`babel-core` is now a peer dependency (#2494)](#babel-core-is-now-a-peer-dependency-2494)
|
||||
- [Base webpack config now contains vital plugins (#1775)](#base-webpack-config-now-contains-vital-plugins-1775)
|
||||
- [`babel-core` is now a peer dependency #2494](#babel-core-is-now-a-peer-dependency-2494)
|
||||
- [Base webpack config now contains vital plugins #1775](#base-webpack-config-now-contains-vital-plugins-1775)
|
||||
- [Refactored Knobs](#refactored-knobs)
|
||||
- [From version 3.1.x to 3.2.x](#from-version-31x-to-32x)
|
||||
- [Moved TypeScript addons definitions](#moved-typescript-addons-definitions)
|
||||
@ -127,6 +162,408 @@
|
||||
- [Packages renaming](#packages-renaming)
|
||||
- [Deprecated embedded addons](#deprecated-embedded-addons)
|
||||
|
||||
## From version 6.2.x to 6.3.0
|
||||
|
||||
### Webpack 5 manager build
|
||||
|
||||
Storybook 6.2 introduced **experimental** webpack5 support for building user components. Storybook 6.3 also supports building the manager UI in webpack 5 to avoid strange hoisting issues.
|
||||
|
||||
If you're upgrading from 6.2 and already using the experimental webpack5 feature, this might be a breaking change (hence the 'experimental' label) and you should try adding the manager builder:
|
||||
|
||||
```shell
|
||||
yarn add @storybook/manager-webpack5 --dev
|
||||
# Or
|
||||
npm install @storybook/manager-webpack5 --save-dev
|
||||
```
|
||||
|
||||
Because Storybook uses `webpack@4` as the default, it's possible for the wrong version of webpack to get hoisted by your package manager. If you receive an error that looks like you might be using the wrong version of webpack, install `webpack@5` explicitly as a dev dependency to force it to be hoisted:
|
||||
|
||||
```shell
|
||||
yarn add webpack@5 --dev
|
||||
# Or
|
||||
npm install webpack@5 --save-dev
|
||||
```
|
||||
|
||||
### Angular 12 upgrade
|
||||
|
||||
Storybook 6.3 supports Angular 12 out of the box when you install it fresh. However, if you're upgrading your project from a previous version, you'll need to do the following steps to force Storybook to use webpack 5 for building your project:
|
||||
|
||||
```shell
|
||||
yarn add @storybook/builder-webpack5@next @storybook/manager-webpack5@next --dev
|
||||
# Or
|
||||
npm install @storybook/builder-webpack5@next @storybook/manager-webpack5@next --save-dev
|
||||
```
|
||||
|
||||
Then edit your `.storybook/main.js` config:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
core: {
|
||||
builder: 'webpack5',
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Lit support
|
||||
|
||||
Storybook 6.3 introduces Lit 2 support in a non-breaking way to ease migration from `lit-html`/`lit-element` to `lit`.
|
||||
|
||||
To do so, it relies on helpers added in the latest minor versions of `lit-html`/`lit-element`. So when upgrading to Storybook 6.3, please ensure your project is using `lit-html` 1.4.x or `lit-element` 2.5.x.
|
||||
|
||||
According to the package manager you are using, it can be handled automatically when updating Storybook or can require to manually update the versions and regenerate the lockfile.
|
||||
|
||||
### No longer inferring default values of args
|
||||
|
||||
Previously, unset `args` were set to the `argType.defaultValue` if set or inferred from the component's prop types (etc.). In 6.3 we no longer infer default values and instead set arg values to `undefined` when unset, allowing the framework to supply the default value.
|
||||
|
||||
If you were using `argType.defaultValue` to fix issues with the above inference, it should no longer be necessary, you can remove that code.
|
||||
|
||||
If you were using `argType.defaultValue` or relying on inference to set a default value for an arg, you should now set a value for the arg at the component level:
|
||||
|
||||
```js
|
||||
export default {
|
||||
component: MyComponent,
|
||||
args: {
|
||||
argName: 'default-value',
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
To manually configure the value that is shown in the ArgsTable doc block, you can configure the `table.defaultValue` setting:
|
||||
|
||||
```js
|
||||
export default {
|
||||
component: MyComponent,
|
||||
argTypes: {
|
||||
argName: {
|
||||
table: { defaultValue: { summary: 'SomeType<T>' } },
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 6.3 deprecations
|
||||
|
||||
#### Deprecated addon-knobs
|
||||
|
||||
We are replacing `@storybook/addon-knobs` with `@storybook/addon-controls`.
|
||||
|
||||
- [Rationale & discussion](https://github.com/storybookjs/storybook/discussions/15060)
|
||||
- [Migration notes](https://github.com/storybookjs/storybook/blob/next/addons/controls/README.md#how-do-i-migrate-from-addon-knobs)
|
||||
|
||||
#### Deprecated scoped blocks imports
|
||||
|
||||
In 6.3, we changed doc block imports from `@storybook/addon-docs/blocks` to `@storybook/addon-docs`. This makes it possible for bundlers to automatically choose the ESM or CJS version of the library depending on the context.
|
||||
|
||||
To update your code, you should be able to global replace `@storybook/addon-docs/blocks` with `@storybook/addon-docs`. Example:
|
||||
|
||||
```js
|
||||
// before
|
||||
import { Meta, Story } from '@storybook/addon-docs/blocks';
|
||||
|
||||
// after
|
||||
import { Meta, Story } from '@storybook/addon-docs';
|
||||
```
|
||||
|
||||
#### Deprecated layout URL params
|
||||
|
||||
Several URL params to control the manager layout have been deprecated and will be removed in 7.0:
|
||||
|
||||
- `addons=0`: use `panel=false` instead
|
||||
- `panelRight=1`: use `panel=right` instead
|
||||
- `stories=0`: use `nav=false` instead
|
||||
|
||||
Additionally, support for legacy URLs using `selectedKind` and `selectedStory` will be removed in 7.0. Use `path` instead.
|
||||
|
||||
## From version 6.1.x to 6.2.0
|
||||
|
||||
### MDX pattern tweaked
|
||||
|
||||
In 6.2 files ending in `stories.mdx` or `story.mdx` are now processed with Storybook's MDX compiler. Previously it only applied to files ending in `.stories.mdx` or `.story.mdx`. See more here: [#13996](https://github.com/storybookjs/storybook/pull/13996).
|
||||
|
||||
### 6.2 Angular overhaul
|
||||
|
||||
#### New Angular storyshots format
|
||||
|
||||
We've updated the Angular storyshots format in 6.2, which is technically a breaking change. Apologies to semver purists: if you're using storyshots, you'll need to [update your snapshots](https://jestjs.io/docs/en/snapshot-testing#updating-snapshots).
|
||||
|
||||
The new format hides the implementation details of `@storybook/angular` so that we can evolve its renderer without breaking your snapshots in the future.
|
||||
|
||||
#### Deprecated Angular story component
|
||||
|
||||
Storybook 6.2 for Angular uses `parameters.component` as the preferred way to specify your stories' components. The previous method, in which the component was a return value of the story, has been deprecated.
|
||||
|
||||
Consider the existing story from 6.1 or earlier:
|
||||
|
||||
```ts
|
||||
export default { title: 'Button' };
|
||||
export const Basic = () => ({
|
||||
component: Button,
|
||||
props: { label: 'Label' },
|
||||
});
|
||||
```
|
||||
|
||||
From 6.2 this should be rewritten as:
|
||||
|
||||
```ts
|
||||
export default { title: 'Button', component: Button };
|
||||
export const Basic = () => ({
|
||||
props: { label: 'Label' },
|
||||
});
|
||||
```
|
||||
|
||||
The new convention is consistent with how other frameworks and addons work in Storybook. The old way will be supported until 7.0. For a full discussion see https://github.com/storybookjs/storybook/issues/8673.
|
||||
|
||||
#### New Angular renderer
|
||||
|
||||
We've rewritten the Angular renderer in Storybook 6.2. It's meant to be entirely backwards compatible, but if you need to use the legacy renderer it's still available via a [parameter](https://storybook.js.org/docs/angular/writing-stories/parameters). To opt out of the new renderer, add the following to `.storybook/preview.ts`:
|
||||
|
||||
```ts
|
||||
export const parameters = {
|
||||
angularLegacyRendering: true,
|
||||
};
|
||||
```
|
||||
|
||||
Please also file an issue if you need to opt out. We plan to remove the legacy renderer in 7.0.
|
||||
|
||||
#### Components without selectors
|
||||
|
||||
When the new Angular renderer is used, all Angular Story components must either have a selector, or be added to the `entryComponents` array of the story's `moduleMetadata`. If the component has any `Input`s or `Output`s to be controlled with `args`, a selector should be added.
|
||||
|
||||
### Packages now available as ESModules
|
||||
|
||||
Many Storybook packages are now available as ESModules in addition to CommonJS. If your jest tests stop working, this is likely why. One common culprit is doc blocks, which [is fixed in 6.3](#deprecated-scoped-blocks-imports). In 6.2, you can configure jest to transform the packages like so ([more info](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring)):
|
||||
|
||||
```json
|
||||
// In your jest config
|
||||
transformIgnorePatterns: ['/node_modules/(?!@storybook)']
|
||||
```
|
||||
|
||||
### 6.2 Deprecations
|
||||
|
||||
#### Deprecated implicit PostCSS loader
|
||||
|
||||
Previously, `@storybook/core` would automatically add the `postcss-loader` to your preview. This caused issues for consumers when PostCSS upgraded to v8 and tools, like Autoprefixer and Tailwind, starting requiring the new version. Implicitly adding `postcss-loader` will be removed in Storybook 7.0.
|
||||
|
||||
Instead of continuing to include PostCSS inside the core library, it has been moved to [`@storybook/addon-postcss`](https://github.com/storybookjs/addon-postcss). This addon provides more fine-grained customization and will be upgraded more flexibly to track PostCSS upgrades.
|
||||
|
||||
If you require PostCSS support, please install `@storybook/addon-postcss` in your project, add it to your list of addons inside `.storybook/main.js`, and configure a `postcss.config.js` file.
|
||||
|
||||
Further information is available at https://github.com/storybookjs/storybook/issues/12668 and https://github.com/storybookjs/storybook/pull/13669.
|
||||
|
||||
If you're not using Postcss and you don't want to see the warning, you can disable it by adding the following to your `.storybook/main.js`:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
features: {
|
||||
postcss: false,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
#### Deprecated default PostCSS plugins
|
||||
|
||||
When relying on the [implicit PostCSS loader](#deprecated-implicit-postcss-loader), it would also add [autoprefixer v9](https://www.npmjs.com/package/autoprefixer/v/9.8.6) and [postcss-flexbugs-fixes v4](https://www.npmjs.com/package/postcss-flexbugs-fixes/v/4.2.1) plugins to the `postcss-loader` configuration when you didn't have a PostCSS config file (such as `postcss.config.js`) within your project.
|
||||
|
||||
They will no longer be applied when switching to `@storybook/addon-postcss` and the implicit PostCSS features will be removed in Storybook 7.0.
|
||||
|
||||
If you depend upon these plugins being applied, install them and create a `postcss.config.js` file within your project that contains:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('postcss-flexbugs-fixes'),
|
||||
require('autoprefixer')({
|
||||
flexbox: 'no-2009',
|
||||
}),
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
#### Deprecated showRoots config option
|
||||
|
||||
Config options for the sidebar are now under the `sidebar` namespace. The `showRoots` option should be set as follows:
|
||||
|
||||
```js
|
||||
addons.setConfig({
|
||||
sidebar: {
|
||||
showRoots: false,
|
||||
},
|
||||
// showRoots: false <- this is deprecated
|
||||
});
|
||||
```
|
||||
|
||||
The top-level `showRoots` option will be removed in Storybook 7.0.
|
||||
|
||||
#### Deprecated control.options
|
||||
|
||||
Possible `options` for a radio/check/select controls has been moved up to the argType level, and no longer accepts an object. Instead, you should specify `options` as an array. You can use `control.labels` to customize labels. Additionally, you can use a `mapping` to deal with complex values.
|
||||
|
||||
```js
|
||||
argTypes: {
|
||||
answer:
|
||||
options: ['yes', 'no'],
|
||||
mapping: {
|
||||
yes: <Check />,
|
||||
no: <Cross />,
|
||||
},
|
||||
control: {
|
||||
type: 'radio',
|
||||
labels: {
|
||||
yes: 'да',
|
||||
no: 'нет',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Keys in `control.labels` as well as in `mapping` should match the values in `options`. Neither object has to be exhaustive, in case of a missing property, the option value will be used directly.
|
||||
|
||||
If you are currently using an object as value for `control.options`, be aware that the key and value are reversed in `control.labels`.
|
||||
|
||||
#### Deprecated storybook components html entry point
|
||||
|
||||
Storybook HTML components are now exported directly from '@storybook/components' for better ESM and Typescript compatibility. The old entry point will be removed in SB 7.0.
|
||||
|
||||
```js
|
||||
// before
|
||||
import { components } from '@storybook/components/html';
|
||||
|
||||
// after
|
||||
import { components } from '@storybook/components';
|
||||
```
|
||||
|
||||
## From version 6.0.x to 6.1.0
|
||||
|
||||
### Addon-backgrounds preset
|
||||
|
||||
In 6.1 we introduced an unintentional breaking change to `addon-backgrounds`.
|
||||
|
||||
The addon uses decorators which are set up automatically by a preset. The required preset is ignored if you register the addon in `main.js` with the `/register` entry point. This used to be valid in `v6.0.x` and earlier:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
stories: ['../**/*.stories.js'],
|
||||
addons: ['@storybook/addon-backgrounds/register'],
|
||||
};
|
||||
```
|
||||
|
||||
To fix it, just replace `@storybook/addon-backgrounds/register` with `@storybook/addon-backgrounds`:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
stories: ['../**/*.stories.js'],
|
||||
addons: ['@storybook/addon-backgrounds'],
|
||||
};
|
||||
```
|
||||
|
||||
### Single story hoisting
|
||||
|
||||
Stories which have **no siblings** (i.e. the component has only one story) and which name **exactly matches** the component name will now be hoisted up to replace their parent component in the sidebar. This means you can have a hierarchy like this:
|
||||
|
||||
```
|
||||
DESIGN SYSTEM [root]
|
||||
- Atoms [group]
|
||||
- Button [component]
|
||||
- Button [story]
|
||||
- Checkbox [component]
|
||||
- Checkbox [story]
|
||||
```
|
||||
|
||||
This will then be visually presented in the sidebar like this:
|
||||
|
||||
```
|
||||
DESIGN SYSTEM [root]
|
||||
- Atoms [group]
|
||||
- Button [story]
|
||||
- Checkbox [story]
|
||||
```
|
||||
|
||||
See [Naming components and hierarchy](https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting) for details.
|
||||
|
||||
### React peer dependencies
|
||||
|
||||
Starting in 6.1, `react` and `react-dom` are required peer dependencies of `@storybook/react`, meaning that if your React project does not have dependencies on them, you need to add them as `devDependencies`. If you don't you'll see errors like this:
|
||||
|
||||
```
|
||||
Error: Cannot find module 'react-dom/package.json'
|
||||
```
|
||||
|
||||
They were also peer dependencies in earlier versions, but due to the package structure they would be installed by Storybook if they were not required by the user's project. For more discussion: https://github.com/storybookjs/storybook/issues/13269
|
||||
|
||||
### 6.1 deprecations
|
||||
|
||||
#### Deprecated DLL flags
|
||||
|
||||
Earlier versions of Storybook used Webpack DLLs as a performance crutch. In 6.1, we've removed Storybook's built-in DLLs and have deprecated the command-line parameters `--no-dll` and `--ui-dll`. They will be removed in 7.0.
|
||||
|
||||
#### Deprecated storyFn
|
||||
|
||||
Each item in the story store contains a field called `storyFn`, which is a fully decorated story that's applied to the denormalized story parameters. Starting in 6.0 we've stopped using this API internally, and have replaced it with a new field called `unboundStoryFn` which, unlike `storyFn`, must passed a story context, typically produced by `applyLoaders`;
|
||||
|
||||
Before:
|
||||
|
||||
```js
|
||||
const { storyFn } = store.fromId('some--id');
|
||||
console.log(storyFn());
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```js
|
||||
const { unboundStoryFn, applyLoaders } = store.fromId('some--id');
|
||||
const context = await applyLoaders();
|
||||
console.log(unboundStoryFn(context));
|
||||
```
|
||||
|
||||
If you're not using loaders, `storyFn` will work as before. If you are, you'll need to use the new approach.
|
||||
|
||||
> NOTE: If you're using `@storybook/addon-docs`, this deprecation warning is triggered by the Docs tab in 6.1. It's safe to ignore and we will be providing a proper fix in a future release. You can track the issue at https://github.com/storybookjs/storybook/issues/13074.
|
||||
|
||||
#### Deprecated onBeforeRender
|
||||
|
||||
The `@storybook/addon-docs` previously accepted a `jsx` option called `onBeforeRender`, which was unfortunately named as it was called after the render.
|
||||
|
||||
We've renamed it `transformSource` and also allowed it to receive the `StoryContext` in case source rendering requires additional information.
|
||||
|
||||
#### Deprecated grid parameter
|
||||
|
||||
Previously when using `@storybook/addon-backgrounds` if you wanted to customize the grid, you would define a parameter like this:
|
||||
|
||||
```js
|
||||
export const Basic = () => <Button />
|
||||
Basic.parameters: {
|
||||
grid: {
|
||||
cellSize: 10
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
As grid is not an addon, but rather backgrounds is, the grid configuration was moved to be inside `backgrounds` parameter instead. Also, there are new properties that can be used to further customize the grid. Here's an example with the default values:
|
||||
|
||||
```js
|
||||
export const Basic = () => <Button />
|
||||
Basic.parameters: {
|
||||
backgrounds: {
|
||||
grid: {
|
||||
disable: false,
|
||||
cellSize: 20,
|
||||
opacity: 0.5,
|
||||
cellAmount: 5,
|
||||
offsetX: 16, // default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'
|
||||
offsetY: 16, // default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'
|
||||
}
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
#### Deprecated package-composition disabled parameter
|
||||
|
||||
Like [Deprecated disabled parameter](#deprecated-disabled-parameter). The `disabled` parameter has been deprecated, please use `disable` instead.
|
||||
|
||||
For more information, see the [the related documentation](https://storybook.js.org/docs/react/workflows/package-composition#configuring).
|
||||
|
||||
## From version 5.3.x to 6.0.x
|
||||
|
||||
### Hoisted CSF annotations
|
||||
@ -157,7 +594,7 @@ Basic.decorators = [ ... ];
|
||||
2. Similar to React's `displayName`, `propTypes`, `defaultProps` annotations
|
||||
3. We're introducing a new feature, [Storybook Args](https://docs.google.com/document/d/1Mhp1UFRCKCsN8pjlfPdz8ZdisgjNXeMXpXvGoALjxYM/edit?usp=sharing), where the new syntax will be significantly more ergonomic
|
||||
|
||||
To help you upgrade your stories, we've crated a codemod:
|
||||
To help you upgrade your stories, we've created a codemod:
|
||||
|
||||
```
|
||||
npx @storybook/cli@next migrate csf-hoist-story-annotations --glob="**/*.stories.js"
|
||||
@ -263,7 +700,7 @@ In SB5.2, we introduced the concept of [DocsPage slots](https://github.com/story
|
||||
|
||||
In 5.3, we introduced `docs.x` story parameters like `docs.prepareForInline` which get filled in by frameworks and can also be overwritten by users, which is a more natural/convenient way to make global customizations.
|
||||
|
||||
We also introduced introduced [Custom DocsPage](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/docspage.md#replacing-docspage), which makes it possible to add/remove/update DocBlocks on the page.
|
||||
We also introduced [Custom DocsPage](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/docspage.md#replacing-docspage), which makes it possible to add/remove/update DocBlocks on the page.
|
||||
|
||||
These mechanisms are superior to slots, so we've removed slots in 6.0. For each slot, we provide a migration path here:
|
||||
|
||||
@ -301,6 +738,23 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
#### User babelrc disabled by default in MDX
|
||||
|
||||
In SB 6.0, the Storybook Docs no longer applies the user's babelrc by default when processing MDX files. It caused lots of hard-to-diagnose bugs.
|
||||
|
||||
To restore the old behavior, or pass any MDX-specific babel options, you can configure `.storybook/main.js`:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
addons: [
|
||||
{
|
||||
name: '@storybook/addon-docs',
|
||||
options: { mdxBabelOptions: { babelrc: true, configFile: true } },
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
#### Docs description parameter
|
||||
|
||||
In 6.0, you can customize a component description using the `docs.description.component` parameter, and a story description using `docs.description.story` parameter.
|
||||
@ -434,7 +888,7 @@ The story store no longer emits `renderCurrentStory`/`RENDER_CURRENT_STORY` to t
|
||||
|
||||
We've removed the ability to specify the hierarchy separators (how you control the grouping of story kinds in the sidebar). From Storybook 6.0 we have a single separator `/`, which cannot be configured.
|
||||
|
||||
If you are currently using using custom separators, we encourage you to migrate to using `/` as the sole separator. If you are using `|` or `.` as a separator currently, we provide a codemod, [`upgrade-hierarchy-separators`](https://github.com/storybookjs/storybook/blob/next/lib/codemod/README.md#upgrade-hierarchy-separators), that can be used to rename your components. **Note: the codemod will not work for `.mdx` components, you will need to make the changes by hand.**
|
||||
If you are currently using custom separators, we encourage you to migrate to using `/` as the sole separator. If you are using `|` or `.` as a separator currently, we provide a codemod, [`upgrade-hierarchy-separators`](https://github.com/storybookjs/storybook/blob/next/lib/codemod/README.md#upgrade-hierarchy-separators), that can be used to rename your components. **Note: the codemod will not work for `.mdx` components, you will need to make the changes by hand.**
|
||||
|
||||
```
|
||||
npx sb@next migrate upgrade-hierarchy-separators --glob="*/**/*.stories.@(tsx|jsx|ts|js)"
|
||||
@ -443,7 +897,7 @@ npx sb@next migrate upgrade-hierarchy-separators --glob="*/**/*.stories.@(tsx|js
|
||||
We also now default to showing "roots", which are non-expandable groupings in the sidebar for the top-level groups. If you'd like to disable this, set the `showRoots` option in `.storybook/manager.js`:
|
||||
|
||||
```js
|
||||
import addons from '@storybook/addons';
|
||||
import { addons } from '@storybook/addons';
|
||||
|
||||
addons.setConfig({
|
||||
showRoots: false,
|
||||
@ -581,6 +1035,22 @@ We've deprecated the `setAddon` method of the `storiesOf` API and plan to remove
|
||||
|
||||
Since early versions, Storybook shipped with a `setAddon` API, which allows you to extend `storiesOf` with arbitrary code. We've removed this from all core addons long ago and recommend writing stories in [Component Story Format](https://medium.com/storybookjs/component-story-format-66f4c32366df) rather than using the internal Storybook API.
|
||||
|
||||
#### Deprecated disabled parameter
|
||||
|
||||
Starting in 6.0.17, we've renamed the `disabled` parameter to `disable` to resolve an inconsistency where `disabled` had been used to hide the addon panel, whereas `disable` had been used to disable an addon's execution. Since `disable` was much more widespread in the code, we standardized on that.
|
||||
|
||||
So, for example:
|
||||
|
||||
```
|
||||
Story.parameters = { actions: { disabled: true } }
|
||||
```
|
||||
|
||||
Should be rewritten as:
|
||||
|
||||
```
|
||||
Story.parameters = { actions: { disable: true } }
|
||||
```
|
||||
|
||||
#### Actions addon uses parameters
|
||||
|
||||
Leveraging the new preset `@storybook/addon-actions` uses parameters to pass action options. If you previously had:
|
||||
@ -606,7 +1076,7 @@ StoryOne.story = {
|
||||
|
||||
#### Removed action decorator APIs
|
||||
|
||||
In 6.0 we removed the actions addon decorate API. Actions handles can be configured globaly, for a collection of stories or per story via parameters. The ability to manipulate the data arguments of an event is only relevant in a few frameworks and is not a common enough usecase to be worth the complexity of supporting.
|
||||
In 6.0 we removed the actions addon decorate API. Actions handles can be configured globally, for a collection of stories or per story via parameters. The ability to manipulate the data arguments of an event is only relevant in a few frameworks and is not a common enough usecase to be worth the complexity of supporting.
|
||||
|
||||
#### Removed withA11y decorator
|
||||
|
||||
@ -679,17 +1149,17 @@ We've deprecated the following in 6.0: `addon-info`, `addon-notes`, `addon-conte
|
||||
|
||||
The info/notes addons have been replaced by [addon-docs](https://github.com/storybookjs/storybook/tree/next/addons/docs). We've documented a migration in the [docs recipes](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/recipes.md#migrating-from-notesinfo-addons).
|
||||
|
||||
Both addons are still widely used, and their source code is still available in the [deprecated-addons repo](https://github.com/storybookjs/deprecated-addons). We're looking for maintainers for both addons. If you're interested, please get in touch on [our Discord](https://discordapp.com/invite/UUt2PJb).
|
||||
Both addons are still widely used, and their source code is still available in the [deprecated-addons repo](https://github.com/storybookjs/deprecated-addons). We're looking for maintainers for both addons. If you're interested, please get in touch on [our Discord](https://discord.gg/storybook).
|
||||
|
||||
#### Deprecated addon-contexts
|
||||
|
||||
The contexts addon has been replaced by [addon-toolbars](https://github.com/storybookjs/storybook/blob/next/addons/toolbars), which is simpler, more ergonomic, and compatible with all Storybook frameworks.
|
||||
|
||||
The addon's source code is still available in the [deprecated-addons repo](https://github.com/storybookjs/deprecated-addons). If you're interested in maintaining it, please get in touch on [our Discord](https://discordapp.com/invite/UUt2PJb).
|
||||
The addon's source code is still available in the [deprecated-addons repo](https://github.com/storybookjs/deprecated-addons). If you're interested in maintaining it, please get in touch on [our Discord](https://discord.gg/storybook).
|
||||
|
||||
#### Removed addon-centered
|
||||
|
||||
In 6.0 we removed the centered addon. Centering is now core feature of storybook, so w no longer need an addon.
|
||||
In 6.0 we removed the centered addon. Centering is now core feature of storybook, so we no longer need an addon.
|
||||
|
||||
Remove the addon-centered decorator and instead add a `layout` parameter:
|
||||
|
||||
@ -704,7 +1174,7 @@ Other possible values are: `padded` (default) and `fullscreen`.
|
||||
|
||||
#### Deprecated polymer
|
||||
|
||||
We've deprecated `@storybook/polymer` and are focusing on `@storybook/web-components`. If you use Polymer and are interested in maintaining it, please get in touch on [our Discord](https://discordapp.com/invite/UUt2PJb).
|
||||
We've deprecated `@storybook/polymer` and are focusing on `@storybook/web-components`. If you use Polymer and are interested in maintaining it, please get in touch on [our Discord](https://discord.gg/storybook).
|
||||
|
||||
#### Deprecated immutable options parameters
|
||||
|
||||
@ -714,7 +1184,7 @@ You should use `addon.setConfig` to set them:
|
||||
|
||||
```js
|
||||
// in .storybook/manager.js
|
||||
import addons from '@storybook/addons';
|
||||
import { addons } from '@storybook/addons';
|
||||
|
||||
addons.setConfig({
|
||||
showRoots: false,
|
||||
@ -968,7 +1438,7 @@ addParameters({
|
||||
|
||||
### Grid toolbar-feature
|
||||
|
||||
The grid feature in the toolbar has been relocated to [addon-background](https://github.com/storybookjs/storybook/tree/next/addons/backgrounds), follow the setup intructions on that addon to get the feature again.
|
||||
The grid feature in the toolbar has been relocated to [addon-background](https://github.com/storybookjs/storybook/tree/next/addons/backgrounds), follow the setup instructions on that addon to get the feature again.
|
||||
|
||||
### Docs mode docgen
|
||||
|
||||
@ -1125,7 +1595,7 @@ sortedModules.forEach((key) => {
|
||||
|
||||
### Webpack config simplification
|
||||
|
||||
The API for custom webpack configuration has been simplifed in 5.0, but it's a breaking change. Storybook's "full control mode" for webpack allows you to override the webpack config with a function that returns a configuration object.
|
||||
The API for custom webpack configuration has been simplified in 5.0, but it's a breaking change. Storybook's "full control mode" for webpack allows you to override the webpack config with a function that returns a configuration object.
|
||||
|
||||
In Storybook 5 there is a single signature for full-control mode that takes a parameters object with the fields `config` and `mode`:
|
||||
|
||||
@ -1156,7 +1626,7 @@ In 5.0, we now provide recommended defaults:
|
||||
}
|
||||
```
|
||||
|
||||
This means if you use the characters { `|`, `/`, `.` } in your story kinds it will triggger the story hierarchy to appear. For example `storiesOf('UI|Widgets/Basics/Button')` will create a story root called `UI` containing a `Widgets/Basics` group, containing a `Button` component.
|
||||
This means if you use the characters { `|`, `/`, `.` } in your story kinds it will trigger the story hierarchy to appear. For example `storiesOf('UI|Widgets/Basics/Button')` will create a story root called `UI` containing a `Widgets/Basics` group, containing a `Button` component.
|
||||
|
||||
If you wish to opt-out of this new behavior and restore the flat UI, set them back to `null` in your storybook config, or remove { `|`, `/`, `.` } from your story kinds:
|
||||
|
||||
@ -1375,7 +1845,7 @@ import centered from '@storybook/addon-centered/vue';
|
||||
|
||||
Storybook's keyboard shortcuts are updated in 5.0, but they are configurable via the menu so if you want to set them back you can:
|
||||
|
||||
| Shorctut | Old | New |
|
||||
| Shortcut | Old | New |
|
||||
| ---------------------- | ----------- | ----- |
|
||||
| Toggle sidebar | cmd-shift-X | S |
|
||||
| Toggle addons panel | cmd-shift-Z | A |
|
||||
@ -1630,7 +2100,7 @@ There are no expected breaking changes in the 3.4.x release, but 3.4 contains a
|
||||
It wasn't expected that there would be any breaking changes in this release, but unfortunately it turned out that there are some. We're revisiting our [release strategy](https://github.com/storybookjs/storybook/blob/master/RELEASES.md) to follow semver more strictly.
|
||||
Also read on if you're using `addon-knobs`: we advise an update to your code for efficiency's sake.
|
||||
|
||||
### `babel-core` is now a peer dependency ([#2494](https://github.com/storybookjs/storybook/pull/2494))
|
||||
### `babel-core` is now a peer dependency #2494
|
||||
|
||||
This affects you if you don't use babel in your project. You may need to add `babel-core` as dev dependency:
|
||||
|
||||
@ -1640,7 +2110,7 @@ yarn add babel-core --dev
|
||||
|
||||
This was done to support different major versions of babel.
|
||||
|
||||
### Base webpack config now contains vital plugins ([#1775](https://github.com/storybookjs/storybook/pull/1775))
|
||||
### Base webpack config now contains vital plugins #1775
|
||||
|
||||
This affects you if you use custom webpack config in [Full Control Mode](https://storybook.js.org/docs/react/configure/webpack#full-control-mode) while not preserving the plugins from `storybookBaseConfig`. Before `3.3`, preserving them was a recommendation, but now it [became](https://github.com/storybookjs/storybook/pull/2578) a requirement.
|
||||
|
||||
|
142
README.md
142
README.md
@ -19,17 +19,17 @@
|
||||
<img src="https://snyk.io/test/github/storybookjs/storybook/badge.svg" alt="Known Vulnerabilities" />
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/storybookjs/storybook">
|
||||
<img src="https://codecov.io/gh/storybookjs/storybook/branch/master/graph/badge.svg" alt="codecov" />
|
||||
<img src="https://codecov.io/gh/storybookjs/storybook/branch/main/graph/badge.svg" alt="codecov" />
|
||||
</a>
|
||||
<a href="https://github.com/storybookjs/storybook/blob/master/LICENSE">
|
||||
<a href="https://github.com/storybookjs/storybook/blob/main/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/storybookjs/storybook.svg" alt="License" />
|
||||
</a>
|
||||
<br/>
|
||||
<a href="https://discord.gg/sMFvFsG">
|
||||
<a href="https://discord.gg/storybook">
|
||||
<img src="https://img.shields.io/badge/discord-join-7289DA.svg?logo=discord&longCache=true&style=flat" />
|
||||
</a>
|
||||
<a href="https://now-examples-slackin-rrirkqohko.now.sh/">
|
||||
<img src="https://now-examples-slackin-rrirkqohko.now.sh/badge.svg?logo=slack" alt="Storybook Slack" />
|
||||
<a href="https://storybook.js.org/community/">
|
||||
<img src="https://img.shields.io/badge/community-join-4BC424.svg" alt="Storybook Community" />
|
||||
</a>
|
||||
<a href="#backers">
|
||||
<img src="https://opencollective.com/storybook/backers/badge.svg" alt="Backers on Open Collective" />
|
||||
@ -42,27 +42,19 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
Storybook is a development environment for UI components.
|
||||
It allows you to browse a component library, view the different states of each component, and interactively develop and test components.
|
||||
[Storybook](https://storybook.js.org) is a development environment for UI components.
|
||||
It allows you to browse a component library, view the different states of each component, and interactively develop and test components. Find out more at https://storybook.js.org.
|
||||
|
||||
<center>
|
||||
<img src="https://raw.githubusercontent.com/storybookjs/storybook/master/media/storybook-intro.gif" width="100%" />
|
||||
<img src="https://raw.githubusercontent.com/storybookjs/storybook/main/media/storybook-intro.gif" width="100%" />
|
||||
</center>
|
||||
|
||||
<p align="center">
|
||||
View README for:<br/>
|
||||
<a href="https://github.com/storybookjs/storybook/blob/master/README.md" title="latest"><img alt="latest" src="https://img.shields.io/npm/v/@storybook/core/latest.svg" /></a>
|
||||
<a href="https://github.com/storybookjs/storybook/blob/main/README.md" title="latest"><img alt="latest" src="https://img.shields.io/npm/v/@storybook/core/latest.svg" /></a>
|
||||
<a href="https://github.com/storybookjs/storybook/blob/next/README.md" title="next"><img alt="next" src="https://img.shields.io/npm/v/@storybook/core/next.svg" /></a>
|
||||
</p>
|
||||
|
||||
## Intro
|
||||
|
||||
Storybook runs outside of your app. This allows you to develop UI components in isolation, which can improve component reuse, testability, and development speed. You can build quickly without having to worry about application-specific dependencies.
|
||||
|
||||
Here are some featured examples that you can reference to see how Storybook works: <https://storybook.js.org/docs/examples/>
|
||||
|
||||
Storybook comes with a lot of [addons](https://storybook.js.org/docs/react/configure/storybook-addons) for component design, documentation, testing, interactivity, and so on. Storybook's API makes it possible to configure and extend in various ways. It has even been extended to support React Native development for mobile.
|
||||
|
||||
## Table of contents
|
||||
|
||||
- 🚀 [Getting Started](#getting-started)
|
||||
@ -80,40 +72,43 @@ Storybook comes with a lot of [addons](https://storybook.js.org/docs/react/confi
|
||||
|
||||
## Getting Started
|
||||
|
||||
First install storybook:
|
||||
Visit [Storybook's website](https://storybook.js.org) to learn more about Storybook, and to get started.
|
||||
|
||||
```sh
|
||||
cd my-react-app
|
||||
npx sb init
|
||||
```
|
||||
### Documentation
|
||||
|
||||
If you'd rather set up your project manually, take a look at our [Slow Start Guide](https://storybook.js.org/docs/react/configure/overview).
|
||||
Documentation can be found [Storybook's docs site](https://storybook.js.org/docs).
|
||||
|
||||
Once it's installed, you can `npm run storybook` and it will run the development server on your local machine, and give you a URL to browse some sample stories.
|
||||
### Examples
|
||||
|
||||
For full documentation on using Storybook visit: [storybook.js.org](https://storybook.js.org)
|
||||
Here are some featured examples that you can reference to see how Storybook works: <https://storybook.js.org/docs/react/get-started/examples>
|
||||
|
||||
For additional help, join us [in our Discord](https://discord.gg/sMFvFsG) or [Slack (legacy)](https://now-examples-slackin-rrirkqohko.now.sh/)
|
||||
Storybook comes with a lot of [addons](https://storybook.js.org/docs/react/configure/storybook-addons) for component design, documentation, testing, interactivity, and so on. Storybook's API makes it possible to configure and extend in various ways. It has even been extended to support React Native, Android, iOS, and Flutter development for mobile.
|
||||
|
||||
### Community
|
||||
|
||||
For additional help, join us in the [Storybook Discord](https://discord.gg/storybook).
|
||||
|
||||
## Projects
|
||||
|
||||
### Supported Frameworks
|
||||
|
||||
| Framework | Demo | |
|
||||
| -------------------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
||||
| [React](app/react) | [v6.0.x](https://storybookjs.netlify.com/official-storybook/?path=/story/*) | [](app/react) |
|
||||
| [React Native](app/react-native) | - | [](app/react-native) |
|
||||
| [Vue](app/vue) | [v6.0.x](https://storybookjs.netlify.com/vue-kitchen-sink/) | [](app/vue) |
|
||||
| [Angular](app/angular) | [v6.0.x](https://storybookjs.netlify.com/angular-cli/) | [](app/angular) |
|
||||
| [Marionette.js](app/marionette) | - | [](app/marionette) |
|
||||
| [Mithril](app/mithril) | [v6.0.x](https://storybookjs.netlify.com/mithril-kitchen-sink/) | [](app/mithril) |
|
||||
| [Marko](app/marko) | [v6.0.x](https://storybookjs.netlify.com/marko-cli/) | [](app/marko) |
|
||||
| [HTML](app/html) | [v6.0.x](https://storybookjs.netlify.com/html-kitchen-sink/) | [](app/html) |
|
||||
| [Svelte](app/svelte) | [v6.0.x](https://storybookjs.netlify.com/svelte-kitchen-sink/) | [](app/svelte) |
|
||||
| [Riot](app/riot) | [v6.0.x](https://storybookjs.netlify.com/riot-kitchen-sink/) | [](app/riot) |
|
||||
| [Ember](app/ember) | [v6.0.x](https://storybookjs.netlify.com/ember-cli/) | [](app/ember) |
|
||||
| [Preact](app/preact) | [v6.0.x](https://storybookjs.netlify.com/preact-kitchen-sink/) | [](app/preact) |
|
||||
| [Rax](app/rax) | [v6.0.x](https://storybookjs.netlify.com/rax-kitchen-sink/) | [](app/rax) |
|
||||
| Framework | Demo | |
|
||||
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
||||
| [React](app/react) | [v6.3.x](https://storybookjs.netlify.com/official-storybook/?path=/story/*) | [](app/react) |
|
||||
| [Vue](app/vue) | [v6.3.x](https://storybookjs.netlify.com/vue-kitchen-sink/) | [](app/vue) |
|
||||
| [Angular](app/angular) | [v6.3.x](https://storybookjs.netlify.com/angular-cli/) | [](app/angular) |
|
||||
| [Web components](app/web-components) | [v6.3.x](https://storybookjs.netlify.com/web-components-kitchen-sink/) | [](app/web-components) |
|
||||
| [React Native](https://github.com/storybookjs/react-native) | - | [](app/react-native) |
|
||||
| [HTML](app/html) | [v6.3.x](https://storybookjs.netlify.com/html-kitchen-sink/) | [](app/html) |
|
||||
| [Ember](app/ember) | [v6.3.x](https://storybookjs.netlify.com/ember-cli/) | [](app/ember) |
|
||||
| [Svelte](app/svelte) | [v6.3.x](https://storybookjs.netlify.com/svelte-kitchen-sink/) | [](app/svelte) |
|
||||
| [Preact](app/preact) | [v6.3.x](https://storybookjs.netlify.com/preact-kitchen-sink/) | [](app/preact) |
|
||||
| [Marionette.js](app/marionette) | - | [](app/marionette) |
|
||||
| [Mithril](app/mithril) | [v6.3.x](https://storybookjs.netlify.com/mithril-kitchen-sink/) | [](app/mithril) |
|
||||
| [Marko](app/marko) | [v6.3.x](https://storybookjs.netlify.com/marko-cli/) | [](app/marko) |
|
||||
| [Riot](app/riot) | [v6.3.x](https://storybookjs.netlify.com/riot-kitchen-sink/) | [](app/riot) |
|
||||
| [Rax](app/rax) | [v6.3.x](https://storybookjs.netlify.com/rax-kitchen-sink/) | [](app/rax) |
|
||||
| [Android, iOS, Flutter](https://github.com/storybookjs/native) | [v6.3.x](https://storybookjs.github.io/native/@storybook/native-flutter-example/index.html) | [](https://github.com/storybookjs/native) |
|
||||
|
||||
### Sub Projects
|
||||
|
||||
@ -122,35 +117,35 @@ For additional help, join us [in our Discord](https://discord.gg/sMFvFsG) or [Sl
|
||||
|
||||
### Addons
|
||||
|
||||
| Addons | |
|
||||
| ------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| [a11y](addons/a11y/) | Test components for user accessibility in Storybook |
|
||||
| [actions](addons/actions/) | Log actions as users interact with components in the Storybook UI |
|
||||
| [backgrounds](addons/backgrounds/) | Let users choose backgrounds in the Storybook UI |
|
||||
| [cssresources](addons/cssresources/) | Dynamically add/remove css resources to the component iframe |
|
||||
| [design assets](addons/design-assets/) | View images, videos, weblinks alongside your story |
|
||||
| [docs](addons/docs/) | Add high quality documentation to your components |
|
||||
| [events](addons/events/) | Interactively fire events to components that respond to EventEmitter |
|
||||
| [google-analytics](addons/google-analytics) | Reports google analytics on stories |
|
||||
| [graphql](addons/graphql/) | Query a GraphQL server within Storybook stories |
|
||||
| [jest](addons/jest/) | View the results of components' unit tests in Storybook |
|
||||
| [knobs](addons/knobs/) | Interactively edit component prop data in the Storybook UI |
|
||||
| [links](addons/links/) | Create links between stories |
|
||||
| [query params](addons/queryparams/) | Mock query params |
|
||||
| [storyshots](addons/storyshots/) | 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 |
|
||||
| Addons | |
|
||||
| ------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| [a11y](addons/a11y/) | Test components for user accessibility in Storybook |
|
||||
| [actions](addons/actions/) | Log actions as users interact with components in the Storybook UI |
|
||||
| [backgrounds](addons/backgrounds/) | Let users choose backgrounds in the Storybook UI |
|
||||
| [cssresources](https://github.com/storybookjs/addon-cssresources) | Dynamically add/remove css resources to the component iframe |
|
||||
| [design assets](https://github.com/storybookjs/addon-design-assets) | View images, videos, weblinks alongside your story |
|
||||
| [docs](addons/docs/) | Add high quality documentation to your components |
|
||||
| [events](https://github.com/storybookjs/addon-events) | Interactively fire events to components that respond to EventEmitter |
|
||||
| [google-analytics](https://github.com/storybookjs/addon-google-analytics) | Reports google analytics on stories |
|
||||
| [graphql](https://github.com/storybookjs/addon-graphql) | Query a GraphQL server within Storybook stories |
|
||||
| [jest](addons/jest/) | View the results of components' unit tests in Storybook |
|
||||
| [links](addons/links/) | Create links between stories |
|
||||
| [query params](https://github.com/storybookjs/addon-queryparams) | Mock query params |
|
||||
| [storyshots](addons/storyshots/) | 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)
|
||||
See [Addon / Framework Support Table](https://storybook.js.org/docs/react/api/frameworks-feature-support)
|
||||
|
||||
### Deprecated Addons
|
||||
|
||||
| Addons | |
|
||||
| ---------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
||||
| [info](https://github.com/storybookjs/deprecated-addons/tree/master/addons/info) | Annotate stories with extra component usage information |
|
||||
| [notes](https://github.com/storybookjs/deprecated-addons/tree/master/addons/notes) | Annotate Storybook stories with notes |
|
||||
| [contexts](https://github.com/storybookjs/storybook/tree/master/addons/contexts) | Addon for driving your components under dynamic contexts |
|
||||
| [options](https://github.com/storybookjs/storybook/tree/master/addons/options/) | Customize the Storybook UI in code |
|
||||
| Addons | |
|
||||
| -------------------------------------------------------------------------------- | ---------------------------------------------------------- |
|
||||
| [info](https://github.com/storybookjs/deprecated-addons/tree/main/addons/info) | Annotate stories with extra component usage information |
|
||||
| [notes](https://github.com/storybookjs/deprecated-addons/tree/main/addons/notes) | Annotate Storybook stories with notes |
|
||||
| [contexts](https://storybook.js.org/addons/@storybook/addon-contexts/) | Addon for driving your components under dynamic contexts |
|
||||
| [options](https://www.npmjs.com/package/@storybook/addon-options) | Customize the Storybook UI in code |
|
||||
| [knobs](https://github.com/storybookjs/addon-knobs) | Interactively edit component prop data in the Storybook UI |
|
||||
|
||||
In order to continue improving your experience, we have to eventually deprecate certain addons in favor of new, better tools.
|
||||
|
||||
@ -162,10 +157,10 @@ If you're using contexts, we highly recommend you to migrate to [toolbars](https
|
||||
|
||||
We have a badge! Link it to your live Storybook example.
|
||||
|
||||

|
||||

|
||||
|
||||
```md
|
||||
[](link to site)
|
||||
[](link to site)
|
||||
```
|
||||
|
||||
If you're looking for material to use in your presentation about storybook, like logo's video material and the colors we use etc, you can find all of that at our [brand repo](https://github.com/storybookjs/brand).
|
||||
@ -173,9 +168,8 @@ If you're looking for material to use in your presentation about storybook, like
|
||||
## Community
|
||||
|
||||
- Tweeting via [@storybookjs](https://twitter.com/storybookjs)
|
||||
- Blogging at [Medium](https://medium.com/storybookjs)
|
||||
- Chatting on [Slack](https://now-examples-slackin-rrirkqohko.now.sh/)
|
||||
- Discussions on [Discord](https://discord.gg/sMFvFsG)
|
||||
- Blogging at [storybook.js.org](https://storybook.js.org/blog/) and [Medium](https://medium.com/storybookjs)
|
||||
- Chatting on [Discord](https://discord.gg/storybook)
|
||||
- Streaming saved at [Youtube](https://www.youtube.com/channel/UCr7Quur3eIyA_oe8FNYexfg)
|
||||
|
||||
## Contributing
|
||||
@ -184,12 +178,12 @@ We welcome contributions to Storybook!
|
||||
|
||||
- 📥 Pull requests and 🌟 Stars are always welcome.
|
||||
- Read our [contributing guide](CONTRIBUTING.md) to get started,
|
||||
or find us on [Discord](https://discord.gg/sMFvFsG), we will take the time to guide you
|
||||
or find us on [Discord](https://discord.gg/storybook), we will take the time to guide you
|
||||
|
||||
Looking for a first issue to tackle?
|
||||
|
||||
- We tag issues with [](https://github.com/storybookjs/storybook/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) when we think they are well suited for people who are new to the codebase or OSS in general.
|
||||
- [Talk to us](https://discord.gg/sMFvFsG), we'll find something to suits your skills and learning interest.
|
||||
- [Talk to us](https://discord.gg/storybook), we'll find something to suits your skills and learning interest.
|
||||
|
||||
### Development scripts
|
||||
|
||||
@ -285,6 +279,6 @@ Support us with a monthly donation and help us continue our activities. \[[Becom
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/storybookjs/storybook/blob/master/LICENSE)
|
||||
[MIT](https://github.com/storybookjs/storybook/blob/main/LICENSE)
|
||||
|
||||
-the end-
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
A Storybook release process based on [Semver](http://semver.org/). In short:
|
||||
|
||||
1. Merge all PRs into `next`, which is the default branch. Cherry-pick bugfix PRs into `master`, which is the stable release.
|
||||
1. Merge all PRs into `next`, which is the default branch. Cherry-pick bugfix PRs into `main`, which is the stable release.
|
||||
|
||||
2. Every week: release patch releases off `master` to the NPM tag `latest`, and alpha releases off `next` to the NPM tag `next` (as e.g. `4.1.0-alpha.0`).
|
||||
2. Every week: release patch releases off `main` to the NPM tag `latest`, and alpha releases off `next` to the NPM tag `next` (as e.g. `4.1.0-alpha.0`).
|
||||
|
||||
3. Every month or two, merge `next` into `master` and release a minor/major version according to `semver`. We set minor release dates as soon as we have feature clarity and manage to those dates:
|
||||
3. Every month or two, merge `next` into `main` and release a minor/major version according to `semver`. We set minor release dates as soon as we have feature clarity and manage to those dates:
|
||||
- Date should be a Monday so if we slip we don't get pushed into the weekend
|
||||
- T-3wk:
|
||||
- Draft announcement and socialize
|
||||
@ -48,7 +48,7 @@ releases. We'll try our best to restrict breaking changes to MAJOR releases.
|
||||
Every bugfix should go out as soon as we've verified the fix, and based on the
|
||||
current rate of contribution, we should be issuing PATCH releases weekly.
|
||||
Eventually, we'll automate the process so that a release will go out every time a PR is
|
||||
merged into `master`, and we've already laid most of the groundwork for this.
|
||||
merged into `main`, and we've already laid most of the groundwork for this.
|
||||
|
||||
## MINOR releases
|
||||
|
||||
|
@ -15,4 +15,4 @@ You can submit a vulnerability in a Storybook package at: https://www.npmjs.com/
|
||||
|
||||
You can also reach out to the maintainers directly on Twitter: https://twitter.com/storybookjs
|
||||
|
||||
When we fix a security issue, we will post a security advisory on Github/NPM, describe the change in the [release notes](https://github.com/storybookjs/storybook/releases), and also announce notify the community on [our Discord](https://discord.com/invite/UUt2PJb).
|
||||
When we fix a security issue, we will post a security advisory on Github/NPM, describe the change in the [release notes](https://github.com/storybookjs/storybook/releases), and also announce notify the community on [our Discord](https://discord.gg/storybook).
|
||||
|
@ -1,4 +1,4 @@
|
||||
const fs = jest.genMockFromModule('fs');
|
||||
const fs = jest.createMockFromModule('fs');
|
||||
|
||||
// This is a custom function that our tests can use during setup to specify
|
||||
// what the files on the "mock" filesystem should look like when any of the
|
||||
|
@ -4,7 +4,7 @@ import { storiesOf, moduleMetadata } from '@storybook/angular';
|
||||
|
||||
@Component({
|
||||
selector: 'storybook-comp-with-store',
|
||||
template: '<div>{{this.getSotreState()}}</div>',
|
||||
template: '<div>{{this.getStoreState()}}</div>',
|
||||
})
|
||||
class WithStoreComponent {
|
||||
private store: Store<any>;
|
||||
@ -13,7 +13,7 @@ class WithStoreComponent {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
getSotreState(): string {
|
||||
getStoreState(): string {
|
||||
return this.store === undefined ? 'Store is NOT injected' : 'Store is injected';
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import React from 'react';
|
||||
|
||||
@Component({
|
||||
selector: 'storybook-comp-with-store',
|
||||
template: '<div>{{this.getSotreState()}}</div>',
|
||||
template: '<div>{{this.getStoreState()}}</div>',
|
||||
})
|
||||
class WithStoreComponent {
|
||||
private store: Store<any>;
|
||||
@ -14,7 +14,7 @@ class WithStoreComponent {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
getSotreState(): string {
|
||||
getStoreState(): string {
|
||||
return this.store === undefined ? 'Store is NOT injected' : 'Store is injected';
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
# storybook-addon-a11y
|
||||
|
||||
This storybook addon can be helpful to make your UI components more accessible.
|
||||
This Storybook addon can be helpful to make your UI components more accessible.
|
||||
|
||||
[Framework Support](https://github.com/storybookjs/storybook/blob/master/ADDONS_SUPPORT.md)
|
||||
[Framework Support](https://github.com/storybookjs/storybook/blob/main/ADDONS_SUPPORT.md)
|
||||
|
||||

|
||||
|
||||
@ -14,7 +14,7 @@ First, install the addon.
|
||||
$ yarn add @storybook/addon-a11y --dev
|
||||
```
|
||||
|
||||
Add this line to your `main.js` file (create this file inside your storybook config directory if needed).
|
||||
Add this line to your `main.js` file (create this file inside your Storybook config directory if needed).
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
@ -29,18 +29,132 @@ export default {
|
||||
title: 'button',
|
||||
};
|
||||
|
||||
export const accessible = () => <button>Accessible button</button>;
|
||||
export const Accessible = () => <button>Accessible button</button>;
|
||||
|
||||
export const inaccessible = () => (
|
||||
export const Inaccessible = () => (
|
||||
<button style={{ backgroundColor: 'red', color: 'darkRed' }}>Inaccessible button</button>
|
||||
);
|
||||
```
|
||||
|
||||
If you wish to selectively disable `a11y` checks for a subset of stories, you can control this with story parameters:
|
||||
## Handling failing rules
|
||||
|
||||
When Axe reports accessibility violations in stories, there are multiple ways to handle these failures depending on your needs.
|
||||
|
||||
### Story-level overrides
|
||||
|
||||
At the Story level, override rules using `parameters.a11y.config.rules`.
|
||||
|
||||
```js
|
||||
export const InputWithoutAutofill = () => <input type="text" autofill="nope" />;
|
||||
|
||||
InputWithoutAutofill.parameters = {
|
||||
a11y: {
|
||||
// Avoid doing this, as it will fully disable all accessibility checks for this story.
|
||||
disable: true,
|
||||
|
||||
// Instead, override rules 👇
|
||||
// axe-core configurationOptions (https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#parameters-1)
|
||||
config: {
|
||||
rules: [
|
||||
{
|
||||
// You can exclude some elements from failing a specific rule:
|
||||
id: 'autocomplete-valid',
|
||||
selector: '*:not([autocomplete="nope"])',
|
||||
},
|
||||
{
|
||||
// You can also signify that a violation will need to be fixed in the future
|
||||
// by overriding the result of a rule to return "Needs Review"
|
||||
// rather than "Violation" if the rule fails:
|
||||
id: 'landmark-complementary-is-top-level',
|
||||
reviewOnFail: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Alternatively, you can disable specific rules in a Story:
|
||||
|
||||
```js
|
||||
export const Inaccessible = () => (
|
||||
<button style={{ backgroundColor: 'red', color: 'darkRed' }}>Inaccessible button</button>
|
||||
);
|
||||
Inaccessible.parameters = {
|
||||
a11y: {
|
||||
config: {
|
||||
rules: [{ id: 'color-contrast', enabled: false }],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Tip: clearly explain in a comment why a rule was overridden, it’ll help you and your team trace back why certain violations aren’t being reported or need to be addressed. For example:
|
||||
|
||||
```js
|
||||
MyStory.parameters = {
|
||||
a11y: {
|
||||
options: {
|
||||
rules: [
|
||||
{
|
||||
// Allow `autocomplete="nope"` on form elements,
|
||||
// a workaround to disable autofill in Chrome.
|
||||
// @link https://bugs.chromium.org/p/chromium/issues/detail?id=468153
|
||||
id: 'autocomplete-valid',
|
||||
selector: '*:not([autocomplete="nope"])',
|
||||
},
|
||||
{
|
||||
// @fixme Color contrast of subdued text fails, as raised in issue #123.
|
||||
id: 'color-contrast',
|
||||
reviewOnFail: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Global overrides
|
||||
|
||||
When you want to ignore an accessibility rule or change its settings across all stories, set `parameters.a11y.config.rules` in your Storybook’s `preview.ts` file. This can be particularly useful for ignoring false positives commonly reported by Axe.
|
||||
|
||||
```ts
|
||||
// .storybook/preview.ts
|
||||
|
||||
export const parameters = {
|
||||
a11y: {
|
||||
config: {
|
||||
rules: [
|
||||
{
|
||||
// This tells Axe to run the 'autocomplete-valid' rule on selectors
|
||||
// that match '*:not([autocomplete="nope"])' (all elements except [autocomplete="nope"]).
|
||||
// This is the safest way of ignoring a violation across all stories,
|
||||
// as Axe will only ignore very specific elements and keep reporting
|
||||
// violations on other elements of this rule.
|
||||
id: 'autocomplete-valid',
|
||||
selector: '*:not([autocomplete="nope"])',
|
||||
},
|
||||
{
|
||||
// To disable a rule across all stories, set `enabled` to `false`.
|
||||
// Use with caution: all violations of this rule will be ignored!
|
||||
id: 'autocomplete-valid',
|
||||
enabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Disabling checks
|
||||
|
||||
If you wish to entirely disable `a11y` checks for a subset of stories, you can control this with story parameters:
|
||||
|
||||
```js
|
||||
export const MyNonCheckedStory = () => <SomeComponent />;
|
||||
MyNonCheckedStory.parameters = {
|
||||
// Avoid doing this, as it fully disables all accessibility checks for this story,
|
||||
// and consider the techniques described above.
|
||||
a11y: { disable: true },
|
||||
};
|
||||
```
|
||||
@ -48,7 +162,7 @@ MyNonCheckedStory.parameters = {
|
||||
## Parameters
|
||||
|
||||
For more customizability use parameters to configure [aXe options](https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure).
|
||||
You can override these options [at story level too](https://storybook.js.org/docs/react/configure/features-and-behavior#per-story-options.
|
||||
You can override these options [at story level too](https://storybook.js.org/docs/react/configure/features-and-behavior#per-story-options).
|
||||
|
||||
```js
|
||||
import React from 'react';
|
||||
|
@ -1,74 +1,93 @@
|
||||
{
|
||||
"name": "@storybook/addon-a11y",
|
||||
"version": "6.0.4",
|
||||
"description": "a11y addon for storybook",
|
||||
"version": "6.4.0-alpha.18",
|
||||
"description": "Test component compliance with web accessibility standards",
|
||||
"keywords": [
|
||||
"a11y",
|
||||
"accessibility",
|
||||
"addon",
|
||||
"storybook",
|
||||
"valid",
|
||||
"verify"
|
||||
"verify",
|
||||
"test"
|
||||
],
|
||||
"homepage": "https://github.com/storybookjs/storybook#readme",
|
||||
"homepage": "https://github.com/storybookjs/storybook/tree/main/addons/a11y",
|
||||
"bugs": {
|
||||
"url": "https://github.com/storybookjs/storybook/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/storybookjs/storybook.git",
|
||||
"url": "https://github.com/storybookjs/storybook.git",
|
||||
"directory": "addons/a11y"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/storybook"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"main": "dist/cjs/index.js",
|
||||
"module": "dist/esm/index.js",
|
||||
"types": "dist/ts3.9/index.d.ts",
|
||||
"typesVersions": {
|
||||
"<3.8": {
|
||||
"*": [
|
||||
"dist/ts3.4/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
"ts3.5/**/*"
|
||||
"*.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.4",
|
||||
"@storybook/api": "6.0.4",
|
||||
"@storybook/channels": "6.0.4",
|
||||
"@storybook/client-api": "6.0.4",
|
||||
"@storybook/client-logger": "6.0.4",
|
||||
"@storybook/components": "6.0.4",
|
||||
"@storybook/core-events": "6.0.4",
|
||||
"@storybook/theming": "6.0.4",
|
||||
"axe-core": "^3.5.2",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
"lodash": "^4.17.15",
|
||||
"react-sizeme": "^2.5.2",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"ts-dedent": "^1.1.1",
|
||||
"@storybook/addons": "6.4.0-alpha.18",
|
||||
"@storybook/api": "6.4.0-alpha.18",
|
||||
"@storybook/channels": "6.4.0-alpha.18",
|
||||
"@storybook/client-api": "6.4.0-alpha.18",
|
||||
"@storybook/client-logger": "6.4.0-alpha.18",
|
||||
"@storybook/components": "6.4.0-alpha.18",
|
||||
"@storybook/core-events": "6.4.0-alpha.18",
|
||||
"@storybook/theming": "6.4.0-alpha.18",
|
||||
"axe-core": "^4.2.0",
|
||||
"core-js": "^3.8.2",
|
||||
"global": "^4.4.0",
|
||||
"lodash": "^4.17.20",
|
||||
"react-sizeme": "^3.0.1",
|
||||
"regenerator-runtime": "^0.13.7",
|
||||
"ts-dedent": "^2.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/react": "^10.0.4",
|
||||
"@types/webpack-env": "^1.15.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1"
|
||||
"@testing-library/react": "^11.2.2",
|
||||
"@types/webpack-env": "^1.16.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-dom": "*"
|
||||
"react": "^16.8.0 || ^17.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"gitHead": "ca50653f3a10879a7e0677d2464677a86678c3fe",
|
||||
"typesVersions": {
|
||||
"<=3.5": {
|
||||
"*": [
|
||||
"ts3.5/*"
|
||||
]
|
||||
}
|
||||
"gitHead": "285782b4010609c6d6c9f306b8f8a110ae55f035",
|
||||
"sbmodern": "dist/modern/index.js",
|
||||
"storybook": {
|
||||
"displayName": "Accessibility",
|
||||
"icon": "https://user-images.githubusercontent.com/263385/101991665-47042f80-3c7c-11eb-8f00-64b5a18f498a.png",
|
||||
"unsupportedFrameworks": [
|
||||
"react-native"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1 +1,13 @@
|
||||
module.exports = require('./dist/preset');
|
||||
function managerEntries(entry = []) {
|
||||
return [...entry, require.resolve('./dist/esm/register')];
|
||||
}
|
||||
|
||||
function config(entry = []) {
|
||||
return [
|
||||
...entry,
|
||||
require.resolve('./dist/esm/a11yRunner'),
|
||||
require.resolve('./dist/esm/a11yHighlight'),
|
||||
];
|
||||
}
|
||||
|
||||
module.exports = { managerEntries, config };
|
||||
|
@ -1 +1 @@
|
||||
require('./dist/register');
|
||||
require('./dist/esm/register');
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { document } from 'global';
|
||||
import addons from '@storybook/addons';
|
||||
import global from 'global';
|
||||
import { addons } from '@storybook/addons';
|
||||
import { STORY_CHANGED } from '@storybook/core-events';
|
||||
import { EVENTS, HIGHLIGHT_STYLE_ID } from './constants';
|
||||
|
||||
import { higlightStyle } from './highlight';
|
||||
import { highlightStyle } from './highlight';
|
||||
|
||||
const { document } = global;
|
||||
|
||||
if (module && module.hot && module.hot.decline) {
|
||||
module.hot.decline();
|
||||
@ -21,13 +23,16 @@ const highlight = (infos: HighlightInfo) => {
|
||||
const id = HIGHLIGHT_STYLE_ID;
|
||||
resetHighlight();
|
||||
|
||||
// Make sure there are no duplicated selectors
|
||||
const elements = Array.from(new Set(infos.elements));
|
||||
|
||||
const sheet = document.createElement('style');
|
||||
sheet.setAttribute('id', id);
|
||||
sheet.innerHTML = infos.elements
|
||||
sheet.innerHTML = elements
|
||||
.map(
|
||||
(target) =>
|
||||
`${target}{
|
||||
${higlightStyle(infos.color)}
|
||||
`${target}{
|
||||
${highlightStyle(infos.color)}
|
||||
}`
|
||||
)
|
||||
.join(' ');
|
||||
|
@ -1,4 +1,4 @@
|
||||
import addons from '@storybook/addons';
|
||||
import { addons } from '@storybook/addons';
|
||||
import { EVENTS } from './constants';
|
||||
|
||||
jest.mock('@storybook/addons');
|
||||
|
@ -1,22 +1,39 @@
|
||||
import { document, window } from 'global';
|
||||
import global from 'global';
|
||||
import axe from 'axe-core';
|
||||
import addons from '@storybook/addons';
|
||||
import { addons } from '@storybook/addons';
|
||||
import { EVENTS } from './constants';
|
||||
import { Setup } from './params';
|
||||
import { A11yParameters } from './params';
|
||||
|
||||
const { document, window: globalWindow } = global;
|
||||
|
||||
if (module && module.hot && module.hot.decline) {
|
||||
module.hot.decline();
|
||||
}
|
||||
|
||||
const channel = addons.getChannel();
|
||||
// Holds axe core running state
|
||||
let active = false;
|
||||
// Holds latest story we requested a run
|
||||
let activeStoryId: string | undefined;
|
||||
|
||||
const getElement = () => {
|
||||
const storyRoot = document.getElementById('story-root');
|
||||
return storyRoot ? storyRoot.children : document.getElementById('root');
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle A11yContext events.
|
||||
* Because the event are sent without manual check, we split calls
|
||||
*/
|
||||
const handleRequest = (storyId: string) => {
|
||||
const { manual } = getParams(storyId);
|
||||
if (!manual) {
|
||||
run(storyId);
|
||||
}
|
||||
};
|
||||
|
||||
const run = async (storyId: string) => {
|
||||
activeStoryId = storyId;
|
||||
try {
|
||||
const input = getParams(storyId);
|
||||
|
||||
@ -24,14 +41,23 @@ const run = async (storyId: string) => {
|
||||
active = true;
|
||||
channel.emit(EVENTS.RUNNING);
|
||||
|
||||
const { element = getElement(), config, options } = input;
|
||||
const { element = getElement(), config, options = {} } = input;
|
||||
axe.reset();
|
||||
if (config) {
|
||||
axe.configure(config);
|
||||
}
|
||||
|
||||
const result = await axe.run(element, options);
|
||||
channel.emit(EVENTS.RESULT, result);
|
||||
// It's possible that we requested a new run on a different story.
|
||||
// Unfortunately, axe doesn't support a cancel method to abort current run.
|
||||
// We check if the story we run against is still the current one,
|
||||
// if not, trigger a new run using the current story
|
||||
if (activeStoryId === storyId) {
|
||||
channel.emit(EVENTS.RESULT, result);
|
||||
} else {
|
||||
active = false;
|
||||
run(activeStoryId);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
channel.emit(EVENTS.ERROR, error);
|
||||
@ -41,8 +67,8 @@ const run = async (storyId: string) => {
|
||||
};
|
||||
|
||||
/** Returns story parameters or default ones. */
|
||||
const getParams = (storyId: string): Setup => {
|
||||
const { parameters } = window.__STORYBOOK_STORY_STORE__.fromId(storyId) || {};
|
||||
const getParams = (storyId: string): A11yParameters => {
|
||||
const { parameters } = globalWindow.__STORYBOOK_STORY_STORE__.fromId(storyId) || {};
|
||||
return (
|
||||
parameters.a11y || {
|
||||
config: {},
|
||||
@ -53,5 +79,5 @@ const getParams = (storyId: string): Setup => {
|
||||
);
|
||||
};
|
||||
|
||||
channel.on(EVENTS.REQUEST, run);
|
||||
channel.on(EVENTS.REQUEST, handleRequest);
|
||||
channel.on(EVENTS.MANUAL, run);
|
||||
|
@ -1,3 +1,3 @@
|
||||
import { withA11y } from '../index';
|
||||
import { withA11y } from '.';
|
||||
|
||||
export const decorators = [withA11y];
|
@ -1,16 +1,16 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { styled } from '@storybook/theming';
|
||||
|
||||
import { ActionBar, Icons, ScrollArea } from '@storybook/components';
|
||||
|
||||
import { AxeResults } from 'axe-core';
|
||||
import { useChannel, useParameter, useStorybookState, useAddonState } from '@storybook/api';
|
||||
import { useChannel, useParameter, useStorybookState } from '@storybook/api';
|
||||
import { Report } from './Report';
|
||||
import { Tabs } from './Tabs';
|
||||
|
||||
import { useA11yContext } from './A11yContext';
|
||||
import { EVENTS, ADDON_ID } from '../constants';
|
||||
import { EVENTS } from '../constants';
|
||||
import { A11yParameters } from '../params';
|
||||
|
||||
export enum RuleType {
|
||||
@ -51,13 +51,13 @@ const Centered = styled.span<{}>({
|
||||
type Status = 'initial' | 'manual' | 'running' | 'error' | 'ran' | 'ready';
|
||||
|
||||
export const A11YPanel: React.FC = () => {
|
||||
const [status, setStatus] = useAddonState<Status>(ADDON_ID, 'initial');
|
||||
const [error, setError] = React.useState<unknown>(undefined);
|
||||
const { setResults, results } = useA11yContext();
|
||||
const { storyId } = useStorybookState();
|
||||
const { manual } = useParameter<Pick<A11yParameters, 'manual'>>('a11y', {
|
||||
manual: false,
|
||||
});
|
||||
const [status, setStatus] = useState<Status>(manual ? 'manual' : 'initial');
|
||||
const [error, setError] = React.useState<unknown>(undefined);
|
||||
const { setResults, results } = useA11yContext();
|
||||
const { storyId } = useStorybookState();
|
||||
|
||||
React.useEffect(() => {
|
||||
setStatus(manual ? 'manual' : 'initial');
|
||||
|
@ -64,9 +64,9 @@ export const A11yContextProvider: React.FC<A11yContextProviderProps> = ({ active
|
||||
: prevHighlighted.filter((t) => !target.includes(t))
|
||||
);
|
||||
}, []);
|
||||
const handleRun = React.useCallback(() => {
|
||||
emit(EVENTS.REQUEST, storyId);
|
||||
}, [storyId]);
|
||||
const handleRun = (renderedStoryId: string) => {
|
||||
emit(EVENTS.REQUEST, renderedStoryId);
|
||||
};
|
||||
const handleClearHighlights = React.useCallback(() => setHighlighted([]), []);
|
||||
const handleSetTab = React.useCallback((index: number) => {
|
||||
handleClearHighlights();
|
||||
@ -90,7 +90,7 @@ export const A11yContextProvider: React.FC<A11yContextProviderProps> = ({ active
|
||||
|
||||
React.useEffect(() => {
|
||||
if (active) {
|
||||
handleRun();
|
||||
handleRun(storyId);
|
||||
} else {
|
||||
handleClearHighlights();
|
||||
}
|
||||
|
@ -24,7 +24,10 @@ const HighlightToggleElement = styled.span({
|
||||
fontWeight: 'normal',
|
||||
alignSelf: 'center',
|
||||
paddingRight: 15,
|
||||
input: { margin: 0 },
|
||||
input: {
|
||||
margin: 0,
|
||||
display: 'block',
|
||||
},
|
||||
});
|
||||
|
||||
interface ElementProps {
|
||||
|
@ -69,7 +69,7 @@ describe('<HighlightToggle />', () => {
|
||||
${['#root']} | ${['#root']} | ${false}
|
||||
${['#root']} | ${['#root', '#root1']} | ${true}
|
||||
`(
|
||||
'should be triggerd with $expected when highlighted is $highlighted and elementsToHighlight is $elementsToHighlight',
|
||||
'should be triggered with $expected when highlighted is $highlighted and elementsToHighlight is $elementsToHighlight',
|
||||
({ highlighted, elementsToHighlight, expected }) => {
|
||||
const { getByRole } = render(
|
||||
<A11yContext.Provider
|
||||
|
@ -7,7 +7,7 @@ const Wrapper = styled.div({
|
||||
padding: 12,
|
||||
marginBottom: 10,
|
||||
});
|
||||
const Help = styled.p({
|
||||
const Description = styled.p({
|
||||
margin: '0 0 12px',
|
||||
});
|
||||
const Link = styled.a({
|
||||
@ -24,7 +24,7 @@ interface InfoProps {
|
||||
export const Info: FunctionComponent<InfoProps> = ({ item }) => {
|
||||
return (
|
||||
<Wrapper>
|
||||
<Help>{item.help}</Help>
|
||||
<Description>{item.description}</Description>
|
||||
<Link href={item.helpUrl} target="_blank">
|
||||
More info...
|
||||
</Link>
|
||||
|
@ -33,6 +33,7 @@ const Icon = styled<any, any>(Icons)(({ theme }) => ({
|
||||
const HeaderBar = styled.div<{}>(({ theme }) => ({
|
||||
padding: theme.layoutMargin,
|
||||
paddingLeft: theme.layoutMargin - 3,
|
||||
lineHeight: '20px',
|
||||
background: 'none',
|
||||
color: 'inherit',
|
||||
textAlign: 'left',
|
||||
@ -51,7 +52,10 @@ const HighlightToggleElement = styled.span({
|
||||
float: 'right',
|
||||
marginRight: 15,
|
||||
alignSelf: 'center',
|
||||
input: { margin: 0 },
|
||||
input: {
|
||||
margin: 0,
|
||||
display: 'block',
|
||||
},
|
||||
});
|
||||
|
||||
interface ItemProps {
|
||||
@ -78,7 +82,7 @@ export const Item = (props: ItemProps) => {
|
||||
transform: `rotate(${open ? 0 : -90}deg)`,
|
||||
}}
|
||||
/>
|
||||
{item.description}
|
||||
{item.help}
|
||||
</HeaderBar>
|
||||
<HighlightToggleElement>
|
||||
<HighlightToggle toggleId={highlightToggleId} elementsToHighlight={item.nodes} />
|
||||
|
@ -71,8 +71,8 @@ const Rule: FunctionComponent<RuleProps> = ({ rule }) => {
|
||||
}
|
||||
return (
|
||||
<SizeMe refreshMode="debounce">
|
||||
{({ size }: { size: { width: number; height: number } }) => (
|
||||
<Item elementWidth={size.width}>
|
||||
{({ size }) => (
|
||||
<Item elementWidth={size.width || 0}>
|
||||
<StyledBadge status={badgeType}>{formatSeverityText(rule.impact)}</StyledBadge>
|
||||
<Message>{rule.message}</Message>
|
||||
</Item>
|
||||
|
@ -18,30 +18,29 @@ const Container = styled.div({
|
||||
const HighlightToggleLabel = styled.label<{}>(({ theme }) => ({
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
marginBottom: 3,
|
||||
marginRight: 3,
|
||||
color: theme.color.dark,
|
||||
}));
|
||||
|
||||
const GlobalToggle = styled.div<{ elementWidth: number }>(({ elementWidth }) => {
|
||||
const GlobalToggle = styled.div<{ elementWidth: number }>(({ elementWidth, theme }) => {
|
||||
const maxWidthBeforeBreak = 450;
|
||||
return {
|
||||
cursor: 'pointer',
|
||||
fontSize: '14px',
|
||||
padding: elementWidth > maxWidthBeforeBreak ? '12px 15px 10px 0' : '12px 0px 3px 12px',
|
||||
fontSize: 13,
|
||||
lineHeight: '20px',
|
||||
padding: elementWidth > maxWidthBeforeBreak ? '10px 15px 10px 0' : '10px 0px 10px 15px',
|
||||
height: '40px',
|
||||
border: 'none',
|
||||
marginTop: elementWidth > maxWidthBeforeBreak ? -40 : 0,
|
||||
float: elementWidth > maxWidthBeforeBreak ? 'right' : 'left',
|
||||
display: elementWidth > maxWidthBeforeBreak ? 'flex' : 'block',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: elementWidth > maxWidthBeforeBreak ? 'auto' : '100%',
|
||||
borderBottom: elementWidth > maxWidthBeforeBreak ? 'none' : '1px solid rgba(0,0,0,.1)',
|
||||
borderBottom: elementWidth > maxWidthBeforeBreak ? 'none' : `1px solid ${theme.appBorderColor}`,
|
||||
|
||||
input: {
|
||||
marginLeft: 10,
|
||||
marginRight: 0,
|
||||
marginTop: 0,
|
||||
marginTop: -1,
|
||||
marginBottom: 0,
|
||||
},
|
||||
};
|
||||
@ -112,7 +111,7 @@ export const Tabs: React.FC<TabsProps> = ({ tabs }) => {
|
||||
const highlightLabel = `Highlight results`;
|
||||
return (
|
||||
<SizeMe refreshMode="debounce">
|
||||
{({ size }: { size: any }) => (
|
||||
{({ size }) => (
|
||||
<Container>
|
||||
<List>
|
||||
<TabsWrapper>
|
||||
@ -130,7 +129,7 @@ export const Tabs: React.FC<TabsProps> = ({ tabs }) => {
|
||||
</TabsWrapper>
|
||||
</List>
|
||||
{tabs[activeTab].items.length > 0 ? (
|
||||
<GlobalToggle elementWidth={size.width}>
|
||||
<GlobalToggle elementWidth={size.width || 0}>
|
||||
<HighlightToggleLabel htmlFor={highlightToggleId}>
|
||||
{highlightLabel}
|
||||
</HighlightToggleLabel>
|
||||
|
@ -7,15 +7,16 @@ import { Filters } from './ColorFilters';
|
||||
const iframeId = 'storybook-preview-iframe';
|
||||
|
||||
const baseList = [
|
||||
'protanopia',
|
||||
'protanomaly',
|
||||
'deuteranopia',
|
||||
'blurred vision',
|
||||
'deuteranomaly',
|
||||
'tritanopia',
|
||||
'deuteranopia',
|
||||
'protanomaly',
|
||||
'protanopia',
|
||||
'tritanomaly',
|
||||
'achromatopsia',
|
||||
'tritanopia',
|
||||
'achromatomaly',
|
||||
'mono',
|
||||
'achromatopsia',
|
||||
'grayscale',
|
||||
] as const;
|
||||
|
||||
type Filter = typeof baseList[number] | null;
|
||||
@ -24,7 +25,10 @@ const getFilter = (filter: Filter) => {
|
||||
if (!filter) {
|
||||
return 'none';
|
||||
}
|
||||
if (filter === 'mono') {
|
||||
if (filter === 'blurred vision') {
|
||||
return 'blur(2px)';
|
||||
}
|
||||
if (filter === 'grayscale') {
|
||||
return 'grayscale(100%)';
|
||||
}
|
||||
return `url('#${filter}')`;
|
||||
@ -87,7 +91,7 @@ const getColorList = (active: Filter, set: (i: Filter) => void): Link[] => [
|
||||
})),
|
||||
];
|
||||
|
||||
export const ColorBlindness: FunctionComponent = () => {
|
||||
export const VisionSimulator: FunctionComponent = () => {
|
||||
const [filter, setFilter] = useState<Filter>(null);
|
||||
|
||||
return (
|
||||
@ -114,8 +118,8 @@ export const ColorBlindness: FunctionComponent = () => {
|
||||
closeOnClick
|
||||
onDoubleClick={() => setFilter(null)}
|
||||
>
|
||||
<IconButton key="filter" active={!!filter} title="Color Blindness Emulation">
|
||||
<Icons icon="mirror" />
|
||||
<IconButton key="filter" active={!!filter} title="Vision simulator">
|
||||
<Icons icon="accessibility" />
|
||||
</IconButton>
|
||||
</WithTooltip>
|
||||
<Hidden>
|
@ -1,8 +1,7 @@
|
||||
export const higlightStyle = (color: string) => `
|
||||
export const highlightStyle = (color: string) => `
|
||||
outline: 2px dashed ${color};
|
||||
outline-offset: 2px;
|
||||
box-shadow: 0 0 0 6px rgba(255,255,255,0.6);
|
||||
}
|
||||
`;
|
||||
|
||||
export const highlightObject = (color: string) => ({
|
||||
|
@ -1,7 +0,0 @@
|
||||
export function managerEntries(entry: any[] = []) {
|
||||
return [...entry, require.resolve('../register')];
|
||||
}
|
||||
|
||||
export function config(entry: any[] = []) {
|
||||
return [...entry, require.resolve('../a11yRunner'), require.resolve('../a11yHighlight')];
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { addons, types } from '@storybook/addons';
|
||||
import { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants';
|
||||
import { ColorBlindness } from './components/ColorBlindness';
|
||||
import { VisionSimulator } from './components/VisionSimulator';
|
||||
import { A11YPanel } from './components/A11YPanel';
|
||||
import { A11yContextProvider } from './components/A11yContext';
|
||||
|
||||
@ -10,7 +10,7 @@ addons.register(ADDON_ID, () => {
|
||||
title: '',
|
||||
type: types.TOOL,
|
||||
match: ({ viewMode }) => viewMode === 'story',
|
||||
render: () => <ColorBlindness />,
|
||||
render: () => <VisionSimulator />,
|
||||
});
|
||||
|
||||
addons.add(PANEL_ID, {
|
||||
|
1
addons/a11y/src/typings.d.ts
vendored
1
addons/a11y/src/typings.d.ts
vendored
@ -1,2 +1 @@
|
||||
declare module 'global';
|
||||
declare module 'react-sizeme';
|
||||
|
@ -11,5 +11,12 @@
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["src/__tests__/**/*"]
|
||||
"exclude": [
|
||||
"src/**/*.test.*",
|
||||
"src/**/tests/**/*",
|
||||
"src/**/__tests__/**/*",
|
||||
"src/**/*.stories.*",
|
||||
"src/**/*.mockdata.*",
|
||||
"src/**/__testfixtures__/**"
|
||||
]
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ This document describes the pre-6.0 usage of the addon, and as such is no longer
|
||||
|
||||
Import the `action` function and use it to create actions handlers. When creating action handlers, provide a **name** to make it easier to identify.
|
||||
|
||||
> _Note: Make sure NOT to use reserved words as function names. [issues#29](https://github.com/storybookjs/storybook-addon-actions/issues/29#issuecomment-288274794)_
|
||||
> _Note: Be mindful of the choice of the function's name. Avoid using Javascript reserved words such as **default** or **if**, as they will lead into unexpected errors._
|
||||
|
||||
```js
|
||||
import { action } from '@storybook/addon-actions';
|
||||
|
@ -1,11 +1,13 @@
|
||||
{
|
||||
"name": "@storybook/addon-actions",
|
||||
"version": "6.0.4",
|
||||
"description": "Action Logger addon for storybook",
|
||||
"version": "6.4.0-alpha.18",
|
||||
"description": "Get UI feedback when an action is performed on an interactive element",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
"storybook",
|
||||
"essentials",
|
||||
"data-state"
|
||||
],
|
||||
"homepage": "https://github.com/storybookjs/storybook/tree/master/addons/actions",
|
||||
"homepage": "https://github.com/storybookjs/storybook/tree/main/addons/actions",
|
||||
"bugs": {
|
||||
"url": "https://github.com/storybookjs/storybook/issues"
|
||||
},
|
||||
@ -14,56 +16,75 @@
|
||||
"url": "https://github.com/storybookjs/storybook.git",
|
||||
"directory": "addons/actions"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/storybook"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"main": "dist/cjs/index.js",
|
||||
"module": "dist/esm/index.js",
|
||||
"types": "dist/ts3.9/index.d.ts",
|
||||
"typesVersions": {
|
||||
"<3.8": {
|
||||
"*": [
|
||||
"dist/ts3.4/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
"ts3.5/**/*"
|
||||
"*.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.4",
|
||||
"@storybook/api": "6.0.4",
|
||||
"@storybook/client-api": "6.0.4",
|
||||
"@storybook/components": "6.0.4",
|
||||
"@storybook/core-events": "6.0.4",
|
||||
"@storybook/theming": "6.0.4",
|
||||
"core-js": "^3.0.1",
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"global": "^4.3.2",
|
||||
"lodash": "^4.17.15",
|
||||
"polished": "^3.4.4",
|
||||
"@storybook/addons": "6.4.0-alpha.18",
|
||||
"@storybook/api": "6.4.0-alpha.18",
|
||||
"@storybook/client-api": "6.4.0-alpha.18",
|
||||
"@storybook/components": "6.4.0-alpha.18",
|
||||
"@storybook/core-events": "6.4.0-alpha.18",
|
||||
"@storybook/theming": "6.4.0-alpha.18",
|
||||
"core-js": "^3.8.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"global": "^4.4.0",
|
||||
"lodash": "^4.17.20",
|
||||
"polished": "^4.0.5",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.8.3",
|
||||
"react-inspector": "^5.0.1",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"ts-dedent": "^1.1.1",
|
||||
"react-inspector": "^5.1.0",
|
||||
"regenerator-runtime": "^0.13.7",
|
||||
"ts-dedent": "^2.0.0",
|
||||
"util-deprecate": "^1.0.2",
|
||||
"uuid": "^8.0.0"
|
||||
"uuid-browser": "^3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.150",
|
||||
"@types/uuid": "^7.0.3",
|
||||
"@types/webpack-env": "^1.15.2"
|
||||
"@types/lodash": "^4.14.167",
|
||||
"@types/webpack-env": "^1.16.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-dom": "*"
|
||||
"react": "^16.8.0 || ^17.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"gitHead": "ca50653f3a10879a7e0677d2464677a86678c3fe",
|
||||
"typesVersions": {
|
||||
"<=3.5": {
|
||||
"*": [
|
||||
"ts3.5/*"
|
||||
]
|
||||
}
|
||||
"gitHead": "285782b4010609c6d6c9f306b8f8a110ae55f035",
|
||||
"sbmodern": "dist/modern/index.js",
|
||||
"storybook": {
|
||||
"displayName": "Actions",
|
||||
"unsupportedFrameworks": [
|
||||
"react-native"
|
||||
],
|
||||
"icon": "https://user-images.githubusercontent.com/263385/101991666-479cc600-3c7c-11eb-837b-be4e5ffa1bb8.png"
|
||||
}
|
||||
}
|
||||
|
@ -1 +1,16 @@
|
||||
module.exports = require('./dist/preset');
|
||||
function managerEntries(entry, options) {
|
||||
return [...entry, require.resolve('./dist/esm/register')];
|
||||
}
|
||||
|
||||
function config(entry = [], { addDecorator = true } = {}) {
|
||||
const actionConfig = [];
|
||||
if (addDecorator) {
|
||||
actionConfig.push(require.resolve('./dist/esm/preset/addDecorator'));
|
||||
}
|
||||
return [...entry, ...actionConfig, require.resolve('./dist/esm/preset/addArgs')];
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
managerEntries,
|
||||
config,
|
||||
};
|
||||
|
@ -1 +1 @@
|
||||
require('./dist/register');
|
||||
require('./dist/esm/register');
|
||||
|
@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
|
||||
import { API } from '@storybook/api';
|
||||
import { STORY_RENDERED } from '@storybook/core-events';
|
||||
import { STORY_CHANGED } from '@storybook/core-events';
|
||||
|
||||
import { ActionLogger as ActionLoggerComponent } from '../../components/ActionLogger';
|
||||
import { EVENT_ID } from '../..';
|
||||
@ -39,14 +39,14 @@ export default class ActionLogger extends Component<ActionLoggerProps, ActionLog
|
||||
const { api } = this.props;
|
||||
|
||||
api.on(EVENT_ID, this.addAction);
|
||||
api.on(STORY_RENDERED, this.handleStoryChange);
|
||||
api.on(STORY_CHANGED, this.handleStoryChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.mounted = false;
|
||||
const { api } = this.props;
|
||||
|
||||
api.off(STORY_RENDERED, this.handleStoryChange);
|
||||
api.off(STORY_CHANGED, this.handleStoryChange);
|
||||
api.off(EVENT_ID, this.addAction);
|
||||
}
|
||||
|
||||
|
@ -1,76 +0,0 @@
|
||||
import { StoryContext } from '@storybook/addons';
|
||||
import { inferActionsFromArgTypesRegex, addActionsFromArgTypes } from './addArgs';
|
||||
|
||||
const withDefaultValue = (argTypes) =>
|
||||
Object.keys(argTypes).filter((key) => !!argTypes[key].defaultValue);
|
||||
|
||||
describe('actions parameter enhancers', () => {
|
||||
describe('actions.argTypesRegex parameter', () => {
|
||||
const baseParameters = {
|
||||
argTypes: { onClick: {}, onFocus: {}, somethingElse: {} },
|
||||
actions: { argTypesRegex: '^on.*' },
|
||||
};
|
||||
|
||||
it('should add actions that match a pattern', () => {
|
||||
const parameters = baseParameters;
|
||||
const argTypes = inferActionsFromArgTypesRegex({ parameters } as StoryContext);
|
||||
expect(withDefaultValue(argTypes)).toEqual(['onClick', 'onFocus']);
|
||||
});
|
||||
|
||||
it('should prioritize pre-existing argTypes unless they are null', () => {
|
||||
const parameters = {
|
||||
...baseParameters,
|
||||
argTypes: {
|
||||
onClick: { defaultValue: 'pre-existing value' },
|
||||
onFocus: { defaultValue: null },
|
||||
},
|
||||
};
|
||||
const argTypes = inferActionsFromArgTypesRegex({ parameters } as StoryContext);
|
||||
expect(withDefaultValue(argTypes)).toEqual(['onClick', 'onFocus']);
|
||||
expect(argTypes.onClick.defaultValue).toEqual('pre-existing value');
|
||||
expect(argTypes.onFocus.defaultValue).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should do nothing if actions are disabled', () => {
|
||||
const parameters = {
|
||||
...baseParameters,
|
||||
actions: { ...baseParameters.actions, disable: true },
|
||||
};
|
||||
const result = inferActionsFromArgTypesRegex({ parameters } as StoryContext);
|
||||
expect(result).toEqual(parameters.argTypes);
|
||||
});
|
||||
});
|
||||
|
||||
describe('argTypes.action parameter', () => {
|
||||
const baseParameters = {
|
||||
argTypes: {
|
||||
onClick: { action: 'clicked!' },
|
||||
onBlur: { action: 'blurred!' },
|
||||
},
|
||||
};
|
||||
it('should add actions based on action.args', () => {
|
||||
const parameters = baseParameters;
|
||||
const argTypes = addActionsFromArgTypes({ parameters } as StoryContext);
|
||||
expect(withDefaultValue(argTypes)).toEqual(['onClick', 'onBlur']);
|
||||
});
|
||||
|
||||
it('should prioritize pre-existing args', () => {
|
||||
const parameters = {
|
||||
...baseParameters,
|
||||
argTypes: {
|
||||
onClick: { defaultValue: 'pre-existing value', action: 'onClick' },
|
||||
onBlur: { action: 'onBlur' },
|
||||
},
|
||||
};
|
||||
const argTypes = addActionsFromArgTypes({ parameters } as StoryContext);
|
||||
expect(withDefaultValue(argTypes)).toEqual(['onClick', 'onBlur']);
|
||||
expect(argTypes.onClick.defaultValue).toEqual('pre-existing value');
|
||||
});
|
||||
|
||||
it('should do nothing if actions are disabled', () => {
|
||||
const parameters = { ...baseParameters, actions: { disable: true } };
|
||||
const result = addActionsFromArgTypes({ parameters } as StoryContext);
|
||||
expect(result).toEqual(parameters.argTypes);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,48 +1,3 @@
|
||||
import mapValues from 'lodash/mapValues';
|
||||
import { ArgTypesEnhancer } from '@storybook/client-api';
|
||||
import { addActionsFromArgTypes, inferActionsFromArgTypesRegex } from './addArgsHelpers';
|
||||
|
||||
import { action } from '../index';
|
||||
|
||||
// interface ActionsParameter {
|
||||
// disable?: boolean;
|
||||
// argTypesRegex?: RegExp;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Automatically add action args for argTypes whose name
|
||||
* matches a regex, such as `^on.*` for react-style `onClick` etc.
|
||||
*/
|
||||
export const inferActionsFromArgTypesRegex: ArgTypesEnhancer = (context) => {
|
||||
const { actions, argTypes } = context.parameters;
|
||||
if (!actions || actions.disable || !actions.argTypesRegex || !argTypes) {
|
||||
return argTypes;
|
||||
}
|
||||
|
||||
const argTypesRegex = new RegExp(actions.argTypesRegex);
|
||||
return mapValues(argTypes, (argType, name) => {
|
||||
if (!argTypesRegex.test(name)) {
|
||||
return argType;
|
||||
}
|
||||
return { ...argType, defaultValue: argType.defaultValue || action(name) };
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Add action args for list of strings.
|
||||
*/
|
||||
export const addActionsFromArgTypes: ArgTypesEnhancer = (context) => {
|
||||
const { argTypes, actions } = context.parameters;
|
||||
if (actions?.disable || !argTypes) {
|
||||
return argTypes;
|
||||
}
|
||||
|
||||
return mapValues(argTypes, (argType, name) => {
|
||||
if (!argType.action) {
|
||||
return argType;
|
||||
}
|
||||
const message = typeof argType.action === 'string' ? argType.action : name;
|
||||
return { ...argType, defaultValue: argType.defaultValue || action(message) };
|
||||
});
|
||||
};
|
||||
|
||||
export const argTypesEnhancers = [addActionsFromArgTypes, inferActionsFromArgTypesRegex];
|
||||
export const argsEnhancers = [addActionsFromArgTypes, inferActionsFromArgTypesRegex];
|
||||
|
115
addons/actions/src/preset/addArgsHelpers.test.ts
Normal file
115
addons/actions/src/preset/addArgsHelpers.test.ts
Normal file
@ -0,0 +1,115 @@
|
||||
import { StoryContext } from '@storybook/addons';
|
||||
import { inferActionsFromArgTypesRegex, addActionsFromArgTypes } from './addArgsHelpers';
|
||||
|
||||
describe('actions parameter enhancers', () => {
|
||||
describe('actions.argTypesRegex parameter', () => {
|
||||
const parameters = { actions: { argTypesRegex: '^on.*' } };
|
||||
const argTypes = { onClick: {}, onFocus: {}, somethingElse: {} };
|
||||
|
||||
it('should add actions that match a pattern', () => {
|
||||
const args = inferActionsFromArgTypesRegex(({
|
||||
args: {},
|
||||
argTypes,
|
||||
parameters,
|
||||
} as unknown) as StoryContext);
|
||||
expect(args).toEqual({
|
||||
onClick: expect.any(Function),
|
||||
onFocus: expect.any(Function),
|
||||
});
|
||||
});
|
||||
|
||||
it('should NOT override pre-existing args', () => {
|
||||
const args = inferActionsFromArgTypesRegex(({
|
||||
args: { onClick: 'pre-existing value' },
|
||||
argTypes,
|
||||
parameters,
|
||||
} as unknown) as StoryContext);
|
||||
expect(args).toEqual({ onFocus: expect.any(Function) });
|
||||
});
|
||||
|
||||
it('should NOT override pre-existing args, if null', () => {
|
||||
const args = inferActionsFromArgTypesRegex(({
|
||||
args: { onClick: null },
|
||||
argTypes,
|
||||
parameters,
|
||||
} as unknown) as StoryContext);
|
||||
expect(args).toEqual({ onFocus: expect.any(Function) });
|
||||
});
|
||||
|
||||
it('should override pre-existing args, if undefined', () => {
|
||||
const args = inferActionsFromArgTypesRegex(({
|
||||
args: { onClick: undefined },
|
||||
argTypes,
|
||||
parameters,
|
||||
} as unknown) as StoryContext);
|
||||
expect(args).toEqual({ onClick: expect.any(Function), onFocus: expect.any(Function) });
|
||||
});
|
||||
|
||||
it('should do nothing if actions are disabled', () => {
|
||||
const args = inferActionsFromArgTypesRegex(({
|
||||
args: {},
|
||||
argTypes,
|
||||
parameters: {
|
||||
...parameters,
|
||||
actions: { ...parameters.actions, disable: true },
|
||||
},
|
||||
} as unknown) as StoryContext);
|
||||
expect(args).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('argTypes.action parameter', () => {
|
||||
const argTypes = {
|
||||
onClick: { action: 'clicked!' },
|
||||
onBlur: { action: 'blurred!' },
|
||||
};
|
||||
it('should add actions based on action.args', () => {
|
||||
expect(
|
||||
addActionsFromArgTypes(({ args: {}, argTypes, parameters: {} } as unknown) as StoryContext)
|
||||
).toEqual({
|
||||
onClick: expect.any(Function),
|
||||
onBlur: expect.any(Function),
|
||||
});
|
||||
});
|
||||
|
||||
it('should NOT override pre-existing args', () => {
|
||||
expect(
|
||||
addActionsFromArgTypes(({
|
||||
argTypes: { onClick: { action: 'clicked!' } },
|
||||
args: { onClick: 'pre-existing value' },
|
||||
parameters: {},
|
||||
} as unknown) as StoryContext)
|
||||
).toEqual({});
|
||||
});
|
||||
|
||||
it('should NOT override pre-existing args, if null', () => {
|
||||
expect(
|
||||
addActionsFromArgTypes(({
|
||||
argTypes: { onClick: { action: 'clicked!' } },
|
||||
args: { onClick: null },
|
||||
parameters: {},
|
||||
} as unknown) as StoryContext)
|
||||
).toEqual({});
|
||||
});
|
||||
|
||||
it('should override pre-existing args, if undefined', () => {
|
||||
expect(
|
||||
addActionsFromArgTypes(({
|
||||
argTypes: { onClick: { action: 'clicked!' } },
|
||||
args: { onClick: undefined },
|
||||
parameters: {},
|
||||
} as unknown) as StoryContext)
|
||||
).toEqual({ onClick: expect.any(Function) });
|
||||
});
|
||||
|
||||
it('should do nothing if actions are disabled', () => {
|
||||
expect(
|
||||
addActionsFromArgTypes(({
|
||||
args: {},
|
||||
argTypes,
|
||||
parameters: { actions: { disable: true } },
|
||||
} as unknown) as StoryContext)
|
||||
).toEqual({});
|
||||
});
|
||||
});
|
||||
});
|
59
addons/actions/src/preset/addArgsHelpers.ts
Normal file
59
addons/actions/src/preset/addArgsHelpers.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { Args } from '@storybook/addons';
|
||||
import { ArgsEnhancer } from '@storybook/client-api';
|
||||
import { action } from '../index';
|
||||
|
||||
// interface ActionsParameter {
|
||||
// disable?: boolean;
|
||||
// argTypesRegex?: RegExp;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Automatically add action args for argTypes whose name
|
||||
* matches a regex, such as `^on.*` for react-style `onClick` etc.
|
||||
*/
|
||||
|
||||
export const inferActionsFromArgTypesRegex: ArgsEnhancer = (context) => {
|
||||
const {
|
||||
args,
|
||||
argTypes,
|
||||
parameters: { actions },
|
||||
} = context;
|
||||
if (!actions || actions.disable || !actions.argTypesRegex || !argTypes) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const argTypesRegex = new RegExp(actions.argTypesRegex);
|
||||
const argTypesMatchingRegex = Object.entries(argTypes).filter(
|
||||
([name]) => !!argTypesRegex.test(name)
|
||||
);
|
||||
|
||||
return argTypesMatchingRegex.reduce((acc, [name, argType]) => {
|
||||
if (typeof args[name] === 'undefined') {
|
||||
acc[name] = action(name);
|
||||
}
|
||||
return acc;
|
||||
}, {} as Args);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add action args for list of strings.
|
||||
*/
|
||||
export const addActionsFromArgTypes: ArgsEnhancer = (context) => {
|
||||
const {
|
||||
args,
|
||||
argTypes,
|
||||
parameters: { actions },
|
||||
} = context;
|
||||
if (actions?.disable || !argTypes) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const argTypesWithAction = Object.entries(argTypes).filter(([name, argType]) => !!argType.action);
|
||||
|
||||
return argTypesWithAction.reduce((acc, [name, argType]) => {
|
||||
if (typeof args[name] === 'undefined') {
|
||||
acc[name] = action(typeof argType.action === 'string' ? argType.action : name);
|
||||
}
|
||||
return acc;
|
||||
}, {} as Args);
|
||||
};
|
@ -1,15 +0,0 @@
|
||||
interface ActionsOptions {
|
||||
addDecorator?: boolean;
|
||||
}
|
||||
|
||||
export function managerEntries(entry: any[] = [], options: any) {
|
||||
return [...entry, require.resolve('../register')];
|
||||
}
|
||||
|
||||
export function config(entry: any[] = [], { addDecorator = true }: ActionsOptions = {}) {
|
||||
const actionConfig = [];
|
||||
if (addDecorator) {
|
||||
actionConfig.push(require.resolve('./addDecorator'));
|
||||
}
|
||||
return [...entry, ...actionConfig, require.resolve('./addArgs')];
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import addons from '@storybook/addons';
|
||||
import { addons } from '@storybook/addons';
|
||||
import { action, configureActions } from '../..';
|
||||
|
||||
jest.mock('@storybook/addons');
|
||||
@ -16,7 +16,7 @@ describe('Action', () => {
|
||||
|
||||
action('test-action')('one');
|
||||
|
||||
expect(getChannelData(channel)[0]).toEqual('one');
|
||||
expect(getChannelData(channel)).toEqual('one');
|
||||
});
|
||||
|
||||
it('with multiple arguments', () => {
|
||||
@ -46,7 +46,7 @@ describe('Depth config', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(getChannelData(channel)[0]).toEqual({
|
||||
expect(getChannelData(channel)).toEqual({
|
||||
root: {
|
||||
one: {
|
||||
two: 'foo',
|
||||
@ -76,7 +76,7 @@ describe('Depth config', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(getChannelData(channel)[0]).toEqual({
|
||||
expect(getChannelData(channel)).toEqual({
|
||||
root: {
|
||||
one: {
|
||||
two: {
|
||||
@ -111,7 +111,7 @@ describe('allowFunction config', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(getChannelData(channel)[0]).toEqual({
|
||||
expect(getChannelData(channel)).toEqual({
|
||||
root: {
|
||||
one: {
|
||||
a: 1,
|
||||
@ -140,7 +140,7 @@ describe('allowFunction config', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(getChannelData(channel)[0]).toEqual({
|
||||
expect(getChannelData(channel)).toEqual({
|
||||
root: {
|
||||
one: {
|
||||
a: 1,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import addons from '@storybook/addons';
|
||||
import { addons } from '@storybook/addons';
|
||||
import { actions } from '../..';
|
||||
|
||||
jest.mock('@storybook/addons');
|
||||
@ -20,7 +20,7 @@ describe('Actions', () => {
|
||||
expect(Object.keys(actionsResult)).toEqual(['test-action']);
|
||||
actionsResult['test-action']('one');
|
||||
|
||||
expect(getChannelData(channel, 0)).toEqual({ name: 'test-action', args: ['one'] });
|
||||
expect(getChannelData(channel, 0)).toEqual({ name: 'test-action', args: 'one' });
|
||||
});
|
||||
|
||||
it('with multiple arguments', () => {
|
||||
@ -33,8 +33,8 @@ describe('Actions', () => {
|
||||
actionsResult['test-action']('one');
|
||||
actionsResult['test-action2']('two');
|
||||
|
||||
expect(getChannelData(channel, 0)).toEqual({ name: 'test-action', args: ['one'] });
|
||||
expect(getChannelData(channel, 1)).toEqual({ name: 'test-action2', args: ['two'] });
|
||||
expect(getChannelData(channel, 0)).toEqual({ name: 'test-action', args: 'one' });
|
||||
expect(getChannelData(channel, 1)).toEqual({ name: 'test-action2', args: 'two' });
|
||||
});
|
||||
|
||||
it('with multiple arguments + config', () => {
|
||||
@ -47,8 +47,8 @@ describe('Actions', () => {
|
||||
actionsResult['test-action']('one');
|
||||
actionsResult['test-action2']('two');
|
||||
|
||||
expect(getChannelData(channel, 0)).toEqual({ name: 'test-action', args: ['one'] });
|
||||
expect(getChannelData(channel, 1)).toEqual({ name: 'test-action2', args: ['two'] });
|
||||
expect(getChannelData(channel, 0)).toEqual({ name: 'test-action', args: 'one' });
|
||||
expect(getChannelData(channel, 1)).toEqual({ name: 'test-action2', args: 'two' });
|
||||
|
||||
expect(getChannelOptions(channel, 0).some).toEqual('config');
|
||||
expect(getChannelOptions(channel, 1).some).toEqual('config');
|
||||
@ -67,8 +67,8 @@ describe('Actions', () => {
|
||||
actionsResult['test-action']('one');
|
||||
actionsResult['test-action2']('two');
|
||||
|
||||
expect(getChannelData(channel, 0)).toEqual({ name: 'test action', args: ['one'] });
|
||||
expect(getChannelData(channel, 1)).toEqual({ name: 'test action two', args: ['two'] });
|
||||
expect(getChannelData(channel, 0)).toEqual({ name: 'test action', args: 'one' });
|
||||
expect(getChannelData(channel, 1)).toEqual({ name: 'test action two', args: 'two' });
|
||||
});
|
||||
|
||||
it('with first argument as array of arguments + config', () => {
|
||||
@ -81,8 +81,8 @@ describe('Actions', () => {
|
||||
actionsResult['test-action']('one');
|
||||
actionsResult['test-action2']('two');
|
||||
|
||||
expect(getChannelData(channel, 0)).toEqual({ name: 'test-action', args: ['one'] });
|
||||
expect(getChannelData(channel, 1)).toEqual({ name: 'test-action2', args: ['two'] });
|
||||
expect(getChannelData(channel, 0)).toEqual({ name: 'test-action', args: 'one' });
|
||||
expect(getChannelData(channel, 1)).toEqual({ name: 'test-action2', args: 'two' });
|
||||
|
||||
expect(getChannelOptions(channel, 0).some).toEqual('config');
|
||||
expect(getChannelOptions(channel, 1).some).toEqual('config');
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import uuidv4 from 'uuid-browser/v4';
|
||||
import { addons } from '@storybook/addons';
|
||||
import { EVENT_ID } from '../constants';
|
||||
import { ActionDisplay, ActionOptions, HandlerFunction } from '../models';
|
||||
@ -14,11 +14,12 @@ export function action(name: string, options: ActionOptions = {}): HandlerFuncti
|
||||
const channel = addons.getChannel();
|
||||
const id = uuidv4();
|
||||
const minDepth = 5; // anything less is really just storybook internals
|
||||
const normalizedArgs = args.length > 1 ? args : args[0];
|
||||
|
||||
const actionDisplayToEmit: ActionDisplay = {
|
||||
id,
|
||||
count: 0,
|
||||
data: { name, args },
|
||||
data: { name, args: normalizedArgs },
|
||||
options: {
|
||||
...actionOptions,
|
||||
depth: minDepth + (actionOptions.depth || 3),
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Based on http://backbonejs.org/docs/backbone.html#section-164
|
||||
import { document, Element } from 'global';
|
||||
import global from 'global';
|
||||
import { useEffect } from '@storybook/client-api';
|
||||
import deprecate from 'util-deprecate';
|
||||
import dedent from 'ts-dedent';
|
||||
@ -9,6 +9,8 @@ import { actions } from './actions';
|
||||
|
||||
import { PARAM_KEY } from '../constants';
|
||||
|
||||
const { document, Element } = global;
|
||||
|
||||
const delegateEventSplitter = /^(\S+)\s*(.*)$/;
|
||||
|
||||
const isIE = Element != null && !Element.prototype.matches;
|
||||
|
@ -1,11 +1,27 @@
|
||||
import React from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { addons, types } from '@storybook/addons';
|
||||
import { STORY_CHANGED } from '@storybook/core-events';
|
||||
import ActionLogger from './containers/ActionLogger';
|
||||
import { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants';
|
||||
import { ADDON_ID, EVENT_ID, PANEL_ID, PARAM_KEY } from './constants';
|
||||
|
||||
addons.register(ADDON_ID, (api) => {
|
||||
addons.addPanel(PANEL_ID, {
|
||||
title: 'Actions',
|
||||
title() {
|
||||
const [actionsCount, setActionsCount] = useState(0);
|
||||
const onEvent = () => setActionsCount((previous) => previous + 1);
|
||||
const onChange = () => setActionsCount(0);
|
||||
|
||||
useEffect(() => {
|
||||
api.on(EVENT_ID, onEvent);
|
||||
api.on(STORY_CHANGED, onChange);
|
||||
return () => {
|
||||
api.off(EVENT_ID, onEvent);
|
||||
api.off(STORY_CHANGED, onChange);
|
||||
};
|
||||
});
|
||||
const suffix = actionsCount === 0 ? '' : ` (${actionsCount})`;
|
||||
return `Actions${suffix}`;
|
||||
},
|
||||
type: types.PANEL,
|
||||
render: ({ active, key }) => <ActionLogger key={key} api={api} active={active} />,
|
||||
paramKey: PARAM_KEY,
|
||||
|
1
addons/actions/src/typings.d.ts
vendored
1
addons/actions/src/typings.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
// TODO: following packages need definition files or a TS migration
|
||||
declare module 'global';
|
||||
declare module 'react-inspector';
|
||||
declare module 'uuid-browser/v4';
|
||||
|
@ -5,5 +5,12 @@
|
||||
"types": ["webpack-env", "jest"]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["src/__tests__/**/*", "src/**/*.test.ts"]
|
||||
"exclude": [
|
||||
"src/**/*.test.*",
|
||||
"src/**/tests/**/*",
|
||||
"src/**/__tests__/**/*",
|
||||
"src/**/*.stories.*",
|
||||
"src/**/*.mockdata.*",
|
||||
"src/**/__testfixtures__/**"
|
||||
]
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ Storybook Addon Backgrounds can be used to change background colors inside the p
|
||||
|
||||
[Framework Support](https://storybook.js.org/docs/react/api/frameworks-feature-support)
|
||||
|
||||

|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
|
@ -1,14 +1,16 @@
|
||||
{
|
||||
"name": "@storybook/addon-backgrounds",
|
||||
"version": "6.0.4",
|
||||
"description": "A storybook addon to show different backgrounds for your preview",
|
||||
"version": "6.4.0-alpha.18",
|
||||
"description": "Switch backgrounds to view components in different settings",
|
||||
"keywords": [
|
||||
"addon",
|
||||
"background",
|
||||
"react",
|
||||
"storybook"
|
||||
"storybook",
|
||||
"essentials",
|
||||
"design"
|
||||
],
|
||||
"homepage": "https://github.com/storybookjs/storybook/tree/master/addons/backgrounds",
|
||||
"homepage": "https://github.com/storybookjs/storybook/tree/main/addons/backgrounds",
|
||||
"bugs": {
|
||||
"url": "https://github.com/storybookjs/storybook/issues"
|
||||
},
|
||||
@ -17,47 +19,70 @@
|
||||
"url": "https://github.com/storybookjs/storybook.git",
|
||||
"directory": "addons/backgrounds"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/storybook"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "jbaxleyiii",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"main": "dist/cjs/index.js",
|
||||
"module": "dist/esm/index.js",
|
||||
"types": "dist/ts3.9/index.d.ts",
|
||||
"typesVersions": {
|
||||
"<3.8": {
|
||||
"*": [
|
||||
"dist/ts3.4/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
"ts3.5/**/*"
|
||||
"*.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.4",
|
||||
"@storybook/api": "6.0.4",
|
||||
"@storybook/client-logger": "6.0.4",
|
||||
"@storybook/components": "6.0.4",
|
||||
"@storybook/core-events": "6.0.4",
|
||||
"@storybook/theming": "6.0.4",
|
||||
"core-js": "^3.0.1",
|
||||
"@storybook/addons": "6.4.0-alpha.18",
|
||||
"@storybook/api": "6.4.0-alpha.18",
|
||||
"@storybook/client-logger": "6.4.0-alpha.18",
|
||||
"@storybook/components": "6.4.0-alpha.18",
|
||||
"@storybook/core-events": "6.4.0-alpha.18",
|
||||
"@storybook/theming": "6.4.0-alpha.18",
|
||||
"core-js": "^3.8.2",
|
||||
"global": "^4.4.0",
|
||||
"memoizerific": "^1.11.3",
|
||||
"react": "^16.8.3",
|
||||
"regenerator-runtime": "^0.13.3"
|
||||
"regenerator-runtime": "^0.13.7",
|
||||
"ts-dedent": "^2.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/webpack-env": "^1.15.2"
|
||||
"@types/webpack-env": "^1.16.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-dom": "*"
|
||||
"react": "^16.8.0 || ^17.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"gitHead": "ca50653f3a10879a7e0677d2464677a86678c3fe",
|
||||
"typesVersions": {
|
||||
"<=3.5": {
|
||||
"*": [
|
||||
"ts3.5/*"
|
||||
]
|
||||
}
|
||||
"gitHead": "285782b4010609c6d6c9f306b8f8a110ae55f035",
|
||||
"sbmodern": "dist/modern/index.js",
|
||||
"storybook": {
|
||||
"displayName": "Backgrounds",
|
||||
"icon": "https://user-images.githubusercontent.com/263385/101991667-479cc600-3c7c-11eb-96d3-410e936252e7.png",
|
||||
"unsupportedFrameworks": [
|
||||
"react-native"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1 +1,16 @@
|
||||
module.exports = require('./dist/preset');
|
||||
function config(entry = []) {
|
||||
return [
|
||||
...entry,
|
||||
require.resolve('./dist/esm/preset/addDecorator'),
|
||||
require.resolve('./dist/esm/preset/addParameter'),
|
||||
];
|
||||
}
|
||||
|
||||
function managerEntries(entry = [], options) {
|
||||
return [...entry, require.resolve('./dist/esm/register')];
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
managerEntries,
|
||||
config,
|
||||
};
|
||||
|
@ -1 +1 @@
|
||||
require('./dist/register');
|
||||
require('./dist/esm/register');
|
||||
|
@ -1,51 +1,14 @@
|
||||
import React, { Component, Fragment, ReactElement } from 'react';
|
||||
import React, { FunctionComponent, Fragment, useCallback, useMemo, memo } from 'react';
|
||||
import memoize from 'memoizerific';
|
||||
|
||||
import { Combo, Consumer, API } from '@storybook/api';
|
||||
import { Global, Theme } from '@storybook/theming';
|
||||
import { useParameter, useGlobals } from '@storybook/api';
|
||||
import { logger } from '@storybook/client-logger';
|
||||
|
||||
import { Icons, IconButton, WithTooltip, TooltipLinkList } from '@storybook/components';
|
||||
|
||||
import { PARAM_KEY as BACKGROUNDS_PARAM_KEY, EVENTS } from '../constants';
|
||||
import { PARAM_KEY as BACKGROUNDS_PARAM_KEY } from '../constants';
|
||||
import { ColorIcon } from '../components/ColorIcon';
|
||||
|
||||
interface GlobalState {
|
||||
name: string | undefined;
|
||||
selected: string | undefined;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
api: API;
|
||||
}
|
||||
|
||||
interface BackgroundSelectorItem {
|
||||
id: string;
|
||||
title: string;
|
||||
onClick: () => void;
|
||||
value: string;
|
||||
right?: ReactElement;
|
||||
}
|
||||
|
||||
interface Background {
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface BackgroundsParameter {
|
||||
default?: string;
|
||||
disable?: boolean;
|
||||
values: Background[];
|
||||
}
|
||||
|
||||
interface BackgroundsConfig {
|
||||
backgrounds: Background[] | null;
|
||||
selectedBackground: string | null;
|
||||
defaultBackgroundName: string | null;
|
||||
disable: boolean;
|
||||
}
|
||||
|
||||
const iframeId = 'storybook-preview-iframe';
|
||||
import { BackgroundSelectorItem, Background, BackgroundsParameter, GlobalState } from '../types';
|
||||
import { getBackgroundColorByName } from '../helpers';
|
||||
|
||||
const createBackgroundSelectorItem = memoize(1000)(
|
||||
(
|
||||
@ -53,7 +16,8 @@ const createBackgroundSelectorItem = memoize(1000)(
|
||||
name: string,
|
||||
value: string,
|
||||
hasSwatch: boolean,
|
||||
change: (arg: { selected: string; name: string }) => void
|
||||
change: (arg: { selected: string; name: string }) => void,
|
||||
active: boolean
|
||||
): BackgroundSelectorItem => ({
|
||||
id: id || name,
|
||||
title: name,
|
||||
@ -62,6 +26,7 @@ const createBackgroundSelectorItem = memoize(1000)(
|
||||
},
|
||||
value,
|
||||
right: hasSwatch ? <ColorIcon background={value} /> : undefined,
|
||||
active,
|
||||
})
|
||||
);
|
||||
|
||||
@ -72,12 +37,26 @@ const getDisplayedItems = memoize(10)(
|
||||
change: (arg: { selected: string; name: string }) => void
|
||||
) => {
|
||||
const backgroundSelectorItems = backgrounds.map(({ name, value }) =>
|
||||
createBackgroundSelectorItem(null, name, value, true, change)
|
||||
createBackgroundSelectorItem(
|
||||
null,
|
||||
name,
|
||||
value,
|
||||
true,
|
||||
change,
|
||||
value === selectedBackgroundColor
|
||||
)
|
||||
);
|
||||
|
||||
if (selectedBackgroundColor !== 'transparent') {
|
||||
return [
|
||||
createBackgroundSelectorItem('reset', 'Clear background', 'transparent', null, change),
|
||||
createBackgroundSelectorItem(
|
||||
'reset',
|
||||
'Clear background',
|
||||
'transparent',
|
||||
null,
|
||||
change,
|
||||
false
|
||||
),
|
||||
...backgroundSelectorItems,
|
||||
];
|
||||
}
|
||||
@ -86,131 +65,78 @@ const getDisplayedItems = memoize(10)(
|
||||
}
|
||||
);
|
||||
|
||||
const getSelectedBackgroundColor = (
|
||||
backgrounds: Background[] = [],
|
||||
currentSelectedValue: string,
|
||||
defaultName: string
|
||||
): string => {
|
||||
if (currentSelectedValue === 'transparent') {
|
||||
return 'transparent';
|
||||
}
|
||||
|
||||
if (backgrounds.find((background) => background.value === currentSelectedValue)) {
|
||||
return currentSelectedValue;
|
||||
}
|
||||
|
||||
const defaultBackground = backgrounds.find((background) => background.name === defaultName);
|
||||
if (defaultBackground) {
|
||||
return defaultBackground.value;
|
||||
}
|
||||
|
||||
if (defaultName) {
|
||||
const availableColors = backgrounds.map((background) => background.name).join(', ');
|
||||
logger.warn(
|
||||
`Backgrounds Addon: could not find the default color "${defaultName}".
|
||||
These are the available colors for your story based on your configuration: ${availableColors}`
|
||||
);
|
||||
}
|
||||
|
||||
return 'transparent';
|
||||
const DEFAULT_BACKGROUNDS_CONFIG: BackgroundsParameter = {
|
||||
default: null,
|
||||
disable: true,
|
||||
values: [],
|
||||
};
|
||||
|
||||
const getBackgroundsConfig = ({ api, state }: Combo): BackgroundsConfig => {
|
||||
const backgroundsParameter = api.getCurrentParameter<BackgroundsParameter>(BACKGROUNDS_PARAM_KEY);
|
||||
const selectedBackgroundValue = state.addons[BACKGROUNDS_PARAM_KEY] || null;
|
||||
export const BackgroundSelector: FunctionComponent = memo(() => {
|
||||
const backgroundsConfig = useParameter<BackgroundsParameter>(
|
||||
BACKGROUNDS_PARAM_KEY,
|
||||
DEFAULT_BACKGROUNDS_CONFIG
|
||||
);
|
||||
|
||||
if (Array.isArray(backgroundsParameter)) {
|
||||
const [globals, updateGlobals] = useGlobals();
|
||||
|
||||
const globalsBackgroundColor = globals[BACKGROUNDS_PARAM_KEY]?.value;
|
||||
|
||||
const selectedBackgroundColor = useMemo(() => {
|
||||
return getBackgroundColorByName(
|
||||
globalsBackgroundColor,
|
||||
backgroundsConfig.values,
|
||||
backgroundsConfig.default
|
||||
);
|
||||
}, [backgroundsConfig, globalsBackgroundColor]);
|
||||
|
||||
if (Array.isArray(backgroundsConfig)) {
|
||||
logger.warn(
|
||||
'Addon Backgrounds api has changed in Storybook 6.0. Please refer to the migration guide: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md'
|
||||
);
|
||||
}
|
||||
|
||||
const isBackgroundsEmpty = !backgroundsParameter?.values?.length;
|
||||
if (backgroundsParameter?.disable || isBackgroundsEmpty) {
|
||||
// other null properties are necessary to keep the same return shape for Consumer memoization
|
||||
return {
|
||||
disable: true,
|
||||
backgrounds: null,
|
||||
selectedBackground: null,
|
||||
defaultBackgroundName: null,
|
||||
};
|
||||
const onBackgroundChange = useCallback(
|
||||
(value: string) => {
|
||||
updateGlobals({ [BACKGROUNDS_PARAM_KEY]: { ...globals[BACKGROUNDS_PARAM_KEY], value } });
|
||||
},
|
||||
[backgroundsConfig, globals, updateGlobals]
|
||||
);
|
||||
|
||||
if (backgroundsConfig.disable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
disable: false,
|
||||
backgrounds: backgroundsParameter?.values,
|
||||
selectedBackground: selectedBackgroundValue,
|
||||
defaultBackgroundName: backgroundsParameter?.default,
|
||||
};
|
||||
};
|
||||
|
||||
export class BackgroundSelector extends Component<Props> {
|
||||
change = ({ selected, name }: GlobalState) => {
|
||||
const { api } = this.props;
|
||||
if (typeof selected === 'string') {
|
||||
api.setAddonState<string>(BACKGROUNDS_PARAM_KEY, selected);
|
||||
}
|
||||
api.emit(EVENTS.UPDATE, { selected, name });
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Consumer filter={getBackgroundsConfig}>
|
||||
{({
|
||||
disable,
|
||||
backgrounds,
|
||||
selectedBackground,
|
||||
defaultBackgroundName,
|
||||
}: BackgroundsConfig) => {
|
||||
if (disable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const selectedBackgroundColor = getSelectedBackgroundColor(
|
||||
backgrounds,
|
||||
selectedBackground,
|
||||
defaultBackgroundName
|
||||
);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<WithTooltip
|
||||
placement="top"
|
||||
trigger="click"
|
||||
closeOnClick
|
||||
tooltip={({ onHide }) => {
|
||||
return (
|
||||
<Fragment>
|
||||
{selectedBackgroundColor ? (
|
||||
<Global
|
||||
styles={(theme: Theme) => ({
|
||||
[`#${iframeId}`]: {
|
||||
background:
|
||||
selectedBackgroundColor === 'transparent'
|
||||
? theme.background.content
|
||||
: selectedBackgroundColor,
|
||||
},
|
||||
})}
|
||||
/>
|
||||
) : null}
|
||||
<WithTooltip
|
||||
placement="top"
|
||||
trigger="click"
|
||||
closeOnClick
|
||||
tooltip={({ onHide }) => (
|
||||
<TooltipLinkList
|
||||
links={getDisplayedItems(backgrounds, selectedBackgroundColor, (i) => {
|
||||
this.change(i);
|
||||
onHide();
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
>
|
||||
<IconButton
|
||||
key="background"
|
||||
title="Change the background of the preview"
|
||||
active={selectedBackgroundColor !== 'transparent'}
|
||||
>
|
||||
<Icons icon="photo" />
|
||||
</IconButton>
|
||||
</WithTooltip>
|
||||
</Fragment>
|
||||
<TooltipLinkList
|
||||
links={getDisplayedItems(
|
||||
backgroundsConfig.values,
|
||||
selectedBackgroundColor,
|
||||
({ selected }: GlobalState) => {
|
||||
if (selectedBackgroundColor !== selected) {
|
||||
onBackgroundChange(selected);
|
||||
}
|
||||
onHide();
|
||||
}
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</Consumer>
|
||||
);
|
||||
}
|
||||
}
|
||||
>
|
||||
<IconButton
|
||||
key="background"
|
||||
title="Change the background of the preview"
|
||||
active={selectedBackgroundColor !== 'transparent'}
|
||||
>
|
||||
<Icons icon="photo" />
|
||||
</IconButton>
|
||||
</WithTooltip>
|
||||
</Fragment>
|
||||
);
|
||||
});
|
||||
|
@ -1,51 +1,35 @@
|
||||
import React, { FunctionComponent, memo } from 'react';
|
||||
|
||||
import { useAddonState, useParameter } from '@storybook/api';
|
||||
import { Global } from '@storybook/theming';
|
||||
import { useGlobals, useParameter } from '@storybook/api';
|
||||
import { Icons, IconButton } from '@storybook/components';
|
||||
|
||||
import { ADDON_ID, GRID_PARAM_KEY } from '../constants';
|
||||
|
||||
export interface BackgroundGridParameters {
|
||||
cellSize: number;
|
||||
}
|
||||
|
||||
const iframeId = 'storybook-preview-iframe';
|
||||
import { PARAM_KEY as BACKGROUNDS_PARAM_KEY } from '../constants';
|
||||
|
||||
export const GridSelector: FunctionComponent = memo(() => {
|
||||
const [state, setState] = useAddonState<boolean>(`${ADDON_ID}/grid`);
|
||||
const { cellSize } = useParameter<BackgroundGridParameters>(GRID_PARAM_KEY, { cellSize: 20 });
|
||||
const [globals, updateGlobals] = useGlobals();
|
||||
|
||||
const { grid } = useParameter(BACKGROUNDS_PARAM_KEY, {
|
||||
grid: { disable: false },
|
||||
});
|
||||
|
||||
if (grid?.disable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isActive = globals[BACKGROUNDS_PARAM_KEY]?.grid || false;
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
key="background"
|
||||
active={state}
|
||||
title="Change the background of the preview"
|
||||
onClick={() => setState(!state)}
|
||||
active={isActive}
|
||||
title="Apply a grid to the preview"
|
||||
onClick={() =>
|
||||
updateGlobals({
|
||||
[BACKGROUNDS_PARAM_KEY]: { ...globals[BACKGROUNDS_PARAM_KEY], grid: !isActive },
|
||||
})
|
||||
}
|
||||
>
|
||||
<Icons icon="grid" />
|
||||
{state ? (
|
||||
<Global
|
||||
styles={{
|
||||
[`#${iframeId}`]: {
|
||||
backgroundSize: [
|
||||
`${cellSize * 5}px ${cellSize * 5}px`,
|
||||
`${cellSize * 5}px ${cellSize * 5}px`,
|
||||
`${cellSize}px ${cellSize}px`,
|
||||
`${cellSize}px ${cellSize}px`,
|
||||
].join(', '),
|
||||
backgroundPosition: '-1px -1px, -1px -1px, -1px -1px, -1px -1px',
|
||||
backgroundBlendMode: 'difference',
|
||||
backgroundImage: [
|
||||
'linear-gradient(rgba(130, 130, 130, 0.5) 1px, transparent 1px)',
|
||||
'linear-gradient(90deg, rgba(130, 130, 130, 0.5) 1px, transparent 1px)',
|
||||
'linear-gradient(rgba(130, 130, 130, 0.25) 1px, transparent 1px)',
|
||||
'linear-gradient(90deg, rgba(130, 130, 130, 0.25) 1px, transparent 1px)',
|
||||
].join(', '),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</IconButton>
|
||||
);
|
||||
});
|
||||
|
2
addons/backgrounds/src/decorators/index.ts
Normal file
2
addons/backgrounds/src/decorators/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './withBackground';
|
||||
export * from './withGrid';
|
65
addons/backgrounds/src/decorators/withBackground.ts
Normal file
65
addons/backgrounds/src/decorators/withBackground.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import { StoryFn as StoryFunction, StoryContext, useMemo, useEffect } from '@storybook/addons';
|
||||
|
||||
import { PARAM_KEY as BACKGROUNDS_PARAM_KEY } from '../constants';
|
||||
import {
|
||||
clearStyles,
|
||||
addBackgroundStyle,
|
||||
getBackgroundColorByName,
|
||||
isReduceMotionEnabled,
|
||||
} from '../helpers';
|
||||
|
||||
export const withBackground = (StoryFn: StoryFunction, context: StoryContext) => {
|
||||
const { globals, parameters } = context;
|
||||
const globalsBackgroundColor = globals[BACKGROUNDS_PARAM_KEY]?.value;
|
||||
const backgroundsConfig = parameters[BACKGROUNDS_PARAM_KEY];
|
||||
|
||||
const selectedBackgroundColor = useMemo(() => {
|
||||
if (backgroundsConfig.disable) {
|
||||
return 'transparent';
|
||||
}
|
||||
|
||||
return getBackgroundColorByName(
|
||||
globalsBackgroundColor,
|
||||
backgroundsConfig.values,
|
||||
backgroundsConfig.default
|
||||
);
|
||||
}, [backgroundsConfig, globalsBackgroundColor]);
|
||||
|
||||
const isActive = useMemo(
|
||||
() => selectedBackgroundColor && selectedBackgroundColor !== 'transparent',
|
||||
[selectedBackgroundColor]
|
||||
);
|
||||
|
||||
const selector =
|
||||
context.viewMode === 'docs' ? `#anchor--${context.id} .docs-story` : '.sb-show-main';
|
||||
|
||||
const backgroundStyles = useMemo(() => {
|
||||
const transitionStyle = 'transition: background-color 0.3s;';
|
||||
return `
|
||||
${selector} {
|
||||
background: ${selectedBackgroundColor} !important;
|
||||
${isReduceMotionEnabled() ? '' : transitionStyle}
|
||||
}
|
||||
`;
|
||||
}, [selectedBackgroundColor, selector]);
|
||||
|
||||
useEffect(() => {
|
||||
const selectorId =
|
||||
context.viewMode === 'docs'
|
||||
? `addon-backgrounds-docs-${context.id}`
|
||||
: `addon-backgrounds-color`;
|
||||
|
||||
if (!isActive) {
|
||||
clearStyles(selectorId);
|
||||
return;
|
||||
}
|
||||
|
||||
addBackgroundStyle(
|
||||
selectorId,
|
||||
backgroundStyles,
|
||||
context.viewMode === 'docs' ? context.id : null
|
||||
);
|
||||
}, [isActive, backgroundStyles, context]);
|
||||
|
||||
return StoryFn();
|
||||
};
|
79
addons/backgrounds/src/decorators/withGrid.ts
Normal file
79
addons/backgrounds/src/decorators/withGrid.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import dedent from 'ts-dedent';
|
||||
import deprecate from 'util-deprecate';
|
||||
import { StoryFn as StoryFunction, StoryContext, useMemo, useEffect } from '@storybook/addons';
|
||||
|
||||
import { clearStyles, addGridStyle } from '../helpers';
|
||||
import { PARAM_KEY as BACKGROUNDS_PARAM_KEY } from '../constants';
|
||||
|
||||
const deprecatedCellSizeWarning = deprecate(
|
||||
() => {},
|
||||
dedent`
|
||||
Backgrounds Addon: The cell size parameter has been changed.
|
||||
|
||||
- parameters.grid.cellSize should now be parameters.backgrounds.grid.cellSize
|
||||
See https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-grid-parameter
|
||||
`
|
||||
);
|
||||
|
||||
export const withGrid = (StoryFn: StoryFunction, context: StoryContext) => {
|
||||
const { globals, parameters } = context;
|
||||
const gridParameters = parameters[BACKGROUNDS_PARAM_KEY].grid;
|
||||
const isActive = globals[BACKGROUNDS_PARAM_KEY]?.grid === true && gridParameters.disable !== true;
|
||||
const { cellAmount, cellSize, opacity } = gridParameters;
|
||||
const isInDocs = context.viewMode === 'docs';
|
||||
|
||||
let gridSize: number;
|
||||
if (parameters.grid?.cellSize) {
|
||||
gridSize = parameters.grid.cellSize;
|
||||
deprecatedCellSizeWarning();
|
||||
} else {
|
||||
gridSize = cellSize;
|
||||
}
|
||||
|
||||
const isLayoutPadded = parameters.layout === undefined || parameters.layout === 'padded';
|
||||
// 16px offset in the grid to account for padded layout
|
||||
const defaultOffset = isLayoutPadded ? 16 : 0;
|
||||
const offsetX = gridParameters.offsetX ?? (isInDocs ? 20 : defaultOffset);
|
||||
const offsetY = gridParameters.offsetY ?? (isInDocs ? 20 : defaultOffset);
|
||||
|
||||
const gridStyles = useMemo(() => {
|
||||
const selector =
|
||||
context.viewMode === 'docs' ? `#anchor--${context.id} .docs-story` : '.sb-show-main';
|
||||
|
||||
const backgroundSize = [
|
||||
`${gridSize * cellAmount}px ${gridSize * cellAmount}px`,
|
||||
`${gridSize * cellAmount}px ${gridSize * cellAmount}px`,
|
||||
`${gridSize}px ${gridSize}px`,
|
||||
`${gridSize}px ${gridSize}px`,
|
||||
].join(', ');
|
||||
|
||||
return `
|
||||
${selector} {
|
||||
background-size: ${backgroundSize} !important;
|
||||
background-position: ${offsetX}px ${offsetY}px, ${offsetX}px ${offsetY}px, ${offsetX}px ${offsetY}px, ${offsetX}px ${offsetY}px !important;
|
||||
background-blend-mode: difference !important;
|
||||
background-image: linear-gradient(rgba(130, 130, 130, ${opacity}) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(130, 130, 130, ${opacity}) 1px, transparent 1px),
|
||||
linear-gradient(rgba(130, 130, 130, ${opacity / 2}) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(130, 130, 130, ${
|
||||
opacity / 2
|
||||
}) 1px, transparent 1px) !important;
|
||||
}
|
||||
`;
|
||||
}, [gridSize]);
|
||||
|
||||
useEffect(() => {
|
||||
const selectorId =
|
||||
context.viewMode === 'docs'
|
||||
? `addon-backgrounds-grid-docs-${context.id}`
|
||||
: `addon-backgrounds-grid`;
|
||||
if (!isActive) {
|
||||
clearStyles(selectorId);
|
||||
return;
|
||||
}
|
||||
|
||||
addGridStyle(selectorId, gridStyles);
|
||||
}, [isActive, gridStyles, context]);
|
||||
|
||||
return StoryFn();
|
||||
};
|
93
addons/backgrounds/src/helpers/index.ts
Normal file
93
addons/backgrounds/src/helpers/index.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import global from 'global';
|
||||
import dedent from 'ts-dedent';
|
||||
|
||||
import { logger } from '@storybook/client-logger';
|
||||
|
||||
import { Background } from '../types';
|
||||
|
||||
const { document, window } = global;
|
||||
|
||||
export const isReduceMotionEnabled = () => {
|
||||
const prefersReduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
return prefersReduceMotion.matches;
|
||||
};
|
||||
|
||||
export const getBackgroundColorByName = (
|
||||
currentSelectedValue: string,
|
||||
backgrounds: Background[] = [],
|
||||
defaultName: string
|
||||
): string => {
|
||||
if (currentSelectedValue === 'transparent') {
|
||||
return 'transparent';
|
||||
}
|
||||
|
||||
if (backgrounds.find((background) => background.value === currentSelectedValue)) {
|
||||
return currentSelectedValue;
|
||||
}
|
||||
|
||||
const defaultBackground = backgrounds.find((background) => background.name === defaultName);
|
||||
if (defaultBackground) {
|
||||
return defaultBackground.value;
|
||||
}
|
||||
|
||||
if (defaultName) {
|
||||
const availableColors = backgrounds.map((background) => background.name).join(', ');
|
||||
logger.warn(
|
||||
dedent`
|
||||
Backgrounds Addon: could not find the default color "${defaultName}".
|
||||
These are the available colors for your story based on your configuration:
|
||||
${availableColors}.
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
return 'transparent';
|
||||
};
|
||||
|
||||
export const clearStyles = (selector: string | string[]) => {
|
||||
const selectors = Array.isArray(selector) ? selector : [selector];
|
||||
selectors.forEach(clearStyle);
|
||||
};
|
||||
|
||||
const clearStyle = (selector: string) => {
|
||||
const element = document.getElementById(selector) as HTMLElement;
|
||||
if (element) {
|
||||
element.parentElement.removeChild(element);
|
||||
}
|
||||
};
|
||||
|
||||
export const addGridStyle = (selector: string, css: string) => {
|
||||
const existingStyle = document.getElementById(selector) as HTMLElement;
|
||||
if (existingStyle) {
|
||||
if (existingStyle.innerHTML !== css) {
|
||||
existingStyle.innerHTML = css;
|
||||
}
|
||||
} else {
|
||||
const style = document.createElement('style') as HTMLElement;
|
||||
style.setAttribute('id', selector);
|
||||
style.innerHTML = css;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
};
|
||||
|
||||
export const addBackgroundStyle = (selector: string, css: string, storyId: string) => {
|
||||
const existingStyle = document.getElementById(selector) as HTMLElement;
|
||||
if (existingStyle) {
|
||||
if (existingStyle.innerHTML !== css) {
|
||||
existingStyle.innerHTML = css;
|
||||
}
|
||||
} else {
|
||||
const style = document.createElement('style') as HTMLElement;
|
||||
style.setAttribute('id', selector);
|
||||
style.innerHTML = css;
|
||||
|
||||
const gridStyleSelector = `addon-backgrounds-grid${storyId ? `-docs-${storyId}` : ''}`;
|
||||
// If grids already exist, we want to add the style tag BEFORE it so the background doesn't override grid
|
||||
const existingGridStyle = document.getElementById(gridStyleSelector) as HTMLElement;
|
||||
if (existingGridStyle) {
|
||||
existingGridStyle.parentElement.insertBefore(style, existingGridStyle);
|
||||
} else {
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
}
|
||||
};
|
@ -1,3 +1,6 @@
|
||||
if (module && module.hot && module.hot.decline) {
|
||||
module.hot.decline();
|
||||
}
|
||||
|
||||
// make it work with --isolatedModules
|
||||
export default {};
|
||||
|
3
addons/backgrounds/src/preset/addDecorator.tsx
Normal file
3
addons/backgrounds/src/preset/addDecorator.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import { withGrid, withBackground } from '../decorators';
|
||||
|
||||
export const decorators = [withGrid, withBackground];
|
@ -1,5 +1,10 @@
|
||||
export const parameters = {
|
||||
backgrounds: {
|
||||
grid: {
|
||||
cellSize: 20,
|
||||
opacity: 0.5,
|
||||
cellAmount: 5,
|
||||
},
|
||||
values: [
|
||||
{ name: 'light', value: '#F8F8F8' },
|
||||
{ name: 'dark', value: '#333333' },
|
@ -1,7 +0,0 @@
|
||||
export function config(entry: any[] = []) {
|
||||
return [...entry, require.resolve('./defaultParameters')];
|
||||
}
|
||||
|
||||
export function managerEntries(entry: any[] = [], options: any) {
|
||||
return [...entry, require.resolve('../register')];
|
||||
}
|
@ -5,14 +5,14 @@ import { ADDON_ID } from './constants';
|
||||
import { BackgroundSelector } from './containers/BackgroundSelector';
|
||||
import { GridSelector } from './containers/GridSelector';
|
||||
|
||||
addons.register(ADDON_ID, (api) => {
|
||||
addons.register(ADDON_ID, () => {
|
||||
addons.add(ADDON_ID, {
|
||||
title: 'Backgrounds',
|
||||
type: types.TOOL,
|
||||
match: ({ viewMode }) => viewMode === 'story',
|
||||
match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)),
|
||||
render: () => (
|
||||
<Fragment>
|
||||
<BackgroundSelector api={api} />
|
||||
<BackgroundSelector />
|
||||
<GridSelector />
|
||||
</Fragment>
|
||||
),
|
||||
|
33
addons/backgrounds/src/types/index.ts
Normal file
33
addons/backgrounds/src/types/index.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { ReactElement } from 'react';
|
||||
|
||||
export interface GlobalState {
|
||||
name: string | undefined;
|
||||
selected: string | undefined;
|
||||
}
|
||||
|
||||
export interface BackgroundSelectorItem {
|
||||
id: string;
|
||||
title: string;
|
||||
onClick: () => void;
|
||||
value: string;
|
||||
active: boolean;
|
||||
right?: ReactElement;
|
||||
}
|
||||
|
||||
export interface Background {
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface BackgroundsParameter {
|
||||
default?: string;
|
||||
disable?: boolean;
|
||||
values: Background[];
|
||||
}
|
||||
|
||||
export interface BackgroundsConfig {
|
||||
backgrounds: Background[] | null;
|
||||
selectedBackgroundName: string | null;
|
||||
defaultBackgroundName: string | null;
|
||||
disable: boolean;
|
||||
}
|
@ -8,6 +8,11 @@
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"src/__tests__/**/*"
|
||||
"src/**/*.test.*",
|
||||
"src/**/tests/**/*",
|
||||
"src/**/__tests__/**/*",
|
||||
"src/**/*.stories.*",
|
||||
"src/**/*.mockdata.*",
|
||||
"src/**/__testfixtures__/**"
|
||||
]
|
||||
}
|
||||
|
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