Merge branch 'next' of github.com:storybookjs/storybook into ts-migration/client-api

This commit is contained in:
Jessica Koch 2019-06-30 14:47:44 -07:00
commit e455427c5f
411 changed files with 12096 additions and 5029 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,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,11 +21,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",
"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",
@ -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;
"
`;

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,13 +23,19 @@
"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/router": "5.2.0-alpha.23",
"@storybook/theming": "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": {

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/* eslint-disable react/destructuring-assignment */
import React from 'react';
// import { MDXProvider } from '@mdx-js/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';
@ -39,13 +39,13 @@ export const DocsContainer: React.FunctionComponent<DocsContainerProps> = ({
<DocsContext.Provider value={context}>
<ThemeProvider theme={theme}>
<Global styles={globalWithOverflow} />
{/* <MDXProvider components={components}> */}
<DocsWrapper>
<DocsContent>
<MDXContent components={components} />
</DocsContent>
</DocsWrapper>
{/* </MDXProvider> */}
<MDXProvider components={components}>
<DocsWrapper>
<DocsContent>
<MDXContent components={components} />
</DocsContent>
</DocsWrapper>
</MDXProvider>
</ThemeProvider>
</DocsContext.Provider>
);

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,9 +24,9 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "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/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

@ -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

@ -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,6 +1,6 @@
{
"name": "@storybook/addon-queryparams",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "parameter addon for storybook",
"keywords": [
"addon",
@ -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

@ -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

@ -1,6 +1,6 @@
{
"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",
@ -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';

View File

@ -3,10 +3,9 @@ import { start } from '@storybook/core/client';
import './globals';
import render from './render';
const { clientApi, configApi, forceReRender } = start(render);
const { load: coreLoad, clientApi, configApi, forceReRender } = start(render);
export const {
storiesOf,
setAddon,
addDecorator,
addParameters,
@ -15,5 +14,9 @@ export const {
raw,
} = clientApi;
const framework = 'rax';
export const storiesOf = (...args) => clientApi.storiesOf(...args).addParameters({ framework });
export const load = (...args) => coreLoad(...args, framework);
export const { configure } = configApi;
export { forceReRender };

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/react-native-server",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "A better way to develop React Native Components for your app",
"keywords": [
"react",
@ -24,12 +24,12 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/api": "5.2.0-alpha.23",
"@storybook/channel-websocket": "5.2.0-alpha.23",
"@storybook/core": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/ui": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/api": "5.2.0-alpha.32",
"@storybook/channel-websocket": "5.2.0-alpha.32",
"@storybook/core": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"@storybook/ui": "5.2.0-alpha.32",
"commander": "^2.19.0",
"core-js": "^3.0.1",
"global": "^4.3.2",

View File

@ -51,8 +51,7 @@ export default class ReactProvider extends Provider {
<Consumer filter={mapper} pure>
{({ storiesHash, storyId, api, viewMode }) => {
if (storiesHash[storyId]) {
const { kind, story } = storiesHash[storyId];
api.emit(Events.SET_CURRENT_STORY, { kind, story });
api.emit(Events.SET_CURRENT_STORY, { storyId });
}
return viewMode === 'story' ? <PreviewHelp /> : null;
}}
@ -62,12 +61,6 @@ export default class ReactProvider extends Provider {
handleAPI(api) {
addons.loadAddons(api);
api.on(Events.STORY_CHANGED, () => {
api.emit(Events.SET_CURRENT_STORY, this.selection);
});
api.on(Events.GET_CURRENT_STORY, () => {
api.emit(Events.SET_CURRENT_STORY, this.selection);
});
api.emit(Events.GET_STORIES);
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/react-native",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "A better way to develop React Native Components for your app",
"keywords": [
"react",
@ -23,11 +23,11 @@
},
"dependencies": {
"@emotion/native": "^10.0.10",
"@storybook/addons": "5.2.0-alpha.23",
"@storybook/channel-websocket": "5.2.0-alpha.23",
"@storybook/channels": "5.2.0-alpha.23",
"@storybook/client-api": "5.2.0-alpha.23",
"@storybook/core-events": "5.2.0-alpha.23",
"@storybook/addons": "5.2.0-alpha.32",
"@storybook/channel-websocket": "5.2.0-alpha.32",
"@storybook/channels": "5.2.0-alpha.32",
"@storybook/client-api": "5.2.0-alpha.32",
"@storybook/core-events": "5.2.0-alpha.32",
"core-js": "^3.0.1",
"react-native-swipe-gestures": "^1.0.3",
"rn-host-detect": "^1.1.5"

View File

@ -1,3 +1,4 @@
/* eslint-disable prefer-destructuring */
import Preview from './preview';
const preview = new Preview();

View File

@ -22,7 +22,9 @@ type Props = {
// To avoid issues we use absolute positioned element with predefined screen size
export default class AbsolutePositionedKeyboardAwareView extends PureComponent<Props> {
keyboardDidShowListener: EmitterSubscription;
keyboardDidHideListener: EmitterSubscription;
keyboardOpen: boolean;
componentWillMount() {

View File

@ -1,5 +1,5 @@
import { NAVIGATOR, PREVIEW, ADDONS } from './navigation/constants';
import { Animated } from 'react-native';
import { NAVIGATOR, PREVIEW, ADDONS } from './navigation/constants';
const PREVIEW_SCALE = 0.3;

View File

@ -8,7 +8,6 @@ import {
TouchableOpacityProps,
} from 'react-native';
import styled from '@emotion/native';
import Events from '@storybook/core-events';
import addons from '@storybook/addons';
import Channel from '@storybook/channels';
import StoryListView from '../StoryListView';
@ -36,14 +35,11 @@ interface OnDeviceUIProps {
url?: string;
tabOpen?: number;
isUIHidden?: boolean;
getInitialStory?: (...args: any[]) => any;
shouldDisableKeyboardAvoidingView?: boolean;
keyboardAvoidingViewVerticalOffset?: number;
}
interface OnDeviceUIState {
selection: any;
storyFn: any;
tabOpen: number;
slideBetweenAnimation: boolean;
previewWidth: number;
@ -64,6 +60,7 @@ const Preview: typeof TouchableOpacity = styled.TouchableOpacity`
export default class OnDeviceUI extends PureComponent<OnDeviceUIProps, OnDeviceUIState> {
animatedValue: Animated.Value;
channel: Channel;
constructor(props: OnDeviceUIProps) {
@ -72,8 +69,6 @@ export default class OnDeviceUI extends PureComponent<OnDeviceUIProps, OnDeviceU
this.state = {
tabOpen,
slideBetweenAnimation: false,
selection: {},
storyFn: null,
previewWidth: 0,
previewHeight: 0,
};
@ -81,24 +76,6 @@ export default class OnDeviceUI extends PureComponent<OnDeviceUIProps, OnDeviceU
this.channel = addons.getChannel();
}
async componentWillMount() {
const { getInitialStory } = this.props;
if (getInitialStory) {
const story = await getInitialStory();
this.setState({
selection: story || {},
storyFn: story ? story.storyFn : null,
});
}
this.channel.on(Events.SELECT_STORY, this.handleStoryChange);
this.channel.on(Events.FORCE_RE_RENDER, this.forceReRender);
}
componentWillUnmount() {
this.channel.removeListener(Events.SELECT_STORY, this.handleStoryChange);
this.channel.removeListener(Events.FORCE_RE_RENDER, this.forceReRender);
}
onLayout = ({ previewWidth, previewHeight }: PreviewDimens) => {
this.setState({ previewWidth, previewHeight });
};
@ -107,24 +84,6 @@ export default class OnDeviceUI extends PureComponent<OnDeviceUIProps, OnDeviceU
this.handleToggleTab(PREVIEW);
};
forceReRender = () => {
this.forceUpdate();
};
handleStoryChange = (selection: any) => {
const { selection: prevSelection } = this.state;
if (selection.kind === prevSelection.kind && selection.story === prevSelection.story) {
this.handleToggleTab(PREVIEW);
}
this.setState({
selection: {
kind: selection.kind,
story: selection.story,
},
storyFn: selection.storyFn,
});
};
handleToggleTab = (newTabOpen: number) => {
const { tabOpen } = this.state;
if (newTabOpen === tabOpen) {
@ -155,14 +114,7 @@ export default class OnDeviceUI extends PureComponent<OnDeviceUIProps, OnDeviceU
keyboardAvoidingViewVerticalOffset,
} = this.props;
const {
tabOpen,
slideBetweenAnimation,
selection,
storyFn,
previewWidth,
previewHeight,
} = this.state;
const { tabOpen, slideBetweenAnimation, previewWidth, previewHeight } = this.state;
const previewWrapperStyles = [
{ flex: 1 },
@ -190,21 +142,12 @@ export default class OnDeviceUI extends PureComponent<OnDeviceUIProps, OnDeviceU
disabled={tabOpen === PREVIEW}
onPress={this.handleOpenPreview}
>
<StoryView
url={url}
selection={selection}
storyFn={storyFn}
listenToEvents={false}
/>
<StoryView url={url} onDevice stories={stories} />
</Preview>
</Animated.View>
</Animated.View>
<Panel style={getNavigatorPanelPosition(this.animatedValue, previewWidth)}>
<StoryListView
stories={stories}
selectedKind={selection.kind}
selectedStory={selection.story}
/>
<StoryListView stories={stories} />
</Panel>
<Panel style={getAddonPanelPosition(this.animatedValue, previewWidth)}>
<Addons />

View File

@ -1,3 +1,4 @@
/* eslint-disable react/destructuring-assignment */
import React, { PureComponent } from 'react';
import { View, SafeAreaView, StyleSheet } from 'react-native';
import GestureRecognizer, { GestureRecognizerConfig } from 'react-native-swipe-gestures';

View File

@ -1,3 +1,4 @@
/* eslint-disable react/destructuring-assignment */
import React, { Component } from 'react';
import { SectionList, TextInput, TouchableOpacity, View, SafeAreaView } from 'react-native';
import styled from '@emotion/native';
@ -64,8 +65,6 @@ const ListItem: React.FunctionComponent<ListItemProps> = ({ kind, title, selecte
interface Props {
stories: any;
selectedKind?: string;
selectedStory?: string;
}
interface State {
@ -90,28 +89,35 @@ export default class StoryListView extends Component<Props, State> {
componentDidMount() {
const channel = addons.getChannel();
channel.on(Events.STORY_ADDED, this.handleStoryAdded);
channel.on(Events.SELECT_STORY, this.forceReRender);
this.handleStoryAdded();
}
componentWillUnmount() {
const channel = addons.getChannel();
channel.removeListener(Events.STORY_ADDED, this.handleStoryAdded);
channel.removeListener(Events.SELECT_STORY, this.forceReRender);
}
forceReRender = () => {
this.forceUpdate();
};
handleStoryAdded = () => {
const { stories } = this.props;
if (stories) {
const data = stories.dumpStoryBook().map(
(section: any) => ({
title: section.kind,
data: section.stories.map((story: any) => ({
key: story,
name: story,
kind: section.kind,
})),
}),
{}
const data = Object.values(
stories
.raw()
.reduce((acc: { [kind: string]: { title: string; data: any[] } }, story: any) => {
acc[story.kind] = {
title: story.kind,
data: (acc[story.kind] ? acc[story.kind].data : []).concat(story),
};
return acc;
}, {})
);
this.setState({ data, originalData: data });
@ -146,13 +152,13 @@ export default class StoryListView extends Component<Props, State> {
this.setState({ data: filteredData });
};
changeStory(kind: string, story: string) {
changeStory(storyId: string) {
const channel = addons.getChannel();
channel.emit(Events.SET_CURRENT_STORY, { kind, story });
channel.emit(Events.SET_CURRENT_STORY, { storyId });
}
render() {
const { selectedKind, selectedStory } = this.props;
const selectedStory = this.props.stories.getSelection();
const { data } = this.state;
return (
@ -171,12 +177,12 @@ export default class StoryListView extends Component<Props, State> {
<ListItem
title={item.name}
kind={item.kind}
selected={item.kind === selectedKind && item.name === selectedStory}
onPress={() => this.changeStory(item.kind, item.name)}
selected={item.id === selectedStory.id}
onPress={() => this.changeStory(item.id)}
/>
)}
renderSectionHeader={({ section: { title } }) => (
<SectionHeader title={title} selected={title === selectedKind} />
<SectionHeader title={title} selected={title === selectedStory.kind} />
)}
keyExtractor={(item, index) => item + index}
sections={data}

View File

@ -5,15 +5,9 @@ import addons from '@storybook/addons';
import Events from '@storybook/core-events';
interface Props {
listenToEvents: boolean;
selection?: any;
storyFn?: any;
stories: any;
url: string;
}
interface State {
storyFn?: any;
selection?: any;
onDevice?: boolean;
}
const HelpContainer = styled.View`
@ -24,33 +18,23 @@ const HelpContainer = styled.View`
justify-content: center;
`;
export default class StoryView extends Component<Props, State> {
export default class StoryView extends Component<Props> {
componentDidMount() {
if (this.props.listenToEvents) {
const channel = addons.getChannel();
channel.on(Events.SELECT_STORY, this.selectStory);
channel.on(Events.FORCE_RE_RENDER, this.forceReRender);
}
const channel = addons.getChannel();
channel.on(Events.STORY_RENDER, this.forceReRender);
channel.on(Events.FORCE_RE_RENDER, this.forceReRender);
}
componentWillUnmount() {
const { listenToEvents } = this.props;
if (listenToEvents) {
const channel = addons.getChannel();
channel.removeListener(Events.SELECT_STORY, this.selectStory);
channel.removeListener(Events.FORCE_RE_RENDER, this.forceReRender);
}
const channel = addons.getChannel();
channel.removeListener(Events.STORY_RENDER, this.forceReRender);
channel.removeListener(Events.FORCE_RE_RENDER, this.forceReRender);
}
forceReRender = () => {
this.forceUpdate();
};
selectStory = (selection: any) => {
this.setState({ storyFn: selection.storyFn, selection });
};
renderHelp = () => {
const { url } = this.props;
return (
@ -75,41 +59,24 @@ export default class StoryView extends Component<Props, State> {
);
render() {
const { listenToEvents } = this.props;
const { onDevice, stories } = this.props;
if (listenToEvents) {
return this.renderListening();
} else {
return this.renderOnDevice();
const selection = stories.getSelection();
const { id, storyFn } = selection;
if (storyFn) {
return (
<View key={id} style={{ flex: 1 }}>
{storyFn()}
</View>
);
}
if (onDevice) {
return this.renderOnDeviceUIHelp();
}
return this.renderHelp();
}
renderListening = () => {
if (!this.state) {
return null;
}
const { storyFn, selection } = this.state;
const { kind, story } = selection;
return storyFn ? (
<View key={`${kind}:::${story}`} style={{ flex: 1 }}>
{storyFn()}
</View>
) : (
this.renderHelp()
);
};
renderOnDevice = () => {
const { storyFn, selection } = this.props;
const { kind, story } = selection;
return storyFn ? (
<View key={`${kind}:::${story}`} style={{ flex: 1 }}>
{storyFn()}
</View>
) : (
this.renderOnDeviceUIHelp()
);
};
}

View File

@ -1,3 +1,4 @@
/* eslint-disable import/no-extraneous-dependencies, no-underscore-dangle */
import React from 'react';
import { AsyncStorage } from 'react-native';
import { ThemeProvider } from 'emotion-theming';
@ -32,16 +33,19 @@ export type Params = {
} & EmotionProps;
export default class Preview {
currentStory: any;
_clientApi: ClientApi;
_stories: StoryStore;
_addons: any;
_decorators: any[];
_asyncStorageStoryId: string;
constructor() {
this._addons = {};
this._decorators = [];
this._stories = new StoryStore({});
this._clientApi = new ClientApi({ storyStore: this._stories });
}
@ -64,9 +68,6 @@ export default class Preview {
const onDeviceUI = params.onDeviceUI !== false;
const { initialSelection, shouldPersistSelection } = params;
// should the initial story be sent to storybookUI
// set to true if using disableWebsockets or if connection to WebsocketServer fails.
let setInitialStory = false;
try {
channel = addons.getChannel();
@ -78,6 +79,7 @@ export default class Preview {
if (!channel || params.resetStorybook) {
if (onDeviceUI && params.disableWebsockets) {
channel = new Channel({ async: true });
this._setInitialStory(initialSelection, shouldPersistSelection);
} else {
const host = getHost(params.host || 'localhost');
const port = `:${params.port || 7007}`;
@ -93,11 +95,7 @@ export default class Preview {
url,
async: onDeviceUI,
onError: () => {
// We are both emitting event and telling the component to get initial story. It may happen that component is created before the error or vise versa.
// This way we handle both cases
this._setInitialStory(initialSelection, shouldPersistSelection);
setInitialStory = true;
},
});
}
@ -113,13 +111,6 @@ export default class Preview {
this._sendSetStories();
// If the app is started with server running, set the story as the one selected in the browser
if (webUrl) {
this._sendGetCurrentStory();
} else {
setInitialStory = true;
}
const preview = this;
addons.loadAddons(this._clientApi);
@ -127,7 +118,6 @@ export default class Preview {
const appliedTheme = { ...theme, ...params.theme };
// react-native hot module loader must take in a Class - https://github.com/facebook/react-native/issues/10991
// eslint-disable-next-line react/prefer-stateless-function
return class StorybookRoot extends React.PureComponent {
render() {
if (onDeviceUI) {
@ -138,11 +128,6 @@ export default class Preview {
url={webUrl}
isUIHidden={params.isUIHidden}
tabOpen={params.tabOpen}
getInitialStory={
setInitialStory
? preview._getInitialStory(initialSelection, shouldPersistSelection)
: null
}
shouldDisableKeyboardAvoidingView={params.shouldDisableKeyboardAvoidingView}
keyboardAvoidingViewVerticalOffset={params.keyboardAvoidingViewVerticalOffset}
/>
@ -152,7 +137,7 @@ export default class Preview {
return (
<ThemeProvider theme={appliedTheme}>
<StoryView url={webUrl} listenToEvents />
<StoryView stories={preview._stories} url={webUrl} />
</ThemeProvider>
);
}
@ -164,14 +149,6 @@ export default class Preview {
const stories = this._stories.extract();
channel.emit(Events.SET_STORIES, { stories });
channel.emit(Events.STORIES_CONFIGURED);
if (this.currentStory) {
channel.emit(Events.SET_CURRENT_STORY, this.currentStory);
}
}
_sendGetCurrentStory() {
const channel = addons.getChannel();
channel.emit(Events.GET_CURRENT_STORY);
}
_setInitialStory = async (initialSelection: any, shouldPersistSelection = true) => {
@ -187,11 +164,18 @@ export default class Preview {
if (initialSelection && this._checkStory(initialSelection)) {
story = initialSelection;
} else if (shouldPersistSelection) {
const value = await AsyncStorage.getItem(STORAGE_KEY);
const previousStory = JSON.parse(value);
try {
let value = this._asyncStorageStoryId;
if (!value) {
value = JSON.parse(await AsyncStorage.getItem(STORAGE_KEY));
this._asyncStorageStoryId = value;
}
if (this._checkStory(previousStory)) {
story = previousStory;
if (this._checkStory(value)) {
story = value;
}
} catch (e) {
//
}
}
@ -199,43 +183,44 @@ export default class Preview {
return this._getStory(story);
}
const dump = this._stories.dumpStoryBook();
const nonEmptyKind = dump.find((kind: any) => kind.stories.length > 0);
if (nonEmptyKind) {
return this._getStory({ kind: nonEmptyKind.kind, story: nonEmptyKind.stories[0] });
const stories = this._stories.raw();
if (stories && stories.length) {
return this._getStory(stories[0].id);
}
return null;
};
_getStory(selection: { kind: string; story: string }) {
const { kind, story } = selection;
const storyFn = this._stories.getStoryWithContext(kind, story);
return { ...selection, storyFn };
_getStory(storyId: string) {
return this._stories.fromId(storyId);
}
_selectStoryEvent(selection: { kind: string; story: string }) {
AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(selection));
_selectStoryEvent({ storyId }: { storyId: string }) {
if (storyId) {
try {
AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(storyId));
} catch (e) {
//
}
if (selection) {
const story = this._getStory(selection);
const story = this._getStory(storyId);
this._selectStory(story);
}
}
_selectStory(story: any) {
this.currentStory = story;
const channel = addons.getChannel();
this._stories.setSelection(story);
channel.emit(Events.SELECT_STORY, story);
}
_checkStory(selection: any) {
if (!selection || typeof selection !== 'object' || !selection.kind || !selection.story) {
_checkStory(storyId: string) {
if (!storyId) {
return null;
}
const story = this._getStory(selection);
const story = this._getStory(storyId);
if (story.storyFn === null) {
return null;

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/react",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook for React: Develop React Component in isolation with Hot Reloading.",
"keywords": [
"storybook"
@ -29,8 +29,8 @@
"@babel/plugin-transform-react-constant-elements": "^7.2.0",
"@babel/preset-flow": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"@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",
"@svgr/webpack": "^4.0.3",
"babel-plugin-add-react-displayname": "^0.0.5",
"babel-plugin-named-asset-import": "^0.3.1",

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/riot",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook for riot.js: View riot 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/svelte",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook for Svelte: Develop Svelte 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/vue",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "Storybook for Vue: Develop Vue 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/addon-parameter",
"version": "5.2.0-alpha.23",
"version": "5.2.0-alpha.32",
"description": "parameter addon for storybook",
"keywords": [
"devkit",
@ -24,14 +24,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"
},

View File

@ -1,44 +1,44 @@
{
"name": "@storybook/addon-roundtrip",
"version": "5.2.0-alpha.23",
"description": "roundtrip addon for storybook",
"keywords": [
"devkit",
"addon",
"storybook",
"roundtrip"
],
"homepage": "https://github.com/storybookjs/storybook#readme",
"bugs": {
"url": "https://github.com/storybookjs/storybook/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/storybookjs/storybook.git",
"directory": "dev-kit/addon-roundtrip"
},
"license": "MIT",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"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",
"common-tags": "^1.8.0",
"core-js": "^2.6.5",
"global": "^4.3.2",
"react": "^16.8.3"
},
"devDependencies": {
"@types/common-tags": "^1.8.0"
},
"publishConfig": {
"access": "public"
}
"name": "@storybook/addon-roundtrip",
"version": "5.2.0-alpha.32",
"description": "roundtrip addon for storybook",
"keywords": [
"devkit",
"addon",
"storybook",
"roundtrip"
],
"homepage": "https://github.com/storybooks/storybook#readme",
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/storybooks/storybook.git",
"directory": "dev-kit/addon-roundtrip"
},
"license": "MIT",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@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": "^3.0.1",
"global": "^4.3.2",
"react": "^16.8.3"
},
"devDependencies": {
"@types/common-tags": "^1.8.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@ -33,7 +33,7 @@
"gatsby-source-filesystem": "^1.5.39",
"gatsby-transformer-remark": "^1.7.44",
"global": "^4.4.0",
"html-react-parser": "^0.7.1",
"html-react-parser": "^0.8.0",
"is-builtin-module": "^3.0.0",
"lodash": "^4.17.11",
"marked": "^0.6.2",
@ -48,7 +48,7 @@
"react-stack-grid": "^0.7.1",
"recompose": "^0.30.0",
"sitemap": "^2.2.0",
"styled-components": "^4.3.1",
"styled-components": "^4.3.2",
"validatorjs": "^3.15.1"
}
}

View File

@ -74,6 +74,14 @@ addParameters({
* theme storybook, see link below
*/
theme: undefined,
/**
* function to sort stories in the tree view
* common use is alphabetical `(a, b) => a[1].id.localeCompare(b[1].id)`
* if left undefined, then the order in which the stories are imported will
* be the order they display
* @type {Function}
*/
storySort: undefined
},
});
```

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