Merge branch 'release/4.1'

This commit is contained in:
Michael Shilman 2018-12-12 04:49:41 -08:00
commit bc54bbd143
290 changed files with 13120 additions and 6065 deletions

View File

@ -1,53 +0,0 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-flow"
],
"plugins": [
"babel-plugin-emotion",
"babel-plugin-macros",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-export-default-from",
[
"@babel/plugin-transform-runtime",
{
"regenerator": true
}
]
],
"env": {
"test": {
"plugins": ["babel-plugin-require-context-hook"]
}
},
"overrides": [
{
"test": "./examples/vue-kitchen-sink",
"presets": [
"@babel/preset-env",
"babel-preset-vue"
]
},
{
"test": [
"./lib/core/src/server",
"./lib/node-logger",
"./lib/codemod",
"./addons/storyshots",
"./addons/storysource/src/loader",
"./app/**/src/server/**"
],
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "8.11"
}
}
]
]
}
]
}

50
.babelrc.js Normal file
View File

@ -0,0 +1,50 @@
module.exports = {
presets: [
['@babel/preset-env', { shippedProposals: true, useBuiltIns: 'usage' }],
'@babel/preset-react',
'@babel/preset-flow',
],
plugins: [
'babel-plugin-emotion',
'babel-plugin-macros',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-export-default-from',
],
env: {
test: {
presets: [['@babel/preset-env', { shippedProposals: true, useBuiltIns: 'usage' }]],
plugins: ['babel-plugin-require-context-hook', 'babel-plugin-dynamic-import-node'],
},
},
overrides: [
{
test: './examples/vue-kitchen-sink',
presets: ['babel-preset-vue'],
},
{
test: [
'./lib/core/src/server',
'./lib/node-logger',
'./lib/codemod',
'./addons/storyshots',
'./addons/storysource/src/loader',
'./app/**/src/server/**',
'./app/**/src/bin/**',
'./dangerfile.js',
],
presets: [
[
'@babel/preset-env',
{
shippedProposals: true,
useBuiltIns: 'usage',
targets: {
node: '8.11',
},
},
],
],
},
],
};

View File

@ -120,52 +120,52 @@ jobs:
name: Run react kitchen-sink (smoke test)
command: |
cd examples/cra-kitchen-sink
yarn storybook --smoke-test
yarn storybook --smoke-test --quiet
- run:
name: Run vue kitchen-sink (smoke test)
command: |
cd examples/vue-kitchen-sink
yarn storybook --smoke-test
yarn storybook --smoke-test --quiet
- run:
name: Run svelte kitchen-sink (smoke test)
command: |
cd examples/svelte-kitchen-sink
yarn storybook --smoke-test
yarn storybook --smoke-test --quiet
- run:
name: Run angular-cli (smoke test)
command: |
cd examples/angular-cli
yarn storybook --smoke-test
yarn storybook --smoke-test --quiet
- run:
name: Run ember-cli (smoke test)
command: |
cd examples/ember-cli
yarn storybook --smoke-test
yarn storybook --smoke-test --quiet
- run:
name: Run polymer-cli (smoke test)
command: |
cd examples/polymer-cli
yarn storybook --smoke-test
yarn storybook --smoke-test --quiet
- run:
name: Run marko-cli (smoke test)
command: |
cd examples/marko-cli
yarn storybook --smoke-test
yarn storybook --smoke-test --quiet
- run:
name: Run official-storybook (smoke test)
command: |
cd examples/official-storybook
yarn storybook --smoke-test
yarn storybook --smoke-test --quiet
- run:
name: Run mithril kitchen-sink (smoke test)
command: |
cd examples/mithril-kitchen-sink
yarn storybook --smoke-test
yarn storybook --smoke-test --quiet
- run:
name: Run riot kitchen-sink (smoke test)
command: |
cd examples/riot-kitchen-sink
yarn storybook --smoke-test
yarn storybook --smoke-test --quiet
native-smoke-tests:
<<: *defaults
steps:

View File

@ -1,4 +1,5 @@
dist
lib/**/dll
build
coverage
node_modules

View File

