Skip to content

Commit

Permalink
Addons: Disable option for addon tab (#6923)
Browse files Browse the repository at this point in the history
feature request: disable option for addon tab
  • Loading branch information
shilman committed Jul 4, 2019
2 parents 3b2ef9b + ff04534 commit b9d2ba2
Show file tree
Hide file tree
Showing 26 changed files with 317 additions and 13 deletions.
3 changes: 2 additions & 1 deletion addons/a11y/src/register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Fragment, FunctionComponent } from 'react';
import { styled } from '@storybook/theming';

import { addons, types } from '@storybook/addons';
import { ADDON_ID, PANEL_ID } from './constants';
import { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants';
import { ColorBlindness } from './components/ColorBlindness';
import { A11YPanel } from './components/A11YPanel';

Expand Down Expand Up @@ -94,6 +94,7 @@ addons.register(ADDON_ID, api => {
title: 'Accessibility',
type: types.PANEL,
render: ({ active, key }) => <A11YPanel key={key} api={api} active={active} />,
paramKey: PARAM_KEY,
});

addons.add(PANEL_ID, {
Expand Down
1 change: 1 addition & 0 deletions addons/actions/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const PARAM_KEY = 'actions';
export const ADDON_ID = 'storybook/actions';
export const PANEL_ID = `${ADDON_ID}/panel`;
export const EVENT_ID = `${ADDON_ID}/action-event`;
Expand Down
3 changes: 2 additions & 1 deletion addons/actions/src/manager.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React from 'react';
import addons from '@storybook/addons';
import ActionLogger from './containers/ActionLogger';
import { ADDON_ID, PANEL_ID } from '.';
import { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants';

export function register() {
addons.register(ADDON_ID, api => {
addons.addPanel(PANEL_ID, {
title: 'Actions',
render: ({ active, key }) => <ActionLogger key={key} api={api} active={active} />,
paramKey: PARAM_KEY,
});
});
}
3 changes: 2 additions & 1 deletion addons/cssresources/src/register.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { addons, types } from '@storybook/addons';

import { ADDON_ID, PANEL_ID } from './constants';
import { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants';
import { CssResourcePanel } from './css-resource-panel';

addons.register(ADDON_ID, api => {
Expand All @@ -10,5 +10,6 @@ addons.register(ADDON_ID, api => {
type: types.PANEL,
title: 'CSS resources',
render: ({ active }) => <CssResourcePanel key={PANEL_ID} api={api} active={active} />,
paramKey: PARAM_KEY,
});
});
3 changes: 2 additions & 1 deletion addons/design-assets/src/register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

import { addons, types } from '@storybook/addons';
import { AddonPanel } from '@storybook/components';
import { ADDON_ID, PANEL_ID } from './constants';
import { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants';
import { Panel } from './panel';

addons.register(ADDON_ID, () => {
Expand All @@ -14,5 +14,6 @@ addons.register(ADDON_ID, () => {
<Panel />
</AddonPanel>
),
paramKey: PARAM_KEY,
});
});
2 changes: 2 additions & 0 deletions addons/events/src/constants.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const PARAM_KEY = 'events';

export const ADDON_ID = 'storybook/events';

export const PANEL_ID = `${ADDON_ID}/panel`;
Expand Down
3 changes: 2 additions & 1 deletion addons/events/src/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import React from 'react';
import addons from '@storybook/addons';

import Panel from './components/Panel';
import { ADDON_ID, PANEL_ID } from './constants';
import { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants';

export function register() {
addons.register(ADDON_ID, api => {
addons.addPanel(PANEL_ID, {
title: 'Events',
// eslint-disable-next-line react/prop-types
render: ({ active, key }) => <Panel key={key} api={api} active={active} />,
paramKey: PARAM_KEY,
});
});
}
3 changes: 2 additions & 1 deletion addons/graphql/src/register.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { addons, types } from '@storybook/addons';

import GQL from './manager';
import { ADDON_ID } from '.';
import { ADDON_ID, PARAM_KEY } from '.';

export const register = () => {
addons.register(ADDON_ID, () => {
Expand All @@ -11,6 +11,7 @@ export const register = () => {
route: ({ storyId }) => `/graphql/${storyId}`,
match: ({ viewMode }) => viewMode === 'graphql',
render: GQL,
paramKey: PARAM_KEY,
});
});
};
3 changes: 2 additions & 1 deletion addons/jest/src/register.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';
import addons from '@storybook/addons';
import { ADDON_ID, PANEL_ID } from './shared';
import { ADDON_ID, PANEL_ID, PARAM_KEY } from './shared';

import Panel from './components/Panel';

addons.register(ADDON_ID, api => {
addons.addPanel(PANEL_ID, {
title: 'tests',
render: ({ active, key }) => <Panel key={key} api={api} active={active} />,
paramKey: PARAM_KEY,
});
});
1 change: 1 addition & 0 deletions addons/jest/src/shared.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// addons, panels and events get unique names using a prefix
export const PARAM_KEY = 'test';
export const ADDON_ID = 'storybookjs/test';
export const PANEL_ID = `${ADDON_ID}/panel`;

Expand Down
3 changes: 2 additions & 1 deletion addons/knobs/src/register.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';
import addons from '@storybook/addons';
import Panel from './components/Panel';
import { ADDON_ID, PANEL_ID } from './shared';
import { ADDON_ID, PANEL_ID, PARAM_KEY } from './shared';

addons.register(ADDON_ID, api => {
addons.addPanel(PANEL_ID, {
title: 'Knobs',
// eslint-disable-next-line react/prop-types
render: ({ active, key }) => <Panel api={api} key={key} active={active} />,
paramKey: PARAM_KEY,
});
});
1 change: 1 addition & 0 deletions addons/knobs/src/shared.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// addons, panels and events get unique names using a prefix
export const PARAM_KEY = 'knobs';
export const ADDON_ID = 'storybookjs/knobs';
export const PANEL_ID = `${ADDON_ID}/panel`;

Expand Down
3 changes: 2 additions & 1 deletion addons/notes/src/register.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import addons, { types } from '@storybook/addons';

import { ADDON_ID, PANEL_ID } from './shared';
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';
Expand All @@ -14,6 +14,7 @@ export default function register(type: types) {
route: ({ storyId }) => `/info/${storyId}`, // todo add type
match: ({ viewMode }) => viewMode === 'info', // todo add type
render: ({ active }) => <Panel api={api} active={active} />,
paramKey: PARAM_KEY,
});
});
}
3 changes: 2 additions & 1 deletion addons/ondevice-actions/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React from 'react';
import addons from '@storybook/addons';
import { ADDON_ID, PANEL_ID } from '@storybook/addon-actions';
import { ADDON_ID, PANEL_ID, PARAM_KEY } from '@storybook/addon-actions';
import ActionLogger from './containers/ActionLogger';

export function register() {
addons.register(ADDON_ID, () => {
addons.addPanel(PANEL_ID, {
title: 'Actions',
render: ({ active, key }) => <ActionLogger key={key} active={active} />,
paramKey: PARAM_KEY,
});
});
}
1 change: 1 addition & 0 deletions addons/ondevice-backgrounds/src/constants.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const PARAM_KEY = 'background';
export const ADDON_ID = 'storybook-addon-background';
export const PANEL_ID = `${ADDON_ID}/background-panel`;

Expand Down
3 changes: 2 additions & 1 deletion addons/ondevice-backgrounds/src/register.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import addons from '@storybook/addons';

import { ADDON_ID, PANEL_ID } from './constants';
import { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants';
import BackgroundPanel from './BackgroundPanel';

addons.register(ADDON_ID, api => {
Expand All @@ -10,5 +10,6 @@ addons.register(ADDON_ID, api => {
title: 'Backgrounds',
// eslint-disable-next-line react/prop-types
render: ({ active }) => <BackgroundPanel channel={channel} api={api} active={active} />,
paramKey: PARAM_KEY,
});
});
1 change: 1 addition & 0 deletions addons/ondevice-knobs/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export function register() {
title: 'Knobs',
// eslint-disable-next-line react/prop-types
render: ({ active, key }) => <Panel key={key} channel={channel} active={active} />,
paramKey: 'knobs',
});
});
}
1 change: 1 addition & 0 deletions addons/ondevice-notes/src/register.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,6 @@ addons.register('storybook/notes', api => {
addons.addPanel('storybook/notes/panel', {
title: 'Notes',
render: ({ active, key }) => <Notes key={key} channel={channel} api={api} active={active} />,
paramKey: PARAM_KEY,
});
});
23 changes: 23 additions & 0 deletions docs/src/pages/addons/using-addons/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,29 @@ Then you'll be able to see those notes when you are viewing the story.

