Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storybook for HTML snippets #3475

Merged
merged 62 commits into from
May 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
7a879b8
Add storybook for HTML snippets
Hypnosphi Apr 22, 2018
b155f65
Add docs
Hypnosphi Apr 22, 2018
64708c4
Add netlify context
Hypnosphi Apr 22, 2018
1a4adc7
Update Live examples section
Hypnosphi Apr 22, 2018
2652127
Add acceptance story
Hypnosphi Apr 22, 2018
099dd2c
Update storyshots
Hypnosphi Apr 22, 2018
9be6965
Merge branch 'master' into html
Hypnosphi Apr 22, 2018
4753936
Add CI build type
Hypnosphi Apr 22, 2018
cc5426e
TeamCity: fix syntax error
Hypnosphi Apr 22, 2018
167ec7d
TeamCity: temporary add only HTML dependency
Hypnosphi Apr 22, 2018
51559e0
Merge branch 'master' into html
Hypnosphi Apr 22, 2018
9243827
TeamCity: depend on HTML build
Hypnosphi Apr 22, 2018
1b76ab2
Revert "TeamCity: depend on HTML build"
Hypnosphi Apr 22, 2018
bc130ff
Merge branch 'master' into html
Hypnosphi Apr 22, 2018
46da4e3
Add StorySource addon
igor-dv Apr 23, 2018
17ae506
Add Viewport addon
igor-dv Apr 23, 2018
625ddbe
Add Options addon
igor-dv Apr 23, 2018
5163d52
TeamCity: make unmerged apps builds noop
Hypnosphi Apr 23, 2018
51cae39
Don't run chromatic twice
Hypnosphi Apr 23, 2018
fcaf79e
Merge branch 'master' into html
Hypnosphi Apr 23, 2018
35b91bd
TeamCity: enable HTML build
Hypnosphi Apr 23, 2018
17bf3be
Introduce subscriptionsStore
Hypnosphi Apr 23, 2018
931dadf
Add Centered addon
igor-dv Apr 24, 2018
c24e5ee
Add Notes addon
igor-dv Apr 24, 2018
f868afd
Add Storyshots addon
igor-dv Apr 24, 2018
e3c8db4
Remove unneeded statement
igor-dv Apr 24, 2018
902a0cb
Reuse divs in Centered addon
igor-dv Apr 25, 2018
a37f096
Update snapshot + allow returning multiple children for storyshots
igor-dv Apr 25, 2018
20cace2
Add multiple nodes example
igor-dv Apr 25, 2018
715f2d8
Merge branch 'master' into html
Hypnosphi Apr 25, 2018
e42a800
Merge branch 'master' into html
Hypnosphi Apr 25, 2018
322be35
Add Knobs addon
igor-dv Apr 25, 2018
4f7f2eb
window => global
Hypnosphi Apr 25, 2018
ea48bae
Update knobs example
igor-dv Apr 25, 2018
805ef36
Simplify knobs registration for HTML app
igor-dv Apr 25, 2018
8b21185
Few fixes + more knobs examples
igor-dv Apr 25, 2018
6e17afc
Merge remote-tracking branch 'origin/master' into html
Hypnosphi Apr 25, 2018
9a919ff
Integrate changes from #3487
Hypnosphi Apr 25, 2018
8e8ba81
Merge remote-tracking branch 'origin/master' into html
Hypnosphi Apr 30, 2018
f5df963
Update version
Hypnosphi Apr 30, 2018
486f278
Fix missed "mithrils"
Hypnosphi Apr 30, 2018
81d3e5b
Merge branch 'master' into html
Hypnosphi Apr 30, 2018
944873d
Merge remote-tracking branch 'origin/master' into html
Hypnosphi May 1, 2018
61f1291
Integrate changes from #3472
Hypnosphi May 1, 2018
8603038
Merge remote-tracking branch 'origin/master' into html
Hypnosphi May 1, 2018
51eeaa0
Merge branch 'postmessage-same-sender' into html
Hypnosphi May 1, 2018
60c96ae
Use force re-render event in knobs
Hypnosphi May 1, 2018
0a5a468
Make welcome story default
Hypnosphi May 1, 2018
61f3232
Introduce "register subscription" event, move declarative links decor…
Hypnosphi May 1, 2018
c12de16
Update snapshots
igor-dv May 2, 2018
4a86624
Merge branch 'master' into html
Hypnosphi May 2, 2018
6df6a3c
Integrate changes from #3520
Hypnosphi May 2, 2018
100985b
withActions decorator
Hypnosphi May 2, 2018
0ad1dd9
Fix for RN
Hypnosphi May 2, 2018
adcbc00
Commit storyshot
Hypnosphi May 2, 2018
6d661af
Addon-a11y support
Hypnosphi May 2, 2018
3851174
Addon-backgrouns support
Hypnosphi May 2, 2018
71f72f0
Commit storyshot
Hypnosphi May 3, 2018
bf86c0c
Addon-events support
Hypnosphi May 3, 2018
8bf5af8
Addon-jest support
Hypnosphi May 4, 2018
3605b76
Commit storyshots
Hypnosphi May 5, 2018
10fa1dc
Refer to html guide in slow start guide
Hypnosphi May 5, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

