Fix useChannel tests

This commit is contained in:
Hypnosphi 2019-06-30 01:36:33 +03:00
commit b07a636af9
484 changed files with 16212 additions and 5267 deletions

View File

@ -13,6 +13,7 @@ const withTests = {
};
module.exports = {
ignore: ['./lib/codemod/src/transforms/__testfixtures__'],
presets: [
['@babel/preset-env', { shippedProposals: true, useBuiltIns: 'usage', corejs: '3' }],
'@babel/preset-typescript',
@ -53,6 +54,7 @@ module.exports = {
},
{
test: './lib',
exclude: './addons/storysource/src/loader',
presets: [
['@babel/preset-env', { shippedProposals: true, useBuiltIns: 'usage', corejs: '3' }],
'@babel/preset-react',
@ -76,6 +78,7 @@ module.exports = {
'./lib/core/src/server',
'./lib/node-logger',
'./lib/codemod',
'./lib/source-loader/src',
'./addons/storyshots',
'./addons/storysource/src/loader',
'./app/**/src/server/**',

View File

@ -10,6 +10,7 @@ lib/cli/test
scripts/storage
*.bundle.js
*.js.map
*.d.ts
!.remarkrc.js
!.babelrc.js
@ -18,7 +19,3 @@ scripts/storage
!.jest.config.js
!.storybook
REACT_NATIVE
examples-native
react-native
ondevice-*

View File

@ -7,7 +7,7 @@
'app: react-native': ['benoitdion', 'gongreg']
'app: react-native-server': ['benoitdion', 'igor-dv']
'app: svelte': ['cam-stitt', 'plumpNation']
'app: vue': ['backbone87', 'elevatebart']
'app: vue': ['backbone87', 'elevatebart', 'pksunkara']
'api: addons': ['ndelangen']
'addon: a11y': ['CodeByAlex', 'Armanio', 'jsomsanith']
'addon: contexts': ['leoyli']

View File

@ -1,3 +1,188 @@
## 5.2.0-alpha.32 (June 29, 2019)
### Features
* Addon-docs: Add .story.mdx support to preset ([#7229](https://github.com/storybookjs/storybook/pull/7229))
### Bug Fixes
* React-native: Fix react native server ([#7187](https://github.com/storybookjs/storybook/pull/7187))
* Addon-docs: Fix source-loader in monorepo examples ([#7214](https://github.com/storybookjs/storybook/pull/7214))
### Maintenance
* Addon-docs: Convert repo stories to new module format ([#7175](https://github.com/storybookjs/storybook/pull/7175))
## 5.2.0-alpha.31 (June 27, 2019)
### Breaking Changes
* Module format: story field for name/parameters annotation ([#7202](https://github.com/storybookjs/storybook/pull/7202))
### Features
* Core: Story sorting ([#6472](https://github.com/storybookjs/storybook/pull/6472))
### Maintenance
* Addon-docs: Fix source-loader CI errors ([#7203](https://github.com/storybookjs/storybook/pull/7203))
## 5.2.0-alpha.30 (June 25, 2019)
This release merges `release/docs-technical-preview` branch back into `next` through a series of PRs. It also contains other changes that came in on `next` since the last alpha.
### Features
* CLI: Add info command to print environment information ([#6937](https://github.com/storybookjs/storybook/pull/6937))
* CLI: Use process.env.CI if available ([#7118](https://github.com/storybookjs/storybook/pull/7118))
* Addon-docs: Source loader library ([#7117](https://github.com/storybookjs/storybook/pull/7117))
* Addon-docs: Support non-story exports in MDX ([#7188](https://github.com/storybookjs/storybook/pull/7188))
* Addon-docs: Support non-story exports in module format ([#7185](https://github.com/storybookjs/storybook/pull/7185))
* Addon-docs: Docs mode with `--docs` flag ([#7154](https://github.com/storybookjs/storybook/pull/7154))
* Addon-docs: Convert to module format codemod ([#7174](https://github.com/storybookjs/storybook/pull/7174))
* Addon-docs: MDX support ([#7145](https://github.com/storybookjs/storybook/pull/7145))
* Addon-docs: Component parameter codemod ([#7155](https://github.com/storybookjs/storybook/pull/7155))
* Addon-docs: DocsPage and doc blocks ([#7119](https://github.com/storybookjs/storybook/pull/7119))
* Addon-docs: Module story format & framework param ([#7110](https://github.com/storybookjs/storybook/pull/7110))
* Addon-docs: Basic skeleton, UI viewMode handling ([#7107](https://github.com/storybookjs/storybook/pull/7107))
### Bug Fixes
* Addon-backgrounds: Fix unstretched preview background wrapper ([#7173](https://github.com/storybookjs/storybook/pull/7173))
* Addon-notes/info: Fix indenting on markdown code blocks ([#7158](https://github.com/storybookjs/storybook/pull/7158))
* Core: Improve HMR error reporting, no refreshes needed for error recovery ([#6972](https://github.com/storybookjs/storybook/pull/6972))
* Addon-info: change stylesheetBase info height from 110vh to 100vh ([#7141](https://github.com/storybookjs/storybook/pull/7141))
### Maintenance
* Typescript: Migrate addon viewport ([#7177](https://github.com/storybookjs/storybook/pull/7177))
### Dependency Upgrades
* Bump css-loader from 2.1.1 to 3.0.0 ([#7122](https://github.com/storybookjs/storybook/pull/7122))
* Upgrade core-js to 3.x in devkits ([#7171](https://github.com/storybookjs/storybook/pull/7171))
* UPGRADE lazy-universal-dotenv ([#7151](https://github.com/storybookjs/storybook/pull/7151))
## 5.1.9 (June 20, 2019)
### Bug Fixes
* Core: Fix JSON babel config error reporting ([#7104](https://github.com/storybookjs/storybook/pull/7104))
* UI: Fix about page version check message ([#7105](https://github.com/storybookjs/storybook/pull/7105))
### Dependency Upgrades
* Add missing dependencies to ui/react ([#7081](https://github.com/storybookjs/storybook/pull/7081))
* UPGRADE lazy-universal-dotenv ([#7151](https://github.com/storybookjs/storybook/pull/7151))
* Make compatible with yarn Pnp ([#6922](https://github.com/storybookjs/storybook/pull/6922))
## 5.2.0-alpha.29 (June 17, 2019)
### Features
* Addon-notes: enable multiple sections in notes panel ([#6861](https://github.com/storybookjs/storybook/pull/6861))
* Addon-context: title fallback ([#7078](https://github.com/storybookjs/storybook/pull/7078))
* Addon-info: Fix rendering of code block ([#6016](https://github.com/storybookjs/storybook/pull/6016))
### Bug Fixes
* Core: Fix JSON babel config error reporting ([#7104](https://github.com/storybookjs/storybook/pull/7104))
* UI: Fix about page version check message ([#7105](https://github.com/storybookjs/storybook/pull/7105))
### Maintenance
* Core: Refactor story_store ([#6382](https://github.com/storybookjs/storybook/pull/6382))
* Core: Make compatible with yarn Pnp ([#6922](https://github.com/storybookjs/storybook/pull/6922))
### Dependency Upgrades
* Bump jest-expo from 32.0.1 to 33.0.2 ([#6996](https://github.com/storybookjs/storybook/pull/6996))
## 5.2.0-alpha.28 (June 17, 2019)
Publish failed
## 5.2.0-alpha.27 (June 17, 2019)
* CLI: improve bootstrap list ([#6993](https://github.com/storybookjs/storybook/pull/6993))
* CLI: replaced merge-dirs dependency by fs-extra ([#7100](https://github.com/storybookjs/storybook/pull/7100))
## 5.1.8 (June 14, 2019)
### Bug Fixes
* CLI: Fix RN template to not import addons ([#7096](https://github.com/storybookjs/storybook/pull/7096))
## 5.1.7 (June 14, 2019)
### Bug Fixes
* UI: Fix warning of loading prop not being a string ([#7080](https://github.com/storybookjs/storybook/pull/7080))
## 5.1.6 (June 14, 2019)
Publish failed
## 5.1.5 (June 14, 2019)
### Bug Fixes
* Core: Upgrade plugin core-js fix ([#7086](https://github.com/storybookjs/storybook/pull/7086))
* UI: Fix sidebar loading visibility ([#7073](https://github.com/storybookjs/storybook/pull/7073))
* UI: Fix unnecessary large bundlesize ([#7091](https://github.com/storybookjs/storybook/pull/7091))
* Addon-contexts, RN-server: Add core-js dep ([#7094](https://github.com/storybookjs/storybook/pull/7094))
## 5.2.0-alpha.26 (June 14, 2019)
- Merge in changes from 5.1.7/next branch.
- Fix earlier merge problems relating to addon-docs:
- Restore `--docs` command-line functionality
- Fix refreshing docs page bug
## 5.2.0-alpha.25 (June 14, 2019)
Publish failed
## 5.1.4 (June 13, 2019)
### Bug Fixes
* Core: Fix core-js 3 errors ([#7051](https://github.com/storybookjs/storybook/pull/7051))
* UI: Fix syntax highlighter plain text not visible ([#7057](https://github.com/storybookjs/storybook/pull/7057))
* Addon-actions: Add default options to action(s) ([#6438](https://github.com/storybookjs/storybook/pull/6438))
### Dependency Upgrades
* fix: add missing core-js dependency ([#7016](https://github.com/storybookjs/storybook/pull/7016))
* chore: set react version to 16.8.3 to match react native ([#7008](https://github.com/storybookjs/storybook/pull/7008))
## 5.2.0-alpha.24 (June 13, 2019)
Merge in changes from 5.1.3/next branch.
## 5.2.0-alpha.23 (June 10, 2019)
Merge in changes from 5.1.3/next branch. Releasing from the addon-docs branch to keep things moving until we can merge addon-docs into next.
## 5.2.0-alpha.22 (June 7, 2019)
- Merge in changes from 5.1.1
- Addon-docs:
- Inline stories respect height prop
- Export Description block
## 5.1.3 (June 6, 2019)
### Bug Fixes
* UI: Fix links that are not working with plain left click ([#6970](https://github.com/storybookjs/storybook/pull/6970))
* Core: Don't redefine `process` variable ([#6991](https://github.com/storybookjs/storybook/pull/6991))
* Core: Don't mutate user's babel config ([#6987](https://github.com/storybookjs/storybook/pull/6987))
## 5.1.2 (June 6, 2019)
Publish failed
## 5.1.1 (June 5, 2019)
Storybook 5.1 is a juicy upgrade including:
@ -42,6 +227,16 @@ Publish failed
* Core: Fix webpack `process.*` variable definitions ([#6946](https://github.com/storybookjs/storybook/pull/6946))
* Angular: Fix tsconfig.app.json detection for Angular 8 ([#6940](https://github.com/storybookjs/storybook/pull/6940))
## 5.2.0-alpha.21 (June 2, 2019)
- Core: Convert module format to use default export for metadata
- Addon-docs: Compile MDX to default export modules format
- Source-loader: Support parameter injection for default export metadata
## 5.2.0-alpha.20 (May 31, 2019)
- Addon-docs: Use Meta doc block instead of exporting componentMeta
## 5.1.0-rc.3 (May 29, 2019)
### Features
@ -62,12 +257,46 @@ Publish failed
* Bump ts-node from 8.1.0 to 8.2.0 ([#6890](https://github.com/storybookjs/storybook/pull/6890))
* Bump svelte from 3.4.2 to 3.4.4 ([#6892](https://github.com/storybookjs/storybook/pull/6892))
## 5.2.0-alpha.19 (May 28, 2019)
- Source-loader: Fix bad package dependencies
## 5.1.0-rc.2 (May 27, 2019)
### Bug Fixes
* Core: Fix JS/JSON loading babel config ([#6878](https://github.com/storybookjs/storybook/pull/6878))
## 5.2.0-alpha.18 (May 26, 2019)
- Addon-docs: Codemod for adding component parameters
- Core: Babel config loading bugfix ([#6878](https://github.com/storybookjs/storybook/pull/6878))
## 5.2.0-alpha.17 (May 26, 2019)
- Addon-docs: Refer to selected story/component with `id="."` / `of="."`
## 5.2.0-alpha.16 (May 25, 2019)
- Addon-docs: Auto-configure `inlineStories` & `getPropDefs` based on framework
## 5.2.0-alpha.15 (May 25, 2019)
- Addon-docs: Expanded Vue support
- Props table support
- iframeHeight configuration parameter
## 5.2.0-alpha.14 (May 25, 2019)
- Addon-docs: Expanded source formats via `@storybook/source-loader`
- Legacy `storiesOf` format x (JS / TSX)
- Component modules format x (JS / TSX)
- Component MDX format
## 5.2.0-alpha.13 (May 24, 2019)
- Addon-docs: Add documentation-only `--docs` option to build storybook
## 5.1.0-rc.1 (May 24, 2019)
### Features
@ -122,6 +351,29 @@ Publish failed
* Bump svelte from 3.4.1 to 3.4.2 ([#6838](https://github.com/storybookjs/storybook/pull/6838))
* Misc upgrades ([#6820](https://github.com/storybookjs/storybook/pull/6820))
## 5.2.0-alpha.12 (May 21, 2019)
- Addon-docs: Fix regression in preview source for legacy stories
## 5.2.0-alpha.11 (May 21, 2019)
- Addon-docs:
- Source refer to stories by name
- Source support for multi-story previews
- Fix loader bug for plaintext stories
## 5.2.0-alpha.10 (May 19, 2019)
- Addon-docs: Display source dropdown in preview component
## 5.2.0-alpha.9 (May 17, 2019)
- Addon-docs bugfixes:
- Fix broken components stories
- Fix regression in iframe preview
- Fix docgen props block
- Fix margin styling on docs page
## 5.1.0-beta.1 (May 16, 2019)
### Bug Fixes
@ -139,6 +391,49 @@ Publish failed
* Bump fs-extra from 7.0.1 to 8.0.1 ([#6776](https://github.com/storybookjs/storybook/pull/6776))
## 5.2.0-alpha.8 (May 15, 2019)
- Addon-docs: Optimize docs pane rerendering
## 5.2.0-alpha.7 (May 15, 2019)
- Addon-docs: Docs page bugfix
- Addon-docs: Fix source block for legacy stories
NOTE: use `@storybook/addon-storysource/loader` with option `injectParameters: true` for legacy source
## 5.2.0-alpha.6 (May 14, 2019)
- Addon-docs: Docs page content update
- Addon-docs: Preview component redefinition
#### Breaking changes
Preview behavior has been updated. Docs page content has been updated.
Before:
- `<Story name="a">` defines a story, `<Preview id="x--a"/>` references it
After:
- `<Story name="a">` defines a story, `<Story id="x--a"/>` references it
- `<Preview><Story .../><Story .../><Component/></Preview>` shows one or more stories in a grid
## 5.2.0-alpha.5 (May 12, 2019)
- Addon-docs: Description block refactor and bugfixes
## 5.2.0-alpha.4 (May 11, 2019)
- Addon-docs: Source, Props, DocsPage doc blocks
#### Breaking changes
- Doc blocks & presets have moved. Update your MDX stories and `presets.js` file accordingly:
- `import { Preview, Story } from '@storybook/addon-docs/blocks';
- `module.exports = ['@storybook/addon-docs/common/preset'];`
## 5.1.0-beta.0 (May 10, 2019)
Welcome to the 5.1 beta! Feature development's done; `beta.0` kicks off the stabilization process for the 5.1 final release. 🚀
@ -204,6 +499,25 @@ Failed publish
- CLI: Refactor how we install dev dependencies in cli ([#6695](https://github.com/storybookjs/storybook/pull/6695))
## 5.2.0-alpha.3 (May 1, 2019)
- Addon-docs: Add Story decorator and parameter support
- Addon-docs: Remove need for extra project babelrc
## 5.2.0-alpha.2 (April 30, 2019)
- Addon-docs: Streamline setup, fix MDX dependencies, improve MDX import, and update guide
## 5.2.0-alpha.0 (April 29, 2019)
Storybook Docs technical preview:
- Docs addon
- MDX story format
- Module story format
- Load API
- [Guide](https://docs.google.com/document/d/1un6YX7xDKEKl5-MVb-egnOYN8dynb5Hf7mq0hipk8JE/edit?usp=sharing)
## 5.0.11 (April 28, 2019)
### Bug Fixes

View File

@ -1,5 +1,7 @@
# Migration
- [From version 5.1.x to 5.2.x](#from-version-51x-to-52x)
- [Docs mode docgen](#docs-mode-docgen)
- [From version 5.0.x to 5.1.x](#from-version-50x-to-51x)
- [React native server](#react-native-server)
- [Angular 7](#angular-7)
@ -56,6 +58,15 @@
- [Packages renaming](#packages-renaming)
- [Deprecated embedded addons](#deprecated-embedded-addons)
## From version 5.1.x to 5.2.x
### Docs mode docgen
This isn't a breaking change per se, because `addon-docs` is a new feature. However it's intended to replace `addon-info`, so if you're migrating from `addon-info` there are a few things you should know:
1. Support for only one prop table
2. Prop table docgen info should be stored on the component and not in the global variable `STORYBOOK_REACT_CLASSES` as before.
## From version 5.0.x to 5.1.x
### React native server

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-a11y",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "a11y addon for storybook",
"keywords": [
"a11y",
@ -26,12 +26,12 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23",
"@storybook/client-logger": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/theming": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"@storybook/client-logger": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"axe-core": "^3.2.2",
"common-tags": "^1.8.0",
"core-js": "^3.0.1",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-actions",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Action Logger addon for storybook",
"keywords": [
"storybook"
@ -21,12 +21,12 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23",
"@storybook/client-api": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/theming": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"@storybook/client-api": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"fast-deep-equal": "^2.0.1",
"global": "^4.3.2",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-backgrounds",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "A storybook addon to show different backgrounds for your preview",
"keywords": [
"addon",
@ -25,12 +25,12 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23",
"@storybook/client-logger": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/theming": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"@storybook/client-logger": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"memoizerific": "^1.11.3",
"react": "^16.8.3",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-centered",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook decorator to center components",
"keywords": [
"addon",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-contexts",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook Addon Contexts",
"keywords": [
"storybook",
@ -28,10 +28,10 @@
"dev:check-types": "tsc --noEmit"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"core-js": "^3.0.1"
},
"peerDependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-cssresources",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "A storybook addon to switch between css resources at runtime for your story",
"keywords": [
"addon",
@ -25,10 +25,10 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"global": "^4.3.2",
"react": "^16.8.3"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-design-assets",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Design asset preview for storybook",
"keywords": [
"addon",
@ -11,13 +11,13 @@
"files",
"viewer"
],
"homepage": "https://github.com/storybooks/storybook#readme",
"homepage": "https://github.com/storybookjs/storybook#readme",
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
"url": "https://github.com/storybookjs/storybook/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/storybooks/storybook.git",
"url": "git+https://github.com/storybookjs/storybook.git",
"directory": "addons/design-assets"
},
"license": "MIT",
@ -27,14 +27,14 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23",
"@storybook/client-logger": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/theming": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"@storybook/client-logger": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"common-tags": "^1.8.0",
"core-js": "^2.6.5",
"core-js": "^3.0.1",
"global": "^4.3.2",
"react": "^16.8.3",
"use-image": "^1.0.3"

View File

@ -1,3 +1,88 @@
# Storybook Docs
Living documentation for your components.
- [Sneak peak article](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a)
- [Technical preview guide](https://docs.google.com/document/d/1un6YX7xDKEKl5-MVb-egnOYN8dynb5Hf7mq0hipk8JE/edit?usp=sharing)
## View layer support
Docs supports all view layers that Storybook supports except for React Native (currently). There are some view-layer specific
features as well. This chart captures the current state of support
| | React | Vue | Angular | Polymer | Mithril | HTML | Marko | Svelte | Riot | Ember | Preact |
| -------------- | :---: | :-: | :-----: | :-----: | :-----: | :--: | :---: | :----: | :--: | :---: | :----: |
| MDX stories | + | + | + | + | + | + | + | + | + | + | + |
| Module stories | + | + | + | + | + | + | + | + | + | + | + |
| Legacy stories | + | + | + | + | + | + | + | + | + | + | + |
| Source \* | + | + | + | + | + | + | + | + | + | + | + |
| Notes / Info | + | + | + | + | + | + | + | + | + | + | + |
| Props table | + | # | # | | | | | | | | |
| Docgen | + | # | # | | | | | | | | |
| Inline stories | + | # | | | | | | | | | |
**Notes:**
- `#` denotes planned/WIP support
- \* Source supports legacy `JS storiesOf` and `MDX` stories. `Typescript` and new `module format` support is WIP
## Installation
First add the package. Make sure that the versions for your `@storybook/*` packages match:
```sh
yarn add -D @storybook/addon-docs
```
The add the following line to your `.storybook/presets.js` file:
```js
module.exports = ['@storybook/addon-docs/react/preset'];
```
Finally, import your stories and MDX files in `.storybook/config.js`:
```js
import { load } from '@storybook/react';
// standard configuration here
// ...
// wherever your story files are located
load(require.context('../src', true, /\.stories\.js$/), module);
load(require.context('../src', true, /\.stories\.mdx$/), module);
```
## Manual configuration
Docs uses Storybook presets as a configuration shortcut. To configure "the long way", first register the addon in `.storybook/addons.js`:
```js
import '@storybook/addon-docs/register';
```
Then configure Storybook's webpack loader to understand MDX files in `.storybook/webpack.config.js`:
```js
const createCompiler = require('@storybook/addon-docs/mdx-compiler-plugin');
module.exports = async ({ config }) => {
config.module.rules.push({
test: /\.mdx$/,
use: [
{
loader: 'babel-loader',
// may or may not need this line depending on your app's setup
plugins: ['@babel/plugin-transform-react-jsx'],
},
{
loader: '@mdx-js/loader',
options: {
compilers: [createCompiler({})],
},
},
],
});
return config;
};
```

View File

@ -0,0 +1,612 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin supports "smart" current story 1`] = `
"/* @jsx mdx */
import { DocsContainer } from '@storybook/addon-docs/blocks';
import { Story } from '@storybook/addon-docs/blocks';
const makeShortcode = name =>
function MDXDefaultShortcode(props) {
console.warn(
'Component ' +
name +
' was not imported, exported, or provided by MDXProvider as global scope'
);
return <div {...props} />;
};
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<h1>{\`Current story\`}</h1>
<Story id=\\".\\" mdxType=\\"Story\\" />
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
const mdxKind = componentMeta.title || componentMeta.displayName;
const WrappedMDXContent = ({ context }) => (
<DocsContainer context={{ ...context, mdxKind }} content={MDXContent} />
);
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = WrappedMDXContent;
export default componentMeta;
"
`;
exports[`docs-mdx-compiler-plugin supports decorators 1`] = `
"/* @jsx mdx */
import { DocsContainer } from '@storybook/addon-docs/blocks';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs/blocks';
const makeShortcode = name =>
function MDXDefaultShortcode(props) {
console.warn(
'Component ' +
name +
' was not imported, exported, or provided by MDXProvider as global scope'
);
return <div {...props} />;
};
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta
title=\\"Button\\"
decorators={[
storyFn => (
<div
style={{
backgroundColor: 'yellow',
}}
>
{storyFn()}
</div>
),
]}
mdxType=\\"Meta\\"
/>
<h1>{\`Decorated story\`}</h1>
<Story name=\\"one\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">One</Button>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const one = () => <Button>One</Button>;
one.story = {};
one.story.parameters = { mdxSource: \`<Button>One</Button>\` };
const componentMeta = {
title: 'Button',
decorators: [
storyFn => (
<div
style={{
backgroundColor: 'yellow',
}}
>
{storyFn()}
</div>
),
],
includeStories: ['one'],
};
const mdxKind = componentMeta.title || componentMeta.displayName;
const WrappedMDXContent = ({ context }) => (
<DocsContainer context={{ ...context, mdxKind }} content={MDXContent} />
);
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = WrappedMDXContent;
export default componentMeta;
"
`;
exports[`docs-mdx-compiler-plugin supports non-story exports 1`] = `
"/* @jsx mdx */
import { DocsContainer } from '@storybook/addon-docs/blocks';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs/blocks';
export const two = 2;
const makeShortcode = name =>
function MDXDefaultShortcode(props) {
console.warn(
'Component ' +
name +
' was not imported, exported, or provided by MDXProvider as global scope'
);
return <div {...props} />;
};
const layoutProps = {
two,
};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Button\\" mdxType=\\"Meta\\" />
<h1>{\`Story definition\`}</h1>
<Story name=\\"one\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">One</Button>
</Story>
<Story name=\\"hello story\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Hello button</Button>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const one = () => <Button>One</Button>;
one.story = {};
one.story.parameters = { mdxSource: \`<Button>One</Button>\` };
export const helloStory = () => <Button>Hello button</Button>;
helloStory.story = {};
helloStory.story.name = 'hello story';
helloStory.story.parameters = { mdxSource: \`<Button>Hello button</Button>\` };
const componentMeta = { title: 'Button', includeStories: ['one', 'helloStory'] };
const mdxKind = componentMeta.title || componentMeta.displayName;
const WrappedMDXContent = ({ context }) => (
<DocsContainer context={{ ...context, mdxKind }} content={MDXContent} />
);
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = WrappedMDXContent;
export default componentMeta;
"
`;
exports[`docs-mdx-compiler-plugin supports object-style story definitions 1`] = `
"/* @jsx mdx */
import { DocsContainer } from '@storybook/addon-docs/blocks';
import { Story, Meta } from '@storybook/addon-docs/blocks';
import { Welcome, Button } from '@storybook/angular/demo';
import { linkTo } from '@storybook/addon-links';
const makeShortcode = name =>
function MDXDefaultShortcode(props) {
console.warn(
'Component ' +
name +
' was not imported, exported, or provided by MDXProvider as global scope'
);
return <div {...props} />;
};
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"MDX|Welcome\\" mdxType=\\"Meta\\" />
<h1>{\`Story object\`}</h1>
<Story name=\\"to storybook\\" height=\\"300px\\" mdxType=\\"Story\\">
{{
template: \`<storybook-welcome-component (showApp)=\\"showApp()\\"></storybook-welcome-component>\`,
props: {
showApp: linkTo('Button'),
},
moduleMetadata: {
declarations: [Welcome],
},
}}
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const toStorybook = () => ({
template: \`<storybook-welcome-component (showApp)=\\"showApp()\\"></storybook-welcome-component>\`,
props: {
showApp: linkTo('Button'),
},
moduleMetadata: {
declarations: [Welcome],
},
});
toStorybook.story = {};
toStorybook.story.name = 'to storybook';
toStorybook.story.parameters = {
mdxSource: \`{
template: \\\\\`<storybook-welcome-component (showApp)=\\"showApp()\\"></storybook-welcome-component>\\\\\`,
props: {
showApp: linkTo('Button')
},
moduleMetadata: {
declarations: [Welcome]
}
}\`,
};
const componentMeta = { title: 'MDX|Welcome', includeStories: ['toStorybook'] };
const mdxKind = componentMeta.title || componentMeta.displayName;
const WrappedMDXContent = ({ context }) => (
<DocsContainer context={{ ...context, mdxKind }} content={MDXContent} />
);
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = WrappedMDXContent;
export default componentMeta;
"
`;
exports[`docs-mdx-compiler-plugin supports parameters 1`] = `
"/* @jsx mdx */
import { DocsContainer } from '@storybook/addon-docs/blocks';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs/blocks';
const makeShortcode = name =>
function MDXDefaultShortcode(props) {
console.warn(
'Component ' +
name +
' was not imported, exported, or provided by MDXProvider as global scope'
);
return <div {...props} />;
};
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta
title=\\"Button\\"
parameters={{
component: Button,
notes: 'component notes',
}}
mdxType=\\"Meta\\"
/>
<Story name=\\"component notes\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Component notes</Button>
</Story>
<Story
name=\\"story notes\\"
parameters={{
notes: 'story notes',
}}
mdxType=\\"Story\\"
>
<Button mdxType=\\"Button\\">Story notes</Button>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const componentNotes = () => <Button>Component notes</Button>;
componentNotes.story = {};
componentNotes.story.name = 'component notes';
componentNotes.story.parameters = { mdxSource: \`<Button>Component notes</Button>\` };
export const storyNotes = () => <Button>Story notes</Button>;
storyNotes.story = {};
storyNotes.story.name = 'story notes';
storyNotes.story.parameters = {
mdxSource: \`<Button>Story notes</Button>\`,
...{
notes: 'story notes',
},
};
const componentMeta = {
title: 'Button',
parameters: {
component: Button,
notes: 'component notes',
},
includeStories: ['componentNotes', 'storyNotes'],
};
const mdxKind = componentMeta.title || componentMeta.displayName;
const WrappedMDXContent = ({ context }) => (
<DocsContainer context={{ ...context, mdxKind }} content={MDXContent} />
);
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = WrappedMDXContent;
export default componentMeta;
"
`;
exports[`docs-mdx-compiler-plugin supports previews 1`] = `
"/* @jsx mdx */
import { DocsContainer } from '@storybook/addon-docs/blocks';
import { Button } from '@storybook/react/demo';
import { Preview, Story, Meta } from '@storybook/addon-docs/blocks';
const makeShortcode = name =>
function MDXDefaultShortcode(props) {
console.warn(
'Component ' +
name +
' was not imported, exported, or provided by MDXProvider as global scope'
);
return <div {...props} />;
};
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta
title=\\"Button\\"
parameters={{
component: Button,
notes: 'component notes',
}}
mdxType=\\"Meta\\"
/>
<h1>{\`Preview\`}</h1>
<p>{\`Previews can contain normal components, stories, and story references\`}</p>
<Preview mdxType=\\"Preview\\">
<Button mdxType=\\"Button\\">Just a button</Button>
<Story name=\\"hello button\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Hello button</Button>
</Story>
<Story name=\\"two\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Two</Button>
</Story>
<Story id=\\"welcome--welcome\\" mdxType=\\"Story\\" />
</Preview>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const helloButton = () => <Button>Hello button</Button>;
helloButton.story = {};
helloButton.story.name = 'hello button';
helloButton.story.parameters = { mdxSource: \`<Button>Hello button</Button>\` };
export const two = () => <Button>Two</Button>;
two.story = {};
two.story.parameters = { mdxSource: \`<Button>Two</Button>\` };
const componentMeta = {
title: 'Button',
parameters: {
component: Button,
notes: 'component notes',
},
includeStories: ['helloButton', 'two'],
};
const mdxKind = componentMeta.title || componentMeta.displayName;
const WrappedMDXContent = ({ context }) => (
<DocsContainer context={{ ...context, mdxKind }} content={MDXContent} />
);
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = WrappedMDXContent;
export default componentMeta;
"
`;
exports[`docs-mdx-compiler-plugin supports story definitions 1`] = `
"/* @jsx mdx */
import { DocsContainer } from '@storybook/addon-docs/blocks';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs/blocks';
const makeShortcode = name =>
function MDXDefaultShortcode(props) {
console.warn(
'Component ' +
name +
' was not imported, exported, or provided by MDXProvider as global scope'
);
return <div {...props} />;
};
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Button\\" mdxType=\\"Meta\\" />
<h1>{\`Story definition\`}</h1>
<Story name=\\"one\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">One</Button>
</Story>
<Story name=\\"hello story\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Hello button</Button>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const one = () => <Button>One</Button>;
one.story = {};
one.story.parameters = { mdxSource: \`<Button>One</Button>\` };
export const helloStory = () => <Button>Hello button</Button>;
helloStory.story = {};
helloStory.story.name = 'hello story';
helloStory.story.parameters = { mdxSource: \`<Button>Hello button</Button>\` };
const componentMeta = { title: 'Button', includeStories: ['one', 'helloStory'] };
const mdxKind = componentMeta.title || componentMeta.displayName;
const WrappedMDXContent = ({ context }) => (
<DocsContainer context={{ ...context, mdxKind }} content={MDXContent} />
);
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = WrappedMDXContent;
export default componentMeta;
"
`;
exports[`docs-mdx-compiler-plugin supports story references 1`] = `
"/* @jsx mdx */
import { DocsContainer } from '@storybook/addon-docs/blocks';
import { Story } from '@storybook/addon-docs/blocks';
const makeShortcode = name =>
function MDXDefaultShortcode(props) {
console.warn(
'Component ' +
name +
' was not imported, exported, or provided by MDXProvider as global scope'
);
return <div {...props} />;
};
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<h1>{\`Story reference\`}</h1>
<Story id=\\"welcome--welcome\\" mdxType=\\"Story\\" />
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
const mdxKind = componentMeta.title || componentMeta.displayName;
const WrappedMDXContent = ({ context }) => (
<DocsContainer context={{ ...context, mdxKind }} content={MDXContent} />
);
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = WrappedMDXContent;
export default componentMeta;
"
`;
exports[`docs-mdx-compiler-plugin supports text-only story definitions 1`] = `
"/* @jsx mdx */
import { DocsContainer } from '@storybook/addon-docs/blocks';
import { Story, Meta } from '@storybook/addon-docs/blocks';
const makeShortcode = name =>
function MDXDefaultShortcode(props) {
console.warn(
'Component ' +
name +
' was not imported, exported, or provided by MDXProvider as global scope'
);
return <div {...props} />;
};
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Text\\" mdxType=\\"Meta\\" />
<h1>{\`Story definition\`}</h1>
<Story name=\\"text\\" mdxType=\\"Story\\">
Plain text
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const text = () => 'Plain text';
text.story = {};
text.story.parameters = { mdxSource: \`'Plain text'\` };
const componentMeta = { title: 'Text', includeStories: ['text'] };
const mdxKind = componentMeta.title || componentMeta.displayName;
const WrappedMDXContent = ({ context }) => (
<DocsContainer context={{ ...context, mdxKind }} content={MDXContent} />
);
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = WrappedMDXContent;
export default componentMeta;
"
`;
exports[`docs-mdx-compiler-plugin supports vanilla mdx 1`] = `
"/* @jsx mdx */
import { DocsContainer } from '@storybook/addon-docs/blocks';
import { Button } from '@storybook/react/demo';
const makeShortcode = name =>
function MDXDefaultShortcode(props) {
console.warn(
'Component ' +
name +
' was not imported, exported, or provided by MDXProvider as global scope'
);
return <div {...props} />;
};
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<h1>{\`Hello MDX\`}</h1>
<p>{\`This is some random content.\`}</p>
<Button mdxType=\\"Button\\">Hello button</Button>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
const mdxKind = componentMeta.title || componentMeta.displayName;
const WrappedMDXContent = ({ context }) => (
<DocsContainer context={{ ...context, mdxKind }} content={MDXContent} />
);
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = WrappedMDXContent;
export default componentMeta;
"
`;

1
addons/docs/blocks.js Normal file
View File

@ -0,0 +1 @@
module.exports = require('./dist/blocks');

View File

@ -0,0 +1,2 @@
// FIXME: move this to typescript and src/react folder
module.exports = require('../dist/lib/getPropDefs');

View File

@ -0,0 +1,66 @@
const createCompiler = require('../mdx-compiler-plugin');
function createBabelOptions({ babelOptions, configureJSX }) {
if (!configureJSX) {
return babelOptions;
}
return {
...babelOptions,
// for frameworks that are not working with react, we need to configure
// the jsx to transpile mdx, for now there will be a flag for that
// for more complex solutions we can find alone that we need to add '@babel/plugin-transform-react-jsx'
plugins: [...babelOptions.plugins, '@babel/plugin-transform-react-jsx'],
};
}
function webpack(webpackConfig = {}, options = {}) {
const { module = {} } = webpackConfig;
// it will reuse babel options that are already in use in storybook
// also, these babel options are chained with other presets.
const { babelOptions, configureJSX } = options;
return {
...webpackConfig,
module: {
...module,
rules: [
...(module.rules || []),
{
test: /\.(stories|story).mdx$/,
use: [
{
loader: 'babel-loader',
options: createBabelOptions({ babelOptions, configureJSX }),
},
{
loader: '@mdx-js/loader',
options: {
compilers: [createCompiler(options)],
},
},
],
},
{
test: /\.mdx$/,
exclude: /\.(stories|story).mdx$/,
use: [
{
loader: 'babel-loader',
options: createBabelOptions({ babelOptions, configureJSX }),
},
{
loader: '@mdx-js/loader',
},
],
},
],
},
};
}
function addons(entry = []) {
return [...entry, require.resolve('../register')];
}
module.exports = { webpack, addons };

View File

@ -0,0 +1,13 @@
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs/blocks';
<Meta
title="Button"
decorators={[storyFn => <div style={{ backgroundColor: 'yellow' }}>{storyFn()}</div>]}
/>
# Decorated story
<Story name="one">
<Button>One</Button>
</Story>

View File

@ -0,0 +1,16 @@
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs/blocks';
<Meta title="Button" />
# Story definition
<Story name="one">
<Button>One</Button>
</Story>
export const two = 2;
<Story name="hello story">
<Button>Hello button</Button>
</Story>

View File

@ -0,0 +1,12 @@
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs/blocks';
<Meta title="Button" parameters={{ component: Button, notes: 'component notes' }} />
<Story name="component notes">
<Button>Component notes</Button>
</Story>
<Story name="story notes" parameters={{ notes: 'story notes' }}>
<Button>Story notes</Button>
</Story>

View File

@ -0,0 +1,19 @@
import { Button } from '@storybook/react/demo';
import { Preview, Story, Meta } from '@storybook/addon-docs/blocks';
<Meta title="Button" parameters={{ component: Button, notes: 'component notes' }} />
# Preview
Previews can contain normal components, stories, and story references
<Preview>
<Button>Just a button</Button>
<Story name="hello button">
<Button>Hello button</Button>
</Story>
<Story name="two">
<Button>Two</Button>
</Story>
<Story id="welcome--welcome" />
</Preview>

View File

@ -0,0 +1,5 @@
import { Story } from '@storybook/addon-docs/blocks';
# Current story
<Story id="." />

View File

@ -0,0 +1,7 @@
import { Story, Meta } from '@storybook/addon-docs/blocks';
<Meta title="Text" />
# Story definition
<Story name="text">Plain text</Story>

View File

@ -0,0 +1,14 @@
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs/blocks';
<Meta title="Button" />
# Story definition
<Story name="one">
<Button>One</Button>
</Story>
<Story name="hello story">
<Button>Hello button</Button>
</Story>

View File

@ -0,0 +1,10 @@
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs/blocks';
<Meta title="Button" />
# Bad story
<Story>
<Button>One</Button>
</Story>

View File

@ -0,0 +1,19 @@
import { Story, Meta } from '@storybook/addon-docs/blocks';
import { Welcome, Button } from '@storybook/angular/demo';
import { linkTo } from '@storybook/addon-links';
<Meta title="MDX|Welcome" />
# Story object
<Story name="to storybook" height="300px">
{{
template: `<storybook-welcome-component (showApp)="showApp()"></storybook-welcome-component>`,
props: {
showApp: linkTo('Button'),
},
moduleMetadata: {
declarations: [Welcome],
},
}}
</Story>

View File

@ -0,0 +1,5 @@
import { Story } from '@storybook/addon-docs/blocks';
# Story reference
<Story id="welcome--welcome" />

View File

@ -0,0 +1,7 @@
import { Button } from '@storybook/react/demo';
# Hello MDX
This is some random content.
<Button>Hello button</Button>

View File

@ -0,0 +1,222 @@
const mdxToJsx = require('@mdx-js/mdx/mdx-hast-to-jsx');
const parser = require('@babel/parser');
const generate = require('@babel/generator').default;
const camelCase = require('lodash/camelCase');
// Generate the MDX as is, but append named exports for every
// story in the contents
const STORY_REGEX = /^<Story[\s>]/;
const PREVIEW_REGEX = /^<Preview[\s>]/;
const META_REGEX = /^<Meta[\s>]/;
const RESERVED = /^(?:do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|await|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$/;
function getAttr(elt, what) {
const attr = elt.attributes.find(n => n.name.name === what);
return attr && attr.value;
}
function getStoryFn(name, counter) {
if (name) {
const storyFn = camelCase(name.replace(/[^a-z0-9-]/g, '-'));
if (storyFn.length > 1 && !RESERVED.exec(storyFn)) {
return storyFn;
}
}
return `story${counter}`;
}
function genStoryExport(ast, counter) {
let storyName = getAttr(ast.openingElement, 'name');
let storyId = getAttr(ast.openingElement, 'id');
storyName = storyName && storyName.value;
storyId = storyId && storyId.value;
if (!storyId && !storyName) {
throw new Error('Expected a story name or ID attribute');
}
// We don't generate exports for story references or the smart "current story"
if (storyId || !storyName) {
return null;
}
// console.log('genStoryExport', JSON.stringify(ast, null, 2));
const statements = [];
const storyKey = getStoryFn(storyName, counter);
let body = ast.children.find(n => n.type !== 'JSXText');
let storyCode = null;
if (!body) {
// plain text node
const { code } = generate(ast.children[0], {});
storyCode = `'${code}'`;
} else {
if (body.type === 'JSXExpressionContainer') {
// FIXME: handle fragments
body = body.expression;
}
const { code } = generate(body, {});
storyCode = code;
}
statements.push(
`export const ${storyKey} = () => (
${storyCode}
);`
);
statements.push(`${storyKey}.story = {};`);
if (storyName !== storyKey) {
statements.push(`${storyKey}.story.name = '${storyName}';`);
}
let parameters = getAttr(ast.openingElement, 'parameters');
parameters = parameters && parameters.expression;
const source = `\`${storyCode.replace(/`/g, '\\`')}\``;
if (parameters) {
const { code: params } = generate(parameters, {});
// FIXME: hack in the story's source as a parameter
statements.push(`${storyKey}.story.parameters = { mdxSource: ${source}, ...${params} };`);
} else {
statements.push(`${storyKey}.story.parameters = { mdxSource: ${source} };`);
}
// console.log(statements);
return {
[storyKey]: statements.join('\n'),
};
}
function genPreviewExports(ast, counter) {
// console.log('genPreviewExports', JSON.stringify(ast, null, 2));
let localCounter = counter;
const previewExports = {};
for (let i = 0; i < ast.children.length; i += 1) {
const child = ast.children[i];
if (child.type === 'JSXElement' && child.openingElement.name.name === 'Story') {
const storyExport = genStoryExport(child, localCounter);
if (storyExport) {
Object.assign(previewExports, storyExport);
localCounter += 1;
}
}
}
return previewExports;
}
function genMeta(ast) {
let title = getAttr(ast.openingElement, 'title');
let parameters = getAttr(ast.openingElement, 'parameters');
let decorators = getAttr(ast.openingElement, 'decorators');
title = title && `'${title.value}'`;
if (parameters && parameters.expression) {
const { code: params } = generate(parameters.expression, {});
parameters = params;
}
if (decorators && decorators.expression) {
const { code: decos } = generate(decorators.expression, {});
decorators = decos;
}
return {
title,
parameters,
decorators,
};
}
function getExports(node, counter) {
const { value, type } = node;
if (type === 'jsx') {
if (STORY_REGEX.exec(value)) {
// Single story
const ast = parser.parseExpression(value, { plugins: ['jsx'] });
const storyExport = genStoryExport(ast, counter);
return storyExport && { stories: storyExport };
}
if (PREVIEW_REGEX.exec(value)) {
// Preview, possibly containing multiple stories
const ast = parser.parseExpression(value, { plugins: ['jsx'] });
return { stories: genPreviewExports(ast, counter) };
}
if (META_REGEX.exec(value)) {
// Preview, possibly containing multiple stories
const ast = parser.parseExpression(value, { plugins: ['jsx'] });
return { meta: genMeta(ast) };
}
}
return null;
}
// insert `mdxKind` into the context so that we can know what "kind" we're rendering into
// when we render <Story name="xxx">...</Story>, since this MDX can be attached to any `selectedKind`!
const wrapperJs = `
const mdxKind = componentMeta.title || componentMeta.displayName;
const WrappedMDXContent = ({ context }) => <DocsContainer context={{...context, mdxKind}} content={MDXContent} />;
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = WrappedMDXContent;
`.trim();
function stringifyMeta(meta) {
let result = '{ ';
Object.entries(meta).forEach(([key, val]) => {
if (val) {
result += `${key}: ${val}, `;
}
});
result += ' }';
return result;
}
function extractExports(node, options) {
// we're overriding default export
const defaultJsx = mdxToJsx.toJSX(node, {}, { ...options, skipExport: true });
const storyExports = [];
const includeStories = [];
let metaExport = null;
let counter = 0;
node.children.forEach(n => {
const exports = getExports(n, counter);
if (exports) {
const { stories, meta } = exports;
if (stories) {
Object.entries(stories).forEach(([key, story]) => {
includeStories.push(key);
storyExports.push(story);
counter += 1;
});
}
if (meta) {
if (metaExport) {
throw new Error('Meta can only be declared once');
}
metaExport = meta;
}
}
});
if (!metaExport) {
metaExport = {};
}
metaExport.includeStories = JSON.stringify(includeStories);
const fullJsx = [
'import { DocsContainer } from "@storybook/addon-docs/blocks";',
defaultJsx,
...storyExports,
`const componentMeta = ${stringifyMeta(metaExport)};`,
wrapperJs,
'export default componentMeta;',
].join('\n\n');
return fullJsx;
}
function createCompiler(mdxOptions) {
return function compiler(options = {}) {
this.Compiler = tree => extractExports(tree, options, mdxOptions);
};
}
module.exports = createCompiler;

View File

@ -0,0 +1,75 @@
const path = require('path');
const fs = require('fs-extra');
const mdx = require('@mdx-js/mdx');
const prettier = require('prettier');
const plugin = require('./mdx-compiler-plugin');
function format(code) {
return prettier.format(code, {
parser: 'babel',
printWidth: 100,
tabWidth: 2,
bracketSpacing: true,
trailingComma: 'es5',
singleQuote: true,
});
}
async function generate(filePath) {
const content = await fs.readFile(filePath, 'utf8');
const result = mdx.sync(content, {
filepath: filePath,
compilers: [plugin({})],
});
return format(result);
}
describe('docs-mdx-compiler-plugin', () => {
it('supports vanilla mdx', async () => {
const code = await generate(path.resolve(__dirname, './fixtures/vanilla.mdx'));
expect(code).toMatchSnapshot();
});
it('supports story definitions', async () => {
const code = await generate(path.resolve(__dirname, './fixtures/story-definitions.mdx'));
expect(code).toMatchSnapshot();
});
it('supports text-only story definitions', async () => {
const code = await generate(path.resolve(__dirname, './fixtures/story-def-text-only.mdx'));
expect(code).toMatchSnapshot();
});
it('supports object-style story definitions', async () => {
const code = await generate(path.resolve(__dirname, './fixtures/story-object.mdx'));
expect(code).toMatchSnapshot();
});
it('supports story references', async () => {
const code = await generate(path.resolve(__dirname, './fixtures/story-references.mdx'));
expect(code).toMatchSnapshot();
});
it('supports "smart" current story', async () => {
const code = await generate(path.resolve(__dirname, './fixtures/story-current.mdx'));
expect(code).toMatchSnapshot();
});
it('supports previews', async () => {
const code = await generate(path.resolve(__dirname, './fixtures/previews.mdx'));
expect(code).toMatchSnapshot();
});
it('supports decorators', async () => {
const code = await generate(path.resolve(__dirname, './fixtures/decorators.mdx'));
expect(code).toMatchSnapshot();
});
it('supports parameters', async () => {
const code = await generate(path.resolve(__dirname, './fixtures/parameters.mdx'));
expect(code).toMatchSnapshot();
});
it('supports non-story exports', async () => {
const code = await generate(path.resolve(__dirname, './fixtures/non-story-exports.mdx'));
expect(code).toMatchSnapshot();
});
it('errors on missing story props', async () => {
await expect(
generate(path.resolve(__dirname, './fixtures/story-missing-props.mdx'))
).rejects.toThrow('Expected a story name or ID attribute');
});
});

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-docs",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Superior documentation for your components",
"keywords": [
"addon",
@ -23,10 +23,23 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23"
"@babel/generator": "^7.4.0",
"@babel/parser": "^7.4.2",
"@mdx-js/loader": "^1.0.0",
"@mdx-js/mdx": "^1.0.0",
"@mdx-js/react": "^1.0.16",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/router": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"global": "^4.3.2",
"lodash": "^4.17.11",
"prop-types": "^15.7.2"
},
"devDependencies": {
"@types/prop-types": "^15.5.9",
"@types/util-deprecate": "^1.0.0",
"@types/webpack-env": "^1.13.7"
},

View File

@ -0,0 +1 @@
module.exports = require('../common/index');

View File

@ -0,0 +1 @@
module.exports = require('../common/preset');

View File

@ -0,0 +1,68 @@
/* eslint-disable no-underscore-dangle */
import React from 'react';
import { Description, DescriptionProps as PureDescriptionProps } from '@storybook/components';
import { DocsContext, DocsContextProps } from './DocsContext';
import { Component, CURRENT_SELECTION } from './shared';
export enum DescriptionType {
INFO = 'info',
NOTES = 'notes',
DOCGEN = 'docgen',
AUTO = 'auto',
}
type Notes = string | any;
type Info = string | any;
interface DescriptionProps {
of?: '.' | Component;
type?: DescriptionType;
markdown?: string;
}
const getNotes = (notes?: Notes) =>
notes && (typeof notes === 'string' ? notes : notes.markdown || notes.text);
const getInfo = (info?: Info) => info && (typeof info === 'string' ? info : info.text);
const getDocgen = (component?: Component) =>
(component && component.__docgenInfo && component.__docgenInfo.description) || '';
export const getDescriptionProps = (
{ of, type, markdown }: DescriptionProps,
{ parameters }: DocsContextProps
): PureDescriptionProps => {
if (markdown) {
return { markdown };
}
const { component, notes, info } = parameters;
const target = of === CURRENT_SELECTION ? component : of;
switch (type) {
case DescriptionType.INFO:
return { markdown: getInfo(info) };
case DescriptionType.NOTES:
return { markdown: getNotes(notes) };
case DescriptionType.DOCGEN:
return { markdown: getDocgen(target) };
case DescriptionType.AUTO:
default:
return {
markdown: `
${getNotes(notes) || getInfo(info) || ''}
${getDocgen(target)}
`.trim(),
};
}
};
const DescriptionContainer: React.FunctionComponent<DescriptionProps> = props => (
<DocsContext.Consumer>
{context => {
const { markdown } = getDescriptionProps(props, context);
return markdown && <Description markdown={markdown} />;
}}
</DocsContext.Consumer>
);
export { DescriptionContainer as Description };

View File

@ -0,0 +1,52 @@
/* eslint-disable react/destructuring-assignment */
import React from 'react';
import { MDXProvider } from '@mdx-js/react';
import { Global, createGlobal, ThemeProvider, ensure as ensureTheme } from '@storybook/theming';
import { DocumentFormatting, DocsWrapper, DocsContent } from '@storybook/components';
import { DocsContextProps, DocsContext } from './DocsContext';
interface DocsContainerProps {
context: DocsContextProps;
content: React.ElementType<any>;
}
const defaultComponents = {
// p: ({ children }) => <b>{children}</b>,
wrapper: DocumentFormatting,
};
const globalWithOverflow = (args: any) => {
const global = createGlobal(args);
const { body, ...rest } = global;
const { overflow, ...bodyRest } = body;
return {
body: bodyRest,
...rest,
};
};
export const DocsContainer: React.FunctionComponent<DocsContainerProps> = ({
context,
content: MDXContent,
}) => {
const parameters = (context && context.parameters) || {};
const options = parameters.options || {};
const theme = ensureTheme(options.theme);
const { components: userComponents = null } = options.docs || {};
const components = { ...defaultComponents, ...userComponents };
return (
<DocsContext.Provider value={context}>
<ThemeProvider theme={theme}>
<Global styles={globalWithOverflow} />
<MDXProvider components={components}>
<DocsWrapper>
<DocsContent>
<MDXContent components={components} />
</DocsContent>
</DocsWrapper>
</MDXProvider>
</ThemeProvider>
</DocsContext.Provider>
);
};

View File

@ -0,0 +1,23 @@
import React from 'react';
export interface DocsContextProps {
id?: string;
selectedKind?: string;
selectedStory?: string;
/**
* mdxKind is a statically-generated "kind" that corresponds to the
* component that's being documented in the MDX file, It's combined
* with the MDX story name `<Story name='story name'>...</Story>` to
* generate a storyId. In the case that the user is viewing a non-MDX
* story, the value of `mdxKind` will be the currently-selected kind.
* (I can't remember the corner case in which using the currentl-selected
* kind breaks down in MDX-defined stories, but there is one!)
*/
mdxKind?: string;
parameters?: any;
storyStore?: any;
forceRender?: () => void;
}
export const DocsContext: React.Context<DocsContextProps> = React.createContext({});

View File

@ -0,0 +1,140 @@
import React from 'react';
import { parseKind } from '@storybook/router';
import { styled } from '@storybook/theming';
import { DocsPage as PureDocsPage, DocsPageProps } from '@storybook/components';
import { DocsContext, DocsContextProps } from './DocsContext';
import { DocsContainer } from './DocsContainer';
import { Description } from './Description';
import { Story } from './Story';
import { Preview } from './Preview';
import { Props } from './Props';
enum DocsStoriesType {
ALL = 'all',
PRIMARY = 'primary',
REST = 'rest',
}
interface DocsStoriesProps {
type?: DocsStoriesType;
}
interface DocsStoryProps {
id: string;
name: string;
description?: string;
expanded?: boolean;
}
interface StoryData {
id: string;
kind: string;
name: string;
parameters?: any;
}
const getDocsStories = (type: DocsStoriesType, componentStories: StoryData[]): DocsStoryProps[] => {
let stories = componentStories;
if (type !== DocsStoriesType.ALL) {
const primary = stories.find(s => s.parameters && s.parameters.primary);
const [first, ...rest] = stories;
if (type === DocsStoriesType.PRIMARY) {
stories = [primary || first];
} else {
stories = primary ? stories.filter(s => !s.parameters || !s.parameters.primary) : rest;
}
}
return stories.map(({ id, name, parameters: { notes, info } }) => ({
id,
name,
description: notes || info || null,
}));
};
const StoriesHeading = styled.h2();
const StoryHeading = styled.h3();
const DocsStory: React.FunctionComponent<DocsStoryProps> = ({
id,
name,
description,
expanded = true,
}) => (
<>
{expanded && <StoryHeading>{name}</StoryHeading>}
{expanded && description && <Description markdown={description} />}
<Preview>
<Story id={id} />
</Preview>
</>
);
const DocsStories: React.FunctionComponent<DocsStoriesProps> = ({ type = DocsStoriesType.ALL }) => (
<DocsContext.Consumer>
{({ selectedKind, storyStore }) => {
const componentStories = (storyStore.raw() as StoryData[]).filter(
s => s.kind === selectedKind
);
const stories = getDocsStories(type, componentStories);
if (stories.length === 0) {
return null;
}
const expanded = type !== DocsStoriesType.PRIMARY;
return (
<>
{expanded && <StoriesHeading>Stories</StoriesHeading>}
{stories.map(s => (
<DocsStory key={s.id} expanded={expanded} {...s} />
))}
</>
);
}}
</DocsContext.Consumer>
);
const getDocsPageProps = (context: DocsContextProps): DocsPageProps => {
const { selectedKind, selectedStory, parameters } = context;
const {
hierarchyRootSeparator: rootSeparator,
hierarchySeparator: groupSeparator,
} = (parameters && parameters.options) || {
hierarchyRootSeparator: '|',
hierarchySeparator: '/',
};
const { groups } = parseKind(selectedKind, { rootSeparator, groupSeparator });
const title = (groups && groups[groups.length - 1]) || selectedKind;
return {
title,
subtitle: parameters && parameters.componentDescription,
};
};
const DocsPage: React.FunctionComponent = () => (
<DocsContext.Consumer>
{context => {
const docsPageProps = getDocsPageProps(context);
return (
<PureDocsPage {...docsPageProps}>
<Description of="." />
<DocsStories type={DocsStoriesType.PRIMARY} />
<Props of="." />
<DocsStories type={DocsStoriesType.REST} />
</PureDocsPage>
);
}}
</DocsContext.Consumer>
);
interface DocsPageWrapperProps {
context: DocsContextProps;
}
const DocsPageWrapper: React.FunctionComponent<DocsPageWrapperProps> = ({ context }) => (
/* eslint-disable react/destructuring-assignment */
<DocsContainer context={{ ...context, mdxKind: context.selectedKind }} content={DocsPage} />
);
export { DocsPageWrapper as DocsPage };

View File

@ -0,0 +1,16 @@
import React from 'react';
type Decorator = (...args: any) => any;
interface MetaProps {
title: string;
decorators?: [Decorator];
parameters?: any;
}
/**
* This component is used to declare component metadata in docs
* and gets transformed into a default export underneath the hood.
* It doesn't actually render anything.
*/
export const Meta: React.FunctionComponent<MetaProps> = props => null;

View File

@ -0,0 +1,48 @@
import React, { ReactNodeArray } from 'react';
import { Preview as PurePreview, PreviewProps as PurePreviewProps } from '@storybook/components';
import { toId } from '@storybook/router';
import { getSourceProps } from './Source';
import { DocsContext, DocsContextProps } from './DocsContext';
export enum SourceState {
OPEN = 'open',
CLOSED = 'closed',
NONE = 'none',
}
type PreviewProps = PurePreviewProps & {
withSource?: SourceState;
};
const getPreviewProps = (
{
withSource = SourceState.CLOSED,
children,
...props
}: PreviewProps & { children?: React.ReactNode },
{ mdxKind, storyStore }: DocsContextProps
): PurePreviewProps => {
if (withSource === SourceState.NONE && !children) {
return props;
}
const childArray: ReactNodeArray = Array.isArray(children) ? children : [children];
const stories = childArray.filter(
(c: React.ReactElement) => c.props && (c.props.id || c.props.name)
) as React.ReactElement[];
const targetIds = stories.map(s => s.props.id || toId(mdxKind, s.props.name));
const sourceProps = getSourceProps({ ids: targetIds }, { storyStore });
return {
...props, // pass through columns etc.
withSource: sourceProps,
isExpanded: withSource === SourceState.OPEN,
};
};
export const Preview: React.FunctionComponent<PreviewProps> = props => (
<DocsContext.Consumer>
{context => {
const previewProps = getPreviewProps(props, context);
return <PurePreview {...previewProps}>{props.children}</PurePreview>;
}}
</DocsContext.Consumer>
);

View File

@ -0,0 +1,57 @@
import React from 'react';
import { PropsTable, PropsTableError, PropsTableProps, PropDef } from '@storybook/components';
import { DocsContext, DocsContextProps } from './DocsContext';
import { Component, CURRENT_SELECTION } from './shared';
import { getPropDefs as autoPropDefs, PropDefGetter } from '../lib/getPropDefs';
interface PropsProps {
exclude?: string[];
of: '.' | Component;
}
const inferPropDefs = (framework: string): PropDefGetter | null => {
switch (framework) {
case 'react':
case 'vue':
return autoPropDefs;
default:
return null;
}
};
export const getPropsTableProps = (
{ exclude, of }: PropsProps,
{ parameters }: DocsContextProps
): PropsTableProps => {
const { component } = parameters;
try {
const target = of === CURRENT_SELECTION ? component : of;
if (!target) {
throw new Error(PropsTableError.NO_COMPONENT);
}
const { framework = null } = parameters || {};
const { getPropDefs = inferPropDefs(framework) } =
(parameters && parameters.options && parameters.options.docs) || {};
if (!getPropDefs) {
throw new Error(PropsTableError.PROPS_UNSUPPORTED);
}
const allRows = getPropDefs(target);
const rows = !exclude ? allRows : allRows.filter((row: PropDef) => !exclude.includes(row.name));
return { rows };
} catch (err) {
return { error: err.message };
}
};
const PropsContainer: React.FunctionComponent<PropsProps> = props => (
<DocsContext.Consumer>
{context => {
const propsTableProps = getPropsTableProps(props, context);
return <PropsTable {...propsTableProps} />;
}}
</DocsContext.Consumer>
);
export { PropsContainer as Props };

View File

@ -0,0 +1,97 @@
import React from 'react';
import { Source, SourceProps as PureSourceProps, SourceError } from '@storybook/components';
import { DocsContext, DocsContextProps } from './DocsContext';
import { CURRENT_SELECTION } from './shared';
interface CommonProps {
language?: string;
}
type SingleSourceProps = {
id: string;
} & CommonProps;
type MultiSourceProps = {
ids: string[];
} & CommonProps;
type CodeProps = {
code: string;
} & CommonProps;
type NoneProps = CommonProps;
type SourceProps = SingleSourceProps | MultiSourceProps | CodeProps | NoneProps;
interface Location {
line: number;
col: number;
}
interface StorySource {
source: string;
locationsMap: { [id: string]: { startBody: Location; endBody: Location } };
}
const extract = (targetId: string, { source, locationsMap }: StorySource) => {
const location = locationsMap[targetId];
// FIXME: bad locationsMap generated for module export functions whose titles are overridden
if (!location) return null;
const { startBody: start, endBody: end } = location;
const lines = source.split('\n');
if (start.line === end.line) {
return lines[start.line - 1].substring(start.col, end.col);
}
// NOTE: storysource locations are 1-based not 0-based!
const startLine = lines[start.line - 1];
const endLine = lines[end.line - 1];
return [
startLine.substring(start.col),
...lines.slice(start.line, end.line - 1),
endLine.substring(0, end.col),
].join('\n');
};
export const getSourceProps = (
props: SourceProps,
{ id: currentId, storyStore }: DocsContextProps
): PureSourceProps => {
const codeProps = props as CodeProps;
const singleProps = props as SingleSourceProps;
const multiProps = props as MultiSourceProps;
let source = codeProps.code; // prefer user-specified code
if (!source) {
const targetId = singleProps.id === CURRENT_SELECTION ? currentId : singleProps.id;
const targetIds = multiProps.ids || [targetId];
source = targetIds
.map(sourceId => {
const data = storyStore.fromId(sourceId);
if (data && data.parameters) {
const { mdxSource, storySource } = data.parameters;
return mdxSource || (storySource && extract(sourceId, storySource));
}
return '';
})
.join('\n\n');
}
return source
? { code: source, language: props.language || 'jsx' }
: { error: SourceError.SOURCE_UNAVAILABLE };
};
/**
* Story source doc block renders source code if provided,
* or the source for a story if `storyId` is provided, or
* the source for the current story if nothing is provided.
*/
const SourceContainer: React.FunctionComponent<SourceProps> = props => (
<DocsContext.Consumer>
{context => {
const sourceProps = getSourceProps(props, context);
return <Source {...sourceProps} />;
}}
</DocsContext.Consumer>
);
export { SourceContainer as Source };

View File

@ -0,0 +1,69 @@
import React from 'react';
import { toId } from '@storybook/router';
import { Story, StoryProps as PureStoryProps } from '@storybook/components';
import { CURRENT_SELECTION } from './shared';
import { DocsContext, DocsContextProps } from './DocsContext';
interface CommonProps {
height?: string;
}
type StoryDefProps = {
name: string;
children: React.ReactNode;
} & CommonProps;
type StoryRefProps = {
id?: string;
} & CommonProps;
export type StoryProps = StoryDefProps | StoryRefProps;
const inferInlineStories = (framework: string): boolean => {
switch (framework) {
case 'react':
return true;
default:
return false;
}
};
export const getStoryProps = (
props: StoryProps,
{ id: currentId, storyStore, parameters, mdxKind }: DocsContextProps
): PureStoryProps => {
const { id } = props as StoryRefProps;
const { name } = props as StoryDefProps;
const inputId = id === CURRENT_SELECTION ? currentId : id;
const previewId = inputId || toId(mdxKind, name);
const { height } = props;
const data = storyStore.fromId(previewId);
const { framework = null } = parameters || {};
const { inlineStories = inferInlineStories(framework), iframeHeight = undefined } =
(parameters && parameters.options && parameters.options.docs) || {};
return {
inline: inlineStories,
id: previewId,
storyFn: data && data.getDecorated(),
height: height || iframeHeight,
title: data && data.name,
};
};
const StoryContainer: React.FunctionComponent<StoryProps> = props => (
<DocsContext.Consumer>
{context => {
const storyProps = getStoryProps(props, context);
return <Story {...storyProps} />;
}}
</DocsContext.Consumer>
);
StoryContainer.defaultProps = {
children: null,
name: null,
};
export { StoryContainer as Story };

View File

@ -0,0 +1,9 @@
import React from 'react';
interface WrapperProps {
children: React.ReactNode;
}
export const Wrapper: React.FunctionComponent<WrapperProps> = ({ children }) => (
<div style={{ fontFamily: 'sans-serif' }}>{children}</div>
);

View File

@ -0,0 +1,12 @@
export { ColorPalette, ColorItem, IconGallery, IconItem, Typeset } from '@storybook/components';
export * from './Description';
export * from './DocsContext';
export * from './DocsPage';
export * from './DocsContainer';
export * from './Meta';
export * from './Preview';
export * from './Props';
export * from './Source';
export * from './Story';
export * from './Wrapper';

View File

@ -0,0 +1,2 @@
export const CURRENT_SELECTION = '.';
export type Component = any;

View File

@ -0,0 +1,88 @@
/* eslint-disable no-underscore-dangle */
import PropTypes from 'prop-types';
import { PropDef } from '@storybook/components';
import { Component } from '../blocks/shared';
interface PropDefMap {
[p: string]: PropDef;
}
export type PropDefGetter = (type: Component) => PropDef[] | null;
const propTypesMap = new Map();
Object.keys(PropTypes).forEach(typeName => {
// @ts-ignore
const type = PropTypes[typeName];
propTypesMap.set(type, typeName);
propTypesMap.set(type.isRequired, typeName);
});
const hasDocgen = (obj: any) => obj && obj.props && Object.keys(obj.props).length > 0;
const propsFromDocgen: PropDefGetter = type => {
const props: PropDefMap = {};
const docgenInfoProps = type.__docgenInfo.props;
Object.keys(docgenInfoProps).forEach(property => {
const docgenInfoProp = docgenInfoProps[property];
const defaultValueDesc = docgenInfoProp.defaultValue || {};
const propType = docgenInfoProp.flowType || docgenInfoProp.type || 'other';
props[property] = {
name: property,
type: propType,
required: docgenInfoProp.required,
description: docgenInfoProp.description,
defaultValue: defaultValueDesc.value,
};
});
return Object.values(props);
};
const propsFromPropTypes: PropDefGetter = type => {
const props: PropDefMap = {};
if (type.propTypes) {
Object.keys(type.propTypes).forEach(property => {
const typeInfo = type.propTypes[property];
const required = typeInfo.isRequired === undefined;
const docgenInfo =
type.__docgenInfo && type.__docgenInfo.props && type.__docgenInfo.props[property];
const description = docgenInfo ? docgenInfo.description : null;
let propType = propTypesMap.get(typeInfo) || 'other';
if (propType === 'other') {
if (docgenInfo && docgenInfo.type) {
propType = docgenInfo.type.name;
}
}
props[property] = { name: property, type: propType, required, description };
});
}
if (type.defaultProps) {
Object.keys(type.defaultProps).forEach(property => {
const value = type.defaultProps[property];
if (value === undefined) {
return;
}
if (!props[property]) {
props[property] = { name: property, type: 'any', required: false };
}
props[property].defaultValue = value;
});
}
return Object.values(props);
};
export const getPropDefs: PropDefGetter = type =>
hasDocgen(type.__docgenInfo) ? propsFromDocgen(type) : propsFromPropTypes(type);

1
addons/docs/src/typings.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare module '@mdx-js/react';

1
addons/docs/vue/index.js Normal file
View File

@ -0,0 +1 @@
module.exports = require('../common/index');

View File

@ -0,0 +1 @@
module.exports = require('../common/preset');

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-events",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Add events to your Storybook stories.",
"keywords": [
"addon",
@ -24,10 +24,10 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/client-api": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/theming": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/client-api": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"format-json": "^1.0.3",
"lodash": "^4.17.11",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-google-analytics",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook addon for google analytics",
"keywords": [
"addon",
@ -20,8 +20,8 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"global": "^4.3.2",
"react-ga": "^2.5.7"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-graphql",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook addon to display the GraphiQL IDE",
"keywords": [
"addon",
@ -22,8 +22,8 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"global": "^4.3.2",
"graphiql": "^0.13.0",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-info",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "A Storybook addon to show additional information for your stories.",
"keywords": [
"addon",
@ -22,10 +22,10 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/client-logger": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/theming": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/client-logger": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"global": "^4.3.2",
"jsx-to-string": "^1.4.0",

View File

@ -1331,7 +1331,7 @@ exports[`addon Info should render component description if story kind matches co
bordered={true}
className={null}
copyable={true}
format={true}
format={false}
language="js"
padded={false}
>
@ -5888,7 +5888,7 @@ exports[`addon Info should render component description if story name matches co
bordered={true}
className={null}
copyable={true}
format={true}
format={false}
language="js"
padded={false}
>

View File

@ -5,7 +5,7 @@ import { ThemeProvider, convert } from '@storybook/theming';
const Code = ({ code, language = 'plaintext', ...rest }) => (
<ThemeProvider theme={convert()}>
<SyntaxHighlighter bordered copyable language={language} {...rest}>
<SyntaxHighlighter bordered copyable format={false} language={language} {...rest}>
{code}
</SyntaxHighlighter>
</ThemeProvider>

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-jest",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "React storybook addon that show component jest report",
"keywords": [
"addon",
@ -28,11 +28,11 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/theming": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"global": "^4.3.2",
"react": "^16.8.3",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-knobs",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook Addon Prop Editor Component",
"keywords": [
"addon",
@ -22,11 +22,11 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/client-api": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/theming": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/client-api": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"copy-to-clipboard": "^3.0.8",
"core-js": "^3.0.1",
"escape-html": "^1.0.3",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-links",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Story Links addon for storybook",
"keywords": [
"addon",
@ -22,9 +22,9 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/router": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"@storybook/router": "5.2.0-alpha.32",
"common-tags": "^1.8.0",
"core-js": "^3.0.1",
"global": "^4.3.2",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-notes",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Write notes for your Storybook stories.",
"keywords": [
"addon",
@ -23,13 +23,13 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23",
"@storybook/client-logger": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/router": "5.2.0-alpha.23",
"@storybook/theming": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"@storybook/client-logger": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"@storybook/router": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"global": "^4.3.2",
"markdown-to-jsx": "^6.9.3",

View File

@ -68,7 +68,13 @@ export const SyntaxHighlighter = ({ className, children, ...props }: SyntaxHighl
// className: "lang-jsx"
const language = className.split('-');
return (
<SyntaxHighlighterBase language={language[1] || 'plaintext'} bordered copyable {...props}>
<SyntaxHighlighterBase
language={language[1] || 'plaintext'}
bordered
format={false}
copyable
{...props}
>
{children}
</SyntaxHighlighterBase>
);

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-ondevice-actions",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Action Logger addon for react-native storybook",
"keywords": [
"storybook"
@ -19,13 +19,13 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"core-js": "^2.5.7",
"fast-deep-equal": "^2.0.1"
},
"devDependencies": {
"@storybook/addon-actions": "5.2.0-alpha.23"
"@storybook/addon-actions": "5.2.0-alpha.32"
},
"peerDependencies": {
"@storybook/addon-actions": "*",

View File

@ -1,3 +1,5 @@
/* eslint-disable react/no-array-index-key */
/* eslint-disable no-nested-ternary */
import React from 'react';
import { Button, View, Text } from 'react-native';
@ -22,6 +24,7 @@ const theme = {
class Inspect extends React.Component<{ name?: string; value: any }, { expanded: boolean }> {
state = { expanded: false };
render() {
const { name, value } = this.props;
const { expanded } = this.state;
@ -52,7 +55,7 @@ class Inspect extends React.Component<{ name?: string; value: any }, { expanded:
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
{toggle}
{nameComponent}
<Text>{': ' + (value.length === 0 ? '[]' : expanded ? '[' : '[...]')}</Text>
<Text>{`: ${value.length === 0 ? '[]' : expanded ? '[' : '[...]'}`}</Text>
</View>
{expanded ? (
<View style={{ marginLeft: 40 }}>
@ -62,7 +65,7 @@ class Inspect extends React.Component<{ name?: string; value: any }, { expanded:
</View>
))}
<View style={{ marginLeft: 20 }}>
<Text>{']'}</Text>
<Text>]</Text>
</View>
</View>
) : null}
@ -71,13 +74,13 @@ class Inspect extends React.Component<{ name?: string; value: any }, { expanded:
}
return (
<View>
<Text>{'['}</Text>
<Text>[</Text>
{value.map((v, i) => (
<View key={i} style={{ marginLeft: 20 }}>
<Inspect value={v} />
</View>
))}
<Text>{']'}</Text>
<Text>]</Text>
</View>
);
}
@ -89,7 +92,7 @@ class Inspect extends React.Component<{ name?: string; value: any }, { expanded:
{toggle}
{nameComponent}
<Text>
{': ' + (Object.keys(value).length === 0 ? '{}' : expanded ? '{' : '{...}')}
{`: ${Object.keys(value).length === 0 ? '{}' : expanded ? '{' : '{...}'}`}
</Text>
</View>
{expanded ? (
@ -124,7 +127,7 @@ class Inspect extends React.Component<{ name?: string; value: any }, { expanded:
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
{toggle}
{nameComponent}
<Text>{': '}</Text>
<Text>: </Text>
<Value value={value} />
</View>
);
@ -147,7 +150,7 @@ function Value({ value }: { value: any }) {
if (value instanceof RegExp) {
return (
<Text style={{ color: theme.OBJECT_VALUE_REGEXP_COLOR }}>
{'/' + value.source + '/' + value.flags}
{`/${value.source}/${value.flags}`}
</Text>
);
}
@ -166,8 +169,9 @@ function Value({ value }: { value: any }) {
);
case 'function':
return <Text style={{ color: theme.OBJECT_VALUE_FUNCTION_PREFIX_COLOR }}>[Function]</Text>;
default:
return <Text>{JSON.stringify(value)}</Text>;
}
return <Text>{JSON.stringify(value)}</Text>;
}
export default Inspect;

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-ondevice-backgrounds",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "A react-native storybook addon to show different backgrounds for your preview",
"keywords": [
"addon",
@ -24,7 +24,7 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"prop-types": "^15.7.2"
},

View File

@ -1,3 +1,4 @@
/* eslint-disable react/prop-types, react/destructuring-assignment, import/no-extraneous-dependencies */
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import Events from '@storybook/core-events';
@ -36,10 +37,6 @@ const Instructions = () => (
);
export default class BackgroundPanel extends Component {
setBackgroundFromSwatch = background => {
this.props.channel.emit(Constants.UPDATE_BACKGROUND, background);
};
componentDidMount() {
this.props.channel.on(Events.SELECT_STORY, this.onStorySelected);
}
@ -48,6 +45,10 @@ export default class BackgroundPanel extends Component {
this.props.channel.removeListener(Events.SELECT_STORY, this.onStorySelected);
}
setBackgroundFromSwatch = background => {
this.props.channel.emit(Constants.UPDATE_BACKGROUND, background);
};
onStorySelected = selection => {
this.setState({ selection });
};

View File

@ -19,9 +19,9 @@ export default class Container extends React.Component {
channel.removeListener(Constants.UPDATE_BACKGROUND, this.onBackgroundChange);
}
onBackgroundChange = (background) => {
onBackgroundChange = background => {
this.setState({ background });
}
};
render() {
const { background } = this.state;

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-ondevice-knobs",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Display storybook story knobs on your deviced.",
"keywords": [
"addon",
@ -21,8 +21,8 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"deep-equal": "^1.0.1",
"prop-types": "^15.7.2",

View File

@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
import { View } from 'react-native';
import PropField from './PropField';
export default class propForm extends React.Component {
export default class PropForm extends React.Component {
makeChangeHandler(name, type) {
return value => {
const { onFieldChange } = this.props;
@ -38,13 +38,13 @@ export default class propForm extends React.Component {
}
}
propForm.displayName = 'propForm';
PropForm.displayName = 'PropForm';
propForm.defaultProps = {
PropForm.defaultProps = {
knobs: [],
};
propForm.propTypes = {
PropForm.propTypes = {
knobs: PropTypes.arrayOf(
PropTypes.shape({
name: PropTypes.string,

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-ondevice-notes",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Write notes for your react-native Storybook stories.",
"keywords": [
"addon",
@ -20,7 +20,7 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"prop-types": "^15.7.2",
"react-native-simple-markdown": "^1.1.0"

View File

@ -1,3 +1,4 @@
// eslint-disable-next-line no-undef
if (__DEV__) {
console.log("import '@storybook/addon-ondevice-notes/register' to register the notes addon");
}
}

View File

@ -1,3 +1,6 @@
/* eslint-disable react/prop-types */
/* eslint-disable react/destructuring-assignment */
/* eslint-disable import/no-extraneous-dependencies */
import React from 'react';
import { View } from 'react-native';
import Markdown from 'react-native-simple-markdown';
@ -7,10 +10,6 @@ import Events from '@storybook/core-events';
export const PARAM_KEY = `notes`;
class Notes extends React.Component {
setBackgroundFromSwatch = background => {
this.props.channel.emit(Constants.UPDATE_BACKGROUND, background);
};
componentDidMount() {
this.props.channel.on(Events.SELECT_STORY, this.onStorySelected);
}

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-options",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Options addon for storybook",
"keywords": [
"addon",
@ -22,7 +22,7 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"util-deprecate": "^1.0.2"
},

View File

@ -1,19 +1,19 @@
{
"name": "@storybook/addon-queryparams",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "parameter addon for storybook",
"keywords": [
"addon",
"storybook",
"query"
],
"homepage": "https://github.com/storybooks/storybook#readme",
"homepage": "https://github.com/storybookjs/storybook#readme",
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
"url": "https://github.com/storybookjs/storybook/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/storybooks/storybook.git",
"url": "git+https://github.com/storybookjs/storybook.git",
"directory": "addons/addon-queryparams"
},
"license": "MIT",
@ -23,14 +23,14 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23",
"@storybook/client-logger": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/theming": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"@storybook/client-logger": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"common-tags": "^1.8.0",
"core-js": "^2.6.5",
"core-js": "^3.0.1",
"global": "^4.3.2",
"qs": "^6.6.0",
"react": "^16.8.3"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-storyshots",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "StoryShots is a Jest Snapshot Testing Addon for Storybook.",
"keywords": [
"addon",
@ -25,7 +25,7 @@
"storybook": "start-storybook -p 6006"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"glob": "^7.1.3",
"global": "^4.3.2",

View File

@ -16,7 +16,8 @@ function integrityTest(integrityOptions, stories2snapsConverter) {
const possibleStoriesFiles = stories2snapsConverter.getPossibleStoriesFiles(fileName);
return !possibleStoriesFiles.some(fs.existsSync);
});
expect(abandonedStoryshots.length).toBe(0);
expect(abandonedStoryshots).toEqual([]);
});
});
}

View File

@ -5,6 +5,9 @@ import { action } from '@storybook/addon-actions';
import { Button } from '@storybook/react/demo';
storiesOf('Button', module)
.addParameters({
component: Button,
})
.add('with text', () => <Button onClick={action('clicked')}>Hello Button</Button>)
.add('with some emoji', () => (
<Button onClick={action('clicked')}>

View File

@ -4,4 +4,8 @@ import { storiesOf } from '@storybook/react';
import { linkTo } from '@storybook/addon-links';
import { Welcome } from '@storybook/react/demo';
storiesOf('Welcome', module).add('to Storybook', () => <Welcome showApp={linkTo('Button')} />);
storiesOf('Welcome', module)
.addParameters({
component: Welcome,
})
.add('to Storybook', () => <Welcome showApp={linkTo('Button')} />);

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-storyshots-puppeteer",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Image snappshots addition to StoryShots base on puppeteer",
"keywords": [
"addon",
@ -22,8 +22,8 @@
"prepare": "node ../../../scripts/prepare.js"
},
"dependencies": {
"@storybook/node-logger": "5.2.0-alpha.23",
"@storybook/router": "5.2.0-alpha.23",
"@storybook/node-logger": "5.2.0-alpha.32",
"@storybook/router": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"jest-image-snapshot": "^2.8.2",
"regenerator-runtime": "^0.12.1"

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-storysource",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Stories addon for storybook",
"keywords": [
"addon",
@ -22,10 +22,10 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/router": "5.2.0-alpha.23",
"@storybook/theming": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/router": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"estraverse": "^4.2.0",
"loader-utils": "^1.2.3",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-viewport",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook addon to change the viewport size to mobile",
"keywords": [
"addon",
@ -21,11 +21,12 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/client-logger": "5.2.0-alpha.23",
"@storybook/components": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/theming": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"@storybook/client-logger": "5.2.0-alpha.32",
"@storybook/components": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"@storybook/theming": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"global": "^4.3.2",
"memoizerific": "^1.11.3",
@ -37,5 +38,8 @@
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@types/util-deprecate": "^1.0.0"
}
}

View File

@ -1,5 +1,4 @@
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import memoize from 'memoizerific';
import deprecate from 'util-deprecate';
@ -10,23 +9,37 @@ import { SET_STORIES } from '@storybook/core-events';
import { PARAM_KEY } from './constants';
import { INITIAL_VIEWPORTS, DEFAULT_VIEWPORT } from './defaults';
import { ViewportAddonParameter, ViewportMap, ViewportStyles } from './models';
const toList = memoize(50)(items =>
const toList = memoize(50)((items: ViewportMap) =>
items ? Object.entries(items).map(([id, value]) => ({ ...value, id })) : []
);
const iframeId = 'storybook-preview-iframe';
const createItem = memoize(1000)((id, name, value, change) => ({
id: id || name,
title: name,
onClick: () => {
change({ selected: id, expanded: false });
},
right: `${value.width.replace('px', '')}x${value.height.replace('px', '')}`,
value,
}));
interface ViewportVM {
id: string;
title: string;
onClick: () => void;
right: string;
value: ViewportStyles;
}
const flip = ({ width, height }) => ({ height: width, width: height });
const createItem = memoize(1000)(
(id: string, name: string, value: ViewportStyles, change: (...args: unknown[]) => void) => {
const result: ViewportVM = {
id: id || name,
title: name,
onClick: () => {
change({ selected: id, expanded: false });
},
right: `${value.width.replace('px', '')}x${value.height.replace('px', '')}`,
value,
};
return result;
}
);
const flip = ({ width, height }: ViewportStyles) => ({ height: width, width: height });
const deprecatedViewportString = deprecate(
() => 0,
@ -37,56 +50,69 @@ const deprecateOnViewportChange = deprecate(
'The viewport parameter `onViewportChange` is no longer supported'
);
const getState = memoize(10)((props, state, change) => {
const data = props.api.getCurrentStoryData();
const parameters = data && data.parameters && data.parameters[PARAM_KEY];
const getState = memoize(10)(
(
props: ViewportToolProps,
state: ViewportToolState,
change: (statePatch: Partial<ViewportToolState>) => void
) => {
const data = props.api.getCurrentStoryData();
const parameters: ViewportAddonParameter =
data && (data as any).parameters && (data as any).parameters[PARAM_KEY];
if (parameters && typeof parameters !== 'object') {
deprecatedViewportString();
}
if (parameters && typeof parameters !== 'object') {
deprecatedViewportString();
}
const { disable, viewports, defaultViewport, onViewportChange } = parameters || {};
const { disable, viewports, defaultViewport, onViewportChange } = parameters || ({} as any);
if (onViewportChange) {
deprecateOnViewportChange();
}
if (onViewportChange) {
deprecateOnViewportChange();
}
const list = disable ? [] : toList(viewports || INITIAL_VIEWPORTS);
const list = disable ? [] : toList(viewports || INITIAL_VIEWPORTS);
const viewportVMList = list.map(({ id, name, styles: value }) =>
createItem(id, name, value, change)
);
const selected =
state.selected === 'responsive' || list.find(i => i.id === state.selected)
? state.selected
: list.find(i => i.default) || defaultViewport || DEFAULT_VIEWPORT;
const selected =
state.selected === 'responsive' || list.find(i => i.id === state.selected)
? state.selected
: list.find(i => i.default) || defaultViewport || DEFAULT_VIEWPORT;
const resets =
selected !== 'responsive'
? [
{
id: 'reset',
title: 'Reset viewport',
onClick: () => {
change({ selected: undefined, expanded: false });
const resets: ViewportVM[] =
selected !== 'responsive'
? [
{
id: 'reset',
title: 'Reset viewport',
onClick: () => {
change({ selected: undefined, expanded: false });
},
right: undefined,
value: undefined,
},
},
{
id: 'rotate',
title: 'Rotate viewport',
onClick: () => {
change({ isRotated: !state.isRotated, expanded: false });
{
id: 'rotate',
title: 'Rotate viewport',
onClick: () => {
change({ isRotated: !state.isRotated, expanded: false });
},
right: undefined,
value: undefined,
},
},
]
: [];
const items = list.length
? resets.concat(list.map(({ id, name, styles: value }) => createItem(id, name, value, change)))
: list;
]
: [];
return {
isRotated: state.isRotated,
items,
selected,
};
});
const items = viewportVMList.length !== 0 ? resets.concat(viewportVMList) : [];
return {
isRotated: state.isRotated,
items,
selected,
};
}
);
const ActiveViewportSize = styled.div(() => ({
display: 'inline-flex',
@ -116,8 +142,20 @@ const IconButtonLabel = styled.div(({ theme }) => ({
marginLeft: '10px',
}));
export default class ViewportTool extends Component {
constructor(props) {
interface ViewportToolState {
isRotated: boolean;
items: any[];
selected: string;
expanded: boolean;
}
interface ViewportToolProps {
api: any;
}
export class ViewportTool extends Component<ViewportToolProps, ViewportToolState> {
listener: () => void;
constructor(props: ViewportToolProps) {
super(props);
this.state = {
@ -144,12 +182,16 @@ export default class ViewportTool extends Component {
api.off(SET_STORIES, this.listener);
}
change = (...args) => this.setState(...args);
// @ts-ignore
change = (...args: any[]) => this.setState(...args);
flipViewport = () =>
this.setState(({ isRotated }) => ({ isRotated: !isRotated, expanded: false }));
this.setState(({ isRotated }: { isRotated: boolean }) => ({
isRotated: !isRotated,
expanded: false,
}));
resetViewport = e => {
resetViewport = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
@ -161,8 +203,8 @@ export default class ViewportTool extends Component {
const { items, selected, isRotated } = getState(this.props, this.state, this.change);
const item = items.find(i => i.id === selected);
let viewportX = 0;
let viewportY = 0;
let viewportX = '0';
let viewportY = '0';
let viewportTitle = '';
if (item) {
const height = item.value.height.replace('px', '');
@ -188,7 +230,7 @@ export default class ViewportTool extends Component {
boxShadow: '0 4px 8px 0 rgba(0,0,0,0.12), 0 2px 4px 0 rgba(0,0,0,0.08);',
boxSizing: 'content-box',
...(isRotated ? flip(item.value || {}) : item.value || {}),
...(isRotated ? flip(item.value) : item.value),
},
}}
/>
@ -224,9 +266,3 @@ export default class ViewportTool extends Component {
) : null;
}
}
ViewportTool.propTypes = {
api: PropTypes.shape({
on: PropTypes.func,
}).isRequired,
};

View File

@ -1,9 +0,0 @@
export const ADDON_ID = 'storybook/viewport';
export const PARAM_KEY = 'viewport';
export default {
UPDATE: `${ADDON_ID}/update`,
CONFIGURE: `${ADDON_ID}/configure`,
SET: `${ADDON_ID}/setStoryDefaultViewport`,
CHANGED: `${ADDON_ID}/viewportChanged`,
};

View File

@ -0,0 +1,7 @@
export const ADDON_ID = 'storybook/viewport';
export const PARAM_KEY = 'viewport';
export const UPDATE = `${ADDON_ID}/update`;
export const CONFIGURE = `${ADDON_ID}/configure`;
export const SET = `${ADDON_ID}/setStoryDefaultViewport`;
export const CHANGED = `${ADDON_ID}/viewportChanged`;

View File

@ -1,4 +1,6 @@
export const INITIAL_VIEWPORTS = {
import { ViewportMap } from './models';
export const INITIAL_VIEWPORTS: ViewportMap = {
iphone5: {
name: 'iPhone 5',
styles: {

View File

@ -1,7 +1,6 @@
import deprecate from 'util-deprecate';
export { INITIAL_VIEWPORTS, DEFAULT_VIEWPORT } from '../defaults';
export { default as withViewport } from './withViewport';
export const configureViewport = deprecate(() => {},
'configureViewport is no longer supported, use .addParameters({ viewport }) instead');

View File

@ -1,11 +1,11 @@
import { makeDecorator } from '@storybook/addons';
import { makeDecorator, StoryGetter, StoryContext } from '@storybook/addons';
import deprecate from 'util-deprecate';
const withViewport = makeDecorator({
name: 'withViewport',
parameterName: 'viewport',
wrapper: deprecate(
(getStory, context) => getStory(context),
(getStory: StoryGetter, context: StoryContext) => getStory(context),
'withViewport is no longer supported, use .addParameters({ viewport }) instead'
),
});

View File

@ -0,0 +1,19 @@
export interface Viewport {
name: string;
styles: ViewportStyles;
type: 'desktop' | 'mobile' | 'tablet';
/*
* @deprecated
* Deprecated option?
*/
default?: boolean;
}
export interface ViewportStyles {
height: string;
width: string;
}
export interface ViewportMap {
[key: string]: Viewport;
}

View File

@ -0,0 +1,12 @@
import { ViewportMap } from './Viewport';
export interface ViewportAddonParameter {
disable: boolean;
defaultViewport: string;
viewports: ViewportMap;
/*
* @deprecated
* The viewport parameter `onViewportChange` is no longer supported
*/
onViewportChange?: never;
}

View File

@ -0,0 +1,2 @@
export * from './Viewport';
export * from './ViewportAddonParameter';

View File

@ -3,13 +3,13 @@ import addons, { types } from '@storybook/addons';
import { ADDON_ID } from './constants';
import Tool from './Tool';
import { ViewportTool } from './Tool';
addons.register(ADDON_ID, api => {
addons.add(ADDON_ID, {
title: 'viewport / media-queries',
type: types.TOOL,
match: ({ viewMode }) => viewMode === 'story',
render: () => <Tool api={api} />,
render: () => <ViewportTool api={api} />,
});
});

View File

@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"types": ["webpack-env"]
},
"include": [
"src/**/*"
],
"exclude": [
"src/__tests__/**/*"
]
}

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/angular",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook for Angular: Develop Angular Components in isolation with Hot Reloading.",
"keywords": [
"storybook"
@ -26,8 +26,8 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/core": "5.2.0-alpha.23",
"@storybook/node-logger": "5.2.0-alpha.23",
"@storybook/core": "5.2.0-alpha.32",
"@storybook/node-logger": "5.2.0-alpha.32",
"angular2-template-loader": "^0.6.2",
"core-js": "^3.0.1",
"fork-ts-checker-webpack-plugin": "^1.3.4",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/ember",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.",
"homepage": "https://github.com/storybookjs/storybook/tree/master/app/ember",
"bugs": {
@ -24,7 +24,7 @@
},
"dependencies": {
"@ember/test-helpers": "^1.5.0",
"@storybook/core": "5.2.0-alpha.23",
"@storybook/core": "5.2.0-alpha.32",
"common-tags": "^1.8.0",
"core-js": "^3.0.1",
"global": "^4.3.2",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/html",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.",
"keywords": [
"storybook"
@ -25,7 +25,7 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/core": "5.2.0-alpha.23",
"@storybook/core": "5.2.0-alpha.32",
"common-tags": "^1.8.0",
"core-js": "^3.0.1",
"global": "^4.3.2",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/marko",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook for Marko: Develop Marko Component in isolation with Hot Reloading.",
"keywords": [
"storybook"
@ -26,7 +26,7 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/core": "5.2.0-alpha.23",
"@storybook/core": "5.2.0-alpha.32",
"common-tags": "^1.8.0",
"core-js": "^3.0.1",
"global": "^4.3.2",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/mithril",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook for Mithril: Develop Mithril Component in isolation.",
"keywords": [
"storybook"
@ -27,7 +27,7 @@
},
"dependencies": {
"@babel/plugin-transform-react-jsx": "^7.3.0",
"@storybook/core": "5.2.0-alpha.23",
"@storybook/core": "5.2.0-alpha.32",
"common-tags": "^1.8.0",
"core-js": "^3.0.1",
"global": "^4.3.2",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/polymer",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook for Polymer: Develop Polymer components in isolation with Hot Reloading.",
"keywords": [
"storybook"
@ -25,7 +25,7 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/core": "5.2.0-alpha.23",
"@storybook/core": "5.2.0-alpha.32",
"@webcomponents/webcomponentsjs": "^1.2.0",
"common-tags": "^1.8.0",
"core-js": "^3.0.1",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/preact",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook for Preact: Develop Preact Component in isolation.",
"keywords": [
"storybook"
@ -27,7 +27,7 @@
},
"dependencies": {
"@babel/plugin-transform-react-jsx": "^7.3.0",
"@storybook/core": "5.2.0-alpha.23",
"@storybook/core": "5.2.0-alpha.32",
"common-tags": "^1.8.0",
"core-js": "^3.0.1",
"global": "^4.3.2",

View File

@ -3,7 +3,7 @@
Storybook for Rax is a UI development environment for your Rax components.
With it, you can visualize different states of your UI components and develop them interactively.
![Storybook Screenshot](https://github.com/storybooks/storybook/blob/master/media/storybook-intro.gif)
![Storybook Screenshot](https://github.com/storybookjs/storybook/blob/master/media/storybook-intro.gif)
Storybook runs outside of your app.
So you can develop UI components in isolation without worrying about app specific dependencies and requirements.

View File

@ -1,18 +1,18 @@
{
"name": "@storybook/rax",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook for Rax: Develop Rax Component in isolation.",
"keywords": [
"storybook",
"rax"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/app/rax",
"homepage": "https://github.com/storybookjs/storybook/tree/master/app/rax",
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
"url": "https://github.com/storybookjs/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git",
"url": "https://github.com/storybookjs/storybook.git",
"directory": "app/rax"
},
"license": "MIT",
@ -27,8 +27,8 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/core": "5.2.0-alpha.32",
"babel-preset-rax": "^1.0.0-beta.0",
"@storybook/core": "5.2.0-alpha.23",
"common-tags": "^1.8.0",
"core-js": "^2.6.2",
"global": "^4.3.2",

View File

@ -7,4 +7,5 @@ export {
getStorybook,
forceReRender,
raw,
load,
} from './preview';

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