![Stories with notes](../static/stories-with-notes.png)

## Disable the addon

You can disable an addon panel for a story by adding a `disabled` parameter.

```js
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';

import Button from './Button';

storiesOf('Button', module).add(
'with some emoji',
() => (
<Button onClick={action('clicked')}>
<span role="img" aria-label="so cool">
😀 😎 👍 💯
</span>
</Button>
),
{ notes: { disabled: true } }
);
```

## Global Configuration

Sometimes you might want to configure an addon globally, as in the case of collocating stories with components, or just simply to keep your stories file cleaner. To do that, you can add your decorators to a config file, typically in `.storybook/config.js`. Here's an example of how you might do that.
Expand Down
29 changes: 29 additions & 0 deletions docs/src/pages/addons/writing-addons/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ addons.register(ADDON_ID, api => {
type: types.PANEL,
title,
render,
paramKey: PARAM_KEY,
});
});
```
Expand Down Expand Up @@ -246,6 +247,34 @@ storiesOf('Button', module)
});
```

### Disabling an addon panel

It's possible to disable an addon panel for a particular story.

To offer that capability, you need to pass the paramKey when you register the panel
```js
addons.register(ADDON_ID, () => {
addons.add(PANEL_ID, {
type: types.PANEL,
title: 'My Addon',
render: () => <div>Addon tab content</div>,
paramKey: 'myAddon',
});
});
```