/addons/a11y/ @jbovenschen
/addons/actions/ @rhalff
/addons/background/ @ndelangen @hypnosphi
/addons/backgrounds/ @ndelangen @hypnosphi
/addons/centered/ @kazupon
/addons/events/ @z4o4z @ndelangen
/addons/graphql/ @mnmtanish
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ enum class StorybookApp(val appName: String, val exampleDir: String, val merged:
ANGULAR("Angular", "angular-cli"),
POLYMER("Polymer", "polymer-cli"),
MITHRIL("Mithril", "mithril-kitchen-sink"),
HTML("HTML", "html-kitchen-sink", false);
HTML("HTML", "html-kitchen-sink");

val lowerName = appName.toLowerCase()

Expand Down
34 changes: 17 additions & 17 deletions ADDONS_SUPPORT.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
## Addon / Framework Support Table

| |[React](app/react)|[React Native](app/react-native)|[Vue](app/vue)|[Angular](app/angular)| [Polymer](app/polymer)| [Mithril](app/mithril)|
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|[a11y](addons/a11y) |+| | | | | |
|[actions](addons/actions) |+|+|+|+|+|+|
|[background](addons/background) |+| | | | |+|
|[centered](addons/centered) |+| |+| | |+|
|[events](addons/events) |+| | | | | |
|[graphql](addons/graphql) |+| | | | | |
|[info](addons/info) |+| | | | | |
|[jest](addons/jest) |+| | | | | |
|[knobs](addons/knobs) |+|+|+|+|+|+|
|[links](addons/links) |+|+|+|+|+|+|
|[notes](addons/notes) |+| |+|+|+|+|
|[options](addons/options) |+|+|+|+|+|+|
|[storyshots](addons/storyshots) |+|+|+|+| | |
|[storysource](addons/storysource)|+| |+|+|+|+|
|[viewport](addons/viewport) |+| |+|+|+|+|
| |[React](app/react)|[React Native](app/react-native)|[Vue](app/vue)|[Angular](app/angular)| [Polymer](app/polymer)| [Mithril](app/mithril)| [HTML](app/html)|
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|[a11y](addons/a11y) |+| | | | | |+|
|[actions](addons/actions) |+|+|+|+|+|+|+|
|[backgrounds](addons/backgrounds) |+| | | | |+|+|
|[centered](addons/centered) |+| |+| | |+|+|
|[events](addons/events) |+| | | | | |+|
|[graphql](addons/graphql) |+| | | | | | |
|[info](addons/info) |+| | | | | | |
|[jest](addons/jest) |+| | | | | |+|
|[knobs](addons/knobs) |+|+|+|+|+|+|+|
|[links](addons/links) |+|+|+|+|+|+|+|
|[notes](addons/notes) |+| |+|+|+|+|+|
|[options](addons/options) |+|+|+|+|+|+|+|
|[storyshots](addons/storyshots) |+|+|+|+| | |+|
|[storysource](addons/storysource)|+| |+|+|+|+|+|
|[viewport](addons/viewport) |+| |+|+|+|+|+|
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ For additional help, join us [in our Slack](https://now-examples-slackin-rrirkqo
- [React Native](app/react-native)
- [Vue](app/vue)
- [Angular](app/angular)
- [Polymer](app/polymer) <sup>release candidate</sup>
- [Polymer](app/polymer)
- [Mithril](app/mithril) <sup>alpha</sup>
- [HTML](app/html) <sup>alpha</sup>

### Sub Projects

Expand All @@ -84,7 +85,7 @@ For additional help, join us [in our Slack](https://now-examples-slackin-rrirkqo

- [a11y](addons/a11y/) - Test components for user accessibility in Storybook
- [actions](addons/actions/) - Log actions as users interact with components in the Storybook UI
- [background](addons/background/) - Let users choose backgrounds in the Storybook UI
- [backgrounds](addons/backgrounds/) - Let users choose backgrounds in the Storybook UI
- [centered](addons/centered/) - Center the alignment of your components within the Storybook UI
- [events](addons/events/) - Interactively fire events to components that respond to EventEmitter
- [graphql](addons/graphql/) - Query a GraphQL server within Storybook stories
Expand All @@ -110,6 +111,7 @@ See [Addon / Framework Support Table](ADDONS_SUPPORT.md)
- [Angular](https://storybooks-angular.netlify.com/)
- [Polymer](https://storybooks-polymer.netlify.com/)
- [Mithril](https://storybooks-mithril.netlify.com/)
- [HTML](https://storybooks-html.netlify.com/)

### 3.4
- [React Official](https://release-3-4--storybooks-official.netlify.com)
Expand Down
1 change: 1 addition & 0 deletions addons/a11y/html.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/html');
2 changes: 2 additions & 0 deletions addons/a11y/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@
"@storybook/addons": "4.0.0-alpha.4",
"@storybook/client-logger": "4.0.0-alpha.4",
"@storybook/components": "4.0.0-alpha.4",
"@storybook/core-events": "4.0.0-alpha.4",
"axe-core": "^3.0.2",
"babel-runtime": "^6.26.0",
"glamor": "^2.20.40",
"glamorous": "^4.12.5",
"global": "^4.3.2",
"prop-types": "^15.6.1"
},
"peerDependencies": {
Expand Down
6 changes: 4 additions & 2 deletions addons/a11y/src/components/Panel.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { Component } from 'react';
import addons from '@storybook/addons';

import { CHECK_EVENT_ID } from '../shared';

import Tabs from './Tabs';
import Report from './Report';

Expand All @@ -26,11 +28,11 @@ class Panel extends Component {
}

componentDidMount() {
this.channel.on('addon:a11y:check', this.onUpdate);
this.channel.on(CHECK_EVENT_ID, this.onUpdate);
}

componentWillUnmount() {
this.channel.removeListener('addon:a11y:check', this.onUpdate);
this.channel.removeListener(CHECK_EVENT_ID, this.onUpdate);
}

onUpdate({ passes, violations }) {
Expand Down
5 changes: 4 additions & 1 deletion addons/a11y/src/components/Report/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
import addons from '@storybook/addons';

import { RERUN_EVENT_ID } from '../../shared';

import RerunButton from './RerunButton';
import Item from './Item';

Expand All @@ -20,7 +23,7 @@ const styles = {

function onRerunClick() {
const channel = addons.getChannel();
channel.emit('addon:a11y:rerun');
channel.emit(RERUN_EVENT_ID);
}

const Report = ({ items, empty, passes }) => (
Expand Down
8 changes: 5 additions & 3 deletions addons/a11y/src/components/WrapStory.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import PropTypes from 'prop-types';
import axe from 'axe-core';
import { logger } from '@storybook/client-logger';

import { CHECK_EVENT_ID, RERUN_EVENT_ID } from '../shared';

class WrapStory extends Component {
static propTypes = {
context: PropTypes.shape({}),
Expand All @@ -25,13 +27,13 @@ class WrapStory extends Component {

componentDidMount() {
const { channel } = this.props;
channel.on('addon:a11y:rerun', this.runA11yCheck);
channel.on(RERUN_EVENT_ID, this.runA11yCheck);
this.runA11yCheck();
}

componentWillUnmount() {
const { channel } = this.props;
channel.removeListener('addon:a11y:rerun', this.runA11yCheck);
channel.removeListener(RERUN_EVENT_ID, this.runA11yCheck);
}

/* eslint-disable react/no-find-dom-node */
Expand All @@ -42,7 +44,7 @@ class WrapStory extends Component {
if (wrapper !== null) {
axe.reset();
axe.configure(axeOptions);
axe.run(wrapper).then(results => channel.emit('addon:a11y:check', results), logger.error);
axe.run(wrapper).then(results => channel.emit(CHECK_EVENT_ID, results), logger.error);
}
}

Expand Down
35 changes: 35 additions & 0 deletions addons/a11y/src/html.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { document, setTimeout } from 'global';
import axe from 'axe-core';
import addons from '@storybook/addons';
import Events from '@storybook/core-events';
import { logger } from '@storybook/client-logger';

import { CHECK_EVENT_ID, RERUN_EVENT_ID } from './shared';

let axeOptions = {};

export const configureA11y = (options = {}) => {
axeOptions = options;
};

const runA11yCheck = () => {
const channel = addons.getChannel();
const wrapper = document.getElementById('root');

axe.reset();
axe.configure(axeOptions);
axe.run(wrapper).then(results => channel.emit(CHECK_EVENT_ID, results), logger.error);
};

const a11ySubscription = () => {
const channel = addons.getChannel();
channel.on(RERUN_EVENT_ID, runA11yCheck);
return () => channel.removeListener(RERUN_EVENT_ID, runA11yCheck);
};

export const checkA11y = story => {
addons.getChannel().emit(Events.REGISTER_SUBSCRIPTION, a11ySubscription);
// We need to wait for rendering
setTimeout(runA11yCheck, 0);
return story();
};
5 changes: 3 additions & 2 deletions addons/a11y/src/shared/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// addons, panels and events get unique names using a prefix
const ADDON_ID = '@storybook/addon-a11y';
const PANEL_ID = `${ADDON_ID}/panel`;
const EVENT_ID = `${ADDON_ID}/event`;
const CHECK_EVENT_ID = `${ADDON_ID}/check`;
const RERUN_EVENT_ID = `${ADDON_ID}/rerun`;

export { ADDON_ID, PANEL_ID, EVENT_ID };
export { ADDON_ID, PANEL_ID, CHECK_EVENT_ID, RERUN_EVENT_ID };
23 changes: 21 additions & 2 deletions addons/actions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ import { actions } from '@storybook/addon-actions';
import Button from './button';

// This will lead to { onClick: action('onClick'), ... }
const eventsFromNames = actions('onClick', 'onDoubleClick');
const eventsFromNames = actions('onClick', 'onMouseOver');

// This will lead to { onClick: action('clicked'), ... }
const eventsFromObject = actions({ onClick: 'clicked', onDoubleClick: 'double clicked' });
const eventsFromObject = actions({ onClick: 'clicked', onMouseOver: 'hovered' });

storiesOf('Button', module)
.add('default view', () => <Button {...eventsFromNames}>Hello World!</Button>)
Expand Down Expand Up @@ -123,3 +123,22 @@ action('my-action', {
|`depth`|Number|Configures the transfered depth of any logged objects.|`10`|
|`clearOnStoryChange`|Boolean|Flag whether to clear the action logger when switching away from the current story.|`true`|
|`limit`|Number|Limits the number of items logged in the action logger|`50`|

## withActions decorator

You can define action handles in a declarative way using `withActions` decorators. It accepts the same arguments as [`actions`](#multiple-actions)
Keys have `'<eventName> <selector>'` format, e.g. `'click .btn'`. Selector is optional. This can be used with any framework but is especially useful for `@storybook/html`.

```js
import { storiesOf } from '@storybook/html';
import { withActions } from '@storybook/addon-actions';

storiesOf('button', module)
// Log mousovers on entire story and clicks on .btn
.addDecorator(withActions('mouseover', 'click .btn'))
.add('with actions', () => `
<div>
Clicks on this button will be logged: <button class="btn" type="button">Button</button>
</div>
`);
```
2 changes: 2 additions & 0 deletions addons/actions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
"dependencies": {
"@storybook/addons": "4.0.0-alpha.4",
"@storybook/components": "4.0.0-alpha.4",
"@storybook/core-events": "4.0.0-alpha.4",
"babel-runtime": "^6.26.0",
"deep-equal": "^1.0.1",
"glamor": "^2.20.40",
"glamorous": "^4.12.5",
"global": "^4.3.2",
"lodash.isequal": "^4.5.0",
"make-error": "^1.3.4",
"prop-types": "^15.6.1",
"react-inspector": "^2.3.0",
Expand Down
11 changes: 9 additions & 2 deletions addons/actions/src/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { action, actions, decorate, configureActions, decorateAction } from './preview';
import {
action,
actions,
decorate,
configureActions,
decorateAction,
withActions,
} from './preview';

// addons, panels and events get unique names using a prefix
export const ADDON_ID = 'storybook/actions';
export const PANEL_ID = `${ADDON_ID}/actions-panel`;
export const EVENT_ID = `${ADDON_ID}/action-event`;

export { action, actions, decorate, configureActions, decorateAction };
export { action, actions, decorate, configureActions, decorateAction, withActions };
19 changes: 11 additions & 8 deletions addons/actions/src/preview/decorateAction.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import action from './action';
import actions from './actions';
import { createDecorator } from './withActions';

function applyDecorators(decorators, actionCallback) {
return (..._args) => {
Expand All @@ -17,15 +18,17 @@ export function decorateAction(decorators) {

export function decorate(decorators) {
const decorated = decorateAction(decorators);
const decoratedActions = (...args) => {
const rawActions = actions(...args);
const actionsObject = {};
Object.keys(rawActions).forEach(name => {
actionsObject[name] = applyDecorators(decorators, rawActions[name]);
});
return actionsObject;
};
return {
action: decorated,
actions: (...args) => {
const rawActions = actions(...args);
const decoratedActions = {};
Object.keys(rawActions).forEach(name => {
decoratedActions[name] = applyDecorators(decorators, rawActions[name]);
});
return decoratedActions;
},
actions: decoratedActions,
withActions: createDecorator(decoratedActions),
};
}
1 change: 1 addition & 0 deletions addons/actions/src/preview/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { default as action } from './action';
export { default as actions } from './actions';
export { configureActions } from './configureActions';
export { decorateAction, decorate } from './decorateAction';
export { default as withActions } from './withActions';
64 changes: 64 additions & 0 deletions addons/actions/src/preview/withActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Based on http://backbonejs.org/docs/backbone.html#section-164
import { document, Element } from 'global';
import isEqual from 'lodash.isequal';
import addons from '@storybook/addons';
import Events from '@storybook/core-events';

import actions from './actions';

let lastSubscription;
let lastArgs;

const delegateEventSplitter = /^(\S+)\s*(.*)$/;

const isIE = Element != null && !Element.prototype.matches;
const matchesMethod = isIE ? 'msMatchesSelector' : 'matches';

const root = document && document.getElementById('root');

const hasMatchInAncestry = (element, selector) => {
if (element[matchesMethod](selector)) {
return true;
}
const parent = element.parentElement;
if (!parent) {
return false;
}
return hasMatchInAncestry(parent, selector);
};

const createHandlers = (actionsFn, ...args) => {
const actionsObject = actionsFn(...args);
return Object.entries(actionsObject).map(([key, action]) => {
// eslint-disable-next-line no-unused-vars
const [_, eventName, selector] = key.match(delegateEventSplitter);
return {
eventName,
handler: e => {
if (!selector || hasMatchInAncestry(e.target, selector)) {
action(e);
}
},
};
});
};

const actionsSubscription = (...args) => {
if (!isEqual(args, lastArgs)) {
lastArgs = args;
const handlers = createHandlers(...args);
lastSubscription = () => {
handlers.forEach(({ eventName, handler }) => root.addEventListener(eventName, handler));
return () =>
handlers.forEach(({ eventName, handler }) => root.removeEventListener(eventName, handler));
};
}
return lastSubscription;
};

export const createDecorator = actionsFn => (...args) => story => {
addons.getChannel().emit(Events.REGISTER_SUBSCRIPTION, actionsSubscription(actionsFn, ...args));
return story();
};

export default createDecorator(actions);
File renamed without changes.
1 change: 1 addition & 0 deletions addons/backgrounds/html.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/html');
File renamed without changes.