@ -123,6 +123,12 @@ module.exports = {
],
},
overrides: [
{
files: ['**/__tests__/**', '**/*.test.js/**', '**/*.spec.js/**'],
rules: {
'import/no-extraneous-dependencies': ignore,
},
},
{
files: ['**/react-native*/**', '**/REACT_NATIVE*/**', '**/crna*/**'],
rules: {

1
.gitignore vendored
View File

@ -23,3 +23,4 @@ integration/__image_snapshots__/__diff_output__
.jest-test-results.json
/examples/cra-kitchen-sink/src/__image_snapshots__/__diff_output__/
lib/*.jar
lib/**/dll

View File

@ -17,6 +17,7 @@ object OpenSourceProjects_Storybook_Bootstrap : BuildType({
addons/storyshots/*/dist/** => dist.zip/addons/storyshots
app/*/dist/** => dist.zip/app
lib/*/dist/** => dist.zip/lib
lib/core/dll/** => dist.zip/lib/core/dll
""".trimIndent()
vcs {

View File

@ -12,10 +12,10 @@ object OpenSourceProjects_Storybook_Examples : BuildType({
name = "Examples"
artifactRules = """
${StorybookApp.values().map { it.artifactPath }.joinToString("\n")}
examples/official-storybook/storybook-static => official.zip
examples/official-storybook/image-snapshots/__image_snapshots__ => image-snapshots
""".trimIndent()
${StorybookApp.values().map { it.artifactPath }.joinToString("\n")}
examples/official-storybook/storybook-static => official.zip
examples/official-storybook/image-snapshots/__image_snapshots__ => image-snapshots
""".trimIndent()
vcs {
root(OpenSourceProjects_Storybook.vcsRoots.OpenSourceProjects_Storybook_HttpsGithubComStorybooksStorybookRefsHeadsMaster)

View File

@ -30,7 +30,7 @@ object OpenSourceProjects_Storybook_SmokeTests : BuildType({
set -e -x
cd examples/$exampleDir
yarn storybook --smoke-test
yarn storybook --smoke-test --quiet
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
@ -44,7 +44,7 @@ object OpenSourceProjects_Storybook_SmokeTests : BuildType({
set -e -x
cd examples/official-storybook
yarn storybook --smoke-test
yarn storybook --smoke-test --quiet
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}

View File

@ -83,7 +83,9 @@ enum class StorybookApp(val appName: String, val exampleDir: String, val merged:
}
artifacts {
artifactRules = "dist.zip!**"
artifactRules = """
dist.zip!**
""".trimIndent()
}
}
}

View File

@ -15,6 +15,7 @@
|[links](addons/links) |+|+|+|+|+|+|+| |+|+|+|
|[notes](addons/notes) |+|+*|+|+|+|+|+| |+|+|+|
|[options](addons/options) |+|+|+|+|+|+|+| |+|+|+|
|[cssresources](addons/cssresources) |+| |+|+|+|+|+|+|+|+|+|
|[storyshots](addons/storyshots) |+|+|+|+| | |+| |+|+| |
|[storysource](addons/storysource) |+| |+|+|+|+|+|+|+|+|+|
|[viewport](addons/viewport) |+| |+|+|+|+|+|+|+|+|+|

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2018 Norbert de Langen ndelangen@me.com
Copyright (c) 2017 Kadira Inc. <hello@kadira.io>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,17 +1,20 @@
# Storybook
[![Build Status on TeamCity](https://teamcity.jetbrains.com/app/rest/builds/buildType:OpenSourceProjects_Storybook_Build_2/statusIcon.svg)](https://teamcity.jetbrains.com/viewType.html?buildTypeId=OpenSourceProjects_Storybook_Build_2&branch_OpenSourceProjects_Storybook=%3Cdefault%3E&tab=buildTypeStatusDiv)
[![Build Status on CircleCI](https://circleci.com/gh/storybooks/storybook.svg?style=shield)](https://circleci.com/gh/storybooks/storybook)
[![CodeFactor](https://www.codefactor.io/repository/github/storybooks/storybook/badge)](https://www.codefactor.io/repository/github/storybooks/storybook)
[![Known Vulnerabilities](https://snyk.io/test/github/storybooks/storybook/badge.svg)](https://snyk.io/test/github/storybooks/storybook)
[![BCH compliance](https://bettercodehub.com/edge/badge/storybooks/storybook)](https://bettercodehub.com/results/storybooks/storybook)
[![codecov](https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg)](https://codecov.io/gh/storybooks/storybook)
[![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/)
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
[![License](https://img.shields.io/github/license/storybooks/storybook.svg)](https://github.com/storybooks/storybook/blob/master/LICENSE)
<!-- [![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=<badge_key>)](https://www.browserstack.com/automate/public-build/<badge_key>) -->
<p align="center">
<a href="https://teamcity.jetbrains.com/viewType.html?buildTypeId=OpenSourceProjects_Storybook_Build_2&amp;branch_OpenSourceProjects_Storybook=%3Cdefault%3E&amp;tab=buildTypeStatusDiv"><img src="https://teamcity.jetbrains.com/app/rest/builds/buildType:OpenSourceProjects_Storybook_Build_2/statusIcon.svg" alt="Build Status on TeamCity" /></a>
<a href="https://circleci.com/gh/storybooks/storybook"><img src="https://circleci.com/gh/storybooks/storybook.svg?style=shield" alt="Build Status on CircleCI" /></a>
<a href="https://www.codefactor.io/repository/github/storybooks/storybook"><img src="https://www.codefactor.io/repository/github/storybooks/storybook/badge" alt="CodeFactor" /></a>
<a href="https://snyk.io/test/github/storybooks/storybook"><img src="https://snyk.io/test/github/storybooks/storybook/badge.svg" alt="Known Vulnerabilities" /></a>
<a href="https://bettercodehub.com/results/storybooks/storybook"><img src="https://bettercodehub.com/edge/badge/storybooks/storybook" alt="BCH compliance" /></a>
<a href="https://codecov.io/gh/storybooks/storybook"><img src="https://codecov.io/gh/storybooks/storybook/branch/master/graph/badge.svg" alt="codecov" /></a>
<a href="https://github.com/storybooks/storybook/blob/master/LICENSE"><img src="https://img.shields.io/github/license/storybooks/storybook.svg" alt="License" /></a></p>
</p>
<p align="center">
<a href="https://discord.gg/sMFvFsG"><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>
<a href="#backers"><img src="https://opencollective.com/storybook/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="#sponsors"><img src="https://opencollective.com/storybook/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
</p>
---
@ -21,13 +24,14 @@ It allows you to browse a component library, view the different states of each c
## Intro
<center>
<img src="media/storybook-intro.gif" width="100%" />
<img src="media/storybook-intro.gif" width="100%" />
</center>
README for:
- [![Alpha](https://img.shields.io/npm/v/@storybook/core/alpha.svg)](https://github.com/storybooks/storybook)
- [![Latest](https://img.shields.io/npm/v/@storybook/core/latest.svg)](https://github.com/storybooks/storybook/tree/master)
<p align="center">
README for:<br/>
<a href="https://img.shields.io/npm/v/@storybook/core/latest.svg" title="latest"><img alt="latest" src="https://img.shields.io/npm/v/@storybook/core/latest.svg" /></a>
<a href="https://img.shields.io/npm/v/@storybook/core/next.svg" title="next"><img alt="next" src="https://img.shields.io/npm/v/@storybook/core/next.svg" /></a>
</p>
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.
@ -79,19 +83,19 @@ For additional help, join us [in our Discord](https://discord.gg/sMFvFsG) or [Sl
### Supported Frameworks
| Framework | Demo latest | Demo prerelease | |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [React](app/react) | [v3.4.x](https://release-3-4--storybooks-official.netlify.com), [v3.3.x](https://release-3-3--storybooks-official.netlify.com) | [v4.0.0](https://storybooks-official.netlify.com) | [![React](https://img.shields.io/npm/dt/@storybook/react.svg)](app/react) |
| [React Native](app/react-native) | - | - | [![React Native](https://img.shields.io/npm/dt/@storybook/react-native.svg)](app/react-native) |
| [Vue](app/vue) | [v3.4.x](https://release-3-4--storybooks-vue.netlify.com/), [v3.3.x](https://release-3-3--storybooks-vue.netlify.com/) | [v4.0.0](https://storybooks-vue.netlify.com/) | [![Vue](https://img.shields.io/npm/dt/@storybook/vue.svg)](app/vue) |
| [Angular](app/angular) | [v3.4.x](https://release-3-4--storybooks-angular.netlify.com/), [v3.3.x](https://release-3-3--storybooks-angular.netlify.com/) | [v4.0.0](https://storybooks-angular.netlify.com/) | [![Angular](https://img.shields.io/npm/dt/@storybook/angular.svg)](app/angular) |
| [Polymer](app/polymer) | [v3.4.x](https://release-3-4--storybooks-polymer.netlify.com/) | [v4.0.0](https://storybooks-polymer.netlify.com/) | [![Polymer](https://img.shields.io/npm/dt/@storybook/polymer.svg)](app/polymer) |
| [Mithril](app/mithril) | - | [v4.0.0](https://storybooks-mithril.netlify.com/) | [![Mithril](https://img.shields.io/npm/dt/@storybook/mithril.svg)](app/mithril) |
| [Marko](app/marko) | - | [v4.0.0](https://storybooks-marko.netlify.com/) | [![Marko](https://img.shields.io/npm/dt/@storybook/marko.svg)](app/marko) |
| [HTML](app/html) | - | [v4.0.0](https://storybooks-html.netlify.com/) | [![HTML](https://img.shields.io/npm/dt/@storybook/html.svg)](app/html) |
| [Svelte](app/svelte) | - | [v4.0.0](https://storybooks-svelte.netlify.com/) | [![Svelte](https://img.shields.io/npm/dt/@storybook/svelte.svg)](app/svelte) |
| [Riot](app/riot) | - | [v4.0.0](https://storybooks-riot.netlify.com/) | [![Riot](https://img.shields.io/npm/dt/@storybook/riot.svg)](app/riot) |
| [Ember](app/ember) | - | [v4.0.0](https://storybooks-ember.netlify.com/) | [![Ember](https://img.shields.io/npm/dt/@storybook/ember.svg)](app/ember) |
| Framework | Demo | |
| -------------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [React](app/react) | [v4.0.0](https://storybooks-official.netlify.com) | [![React](https://img.shields.io/npm/dm/@storybook/react.svg)](app/react) |
| [React Native](app/react-native) | - | [![React Native](https://img.shields.io/npm/dm/@storybook/react-native.svg)](app/react-native) |
| [Vue](app/vue) | [v4.0.0](https://storybooks-vue.netlify.com/) | [![Vue](https://img.shields.io/npm/dm/@storybook/vue.svg)](app/vue) |
| [Angular](app/angular) | [v4.0.0](https://storybooks-angular.netlify.com/) | [![Angular](https://img.shields.io/npm/dm/@storybook/angular.svg)](app/angular) |
| [Polymer](app/polymer) | [v4.0.0](https://storybooks-polymer.netlify.com/) | [![Polymer](https://img.shields.io/npm/dm/@storybook/polymer.svg)](app/polymer) |
| [Mithril](app/mithril) | [v4.0.0](https://storybooks-mithril.netlify.com/) | [![Mithril](https://img.shields.io/npm/dm/@storybook/mithril.svg)](app/mithril) |
| [Marko](app/marko) | [v4.0.0](https://storybooks-marko.netlify.com/) | [![Marko](https://img.shields.io/npm/dm/@storybook/marko.svg)](app/marko) |
| [HTML](app/html) | [v4.0.0](https://storybooks-html.netlify.com/) | [![HTML](https://img.shields.io/npm/dm/@storybook/html.svg)](app/html) |
| [Svelte](app/svelte) | [v4.0.0](https://storybooks-svelte.netlify.com/) | [![Svelte](https://img.shields.io/npm/dm/@storybook/svelte.svg)](app/svelte) |
| [Riot](app/riot) | [v4.0.0](https://storybooks-riot.netlify.com/) | [![Riot](https://img.shields.io/npm/dm/@storybook/riot.svg)](app/riot) |
| [Ember](app/ember) | [v4.0.0](https://storybooks-ember.netlify.com/) | [![Ember](https://img.shields.io/npm/dm/@storybook/ember.svg)](app/ember) |
### Sub Projects
@ -106,6 +110,7 @@ For additional help, join us [in our Discord](https://discord.gg/sMFvFsG) or [Sl
| [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 |
| [centered](addons/centered/) | Center the alignment of your components within the Storybook UI |
| [cssresources](addons/cssresources/) | Dynamically add/remove css resources to the component iframe |
| [events](addons/events/) | Interactively fire events to components that respond to EventEmitter |
| [graphql](addons/graphql/) | Query a GraphQL server within Storybook stories |
| [google-analytics](addons/google-analytics) | Reports google analytics on stories |

View File

@ -1,6 +1,6 @@
# storybook-addon-a11y
This storybook addon can be helpfull to make your UI components more accessibile.
This storybook addon can be helpful to make your UI components more accessible.
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-a11y",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "a11y addon for storybook",
"keywords": [
"a11y",
@ -11,9 +11,6 @@
"verify"
],
"homepage": "https://github.com/storybooks/storybook#readme",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -29,10 +26,10 @@
},
"dependencies": {
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.12",
"@storybook/client-logger": "4.0.12",
"@storybook/components": "4.0.12",
"@storybook/core-events": "4.0.12",
"@storybook/addons": "4.1.0-alpha.12",
"@storybook/client-logger": "4.1.0-alpha.12",
"@storybook/components": "4.1.0-alpha.12",
"@storybook/core-events": "4.1.0-alpha.12",
"axe-core": "^3.1.2",
"global": "^4.3.2",
"prop-types": "^15.6.2"
@ -40,5 +37,8 @@
"peerDependencies": {
"react": "*",
"react-dom": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -14,11 +14,14 @@ export const configureA11y = (options = {}) => {
const runA11yCheck = () => {
const channel = addons.getChannel();
const infoWrapper = document.getElementById('story-root').children;
const wrapper = document.getElementById('root');
axe.reset();
axe.configure(axeOptions);
axe.run(wrapper).then(results => channel.emit(CHECK_EVENT_ID, results), logger.error);
axe
.run(infoWrapper || wrapper)
.then(results => channel.emit(CHECK_EVENT_ID, results), logger.error);
};
const a11ySubscription = () => {

View File

@ -1,14 +1,11 @@
{
"name": "@storybook/addon-actions",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Action Logger addon for storybook",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/actions",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -26,9 +23,9 @@
"@emotion/core": "^0.13.1",
"@emotion/provider": "^0.11.2",
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.12",
"@storybook/components": "4.0.12",
"@storybook/core-events": "4.0.12",
"@storybook/addons": "4.1.0-alpha.12",
"@storybook/components": "4.1.0-alpha.12",
"@storybook/core-events": "4.1.0-alpha.12",
"deep-equal": "^1.0.1",
"global": "^4.3.2",
"lodash": "^4.17.11",
@ -39,5 +36,8 @@
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-backgrounds",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "A storybook addon to show different backgrounds for your preview",
"keywords": [
"addon",
@ -9,9 +9,6 @@
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/backgrounds",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -28,13 +25,17 @@
},
"dependencies": {
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.8",
"@storybook/core-events": "4.0.12",
"@storybook/addons": "4.1.0-alpha.12",
"@storybook/core-events": "4.1.0-alpha.12",
"eventemitter3": "^3.1.0",
"global": "^4.3.2",
"prop-types": "^15.6.2",
"util-deprecate": "^1.0.2"
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,6 +1,6 @@
import React from 'react';
import { shallow, mount } from 'enzyme';
import EventEmitter from 'events';
import EventEmitter from 'eventemitter3';
import BackgroundPanel from '../BackgroundPanel';
import Events from '../constants';

View File

@ -1,15 +1,12 @@
{
"name": "@storybook/addon-centered",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook decorator to center components",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/centered",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -26,5 +23,8 @@
},
"dependencies": {
"global": "^4.3.2"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -0,0 +1,63 @@
# Storybook Addon Cssresources
Storybook Addon Cssresources to switch between css resources at runtime for your story [Storybook](https://storybook.js.org).
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
![Storybook Addon Cssresources Demo](docs/demo.gif)
## Installation
```sh
yarn add -D @storybook/addon-cssresources
```
## Configuration
Then create a file called `addons.js` in your storybook config.
Add following content to it:
```js
import '@storybook/addon-cssresources/register';
```
## Usage
You need add the all the css resources at compile time using the `withCssResources` decorator. They can be added globally or per story. You can then choose which ones to load from the cssresources addon ui:
```js
// Import from @storybook/X where X is your framework
import { configure, addDecorator, storiesOf } from '@storybook/react';
import { withCssResources } from '@storybook/addon-cssresources';
// global
addDecorator(
withCssResources({
cssresources: [{
name: `bluetheme`,
code: `<style>body { background-color: lightblue; }</style>`,
picked: false,
},
],
})
);
// per story
storiesOf('Addons|Cssresources', module)
.addDecorator(
withCssResources({
cssresources: [{
name: `fontawesome`,
code: `<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"></link>`,
picked: true,
}, {
name: `whitetheme`,
code: `<style>.fa { color: #fff }</style>`,
picked: true,
},
],
})
)
.add('Camera Icon', () => <i className="fa fa-camera-retro"> Camera Icon</i>);
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 MiB

View File

@ -0,0 +1,42 @@
{
"name": "@storybook/addon-cssresources",
"version": "4.1.0-alpha.12",
"description": "A storybook addon to switch between css resources at runtime for your story",
"keywords": [
"addon",
"cssresources",
"react",
"storybook"
],
"homepage": "https://storybook.js.org",
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
},
"license": "MIT",
"author": "nm123github",
"main": "dist/index.js",
"jsnext:main": "src/index.js",
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@emotion/styled": "0.10.6",
"@storybook/addons": "4.1.0-alpha.12",
"@storybook/components": "4.1.0-alpha.12",
"@storybook/core-events": "4.1.0-alpha.12",
"global": "^4.3.2",
"prop-types": "^15.6.2",
"react-syntax-highlighter": "^10.0.0",
"util-deprecate": "^1.0.2"
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -0,0 +1 @@
require('./dist/register.js');

View File

@ -0,0 +1,147 @@
import { document, DOMParser } from 'global';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { monoFonts } from '@storybook/components';
import styled from '@emotion/styled';
import css from 'react-syntax-highlighter/dist/esm/languages/prism/css';
import { darcula } from 'react-syntax-highlighter/dist/esm/styles/prism';
import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-light';
SyntaxHighlighter.registerLanguage('css', css);
const storybookIframe = 'storybook-preview-iframe';
const addedElAttr = 'addedbycssresourcesaddon';
// Taken from StoryPanel.js
const highlighterTheme = {
...darcula,
'pre[class*="language-"]': {
...darcula['pre[class*="language-"]'],
margin: 'auto',
width: 'auto',
height: 'auto',
minHeight: '100%',
overflow: 'hidden',
boxSizing: 'border-box',
display: 'flex',
fontFamily: monoFonts.fontFamily,
fontSize: 'inherit',
},
'code[class*="language-"]': {
...darcula['code[class*="language-"]'],
margin: 0,
fontFamily: 'inherit',
},
};
const PanelWrapper = styled.div({
position: 'absolute',
top: '10px',
left: '10px',
fontFamily: monoFonts.fontFamily,
});
export default class CssResourcePanel extends Component {
constructor(props) {
super(props);
this.state = { cssresources: `` };
this.onAddCssresources = this.onAddCssresources.bind(this);
this.parser = new DOMParser();
}
componentDidMount() {
const { channel } = this.props;
this.iframe = document.getElementById(storybookIframe);
if (!this.iframe) {
throw new Error('Cannot find Storybook iframe');
}
channel.on('storybook/resources/add_cssresources', this.onAddCssresources);
}
componentWillUnmount() {
const { channel } = this.props;
channel.removeListener('storybook/resources/add_cssresources', this.onAddCssresources);
}
onAddCssresources(cssresources) {
this.loadCssresources(cssresources.filter(res => res.picked));
this.setState(prevState => ({ ...prevState, cssresources }));
}
handleChange(i, { target }) {
const { channel } = this.props;
const { cssresources = [] } = this.state;
cssresources[i].picked = target.checked;
channel.emit('storybook/resources/add_cssresources', cssresources);
}
loadCssresources(cssresources) {
// remove previously added elements!
this.iframe.contentDocument.head.querySelectorAll(`[${addedElAttr}]`).forEach(eL => {
if (eL) {
eL.parentNode.removeChild(eL);
}
});
// add new elements!
const str = cssresources.map(res => res.code).join('');
const parsedHtml = this.parser.parseFromString(str, 'text/html');
const elements = parsedHtml.querySelectorAll('head > *');
elements.forEach(eL => {
// add addedElAttr to css elements
eL.setAttribute(addedElAttr, '');
this.iframe.contentDocument.head.appendChild(eL);
});
}
render() {
const { cssresources = [] } = this.state;
const { active } = this.props;
if (!active) {
return null;
}
return (
<PanelWrapper className="addon-cssresources-container">
{cssresources &&
cssresources.map(({ name, code, picked }, i) => (
<div key={name} style={{ padding: 10 }}>
<div style={{ fontSize: '1.1em', marginBottom: 10 }}>
<input
id={`cssresource${i}`}
style={{ fontSize: '1.5em' }}
type="checkbox"
checked={picked}
onChange={this.handleChange.bind(this, i)}
/>
<label htmlFor={`cssresource${i}`}>#{name}</label>
</div>
<SyntaxHighlighter
language="css"
style={highlighterTheme}
customStyle={{ opacity: picked ? 1 : 0.5 }}
>
{code}
</SyntaxHighlighter>
</div>
))}
</PanelWrapper>
);
}
}
CssResourcePanel.propTypes = {
active: PropTypes.bool.isRequired,
channel: PropTypes.shape({
on: PropTypes.func,
emit: PropTypes.func,
removeListener: PropTypes.func,
}).isRequired,
api: PropTypes.shape({
onStory: PropTypes.func,
getQueryParam: PropTypes.func,
setQueryParams: PropTypes.func,
}).isRequired,
};

View File

@ -0,0 +1,23 @@
import addons, { makeDecorator } from '@storybook/addons';
export const withCssResources = makeDecorator({
name: 'withCssResources',
parameterName: 'cssresources',
skipIfNoParametersOrOptions: true,
allowDeprecatedUsage: false,
wrapper: (getStory, context, { options, parameters }) => {
const channel = addons.getChannel();
const storyOptions = parameters || options;
if (!Array.isArray(storyOptions) && !Array.isArray(storyOptions.cssresources)) {
throw new Error('The `cssresources` parameter needs to be an Array');
}
channel.emit(
'storybook/resources/add_cssresources',
Array.isArray(storyOptions) ? storyOptions : storyOptions.cssresources
);
return getStory(context);
},
});

View File

@ -0,0 +1,12 @@
import React from 'react';
import addons from '@storybook/addons';
import CssResourcePanel from './CssResourcePanel';
addons.register('storybook/cssresources', api => {
const channel = addons.getChannel();
addons.addPanel('storybook/cssresources/panel', {
title: 'Cssresources',
// eslint-disable-next-line react/prop-types
render: ({ active }) => <CssResourcePanel channel={channel} api={api} active={active} />,
});
});

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-events",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Add events to your Storybook stories.",
"keywords": [
"addon",
@ -9,9 +9,6 @@
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/events",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -27,8 +24,8 @@
},
"dependencies": {
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.8",
"@storybook/core-events": "4.0.12",
"@storybook/addons": "4.1.0-alpha.12",
"@storybook/core-events": "4.1.0-alpha.12",
"format-json": "^1.0.3",
"prop-types": "^15.6.2",
"react-lifecycles-compat": "^3.0.4",
@ -37,5 +34,8 @@
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,14 +1,11 @@
{
"name": "@storybook/addon-google-analytics",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook addon for google analytics",
"keywords": [
"addon",
"storybook"
],
"publishConfig": {
"access": "public"
},
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/google-analytics",
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
@ -24,8 +21,11 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.8",
"@storybook/addons": "4.1.0-alpha.12",
"global": "^4.3.2",
"react-ga": "^2.5.3"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,15 +1,12 @@
{
"name": "@storybook/addon-graphql",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook addon to display the GraphiQL IDE",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/graphql",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -31,5 +28,8 @@
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,15 +1,12 @@
{
"name": "@storybook/addon-info",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "A Storybook addon to show additional information for your stories.",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/info",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -25,10 +22,9 @@
},
"dependencies": {
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.12",
"@storybook/client-logger": "4.0.12",
"@storybook/components": "4.0.12",
"core-js": "2.5.7",
"@storybook/addons": "4.1.0-alpha.12",
"@storybook/client-logger": "4.1.0-alpha.12",
"@storybook/components": "4.1.0-alpha.12",
"global": "^4.3.2",
"marksy": "^6.1.0",
"nested-object-assign": "^1.0.1",
@ -42,5 +38,8 @@
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -2880,6 +2880,7 @@ exports[`addon Info should render component description 1`] = `
</div>
</div>
<div
id="story-root"
style={Object {}}
>
<div>

View File

@ -1,6 +1,5 @@
import PropTypes from 'prop-types';
import React from 'react';
import 'core-js/fn/array/includes';
import { Table, Td, Th } from '@storybook/components';
import PropVal from './PropVal';

View File

@ -117,7 +117,11 @@ class Story extends Component {
const { stylesheet } = this.state;
const { children } = this.props;
return <div style={stylesheet.infoStory}>{children}</div>;
return (
<div id="story-root" style={stylesheet.infoStory}>
{children}
</div>
);
}
_renderInline() {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 MiB

After

Width:  |  Height:  |  Size: 831 KiB

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-jest",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "React storybook addon that show component jest report",
"keywords": [
"addon",
@ -12,9 +12,6 @@
"unit-testing"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/jest",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -31,8 +28,8 @@
},
"dependencies": {
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.12",
"@storybook/components": "4.0.12",
"@storybook/addons": "4.1.0-alpha.12",
"@storybook/components": "4.1.0-alpha.12",
"global": "^4.3.2",
"prop-types": "^15.6.2",
"upath": "^1.1.0",
@ -40,5 +37,8 @@
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -140,24 +140,22 @@ const Message = ({ msg }) => {
.join('')
.split(/\[22m/)
.reduce((acc, item) => acc.concat(item), [])
.map(
(item, li) =>
typeof item === 'string'
? item
.split(/\[32m(.*?)\[39m/)
// eslint-disable-next-line react/no-array-index-key
.map((i, index) => (index % 2 ? <Positive key={`p_${li}_${i}`}>{i}</Positive> : i))
: item
.map((item, li) =>
typeof item === 'string'
? item
.split(/\[32m(.*?)\[39m/)
// eslint-disable-next-line react/no-array-index-key
.map((i, index) => (index % 2 ? <Positive key={`p_${li}_${i}`}>{i}</Positive> : i))
: item
)
.reduce((acc, item) => acc.concat(item), [])
.map(
(item, li) =>
typeof item === 'string'
? item
.split(/\[31m(.*?)\[39m/)
// eslint-disable-next-line react/no-array-index-key
.map((i, index) => (index % 2 ? <Negative key={`n_${li}_${i}`}>{i}</Negative> : i))
: item
.map((item, li) =>
typeof item === 'string'
? item
.split(/\[31m(.*?)\[39m/)
// eslint-disable-next-line react/no-array-index-key
.map((i, index) => (index % 2 ? <Negative key={`n_${li}_${i}`}>{i}</Negative> : i))
: item
)
.reduce((acc, item) => acc.concat(item), [])
.reduce(createSubgroup, {

View File

@ -55,6 +55,39 @@ stories.add('as dynamic variables', () => {
});
```
### With Vue.js
```js
import { storiesOf } from '@storybook/vue';
import { withKnobs, text, boolean, number } from '@storybook/addon-knobs';
import MyButton from './Button.vue';
const stories = storiesOf('Storybook Knobs', module);
// Add the `withKnobs` decorator to add knobs support to your stories.
// You can also configure `withKnobs` as a global decorator.
stories.addDecorator(withKnobs);
// Knobs for Vue props
// Knobs for Vue props
stories.add('with a button', () => ({
components: { MyButton },
template:
`<button disabled="${boolean('Disabled', false)}" >
${text('Label', 'Hello Storybook')}
</button>`
}));
// Knobs as dynamic variables.
stories.add('as dynamic variables', () => {
const name = text('Name', 'Arunoda Susiripala');
const age = number('Age', 89);
const content = `I am ${name} and I'm ${age} years old.`;
return `<div>${content}</div>`;
});
```
### With Angular
```js
import { storiesOf } from '@storybook/angular';
@ -344,8 +377,8 @@ stories.addDecorator(withKnobs)
stories.add('story name', () => ..., {
knobs: {
timestamps: true, // Doesn't emit events while user is typing.
escapeHTML: true // Escapes strings to be safe for inserting as innerHTML. This option is true by default in storybook for Vue, Angular, and Polymer, because those frameworks allow rendering plain HTML.
// You can still set it to false, but it's strongly unrecommendend in cases when you host your storybook on some route of your main site or web app.
escapeHTML: true // Escapes strings to be safe for inserting as innerHTML. This option is true by default. It's safe to set it to `false` with frameworks like React which do escaping on their side.
// You can still set it to false, but it's strongly unrecommendend in cases when you host your storybook on some route of your main site or web app.
}
});
```

View File

@ -1,15 +1,12 @@
{
"name": "@storybook/addon-knobs",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook Addon Prop Editor Component",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/knobs",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -25,9 +22,9 @@
},
"dependencies": {
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.12",
"@storybook/components": "4.0.12",
"@storybook/core-events": "4.0.12",
"@storybook/addons": "4.1.0-alpha.12",
"@storybook/components": "4.1.0-alpha.12",
"@storybook/core-events": "4.1.0-alpha.12",
"copy-to-clipboard": "^3.0.8",
"escape-html": "^1.0.3",
"fast-deep-equal": "^2.0.1",
@ -40,5 +37,8 @@
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -138,22 +138,24 @@ export default class Panel extends PureComponent {
let knobsArray = Object.keys(knobs).filter(key => knobs[key].used);
knobsArray.filter(key => knobs[key].groupId).forEach(key => {
const knobKeyGroupId = knobs[key].groupId;
groupIds.push(knobKeyGroupId);
groups[knobKeyGroupId] = {
render: ({ active: groupActive, selected }) => (
<TabWrapper active={groupActive || selected === DEFAULT_GROUP_ID}>
<PropForm
knobs={knobsArray.filter(knob => knob.groupId === knobKeyGroupId)}
onFieldChange={this.handleChange}
onFieldClick={this.handleClick}
/>
</TabWrapper>
),
title: knobKeyGroupId,
};
});
knobsArray
.filter(key => knobs[key].groupId)
.forEach(key => {
const knobKeyGroupId = knobs[key].groupId;
groupIds.push(knobKeyGroupId);
groups[knobKeyGroupId] = {
render: ({ active: groupActive, selected }) => (
<TabWrapper active={groupActive || selected === DEFAULT_GROUP_ID}>
<PropForm
knobs={knobsArray.filter(knob => knob.groupId === knobKeyGroupId)}
onFieldChange={this.handleChange}
onFieldClick={this.handleClick}
/>
</TabWrapper>
),
title: knobKeyGroupId,
};
});
groups[DEFAULT_GROUP_ID] = {
render: () => null,

View File

@ -1,15 +1,12 @@
{
"name": "@storybook/addon-links",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Story Links addon for storybook",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/links",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -24,13 +21,16 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.12",
"@storybook/components": "4.0.12",
"@storybook/core-events": "4.0.12",
"@storybook/addons": "4.1.0-alpha.12",
"@storybook/components": "4.1.0-alpha.12",
"@storybook/core-events": "4.1.0-alpha.12",
"global": "^4.3.2",
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-notes",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Write notes for your Storybook stories.",
"keywords": [
"addon",
@ -8,9 +8,6 @@
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/notes",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -26,11 +23,14 @@
},
"dependencies": {
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.8",
"@storybook/addons": "4.1.0-alpha.12",
"marked": "^0.5.1",
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-ondevice-backgrounds",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "A storybook addon to show different backgrounds for your preview",
"keywords": [
"addon",
@ -9,9 +9,6 @@
"storybook"
],
"homepage": "https://storybook.js.org",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -26,11 +23,14 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.8",
"@storybook/addons": "4.1.0-alpha.12",
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-ondevice-knobs",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Display storybook story knobs on your deviced.",
"keywords": [
"addon",
@ -9,9 +9,6 @@
"react-native",
"storybook"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
@ -23,7 +20,7 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.8",
"@storybook/addons": "4.1.0-alpha.12",
"deep-equal": "^1.0.1",
"prop-types": "^15.6.2",
"react-native-color-picker": "^0.4.0",
@ -32,8 +29,11 @@
"react-native-switch": "^1.5.0"
},
"peerDependencies": {
"@storybook/addon-knobs": "4.0.0",
"@storybook/addon-knobs": "4.1.0-alpha.1",
"react": "*",
"react-native": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -103,14 +103,16 @@ export default class Panel extends React.Component {
let knobsArray = Object.keys(knobs);
knobsArray.filter(key => knobs[key].groupId).forEach(key => {
const knobKeyGroupId = knobs[key].groupId;
groupIds.push(knobKeyGroupId);
groups[knobKeyGroupId] = {
render: () => <Text id={knobKeyGroupId}>{knobKeyGroupId}</Text>,
title: knobKeyGroupId,
};
});
knobsArray
.filter(key => knobs[key].groupId)
.forEach(key => {
const knobKeyGroupId = knobs[key].groupId;
groupIds.push(knobKeyGroupId);
groups[knobKeyGroupId] = {
render: () => <Text id={knobKeyGroupId}>{knobKeyGroupId}</Text>,
title: knobKeyGroupId,
};
});
if (groupIds.length > 0) {
groups[DEFAULT_GROUP_ID] = {

View File

@ -1,15 +1,12 @@
{
"name": "@storybook/addon-ondevice-notes",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Write notes for your Storybook stories.",
"keywords": [
"addon",
"notes",
"storybook"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
@ -21,12 +18,15 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.8",
"@storybook/addons": "4.1.0-alpha.12",
"prop-types": "^15.6.2",
"react-native-simple-markdown": "^1.1.0"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -20,7 +20,9 @@ Add this line to your `addons.js` file (create this file inside your storybook c
import '@storybook/addon-options/register';
```
Import and use the `withOptions` decorator in your config.js file.
###Set options globally
Import and use the `withOptions` decorator in your `config.js` file.
```js
import { addDecorator, configure } from '@storybook/react';
@ -113,27 +115,29 @@ configure(() => require('./stories'), module);
The options-addon accepts story parameters on the `options` key:
```js
import { storiesOf } from '@storybook/marko';
import { withKnobs, text, number } from '@storybook/addon-knobs';
import Hello from '../components/hello/index.marko';
import { storiesOf } from '@storybook/react';
import MyComponent from './my-component';
storiesOf('Addons|Knobs/Hello', module)
storiesOf('Addons|Custom options', module)
// If you want to set the option for all stories in of this kind
.addParameters({ options: { addonPanelInRight: true } })
.addDecorator(withKnobs)
.add(
'Simple',
() => {
const name = text('Name', 'John Doe');
const age = number('Age', 44);
return Hello.renderSync({
name,
age,
});
},
'Story for MyComponent',
() => <MyComponent />,
// If you want to set the options for a specific story
{ options: { addonPanelInRight: false } }
);
```
_NOTE_ that you must attach `withOptions` as a decorator (at the top-level) for this to work.
## Typescript
To install type definitions: `npm install -D @types/storybook__addon-options`
Make sure you also have the type definitions installed for the following libs:
- node
- react
You can install them using `npm install -D @types/node @types/react`, assuming you are using Typescript >2.0.

View File

@ -1,15 +1,12 @@
{
"name": "@storybook/addon-options",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Options addon for storybook",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/options",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -23,10 +20,13 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.8",
"@storybook/addons": "4.1.0-alpha.12",
"util-deprecate": "^1.0.2"
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,15 +1,12 @@
{
"name": "@storybook/addon-storyshots",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "StoryShots is a Jest Snapshot Testing Addon for Storybook.",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/storyshorts/storyshots-core",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -27,19 +24,23 @@
"storybook": "start-storybook -p 6006"
},
"dependencies": {
"@babel/runtime": "^7.1.2",
"@storybook/addons": "4.0.12",
"@storybook/addons": "4.1.0-alpha.12",
"core-js": "^2.5.7",
"glob": "^7.1.3",
"global": "^4.3.2",
"jest-specific-snapshot": "^1.0.0",
"read-pkg-up": "^4.0.0"
"read-pkg-up": "^4.0.0",
"regenerator-runtime": "^0.12.1"
},
"devDependencies": {
"@storybook/addon-actions": "4.0.12",
"@storybook/addon-links": "4.0.12",
"@storybook/addons": "4.0.0",
"@storybook/react": "4.0.12",
"@storybook/addon-actions": "4.1.0-alpha.12",
"@storybook/addon-links": "4.1.0-alpha.12",
"@storybook/addons": "4.1.0-alpha.1",
"@storybook/react": "4.1.0-alpha.12",
"enzyme-to-json": "^3.3.4",
"react": "^16.6.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -2,6 +2,9 @@ import hasDependency from '../hasDependency';
import configure from '../configure';
function setupAngularJestPreset() {
// Needed to prevent "Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten."
require.requireActual('core-js/modules/es6.promise');
// Angular + Jest + Storyshots = Crazy Shit:
// We need to require 'jest-preset-angular/setupJest' before any storybook code
// is running inside jest - one of the things that `jest-preset-angular/setupJest` does is

View File

@ -1,15 +1,12 @@
{
"name": "@storybook/addon-storyshots-puppeteer",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Image snappshots addition to StoryShots base on puppeteer",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/storyshorts/storyshots-puppeteer",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -24,12 +21,16 @@
"prepare": "node ../../../scripts/prepare.js"
},
"dependencies": {
"@babel/runtime": "^7.1.2",
"@storybook/node-logger": "4.0.12",
"@storybook/node-logger": "4.1.0-alpha.12",
"core-js": "^2.5.7",
"jest-image-snapshot": "^2.6.0",
"puppeteer": "^1.9.0"
"puppeteer": "^1.9.0",
"regenerator-runtime": "^0.12.1"
},
"peerDependencies": {
"@storybook/addon-storyshots": "^4.0.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,15 +1,12 @@
{
"name": "@storybook/addon-storysource",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Stories addon for storybook",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/storysource",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -24,16 +21,20 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@babel/runtime": "^7.1.2",
"@storybook/addons": "4.0.12",
"@storybook/components": "4.0.12",
"@storybook/addons": "4.1.0-alpha.12",
"@storybook/components": "4.1.0-alpha.12",
"core-js": "^2.5.7",
"estraverse": "^4.2.0",
"loader-utils": "^1.1.0",
"prettier": "^1.14.3",
"prop-types": "^15.6.2",
"react-syntax-highlighter": "^10.0.0"
"react-syntax-highlighter": "^10.0.0",
"regenerator-runtime": "^0.12.1"
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -216,11 +216,11 @@ Object {
"Custom|ng-content@Default": Object {
"endLoc": Object {
"col": 2,
"line": 15,
"line": 17,
},
"startLoc": Object {
"col": 43,
"line": 10,
"line": 12,
},
},
}

View File

@ -1,15 +1,12 @@
{
"name": "@storybook/addon-viewport",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook addon to change the viewport size to mobile",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/viewport",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -24,14 +21,17 @@
},
"dependencies": {
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.12",
"@storybook/components": "4.0.12",
"@storybook/core-events": "4.0.12",
"@storybook/addons": "4.1.0-alpha.12",
"@storybook/components": "4.1.0-alpha.12",
"@storybook/core-events": "4.1.0-alpha.12",
"global": "^4.3.2",
"prop-types": "^15.6.2",
"util-deprecate": "^1.0.2"
},
"peerDependencies": {
"react": "*"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,14 +1,11 @@
{
"name": "@storybook/angular",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook for Angular: Develop Angular Components in isolation with Hot Reloading.",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/app/angular",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -28,20 +25,23 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@babel/runtime": "^7.1.2",
"@storybook/core": "4.0.12",
"@storybook/node-logger": "4.0.12",
"@storybook/core": "4.1.0-alpha.12",
"@storybook/node-logger": "4.1.0-alpha.12",
"angular2-template-loader": "^0.6.2",
"core-js": "^2.5.7",
"fork-ts-checker-webpack-plugin": "^0.4.14",
"global": "^4.3.2",
"react": "^16.6.0",
"react-dom": "^16.6.0",
"regenerator-runtime": "^0.12.1",
"sass-loader": "^7.1.0",
"ts-loader": "^5.2.2",
"tsconfig-paths-webpack-plugin": "^3.2.0",
"webpack": "^4.23.1"
},
"devDependencies": {
"zone.js": "^0.8.26"
},
"peerDependencies": {
"@angular-devkit/core": "^0.6.1 || >=7.0.0",
"@angular/common": ">=6.0.0",
@ -53,7 +53,7 @@
"babel-loader": "^7.0.0 || ^8.0.0",
"zone.js": "^0.8.26"
},
"devDependencies": {
"zone.js": "^0.8.26"
"publishConfig": {
"access": "public"
}
}

View File

@ -3,7 +3,7 @@ import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'storybook-button-component',
template: `
<button (click)="onClick.emit($event);">{{ text }}</button>
<button (click)="onClick.emit($event)">{{ text }}</button>
`,
styles: [
`

View File

@ -3,46 +3,45 @@ import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'storybook-welcome-component',
template: `
<main>
<h1>Welcome to storybook</h1>
<p>This is a UI component dev environment for your app.</p>
<p>
We've added some basic stories inside the <span class="inline-code">src/stories</span> directory.
<br/>
A story is a single state of one or more UI components. You can have as many stories as
you want.
<br/>
(Basically a story is like a visual test case.)
</p>
<p>
See these sample <a (click)="showApp.emit($event);" role="button" tabIndex="0">stories</a> for a component called
<span class="inline-code">Button</span> .
</p>
<p>
Just like that, you can add your own components as stories.
<br />
You can also edit those components and see changes right away.
<br />
(Try editing the <span class="inline-code">Button</span> stories
located at <span class="inline-code">src/stories/index.js</span>.)
</p>
<p>
Usually we create stories with smaller UI components in the app.<br />
Have a look at the <a
href="https://storybook.js.org/basics/writing-stories"
target="_blank"
rel="noopener noreferrer"
>
Writing Stories
</a> section in our documentation.
</p>
<p class="note">
<b>NOTE:</b>
<br />
Have a look at the <span class="inline-code">.storybook/webpack.config.js</span>
to add webpack loaders and plugins you are using in this project.
</p>
</main>
<main>
<h1>Welcome to storybook</h1>
<p>This is a UI component dev environment for your app.</p>
<p>
We've added some basic stories inside the
<span class="inline-code">src/stories</span> directory. <br />
A story is a single state of one or more UI components. You can have as many stories as you
want. <br />
(Basically a story is like a visual test case.)
</p>
<p>
See these sample
<a (click)="showApp.emit($event)" role="button" tabIndex="0">stories</a> for a component
called <span class="inline-code">Button</span> .
</p>
<p>
Just like that, you can add your own components as stories. <br />
You can also edit those components and see changes right away. <br />
(Try editing the <span class="inline-code">Button</span> stories located at
<span class="inline-code">src/stories/index.js</span>.)
</p>
<p>
Usually we create stories with smaller UI components in the app.<br />
Have a look at the
<a
href="https://storybook.js.org/basics/writing-stories"
target="_blank"
rel="noopener noreferrer"
>
Writing Stories
</a>
section in our documentation.
</p>
<p class="note">
<b>NOTE:</b> <br />
Have a look at the <span class="inline-code">.storybook/webpack.config.js</span> to add
webpack loaders and plugins you are using in this project.
</p>
</main>
`,
styles: [
`

View File

@ -103,12 +103,10 @@ export function applyAngularCliWebpackConfig(baseConfig, cliWebpackConfigOptions
const rulesExcludingStyles = filterOutStylingRules(baseConfig);
// cliStyleConfig.entry adds global style files to the webpack context
const entry = {
const entry = [
...baseConfig.entry,
iframe: []
.concat(baseConfig.entry.iframe)
.concat(Object.values(cliStyleConfig.entry).reduce((acc, item) => acc.concat(item), [])),
};
...Object.values(cliStyleConfig.entry).reduce((acc, item) => acc.concat(item), []),
];
const module = {
...baseConfig.module,

View File

@ -38,13 +38,13 @@ export function webpack(config, { configDir }) {
},
resolve: {
...config.resolve,
extensions: [...config.resolve.extensions, '.ts', '.tsx'],
extensions: ['.ts', '.tsx', ...config.resolve.extensions],
},
plugins: [
...config.plugins,
// See https://github.com/angular/angular/issues/11580#issuecomment-401127742
new ContextReplacementPlugin(
/@angular(\\|\/)core(\\|\/)fesm5/,
/@angular(\\|\/)core(\\|\/)(fesm5|bundles)/,
path.resolve(__dirname, '..')
),
createForkTsCheckerInstance(tsLoaderOptions),

View File

@ -1,11 +1,8 @@
{
"name": "@storybook/ember",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.",
"homepage": "https://github.com/storybooks/storybook/tree/master/app/ember",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -25,18 +22,22 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@babel/runtime": "^7.1.2",
"@ember/test-helpers": "^1.0.0",
"@storybook/core": "4.0.12",
"@storybook/core": "4.1.0-alpha.12",
"common-tags": "^1.8.0",
"core-js": "^2.5.7",
"global": "^4.3.2",
"react": "^16.6.0",
"react-dom": "^16.6.0"
"react-dom": "^16.6.0",
"regenerator-runtime": "^0.12.1"
},
"peerDependencies": {
"babel-loader": "^7.0.0 || ^8.0.0",
"babel-plugin-ember-modules-api-polyfill": "^2.4.0",
"ember-cli-htmlbars-inline-precompile": "^1.0.3",
"ember-source": "^3.4.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,14 +1,11 @@
{
"name": "@storybook/html",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/app/html",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -27,15 +24,19 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@babel/runtime": "^7.1.2",
"@storybook/core": "4.0.12",
"@storybook/core": "4.1.0-alpha.12",
"common-tags": "^1.8.0",
"core-js": "^2.5.7",
"global": "^4.3.2",
"html-loader": "^0.5.5",
"react": "^16.6.0",
"react-dom": "^16.6.0"
"react-dom": "^16.6.0",
"regenerator-runtime": "^0.12.1"
},
"peerDependencies": {
"babel-loader": "^7.0.0 || ^8.0.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -3,13 +3,24 @@ import { stripIndents } from 'common-tags';
const rootElement = document.getElementById('root');
export default function renderMain({ story, selectedKind, selectedStory, showMain, showError }) {
export default function renderMain({
story,
selectedKind,
selectedStory,
showMain,
showError,
forceRender,
}) {
const component = story();
showMain();
if (typeof component === 'string') {
rootElement.innerHTML = component;
} else if (component instanceof Node) {
if (forceRender === true) {
return;
}
rootElement.innerHTML = '';
rootElement.appendChild(component);
} else {

View File

@ -1,14 +1,11 @@
{
"name": "@storybook/marko",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook for Marko: Develop Marko Component in isolation with Hot Reloading.",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/app/marko",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -28,18 +25,22 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@babel/runtime": "^7.1.2",
"@storybook/core": "4.0.12",
"@storybook/core": "4.1.0-alpha.12",
"common-tags": "^1.8.0",
"core-js": "^2.5.7",
"global": "^4.3.2",
"marko-loader": "^1.3.3",
"raw-loader": "^0.5.1",
"react": "^16.6.0",
"react-dom": "^16.6.0"
"react-dom": "^16.6.0",
"regenerator-runtime": "^0.12.1"
},
"peerDependencies": {
"babel-loader": "^7.0.0 || ^8.0.0",
"marko": "^4.10.0",
"marko-widgets": "^7.0.1"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,14 +1,11 @@
{
"name": "@storybook/mithril",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook for Mithril: Develop Mithril Component in isolation.",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/app/mithril",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -28,13 +25,14 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@babel/plugin-transform-react-jsx": "^7.0.0",
"@babel/runtime": "^7.1.2",
"@storybook/core": "4.0.12",
"@babel/plugin-transform-react-jsx": "^7.2.0",
"@storybook/core": "4.1.0-alpha.12",
"common-tags": "^1.8.0",
"core-js": "^2.5.7",
"global": "^4.3.2",
"react": "^16.6.0",
"react-dom": "^16.6.0"
"react-dom": "^16.6.0",
"regenerator-runtime": "^0.12.1"
},
"devDependencies": {
"mithril": "^1.1.6"
@ -42,5 +40,8 @@
"peerDependencies": {
"babel-loader": "^7.0.0 || ^8.0.0",
"mithril": "^1.1.6"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,14 +1,11 @@
{
"name": "@storybook/polymer",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook for Polymer: Develop Polymer components in isolation with Hot Reloading.",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/app/polymer",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -27,14 +24,14 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@babel/polyfill": "^7.0.0",
"@babel/runtime": "^7.1.2",
"@storybook/core": "4.0.12",
"@storybook/core": "4.1.0-alpha.12",
"@webcomponents/webcomponentsjs": "^1.2.0",
"common-tags": "^1.8.0",
"core-js": "^2.5.7",
"global": "^4.3.2",
"react": "^16.6.0",
"react-dom": "^16.6.0",
"regenerator-runtime": "^0.12.1",
"webpack": "^4.23.1"
},
"devDependencies": {
@ -45,5 +42,8 @@
"babel-loader": "^7.0.0 || ^8.0.0",
"lit-html": "0.10.0",
"polymer-webpack-loader": "^2.0.2"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,6 +1,5 @@
import '@webcomponents/webcomponentsjs/webcomponents-lite';
import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter';
import '@babel/polyfill';
import { window } from 'global';

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/react-native",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "A better way to develop React Native Components for your app",
"keywords": [
"react",
@ -8,9 +8,6 @@
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/app/react-native",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -28,12 +25,12 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.12",
"@storybook/channel-websocket": "4.0.12",
"@storybook/channels": "4.0.12",
"@storybook/core": "4.0.12",
"@storybook/core-events": "4.0.12",
"@storybook/ui": "4.0.12",
"@storybook/addons": "4.1.0-alpha.12",
"@storybook/channel-websocket": "4.1.0-alpha.12",
"@storybook/channels": "4.1.0-alpha.12",
"@storybook/core": "4.1.0-alpha.12",
"@storybook/core-events": "4.1.0-alpha.12",
"@storybook/ui": "4.1.0-alpha.12",
"babel-loader": "^8.0.4",
"babel-plugin-macros": "^2.4.2",
"babel-plugin-syntax-async-functions": "^6.13.0",
@ -43,7 +40,7 @@
"babel-plugin-transform-regenerator": "^6.26.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.7.0",
"babel-preset-minify": "^0.5.0",
"babel-preset-minify": "^0.5.0 || 0.6.0-alpha.5",
"babel-preset-react": "^6.24.1",
"babel-runtime": "^6.26.0",
"case-sensitive-paths-webpack-plugin": "^2.1.2",
@ -76,5 +73,8 @@
"babel-runtime": ">=6.0.0",
"react": "*",
"react-native": ">=0.51.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -22,16 +22,16 @@ The next thing you need to do is make Storybook UI visible in your app.
The easiest way to use Storybook is to simply replace your App with the Storybook UI, which is possible by replacing `App.js` with a single line of code:
```js
export default from "./storybook";
export default from './storybook';
```
This will get you up and running quickly, but then you lose your app!
There are multiple options here. for example, you can export conditionally:
```js
import StorybookUI from "./storybook";
import StorybookUI from './storybook';
import App from "./app";
import App from './app';
module.exports = __DEV__ ? StorybookUI : App;
```
@ -121,6 +121,14 @@ You can pass these parameters to getStorybookUI call in your storybook entry poi
-- should the ui be closed initialy.
tabOpen: Number (0)
-- which tab should be open. -1 Navigator, 0 Preview, 1 Addons
initialSelection: Object (null)
-- initialize storybook with a specific story. In case a valid object is passed, it will take precedence over `shouldPersistSelection. ex: `{ kind: 'Knobs', story: 'with knobs' }`
shouldPersistSelection: Boolean (true)
-- initialize storybook with the last selected story.
shouldDisableKeyboardAvoidingView: Boolean (false)
-- Disable KeyboardAvoidingView wrapping Storybook's view
keyboardAvoidingViewVerticalOffset: Number (0)
-- With shouldDisableKeyboardAvoidingView=true, this will set the keyboardverticaloffset (https://facebook.github.io/react-native/docs/keyboardavoidingview#keyboardverticaloffset) value for KeyboardAvoidingView wrapping Storybook's view
}
```

View File

@ -5,6 +5,7 @@ import program from 'commander';
import Server from '../server';
program
.allowUnknownOption()
.option('-h, --host <host>', 'host to listen on', 'localhost')
.option('-p, --port <port>', 'port to listen on', 7007)
.option('-s, --secured', 'whether server is running on https')

View File

@ -1,6 +1,6 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { View, ScrollView, KeyboardAvoidingView, Platform } from 'react-native';
import { View, ScrollView } from 'react-native';
import style from '../style';
@ -8,8 +8,6 @@ export default class Wrapper extends PureComponent {
render() {
const { panels, addonSelected } = this.props;
const keyboardVerticalOffset = Platform.OS === 'ios' ? 60 : 0;
const addonKeys = Object.keys(panels);
return addonKeys.map(id => {
@ -17,13 +15,7 @@ export default class Wrapper extends PureComponent {
return (
<View key={id} style={selected ? style.flex : style.invisible}>
<KeyboardAvoidingView
behavior={Platform.OS === 'android' ? null : 'padding'}
keyboardVerticalOffset={keyboardVerticalOffset}
style={style.flex}
>
<ScrollView style={style.flex}>{panels[id].render({ active: selected })}</ScrollView>
</KeyboardAvoidingView>
<ScrollView style={style.flex}>{panels[id].render({ active: selected })}</ScrollView>
</View>
);
});

View File

@ -1,6 +1,13 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { SafeAreaView, Animated, TouchableOpacity } from 'react-native';
import {
Keyboard,
KeyboardAvoidingView,
Platform,
SafeAreaView,
Animated,
TouchableOpacity,
} from 'react-native';
import Events from '@storybook/core-events';
import StoryListView from '../StoryListView';
@ -22,6 +29,7 @@ import {
import style from './style';
const ANIMATION_DURATION = 300;
const IS_IOS = Platform.OS === 'ios';
export default class OnDeviceUI extends PureComponent {
constructor(props) {
@ -32,8 +40,8 @@ export default class OnDeviceUI extends PureComponent {
this.state = {
tabOpen,
slideBetweenAnimation: false,
selection: props.initialStory || {},
storyFn: props.initialStory ? props.initialStory.storyFn : null,
selection: {},
storyFn: null,
previewWidth: 0,
previewHeight: 0,
};
@ -42,8 +50,18 @@ export default class OnDeviceUI extends PureComponent {
this.forceRender = this.forceUpdate.bind(this);
}
componentWillMount() {
const { events } = this.props;
async componentWillMount() {
const { events, getInitialStory } = this.props;
if (getInitialStory) {
const story = await getInitialStory();
this.setState({
selection: story || {},
storyFn: story ? story.storyFn : null,
});
}
events.on(Events.SELECT_STORY, this.handleStoryChange);
events.on(Events.FORCE_RE_RENDER, this.forceRender);
}
@ -95,10 +113,22 @@ export default class OnDeviceUI extends PureComponent {
// True if swiping between navigator and addons
slideBetweenAnimation: tabOpen + newTabOpen === PREVIEW,
});
// close the keyboard opened from a TextInput from story list or knobs
if (newTabOpen === PREVIEW) {
Keyboard.dismiss();
}
};
render() {
const { stories, events, url, isUIHidden } = this.props;
const {
stories,
events,
url,
isUIHidden,
shouldDisableKeyboardAvoidingView,
keyboardAvoidingViewVerticalOffset,
} = this.props;
const {
tabOpen,
slideBetweenAnimation,
@ -121,40 +151,47 @@ export default class OnDeviceUI extends PureComponent {
return (
<SafeAreaView style={style.flex}>
<AbsolutePositionedKeyboardAwareView
onLayout={this.onLayout}
previewHeight={previewHeight}
previewWidth={previewWidth}
<KeyboardAvoidingView
enabled={!shouldDisableKeyboardAvoidingView || tabOpen !== PREVIEW}
behavior={IS_IOS ? 'padding' : null}
keyboardVerticalOffset={keyboardAvoidingViewVerticalOffset}
style={style.flex}
>
<Animated.View style={previewWrapperStyles}>
<Animated.View style={previewStyles}>
<TouchableOpacity
accessible={false}
style={style.flex}
disabled={tabOpen === PREVIEW}
onPress={this.handleOpenPreview}
>
<StoryView url={url} events={events} selection={selection} storyFn={storyFn} />
</TouchableOpacity>
<AbsolutePositionedKeyboardAwareView
onLayout={this.onLayout}
previewHeight={previewHeight}
previewWidth={previewWidth}
>
<Animated.View style={previewWrapperStyles}>
<Animated.View style={previewStyles}>
<TouchableOpacity
accessible={false}
style={style.flex}
disabled={tabOpen === PREVIEW}
onPress={this.handleOpenPreview}
>
<StoryView url={url} events={events} selection={selection} storyFn={storyFn} />
</TouchableOpacity>
</Animated.View>
</Animated.View>
</Animated.View>
<Panel style={getNavigatorPanelPosition(this.animatedValue, previewWidth)}>
<StoryListView
stories={stories}
events={events}
selectedKind={selection.kind}
selectedStory={selection.story}
/>
</Panel>
<Panel style={getAddonPanelPosition(this.animatedValue, previewWidth)}>
<Addons />
</Panel>
</AbsolutePositionedKeyboardAwareView>
<Navigation
tabOpen={tabOpen}
onChangeTab={this.handleToggleTab}
initialUiVisible={!isUIHidden}
/>
<Panel style={getNavigatorPanelPosition(this.animatedValue, previewWidth)}>
<StoryListView
stories={stories}
events={events}
selectedKind={selection.kind}
selectedStory={selection.story}
/>
</Panel>
<Panel style={getAddonPanelPosition(this.animatedValue, previewWidth)}>
<Addons />
</Panel>
</AbsolutePositionedKeyboardAwareView>
<Navigation
tabOpen={tabOpen}
onChangeTab={this.handleToggleTab}
initialUiVisible={!isUIHidden}
/>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
@ -175,16 +212,16 @@ OnDeviceUI.propTypes = {
url: PropTypes.string,
tabOpen: PropTypes.number,
isUIHidden: PropTypes.bool,
initialStory: PropTypes.shape({
story: PropTypes.string.isRequired,
kind: PropTypes.string.isRequired,
storyFn: PropTypes.func.isRequired,
}),
getInitialStory: PropTypes.func,
shouldDisableKeyboardAvoidingView: PropTypes.bool,
keyboardAvoidingViewVerticalOffset: PropTypes.number,
};
OnDeviceUI.defaultProps = {
url: '',
tabOpen: 0,
isUIHidden: false,
initialStory: null,
getInitialStory: null,
shouldDisableKeyboardAvoidingView: false,
keyboardAvoidingViewVerticalOffset: 0,
};

View File

@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { SectionList, View, Text, TouchableOpacity } from 'react-native';
import { SectionList, Text, TextInput, TouchableOpacity, View } from 'react-native';
import Events from '@storybook/core-events';
import style from './style';
@ -40,6 +40,7 @@ export default class StoryListView extends Component {
this.state = {
data: [],
originalData: [],
};
this.storyAddedHandler = this.handleStoryAdded.bind(this);
@ -71,12 +72,39 @@ export default class StoryListView extends Component {
}),
{}
);
this.setState({
data,
});
this.setState({ data, originalData: data });
}
};
handleChangeSearchText = text => {
const query = text.trim();
const { originalData: data } = this.state;
if (!query) {
this.setState({ data });
return;
}
const checkValue = value => value.toLowerCase().includes(query.toLowerCase());
const filteredData = data.reduce((acc, story) => {
const hasTitle = checkValue(story.title);
const hasKind = story.data.some(kind => checkValue(kind.name));
if (hasTitle || hasKind) {
acc.push({
...story,
// in case the query matches component's title, all of its stories will be shown
data: !hasTitle ? story.data.filter(kind => checkValue(kind.name)) : story.data,
});
}
return acc;
}, []);
this.setState({ data: filteredData });
};
changeStory(kind, story) {
const { events } = this.props;
@ -88,24 +116,34 @@ export default class StoryListView extends Component {
const { data } = this.state;
return (
<SectionList
testID="Storybook.ListView"
style={[style.list]}
renderItem={({ item }) => (
<ListItem
title={item.name}
kind={item.kind}
selected={item.kind === selectedKind && item.name === selectedStory}
onPress={() => this.changeStory(item.kind, item.name)}
/>
)}
renderSectionHeader={({ section: { title } }) => (
<SectionHeader title={title} selected={title === selectedKind} />
)}
keyExtractor={(item, index) => item + index}
sections={data}
stickySectionHeadersEnabled={false}
/>
<View style={style.flex}>
<TextInput
clearButtonMode="while-editing"
disableFullscreenUI
onChangeText={this.handleChangeSearchText}
placeholder="Filter"
returnKeyType="search"
style={style.searchBar}
/>
<SectionList
testID="Storybook.ListView"
style={style.flex}
renderItem={({ item }) => (
<ListItem
title={item.name}
kind={item.kind}
selected={item.kind === selectedKind && item.name === selectedStory}
onPress={() => this.changeStory(item.kind, item.name)}
/>
)}
renderSectionHeader={({ section: { title } }) => (
<SectionHeader title={title} selected={title === selectedKind} />
)}
keyExtractor={(item, index) => item + index}
sections={data}
stickySectionHeadersEnabled={false}
/>
</View>
);
}
}

View File

@ -1,10 +1,17 @@
export default {
list: {
searchBar: {
backgroundColor: '#eee',
borderRadius: 5,
fontSize: 16,
marginHorizontal: 5,
marginVertical: 5,
padding: 5,
},
flex: {
flex: 1,
},
header: {
paddingTop: 5,
paddingBottom: 5,
paddingVertical: 5,
},
headerText: {
fontSize: 20,

View File

@ -1,7 +1,7 @@
/* eslint-disable react/no-this-in-sfc, no-underscore-dangle */
/* eslint-disable no-underscore-dangle */
import React from 'react';
import { NativeModules } from 'react-native';
import { AsyncStorage, NativeModules } from 'react-native';
import parse from 'url-parse';
import addons from '@storybook/addons';
@ -12,6 +12,8 @@ import { StoryStore, ClientApi } from '@storybook/core/client';
import OnDeviceUI from './components/OnDeviceUI';
import StoryView from './components/StoryView';
const STORAGE_KEY = 'lastOpenedStory';
export default class Preview {
constructor() {
this._addons = {};
@ -44,7 +46,7 @@ export default class Preview {
let channel = null;
const onDeviceUI = params.onDeviceUI !== false;
const { initialSelection, shouldPersistSelection } = params;
// should the initial story be sent to storybookUI
// set to true if using disableWebsockets or if connection to WebsocketServer fails.
let setInitialStory = false;
@ -75,7 +77,9 @@ export default class Preview {
url,
async: onDeviceUI,
onError: () => {
this._setInitialStory();
// We are both emitting event and telling the component to get initial story. It may happen that component is created before the error or vise versa.
// This way we handle both cases
this._setInitialStory(initialSelection, shouldPersistSelection);
setInitialStory = true;
},
@ -88,7 +92,7 @@ export default class Preview {
}
channel.on(Events.GET_STORIES, () => this._sendSetStories());
channel.on(Events.SET_CURRENT_STORY, d => this._selectStory(d));
channel.on(Events.SET_CURRENT_STORY, d => this._selectStoryEvent(d));
this._sendSetStories();
// If the app is started with server running, set the story as the one selected in the browser
@ -112,7 +116,13 @@ export default class Preview {
url={webUrl}
isUIOpen={params.isUIOpen}
tabOpen={params.tabOpen}
initialStory={setInitialStory ? preview._getInitialStory() : null}
getInitialStory={
setInitialStory
? preview._getInitialStory(initialSelection, shouldPersistSelection)
: null
}
shouldDisableKeyboardAvoidingView={params.shouldDisableKeyboardAvoidingView}
keyboardAvoidingViewVerticalOffset={params.keyboardAvoidingViewVerticalOffset}
/>
);
}
@ -133,15 +143,33 @@ export default class Preview {
channel.emit(Events.GET_CURRENT_STORY);
}
_setInitialStory = () => {
const story = this._getInitialStory();
_setInitialStory = async (initialSelection, shouldPersistSelection = true) => {
const story = await this._getInitialStory(initialSelection, shouldPersistSelection)();
if (story) {
this._selectStory(story);
}
};
_getInitialStory = () => {
_getInitialStory = (initialSelection, shouldPersistSelection = true) => async () => {
let story = null;
if (initialSelection && this._checkStory(initialSelection)) {
story = initialSelection;
} else if (shouldPersistSelection) {
const value = await AsyncStorage.getItem(STORAGE_KEY);
const previousStory = JSON.parse(value);
if (this._checkStory(previousStory)) {
story = previousStory;
}
}
if (story) {
return this._getStory(story);
}
const dump = this._stories.dumpStoryBook();
const nonEmptyKind = dump.find(kind => kind.stories.length > 0);
if (nonEmptyKind) {
return this._getStory({ kind: nonEmptyKind.kind, story: nonEmptyKind.stories[0] });
@ -156,8 +184,31 @@ export default class Preview {
return { ...selection, storyFn };
}
_selectStory(selection) {
_selectStoryEvent(selection) {
AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(selection));
const story = this._getStory(selection);
this._selectStory(story);
}
_selectStory(story) {
const channel = addons.getChannel();
channel.emit(Events.SELECT_STORY, this._getStory(selection));
channel.emit(Events.SELECT_STORY, story);
}
_checkStory(selection) {
if (!selection || typeof selection !== 'object' || !selection.kind || !selection.story) {
console.warn('invalid storybook selection'); // eslint-disable-line no-console
return null;
}
const story = this._getStory(selection);
if (story.storyFn === null) {
console.warn('invalid storybook selection'); // eslint-disable-line no-console
return null;
}
return story;
}
}

View File

@ -6,6 +6,7 @@ module.exports = {
require.resolve('babel-preset-env'),
{
modules: process.env.NODE_ENV === 'test' ? 'commonjs' : false,
shippedProposals: true,
},
],
require.resolve('babel-preset-react'),

View File

@ -3,7 +3,7 @@ import webpack from 'webpack';
import Dotenv from 'dotenv-webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import { getManagerHeadHtml } from '@storybook/core/dist/server/utils';
import { getManagerHeadHtml } from '@storybook/core/dist/server/utils/template';
import { version } from '../../../package.json';
import { includePaths, excludePaths, loadEnv } from './utils';

View File

@ -1,14 +1,11 @@
{
"name": "@storybook/react",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook for React: Develop React Component in isolation with Hot Reloading.",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/app/react",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -28,25 +25,33 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@babel/plugin-transform-react-constant-elements": "^7.2.0",
"@babel/preset-flow": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"@babel/runtime": "^7.1.2",
"@emotion/styled": "^0.10.6",
"@storybook/core": "4.0.12",
"@storybook/node-logger": "4.0.12",
"@storybook/core": "4.1.0-alpha.12",
"@storybook/node-logger": "4.1.0-alpha.12",
"@svgr/webpack": "^4.0.3",
"babel-plugin-named-asset-import": "^0.2.3",
"babel-plugin-react-docgen": "^2.0.0",
"babel-preset-react-app": "^6.1.0",
"common-tags": "^1.8.0",
"core-js": "^2.5.7",
"global": "^4.3.2",
"lodash": "^4.17.11",
"mini-css-extract-plugin": "^0.4.4",
"prop-types": "^15.6.2",
"react": "^16.6.0",
"react-dev-utils": "^6.1.0",
"react-dom": "^16.6.0",
"regenerator-runtime": "^0.12.1",
"semver": "^5.6.0",
"webpack": "^4.23.1"
},
"peerDependencies": {
"babel-loader": "^7.0.0 || ^8.0.0",
"react": ">=15.0.0",
"react-dom": ">=15.0.0"
"babel-loader": "^7.0.0 || ^8.0.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,6 +1,6 @@
import { window } from 'global';
if (window.parent !== window) {
if (window && window.parent !== window) {
try {
// eslint-disable-next-line no-underscore-dangle
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
@ -8,4 +8,7 @@ if (window.parent !== window) {
// The above line can throw if we do not have access to the parent frame -- i.e. cross origin
}
}
window.STORYBOOK_ENV = 'react';
if (window) {
window.STORYBOOK_ENV = 'react';
}

View File

@ -0,0 +1,24 @@
/* eslint-disable global-require */
describe('preview', () => {
afterEach(() => {
jest.resetModules();
});
const isFunction = value => typeof value === 'function';
it('should return the client api in a browser environment', () => {
const api = require('.');
expect(Object.keys(api).length).toBeGreaterThan(0);
expect(Object.values(api).every(isFunction)).toEqual(true);
});
it('should return the client api in a node.js environment', () => {
jest.mock('global', () => ({
document: undefined,
window: undefined,
}));
const api = require('.');
expect(Object.keys(api).length).toBeGreaterThan(0);
expect(Object.values(api).every(isFunction)).toEqual(true);
});
});

View File

@ -4,7 +4,7 @@ import ReactDOM from 'react-dom';
import { stripIndents } from 'common-tags';
import isReactRenderable from './element_check';
const rootEl = document.getElementById('root');
const rootEl = document ? document.getElementById('root') : null;
function render(node, el) {
ReactDOM.render(

View File

@ -0,0 +1,151 @@
export default [
{ parser: { requireEnsure: false } },
{
test: /\.(js|mjs|jsx)$/,
enforce: 'pre',
use: [
{
options: {
formatter: '/mock_folder/node_modules/react-dev-utils/eslintFormatter.js',
eslintPath: '/mock_folder/node_modules/eslint/lib/api.js',
baseConfig: {
extends: ['/mock_folder/node_modules/eslint-config-react-app/index.js'],
settings: { react: { version: '999.999.999' } },
},
ignore: false,
useEslintrc: false,
},
loader: '/mock_folder/node_modules/eslint-loader/index.js',
},
],
include: '/mock_folder/src',
},
{
oneOf: [
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: '/mock_folder/node_modules/url-loader/dist/cjs.js',
options: { limit: 10000, name: 'static/media/[name].[hash:8].[ext]' },
},
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: '/mock_folder/src',
loader: '/mock_folder/node_modules/babel-loader/lib/index.js',
options: {
customize: '/mock_folder/node_modules/babel-preset-react-app/webpack-overrides.js',
babelrc: false,
configFile: false,
presets: ['/mock_folder/node_modules/babel-preset-react-app/index.js'],
cacheIdentifier:
'development:babel-plugin-named-asset-import@0.2.3:babel-preset-react-app@6.1.0:react-dev-utils@6.1.1:react-scripts@',
plugins: [
[
'/mock_folder/node_modules/babel-plugin-named-asset-import/index.js',
{
loaderMap: {
svg: {
ReactComponent: '@svgr/webpack?-prettier,-svgo![path]',
},
},
},
],
],
cacheDirectory: true,
cacheCompression: false,
compact: false,
},
},
{
test: /\.(js|mjs)$/,
exclude: {},
loader: '/mock_folder/node_modules/babel-loader/lib/index.js',
options: {
babelrc: false,
configFile: false,
compact: false,
presets: [
['/mock_folder/node_modules/babel-preset-react-app/dependencies.js', { helpers: true }],
],
cacheDirectory: true,
cacheCompression: false,
cacheIdentifier:
'development:babel-plugin-named-asset-import@0.2.3:babel-preset-react-app@6.1.0:react-dev-utils@6.1.1:react-scripts@',
sourceMaps: false,
},
},
{
test: /\.css$/,
exclude: {},
use: [
'/mock_folder/node_modules/bmr-react-scripts/node_modules/style-loader/index.js',
{
loader: '/mock_folder/node_modules/bmr-react-scripts/node_modules/css-loader/index.js',
options: { importLoaders: 1, sourceMap: false },
},
{
loader: '/mock_folder/node_modules/postcss-loader/src/index.js',
options: { ident: 'postcss', sourceMap: false },
},
],
sideEffects: true,
},
{
test: /\.module\.css$/,
use: [
'/mock_folder/node_modules/bmr-react-scripts/node_modules/style-loader/index.js',
{
loader: '/mock_folder/node_modules/bmr-react-scripts/node_modules/css-loader/index.js',
options: { importLoaders: 1, sourceMap: false, modules: true },
},
{
loader: '/mock_folder/node_modules/postcss-loader/src/index.js',
options: { ident: 'postcss', sourceMap: false },
},
],
},
{
test: /\.(scss|sass)$/,
exclude: {},
use: [
'/mock_folder/node_modules/bmr-react-scripts/node_modules/style-loader/index.js',
{
loader: '/mock_folder/node_modules/bmr-react-scripts/node_modules/css-loader/index.js',
options: { importLoaders: 2, sourceMap: false },
},
{
loader: '/mock_folder/node_modules/postcss-loader/src/index.js',
options: { ident: 'postcss', sourceMap: false },
},
{
loader: '/mock_folder/node_modules/sass-loader/lib/loader.js',
options: { sourceMap: false },
},
],
sideEffects: true,
},
{
test: /\.module\.(scss|sass)$/,
use: [
'/mock_folder/node_modules/bmr-react-scripts/node_modules/style-loader/index.js',
{
loader: '/mock_folder/node_modules/bmr-react-scripts/node_modules/css-loader/index.js',
options: { importLoaders: 2, sourceMap: false, modules: true },
},
{
loader: '/mock_folder/node_modules/postcss-loader/src/index.js',
options: { ident: 'postcss', sourceMap: false },
},
{
loader: '/mock_folder/node_modules/sass-loader/lib/loader.js',
options: { sourceMap: false },
},
],
},
{
loader: '/mock_folder/node_modules/file-loader/dist/cjs.js',
exclude: [{}, {}, {}],
options: { name: 'static/media/[name].[hash:8].[ext]' },
},
],
},
];

View File

@ -0,0 +1,141 @@
import fs from 'fs';
import path from 'path';
import semver from 'semver';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import { normalizeCondition } from 'webpack/lib/RuleSet';
const cssExtensions = ['.css', '.scss', '.sass'];
const cssModuleExtensions = ['.module.css', '.module.scss', '.module.sass'];
const typeScriptExtensions = ['.ts', '.tsx'];
let reactScriptsPath;
export function getReactScriptsPath({ noCache } = {}) {
if (reactScriptsPath && !noCache) return reactScriptsPath;
const appDirectory = fs.realpathSync(process.cwd());
const reactScriptsScriptPath = fs.realpathSync(
path.join(appDirectory, '/node_modules/.bin/react-scripts')
);
reactScriptsPath = path.join(reactScriptsScriptPath, '../..');
const scriptsPkgJson = path.join(reactScriptsPath, 'package.json');
if (!fs.existsSync(scriptsPkgJson)) {
reactScriptsPath = 'react-scripts';
}
return reactScriptsPath;
}
export function isReactScriptsInstalled(requiredVersion = '2.0.0') {
try {
// eslint-disable-next-line import/no-dynamic-require,global-require
const reactScriptsJson = require(path.join(getReactScriptsPath(), 'package.json'));
return !semver.lt(reactScriptsJson.version, requiredVersion);
} catch (e) {
return false;
}
}
export const getRules = extensions => rules =>
rules.reduce((craRules, rule) => {
// If at least one extension satisfies the rule test, the rule is one
// we want to extract
if (rule.test && extensions.some(normalizeCondition(rule.test))) {
// If the base test is for extensions, return early
return craRules.concat(rule);
}
// Get any rules contained in rule.oneOf
if (!rule.test && rule.oneOf) {
craRules.push(...getRules(extensions)(rule.oneOf));
}
// Get any rules contained in rule.rules
if (!rule.test && rule.rules) {
craRules.push(...getRules(extensions)(rule.rules));
}
return craRules;
}, []);
const getStyleRules = getRules(cssExtensions.concat(cssModuleExtensions));
export const getTypeScriptRules = (webpackConfigRules, configDir) => {
const rules = getRules(typeScriptExtensions)(webpackConfigRules);
// We know CRA only has one rule targetting TS for now, which is the first rule.
const babelRule = rules[0];
// Resolves an issue where this config is parsed twice (#4903).
if (typeof babelRule.include !== 'string') return rules;
// Adds support for using TypeScript in the `.storybook` (or config) folder.
return [
{
...babelRule,
include: [babelRule.include, path.resolve(configDir)],
},
...rules.slice(1),
];
};
export function getCraWebpackConfig(mode) {
const pathToReactScripts = getReactScriptsPath();
const craWebpackConfig =
mode === 'production' ? 'config/webpack.config.prod' : 'config/webpack.config.dev';
let pathToWebpackConfig = require.resolve(path.join(pathToReactScripts, craWebpackConfig));
if (!fs.existsSync(pathToWebpackConfig)) {
pathToWebpackConfig = path.join(pathToReactScripts, 'config/webpack.config');
}
// eslint-disable-next-line import/no-dynamic-require,global-require
const webpackConfig = require(pathToWebpackConfig);
if (typeof webpackConfig === 'function') {
return webpackConfig(mode);
}
return webpackConfig;
}
export function applyCRAWebpackConfig(baseConfig, configDir) {
// Check if the user can use TypeScript (react-scripts version 2.1+).
const hasTsSupport = isReactScriptsInstalled('2.1.0');
const tsExtensions = hasTsSupport ? typeScriptExtensions : [];
const extensions = [...cssExtensions, ...tsExtensions];
// Remove any rules from baseConfig that test true for any one of the extensions
const filteredBaseRules = baseConfig.module.rules.filter(
rule => !rule.test || !extensions.some(normalizeCondition(rule.test))
);
// Load create-react-app config
const craWebpackConfig = getCraWebpackConfig(baseConfig.mode);
const craStyleRules = getStyleRules(craWebpackConfig.module.rules);
const craTypeScriptRules = hasTsSupport
? getTypeScriptRules(craWebpackConfig.module.rules, configDir)
: [];
// Add css minification for production
const plugins = [...baseConfig.plugins];
if (baseConfig.mode === 'production') {
plugins.push(new MiniCssExtractPlugin());
}
return {
...baseConfig,
module: {
...baseConfig.module,
rules: [...filteredBaseRules, ...craStyleRules, ...craTypeScriptRules],
},
plugins,
resolve: {
...baseConfig.resolve,
extensions: [...baseConfig.resolve.extensions, ...tsExtensions],
},
};
}

View File

@ -0,0 +1,60 @@
import fs from 'fs';
import { getReactScriptsPath, getTypeScriptRules } from './cra-config';
import mockRules from './__mocks__/mockRules';
jest.mock('fs', () => ({
realpathSync: jest.fn(),
existsSync: () => true,
}));
jest.mock('mini-css-extract-plugin', () => {});
const SCRIPT_PATH = '.bin/react-scripts';
describe('cra-config', () => {
beforeEach(() => {
fs.realpathSync.mockImplementationOnce(() => '/test-project');
});
describe('when used with the default react-scripts package', () => {
beforeEach(() => {
fs.realpathSync.mockImplementationOnce(path =>
path.replace(SCRIPT_PATH, `react-scripts/${SCRIPT_PATH}`)
);
});
it('should locate the react-scripts package', () => {
expect(getReactScriptsPath({ noCache: true })).toEqual(
'/test-project/node_modules/react-scripts'
);
});
});
describe('when used with a custom react-scripts package', () => {
beforeEach(() => {
fs.realpathSync.mockImplementationOnce(path =>
path.replace(SCRIPT_PATH, `custom-react-scripts/${SCRIPT_PATH}`)
);
});
it('should locate the react-scripts package', () => {
expect(getReactScriptsPath({ noCache: true })).toEqual(
'/test-project/node_modules/custom-react-scripts'
);
});
});
describe('when used with TypeScript', () => {
const rules = getTypeScriptRules(mockRules, './.storybook');
it('should return the correct config', () => {
// Normalise the return, as we know our new rules object will be an array, whereas a string is expected.
const rulesObject = { ...rules[0], include: rules[0].include[0] };
expect(rulesObject).toMatchObject(mockRules[2].oneOf[1]);
});
// Allows using TypeScript in the `.storybook` (or config) folder.
it('should add the Storybook config directory to `include`', () => {
expect(rules[0].include.findIndex(string => string.includes('.storybook'))).toEqual(1);
});
});
});

View File

@ -1,91 +0,0 @@
import fs from 'fs';
import path from 'path';
import semver from 'semver';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import { normalizeCondition } from 'webpack/lib/RuleSet';
let reactScriptsPath;
function getReactScriptsPath() {
if (reactScriptsPath) return reactScriptsPath;
const appDirectory = fs.realpathSync(process.cwd());
const reactScriptsScriptPath = fs.realpathSync(
path.join(appDirectory, '/node_modules/.bin/react-scripts')
);
reactScriptsPath = path.join(reactScriptsScriptPath, '../..');
return reactScriptsPath;
}
export function isReactScriptsInstalled() {
try {
// eslint-disable-next-line global-require, import/no-dynamic-require
const reactScriptsJson = require(path.join(getReactScriptsPath(), 'package.json'));
if (semver.lt(reactScriptsJson.version, '2.0.0')) return false;
return true;
} catch (e) {
return false;
}
}
export function getStyleRules(rules) {
// Extensions of style rules we're interested in
const extensions = ['.css', '.scss', '.sass', '.module.css', '.module.scss', '.module.sass'];
return rules.reduce((styleRules, rule) => {
// If at least one style extension satisfies the rule test, the rule is one
// we want to extract
if (rule.test && extensions.some(normalizeCondition(rule.test))) {
// If the base test is for styles, return early
return styleRules.concat(rule);
}
// Get any style rules contained in rule.oneOf
if (!rule.test && rule.oneOf) {
styleRules.push(...getStyleRules(rule.oneOf));
}
// Get any style rules contained in rule.rules
if (!rule.test && rule.rules) {
styleRules.push(...getStyleRules(rule.rules));
}
return styleRules;
}, []);
}
export function getCraWebpackConfig(mode) {
if (mode === 'production') {
// eslint-disable-next-line global-require, import/no-dynamic-require
return require(path.join(getReactScriptsPath(), 'config/webpack.config.prod'));
}
// eslint-disable-next-line global-require, import/no-dynamic-require
return require(path.join(getReactScriptsPath(), 'config/webpack.config.dev'));
}
export function applyCRAWebpackConfig(baseConfig) {
// Remove any rules from baseConfig that test true for any one of the extensions
const baseRulesExcludingStyles = baseConfig.module.rules.filter(
rule => !rule.test || !['.css', '.scss', '.sass'].some(normalizeCondition(rule.test))
);
// Load create-react-app config
const craWebpackConfig = getCraWebpackConfig(baseConfig.mode);
const craStyleRules = getStyleRules(craWebpackConfig.module.rules);
// Add css minification for production
const plugins = [...baseConfig.plugins];
if (baseConfig.mode === 'production') {
plugins.push(new MiniCssExtractPlugin());
}
return {
...baseConfig,
module: {
...baseConfig.module,
rules: [...baseRulesExcludingStyles, ...craStyleRules],
},
plugins,
};
}

View File

@ -1,13 +0,0 @@
import { logger } from '@storybook/node-logger';
import { applyCRAWebpackConfig, isReactScriptsInstalled } from './cra_config';
export function webpackFinal(config) {
if (!isReactScriptsInstalled()) {
logger.info('=> Using base config because react-scripts is not installed.');
return config;
}
logger.info('=> Loading create-react-app config.');
return applyCRAWebpackConfig(config);
}

View File

@ -0,0 +1,36 @@
import { logger } from '@storybook/node-logger';
import { applyCRAWebpackConfig, isReactScriptsInstalled } from './cra-config';
export function webpackFinal(config, { configDir }) {
if (!isReactScriptsInstalled()) {
logger.info('=> Using base config because react-scripts is not installed.');
return config;
}
logger.info('=> Loading create-react-app config.');
return applyCRAWebpackConfig(config, configDir);
}
export function babelDefault(config) {
if (!isReactScriptsInstalled()) {
return config;
}
return {
...config,
presets: [require.resolve('babel-preset-react-app')],
plugins: [
[
require.resolve('babel-plugin-named-asset-import'),
{
loaderMap: {
svg: {
ReactComponent: '@svgr/webpack?-prettier,-svgo![path]',
},
},
},
],
],
};
}

View File

@ -5,7 +5,7 @@ export default {
defaultConfigName: 'create-react-app',
frameworkPresets: [
require.resolve('./framework-preset-react.js'),
require.resolve('./framework-preset-cra.js'),
require.resolve('./framework-preset-react-docgen.js'),
require.resolve('./framework-preset-cra-styles.js'),
],
};

View File

@ -1,14 +1,11 @@
{
"name": "@storybook/riot",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook for riot.js: View riot snippets in isolation with Hot Reloading.",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/app/riot",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -27,21 +24,20 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@babel/runtime": "^7.1.2",
"@storybook/core": "4.0.12",
"@storybook/core": "4.1.0-alpha.12",
"common-tags": "^1.8.0",
"core-js": "^2.5.7",
"global": "^4.3.2",
"raw-loader": "^0.5.1",
"react": "^16.6.0",
"react-dom": "^16.6.0"
"react-dom": "^16.6.0",
"regenerator-runtime": "^0.12.1"
},
"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.1.0",
"@babel/plugin-transform-runtime": "^7.1.0",
"@babel/preset-env": "^7.1.0",
"@babel/plugin-transform-modules-commonjs": "^7.2.0",
"@babel/preset-env": "^7.2.0",
"@babel/preset-flow": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"@babel/runtime": "^7.0.0"
"@babel/preset-react": "^7.0.0"
},
"peerDependencies": {
"babel-loader": "^7.0.0 || ^8.0.0",
@ -49,5 +45,8 @@
"riot-compiler": "^3.5.1 || ^4.0.0",
"riot-hot-reload": "^1.0.0",
"riot-tag-loader": "^2.0.0 || ^3.0.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -15,5 +15,12 @@ export function webpack(config) {
},
],
},
resolve: {
...config.resolve,
alias: {
...config.resolve.alias,
'riot-compiler': 'riot-compiler/dist/es6.compiler',
},
},
};
}

View File

@ -1,14 +1,11 @@
{
"name": "@storybook/svelte",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/app/svelte",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -28,19 +25,24 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/core": "4.0.12",
"@storybook/core": "4.1.0-alpha.12",
"common-tags": "^1.8.0",
"core-js": "^2.5.7",
"global": "^4.3.2",
"react": "^16.6.0",
"react-dom": "^16.6.0"
"react-dom": "^16.6.0",
"regenerator-runtime": "^0.12.1"
},
"devDependencies": {
"svelte": "^2.13.5",
"svelte": "^2.15.3",
"svelte-loader": "^2.11.0"
},
"peerDependencies": {
"babel-loader": "^7.0.0 || ^8.0.0",
"svelte": "^2.7.2",
"svelte-loader": "^2.9.1"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -1,14 +1,11 @@
{
"name": "@storybook/vue",
"version": "4.0.12",
"version": "4.1.0-alpha.12",
"description": "Storybook for Vue: Develop Vue Component in isolation with Hot Reloading.",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/app/vue",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -28,12 +25,13 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@babel/runtime": "^7.1.2",
"@storybook/core": "4.0.12",
"@storybook/core": "4.1.0-alpha.12",
"common-tags": "^1.8.0",
"core-js": "^2.5.7",
"global": "^4.3.2",
"react": "^16.6.0",
"react-dom": "^16.6.0"
"react-dom": "^16.6.0",
"regenerator-runtime": "^0.12.1"
},
"devDependencies": {
"babel-preset-vue": "^2.0.2",
@ -46,5 +44,8 @@
"vue": ">=2.5.16",
"vue-loader": ">=15.x.x",
"vue-template-compiler": ">=2.5.16"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -37,6 +37,8 @@ const checkRequiredLabels = labels => {
const foundLabels = intersection(requiredLabels, labels);
if (isEmpty(foundLabels)) {
fail(`PR is not labeled with one of: ${JSON.stringify(requiredLabels)}`);
} else if (foundLabels.length > 1) {
fail(`Please choose only one of these labels: ${JSON.stringify(foundLabels)}`);
}
};

View File

@ -6,11 +6,13 @@ const sm = require('sitemap');
const stripIndent = require('common-tags/lib/stripIndent');
function pagesToSitemap(pages) {
return pages.filter(p => !!p.path).map(p => ({
url: p.path,
changefreq: 'daily',
priority: 0.7,
}));
return pages
.filter(p => !!p.path)
.map(p => ({
url: p.path,
changefreq: 'daily',
priority: 0.7,
}));
}
function generateSitemap(pages) {

View File

@ -19,16 +19,16 @@
"prepare": "npm run snyk-protect"
},
"dependencies": {
"@storybook/addon-actions": "^4.0.0",
"@storybook/addon-links": "^3.4.11",
"@storybook/addons": "^3.4.11",
"@storybook/addon-actions": "^4.0.9",
"@storybook/addon-links": "^4.0.9",
"@storybook/addons": "^4.0.9",
"@storybook/react": "^3.4.11",
"babel-loader": "^6.4.1",
"bootstrap": "^4.1.3",
"common-tags": "^1.8.0",
"gatsby": "^1.9.279",
"gatsby-link": "^1.6.45",
"gatsby-plugin-sharp": "^2.0.10",
"gatsby-plugin-sharp": "^2.0.12",
"gatsby-remark-autolink-headers": "^1.4.19",
"gatsby-remark-copy-linked-files": "^1.5.37",
"gatsby-remark-images": "^1.5.67",
@ -36,9 +36,9 @@
"gatsby-source-filesystem": "^1.5.39",
"gatsby-transformer-remark": "^1.7.44",
"global": "^4.3.2",
"highlight.js": "^9.13.0",
"highlight.js": "^9.13.1",
"lodash": "^4.17.11",
"marked": "^0.5.1",
"marked": "^0.5.2",
"prop-types": "^15.6.2",
"react": "^15.6.2",
"react-document-title": "^2.0.3",
@ -46,8 +46,8 @@
"react-helmet": "^5.2.0",
"react-router": "^4.3.1",
"react-stack-grid": "^0.7.1",
"sitemap": "^2.0.1",
"snyk": "^1.104.0"
"sitemap": "^2.1.0",
"snyk": "^1.110.2"
},
"snyk": true
}

View File

@ -22,6 +22,8 @@ import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
import '@storybook/addon-notes/register';
```
Once created, youl'll have to restart storybook to make the underlying webpack aware of the addons file.
This will register all the addons and you'll be able to see the actions and notes panels (in that order) when you are viewing the story. (Links do not register a tab--check individual addon docs to see which Storybook features they use!)

View File

@ -15,11 +15,11 @@ In this guide, we will set up Storybook for your React project.
## Table of contents
- [Add @storybook/react](#add-storybookreact)
- [Add react, react-dom, babel-core, and babel-loader](#add-react-react-dom-babel-core-and-babel-loader)
- [Create the config file](#create-the-config-file)
- [Write your stories](#write-your-stories)
- [Run your Storybook](#run-your-storybook)
- [Add @storybook/react](#add-storybookreact)
- [Add react, react-dom, @babel/core, and babel-loader](#add-react-react-dom-babel-core-and-babel-loader)
- [Create the config file](#create-the-config-file)
- [Write your stories](#write-your-stories)
- [Run your Storybook](#run-your-storybook)
## Add @storybook/react
@ -29,13 +29,13 @@ First of all, you need to add `@storybook/react` to your project. To do that, ru
npm i --save-dev @storybook/react
```
## Add react, react-dom, babel-core, and babel-loader
## Add react, react-dom, @babel/core, and babel-loader
Make sure that you have `react`, `react-dom`, `babel-core`, and `babel-loader` in your dependencies as well because we list these as peer dependencies:
Make sure that you have `react`, `react-dom`, `@babel/core`, and `babel-loader` in your dependencies as well because we list these as a peer dependencies:
```sh
npm i --save react react-dom
npm i --save-dev babel-core
npm i --save-dev @babel/core
npm i --save-dev babel-loader
```
@ -51,7 +51,7 @@ Then add the following NPM script to your `package.json` in order to start the s
## Create the config file
Storybook can be configured in several different ways.
Storybook can be configured in several different ways.
Thats why we need a config directory. We've added a `-c` option to the above NPM script mentioning `.storybook` as the config directory.
For a basic Storybook configuration, the only thing you need to do is tell Storybook where to find stories.
@ -83,14 +83,12 @@ import { storiesOf } from '@storybook/react';
import { Button } from '@storybook/react/demo';
storiesOf('Button', module)
.add('with text', () => <Button>Hello Button</Button>)
.add('with text', () => (
<Button>Hello Button</Button>
))
.add('with some emoji', () => (
<Button>
<span role="img" aria-label="so cool">
😀 😎 👍 💯
</span>
</Button>
));
<Button><span role="img" aria-label="so cool">😀 😎 👍 💯</span></Button>
));
```
Each story is a single state of your component. In the above case, there are two stories for the demo button component:

View File

@ -86,4 +86,5 @@ storybook({
port: 9009,
configDir: './.storybook',
});
```
```

View File

@ -78,7 +78,17 @@ overlayBackground: applied to overlay `background`, // 'linear-gradient(to botto
All options above are single key options, in other words, they are variables, and their usage is fixed.
We will extend the theming ability in the future and possibly add more deep theming ability.
Right now we have identified the most likely thing you might want to change the appearance of more then just 1 variable so we allow you the deep-theme the header using: `brand`.
Right now we allow to deep theme: `stories nav panel`. Below are the varaiables that are used to deep theme `stories nav panel`.
storiesNav: deep theme for `stories nav`
```
storiesNav: {
backgroundColor: 'aqua',
}
```
brand: deep theme for brand including `brand name` and `shortcuts`
```
brand: {
@ -86,6 +96,69 @@ brand: {
}
```
brandLink: deep theme for only `brand name`
```
brandLink: {
border: 'none'
}
```
filter: deep thene for `stories filter section`
```
filter: {
backgroundColor: 'red',
}
```
treeHeader: deep thene for `tree header`
```
treeHeader: {
color: 'blue',
}
```
treeMenuHeader: deep thene for `tree menu header` of each menu
```
treeMenuHeader: {
color: 'aqua',
}
```
menuLink: deep thene for `menu link` of each story
```
menuLink: {
color: 'black',
}
```
activeMenuLink: deep thene for `active menu link` for the active story
```
activeMenuLink: {
fontWeight: 'light',
}
```
treeArrow: deep theme for `tree arrow`. This accepts an object which receives `height`, `width`, `base` and `wrapper`
```
treeArrow: {
height: 5,
width: 5,
base: {
fontSize: '12px'
},
wrapper: {
backgroundColor: 'white'
}
}
```
The styles provided here support everything [emotion](https://emotion.sh/) does. So that included things like nested selectors!
## Adding more theme variables for addons

View File

@ -1,11 +1,13 @@
---
id: 'typescript-config'
title: 'Typescript Config'
title: 'TypeScript Config'
---
This is a central reference for using Storybook with Typescript.
This is a central reference for using Storybook with TypeScript.
## Dependencies you may need
## Setting up TypeScript with awesome-typescript-loader
### Dependencies you may need
```bash
yarn add -D typescript
@ -17,7 +19,7 @@ yarn add -D jest "@types/jest" ts-jest #testing
We have had the best experience using `awesome-typescript-loader`, but other tutorials may use `ts-loader`, just configure accordingly. You can even use `babel-loader` with a `ts-loader` configuration.
## Setting up Typescript to work with Storybook
### Setting up TypeScript to work with Storybook
We first have to use the [custom Webpack config in full control mode, extending default configs](/configurations/custom-webpack-config/#full-control-mode--default) by creating a `webpack.config.js` file in our Storybook configuration directory (by default, its `.storybook`):
@ -37,7 +39,7 @@ module.exports = (baseConfig, env, config) => {
The above example shows a working Webpack config with the TSDocgen plugin also integrated; remove the optional sections if you don't plan on using them.
## `tsconfig.json`
### `tsconfig.json`
```json
{
@ -71,9 +73,41 @@ The above example shows a working Webpack config with the TSDocgen plugin also i
This is for the default configuration where `/stories` is a peer of `src`. If you have them all in just `src` you may wish to replace `"rootDirs": ["src", "stories"]` above with `"rootDir": "src",`.
## Setting up TypeScript with babel-loader
When using latest create-react-app (CRA 2.0), Babel 7 has native TypeScript support. Setup becomes easier.
### Dependencies you may need
```bash
yarn add -D @types/storybook__react # typings
```
### Setting up TypeScript to work with Storybook
We first have to use the [custom Webpack config in full control mode, extending default configs](/configurations/custom-webpack-config/#full-control-mode--default) by creating a `webpack.config.js` file in our Storybook configuration directory (by default, its `.storybook`):
```js
module.exports = (baseConfig, env, config) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('babel-loader'),
options: {
presets: [['react-app', { flow: false, typescript: true }]],
},
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
};
```
### `tsconfig.json`
The default `tsconfig.json` that comes with CRA works great. If your stories are outside the `src` folder, for example the `stories` folder in root, then `rootDirs": ["src", "stories"]` needs to be added to be added to `compilerOptions` so it knows what folders to compile. Make sure `jsx` is set to preserve. Should be unchanged.
## Import tsx stories
Change `config.ts` inside the Storybook config directory (by default, its `.storybook`) to import stories made with Typescript:
Change `config.ts` inside the Storybook config directory (by default, its `.storybook`) to import stories made with TypeScript:
```js
// automatically import all files ending in *.stories.tsx
@ -86,9 +120,9 @@ function loadStories() {
configure(loadStories, module);
```
## Using Typescript with the TSDocgen addon
## Using TypeScript with the TSDocgen addon
The very handy [Storybook Info addon](https://github.com/storybooks/storybook/tree/master/addons/info) autogenerates prop tables documentation for each component, however it doesn't work with Typescript types. The current solution is to use [react-docgen-typescript-loader](https://github.com/strothj/react-docgen-typescript-loader) to preprocess the Typescript files to give the Info addon what it needs. The webpack config above does this, and so for the rest of your stories you use it as per normal:
The very handy [Storybook Info addon](https://github.com/storybooks/storybook/tree/master/addons/info) autogenerates prop tables documentation for each component, however it doesn't work with Typescript types. The current solution is to use [react-docgen-typescript-loader](https://github.com/strothj/react-docgen-typescript-loader) to preprocess the TypeScript files to give the Info addon what it needs. The webpack config above does this, and so for the rest of your stories you use it as per normal:
```js
import * as React from 'react';
@ -196,16 +230,16 @@ This is an example `jest.config.js` file for jest:
```js
module.exports = {
transform: {
".(ts|tsx)": "ts-jest",
},
testPathIgnorePatterns: ["/node_modules/", "/lib/"],
testRegex: "(/test/.*|\\.(test|spec))\\.(ts|tsx|js)$",
moduleFileExtensions: ["ts", "tsx", "js", "json"],
transform: {
'.(ts|tsx)': 'ts-jest',
},
testPathIgnorePatterns: ['/node_modules/', '/lib/'],
testRegex: '(/test/.*|\\.(test|spec))\\.(ts|tsx|js)$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
};
```
## Building your Typescript Storybook
## Building your TypeScript Storybook
You will need to set up some scripts - these may help:

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