While adding a story, you can then pass a `disabled` parameter.

```js
storiesOf('Button', module)
.add('with text', () => <Button>Hello Button</Button>, {
myAddon: {
disabled: true,
},
});
```


## Styling your addon

We use [emotion](https://emotion.sh) for styling, AND we provide a theme which can be set by the user!
Expand Down
1 change: 1 addition & 0 deletions lib/addons/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface Addon {
route?: (routeOptions: RouteOptions) => string;
match?: (matchOptions: MatchOptions) => boolean;
render: (renderOptions: RenderOptions) => ReactElement<any>;
paramKey?: string;
}

export type Loader = (api: API) => void;
Expand Down
32 changes: 31 additions & 1 deletion lib/api/src/modules/addons.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ReactElement } from 'react';

import { Module, State } from '../index';
import { Module } from '../index';
import { Options } from '../store';

export enum types {
Expand Down Expand Up @@ -31,6 +31,7 @@ export interface Addon {
route?: (routeOptions: RouteOptions) => string;
match?: (matchOptions: MatchOptions) => boolean;
render: (renderOptions: RenderOptions) => ReactElement<any>;
paramKey?: string;
}
export interface Collection {
[key: string]: Addon;
Expand All @@ -42,9 +43,16 @@ interface Panels {

type StateMerger<S> = (input: S) => S;

interface StoryInput {
parameters: {
[parameterName: string]: any;
};
}

export interface SubAPI {
getElements: (type: Types) => Collection;
getPanels: () => Collection;
getStoryPanels: () => Collection;
getSelectedPanel: () => string;
setSelectedPanel: (panelName: string) => void;
setAddonState<S>(
Expand Down Expand Up @@ -72,6 +80,28 @@ export default ({ provider, store }: Module) => {
const api: SubAPI = {
getElements: type => provider.getElements(type),
getPanels: () => api.getElements(types.PANEL),
getStoryPanels: () => {
const allPanels = api.getPanels();
const { storyId, storiesHash } = store.getState();
const storyInput = storyId && (storiesHash[storyId] as StoryInput);

if (!allPanels || !storyInput) {
return allPanels;
}

const { parameters } = storyInput;

const filteredPanels: Collection = {};
Object.entries(allPanels).forEach(([id, panel]) => {
const { paramKey } = panel;
if (paramKey && parameters[paramKey] && parameters[paramKey].disabled) {
return;
}
filteredPanels[id] = panel;
});

return filteredPanels;
},
getSelectedPanel: () => {
const { selectedPanel } = store.getState();
return ensurePanel(api.getPanels(), selectedPanel, selectedPanel);
Expand Down
Loading

1 comment on commit b9d2ba2

@vercel
Copy link

@vercel vercel bot commented on b9d2ba2 Jul 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.