mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-04 22:11:15 +08:00
Merge branch 'next' into migrate-from-simplebar-to-overlaybars-2
# Conflicts: # addons/info/src/__snapshots__/index.test.js.snap # addons/info/src/index.test.js # lib/components/package.json # yarn.lock
This commit is contained in:
commit
908c58ee6a
106
CHANGELOG.md
106
CHANGELOG.md
@ -1,3 +1,109 @@
|
||||
## 6.0.0-alpha.6 (February 5, 2020)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Core: Fix dev server error - back out bad change ([#9753](https://github.com/storybookjs/storybook/pull/9753))
|
||||
* CLI: Fix file path for the Button story ([#9325](https://github.com/storybookjs/storybook/pull/9325))
|
||||
|
||||
## 5.3.12 (February 5, 2020)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Core: Fix dev server error - back out bad change ([#9753](https://github.com/storybookjs/storybook/pull/9753))
|
||||
|
||||
## 5.3.11 (February 4, 2020)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Svelte: Fix Svelte 3 slots for decorators ([#9724](https://github.com/storybookjs/storybook/pull/9724))
|
||||
* CLI: Fix file path for Button story ([#9325](https://github.com/storybookjs/storybook/pull/9325))
|
||||
* Angular: Emit decorator metadata by default ([#9701](https://github.com/storybookjs/storybook/pull/9701))
|
||||
* Storyshots: Fix config via main.ts ([#9577](https://github.com/storybookjs/storybook/pull/9577))
|
||||
|
||||
## 6.0.0-alpha.5 (February 4, 2020)
|
||||
|
||||
### Features
|
||||
|
||||
* Core: Add Yarn 2 compatibility ([#9667](https://github.com/storybookjs/storybook/pull/9667))
|
||||
* Addon-a11y: Add preset ([#9697](https://github.com/storybookjs/storybook/pull/9697))
|
||||
* Server: Initial support for @storybook/server ([#9722](https://github.com/storybookjs/storybook/pull/9722))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Svelte: Fix Svelte 3 slots for decorators ([#9724](https://github.com/storybookjs/storybook/pull/9724))
|
||||
|
||||
### Maintenance
|
||||
|
||||
* Cra-ts-kitchen-sink: Fix stories glob pattern ([#9706](https://github.com/storybookjs/storybook/pull/9706))
|
||||
|
||||
## 6.0.0-alpha.4 (February 3, 2020)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Angular: Emit decorator metadata by default ([#9701](https://github.com/storybookjs/storybook/pull/9701))
|
||||
* Addon-centered: Fix clash with addon-docs for react ([#8388](https://github.com/storybookjs/storybook/pull/8388))
|
||||
|
||||
### Maintenance
|
||||
|
||||
* Add angular 8 and 9 cli fixtures ([#8769](https://github.com/storybookjs/storybook/pull/8769))
|
||||
|
||||
### Dependency Upgrades
|
||||
|
||||
* Misc upgrades ([#9688](https://github.com/storybookjs/storybook/pull/9688))
|
||||
|
||||
## 5.3.10 (February 2, 2020)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Core: Upgrade `min-css-extract-plugin` to fix SASS loading ([#9652](https://github.com/storybookjs/storybook/pull/9652))
|
||||
* CRA: Fix jsconfig support ([#9324](https://github.com/storybookjs/storybook/pull/9324))
|
||||
* Web-components: Fix default value for docs prop table ([#9655](https://github.com/storybookjs/storybook/pull/9655))
|
||||
* Web-components: Fix types to play nicely with lit-element ([#9557](https://github.com/storybookjs/storybook/pull/9557))
|
||||
* UI: Add support for className prop on Form.Field ([#9665](https://github.com/storybookjs/storybook/pull/9665))
|
||||
* Addon-storyshots: Remove excess slashes from jest transform warning ([#9616](https://github.com/storybookjs/storybook/pull/9616))
|
||||
|
||||
### Maintenance
|
||||
|
||||
* Ember: Migrate to new "import { hbs } from 'ember-cli-htmlbars'" ([#9633](https://github.com/storybookjs/storybook/pull/9633))
|
||||
* Build: Netlify for examples again ([#9585](https://github.com/storybookjs/storybook/pull/9585))
|
||||
* Publish: Remove docs to reduce package size ([#9612](https://github.com/storybookjs/storybook/pull/9612))
|
||||
|
||||
## 6.0.0-alpha.3 (February 2, 2020)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* CRA: Fix jsconfig support ([#9324](https://github.com/storybookjs/storybook/pull/9324))
|
||||
* UI: Check if docsOnly is set to hide the addon panels ([#9687](https://github.com/storybookjs/storybook/pull/9687))
|
||||
|
||||
### Maintenance
|
||||
|
||||
* Addon-notes, addon-info: Move to deprecated-addons repo ([#9673](https://github.com/storybookjs/storybook/pull/9673))
|
||||
|
||||
## 6.0.0-alpha.2 (January 30, 2020)
|
||||
|
||||
### Features
|
||||
|
||||
* UI: Configure tabs title, visibility, order and disable ([#9095](https://github.com/storybookjs/storybook/pull/9095))
|
||||
* Addon-cssresources: Add hideCode option ([#9627](https://github.com/storybookjs/storybook/pull/9627))
|
||||
* UI: Add `viewMode` parameter to control story nav UI ([#9090](https://github.com/storybookjs/storybook/pull/9090))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Web-components: Fix default value for prop table docs ([#9655](https://github.com/storybookjs/storybook/pull/9655))
|
||||
* Web-components: Make TypeScript types play nicely with lit-element ([#9557](https://github.com/storybookjs/storybook/pull/9557))
|
||||
* UI: Fix tabs to scroll horizontally ([#9383](https://github.com/storybookjs/storybook/pull/9383))
|
||||
* UI: Add support for className prop on Form.Field ([#9665](https://github.com/storybookjs/storybook/pull/9665))
|
||||
* Core: Upgrade `min-css-extract-plugin` to fix SASS loading ([#9652](https://github.com/storybookjs/storybook/pull/9652))
|
||||
* Adon-docs: Fix ColorPalette styling ([#9643](https://github.com/storybookjs/storybook/pull/9643))
|
||||
* Addon-storyshots: Remove excess slashes from jest transform warning ([#9616](https://github.com/storybookjs/storybook/pull/9616))
|
||||
|
||||
### Maintenance
|
||||
|
||||
* Source-loader: Overhaul to remove decorators, support user-configurable source ([#9547](https://github.com/storybookjs/storybook/pull/9547))
|
||||
* Build: Use Netlify for examples again ([#9585](https://github.com/storybookjs/storybook/pull/9585))
|
||||
* Ember: Migrate to new "import { hbs } from 'ember-cli-htmlbars'" ([#9633](https://github.com/storybookjs/storybook/pull/9633))
|
||||
* Publish: Remove docs to reduce package size ([#9612](https://github.com/storybookjs/storybook/pull/9612))
|
||||
|
||||
## 5.3.9 (January 24, 2020)
|
||||
|
||||
### Bug Fixes
|
||||
|
@ -30,6 +30,8 @@ cd storybook
|
||||
yarn bootstrap
|
||||
```
|
||||
|
||||
> NOTE: on windows you may need to run `yarn` before `yarn bootstrap`!
|
||||
|
||||
The bootstrap command might ask which sections of the codebase you want to bootstrap. Unless you're going to work with ReactNative or the Documentation, you can keep the default.
|
||||
|
||||
You can also pick directly from CLI:
|
||||
@ -140,6 +142,8 @@ git clone https://github.com/storybookjs/storybook.git
|
||||
cd storybook
|
||||
yarn bootstrap --core
|
||||
|
||||
# NOTE: on windows you may need to run `yarn` before `yarn bootstrap`!
|
||||
|
||||
# make changes to try and reproduce the problem, such as adding components + stories
|
||||
cd examples/cra-kitchen-sink
|
||||
yarn storybook
|
||||
@ -263,10 +267,11 @@ If you run into trouble here, make sure your node, npm, and **_yarn_** are on th
|
||||
1. `cd ~` (optional)
|
||||
2. `git clone https://github.com/storybookjs/storybook.git` _bonus_: use your own fork for this step
|
||||
3. `cd storybook`
|
||||
4. `yarn`
|
||||
5. `yarn bootstrap --core`
|
||||
6. `yarn test --core`
|
||||
7. `yarn dev` _You must have this running for your changes to show up_
|
||||
4. `yarn bootstrap --core`
|
||||
5. `yarn test --core`
|
||||
6. `yarn dev` _You must have this running for your changes to show up_
|
||||
|
||||
> NOTE: on windows you may need to run `yarn` before `yarn bootstrap` (between steps 3 and 4).
|
||||
|
||||
#### Bootstrapping everything
|
||||
|
||||
|
56
MIGRATION.md
56
MIGRATION.md
@ -1,6 +1,8 @@
|
||||
# Migration
|
||||
|
||||
- [Migration](#migration)
|
||||
- [From version 5.3.x to 6.0.x](#from-version-53x-to-60x)
|
||||
- [New addon presets](#new-addon-presets)
|
||||
- [From version 5.2.x to 5.3.x](#from-version-52x-to-53x)
|
||||
- [To main.js configuration](#to-mainjs-configuration)
|
||||
- [Create React App preset](#create-react-app-preset)
|
||||
@ -76,6 +78,53 @@
|
||||
- [Packages renaming](#packages-renaming)
|
||||
- [Deprecated embedded addons](#deprecated-embedded-addons)
|
||||
|
||||
## From version 5.3.x to 6.0.x
|
||||
|
||||
### New addon presets
|
||||
|
||||
In Storybook 5.3 we introduced a declarative [main.js configuration](#to-mainjs-configuration), which is now the recommended way to configure Storybook. Part of the change is a simplified syntax for registering addons, which in 6.0 automatically registers many addons _using a preset_, which is a slightly different behavior than in earlier versions.
|
||||
|
||||
This breaking change currently applies to: `addon-a11y`, `addon-knobs`.
|
||||
|
||||
Consider the following `main.js` config for the accessibility addon, `addon-a11y`:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
stories: ['../**/*.stories.js'],
|
||||
addons: ['@storybook/addon-a11y'],
|
||||
};
|
||||
```
|
||||
|
||||
In earlier versions of Storybook, this would automatically call `@storybook/addon-a11y/register`, which adds the the a11y panel to the Storybook UI. As a user you would also add a decorator:
|
||||
|
||||
```js
|
||||
import { withA11Y } from '../index';
|
||||
|
||||
addDecorator(withA11Y);
|
||||
```
|
||||
|
||||
Now in 6.0, `addon-a11y` comes with a preset, `@storybook/addon-a11y/preset`, that does this automatically for you. This change simplifies configuration, since now you don't need to add that decorator. However, if you are upgrading
|
||||
|
||||
If you wish to disable this new behavior, you can modify your `main.js` to force it to use the `register` logic rather than the `preset`:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
stories: ['../**/*.stories.js'],
|
||||
addons: ['@storybook/addon-a11y/register'],
|
||||
};
|
||||
```
|
||||
|
||||
If you wish to selectively disable `a11y` checks for a subset of stories, you can control this with story parameters:
|
||||
|
||||
```js
|
||||
export const MyNonCheckedStory = () => <SomeComponent />;
|
||||
MyNonCheckedStory.story = {
|
||||
parameters: {
|
||||
a11y: { disable: true },
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## From version 5.2.x to 5.3.x
|
||||
|
||||
### To main.js configuration
|
||||
@ -214,7 +263,7 @@ yarn sb migrate upgrade-hierarchy-separators --glob="*.stories.js"
|
||||
If you were using `|` and wish to keep the "root" behavior, use the `showRoots: true` option to re-enable roots:
|
||||
|
||||
```js
|
||||
addParameters({
|
||||
addParameters({
|
||||
options: {
|
||||
showRoots: true,
|
||||
},
|
||||
@ -226,13 +275,14 @@ NOTE: it is no longer possible to have some stories with roots and others withou
|
||||
### Addon StoryShots Puppeteer uses external puppeteer
|
||||
|
||||
To give you more control on the Chrome version used when running StoryShots Puppeteer, `puppeteer` is no more included in the addon dependencies. So you can now pick the version of `puppeteer` you want and set it in your project.
|
||||
|
||||
|
||||
If you want the latest version available just run:
|
||||
|
||||
```sh
|
||||
yarn add puppeteer --dev
|
||||
OR
|
||||
npm install puppeteer --save-dev
|
||||
```
|
||||
```
|
||||
|
||||
## From version 5.1.x to 5.2.x
|
||||
|
||||
|
@ -18,8 +18,8 @@ Add this line to your `main.js` file (create this file inside your storybook con
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
addons: ['@storybook/addon-a11y/register']
|
||||
}
|
||||
addons: ['@storybook/addon-a11y/register'],
|
||||
};
|
||||
```
|
||||
|
||||
import the `withA11y` decorator to check your stories for violations within your components.
|
||||
@ -34,19 +34,23 @@ export default {
|
||||
decorators: [withA11y],
|
||||
};
|
||||
|
||||
export const accessible = () => (
|
||||
<button>
|
||||
Accessible button
|
||||
</button>
|
||||
);
|
||||
export const accessible = () => <button>Accessible button</button>;
|
||||
|
||||
export const inaccessible = () => (
|
||||
<button style={{ backgroundColor: 'red', color: 'darkRed', }}>
|
||||
Inaccessible button
|
||||
</button>
|
||||
<button style={{ backgroundColor: 'red', color: 'darkRed' }}>Inaccessible button</button>
|
||||
);
|
||||
```
|
||||
|
||||
## Using the preset
|
||||
|
||||
Add the decorator to all stories:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
addons: ['@storybook/addon-a11y'],
|
||||
};
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
For more customizability use parameters to configure [aXe options](https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure).
|
||||
@ -69,29 +73,23 @@ export default {
|
||||
config: {},
|
||||
// axe-core optionsParameter (https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter)
|
||||
options: {},
|
||||
// optional flag to prevent the automatic check
|
||||
// optional flag to prevent the automatic check
|
||||
manual: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const accessible = () => (
|
||||
<button>
|
||||
Accessible button
|
||||
</button>
|
||||
);
|
||||
export const accessible = () => <button>Accessible button</button>;
|
||||
|
||||
export const inaccessible = () => (
|
||||
<button style={{ backgroundColor: 'red', color: 'darkRed', }}>
|
||||
Inaccessible button
|
||||
</button>
|
||||
<button style={{ backgroundColor: 'red', color: 'darkRed' }}>Inaccessible button</button>
|
||||
);
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
* Make UI accessible
|
||||
* Show in story where violations are.
|
||||
* Add more example tests
|
||||
* Add tests
|
||||
* Make CI integration possible
|
||||
- Make UI accessible
|
||||
- Show in story where violations are.
|
||||
- Add more example tests
|
||||
- Add tests
|
||||
- Make CI integration possible
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-a11y",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "a11y addon for storybook",
|
||||
"keywords": [
|
||||
"a11y",
|
||||
@ -20,24 +20,25 @@
|
||||
"directory": "addons/a11y"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/client-logger": "6.0.0-alpha.1",
|
||||
"@storybook/components": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/theming": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"@storybook/client-api": "6.0.0-alpha.6",
|
||||
"@storybook/client-logger": "6.0.0-alpha.6",
|
||||
"@storybook/components": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"@storybook/theming": "6.0.0-alpha.6",
|
||||
"axe-core": "^3.3.2",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
@ -46,12 +47,16 @@
|
||||
"react-redux": "^7.0.2",
|
||||
"react-sizeme": "^2.5.2",
|
||||
"redux": "^4.0.1",
|
||||
"ts-dedent": "^1.1.0",
|
||||
"ts-dedent": "^1.1.1",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-redux": "^7.0.6",
|
||||
"@types/webpack-env": "^1.15.0"
|
||||
"@types/webpack-env": "^1.15.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
1
addons/a11y/preset.js
Normal file
1
addons/a11y/preset.js
Normal file
@ -0,0 +1 @@
|
||||
module.exports = require('./dist/preset');
|
4
addons/a11y/src/preset/addDecorator.ts
Normal file
4
addons/a11y/src/preset/addDecorator.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { addDecorator } from '@storybook/client-api';
|
||||
import { withA11Y } from '../index';
|
||||
|
||||
addDecorator(withA11Y);
|
15
addons/a11y/src/preset/index.ts
Normal file
15
addons/a11y/src/preset/index.ts
Normal file
@ -0,0 +1,15 @@
|
||||
type A11yOptions = {
|
||||
addDecorator?: boolean;
|
||||
};
|
||||
|
||||
export function managerEntries(entry: any[] = []) {
|
||||
return [...entry, require.resolve('../register')];
|
||||
}
|
||||
|
||||
export function config(entry: any[] = [], { addDecorator = true }: A11yOptions = {}) {
|
||||
const a11yConfig = [];
|
||||
if (addDecorator) {
|
||||
a11yConfig.push(require.resolve('./addDecorator'));
|
||||
}
|
||||
return [...entry, ...a11yConfig];
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-actions",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "Action Logger addon for storybook",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -15,28 +15,28 @@
|
||||
"directory": "addons/actions"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/client-api": "6.0.0-alpha.1",
|
||||
"@storybook/components": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/theming": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"@storybook/client-api": "6.0.0-alpha.6",
|
||||
"@storybook/components": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"@storybook/theming": "6.0.0-alpha.6",
|
||||
"core-js": "^3.0.1",
|
||||
"fast-deep-equal": "^2.0.1",
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"global": "^4.3.2",
|
||||
"polished": "^3.3.1",
|
||||
"polished": "^3.4.4",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.8.3",
|
||||
"react-inspector": "^4.0.0",
|
||||
@ -44,8 +44,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.149",
|
||||
"@types/uuid": "^3.4.4",
|
||||
"@types/webpack-env": "^1.15.0"
|
||||
"@types/uuid": "^3.4.7",
|
||||
"@types/webpack-env": "^1.15.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-backgrounds",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "A storybook addon to show different backgrounds for your preview",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -19,24 +19,24 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "jbaxleyiii",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/client-logger": "6.0.0-alpha.1",
|
||||
"@storybook/components": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/theming": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"@storybook/client-logger": "6.0.0-alpha.6",
|
||||
"@storybook/components": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"@storybook/theming": "6.0.0-alpha.6",
|
||||
"core-js": "^3.0.1",
|
||||
"memoizerific": "^1.11.3",
|
||||
"react": "^16.8.3",
|
||||
@ -44,7 +44,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/util-deprecate": "^1.0.0",
|
||||
"@types/webpack-env": "^1.15.0"
|
||||
"@types/webpack-env": "^1.15.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-centered",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "Storybook decorator to center components",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -17,29 +17,33 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "Muhammed Thanish <mnmtanish@gmail.com>",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mithril": "^1.1.16",
|
||||
"@types/webpack-env": "^1.15.0",
|
||||
"@types/webpack-env": "^1.15.1",
|
||||
"mithril": "*",
|
||||
"preact": "*",
|
||||
"react": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"gitHead": "4b9d901add9452525135caae98ae5f78dd8da9ff"
|
||||
}
|
||||
|
@ -5,6 +5,17 @@ import parameters from './parameters';
|
||||
import styles from './styles';
|
||||
|
||||
function centered(storyFn: () => ReactNode) {
|
||||
/* eslint-disable no-undef */
|
||||
if (window) {
|
||||
const params = new URL(window.location.href).search;
|
||||
const isInDocsView = params.includes('viewMode=docs');
|
||||
|
||||
if (isInDocsView) {
|
||||
return storyFn();
|
||||
}
|
||||
}
|
||||
/* eslint-enable no-undef */
|
||||
|
||||
return (
|
||||
<div style={styles.style}>
|
||||
<div style={styles.innerStyle}>{storyFn()}</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-contexts",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "Storybook Addon Contexts",
|
||||
"keywords": [
|
||||
"preact",
|
||||
@ -15,22 +15,22 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "Leo Y. Li",
|
||||
"main": "dist/register.js",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/register.js",
|
||||
"scripts": {
|
||||
"dev:check-types": "tsc --noEmit",
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/components": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"@storybook/components": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
"qs": "^6.6.0"
|
||||
@ -41,8 +41,21 @@
|
||||
"qs": "*",
|
||||
"rax": "*",
|
||||
"react": "*",
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*",
|
||||
"vue": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"preact": {
|
||||
"optional": true
|
||||
},
|
||||
"rax": {
|
||||
"optional": true
|
||||
},
|
||||
"vue": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-cssresources",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "A storybook addon to switch between css resources at runtime for your story",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -19,32 +19,34 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "nm123github",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/components": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/theming": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"@storybook/components": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"@storybook/theming": "6.0.0-alpha.6",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
"react": "^16.8.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/webpack-env": "^1.15.0"
|
||||
"@types/webpack-env": "^1.15.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
"react": "*",
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-design-assets",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "Design asset preview for storybook",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -21,30 +21,34 @@
|
||||
"directory": "addons/design-assets"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/client-logger": "6.0.0-alpha.1",
|
||||
"@storybook/components": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/theming": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"@storybook/client-logger": "6.0.0-alpha.6",
|
||||
"@storybook/components": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"@storybook/theming": "6.0.0-alpha.6",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
"react": "^16.8.3",
|
||||
"ts-dedent": "^1.1.0",
|
||||
"ts-dedent": "^1.1.1",
|
||||
"use-image": "^1.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-docs",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "Superior documentation for your components",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -17,6 +17,8 @@
|
||||
"directory": "addons/docs"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/public_api.js",
|
||||
"types": "dist/public_api.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"angular/**/*",
|
||||
@ -31,28 +33,26 @@
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/public_api.js",
|
||||
"types": "dist/public_api.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/generator": "^7.4.0",
|
||||
"@babel/parser": "^7.4.2",
|
||||
"@babel/generator": "^7.8.4",
|
||||
"@babel/parser": "^7.8.4",
|
||||
"@babel/plugin-transform-react-jsx": "^7.3.0",
|
||||
"@egoist/vue-to-react": "^1.1.0",
|
||||
"@jest/transform": "^24.9.0",
|
||||
"@jest/transform": "^25.1.0",
|
||||
"@mdx-js/loader": "^1.5.1",
|
||||
"@mdx-js/mdx": "^1.5.1",
|
||||
"@mdx-js/react": "^1.5.1",
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/components": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"@storybook/components": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"@storybook/csf": "0.0.1",
|
||||
"@storybook/postinstall": "6.0.0-alpha.1",
|
||||
"@storybook/source-loader": "6.0.0-alpha.1",
|
||||
"@storybook/theming": "6.0.0-alpha.1",
|
||||
"@storybook/postinstall": "6.0.0-alpha.6",
|
||||
"@storybook/source-loader": "6.0.0-alpha.6",
|
||||
"@storybook/theming": "6.0.0-alpha.6",
|
||||
"acorn": "^7.1.0",
|
||||
"acorn-jsx": "^5.1.0",
|
||||
"acorn-walk": "^7.0.0",
|
||||
@ -67,7 +67,7 @@
|
||||
"react-element-to-jsx-string": "^14.1.0",
|
||||
"remark-external-links": "^5.0.0",
|
||||
"remark-slug": "^5.1.2",
|
||||
"ts-dedent": "^1.1.0",
|
||||
"ts-dedent": "^1.1.1",
|
||||
"util-deprecate": "^1.0.2",
|
||||
"vue-docgen-api": "^4.1.0",
|
||||
"vue-docgen-loader": "^1.3.0-beta.0"
|
||||
@ -75,15 +75,18 @@
|
||||
"devDependencies": {
|
||||
"@types/doctrine": "^0.0.3",
|
||||
"@types/enzyme": "^3.10.3",
|
||||
"@types/jest": "^24.0.11",
|
||||
"@types/jest": "^25.1.1",
|
||||
"@types/prop-types": "^15.5.9",
|
||||
"@types/util-deprecate": "^1.0.0",
|
||||
"jest-specific-snapshot": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0",
|
||||
"babel-loader": "^8.0.0",
|
||||
"react": "^16.8.0",
|
||||
"react-is": "^16.8.0"
|
||||
"react": "^16.9.0",
|
||||
"react-dom": "*",
|
||||
"react-is": "^16.8.0",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -11,7 +11,7 @@ function mapData(data) {
|
||||
type: { summary: item.type },
|
||||
required: '',
|
||||
description: item.description,
|
||||
defaultValue: { summary: item.defaultValue },
|
||||
defaultValue: { summary: item.default !== undefined ? item.default : item.defaultValue },
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-essentials",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "Curated addons to bring out the best of Storybook",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -17,30 +17,32 @@
|
||||
"directory": "addons/essentials"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addon-backgrounds": "6.0.0-alpha.1",
|
||||
"@storybook/addon-viewport": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/node-logger": "6.0.0-alpha.1",
|
||||
"ts-dedent": "^1.1.0"
|
||||
"@storybook/addon-backgrounds": "6.0.0-alpha.6",
|
||||
"@storybook/addon-viewport": "6.0.0-alpha.6",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"@storybook/node-logger": "6.0.0-alpha.6",
|
||||
"ts-dedent": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^24.0.11"
|
||||
"@types/jest": "^25.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"babel-loader": "^8.0.0",
|
||||
"react": "^16.8.0",
|
||||
"react-is": "^16.8.0"
|
||||
"react-dom": "*",
|
||||
"react-is": "^16.8.0",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-events",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "Add events to your Storybook stories.",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -18,23 +18,23 @@
|
||||
"directory": "addons/events"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/client-api": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/theming": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"@storybook/client-api": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"@storybook/theming": "6.0.0-alpha.6",
|
||||
"core-js": "^3.0.1",
|
||||
"format-json": "^1.0.3",
|
||||
"lodash": "^4.17.15",
|
||||
@ -45,10 +45,12 @@
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/webpack-env": "^1.15.0"
|
||||
"@types/webpack-env": "^1.15.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
"react": "*",
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-google-analytics",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "Storybook addon for google analytics",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -20,12 +20,16 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
"react-ga": "^2.5.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-graphql",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "Storybook addon to display the GraphiQL IDE",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -16,28 +16,30 @@
|
||||
"directory": "addons/graphql"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
"graphiql": "^0.16.0",
|
||||
"graphql": "^14.2.1",
|
||||
"graphiql": "^0.17.5",
|
||||
"graphql": "^14.6.0",
|
||||
"prop-types": "^15.7.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
"react": "*",
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -1,338 +0,0 @@
|
||||
# Storybook Info Addon
|
||||
|
||||
Storybook Info Addon will show additional information for your stories in [Storybook](https://storybook.js.org).
|
||||
Useful when you want to display usage or other types of documentation alongside your story.
|
||||
|
||||
[Framework Support](https://github.com/storybookjs/storybook/blob/master/ADDONS_SUPPORT.md)
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
Install the following npm module:
|
||||
|
||||
```sh
|
||||
npm i -D @storybook/addon-info
|
||||
```
|
||||
|
||||
## Basic usage
|
||||
|
||||
Then, add `withInfo` as a decorator to your book of stories.
|
||||
It is possible to add `info` by default to all or a subsection of stories by using a global or story decorator.
|
||||
|
||||
It is important to declare this decorator as **the first decorator**, otherwise it won't work well.
|
||||
|
||||
```js
|
||||
// Globally in your .storybook/preview.js.
|
||||
import { addDecorator } from '@storybook/react';
|
||||
import { withInfo } from '@storybook/addon-info';
|
||||
|
||||
addDecorator(withInfo);
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```js
|
||||
export default {
|
||||
title: 'Component',
|
||||
decorators: [withInfo],
|
||||
};
|
||||
```
|
||||
|
||||
Then, you can use the `info` parameter to either pass certain options or specific documentation text to your stories.
|
||||
A complete list of possible configurations can be found [in a later section](#setting-global-options).
|
||||
This can be done per book of stories:
|
||||
|
||||
```js
|
||||
import Component from './Component';
|
||||
|
||||
export default {
|
||||
title: 'Component',
|
||||
parameters: {
|
||||
info: {},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
...or for each story individually:
|
||||
|
||||
```js
|
||||
import Component from './Component';
|
||||
|
||||
export default {
|
||||
title: 'Component',
|
||||
};
|
||||
|
||||
export const defaultView = () => <Component />;
|
||||
defaultView = {
|
||||
parameters: {
|
||||
info: { inline: true },
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
It is also possible to disable the `info` addon entirely.
|
||||
Depending on the scope at which you want to disable the addon, pass the following parameters object either to an individual story or to an `addParameters` call.
|
||||
|
||||
```
|
||||
info: {
|
||||
disable: true,
|
||||
}
|
||||
```
|
||||
|
||||
## Markdown
|
||||
|
||||
The `info` addon also supports markdown.
|
||||
To use markdown as additional textual documentation for your stories, either pass it directly as a String to the `info` parameters, or use the `text` option.
|
||||
|
||||
```js
|
||||
info: {
|
||||
text: `
|
||||
description or documentation about my component, supports markdown
|
||||
|
||||
~~~js
|
||||
<Button>Click Here</Button>
|
||||
~~~
|
||||
`,
|
||||
}
|
||||
```
|
||||
|
||||
## Setting Global Options
|
||||
|
||||
To configure default options for all usage of the info addon, pass a option object along with the decorator in `.storybook/preview.js`.
|
||||
|
||||
```js
|
||||
import { withInfo } from '@storybook/addon-info';
|
||||
|
||||
addDecorator(
|
||||
withInfo({
|
||||
header: false,
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
Configuration parameters can be set at 3 different locations: passed as default options along the `addDecorator` call, passed as an object of parameters to a book of stories to the `addParameters` call, and passed as direct parameters to each individual story.
|
||||
In order, all of them will be combined together, with a later call overriding the previous set configurations on a per-key basis.
|
||||
|
||||
## Options and Defaults
|
||||
|
||||
```js
|
||||
{
|
||||
/**
|
||||
* Text to display with storybook component
|
||||
*/
|
||||
text?: string;
|
||||
/**
|
||||
* Displays info inline vs click button to view
|
||||
* @default false
|
||||
*/
|
||||
inline: boolean,
|
||||
/**
|
||||
* Toggles display of header with component name and description
|
||||
* @default true
|
||||
*/
|
||||
header: boolean,
|
||||
/**
|
||||
* Displays the source of story Component
|
||||
* @default true
|
||||
*/
|
||||
source: boolean,
|
||||
/**
|
||||
* Components used in story
|
||||
* Displays Prop Tables with these components
|
||||
* @default []
|
||||
*/
|
||||
propTables: Array<React.ComponentType>,
|
||||
/**
|
||||
* Exclude Components from being shown in Prop Tables section
|
||||
* Accepts an array of component classes or functions
|
||||
* @default []
|
||||
*/
|
||||
propTablesExclude: Array<React.ComponentType>,
|
||||
/**
|
||||
* Overrides styles of addon. The object should follow this shape:
|
||||
* https://github.com/storybookjs/storybook/blob/master/addons/info/src/components/Story.js#L19.
|
||||
* This prop can also accept a function which has the default stylesheet passed as an argument
|
||||
*/
|
||||
styles: Object | Function,
|
||||
/**
|
||||
* Overrides components used to display markdown
|
||||
* @default {}
|
||||
*/
|
||||
components: { [key: string]: React.ComponentType },
|
||||
/**
|
||||
* Max props to display per line in source code
|
||||
* @default 3
|
||||
*/
|
||||
maxPropsIntoLine: number,
|
||||
/**
|
||||
* Displays the first 10 characters of the prop name
|
||||
* @default 3
|
||||
*/
|
||||
maxPropObjectKeys: number,
|
||||
/**
|
||||
* Displays the first 10 items in the default prop array
|
||||
* @default 3
|
||||
*/
|
||||
maxPropArrayLength: number,
|
||||
/**
|
||||
* Displays the first 100 characters in the default prop string
|
||||
* @default 50
|
||||
*/
|
||||
maxPropStringLength: number,
|
||||
/**
|
||||
* Override the component used to render the props table
|
||||
* @default PropTable
|
||||
*/
|
||||
TableComponent: React.ComponentType,
|
||||
/**
|
||||
* Will exclude any respective properties whose name is included in array
|
||||
* @default []
|
||||
*/
|
||||
excludedPropTypes: Array<string>,
|
||||
}
|
||||
```
|
||||
|
||||
### Rendering a Custom Table
|
||||
|
||||
The `TableComponent` option allows you to define how the prop table should be rendered. Your component will be rendered with the following props.
|
||||
|
||||
```js
|
||||
{
|
||||
propDefinitions: Array<{
|
||||
property: string, // The name of the prop
|
||||
propType: Object | string, // The prop type. TODO: info about what this object is...
|
||||
required: boolean, // True if the prop is required
|
||||
description: string, // The description of the prop
|
||||
defaultValue: any // The default value of the prop
|
||||
}>
|
||||
}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
// button.js
|
||||
// @flow
|
||||
import React from 'react';
|
||||
|
||||
const paddingStyles = {
|
||||
small: '4px 8px',
|
||||
medium: '8px 16px',
|
||||
};
|
||||
|
||||
const Button = ({
|
||||
size,
|
||||
...rest
|
||||
}: {
|
||||
/** The size of the button */
|
||||
size: 'small' | 'medium',
|
||||
}) => {
|
||||
const style = {
|
||||
padding: paddingStyles[size] || '',
|
||||
};
|
||||
return <button style={style} {...rest} />;
|
||||
};
|
||||
Button.defaultProps = {
|
||||
size: 'medium',
|
||||
};
|
||||
|
||||
export default Button;
|
||||
```
|
||||
|
||||
```js
|
||||
// stories.js
|
||||
import React from 'react';
|
||||
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import Button from './button';
|
||||
|
||||
export default {
|
||||
title: 'Button',
|
||||
component: Button,
|
||||
parameters: {
|
||||
info: TableComponent,
|
||||
},
|
||||
};
|
||||
|
||||
const Red = props => <span style={{ color: 'red' }} {...props} />;
|
||||
|
||||
const TableComponent = ({ propDefinitions }) => {
|
||||
const props = propDefinitions.map(
|
||||
({ property, propType, required, description, defaultValue }) => {
|
||||
return (
|
||||
<tr key={property}>
|
||||
<td>
|
||||
{property}
|
||||
{required ? <Red>*</Red> : null}
|
||||
</td>
|
||||
<td>{propType.name}</td>
|
||||
<td>{defaultValue}</td>
|
||||
<td>{description}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>name</th>
|
||||
<th>type</th>
|
||||
<th>default</th>
|
||||
<th>description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>{props}</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
||||
|
||||
export const defaultView = () => <Button />;
|
||||
```
|
||||
|
||||
### React Docgen Integration
|
||||
|
||||
React Docgen is included as part of the @storybook/react package through the use of `babel-plugin-react-docgen` during babel compile time.
|
||||
When rendering a story with a React component commented in this supported format, the Addon Info description will render the comments above the component declaration and the prop table will display the prop's comment in the description column.
|
||||
|
||||
```js
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/** Button component description */
|
||||
const DocgenButton = ({ disabled, label, style, onClick }) => (
|
||||
<button disabled={disabled} style={style} onClick={onClick}>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
|
||||
DocgenButton.defaultProps = {
|
||||
disabled: false,
|
||||
onClick: () => {},
|
||||
style: {},
|
||||
};
|
||||
|
||||
DocgenButton.propTypes = {
|
||||
/** Boolean indicating whether the button should render as disabled */
|
||||
disabled: PropTypes.bool,
|
||||
/** button label. */
|
||||
label: PropTypes.string.isRequired,
|
||||
/** onClick handler */
|
||||
onClick: PropTypes.func,
|
||||
/** component styles */
|
||||
style: PropTypes.shape,
|
||||
};
|
||||
|
||||
export default DocgenButton;
|
||||
```
|
||||
|
||||
Comments above flow types are also supported. Storybook Info Addon should now render all the correct types for your component if the PropTypes are in the same file as the React component.
|
||||
|
||||
## The FAQ
|
||||
|
||||
**Components lose their names on static build**
|
||||
|
||||
Component names also get minified with other javascript code when building for production.
|
||||
When creating components, set the `displayName` static property to show the correct component name on static builds.
|
Binary file not shown.
Before Width: | Height: | Size: 122 KiB |
@ -1,56 +0,0 @@
|
||||
{
|
||||
"name": "@storybook/addon-info",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"description": "A Storybook addon to show additional information for your stories.",
|
||||
"keywords": [
|
||||
"addon",
|
||||
"storybook"
|
||||
],
|
||||
"homepage": "https://github.com/storybookjs/storybook/tree/master/addons/info",
|
||||
"bugs": {
|
||||
"url": "https://github.com/storybookjs/storybook/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/storybookjs/storybook.git",
|
||||
"directory": "addons/info"
|
||||
},
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/client-logger": "6.0.0-alpha.1",
|
||||
"@storybook/components": "6.0.0-alpha.1",
|
||||
"@storybook/theming": "6.0.0-alpha.1",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
"marksy": "^8.0.0",
|
||||
"nested-object-assign": "^1.0.3",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.8.3",
|
||||
"react-addons-create-fragment": "^15.6.2",
|
||||
"react-element-to-jsx-string": "^14.0.2",
|
||||
"react-is": "^16.8.3",
|
||||
"react-lifecycles-compat": "^3.0.4",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react-test-renderer": "^16.8.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"gitHead": "4b9d901add9452525135caae98ae5f78dd8da9ff"
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
import PropVal from './PropVal';
|
||||
import PrettyPropType from './types/PrettyPropType';
|
||||
|
||||
const Table = props => <table {...props} />;
|
||||
const Td = props => <td style={{ paddingRight: 10, verticalAlign: 'top' }} {...props} />;
|
||||
const Tr = props => <tr {...props} />;
|
||||
const Th = props => <th style={{ textAlign: 'left', verticalAlign: 'top' }} {...props} />;
|
||||
const Tbody = props => <tbody {...props} />;
|
||||
const Thead = props => <thead {...props} />;
|
||||
|
||||
export const multiLineText = input => {
|
||||
if (!input) {
|
||||
return input;
|
||||
}
|
||||
const text = String(input);
|
||||
const arrayOfText = text.split(/\r?\n|\r/g);
|
||||
const isSingleLine = arrayOfText.length < 2;
|
||||
return isSingleLine
|
||||
? text
|
||||
: arrayOfText.map((lineOfText, i) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<span key={`${lineOfText}.${i}`}>
|
||||
{i > 0 && <br />} {lineOfText}
|
||||
</span>
|
||||
));
|
||||
};
|
||||
|
||||
const determineIncludedPropTypes = (propDefinitions, excludedPropTypes) => {
|
||||
if (excludedPropTypes.length === 0) {
|
||||
return propDefinitions;
|
||||
}
|
||||
|
||||
return propDefinitions.filter(
|
||||
propDefinition => !excludedPropTypes.includes(propDefinition.property)
|
||||
);
|
||||
};
|
||||
|
||||
export default function PropTable(props) {
|
||||
const {
|
||||
type,
|
||||
maxPropObjectKeys,
|
||||
maxPropArrayLength,
|
||||
maxPropStringLength,
|
||||
propDefinitions,
|
||||
excludedPropTypes,
|
||||
} = props;
|
||||
|
||||
if (!type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const includedPropDefinitions = determineIncludedPropTypes(propDefinitions, excludedPropTypes);
|
||||
|
||||
if (!includedPropDefinitions.length) {
|
||||
return <small>No propTypes defined!</small>;
|
||||
}
|
||||
|
||||
const propValProps = {
|
||||
maxPropObjectKeys,
|
||||
maxPropArrayLength,
|
||||
maxPropStringLength,
|
||||
};
|
||||
|
||||
return (
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>property</Th>
|
||||
<Th>propType</Th>
|
||||
<Th>required</Th>
|
||||
<Th>default</Th>
|
||||
<Th>description</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{includedPropDefinitions.map(row => (
|
||||
<Tr key={row.property}>
|
||||
<Td>{row.property}</Td>
|
||||
<Td>
|
||||
<PrettyPropType propType={row.propType} />
|
||||
</Td>
|
||||
<Td>{row.required ? 'yes' : '-'}</Td>
|
||||
<Td>
|
||||
{row.defaultValue === undefined ? (
|
||||
'-'
|
||||
) : (
|
||||
<PropVal val={row.defaultValue} {...propValProps} valueStyles={{}} />
|
||||
)}
|
||||
</Td>
|
||||
<Td>{multiLineText(row.description)}</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
|
||||
PropTable.displayName = 'PropTable';
|
||||
PropTable.defaultProps = {
|
||||
type: null,
|
||||
propDefinitions: [],
|
||||
excludedPropTypes: [],
|
||||
};
|
||||
PropTable.propTypes = {
|
||||
type: PropTypes.func,
|
||||
maxPropObjectKeys: PropTypes.number.isRequired,
|
||||
maxPropArrayLength: PropTypes.number.isRequired,
|
||||
maxPropStringLength: PropTypes.number.isRequired,
|
||||
excludedPropTypes: PropTypes.arrayOf(PropTypes.string),
|
||||
propDefinitions: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
property: PropTypes.string.isRequired,
|
||||
propType: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
|
||||
required: PropTypes.bool,
|
||||
description: PropTypes.string,
|
||||
defaultValue: PropTypes.any,
|
||||
})
|
||||
),
|
||||
};
|
@ -1,71 +0,0 @@
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import PropTable, { multiLineText } from './PropTable';
|
||||
|
||||
describe('PropTable', () => {
|
||||
describe('multiLineText', () => {
|
||||
const singleLine = 'Foo bar baz';
|
||||
const unixMultiLineText = 'foo \n bar \n baz';
|
||||
const windowsMultiLineText = 'foo \r bar \r baz';
|
||||
const duplicatedMultiLine = 'foo\nfoo\nfoo';
|
||||
const propDefinitions = [
|
||||
{
|
||||
defaultValue: undefined,
|
||||
description: '',
|
||||
propType: { name: 'string' },
|
||||
property: 'foo',
|
||||
required: false,
|
||||
},
|
||||
];
|
||||
const FooComponent = () => <div />;
|
||||
const propTableProps = {
|
||||
type: FooComponent,
|
||||
maxPropArrayLength: 5,
|
||||
maxPropObjectKeys: 5,
|
||||
maxPropStringLength: 5,
|
||||
propDefinitions,
|
||||
};
|
||||
|
||||
it('should include all propTypes by default', () => {
|
||||
const wrapper = shallow(<PropTable {...propTableProps} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should exclude excluded propTypes', () => {
|
||||
const props = { ...propTableProps, excludedPropTypes: ['foo'] };
|
||||
const wrapper = shallow(<PropTable {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should return a blank string for a null input', () => {
|
||||
expect(multiLineText(null)).toBe(null);
|
||||
});
|
||||
it('should return a blank string for an undefined input', () => {
|
||||
expect(multiLineText(undefined)).toBe(undefined);
|
||||
});
|
||||
it('should cast a number to a string', () => {
|
||||
expect(multiLineText(1)).toBe('1');
|
||||
});
|
||||
it('should return its input for a single line of text', () => {
|
||||
expect(multiLineText(singleLine)).toBe(singleLine);
|
||||
});
|
||||
it('should return an array for unix multiline text', () => {
|
||||
expect(multiLineText(unixMultiLineText)).toHaveLength(3);
|
||||
});
|
||||
it('should return an array for windows multiline text', () => {
|
||||
expect(multiLineText(windowsMultiLineText)).toHaveLength(3);
|
||||
});
|
||||
it('should return an array with unique keys for duplicated multiline text', () => {
|
||||
const wrappers = multiLineText(duplicatedMultiLine).map(tag => shallow(tag));
|
||||
const keys = wrappers.map(wrapper => wrapper.key());
|
||||
const deDup = new Set(keys);
|
||||
expect(keys).toHaveLength(deDup.size);
|
||||
});
|
||||
it('should have 2 br tags for 3 lines of text', () => {
|
||||
const tree = renderer.create(multiLineText(unixMultiLineText)).toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
@ -1,86 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PropTable multiLineText should exclude excluded propTypes 1`] = `
|
||||
<small>
|
||||
No propTypes defined!
|
||||
</small>
|
||||
`;
|
||||
|
||||
exports[`PropTable multiLineText should have 2 br tags for 3 lines of text 1`] = `
|
||||
Array [
|
||||
<span>
|
||||
|
||||
foo
|
||||
</span>,
|
||||
<span>
|
||||
<br />
|
||||
|
||||
bar
|
||||
</span>,
|
||||
<span>
|
||||
<br />
|
||||
|
||||
baz
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`PropTable multiLineText should include all propTypes by default 1`] = `
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>
|
||||
property
|
||||
</Th>
|
||||
<Th>
|
||||
propType
|
||||
</Th>
|
||||
<Th>
|
||||
required
|
||||
</Th>
|
||||
<Th>
|
||||
default
|
||||
</Th>
|
||||
<Th>
|
||||
description
|
||||
</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
<Tr
|
||||
key="foo"
|
||||
>
|
||||
<Td
|
||||
isMonospace={true}
|
||||
>
|
||||
foo
|
||||
</Td>
|
||||
<Td
|
||||
isMonospace={true}
|
||||
>
|
||||
<PrettyPropType
|
||||
depth={1}
|
||||
propType={
|
||||
Object {
|
||||
"name": "string",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Td>
|
||||
<Td
|
||||
isMonospace={false}
|
||||
>
|
||||
-
|
||||
</Td>
|
||||
<Td
|
||||
isMonospace={false}
|
||||
>
|
||||
-
|
||||
</Td>
|
||||
<Td
|
||||
isMonospace={false}
|
||||
/>
|
||||
</Tr>
|
||||
</Tbody>
|
||||
</Table>
|
||||
`;
|
@ -1,12 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import '../style.css';
|
||||
|
||||
const Table = ({ children }) => <table className="info-table">{children}</table>;
|
||||
|
||||
Table.propTypes = {
|
||||
children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)])
|
||||
.isRequired,
|
||||
};
|
||||
|
||||
export default Table;
|
@ -1,25 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import Table from './Table';
|
||||
|
||||
describe('PropTable/Table', () => {
|
||||
it('renders a table html node with one child element', () => {
|
||||
const wrapper = shallow(
|
||||
<Table>
|
||||
<div>foo bar</div>
|
||||
</Table>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a table html node with multiple children elements', () => {
|
||||
const wrapper = shallow(
|
||||
<Table>
|
||||
<div>foo bar</div>
|
||||
<div>baz</div>
|
||||
</Table>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -1,11 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
const Tbody = ({ children }) => <tbody>{children}</tbody>;
|
||||
|
||||
Tbody.propTypes = {
|
||||
children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)])
|
||||
.isRequired,
|
||||
};
|
||||
|
||||
export default Tbody;
|
@ -1,25 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import Tbody from './Tbody';
|
||||
|
||||
describe('PropTable/Tbody', () => {
|
||||
it('renders a tbody html node with children', () => {
|
||||
const wrapper = shallow(
|
||||
<Tbody>
|
||||
<div>foo bar</div>
|
||||
</Tbody>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a tbody html node with multiple children elements', () => {
|
||||
const wrapper = shallow(
|
||||
<Tbody>
|
||||
<div>foo bar</div>
|
||||
<div>baz</div>
|
||||
</Tbody>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -1,24 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import '../style.css';
|
||||
|
||||
const Td = ({ isMonospace, children }) => (
|
||||
<td className={isMonospace ? 'info-table-monospace' : null}>{children}</td>
|
||||
);
|
||||
|
||||
Td.propTypes = {
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.node,
|
||||
PropTypes.element,
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.arrayOf(PropTypes.element),
|
||||
]),
|
||||
isMonospace: PropTypes.bool,
|
||||
};
|
||||
|
||||
Td.defaultProps = {
|
||||
isMonospace: false,
|
||||
children: null,
|
||||
};
|
||||
|
||||
export default Td;
|
@ -1,54 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import Td from './Td';
|
||||
|
||||
describe('PropTable/Td', () => {
|
||||
it('renders a td html node child element', () => {
|
||||
const wrapper = shallow(
|
||||
<Td>
|
||||
<div>foo bar</div>
|
||||
</Td>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a monospace td html node child element', () => {
|
||||
const wrapper = shallow(
|
||||
<Td isMonospace>
|
||||
<div>foo bar</div>
|
||||
</Td>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a td html node with multiple children elements', () => {
|
||||
const wrapper = shallow(
|
||||
<Td>
|
||||
<div>foo bar</div>
|
||||
<div>baz</div>
|
||||
</Td>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a monospace td html node with multiple children elements', () => {
|
||||
const wrapper = shallow(
|
||||
<Td isMonospace>
|
||||
<div>foo bar</div>
|
||||
<div>baz</div>
|
||||
</Td>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a td html node with one child node', () => {
|
||||
const wrapper = shallow(<Td>foo bar</Td>);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a monospace td html node with one child node', () => {
|
||||
const wrapper = shallow(<Td isMonospace>foo bar</Td>);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -1,15 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
const Th = ({ children }) => <th>{children}</th>;
|
||||
|
||||
Th.propTypes = {
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.node,
|
||||
PropTypes.element,
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.arrayOf(PropTypes.element),
|
||||
]).isRequired,
|
||||
};
|
||||
|
||||
export default Th;
|
@ -1,26 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import Th from './Th';
|
||||
|
||||
describe('PropTable/Th', () => {
|
||||
it('renders a th html node with react element children', () => {
|
||||
const wrapper = shallow(
|
||||
<Th>
|
||||
<div>foo bar</div>
|
||||
<div>baz</div>
|
||||
</Th>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a th html node with html node children', () => {
|
||||
const wrapper = shallow(<Th>foo bar baz</Th>);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a th html node with one child node', () => {
|
||||
const wrapper = shallow(<Th>foo bar</Th>);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -1,11 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
const Thead = ({ children }) => <thead>{children}</thead>;
|
||||
|
||||
Thead.propTypes = {
|
||||
children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)])
|
||||
.isRequired,
|
||||
};
|
||||
|
||||
export default Thead;
|
@ -1,25 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import Thead from './Thead';
|
||||
|
||||
describe('PropTable/Thead', () => {
|
||||
it('renders a thead html node with children', () => {
|
||||
const wrapper = shallow(
|
||||
<Thead>
|
||||
<div>foo bar</div>
|
||||
</Thead>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a thead html node with multiple children elements', () => {
|
||||
const wrapper = shallow(
|
||||
<Thead>
|
||||
<div>foo bar</div>
|
||||
<div>baz</div>
|
||||
</Thead>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -1,10 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
const Tr = ({ children }) => <tr>{children}</tr>;
|
||||
|
||||
Tr.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export default Tr;
|
@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import Tr from './Tr';
|
||||
import Td from './Td';
|
||||
|
||||
describe('PropTable/Tr', () => {
|
||||
it('renders a tr html node with react element children', () => {
|
||||
const wrapper = shallow(
|
||||
<Tr>
|
||||
<Td>foo bar</Td>
|
||||
<Td>baz</Td>
|
||||
</Tr>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a tr html node with html node children', () => {
|
||||
const wrapper = shallow(<Tr>foo bar baz</Tr>);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a tr html node with one child node', () => {
|
||||
const wrapper = shallow(<Tr>foo bar</Tr>);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -1,24 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PropTable/Table renders a table html node with multiple children elements 1`] = `
|
||||
<table
|
||||
className="info-table"
|
||||
>
|
||||
<div>
|
||||
foo bar
|
||||
</div>
|
||||
<div>
|
||||
baz
|
||||
</div>
|
||||
</table>
|
||||
`;
|
||||
|
||||
exports[`PropTable/Table renders a table html node with one child element 1`] = `
|
||||
<table
|
||||
className="info-table"
|
||||
>
|
||||
<div>
|
||||
foo bar
|
||||
</div>
|
||||
</table>
|
||||
`;
|
@ -1,20 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PropTable/Tbody renders a tbody html node with children 1`] = `
|
||||
<tbody>
|
||||
<div>
|
||||
foo bar
|
||||
</div>
|
||||
</tbody>
|
||||
`;
|
||||
|
||||
exports[`PropTable/Tbody renders a tbody html node with multiple children elements 1`] = `
|
||||
<tbody>
|
||||
<div>
|
||||
foo bar
|
||||
</div>
|
||||
<div>
|
||||
baz
|
||||
</div>
|
||||
</tbody>
|
||||
`;
|
@ -1,63 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PropTable/Td renders a monospace td html node child element 1`] = `
|
||||
<td
|
||||
className="info-table-monospace"
|
||||
>
|
||||
<div>
|
||||
foo bar
|
||||
</div>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`PropTable/Td renders a monospace td html node with multiple children elements 1`] = `
|
||||
<td
|
||||
className="info-table-monospace"
|
||||
>
|
||||
<div>
|
||||
foo bar
|
||||
</div>
|
||||
<div>
|
||||
baz
|
||||
</div>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`PropTable/Td renders a monospace td html node with one child node 1`] = `
|
||||
<td
|
||||
className="info-table-monospace"
|
||||
>
|
||||
foo bar
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`PropTable/Td renders a td html node child element 1`] = `
|
||||
<td
|
||||
className={null}
|
||||
>
|
||||
<div>
|
||||
foo bar
|
||||
</div>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`PropTable/Td renders a td html node with multiple children elements 1`] = `
|
||||
<td
|
||||
className={null}
|
||||
>
|
||||
<div>
|
||||
foo bar
|
||||
</div>
|
||||
<div>
|
||||
baz
|
||||
</div>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`PropTable/Td renders a td html node with one child node 1`] = `
|
||||
<td
|
||||
className={null}
|
||||
>
|
||||
foo bar
|
||||
</td>
|
||||
`;
|
@ -1,24 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PropTable/Th renders a th html node with html node children 1`] = `
|
||||
<th>
|
||||
foo bar baz
|
||||
</th>
|
||||
`;
|
||||
|
||||
exports[`PropTable/Th renders a th html node with one child node 1`] = `
|
||||
<th>
|
||||
foo bar
|
||||
</th>
|
||||
`;
|
||||
|
||||
exports[`PropTable/Th renders a th html node with react element children 1`] = `
|
||||
<th>
|
||||
<div>
|
||||
foo bar
|
||||
</div>
|
||||
<div>
|
||||
baz
|
||||
</div>
|
||||
</th>
|
||||
`;
|
@ -1,20 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PropTable/Thead renders a thead html node with children 1`] = `
|
||||
<thead>
|
||||
<div>
|
||||
foo bar
|
||||
</div>
|
||||
</thead>
|
||||
`;
|
||||
|
||||
exports[`PropTable/Thead renders a thead html node with multiple children elements 1`] = `
|
||||
<thead>
|
||||
<div>
|
||||
foo bar
|
||||
</div>
|
||||
<div>
|
||||
baz
|
||||
</div>
|
||||
</thead>
|
||||
`;
|
@ -1,28 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PropTable/Tr renders a tr html node with html node children 1`] = `
|
||||
<tr>
|
||||
foo bar baz
|
||||
</tr>
|
||||
`;
|
||||
|
||||
exports[`PropTable/Tr renders a tr html node with one child node 1`] = `
|
||||
<tr>
|
||||
foo bar
|
||||
</tr>
|
||||
`;
|
||||
|
||||
exports[`PropTable/Tr renders a tr html node with react element children 1`] = `
|
||||
<tr>
|
||||
<Td
|
||||
isMonospace={false}
|
||||
>
|
||||
foo bar
|
||||
</Td>
|
||||
<Td
|
||||
isMonospace={false}
|
||||
>
|
||||
baz
|
||||
</Td>
|
||||
</tr>
|
||||
`;
|
@ -1,121 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
import PrettyPropType from '../types/PrettyPropType';
|
||||
import PropVal from '../PropVal';
|
||||
import Table from './components/Table';
|
||||
import Tbody from './components/Tbody';
|
||||
import Td from './components/Td';
|
||||
import Th from './components/Th';
|
||||
import Thead from './components/Thead';
|
||||
import Tr from './components/Tr';
|
||||
|
||||
export const multiLineText = input => {
|
||||
if (!input) {
|
||||
return input;
|
||||
}
|
||||
const text = String(input);
|
||||
const arrayOfText = text.split(/\r?\n|\r/g);
|
||||
const isSingleLine = arrayOfText.length < 2;
|
||||
return isSingleLine
|
||||
? text
|
||||
: arrayOfText.map((lineOfText, i) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<span key={`${lineOfText}.${i}`}>
|
||||
{i > 0 && <br />} {lineOfText}
|
||||
</span>
|
||||
));
|
||||
};
|
||||
|
||||
const determineIncludedPropTypes = (propDefinitions, excludedPropTypes) => {
|
||||
if (excludedPropTypes.length === 0) {
|
||||
return propDefinitions;
|
||||
}
|
||||
|
||||
return propDefinitions.filter(
|
||||
propDefinition => !excludedPropTypes.includes(propDefinition.property)
|
||||
);
|
||||
};
|
||||
|
||||
export default function PropTable(props) {
|
||||
const {
|
||||
type,
|
||||
maxPropObjectKeys,
|
||||
maxPropArrayLength,
|
||||
maxPropStringLength,
|
||||
propDefinitions,
|
||||
excludedPropTypes,
|
||||
} = props;
|
||||
|
||||
if (!type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const includedPropDefinitions = determineIncludedPropTypes(propDefinitions, excludedPropTypes);
|
||||
|
||||
if (!includedPropDefinitions.length) {
|
||||
return <small>No propTypes defined!</small>;
|
||||
}
|
||||
|
||||
const propValProps = {
|
||||
maxPropObjectKeys,
|
||||
maxPropArrayLength,
|
||||
maxPropStringLength,
|
||||
};
|
||||
|
||||
return (
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>property</Th>
|
||||
<Th>propType</Th>
|
||||
<Th>required</Th>
|
||||
<Th>default</Th>
|
||||
<Th>description</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{includedPropDefinitions.map(row => (
|
||||
<Tr key={row.property}>
|
||||
<Td isMonospace>{row.property}</Td>
|
||||
<Td isMonospace>
|
||||
<PrettyPropType propType={row.propType} />
|
||||
</Td>
|
||||
<Td>{row.required ? 'yes' : '-'}</Td>
|
||||
<Td>
|
||||
{row.defaultValue === undefined ? (
|
||||
'-'
|
||||
) : (
|
||||
<PropVal val={row.defaultValue} {...propValProps} valueStyles={{}} />
|
||||
)}
|
||||
</Td>
|
||||
<Td>{multiLineText(row.description)}</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
|
||||
PropTable.displayName = 'PropTable';
|
||||
PropTable.defaultProps = {
|
||||
type: null,
|
||||
propDefinitions: [],
|
||||
excludedPropTypes: [],
|
||||
};
|
||||
PropTable.propTypes = {
|
||||
type: PropTypes.func,
|
||||
maxPropObjectKeys: PropTypes.number.isRequired,
|
||||
maxPropArrayLength: PropTypes.number.isRequired,
|
||||
maxPropStringLength: PropTypes.number.isRequired,
|
||||
excludedPropTypes: PropTypes.arrayOf(PropTypes.string),
|
||||
propDefinitions: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
property: PropTypes.string.isRequired,
|
||||
propType: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
|
||||
required: PropTypes.bool,
|
||||
description: PropTypes.string,
|
||||
defaultValue: PropTypes.any,
|
||||
})
|
||||
),
|
||||
};
|
@ -1,78 +0,0 @@
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import PropTable, { multiLineText } from './index';
|
||||
|
||||
describe('PropTable', () => {
|
||||
describe('multiLineText', () => {
|
||||
const singleLine = 'Foo bar baz';
|
||||
const unixMultiLineText = 'foo \n bar \n baz';
|
||||
const windowsMultiLineText = 'foo \r bar \r baz';
|
||||
const duplicatedMultiLine = 'foo\nfoo\nfoo';
|
||||
const propDefinitions = [
|
||||
{
|
||||
defaultValue: undefined,
|
||||
description: '',
|
||||
propType: { name: 'string' },
|
||||
property: 'foo',
|
||||
required: false,
|
||||
},
|
||||
];
|
||||
const FooComponent = () => <div />;
|
||||
const propTableProps = {
|
||||
type: FooComponent,
|
||||
maxPropArrayLength: 5,
|
||||
maxPropObjectKeys: 5,
|
||||
maxPropStringLength: 5,
|
||||
propDefinitions,
|
||||
};
|
||||
|
||||
it('should include all propTypes by default', () => {
|
||||
const wrapper = shallow(<PropTable {...propTableProps} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should exclude excluded propTypes', () => {
|
||||
const props = { ...propTableProps, excludedPropTypes: ['foo'] };
|
||||
const wrapper = shallow(<PropTable {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should return a blank string for a null input', () => {
|
||||
expect(multiLineText(null)).toBe(null);
|
||||
});
|
||||
|
||||
it('should return a blank string for an undefined input', () => {
|
||||
expect(multiLineText(undefined)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should cast a number to a string', () => {
|
||||
expect(multiLineText(1)).toBe('1');
|
||||
});
|
||||
|
||||
it('should return its input for a single line of text', () => {
|
||||
expect(multiLineText(singleLine)).toBe(singleLine);
|
||||
});
|
||||
|
||||
it('should return an array for unix multiline text', () => {
|
||||
expect(multiLineText(unixMultiLineText)).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('should return an array for windows multiline text', () => {
|
||||
expect(multiLineText(windowsMultiLineText)).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('should return an array with unique keys for duplicated multiline text', () => {
|
||||
const wrappers = multiLineText(duplicatedMultiLine).map(tag => shallow(tag));
|
||||
const keys = wrappers.map(wrapper => wrapper.key());
|
||||
const deDup = new Set(keys);
|
||||
expect(keys).toHaveLength(deDup.size);
|
||||
});
|
||||
|
||||
it('should have 2 br tags for 3 lines of text', () => {
|
||||
const tree = renderer.create(multiLineText(unixMultiLineText)).toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
@ -1,19 +0,0 @@
|
||||
.info-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.info-table, .info-table td, .info-table th {
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #cccccc;
|
||||
color: #444444;
|
||||
margin-top: 0.25rem;
|
||||
padding-right: 0.5rem;
|
||||
padding: 0.25rem;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.info-table-monospace {
|
||||
font-family: Menlo, Monaco, "Courier New", monospace;
|
||||
font-size: 0.88em;
|
||||
}
|
@ -1,274 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import createFragment from 'react-addons-create-fragment';
|
||||
|
||||
const getValueStyles = (codeColors = {}) => ({
|
||||
func: {
|
||||
color: codeColors.func || '#170',
|
||||
},
|
||||
|
||||
attr: {
|
||||
color: codeColors.attr || '#666',
|
||||
},
|
||||
|
||||
object: {
|
||||
color: codeColors.object || '#666',
|
||||
},
|
||||
|
||||
array: {
|
||||
color: codeColors.array || '#666',
|
||||
},
|
||||
|
||||
number: {
|
||||
color: codeColors.number || '#a11',
|
||||
},
|
||||
|
||||
string: {
|
||||
color: codeColors.string || '#22a',
|
||||
wordBreak: 'break-word',
|
||||
},
|
||||
|
||||
bool: {
|
||||
color: codeColors.bool || '#a11',
|
||||
},
|
||||
|
||||
empty: {
|
||||
color: '#444',
|
||||
},
|
||||
});
|
||||
|
||||
function indent(breakIntoNewLines, level, isBlock) {
|
||||
return (
|
||||
breakIntoNewLines && (
|
||||
<span>
|
||||
<br />
|
||||
{`${Array(level).join(' ')} `}
|
||||
{!isBlock && ' '}
|
||||
</span>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function PreviewArray({
|
||||
val,
|
||||
level,
|
||||
maxPropArrayLength,
|
||||
maxPropStringLength,
|
||||
maxPropsIntoLine,
|
||||
valueStyles,
|
||||
}) {
|
||||
const items = {};
|
||||
const breakIntoNewLines = val.length > maxPropsIntoLine;
|
||||
val.slice(0, maxPropArrayLength).forEach((item, i) => {
|
||||
items[`n${i}`] = (
|
||||
<span>
|
||||
{indent(breakIntoNewLines, level)}
|
||||
<PropVal
|
||||
val={item}
|
||||
level={level + 1}
|
||||
valueStyles={valueStyles}
|
||||
maxPropStringLength={maxPropStringLength}
|
||||
maxPropsIntoLine={maxPropsIntoLine}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
items[`c${i}`] = ',';
|
||||
});
|
||||
if (val.length > maxPropArrayLength) {
|
||||
items.last = <span>{indent(breakIntoNewLines, level)}…</span>;
|
||||
} else {
|
||||
delete items[`c${val.length - 1}`];
|
||||
}
|
||||
|
||||
return (
|
||||
<span style={valueStyles.array}>
|
||||
[{createFragment(items)}
|
||||
{indent(breakIntoNewLines, level, true)}]
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
PreviewArray.propTypes = {
|
||||
val: PropTypes.any, // eslint-disable-line
|
||||
maxPropArrayLength: PropTypes.number.isRequired,
|
||||
maxPropStringLength: PropTypes.number.isRequired,
|
||||
maxPropsIntoLine: PropTypes.number.isRequired,
|
||||
level: PropTypes.number.isRequired,
|
||||
valueStyles: PropTypes.shape({
|
||||
func: PropTypes.object,
|
||||
attr: PropTypes.object,
|
||||
object: PropTypes.object,
|
||||
array: PropTypes.object,
|
||||
number: PropTypes.object,
|
||||
string: PropTypes.object,
|
||||
bool: PropTypes.object,
|
||||
empty: PropTypes.object,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
function PreviewObject({
|
||||
val,
|
||||
level,
|
||||
maxPropObjectKeys,
|
||||
maxPropStringLength,
|
||||
maxPropsIntoLine,
|
||||
valueStyles,
|
||||
}) {
|
||||
const names = Object.keys(val);
|
||||
const items = {};
|
||||
const breakIntoNewLines = names.length > maxPropsIntoLine;
|
||||
names.slice(0, maxPropObjectKeys).forEach((name, i) => {
|
||||
items[`k${i}`] = (
|
||||
<span>
|
||||
{indent(breakIntoNewLines, level)}
|
||||
<span style={valueStyles.attr}>{name}</span>
|
||||
</span>
|
||||
);
|
||||
items[`c${i}`] = ': ';
|
||||
items[`v${i}`] = (
|
||||
<PropVal
|
||||
val={val[name]}
|
||||
level={level + 1}
|
||||
valueStyles={valueStyles}
|
||||
maxPropStringLength={maxPropStringLength}
|
||||
maxPropsIntoLine={maxPropsIntoLine}
|
||||
/>
|
||||
);
|
||||
items[`m${i}`] = ',';
|
||||
});
|
||||
if (names.length > maxPropObjectKeys) {
|
||||
items.rest = <span>{indent(breakIntoNewLines, level)}…</span>;
|
||||
} else {
|
||||
delete items[`m${names.length - 1}`];
|
||||
}
|
||||
return (
|
||||
<span style={valueStyles.object}>
|
||||
{'{'}
|
||||
{createFragment(items)}
|
||||
{indent(breakIntoNewLines, level, true)}
|
||||
{'}'}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
PreviewObject.propTypes = {
|
||||
val: PropTypes.any, // eslint-disable-line
|
||||
maxPropObjectKeys: PropTypes.number.isRequired,
|
||||
maxPropStringLength: PropTypes.number.isRequired,
|
||||
maxPropsIntoLine: PropTypes.number.isRequired,
|
||||
level: PropTypes.number.isRequired,
|
||||
valueStyles: PropTypes.shape({
|
||||
func: PropTypes.object,
|
||||
attr: PropTypes.object,
|
||||
object: PropTypes.object,
|
||||
array: PropTypes.object,
|
||||
number: PropTypes.object,
|
||||
string: PropTypes.object,
|
||||
bool: PropTypes.object,
|
||||
empty: PropTypes.object,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
function PropVal(props) {
|
||||
const {
|
||||
level,
|
||||
maxPropObjectKeys,
|
||||
maxPropArrayLength,
|
||||
maxPropStringLength,
|
||||
maxPropsIntoLine,
|
||||
theme,
|
||||
} = props;
|
||||
let { val } = props;
|
||||
const { codeColors } = theme || {};
|
||||
let content = null;
|
||||
const valueStyles = props.valueStyles || getValueStyles(codeColors);
|
||||
|
||||
if (typeof val === 'number') {
|
||||
content = <span style={valueStyles.number}>{val}</span>;
|
||||
} else if (typeof val === 'string') {
|
||||
if (val.length > maxPropStringLength) {
|
||||
val = `${val.slice(0, maxPropStringLength)}…`;
|
||||
}
|
||||
if (level > 1) {
|
||||
val = `'${val}'`;
|
||||
}
|
||||
content = <span style={valueStyles.string}>{val}</span>;
|
||||
} else if (typeof val === 'boolean') {
|
||||
content = <span style={valueStyles.bool}>{`${val}`}</span>;
|
||||
} else if (Array.isArray(val)) {
|
||||
content = (
|
||||
<PreviewArray
|
||||
{...{
|
||||
val,
|
||||
level,
|
||||
maxPropArrayLength,
|
||||
maxPropStringLength,
|
||||
maxPropsIntoLine,
|
||||
valueStyles,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else if (typeof val === 'function') {
|
||||
content = <span style={valueStyles.func}>{val.name || 'anonymous'}</span>;
|
||||
} else if (!val) {
|
||||
content = <span style={valueStyles.empty}>{`${val}`}</span>;
|
||||
} else if (typeof val !== 'object') {
|
||||
content = <span>…</span>;
|
||||
} else if (React.isValidElement(val)) {
|
||||
content = (
|
||||
<span style={valueStyles.object}>
|
||||
{`<${val.type.displayName || val.type.name || val.type} />`}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<PreviewObject
|
||||
{...{
|
||||
val,
|
||||
level,
|
||||
maxPropObjectKeys,
|
||||
maxPropStringLength,
|
||||
maxPropsIntoLine,
|
||||
valueStyles,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
PropVal.defaultProps = {
|
||||
val: null,
|
||||
maxPropObjectKeys: 3,
|
||||
maxPropArrayLength: 3,
|
||||
maxPropStringLength: 50,
|
||||
maxPropsIntoLine: 3,
|
||||
level: 1,
|
||||
theme: {},
|
||||
valueStyles: null,
|
||||
};
|
||||
|
||||
PropVal.propTypes = {
|
||||
val: PropTypes.any, // eslint-disable-line
|
||||
maxPropObjectKeys: PropTypes.number,
|
||||
maxPropArrayLength: PropTypes.number,
|
||||
maxPropStringLength: PropTypes.number,
|
||||
maxPropsIntoLine: PropTypes.number,
|
||||
level: PropTypes.number,
|
||||
theme: PropTypes.shape({
|
||||
codeColors: PropTypes.object,
|
||||
}),
|
||||
valueStyles: PropTypes.shape({
|
||||
func: PropTypes.object,
|
||||
attr: PropTypes.object,
|
||||
object: PropTypes.object,
|
||||
array: PropTypes.object,
|
||||
number: PropTypes.object,
|
||||
string: PropTypes.object,
|
||||
bool: PropTypes.object,
|
||||
empty: PropTypes.object,
|
||||
}),
|
||||
};
|
||||
|
||||
export default PropVal;
|
@ -1,89 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import PropVal from './PropVal';
|
||||
import { getType } from '../react-utils';
|
||||
|
||||
const stylesheet = {
|
||||
propStyle: {},
|
||||
propNameStyle: {},
|
||||
propValueStyle: {},
|
||||
};
|
||||
|
||||
export default function Props(props) {
|
||||
const {
|
||||
maxPropsIntoLine,
|
||||
maxPropArrayLength,
|
||||
maxPropObjectKeys,
|
||||
maxPropStringLength,
|
||||
node,
|
||||
singleLine,
|
||||
} = props;
|
||||
const nodeProps = node.props;
|
||||
const { defaultProps } = getType(node.type);
|
||||
if (!nodeProps || typeof nodeProps !== 'object') {
|
||||
return <span />;
|
||||
}
|
||||
|
||||
const { propValueStyle, propNameStyle } = stylesheet;
|
||||
|
||||
const names = Object.keys(nodeProps).filter(
|
||||
name =>
|
||||
name[0] !== '_' &&
|
||||
name !== 'children' &&
|
||||
(!defaultProps || nodeProps[name] !== defaultProps[name])
|
||||
);
|
||||
|
||||
const breakIntoNewLines = names.length > maxPropsIntoLine;
|
||||
const endingSpace = singleLine ? ' ' : '';
|
||||
|
||||
const items = [];
|
||||
names.forEach((name, i) => {
|
||||
items.push(
|
||||
<span key={name}>
|
||||
{breakIntoNewLines ? (
|
||||
<span>
|
||||
<br />
|
||||
|
||||
</span>
|
||||
) : (
|
||||
' '
|
||||
)}
|
||||
<span style={propNameStyle}>{name}</span>
|
||||
{/* Use implicit true: */}
|
||||
{(!nodeProps[name] || typeof nodeProps[name] !== 'boolean') && (
|
||||
<span>
|
||||
=
|
||||
<span style={propValueStyle}>
|
||||
{typeof nodeProps[name] === 'string' ? '"' : '{'}
|
||||
<PropVal
|
||||
val={nodeProps[name]}
|
||||
maxPropObjectKeys={maxPropObjectKeys}
|
||||
maxPropArrayLength={maxPropArrayLength}
|
||||
maxPropStringLength={maxPropStringLength}
|
||||
maxPropsIntoLine={maxPropsIntoLine}
|
||||
/>
|
||||
{typeof nodeProps[name] === 'string' ? '"' : '}'}
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
|
||||
{i === names.length - 1 && (breakIntoNewLines ? <br /> : endingSpace)}
|
||||
</span>
|
||||
);
|
||||
});
|
||||
|
||||
return <span>{items}</span>;
|
||||
}
|
||||
|
||||
Props.defaultProps = {
|
||||
singleLine: false,
|
||||
};
|
||||
|
||||
Props.propTypes = {
|
||||
node: PropTypes.node.isRequired,
|
||||
singleLine: PropTypes.bool,
|
||||
maxPropsIntoLine: PropTypes.number.isRequired,
|
||||
maxPropObjectKeys: PropTypes.number.isRequired,
|
||||
maxPropArrayLength: PropTypes.number.isRequired,
|
||||
maxPropStringLength: PropTypes.number.isRequired,
|
||||
};
|
@ -1,442 +0,0 @@
|
||||
/* eslint no-underscore-dangle: 0 */
|
||||
|
||||
import React, { Fragment, Component, createElement } from 'react';
|
||||
import { isForwardRef } from 'react-is';
|
||||
import { polyfill } from 'react-lifecycles-compat';
|
||||
import PropTypes from 'prop-types';
|
||||
import global from 'global';
|
||||
|
||||
import marksy from 'marksy';
|
||||
import jsxToString from 'react-element-to-jsx-string';
|
||||
import { Code } from './markdown';
|
||||
import { getDisplayName, getType } from '../react-utils';
|
||||
|
||||
global.STORYBOOK_REACT_CLASSES = global.STORYBOOK_REACT_CLASSES || [];
|
||||
const { STORYBOOK_REACT_CLASSES } = global;
|
||||
|
||||
const stylesheetBase = {
|
||||
button: {
|
||||
base: {
|
||||
fontFamily: 'sans-serif',
|
||||
fontSize: 12,
|
||||
display: 'block',
|
||||
position: 'fixed',
|
||||
border: 'none',
|
||||
background: '#027ac5',
|
||||
color: '#fff',
|
||||
padding: '5px 15px',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
topRight: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
borderRadius: '0 0 0 5px',
|
||||
},
|
||||
},
|
||||
info: {
|
||||
position: 'fixed',
|
||||
background: 'white',
|
||||
top: 0,
|
||||
left: 0,
|
||||
height: '100vh',
|
||||
width: '100vw',
|
||||
overflow: 'auto',
|
||||
zIndex: 99999,
|
||||
},
|
||||
children: {
|
||||
position: 'relative',
|
||||
zIndex: 0,
|
||||
},
|
||||
infoBody: {
|
||||
fontFamily: 'Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif',
|
||||
color: 'black',
|
||||
fontWeight: 300,
|
||||
lineHeight: 1.45,
|
||||
fontSize: '15px',
|
||||
padding: '20px 40px 40px',
|
||||
borderRadius: '2px',
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
infoContent: {
|
||||
marginBottom: 0,
|
||||
},
|
||||
infoStory: {},
|
||||
jsxInfoContent: {
|
||||
borderTop: '1px solid #eee',
|
||||
margin: '20px 0 0 0',
|
||||
},
|
||||
header: {
|
||||
h1: {
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontSize: '35px',
|
||||
},
|
||||
h2: {
|
||||
margin: '0 0 10px 0',
|
||||
padding: 0,
|
||||
fontWeight: 400,
|
||||
fontSize: '22px',
|
||||
},
|
||||
h3: {
|
||||
margin: '0 0 10px 0',
|
||||
padding: 0,
|
||||
fontWeight: 400,
|
||||
fontSize: '18px',
|
||||
},
|
||||
body: {
|
||||
borderBottom: '1px solid #eee',
|
||||
paddingTop: 10,
|
||||
marginBottom: 10,
|
||||
},
|
||||
},
|
||||
source: {
|
||||
h1: {
|
||||
margin: '20px 0 0 0',
|
||||
padding: '0 0 5px 0',
|
||||
fontSize: '25px',
|
||||
borderBottom: '1px solid #EEE',
|
||||
},
|
||||
},
|
||||
propTableHead: {
|
||||
margin: '20px 0 0 0',
|
||||
},
|
||||
};
|
||||
|
||||
class Story extends Component {
|
||||
constructor(props, ...args) {
|
||||
super(props, ...args);
|
||||
this.state = {
|
||||
open: false,
|
||||
};
|
||||
this.marksy = marksy({
|
||||
createElement,
|
||||
elements: props.components,
|
||||
});
|
||||
}
|
||||
|
||||
_renderStory() {
|
||||
const { stylesheet } = this.state;
|
||||
const { children } = this.props;
|
||||
|
||||
return (
|
||||
<div id="story-root" style={stylesheet.infoStory}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
_renderInline() {
|
||||
const { stylesheet } = this.state;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{this._renderInlineHeader()}
|
||||
{this._renderStory()}
|
||||
<div style={stylesheet.infoPage}>
|
||||
<div style={stylesheet.infoBody}>
|
||||
{this._getInfoContent()}
|
||||
{this._getComponentDescription()}
|
||||
{this._getSourceCode()}
|
||||
{this._getPropTables()}
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
_renderInlineHeader() {
|
||||
const { stylesheet } = this.state;
|
||||
|
||||
const infoHeader = this._getInfoHeader();
|
||||
|
||||
return (
|
||||
infoHeader && (
|
||||
<div style={stylesheet.infoPage}>
|
||||
<div style={stylesheet.infoBody}>{infoHeader}</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
_renderOverlay() {
|
||||
const { stylesheet, open } = this.state;
|
||||
const { children } = this.props;
|
||||
|
||||
const buttonStyle = {
|
||||
...stylesheet.button.base,
|
||||
...stylesheet.button.topRight,
|
||||
};
|
||||
|
||||
const infoStyle = { ...stylesheet.info };
|
||||
if (!open) {
|
||||
infoStyle.display = 'none';
|
||||
}
|
||||
|
||||
const openOverlay = () => {
|
||||
this.setState({ open: true });
|
||||
return false;
|
||||
};
|
||||
|
||||
const closeOverlay = () => {
|
||||
this.setState({ open: false });
|
||||
return false;
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div style={stylesheet.children}>{children}</div>
|
||||
<button
|
||||
type="button"
|
||||
style={buttonStyle}
|
||||
onClick={openOverlay}
|
||||
className="info__show-button"
|
||||
>
|
||||
Show Info
|
||||
</button>
|
||||
{open ? (
|
||||
<div style={infoStyle} className="info__overlay">
|
||||
<button
|
||||
type="button"
|
||||
style={buttonStyle}
|
||||
onClick={closeOverlay}
|
||||
className="info__close-button"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
<div style={stylesheet.infoPage}>
|
||||
<div style={stylesheet.infoBody}>
|
||||
{this._getInfoHeader()}
|
||||
{this._getInfoContent()}
|
||||
{this._getComponentDescription()}
|
||||
{this._getSourceCode()}
|
||||
{this._getPropTables()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
_getInfoHeader() {
|
||||
const { stylesheet } = this.state;
|
||||
const { context, showHeader } = this.props;
|
||||
|
||||
if (!context || !showHeader) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={stylesheet.header.body}>
|
||||
<h1 style={stylesheet.header.h1}>{context.kind}</h1>
|
||||
<h2 style={stylesheet.header.h2}>{context.name}</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
_getInfoContent() {
|
||||
const { info, showInline } = this.props;
|
||||
const { stylesheet } = this.state;
|
||||
|
||||
if (!info) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (React.isValidElement(info)) {
|
||||
return (
|
||||
<div style={showInline ? stylesheet.jsxInfoContent : stylesheet.infoContent}>{info}</div>
|
||||
);
|
||||
}
|
||||
|
||||
const lines = info.split('\n');
|
||||
while (lines[0].trim() === '') {
|
||||
lines.shift();
|
||||
}
|
||||
let padding = 0;
|
||||
const matches = lines[0].match(/^ */);
|
||||
if (matches) {
|
||||
padding = matches[0].length;
|
||||
}
|
||||
const source = lines.map(s => s.slice(padding)).join('\n');
|
||||
|
||||
return <Fragment>{this.marksy(source).tree}</Fragment>;
|
||||
}
|
||||
|
||||
_getComponentDescription() {
|
||||
const {
|
||||
context: { kind, name },
|
||||
} = this.props;
|
||||
let retDiv = null;
|
||||
|
||||
const validMatches = [kind, name];
|
||||
|
||||
if (Object.keys(STORYBOOK_REACT_CLASSES).length) {
|
||||
Object.keys(STORYBOOK_REACT_CLASSES).forEach(key => {
|
||||
if (validMatches.includes(STORYBOOK_REACT_CLASSES[key].name)) {
|
||||
const componentDescription = STORYBOOK_REACT_CLASSES[key].docgenInfo.description;
|
||||
retDiv = <Fragment>{this.marksy(componentDescription).tree}</Fragment>;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return retDiv;
|
||||
}
|
||||
|
||||
_getSourceCode() {
|
||||
const { showSource, children } = this.props;
|
||||
const { stylesheet } = this.state;
|
||||
|
||||
if (!showSource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<h1 style={stylesheet.source.h1}>Story Source</h1>
|
||||
<Code code={jsxToString(children)} language="jsx" format={false} />
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
_getPropTables() {
|
||||
const {
|
||||
children,
|
||||
propTablesExclude,
|
||||
propTableCompare,
|
||||
maxPropObjectKeys,
|
||||
maxPropArrayLength,
|
||||
maxPropStringLength,
|
||||
excludedPropTypes,
|
||||
} = this.props;
|
||||
let { propTables } = this.props;
|
||||
const { stylesheet } = this.state;
|
||||
const types = new Map();
|
||||
|
||||
if (!propTables) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!children) {
|
||||
return null;
|
||||
}
|
||||
|
||||
propTables.forEach(type => {
|
||||
types.set(type, true);
|
||||
});
|
||||
|
||||
// depth-first traverse and collect types
|
||||
const extract = innerChildren => {
|
||||
if (!innerChildren) {
|
||||
return;
|
||||
}
|
||||
if (Array.isArray(innerChildren)) {
|
||||
innerChildren.forEach(extract);
|
||||
return;
|
||||
}
|
||||
if (innerChildren.props && innerChildren.props.children) {
|
||||
extract(innerChildren.props.children);
|
||||
}
|
||||
if (isForwardRef(innerChildren)) {
|
||||
try {
|
||||
// this might fail because of hooks being used
|
||||
extract(innerChildren.type.render(innerChildren.props));
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
if (
|
||||
typeof innerChildren === 'string' ||
|
||||
typeof innerChildren.type === 'string' ||
|
||||
(propTables.length > 0 && // if propTables is set and has items in it
|
||||
!propTables.includes(innerChildren.type)) || // ignore types that are missing from propTables
|
||||
(Array.isArray(propTablesExclude) && // also ignore excluded types
|
||||
propTablesExclude.some(Comp => propTableCompare(innerChildren, Comp)))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (innerChildren.type && !types.has(innerChildren.type)) {
|
||||
types.set(innerChildren.type, true);
|
||||
}
|
||||
};
|
||||
|
||||
// extract components from children
|
||||
extract(children);
|
||||
|
||||
const array = Array.from(types.keys());
|
||||
array.sort((a, b) => (getDisplayName(a) > getDisplayName(b) ? 1 : -1));
|
||||
|
||||
propTables = array.map((type, i) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<div key={`${getDisplayName(type)}_${i}`}>
|
||||
<h3 style={stylesheet.propTableHead}>"{getDisplayName(type)}" Component</h3>
|
||||
<this.props.PropTable
|
||||
type={getType(type)}
|
||||
maxPropObjectKeys={maxPropObjectKeys}
|
||||
maxPropArrayLength={maxPropArrayLength}
|
||||
maxPropStringLength={maxPropStringLength}
|
||||
excludedPropTypes={excludedPropTypes}
|
||||
/>
|
||||
</div>
|
||||
));
|
||||
|
||||
if (!propTables || propTables.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<h1 style={stylesheet.source.h1}>Prop Types</h1>
|
||||
{propTables}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { showInline } = this.props;
|
||||
return showInline ? this._renderInline() : this._renderOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
Story.getDerivedStateFromProps = ({ styles }) => ({ stylesheet: styles(stylesheetBase) });
|
||||
|
||||
Story.displayName = 'Story';
|
||||
|
||||
Story.propTypes = {
|
||||
context: PropTypes.shape({
|
||||
kind: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
}),
|
||||
info: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||
propTables: PropTypes.arrayOf(PropTypes.func),
|
||||
propTablesExclude: PropTypes.arrayOf(PropTypes.func),
|
||||
propTableCompare: PropTypes.func.isRequired,
|
||||
showInline: PropTypes.bool,
|
||||
showHeader: PropTypes.bool,
|
||||
showSource: PropTypes.bool,
|
||||
// eslint-disable-next-line react/no-unused-prop-types
|
||||
styles: PropTypes.func.isRequired,
|
||||
children: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
||||
components: PropTypes.shape({}),
|
||||
maxPropObjectKeys: PropTypes.number.isRequired,
|
||||
maxPropArrayLength: PropTypes.number.isRequired,
|
||||
maxPropStringLength: PropTypes.number.isRequired,
|
||||
excludedPropTypes: PropTypes.arrayOf(PropTypes.string),
|
||||
};
|
||||
|
||||
Story.defaultProps = {
|
||||
context: null,
|
||||
info: '',
|
||||
children: null,
|
||||
propTables: null,
|
||||
propTablesExclude: [],
|
||||
showInline: false,
|
||||
showHeader: true,
|
||||
showSource: true,
|
||||
components: {},
|
||||
excludedPropTypes: [],
|
||||
};
|
||||
|
||||
polyfill(Story);
|
||||
|
||||
export default Story;
|
@ -1,76 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PropTable multiLineText should exclude excluded propTypes 1`] = `
|
||||
<small>
|
||||
No propTypes defined!
|
||||
</small>
|
||||
`;
|
||||
|
||||
exports[`PropTable multiLineText should have 2 br tags for 3 lines of text 1`] = `
|
||||
Array [
|
||||
<span>
|
||||
|
||||
foo
|
||||
</span>,
|
||||
<span>
|
||||
<br />
|
||||
|
||||
bar
|
||||
</span>,
|
||||
<span>
|
||||
<br />
|
||||
|
||||
baz
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`PropTable multiLineText should include all propTypes by default 1`] = `
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>
|
||||
property
|
||||
</Th>
|
||||
<Th>
|
||||
propType
|
||||
</Th>
|
||||
<Th>
|
||||
required
|
||||
</Th>
|
||||
<Th>
|
||||
default
|
||||
</Th>
|
||||
<Th>
|
||||
description
|
||||
</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
<Tr
|
||||
key="foo"
|
||||
>
|
||||
<Td>
|
||||
foo
|
||||
</Td>
|
||||
<Td>
|
||||
<PrettyPropType
|
||||
depth={1}
|
||||
propType={
|
||||
Object {
|
||||
"name": "string",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Td>
|
||||
<Td>
|
||||
-
|
||||
</Td>
|
||||
<Td>
|
||||
-
|
||||
</Td>
|
||||
<Td />
|
||||
</Tr>
|
||||
</Tbody>
|
||||
</Table>
|
||||
`;
|
@ -1,98 +0,0 @@
|
||||
/* eslint-disable no-underscore-dangle,react/forbid-foreign-prop-types */
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
const PropTypesMap = new Map();
|
||||
|
||||
Object.keys(PropTypes).forEach(typeName => {
|
||||
const type = PropTypes[typeName];
|
||||
|
||||
PropTypesMap.set(type, typeName);
|
||||
PropTypesMap.set(type.isRequired, typeName);
|
||||
});
|
||||
|
||||
const isNotEmpty = obj => obj && obj.props && Object.keys(obj.props).length > 0;
|
||||
|
||||
const hasDocgen = type => isNotEmpty(type.__docgenInfo);
|
||||
|
||||
const propsFromDocgen = type => {
|
||||
const props = {};
|
||||
const docgenInfoProps = type.__docgenInfo.props;
|
||||
|
||||
Object.keys(docgenInfoProps).forEach(property => {
|
||||
const docgenInfoProp = docgenInfoProps[property];
|
||||
const defaultValueDesc = docgenInfoProp.defaultValue || {};
|
||||
const propType = docgenInfoProp.flowType || docgenInfoProp.type || 'other';
|
||||
|
||||
props[property] = {
|
||||
property,
|
||||
propType,
|
||||
required: docgenInfoProp.required,
|
||||
description: docgenInfoProp.description,
|
||||
defaultValue: defaultValueDesc.value,
|
||||
};
|
||||
});
|
||||
|
||||
return props;
|
||||
};
|
||||
|
||||
const propsFromPropTypes = type => {
|
||||
const props = {};
|
||||
|
||||
if (type.propTypes) {
|
||||
Object.keys(type.propTypes).forEach(property => {
|
||||
const typeInfo = type.propTypes[property];
|
||||
const required = typeInfo.isRequired === undefined;
|
||||
const docgenInfo =
|
||||
type.__docgenInfo && type.__docgenInfo.props && type.__docgenInfo.props[property];
|
||||
const description = docgenInfo ? docgenInfo.description : null;
|
||||
let propType = PropTypesMap.get(typeInfo) || 'other';
|
||||
|
||||
if (propType === 'other') {
|
||||
if (docgenInfo && docgenInfo.type) {
|
||||
propType = docgenInfo.type.name;
|
||||
}
|
||||
}
|
||||
|
||||
props[property] = { property, propType, required, description };
|
||||
});
|
||||
}
|
||||
|
||||
if (type.defaultProps) {
|
||||
Object.keys(type.defaultProps).forEach(property => {
|
||||
const value = type.defaultProps[property];
|
||||
|
||||
if (value === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!props[property]) {
|
||||
props[property] = { property };
|
||||
}
|
||||
|
||||
props[property].defaultValue = value;
|
||||
});
|
||||
}
|
||||
|
||||
return props;
|
||||
};
|
||||
|
||||
export default function makeTableComponent(Component) {
|
||||
const TableComponent = props => {
|
||||
const { type } = props;
|
||||
if (!type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const propDefinitionsMap = hasDocgen(type) ? propsFromDocgen(type) : propsFromPropTypes(type);
|
||||
const propDefinitions = Object.values(propDefinitionsMap);
|
||||
|
||||
return <Component propDefinitions={propDefinitions} {...props} />;
|
||||
};
|
||||
|
||||
TableComponent.propTypes = {
|
||||
type: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
return TableComponent;
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { SyntaxHighlighter } from '@storybook/components';
|
||||
import { ThemeProvider, convert } from '@storybook/theming';
|
||||
|
||||
const Code = ({ code, language = 'plaintext', ...rest }) => (
|
||||
<ThemeProvider theme={convert()}>
|
||||
<SyntaxHighlighter bordered copyable format={false} language={language} {...rest}>
|
||||
{code}
|
||||
</SyntaxHighlighter>
|
||||
</ThemeProvider>
|
||||
);
|
||||
Code.propTypes = {
|
||||
language: PropTypes.string.isRequired,
|
||||
code: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export { Code };
|
||||
|
||||
export function Blockquote({ children }) {
|
||||
const style = {
|
||||
fontSize: '1.88em',
|
||||
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
|
||||
borderLeft: '8px solid #fafafa',
|
||||
padding: '1rem',
|
||||
};
|
||||
return <blockquote style={style}>{children}</blockquote>;
|
||||
}
|
||||
|
||||
Blockquote.propTypes = { children: PropTypes.node };
|
||||
Blockquote.defaultProps = { children: null };
|
||||
|
||||
export { default as Pre } from './pre/pre';
|
@ -1,115 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const defaultProps = {
|
||||
children: null,
|
||||
id: null,
|
||||
};
|
||||
const propTypes = {
|
||||
children: PropTypes.node,
|
||||
id: PropTypes.string,
|
||||
};
|
||||
|
||||
export function H1({ id, children }) {
|
||||
const styles = {
|
||||
borderBottom: '1px solid #eee',
|
||||
fontWeight: 600,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontSize: '40px',
|
||||
};
|
||||
return (
|
||||
<h1 id={id} style={styles}>
|
||||
{children}
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
H1.defaultProps = defaultProps;
|
||||
H1.propTypes = propTypes;
|
||||
|
||||
export function H2({ id, children }) {
|
||||
const styles = {
|
||||
fontWeight: 600,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontSize: '30px',
|
||||
};
|
||||
return (
|
||||
<h2 id={id} style={styles}>
|
||||
{children}
|
||||
</h2>
|
||||
);
|
||||
}
|
||||
|
||||
H2.defaultProps = defaultProps;
|
||||
H2.propTypes = propTypes;
|
||||
|
||||
export function H3({ id, children }) {
|
||||
const styles = {
|
||||
fontWeight: 600,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontSize: '22px',
|
||||
textTransform: 'uppercase',
|
||||
};
|
||||
return (
|
||||
<h3 id={id} style={styles}>
|
||||
{children}
|
||||
</h3>
|
||||
);
|
||||
}
|
||||
|
||||
H3.defaultProps = defaultProps;
|
||||
H3.propTypes = propTypes;
|
||||
|
||||
export function H4({ id, children }) {
|
||||
const styles = {
|
||||
fontWeight: 600,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontSize: '20px',
|
||||
};
|
||||
return (
|
||||
<h4 id={id} style={styles}>
|
||||
{children}
|
||||
</h4>
|
||||
);
|
||||
}
|
||||
|
||||
H4.defaultProps = defaultProps;
|
||||
H4.propTypes = propTypes;
|
||||
|
||||
export function H5({ id, children }) {
|
||||
const styles = {
|
||||
fontWeight: 600,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontSize: '18px',
|
||||
};
|
||||
return (
|
||||
<h5 id={id} style={styles}>
|
||||
{children}
|
||||
</h5>
|
||||
);
|
||||
}
|
||||
|
||||
H5.defaultProps = defaultProps;
|
||||
H5.propTypes = propTypes;
|
||||
|
||||
export function H6({ id, children }) {
|
||||
const styles = {
|
||||
fontWeight: 400,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontSize: '18px',
|
||||
};
|
||||
return (
|
||||
<h6 id={id} style={styles}>
|
||||
{children}
|
||||
</h6>
|
||||
);
|
||||
}
|
||||
|
||||
H6.defaultProps = defaultProps;
|
||||
H6.propTypes = propTypes;
|
@ -1,3 +0,0 @@
|
||||
export { H1, H2, H3, H4, H5, H6 } from './htags';
|
||||
export { Code, Pre } from './code';
|
||||
export { P, A, LI, UL } from './text';
|
@ -1,13 +0,0 @@
|
||||
/* eslint-disable no-undef */
|
||||
export default function copy(str) {
|
||||
const tmp = document.createElement('TEXTAREA');
|
||||
const focus = document.activeElement;
|
||||
|
||||
tmp.value = str;
|
||||
|
||||
document.body.appendChild(tmp);
|
||||
tmp.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(tmp);
|
||||
focus.focus();
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
function CopyButton({ onClick, toggled }) {
|
||||
const toggleText = 'Copied!';
|
||||
const text = 'Copy';
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
style={{
|
||||
backgroundColor: 'rgb(255, 255, 255)',
|
||||
cursor: 'pointer',
|
||||
fontSize: '13px',
|
||||
alignSelf: 'flex-start',
|
||||
flexShrink: '0',
|
||||
overflow: 'hidden',
|
||||
borderWidth: 1,
|
||||
borderStyle: 'solid',
|
||||
borderColor: 'rgb(238, 238, 238)',
|
||||
borderImage: 'initial',
|
||||
borderRadius: 3,
|
||||
padding: '3px 10px',
|
||||
}}
|
||||
>
|
||||
{toggled ? toggleText : text}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
CopyButton.propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
toggled: PropTypes.bool,
|
||||
};
|
||||
|
||||
CopyButton.defaultProps = {
|
||||
onClick: () => {},
|
||||
toggled: false,
|
||||
};
|
||||
|
||||
export default CopyButton;
|
@ -1,76 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import CopyButton from './copyButton';
|
||||
import copy from './copy';
|
||||
|
||||
const TOGGLE_TIMEOUT = 1800;
|
||||
|
||||
class Pre extends React.Component {
|
||||
state = {
|
||||
copied: false,
|
||||
};
|
||||
|
||||
setRef = elem => {
|
||||
this.pre = elem;
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
const text = this.pre && this.pre.innerText;
|
||||
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
|
||||
copy(text);
|
||||
this.setState({ copied: true });
|
||||
|
||||
clearTimeout(this.timeout);
|
||||
|
||||
this.timeout = setTimeout(() => {
|
||||
this.setState({ copied: false });
|
||||
}, TOGGLE_TIMEOUT);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { theme, children } = this.props;
|
||||
const { pre } = theme;
|
||||
const { copied } = this.state;
|
||||
|
||||
return (
|
||||
<pre
|
||||
style={{
|
||||
...{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
fontSize: '.88em',
|
||||
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
|
||||
backgroundColor: '#fafafa',
|
||||
padding: '.5rem',
|
||||
lineHeight: 1.5,
|
||||
overflowX: 'scroll',
|
||||
},
|
||||
...pre,
|
||||
}}
|
||||
>
|
||||
<div ref={this.setRef}>{children}</div>
|
||||
<CopyButton onClick={this.handleClick} toggled={copied} />
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Pre.propTypes = {
|
||||
children: PropTypes.node,
|
||||
theme: PropTypes.shape({
|
||||
pre: PropTypes.object,
|
||||
}),
|
||||
};
|
||||
|
||||
Pre.defaultProps = {
|
||||
children: null,
|
||||
theme: {},
|
||||
};
|
||||
|
||||
export default Pre;
|
@ -1,40 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const defaultProps = { children: null };
|
||||
const propTypes = { children: PropTypes.node };
|
||||
|
||||
export function P({ children }) {
|
||||
return <p>{children}</p>;
|
||||
}
|
||||
|
||||
P.defaultProps = defaultProps;
|
||||
P.propTypes = propTypes;
|
||||
|
||||
export function LI({ children }) {
|
||||
return <li>{children}</li>;
|
||||
}
|
||||
|
||||
LI.defaultProps = defaultProps;
|
||||
LI.propTypes = propTypes;
|
||||
|
||||
export function UL({ children }) {
|
||||
return <ul>{children}</ul>;
|
||||
}
|
||||
|
||||
UL.defaultProps = defaultProps;
|
||||
UL.propTypes = propTypes;
|
||||
|
||||
export function A({ href, children }) {
|
||||
const style = {
|
||||
color: '#3498db',
|
||||
};
|
||||
return (
|
||||
<a href={href} target="_blank" rel="noopener noreferrer" style={style}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
A.defaultProps = defaultProps;
|
||||
A.propTypes = { children: PropTypes.node, href: PropTypes.string.isRequired };
|
@ -1,21 +0,0 @@
|
||||
/* eslint-disable import/no-cycle */
|
||||
import React from 'react';
|
||||
|
||||
import PrettyPropType from './PrettyPropType';
|
||||
import { TypeInfo, getPropTypes } from './proptypes';
|
||||
|
||||
const ArrayOf = ({ propType }) => (
|
||||
<span>
|
||||
<span>[</span>
|
||||
<span>
|
||||
<PrettyPropType propType={getPropTypes(propType)} />
|
||||
</span>
|
||||
<span>]</span>
|
||||
</span>
|
||||
);
|
||||
|
||||
ArrayOf.propTypes = {
|
||||
propType: TypeInfo.isRequired,
|
||||
};
|
||||
|
||||
export default ArrayOf;
|
@ -1,14 +0,0 @@
|
||||
import React from 'react';
|
||||
import { TypeInfo, getPropTypes } from './proptypes';
|
||||
|
||||
const Enum = ({ propType }) => (
|
||||
<span>
|
||||
{getPropTypes(propType)
|
||||
.map(({ value }) => value)
|
||||
.join(' | ')}
|
||||
</span>
|
||||
);
|
||||
|
||||
Enum.propTypes = {
|
||||
propType: TypeInfo.isRequired,
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
import React from 'react';
|
||||
import { TypeInfo, getPropTypes } from './proptypes';
|
||||
|
||||
const InstanceOf = ({ propType }) => <span>{getPropTypes(propType)}</span>;
|
||||
|
||||
InstanceOf.propTypes = {
|
||||
propType: TypeInfo.isRequired,
|
||||
};
|
||||
|
||||
export default InstanceOf;
|
@ -1,10 +0,0 @@
|
||||
import React from 'react';
|
||||
import { TypeInfo } from './proptypes';
|
||||
|
||||
const Literal = ({ propType }) => <span>{propType.value}</span>;
|
||||
|
||||
Literal.propTypes = {
|
||||
propType: TypeInfo.isRequired,
|
||||
};
|
||||
|
||||
export default Literal;
|
@ -1,19 +0,0 @@
|
||||
/* eslint-disable import/no-cycle */
|
||||
import React from 'react';
|
||||
|
||||
import PrettyPropType from './PrettyPropType';
|
||||
import { TypeInfo, getPropTypes } from './proptypes';
|
||||
|
||||
const ObjectOf = ({ propType }) => (
|
||||
<span>
|
||||
{'{[<key>]: '}
|
||||
<PrettyPropType propType={getPropTypes(propType)} />
|
||||
{'}'}
|
||||
</span>
|
||||
);
|
||||
|
||||
ObjectOf.propTypes = {
|
||||
propType: TypeInfo.isRequired,
|
||||
};
|
||||
|
||||
export default ObjectOf;
|
@ -1,15 +0,0 @@
|
||||
import React from 'react';
|
||||
import { TypeInfo, getPropTypes } from './proptypes';
|
||||
|
||||
const joinValues = propTypes => propTypes.map(({ value }) => value).join(' | ');
|
||||
|
||||
const OneOf = ({ propType }) => {
|
||||
const propTypes = getPropTypes(propType);
|
||||
return <span>{`oneOf ${Array.isArray(propTypes) ? joinValues(propTypes) : propTypes}`}</span>;
|
||||
};
|
||||
|
||||
OneOf.propTypes = {
|
||||
propType: TypeInfo.isRequired,
|
||||
};
|
||||
|
||||
export default OneOf;
|
@ -1,26 +0,0 @@
|
||||
/* eslint-disable import/no-cycle */
|
||||
import React from 'react';
|
||||
|
||||
import PrettyPropType from './PrettyPropType';
|
||||
import { TypeInfo, getPropTypes } from './proptypes';
|
||||
|
||||
const OneOfType = ({ propType }) => {
|
||||
const propTypes = getPropTypes(propType);
|
||||
return (
|
||||
<span>
|
||||
{propTypes
|
||||
.map((value, i) => {
|
||||
const key = `${value.name}${value.value ? `-${value.value}` : ''}`;
|
||||
return [
|
||||
<PrettyPropType key={key} propType={value} />,
|
||||
i < propTypes.length - 1 ? <span key={`${key}-separator`}> | </span> : null,
|
||||
];
|
||||
})
|
||||
.reduce((acc, tuple) => acc.concat(tuple), [])}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
OneOfType.propTypes = {
|
||||
propType: TypeInfo.isRequired,
|
||||
};
|
||||
export default OneOfType;
|
@ -1,56 +0,0 @@
|
||||
/* eslint-disable import/no-cycle */
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
import Shape from './Shape';
|
||||
import OneOfType from './OneOfType';
|
||||
import ArrayOf from './ArrayOf';
|
||||
import ObjectOf from './ObjectOf';
|
||||
import OneOf from './OneOf';
|
||||
import InstanceOf from './InstanceOf';
|
||||
import Signature from './Signature';
|
||||
import Literal from './Literal';
|
||||
|
||||
import { TypeInfo } from './proptypes';
|
||||
|
||||
// propType -> Component map - these are a bit more complex prop types to display
|
||||
const propTypeComponentMap = new Map([
|
||||
['shape', Shape],
|
||||
['union', OneOfType],
|
||||
['arrayOf', ArrayOf],
|
||||
['objectOf', ObjectOf],
|
||||
// Might be overkill to have below proptypes as separate components *shrug*
|
||||
['literal', Literal],
|
||||
['enum', OneOf],
|
||||
['instanceOf', InstanceOf],
|
||||
['signature', Signature],
|
||||
]);
|
||||
|
||||
const PrettyPropType = props => {
|
||||
const { propType, depth } = props;
|
||||
if (!propType) {
|
||||
return <span>unknown</span>;
|
||||
}
|
||||
|
||||
if (propTypeComponentMap.has(propType.name)) {
|
||||
const Component = propTypeComponentMap.get(propType.name);
|
||||
return <Component propType={propType} depth={depth} />;
|
||||
}
|
||||
|
||||
// Otherwise, propType does not have a dedicated component, display proptype name by default
|
||||
return <span>{propType.name || propType}</span>;
|
||||
};
|
||||
|
||||
PrettyPropType.displayName = 'PrettyPropType';
|
||||
|
||||
PrettyPropType.defaultProps = {
|
||||
propType: null,
|
||||
depth: 1,
|
||||
};
|
||||
|
||||
PrettyPropType.propTypes = {
|
||||
propType: TypeInfo,
|
||||
depth: PropTypes.number,
|
||||
};
|
||||
|
||||
export default PrettyPropType;
|
@ -1,31 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
const styles = {
|
||||
hasProperty: {
|
||||
whiteSpace: 'nowrap',
|
||||
},
|
||||
};
|
||||
|
||||
const PropertyLabel = ({ property, required }) => {
|
||||
if (!property) return null;
|
||||
|
||||
return (
|
||||
<span style={styles.hasProperty}>
|
||||
{property}
|
||||
{required ? '' : '?'}:
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
PropertyLabel.propTypes = {
|
||||
property: PropTypes.string,
|
||||
required: PropTypes.bool,
|
||||
};
|
||||
|
||||
PropertyLabel.defaultProps = {
|
||||
property: '',
|
||||
required: false,
|
||||
};
|
||||
|
||||
export default PropertyLabel;
|
@ -1,76 +0,0 @@
|
||||
/* eslint-disable import/no-cycle */
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
import PrettyPropType from './PrettyPropType';
|
||||
import PropertyLabel from './PropertyLabel';
|
||||
|
||||
import { TypeInfo, getPropTypes } from './proptypes';
|
||||
|
||||
const MARGIN_SIZE = 15;
|
||||
|
||||
const HighlightButton = props => (
|
||||
<button
|
||||
type="button"
|
||||
{...props}
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
background: 'none',
|
||||
border: '0 none',
|
||||
color: 'gray',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
class Shape extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
minimized: false,
|
||||
};
|
||||
}
|
||||
|
||||
handleToggle = () => {
|
||||
const { minimized } = this.state;
|
||||
this.setState({
|
||||
minimized: !minimized,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { propType, depth } = this.props;
|
||||
const { minimized } = this.state;
|
||||
|
||||
const propTypes = getPropTypes(propType);
|
||||
return (
|
||||
<span>
|
||||
<HighlightButton onClick={this.handleToggle}>{'{'}</HighlightButton>
|
||||
<HighlightButton onClick={this.handleToggle}>...</HighlightButton>
|
||||
{!minimized &&
|
||||
Object.keys(propTypes).map(childProperty => (
|
||||
<div key={childProperty} style={{ marginLeft: depth * MARGIN_SIZE }}>
|
||||
<PropertyLabel
|
||||
property={childProperty}
|
||||
required={propTypes[childProperty].required}
|
||||
/>
|
||||
<PrettyPropType depth={depth + 1} propType={propTypes[childProperty]} />,
|
||||
</div>
|
||||
))}
|
||||
|
||||
<HighlightButton onClick={this.handleToggle}>{'}'}</HighlightButton>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Shape.propTypes = {
|
||||
propType: TypeInfo,
|
||||
depth: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
Shape.defaultProps = {
|
||||
propType: null,
|
||||
};
|
||||
|
||||
export default Shape;
|
@ -1,10 +0,0 @@
|
||||
import React from 'react';
|
||||
import { TypeInfo } from './proptypes';
|
||||
|
||||
const Signature = ({ propType }) => <span>{propType.raw}</span>;
|
||||
|
||||
Signature.propTypes = {
|
||||
propType: TypeInfo.isRequired,
|
||||
};
|
||||
|
||||
export default Signature;
|
@ -1,12 +0,0 @@
|
||||
import PropTypes, { oneOfType } from 'prop-types';
|
||||
|
||||
export const TypeInfo = oneOfType([
|
||||
PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
value: PropTypes.any,
|
||||
}),
|
||||
PropTypes.string,
|
||||
]);
|
||||
|
||||
export const getPropTypes = propType =>
|
||||
typeof propType === 'string' ? propType : propType.value || propType.elements;
|
@ -1,114 +0,0 @@
|
||||
import React from 'react';
|
||||
import nestedObjectAssign from 'nested-object-assign';
|
||||
import deprecate from 'util-deprecate';
|
||||
import { makeDecorator } from '@storybook/addons';
|
||||
import { logger } from '@storybook/client-logger';
|
||||
import Story from './components/Story';
|
||||
import PropTable from './components/PropTable/index';
|
||||
import makeTableComponent from './components/makeTableComponent';
|
||||
import { H1, H2, H3, H4, H5, H6, Code, P, UL, A, LI } from './components/markdown';
|
||||
|
||||
const defaultOptions = {
|
||||
inline: false,
|
||||
header: true,
|
||||
source: true,
|
||||
propTables: [],
|
||||
propTableCompare: (element, Component) =>
|
||||
// https://github.com/gaearon/react-hot-loader#checking-element-types
|
||||
typeof reactHotLoaderGlobal === 'undefined'
|
||||
? element.type === Component
|
||||
: // eslint-disable-next-line no-undef
|
||||
reactHotLoaderGlobal.areComponentsEqual(element.type, Component),
|
||||
TableComponent: PropTable,
|
||||
maxPropsIntoLine: 3,
|
||||
maxPropObjectKeys: 3,
|
||||
maxPropArrayLength: 3,
|
||||
maxPropStringLength: 50,
|
||||
};
|
||||
|
||||
const defaultComponents = {
|
||||
h1: H1,
|
||||
h2: H2,
|
||||
h3: H3,
|
||||
h4: H4,
|
||||
h5: H5,
|
||||
h6: H6,
|
||||
code: Code,
|
||||
p: P,
|
||||
a: A,
|
||||
li: LI,
|
||||
ul: UL,
|
||||
};
|
||||
|
||||
let hasWarned = false;
|
||||
|
||||
function addInfo(storyFn, context, infoOptions) {
|
||||
const options = {
|
||||
...defaultOptions,
|
||||
...infoOptions,
|
||||
};
|
||||
|
||||
// props.propTables can only be either an array of components or null
|
||||
// propTables option is allowed to be set to 'false' (a boolean)
|
||||
// if the option is false, replace it with null to avoid react warnings
|
||||
if (!options.propTables) {
|
||||
options.propTables = null;
|
||||
}
|
||||
|
||||
const components = { ...defaultComponents };
|
||||
if (options && options.components) {
|
||||
Object.assign(components, options.components);
|
||||
}
|
||||
if (options && options.marksyConf) {
|
||||
if (!hasWarned) {
|
||||
logger.warn('@storybook/addon-info: "marksyConf" option has been renamed to "components"');
|
||||
hasWarned = true;
|
||||
}
|
||||
|
||||
Object.assign(components, options.marksyConf);
|
||||
}
|
||||
const props = {
|
||||
info: options.text,
|
||||
context,
|
||||
showInline: Boolean(options.inline),
|
||||
showHeader: Boolean(options.header),
|
||||
showSource: Boolean(options.source),
|
||||
styles:
|
||||
typeof options.styles === 'function'
|
||||
? options.styles
|
||||
: s => nestedObjectAssign({}, s, options.styles),
|
||||
propTables: options.propTables,
|
||||
propTablesExclude: options.propTablesExclude,
|
||||
propTableCompare: options.propTableCompare,
|
||||
PropTable: makeTableComponent(options.TableComponent),
|
||||
components,
|
||||
maxPropObjectKeys: options.maxPropObjectKeys,
|
||||
maxPropArrayLength: options.maxPropArrayLength,
|
||||
maxPropsIntoLine: options.maxPropsIntoLine,
|
||||
maxPropStringLength: options.maxPropStringLength,
|
||||
excludedPropTypes: options.excludedPropTypes,
|
||||
};
|
||||
return <Story {...props}>{storyFn(context)}</Story>;
|
||||
}
|
||||
|
||||
export const withInfo = makeDecorator({
|
||||
name: 'withInfo',
|
||||
parameterName: 'info',
|
||||
allowDeprecatedUsage: true,
|
||||
wrapper: (getStory, context, { options, parameters }) => {
|
||||
const storyOptions = parameters || options;
|
||||
const infoOptions = typeof storyOptions === 'string' ? { text: storyOptions } : storyOptions;
|
||||
const mergedOptions =
|
||||
typeof infoOptions === 'string' ? infoOptions : { ...options, ...infoOptions };
|
||||
return addInfo(getStory, context, mergedOptions);
|
||||
},
|
||||
});
|
||||
|
||||
export { Story };
|
||||
|
||||
export function setDefaults(newDefaults) {
|
||||
return deprecate(
|
||||
() => Object.assign(defaultOptions, newDefaults),
|
||||
'setDefaults is deprecated. Instead, you can pass options into withInfo(options) directly, or use the info parameter.'
|
||||
)();
|
||||
}
|
14
addons/info/src/react-utils.js
vendored
14
addons/info/src/react-utils.js
vendored
@ -1,14 +0,0 @@
|
||||
import { isMemo } from 'react-is';
|
||||
|
||||
export function getType(typeOrMemo) {
|
||||
return isMemo(typeOrMemo) ? typeOrMemo.type : typeOrMemo;
|
||||
}
|
||||
|
||||
export function getDisplayName(typeOrMemo) {
|
||||
if (typeof typeOrMemo === 'string') {
|
||||
return typeOrMemo;
|
||||
}
|
||||
|
||||
const type = getType(typeOrMemo);
|
||||
return type.displayName || type.name || 'Unknown';
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-jest",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "React storybook addon that show component jest report",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -22,23 +22,23 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "Renaud Tertrais <renaud.tertrais@gmail.com> (https://github.com/renaudtertrais)",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/components": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/theming": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"@storybook/components": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"@storybook/theming": "6.0.0-alpha.6",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
"react": "^16.8.3",
|
||||
@ -47,10 +47,12 @@
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/webpack-env": "^1.15.0"
|
||||
"@types/webpack-env": "^1.15.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
"react": "*",
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-knobs",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "Storybook Addon Prop Editor Component",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -16,29 +16,29 @@
|
||||
"directory": "addons/knobs"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/client-api": "6.0.0-alpha.1",
|
||||
"@storybook/components": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/theming": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"@storybook/client-api": "6.0.0-alpha.6",
|
||||
"@storybook/components": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"@storybook/theming": "6.0.0-alpha.6",
|
||||
"@types/react-color": "^3.0.1",
|
||||
"copy-to-clipboard": "^3.0.8",
|
||||
"core-js": "^3.0.1",
|
||||
"escape-html": "^1.0.3",
|
||||
"fast-deep-equal": "^2.0.1",
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"global": "^4.3.2",
|
||||
"lodash": "^4.17.15",
|
||||
"prop-types": "^15.7.2",
|
||||
@ -51,10 +51,12 @@
|
||||
"@types/escape-html": "0.0.20",
|
||||
"@types/react-lifecycles-compat": "^3.0.1",
|
||||
"@types/react-select": "^2.0.19",
|
||||
"@types/webpack-env": "^1.15.0"
|
||||
"@types/webpack-env": "^1.15.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
"react": "*",
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-links",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "Story Links addon for storybook",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -16,35 +16,37 @@
|
||||
"directory": "addons/links"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/client-logger": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/client-logger": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"@storybook/csf": "0.0.1",
|
||||
"@storybook/router": "6.0.0-alpha.1",
|
||||
"@storybook/router": "6.0.0-alpha.6",
|
||||
"@types/qs": "^6.9.0",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
"prop-types": "^15.7.2",
|
||||
"qs": "^6.6.0",
|
||||
"ts-dedent": "^1.1.0"
|
||||
"ts-dedent": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/webpack-env": "^1.15.0"
|
||||
"@types/webpack-env": "^1.15.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
"react": "*",
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -1,106 +0,0 @@
|
||||
# Storybook Addon Notes
|
||||
|
||||
Storybook Addon Notes allows you to write notes (text or HTML) for your stories in [Storybook](https://storybook.js.org).
|
||||
|
||||
[Framework Support](https://github.com/storybookjs/storybook/blob/master/ADDONS_SUPPORT.md)
|
||||
|
||||

|
||||
|
||||
## Getting Started
|
||||
|
||||
**NOTE: Documentation on `next` branch is for alpha version, stable release is on [master](https://github.com/storybookjs/storybook/tree/master/addons/)**
|
||||
|
||||
```sh
|
||||
yarn add -D @storybook/addon-notes
|
||||
```
|
||||
|
||||
within `.storybook/main.js`:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
addons: ['@storybook/addon-notes/register']
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively register the notes addon into a panel. Choose only one, not both.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
addons: ['@storybook/addon-notes/register-panel']
|
||||
}
|
||||
```
|
||||
|
||||
Now, you can use the `notes` parameter to add a note to each story.
|
||||
|
||||
|
||||
```js
|
||||
import Component from './Component';
|
||||
|
||||
export default {
|
||||
title: 'Component',
|
||||
parameters: {
|
||||
notes: 'some documentation here',
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Upgrading to CSF Format
|
||||
|
||||
Add `notes` to the `parameters` object:
|
||||
|
||||
```js
|
||||
export default {
|
||||
parameters: {
|
||||
notes: 'My notes',
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Using Markdown
|
||||
|
||||
Using Markdown in your notes is supported, Storybook will load Markdown as raw by default.
|
||||
|
||||
```js
|
||||
import Component from './Component';
|
||||
import markdown from './someMarkdownText.md';
|
||||
|
||||
export default {
|
||||
title: 'Component',
|
||||
};
|
||||
|
||||
export const withMarkdown = () => <Component />;
|
||||
withmarkdown.story = {
|
||||
parameters: {
|
||||
notes: { markdown },
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Giphy
|
||||
|
||||
When using Markdown, you can also embed gifs from Giphy into your Markdown. Currently, the value `cheese` of the query prop is used to search and return the first result returned by Giphy.
|
||||
|
||||
```md
|
||||
# Title
|
||||
|
||||
<Giphy query='cheese' />
|
||||
```
|
||||
|
||||
## Multiple Notes Sections
|
||||
|
||||
If you need to display different notes for different consumers of your storybook (e.g design, developers), you can configure multiple notes pages. The following will render a tab with unique notes for both `Introduction` and `Design`.
|
||||
|
||||
```js
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import Component from './Component';
|
||||
|
||||
import intro from './intro.md';
|
||||
import design from './design.md';
|
||||
|
||||
export default {
|
||||
title: 'Component',
|
||||
parameters: {
|
||||
notes: { Introduction: intro, 'Design Notes': design },
|
||||
},
|
||||
};
|
||||
```
|
Binary file not shown.
Before Width: | Height: | Size: 93 KiB |
@ -1,58 +0,0 @@
|
||||
{
|
||||
"name": "@storybook/addon-notes",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"description": "Write notes for your Storybook stories.",
|
||||
"keywords": [
|
||||
"addon",
|
||||
"notes",
|
||||
"storybook"
|
||||
],
|
||||
"homepage": "https://github.com/storybookjs/storybook/tree/master/addons/notes",
|
||||
"bugs": {
|
||||
"url": "https://github.com/storybookjs/storybook/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/storybookjs/storybook.git",
|
||||
"directory": "addons/notes"
|
||||
},
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/public_api.js",
|
||||
"types": "dist/public_api.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/client-logger": "6.0.0-alpha.1",
|
||||
"@storybook/components": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/router": "6.0.0-alpha.1",
|
||||
"@storybook/theming": "6.0.0-alpha.1",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
"markdown-to-jsx": "^6.10.3",
|
||||
"memoizerific": "^1.11.3",
|
||||
"prop-types": "^15.7.2",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/prop-types": "^15.5.9",
|
||||
"@types/util-deprecate": "^1.0.0",
|
||||
"@types/webpack-env": "^1.15.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"gitHead": "4b9d901add9452525135caae98ae5f78dd8da9ff"
|
||||
}
|
@ -1 +0,0 @@
|
||||
require('./dist/register.js').default('panel');
|
@ -1 +0,0 @@
|
||||
require('./dist/register.js').default('tab');
|
@ -1,45 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow, mount } from 'enzyme';
|
||||
import { Link } from '@reach/router';
|
||||
import { SyntaxHighlighter as SyntaxHighlighterBase } from '@storybook/components';
|
||||
import { SyntaxHighlighter, NotesLink } from './Panel';
|
||||
|
||||
describe('NotesPanel', () => {
|
||||
describe('SyntaxHighlighter component', () => {
|
||||
it('should return code if className is undefined', () => {
|
||||
const wrapper = shallow(<SyntaxHighlighter>some text</SyntaxHighlighter>);
|
||||
const code = wrapper.find('code');
|
||||
expect(code.exists()).toBeTruthy();
|
||||
expect(code.text()).toBe('some text');
|
||||
});
|
||||
it('should return SyntaxHighlighterBase if there is a className prop', () => {
|
||||
const wrapper = shallow(
|
||||
<SyntaxHighlighter className="lang-jsx">some text</SyntaxHighlighter>
|
||||
);
|
||||
const syntaxHighlighterBase = wrapper.find(SyntaxHighlighterBase);
|
||||
expect(syntaxHighlighterBase.exists()).toBeTruthy();
|
||||
expect(syntaxHighlighterBase.prop('language')).toBe('jsx');
|
||||
});
|
||||
});
|
||||
|
||||
describe('NotesLink component', () => {
|
||||
it('should render storybook links with @storybook/router Link', () => {
|
||||
const component = mount(
|
||||
<NotesLink href="/story/addon-notes" title="title">
|
||||
Storybook Link
|
||||
</NotesLink>
|
||||
);
|
||||
expect(component.find(Link).prop('to')).toBe('/?path=/story/addon-notes');
|
||||
expect(component.find(Link).prop('title')).toBe('title');
|
||||
});
|
||||
it('should render absolute links as <a>', () => {
|
||||
const component = mount(
|
||||
<NotesLink href="https://example.com" title="title">
|
||||
Storybook Link
|
||||
</NotesLink>
|
||||
);
|
||||
expect(component.find('a').prop('href')).toBe('https://example.com');
|
||||
expect(component.find('a').prop('title')).toBe('title');
|
||||
});
|
||||
});
|
||||
});
|
@ -1,218 +0,0 @@
|
||||
import React, { ReactElement, Fragment, ReactNode } from 'react';
|
||||
import { types } from '@storybook/addons';
|
||||
import { API, Consumer, Combo } from '@storybook/api';
|
||||
import { Link as RouterLink } from '@storybook/router';
|
||||
import { styled } from '@storybook/theming';
|
||||
|
||||
import {
|
||||
SyntaxHighlighter as SyntaxHighlighterBase,
|
||||
Placeholder,
|
||||
DocumentWrapper,
|
||||
Link,
|
||||
TabWrapper,
|
||||
TabsState,
|
||||
} from '@storybook/components';
|
||||
import Markdown from 'markdown-to-jsx';
|
||||
import Giphy from './giphy';
|
||||
|
||||
import { formatter } from './formatter';
|
||||
|
||||
import { PARAM_KEY, Parameters } from './shared';
|
||||
|
||||
const Panel = styled.div<{}>(({ theme }) => ({
|
||||
padding: '3rem 40px',
|
||||
boxSizing: 'border-box',
|
||||
width: '100%',
|
||||
maxWidth: 980,
|
||||
margin: '0 auto',
|
||||
...(theme.addonNotesTheme || {}),
|
||||
}));
|
||||
|
||||
interface Props {
|
||||
active: boolean;
|
||||
api: API;
|
||||
}
|
||||
|
||||
function read(param: Parameters | undefined): Record<string, string> | string | undefined {
|
||||
if (!param) {
|
||||
return undefined;
|
||||
}
|
||||
if (typeof param === 'string') {
|
||||
return param;
|
||||
}
|
||||
if ('disable' in param) {
|
||||
return undefined;
|
||||
}
|
||||
if ('text' in param) {
|
||||
return param.text;
|
||||
}
|
||||
if ('markdown' in param) {
|
||||
return param.markdown;
|
||||
}
|
||||
if (typeof param === 'object') {
|
||||
return param;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
interface SyntaxHighlighterProps {
|
||||
className?: string;
|
||||
children: ReactElement;
|
||||
[key: string]: any;
|
||||
}
|
||||
export const SyntaxHighlighter = ({ className, children, ...props }: SyntaxHighlighterProps) => {
|
||||
// markdown-to-jsx does not add className to inline code
|
||||
if (typeof className !== 'string') {
|
||||
return <code>{children}</code>;
|
||||
}
|
||||
// className: "lang-jsx"
|
||||
const language = className.split('-');
|
||||
return (
|
||||
<SyntaxHighlighterBase
|
||||
language={language[1] || 'plaintext'}
|
||||
bordered
|
||||
format={false}
|
||||
copyable
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</SyntaxHighlighterBase>
|
||||
);
|
||||
};
|
||||
|
||||
interface NotesLinkProps {
|
||||
href: string;
|
||||
children: ReactElement;
|
||||
}
|
||||
export const NotesLink = ({ href, children, ...props }: NotesLinkProps) => {
|
||||
/* https://github.com/sindresorhus/is-absolute-url/blob/master/index.js */
|
||||
const isAbsoluteUrl = /^[a-z][a-z0-9+.-]*:/.test(href);
|
||||
const isAnchorUrl = /^#.*/.test(href);
|
||||
|
||||
if (isAbsoluteUrl || isAnchorUrl) {
|
||||
return (
|
||||
<a href={href} {...props}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<RouterLink to={href} {...props}>
|
||||
{children}
|
||||
</RouterLink>
|
||||
);
|
||||
};
|
||||
|
||||
// use our SyntaxHighlighter component in place of a <code> element when
|
||||
// converting markdown to react elements
|
||||
const defaultOptions = {
|
||||
overrides: {
|
||||
code: SyntaxHighlighter,
|
||||
a: NotesLink,
|
||||
Giphy: {
|
||||
component: Giphy,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
interface Overrides {
|
||||
overrides: {
|
||||
[type: string]: ReactNode;
|
||||
};
|
||||
}
|
||||
type Options = typeof defaultOptions & Overrides;
|
||||
|
||||
const mapper = ({
|
||||
state,
|
||||
api,
|
||||
}: Combo): { value?: string | Record<string, string>; options: Options } => {
|
||||
const extraElements = Object.entries(api.getElements(types.NOTES_ELEMENT)).reduce(
|
||||
(acc, [k, v]) => ({ ...acc, [k]: v.render }),
|
||||
{}
|
||||
);
|
||||
const options = {
|
||||
...defaultOptions,
|
||||
overrides: { ...defaultOptions.overrides, ...extraElements },
|
||||
};
|
||||
|
||||
const story = state.storiesHash[state.storyId];
|
||||
const value = read(story ? api.getParameters(story.id, PARAM_KEY) : undefined);
|
||||
|
||||
return { options, value };
|
||||
};
|
||||
|
||||
const NotesPanel = ({ active }: Props) => {
|
||||
if (!active) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Consumer filter={mapper}>
|
||||
{({ options, value }: { options: Options; value?: string | Record<string, string> }) => {
|
||||
if (!value) {
|
||||
return (
|
||||
<Placeholder>
|
||||
<Fragment>No notes yet</Fragment>
|
||||
<Fragment>
|
||||
Learn how to
|
||||
<Link
|
||||
href="https://github.com/storybookjs/storybook/tree/master/addons/notes"
|
||||
target="_blank"
|
||||
withArrow
|
||||
secondary
|
||||
cancel={false}
|
||||
>
|
||||
document components in Markdown
|
||||
</Link>
|
||||
</Fragment>
|
||||
</Placeholder>
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof value === 'string' || Object.keys(value).length === 1) {
|
||||
const md = typeof value === 'object' ? Object.values(value)[0] : value;
|
||||
|
||||
return (
|
||||
<Panel className="addon-notes-container">
|
||||
<DocumentWrapper>
|
||||
<Markdown options={options}>{formatter(md)}</Markdown>
|
||||
</DocumentWrapper>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
const groups: { title: string; render: (props: { active: boolean }) => void }[] = [];
|
||||
|
||||
Object.entries(value).forEach(([title, docs]) => {
|
||||
groups.push({
|
||||
title,
|
||||
render: ({ active: isActive }) => (
|
||||
<TabWrapper key={title} active={isActive}>
|
||||
<Panel>
|
||||
<DocumentWrapper>
|
||||
<Markdown options={options}>{formatter(docs)}</Markdown>
|
||||
</DocumentWrapper>
|
||||
</Panel>
|
||||
</TabWrapper>
|
||||
),
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="addon-notes-container">
|
||||
<TabsState>
|
||||
{groups.map(group => (
|
||||
<div id={group.title} key={group.title} title={group.title}>
|
||||
{group.render}
|
||||
</div>
|
||||
))}
|
||||
</TabsState>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotesPanel;
|
@ -1,26 +0,0 @@
|
||||
import memoize from 'memoizerific';
|
||||
|
||||
export const formatter = memoize(2)((code: string) => {
|
||||
// code provided to the component is often coming from template literals, which preserve whitespace.
|
||||
// sometimes the first line doesn't have padding, but the second does.
|
||||
// we split the code-string into lines, then if we find padding on line 0 or 1,
|
||||
// we assume that padding is bad, and remove that much padding on all following lines
|
||||
return code
|
||||
.split(/\n/)
|
||||
.reduce(
|
||||
(acc, i, index) => {
|
||||
const match = i.match(/^((:?\s|\t)+)/);
|
||||
const padding = match ? match[1] : '';
|
||||
|
||||
if (acc.firstIndent === '' && padding && index < 3) {
|
||||
return { result: `${acc.result}\n${i.replace(padding, '')}`, firstIndent: padding };
|
||||
}
|
||||
return {
|
||||
result: `${acc.result}\n${i.replace(acc.firstIndent, '').replace(/\s*$/, '')}`,
|
||||
firstIndent: acc.firstIndent,
|
||||
};
|
||||
},
|
||||
{ firstIndent: '', result: '' }
|
||||
)
|
||||
.result.trim();
|
||||
});
|
@ -1,37 +0,0 @@
|
||||
import { fetch } from 'global';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { logger } from '@storybook/client-logger';
|
||||
|
||||
interface Props {
|
||||
query: string;
|
||||
}
|
||||
interface State {
|
||||
src: string | null;
|
||||
}
|
||||
export default class Giphy extends Component<Props, State> {
|
||||
state: State = {
|
||||
src: null,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { query } = this.props;
|
||||
// TODO: replace this api_key, and make it configurable
|
||||
// note: I have requested a production api_key:
|
||||
// it's pending: bluXZc8ZAre19mvTtVi900CdsJhbVTEK
|
||||
fetch(`http://api.giphy.com/v1/gifs/search?limit=1&api_key=dc6zaTOxFJmzC&q=${query}`)
|
||||
.then((response: { ok: any; json: () => void }) => response.ok && response.json())
|
||||
.then((data: { data: { images: { original: { url: string } } }[] }) => {
|
||||
this.setState({
|
||||
src: data.data[0].images.original.url,
|
||||
});
|
||||
})
|
||||
.catch((e: any) => logger.error(e));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { src } = this.state;
|
||||
// TODO: we should have a nice looking <Img /> component
|
||||
return src ? <img src={src} alt="" /> : null;
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
import { makeDecorator, StoryContext, StoryGetter, WrapperSettings } from '@storybook/addons';
|
||||
import deprecate from 'util-deprecate';
|
||||
|
||||
// todo resolve any after @storybook/addons and @storybook/channels are migrated to TypeScript
|
||||
export const withNotes = makeDecorator({
|
||||
name: 'withNotes',
|
||||
parameterName: 'notes',
|
||||
skipIfNoParametersOrOptions: true,
|
||||
allowDeprecatedUsage: true,
|
||||
|
||||
wrapper: deprecate(
|
||||
(getStory: StoryGetter, context: StoryContext, { options, parameters }: WrapperSettings) => {
|
||||
const storyOptions = parameters || options;
|
||||
|
||||
const { text, markdown } =
|
||||
typeof storyOptions === 'string'
|
||||
? {
|
||||
text: storyOptions,
|
||||
markdown: undefined,
|
||||
}
|
||||
: storyOptions;
|
||||
|
||||
if (!text && !markdown) {
|
||||
throw new Error(
|
||||
`Parameter 'notes' must must be a string or an object with 'text' or 'markdown' properties`
|
||||
);
|
||||
}
|
||||
|
||||
return getStory(context);
|
||||
},
|
||||
'withNotes is deprecated'
|
||||
),
|
||||
});
|
||||
|
||||
export const withMarkdownNotes = deprecate((text: string, options: any) => {},
|
||||
'withMarkdownNotes is deprecated');
|
||||
|
||||
if (module && module.hot && module.hot.decline) {
|
||||
module.hot.decline();
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from '.';
|
@ -1,20 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import addons, { types } from '@storybook/addons';
|
||||
|
||||
import { ADDON_ID, PANEL_ID, PARAM_KEY } from './shared';
|
||||
|
||||
// TODO: fix eslint in tslint (igor said he fixed it, should ask him)
|
||||
import Panel from './Panel';
|
||||
|
||||
export default function register(type: types) {
|
||||
addons.register(ADDON_ID, api => {
|
||||
addons.add(PANEL_ID, {
|
||||
type,
|
||||
title: 'Notes',
|
||||
route: ({ storyId }) => `/info/${storyId}`, // todo add type
|
||||
match: ({ viewMode }) => viewMode === 'info', // todo add type
|
||||
render: ({ active, key }) => <Panel api={api} active={active} key={key} />,
|
||||
paramKey: PARAM_KEY,
|
||||
});
|
||||
});
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
export const ADDON_ID = 'storybookjs/notes';
|
||||
export const PANEL_ID = `${ADDON_ID}/panel`;
|
||||
export const PARAM_KEY = `notes`;
|
||||
|
||||
interface TextParameter {
|
||||
text: string;
|
||||
}
|
||||
interface MarkdownParameter {
|
||||
markdown: string;
|
||||
}
|
||||
interface DisabledParameter {
|
||||
disable: boolean;
|
||||
}
|
||||
type TabsParameter = Record<string, string>;
|
||||
|
||||
export type Parameters =
|
||||
| string
|
||||
| TextParameter
|
||||
| MarkdownParameter
|
||||
| DisabledParameter
|
||||
| TabsParameter;
|
7
addons/notes/src/typings.d.ts
vendored
7
addons/notes/src/typings.d.ts
vendored
@ -1,7 +0,0 @@
|
||||
// There are no types for markdown-to-jsx
|
||||
declare module 'markdown-to-jsx' {
|
||||
const Markdown: any;
|
||||
export default Markdown;
|
||||
}
|
||||
|
||||
declare module 'global';
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-options",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "Options addon for storybook",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -16,27 +16,29 @@
|
||||
"directory": "addons/options"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/public_api.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/public_api.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"core-js": "^3.0.1",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/webpack-env": "^1.15.0"
|
||||
"@types/webpack-env": "^1.15.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
"react": "*",
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-queryparams",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "parameter addon for storybook",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -17,32 +17,36 @@
|
||||
"directory": "addons/addon-queryparams"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/api": "6.0.0-alpha.1",
|
||||
"@storybook/client-logger": "6.0.0-alpha.1",
|
||||
"@storybook/components": "6.0.0-alpha.1",
|
||||
"@storybook/core-events": "6.0.0-alpha.1",
|
||||
"@storybook/theming": "6.0.0-alpha.1",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/api": "6.0.0-alpha.6",
|
||||
"@storybook/client-logger": "6.0.0-alpha.6",
|
||||
"@storybook/components": "6.0.0-alpha.6",
|
||||
"@storybook/core-events": "6.0.0-alpha.6",
|
||||
"@storybook/theming": "6.0.0-alpha.6",
|
||||
"core-js": "^3.0.1",
|
||||
"global": "^4.3.2",
|
||||
"qs": "^6.6.0",
|
||||
"react": "^16.8.3",
|
||||
"ts-dedent": "^1.1.0"
|
||||
"ts-dedent": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/webpack-env": "^1.15.0"
|
||||
"@types/webpack-env": "^1.15.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -381,7 +381,7 @@ NOTICE that When using the `asyncJest: true` option, you also must specify a `te
|
||||
|
||||
This is a really powerful technique to write stories of Relay components because it integrates data fetching with component rendering. So instead of passing data props manually, we can let Relay do the job for us as it does in our application.
|
||||
|
||||
Whenever you change you're data requirements by adding (and rendering) or (accidentally) deleting fields in your graphql query fragments, you'll get a different snapshot and thus an error in the StoryShot test.
|
||||
Whenever you change your data requirements by adding (and rendering) or (accidentally) deleting fields in your graphql query fragments, you'll get a different snapshot and thus an error in the StoryShot test.
|
||||
|
||||
## Options
|
||||
|
||||
@ -677,3 +677,22 @@ initStoryshots({
|
||||
### `asyncJest`
|
||||
|
||||
Enables Jest `done()` callback in the StoryShots tests for async testing. See [StoryShots for async rendered components](#storyshots-for-async-rendered-components) for more info.
|
||||
|
||||
|
||||
## Story Parameters
|
||||
|
||||
### `disable`
|
||||
|
||||
Some stories are difficult or impossible to snapshot, such as those covering components that use external DOM-modifying libraries, and those that deliberately throw errors. It is possible to skip stories like these by giving them a parameter of `storyshots: {disable: true}`. There is also a shorthand for this, `storyshots: false`.
|
||||
|
||||
```js
|
||||
export const Exception = () => {
|
||||
throw new Error('storyFn threw an error! WHOOPS');
|
||||
};
|
||||
Exception.story = {
|
||||
name: 'story throws exception',
|
||||
parameters: {
|
||||
storyshots: { disable: true },
|
||||
},
|
||||
};
|
||||
```
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-storyshots",
|
||||
"version": "6.0.0-alpha.1",
|
||||
"version": "6.0.0-alpha.6",
|
||||
"description": "StoryShots is a Jest Snapshot Testing Addon for Storybook.",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -16,14 +16,14 @@
|
||||
"directory": "addons/storyshots/storyshots-core"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"README.md",
|
||||
"*.js",
|
||||
"*.d.ts"
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build-storybook": "build-storybook",
|
||||
"example": "jest storyshot.test",
|
||||
@ -31,30 +31,35 @@
|
||||
"storybook": "start-storybook -p 6006"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jest/transform": "^24.9.0",
|
||||
"@storybook/addons": "6.0.0-alpha.1",
|
||||
"@storybook/client-api": "6.0.0-alpha.1",
|
||||
"@storybook/core": "6.0.0-alpha.1",
|
||||
"@jest/transform": "^25.1.0",
|
||||
"@storybook/addons": "6.0.0-alpha.6",
|
||||
"@storybook/client-api": "6.0.0-alpha.6",
|
||||
"@storybook/core": "6.0.0-alpha.6",
|
||||
"@types/glob": "^7.1.1",
|
||||
"@types/jest": "^24.0.16",
|
||||
"@types/jest": "^25.1.1",
|
||||
"@types/jest-specific-snapshot": "^0.5.3",
|
||||
"babel-plugin-require-context-hook": "^1.0.0",
|
||||
"core-js": "^3.0.1",
|
||||
"glob": "^7.1.3",
|
||||
"global": "^4.3.2",
|
||||
"jest-specific-snapshot": "^2.0.0",
|
||||
"pretty-format": "^25.1.0",
|
||||
"read-pkg-up": "^7.0.0",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"ts-dedent": "^1.1.0"
|
||||
"ts-dedent": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/addon-docs": "6.0.0-alpha.1",
|
||||
"@storybook/react": "6.0.0-alpha.1",
|
||||
"@storybook/addon-docs": "6.0.0-alpha.6",
|
||||
"@storybook/react": "6.0.0-alpha.6",
|
||||
"babel-loader": "^8.0.6",
|
||||
"enzyme-to-json": "^3.4.1",
|
||||
"jest-emotion": "^10.0.17",
|
||||
"react": "^16.8.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-dom": "*",
|
||||
"regenerator-runtime": "*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
@ -25,6 +25,7 @@ function getIntegrityOptions({ integrityOptions }: StoryshotsOptions) {
|
||||
};
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
function ensureOptionsDefaults(options: StoryshotsOptions) {
|
||||
const {
|
||||
suite = 'Storyshots',
|
||||
@ -49,7 +50,7 @@ function ensureOptionsDefaults(options: StoryshotsOptions) {
|
||||
testMethod,
|
||||
snapshotSerializers,
|
||||
integrityOptions,
|
||||
};
|
||||
} as any;
|
||||
}
|
||||
|
||||
export default ensureOptionsDefaults;
|
||||
|
@ -4,15 +4,6 @@ import glob from 'glob';
|
||||
import { describe, it } from 'global';
|
||||
import dedent from 'ts-dedent';
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace,no-redeclare
|
||||
namespace jest {
|
||||
interface Matchers<R, T> {
|
||||
notToBeAbandoned(stories2snapsConverter: any): R;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect.extend({
|
||||
notToBeAbandoned(storyshots, stories2snapsConverter) {
|
||||
const abandonedStoryshots = storyshots.filter((fileName: string) => {
|
||||
@ -59,6 +50,7 @@ function integrityTest(integrityOptions: any, stories2snapsConverter: any) {
|
||||
const snapshotExtension = stories2snapsConverter.getSnapshotExtension();
|
||||
const storyshots = glob.sync(`**/*${snapshotExtension}`, integrityOptions);
|
||||
|
||||
// @ts-ignore
|
||||
expect(storyshots).notToBeAbandoned(stories2snapsConverter);
|
||||
});
|
||||
});
|
||||
|
@ -246,7 +246,7 @@ exports[`Storyshots Welcome MDX to Storybook 1`] = `
|
||||
}
|
||||
}
|
||||
>
|
||||
src/stories/index.js
|
||||
src/stories/1-Button.stories.js
|
||||
</code>
|
||||
</InlineCode>
|
||||
.)
|
||||
@ -450,7 +450,7 @@ exports[`Storyshots Welcome to Storybook 1`] = `
|
||||
}
|
||||
}
|
||||
>
|
||||
src/stories/index.js
|
||||
src/stories/1-Button.stories.js
|
||||
</code>
|
||||
</InlineCode>
|
||||
.)
|
||||
|
@ -139,7 +139,7 @@ exports[`Storyshots Welcome MDX to Storybook 1`] = `
|
||||
</InlineCode>
|
||||
stories located at
|
||||
<InlineCode>
|
||||
src/stories/index.js
|
||||
src/stories/1-Button.stories.js
|
||||
</InlineCode>
|
||||
.)
|
||||
</p>
|
||||
@ -213,7 +213,7 @@ exports[`Storyshots Welcome to Storybook 1`] = `
|
||||
</InlineCode>
|
||||
stories located at
|
||||
<InlineCode>
|
||||
src/stories/index.js
|
||||
src/stories/1-Button.stories.js
|
||||
</InlineCode>
|
||||
.)
|
||||
</p>
|
||||
|
@ -139,7 +139,7 @@ exports[`Storyshots Welcome MDX to Storybook 1`] = `
|
||||
</InlineCode>
|
||||
stories located at
|
||||
<InlineCode>
|
||||
src/stories/index.js
|
||||
src/stories/1-Button.stories.js
|
||||
</InlineCode>
|
||||
.)
|
||||
</p>
|
||||
@ -213,7 +213,7 @@ exports[`Storyshots Welcome to Storybook 1`] = `
|
||||
</InlineCode>
|
||||
stories located at
|
||||
<InlineCode>
|
||||
src/stories/index.js
|
||||
src/stories/1-Button.stories.js
|
||||
</InlineCode>
|
||||
.)
|
||||
</p>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user