From 821ac04c36d918984c905049479a49af5fb4c2a4 Mon Sep 17 00:00:00 2001 From: Hypnosphi Date: Sun, 19 May 2019 16:47:52 +0200 Subject: [PATCH 01/18] Addon React: POC of multiframework support using decorators --- addons/frameworks/react/package.json | 35 ++ addons/frameworks/react/src/client/index.ts | 36 ++ .../server/framework-preset-react-docgen.js | 0 .../framework-preset-react-docgen.test.js | 0 .../src/server/framework-preset-react.js | 0 addons/frameworks/react/src/typings.d.ts | 1 + addons/frameworks/react/tsconfig.json | 10 + addons/links/src/react/components/link.tsx | 2 +- app/react/package.json | 1 + app/react/src/server/options.js | 4 +- .../html-kitchen-sink/.storybook/config.js | 14 + .../html-kitchen-sink/.storybook/presets.js | 4 + examples/html-kitchen-sink/package.json | 8 +- .../html-kitchen-sink/stories/react/Logger.js | 76 ++++ .../stories/react/addon-a11y.stories.js | 101 +++++ .../stories/react/addon-actions.stories.js | 169 ++++++++ .../react/addon-backgrounds.stories.js | 36 ++ .../stories/react/addon-centered.stories.js | 10 + .../stories/react/addon-contexts.stories.js | 100 +++++ .../react/addon-cssresources.stories.js | 49 +++ .../stories/react/addon-events.stories.js | 93 ++++ .../stories/react/addon-graphql.stories.js | 44 ++ .../react/addon-info-resources/EXAMPLE.md | 3 + .../stories/react/addon-info.stories.js | 405 ++++++++++++++++++ .../stories/react/addon-knobs.stories.js | 329 ++++++++++++++ .../stories/react/addon-links.stories.js | 64 +++ .../stories/react/addon-notes.stories.js | 67 +++ .../stories/react/addon-options.stories.js | 19 + .../stories/react/addon-viewport.stories.js | 48 +++ .../stories/react/components/BaseButton.js | 28 ++ .../stories/react/components/DelayedRender.js | 30 ++ .../stories/react/components/DocgenButton.js | 149 +++++++ .../react/components/FlowTypeButton.js | 50 +++ .../react/components/ForwardedRefButton.js | 24 ++ .../ForwardedRefButtonWDisplayName.js | 28 ++ .../react/components/ImportedPropsButton.js | 15 + .../react/components/NamedExportButton.js | 24 ++ .../react/components/TableComponent.js | 51 +++ .../react/components/addon-a11y/Button.js | 48 +++ .../react/components/addon-a11y/Form/Input.js | 22 + .../react/components/addon-a11y/Form/Label.js | 23 + .../react/components/addon-a11y/Form/Row.js | 25 ++ .../react/components/addon-a11y/Form/index.js | 5 + .../stories/react/notes/notes.md | 11 + package.json | 1 + yarn.lock | 4 +- 46 files changed, 2260 insertions(+), 6 deletions(-) create mode 100644 addons/frameworks/react/package.json create mode 100644 addons/frameworks/react/src/client/index.ts rename {app => addons/frameworks}/react/src/server/framework-preset-react-docgen.js (100%) rename {app => addons/frameworks}/react/src/server/framework-preset-react-docgen.test.js (100%) rename {app => addons/frameworks}/react/src/server/framework-preset-react.js (100%) create mode 100644 addons/frameworks/react/src/typings.d.ts create mode 100644 addons/frameworks/react/tsconfig.json create mode 100644 examples/html-kitchen-sink/.storybook/presets.js create mode 100644 examples/html-kitchen-sink/stories/react/Logger.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-a11y.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-actions.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-backgrounds.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-centered.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-contexts.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-cssresources.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-events.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-graphql.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-info-resources/EXAMPLE.md create mode 100644 examples/html-kitchen-sink/stories/react/addon-info.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-knobs.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-links.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-notes.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-options.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/addon-viewport.stories.js create mode 100644 examples/html-kitchen-sink/stories/react/components/BaseButton.js create mode 100644 examples/html-kitchen-sink/stories/react/components/DelayedRender.js create mode 100644 examples/html-kitchen-sink/stories/react/components/DocgenButton.js create mode 100644 examples/html-kitchen-sink/stories/react/components/FlowTypeButton.js create mode 100644 examples/html-kitchen-sink/stories/react/components/ForwardedRefButton.js create mode 100644 examples/html-kitchen-sink/stories/react/components/ForwardedRefButtonWDisplayName.js create mode 100644 examples/html-kitchen-sink/stories/react/components/ImportedPropsButton.js create mode 100644 examples/html-kitchen-sink/stories/react/components/NamedExportButton.js create mode 100644 examples/html-kitchen-sink/stories/react/components/TableComponent.js create mode 100644 examples/html-kitchen-sink/stories/react/components/addon-a11y/Button.js create mode 100644 examples/html-kitchen-sink/stories/react/components/addon-a11y/Form/Input.js create mode 100644 examples/html-kitchen-sink/stories/react/components/addon-a11y/Form/Label.js create mode 100644 examples/html-kitchen-sink/stories/react/components/addon-a11y/Form/Row.js create mode 100644 examples/html-kitchen-sink/stories/react/components/addon-a11y/Form/index.js create mode 100644 examples/html-kitchen-sink/stories/react/notes/notes.md diff --git a/addons/frameworks/react/package.json b/addons/frameworks/react/package.json new file mode 100644 index 000000000000..510d6e88d986 --- /dev/null +++ b/addons/frameworks/react/package.json @@ -0,0 +1,35 @@ +{ + "name": "@storybook/addon-react", + "version": "5.1.0-beta.1", + "description": "React addon for Storybook", + "keywords": [ + "storybook", + "react" + ], + "homepage": "https://github.com/storybooks/storybook/tree/master/addons/app/react", + "bugs": { + "url": "https://github.com/storybooks/storybook/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/storybooks/storybook.git", + "directory": "app/react" + }, + "license": "MIT", + "main": "dist/client/index.js", + "types": "dist/client/index.d.ts", + "scripts": { + "prepare": "node ../../../scripts/prepare.js" + }, + "dependencies": { + "@storybook/addons": "5.1.0-beta.1", + "@storybook/core-events": "5.1.0-beta.1", + "global": "^4.3.2" + }, + "peerDependencies": { + "react-dom": "*" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/addons/frameworks/react/src/client/index.ts b/addons/frameworks/react/src/client/index.ts new file mode 100644 index 000000000000..4257a87a54ec --- /dev/null +++ b/addons/frameworks/react/src/client/index.ts @@ -0,0 +1,36 @@ +import ReactDOM from 'react-dom'; +import addons, { makeDecorator } from '@storybook/addons'; +import { REGISTER_SUBSCRIPTION, STORY_CHANGED } from '@storybook/core-events'; +import { document } from 'global'; + +let node = document.createElement('div'); + +const unmount = () => { + ReactDOM.unmountComponentAtNode(node); + node = document.createElement('div'); +}; + +const subscription = () => { + const channel = addons.getChannel(); + channel.on(STORY_CHANGED, unmount); + return () => { + unmount(); + channel.removeListener(STORY_CHANGED, unmount); + }; +}; + +export default makeDecorator({ + name: 'withReact', + parameterName: 'framework', + wrapper: (getStory, context, { parameters }) => { + const story = getStory(context); + if (!parameters || !parameters.react) { + return story; + } + + const channel = addons.getChannel(); + channel.emit(REGISTER_SUBSCRIPTION, subscription); + ReactDOM.render(story, node); + return node; + }, +}); diff --git a/app/react/src/server/framework-preset-react-docgen.js b/addons/frameworks/react/src/server/framework-preset-react-docgen.js similarity index 100% rename from app/react/src/server/framework-preset-react-docgen.js rename to addons/frameworks/react/src/server/framework-preset-react-docgen.js diff --git a/app/react/src/server/framework-preset-react-docgen.test.js b/addons/frameworks/react/src/server/framework-preset-react-docgen.test.js similarity index 100% rename from app/react/src/server/framework-preset-react-docgen.test.js rename to addons/frameworks/react/src/server/framework-preset-react-docgen.test.js diff --git a/app/react/src/server/framework-preset-react.js b/addons/frameworks/react/src/server/framework-preset-react.js similarity index 100% rename from app/react/src/server/framework-preset-react.js rename to addons/frameworks/react/src/server/framework-preset-react.js diff --git a/addons/frameworks/react/src/typings.d.ts b/addons/frameworks/react/src/typings.d.ts new file mode 100644 index 000000000000..2f4eb9cf4fd9 --- /dev/null +++ b/addons/frameworks/react/src/typings.d.ts @@ -0,0 +1 @@ +declare module 'global'; diff --git a/addons/frameworks/react/tsconfig.json b/addons/frameworks/react/tsconfig.json new file mode 100644 index 000000000000..022794d1b5af --- /dev/null +++ b/addons/frameworks/react/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "types": ["webpack-env"] + }, + "include": [ + "src/**/*" + ] +} diff --git a/addons/links/src/react/components/link.tsx b/addons/links/src/react/components/link.tsx index b84547609a87..3d3b3d3c6fef 100644 --- a/addons/links/src/react/components/link.tsx +++ b/addons/links/src/react/components/link.tsx @@ -29,7 +29,7 @@ interface State { } export default class LinkTo extends PureComponent { - defaultProps: Props = { + static defaultProps: Props = { kind: null, story: null, children: undefined, diff --git a/app/react/package.json b/app/react/package.json index 84b80ddae495..a419ea99a47d 100644 --- a/app/react/package.json +++ b/app/react/package.json @@ -29,6 +29,7 @@ "@babel/plugin-transform-react-constant-elements": "^7.2.0", "@babel/preset-flow": "^7.0.0", "@babel/preset-react": "^7.0.0", + "@storybook/addon-react": "5.1.0-beta.1", "@storybook/core": "5.1.0-beta.1", "@storybook/node-logger": "5.1.0-beta.1", "@svgr/webpack": "^4.0.3", diff --git a/app/react/src/server/options.js b/app/react/src/server/options.js index dd787ee58788..e450997ebe17 100644 --- a/app/react/src/server/options.js +++ b/app/react/src/server/options.js @@ -3,8 +3,8 @@ import packageJson from '../../package.json'; export default { packageJson, frameworkPresets: [ - require.resolve('./framework-preset-react.js'), + require.resolve('@storybook/addon-react/dist/server/framework-preset-react.js'), require.resolve('./framework-preset-cra.js'), - require.resolve('./framework-preset-react-docgen.js'), + require.resolve('@storybook/addon-react/dist/server/framework-preset-react-docgen.js'), ], }; diff --git a/examples/html-kitchen-sink/.storybook/config.js b/examples/html-kitchen-sink/.storybook/config.js index df93c95611ea..e51048817ca7 100644 --- a/examples/html-kitchen-sink/.storybook/config.js +++ b/examples/html-kitchen-sink/.storybook/config.js @@ -1,8 +1,22 @@ import { configure, addParameters, addDecorator } from '@storybook/html'; import { withA11y } from '@storybook/addon-a11y'; +import withReact from '@storybook/addon-react'; +import { ThemeProvider, themes, convert } from '@storybook/theming'; +import React from 'react'; addDecorator(withA11y); +addDecorator((getStory, context) => { + const story = getStory(context); + const { framework } = context.parameters; + if (!framework || !framework.react) { + return story; + } + + return {story}; +}); +addDecorator(withReact); + addParameters({ a11y: { config: {}, diff --git a/examples/html-kitchen-sink/.storybook/presets.js b/examples/html-kitchen-sink/.storybook/presets.js new file mode 100644 index 000000000000..698c38ad9da5 --- /dev/null +++ b/examples/html-kitchen-sink/.storybook/presets.js @@ -0,0 +1,4 @@ +module.exports = [ + '@storybook/addon-react/dist/server/framework-preset-react', + '@storybook/addon-react/dist/server/framework-preset-react-docgen', +]; diff --git a/examples/html-kitchen-sink/package.json b/examples/html-kitchen-sink/package.json index 4385985cb78b..ca18e8829b34 100644 --- a/examples/html-kitchen-sink/package.json +++ b/examples/html-kitchen-sink/package.json @@ -24,6 +24,7 @@ "@storybook/addon-links": "5.1.0-beta.1", "@storybook/addon-notes": "5.1.0-beta.1", "@storybook/addon-options": "5.1.0-beta.1", + "@storybook/addon-react": "5.1.0-beta.1", "@storybook/addon-storyshots": "5.1.0-beta.1", "@storybook/addon-storysource": "5.1.0-beta.1", "@storybook/addon-viewport": "5.1.0-beta.1", @@ -31,8 +32,13 @@ "@storybook/core": "5.1.0-beta.1", "@storybook/core-events": "5.1.0-beta.1", "@storybook/html": "5.1.0-beta.1", + "@storybook/theming": "5.1.0-beta.1", "eventemitter3": "^3.1.0", "format-json": "^1.0.3", - "global": "^4.3.2" + "global": "^4.3.2", + "react": "^16.8.6", + "react-dom": "^16.8.6", + "prop-types": "^15.7.2", + "uuid": "^3.3.2" } } diff --git a/examples/html-kitchen-sink/stories/react/Logger.js b/examples/html-kitchen-sink/stories/react/Logger.js new file mode 100644 index 000000000000..c9e47f0197cb --- /dev/null +++ b/examples/html-kitchen-sink/stories/react/Logger.js @@ -0,0 +1,76 @@ +import React, { Component } from 'react'; +import json from 'format-json'; +import PropTypes from 'prop-types'; + +import { styled } from '@storybook/theming'; +import EventEmitter from 'eventemitter3'; +import uuid from 'uuid/v4'; + +const Wrapper = styled.div({ + padding: 20, +}); +const Title = styled.h1({ + margin: 0, +}); +const Item = styled.div({ + listStyle: 'none', + marginBottom: 10, +}); + +export default class Logger extends Component { + static LOG_EVENT = 'Logger:log'; + + static propTypes = { + emitter: PropTypes.instanceOf(EventEmitter).isRequired, + title: PropTypes.string, + }; + + static defaultProps = { + title: 'Logger', + }; + + state = { + events: [], + }; + + componentDidMount() { + const { emitter } = this.props; + + emitter.on(Logger.LOG_EVENT, this.onEventHandler); + } + + componentWillUnmount() { + const { emitter } = this.props; + + emitter.removeListener(Logger.LOG_EVENT, this.onEventHandler); + } + + onEventHandler = ({ name, payload }) => { + this.setState(({ events }) => ({ + events: [...events, { name, id: uuid(), payload }], + })); + }; + + render() { + const { events } = this.state; + const { title } = this.props; + + return ( + + {title} +
+ {events.map(({ id, name, payload }) => ( + +
+ Event name: {name} +
+
+ Event payload: {json.plain(payload)} +
+
+ ))} +
+
+ ); + } +} diff --git a/examples/html-kitchen-sink/stories/react/addon-a11y.stories.js b/examples/html-kitchen-sink/stories/react/addon-a11y.stories.js new file mode 100644 index 000000000000..07316392357c --- /dev/null +++ b/examples/html-kitchen-sink/stories/react/addon-a11y.stories.js @@ -0,0 +1,101 @@ +import React, { Fragment } from 'react'; +import { storiesOf } from '@storybook/html'; + +import { Form } from '@storybook/components'; +import BaseButton from './components/BaseButton'; +import DelayedRender from './components/DelayedRender'; +import Button from './components/addon-a11y/Button'; + +const text = 'Testing the a11y addon'; +const image = 'http://placehold.it/350x150'; +// eslint-disable-next-line no-script-url +const href = 'javascript:void 0'; + +storiesOf('React|A11y/BaseButton', module) + .addParameters({ + framework: { react: true }, + options: { selectedPanel: 'storybook/a11y/panel' }, + }) + .add('Default', () => ) + .add('Label', () => ) + .add('Disabled', () => ) + .add('Invalid contrast', () => ( + // FIXME: has no effect on score + + )) + .add('delayed render', () => ( + + + + )); + +storiesOf('React|A11y/Button', module) + .addParameters({ + framework: { react: true }, + options: { selectedPanel: 'storybook/a11y/panel' }, + }) + .add('Default', () => ) + .add('Multiple actions', () => ( + + )) + .add('Multiple actions + config', () => ( + + )) + .add('Multiple actions as object', () => ( + + )) + .add('Multiple actions, object + config', () => ( + + )) + .add('Decorated action', () => ( + + )) + .add('Decorated action + config', () => ( + + )) + .add('Decorated actions', () => ( + + )) + .add('Decorated actions + config', () => ( + + )) + .add('Circular Payload', () => { + const circular = { foo: {} }; + circular.foo.circular = circular; + return ; + }) + .add('Reserved keyword as name', () => ) + .add('All types', () => { + function A() {} + function B() {} + + const bound = B.bind({}); + + let file; + try { + file = new File([''], 'filename.txt', { type: 'text/plain', lastModified: new Date() }); + } catch (error) { + file = error; + } + const reg = /fooBar/g; + + return ( + + + + + + + + + + + + + + + + + + + + + + + ); + }) + + .add('configureActionsDepth', () => { + configureActions({ + depth: 2, + }); + + return ( + + ); + }) + .add('Persisting the action logger', () => ( + +

Moving away from this story will persist the action logger

+ +
+ )) + .add('Limit Action Output', () => { + configureActions({ + limit: 2, + }); + + return ( + + + + + ); + }); + +storiesOf('React|Actions.deprecated', module) + .addParameters({ framework: { react: true } }) + .add('Decorated Action', () => ( + + )); diff --git a/examples/html-kitchen-sink/stories/react/addon-backgrounds.stories.js b/examples/html-kitchen-sink/stories/react/addon-backgrounds.stories.js new file mode 100644 index 000000000000..cf3d3e4ad1cc --- /dev/null +++ b/examples/html-kitchen-sink/stories/react/addon-backgrounds.stories.js @@ -0,0 +1,36 @@ +import React from 'react'; +import { storiesOf } from '@storybook/html'; + +import BaseButton from './components/BaseButton'; + +storiesOf('React|Backgrounds', module) + .addParameters({ + framework: { react: true }, + backgrounds: [ + { name: 'white', value: '#ffffff' }, + { name: 'light', value: '#eeeeee' }, + { name: 'gray', value: '#cccccc' }, + { name: 'dark', value: '#222222', default: true }, + { name: 'black', value: '#000000' }, + ], + }) + .add('story 1', () => ( + + )) + .add('story 2', () => ) + .add('overriden', () => , { + backgrounds: [ + { name: 'pink', value: 'hotpink' }, + { name: 'blue', value: 'deepskyblue', default: true }, + ], + }) + .add('disabled via []', () => , { + backgrounds: [], + }) + .add( + 'skipped via disable:true', + () => , + { + backgrounds: { disable: true }, + } + ); diff --git a/examples/html-kitchen-sink/stories/react/addon-centered.stories.js b/examples/html-kitchen-sink/stories/react/addon-centered.stories.js new file mode 100644 index 000000000000..1fc703572840 --- /dev/null +++ b/examples/html-kitchen-sink/stories/react/addon-centered.stories.js @@ -0,0 +1,10 @@ +import React from 'react'; +import { storiesOf } from '@storybook/html'; +import centered from '@storybook/addon-centered/react'; + +import BaseButton from './components/BaseButton'; + +storiesOf('React|Centered', module) + .addParameters({ framework: { react: true } }) + .addDecorator(centered) + .add('story 1', () => ); diff --git a/examples/html-kitchen-sink/stories/react/addon-contexts.stories.js b/examples/html-kitchen-sink/stories/react/addon-contexts.stories.js new file mode 100644 index 000000000000..65d2ceaa38ac --- /dev/null +++ b/examples/html-kitchen-sink/stories/react/addon-contexts.stories.js @@ -0,0 +1,100 @@ +import React from 'react'; +import { storiesOf } from '@storybook/html'; +import { withContexts } from '@storybook/addon-contexts/react'; + +// Example A: Simple CSS Theming +const topLevelContexts = [ + { + icon: 'sidebaralt', + title: 'CSS Themes', + components: ['div'], + params: [ + { + name: 'Desert', + props: { + style: { color: 'brown', background: '#F4A261', height: '100vh', padding: '10px' }, + }, + }, + { + name: 'Ocean', + props: { + style: { color: 'white', background: '#173F5F', height: '100vh', padding: '10px' }, + }, + default: true, + }, + ], + }, +]; + +const storyLevelContexts = [ + { + title: 'CSS Themes', + params: [ + { + name: 'Forest', + props: { + style: { color: 'teal', background: '#00b894', height: '100vh', padding: '10px' }, + }, + }, + ], + }, +]; + +const stories = storiesOf('React|Contexts', module) + .addParameters({ framework: { react: true } }) + .addDecorator(withContexts(topLevelContexts)); + +stories.add( + 'Simple CSS Theming', + () => <>I'm a children of the injected 'div' (where provides a theming context)., + { + contexts: storyLevelContexts, + } +); + +// Example B: Language (React Contexts API) +const NaiveIntlContext = React.createContext({ + locale: 'unknown', + greeting: 'NULL', +}); + +stories.add( + 'Languages', + () => ( + + {({ locale, greeting }) => `Your locale is "${locale}", so I say "${greeting}"!`} + + ), + { + contexts: [ + { + icon: 'globe', + title: 'Languages', + components: [NaiveIntlContext.Provider], + params: [ + { + name: 'English', + props: { + value: { locale: 'en', greeting: 'Hello' }, + }, + }, + { + name: 'French', + props: { + value: { locale: 'fr', greeting: 'Bonjour' }, + }, + }, + { + name: 'Chinese', + props: { + value: { locale: 'cn', greeting: '你好' }, + }, + }, + ], + options: { + cancelable: true, + }, + }, + ], + } +); diff --git a/examples/html-kitchen-sink/stories/react/addon-cssresources.stories.js b/examples/html-kitchen-sink/stories/react/addon-cssresources.stories.js new file mode 100644 index 000000000000..990519357cc1 --- /dev/null +++ b/examples/html-kitchen-sink/stories/react/addon-cssresources.stories.js @@ -0,0 +1,49 @@ +import React from 'react'; +import { storiesOf } from '@storybook/html'; + +storiesOf('React|Cssresources', module) + .addParameters({ + framework: { react: true }, + cssresources: [ + { + id: `bootstrap v4.1.3`, + code: ``, + picked: true, + }, + { + id: `bootstrap v3.3.5`, + code: ``, + picked: false, + }, + ], + options: { + selectedPanel: 'storybook/cssresources/panel', + }, + }) + .add('Primary Large Button', () => ( + + )); + +storiesOf('React|Cssresources', module) + .addParameters({ + framework: { react: true }, + cssresources: [ + { + id: `fontawesome`, + code: ``, + picked: true, + }, + { + id: `whitetheme`, + code: ``, + picked: false, + }, + ], + options: { + selectedPanel: 'storybook/cssresources/panel', + }, + }) + + .add('Camera Icon', () => Camera Icon); diff --git a/examples/html-kitchen-sink/stories/react/addon-events.stories.js b/examples/html-kitchen-sink/stories/react/addon-events.stories.js new file mode 100644 index 000000000000..b5440e8b745c --- /dev/null +++ b/examples/html-kitchen-sink/stories/react/addon-events.stories.js @@ -0,0 +1,93 @@ +import React from 'react'; +import EventEmitter from 'eventemitter3'; +import { storiesOf } from '@storybook/html'; + +import withEvents from '@storybook/addon-events'; +import Logger from './Logger'; + +const EVENTS = { + TEST_EVENT_1: 'test-event-1', + TEST_EVENT_2: 'test-event-2', + TEST_EVENT_3: 'test-event-3', + TEST_EVENT_4: 'test-event-4', +}; + +const emitter = new EventEmitter(); +const emit = emitter.emit.bind(emitter); + +const eventHandler = name => payload => emit(Logger.LOG_EVENT, { name, payload }); + +Object.keys(EVENTS).forEach(event => emitter.on(EVENTS[event], eventHandler(EVENTS[event]))); + +const events = [ + { + name: EVENTS.TEST_EVENT_1, + title: 'Test event 1', + payload: 0, + }, + { + name: EVENTS.TEST_EVENT_2, + title: 'Test event 2', + payload: 'Test event 2', + }, + { + name: EVENTS.TEST_EVENT_3, + title: 'Test event 3', + payload: { + string: 'value', + number: 123, + array: [1, 2, 3], + object: { + string: 'value', + number: 123, + array: [1, 2, 3], + }, + }, + }, + { + name: EVENTS.TEST_EVENT_4, + title: 'Test event 4', + payload: [ + { + string: 'value', + number: 123, + array: [1, 2, 3], + }, + { + string: 'value', + number: 123, + array: [1, 2, 3], + }, + { + string: 'value', + number: 123, + array: [1, 2, 3], + }, + ], + }, +]; + +storiesOf('React|Events', module) + .addParameters({ + framework: { react: true }, + options: { + selectedPanel: 'storybook/events/panel', + }, + }) + .addDecorator(withEvents({ emit, events })) + .add('Logger', () => ); + +const WithEvents = withEvents; +storiesOf('React|Events.deprecated', module) + .addParameters({ + framework: { react: true }, + options: { + selectedPanel: 'storybook/events/panel', + }, + }) + .addDecorator(storyFn => ( + + {storyFn()} + + )) + .add('Logger', () => ); diff --git a/examples/html-kitchen-sink/stories/react/addon-graphql.stories.js b/examples/html-kitchen-sink/stories/react/addon-graphql.stories.js new file mode 100644 index 000000000000..760d94c69315 --- /dev/null +++ b/examples/html-kitchen-sink/stories/react/addon-graphql.stories.js @@ -0,0 +1,44 @@ +import React from 'react'; +import { storiesOf } from '@storybook/html'; +// import { setupGraphiQL } from '@storybook/addon-graphql'; + +// const graphiql = setupGraphiQL({ +// url: 'https://graphql-pokemon.now.sh/?', +// }); + +storiesOf('React|GraphQL', module).add('get Pickachu', () =>
hello
, { + framework: { react: true }, + graphiql: { + query: `{ + pokemon(name: "Pikachu") { + id + number + name + attacks { + special { + name + type + damage + } + } + evolutions { + id + number + name + weight { + minimum + maximum + } + attacks { + fast { + name + type + damage + } + } + } + } + }`, + url: 'https://graphql-pokemon.now.sh/?', + }, +}); diff --git a/examples/html-kitchen-sink/stories/react/addon-info-resources/EXAMPLE.md b/examples/html-kitchen-sink/stories/react/addon-info-resources/EXAMPLE.md new file mode 100644 index 000000000000..fc965844dda0 --- /dev/null +++ b/examples/html-kitchen-sink/stories/react/addon-info-resources/EXAMPLE.md @@ -0,0 +1,3 @@ +# external +## markdown +file diff --git a/examples/html-kitchen-sink/stories/react/addon-info.stories.js b/examples/html-kitchen-sink/stories/react/addon-info.stories.js new file mode 100644 index 000000000000..66a8537a242e --- /dev/null +++ b/examples/html-kitchen-sink/stories/react/addon-info.stories.js @@ -0,0 +1,405 @@ +import React from 'react'; +import { storiesOf } from '@storybook/html'; +import { withInfo } from '@storybook/addon-info'; +import { action } from '@storybook/addon-actions'; + +import DocgenButton from './components/DocgenButton'; +import FlowTypeButton from './components/FlowTypeButton'; +import BaseButton from './components/BaseButton'; +import ForwardedRefButton from './components/ForwardedRefButton'; +import ForwardedRefButtonWDisplayName from './components/ForwardedRefButtonWDisplayName'; +import { NamedExportButton } from './components/NamedExportButton'; +import TableComponent from './components/TableComponent'; +import externalMdDocs from './addon-info-resources/EXAMPLE.md'; + +storiesOf('React|Info/React Docgen', module) + .addParameters({ framework: { react: true } }) + .addDecorator(withInfo) + .add( + 'Comments from PropType declarations', + () => ( + {}, + }} + arrayOf={[1, 2, 3]} + /> + ), + { + info: + 'Comments above the PropType declarations should be extracted from the React component file itself and rendered in the Info Addon prop table', + } + ) + .add( + 'Comments from Flow declarations', + () => , + { + info: + 'Comments above the Flow declarations should be extracted from the React component file itself and rendered in the Info Addon prop table', + } + ) + .add( + 'Comments from component declaration', + () => , + { + info: + 'Comments above the component declaration should be extracted from the React component file itself and rendered below the Info Addon heading', + } + ) + .add( + 'Comments from named export component declaration', + () => , + { + info: + 'Comments above the component declaration should be extracted from the React component file itself and rendered below the Info Addon heading', + } + ); + +const markdownDescription = ` +#### You can use markdown in your withInfo description. + +Sometimes you might want to manually include some \`code\` examples: + +~~~js +const Button = () =>