From 075cb67be4b8852378e87e3c8de5a34dbdd0e57b Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Tue, 4 Apr 2023 09:14:21 -0600 Subject: [PATCH 1/5] Don't use prerelease commands in Migration Guide --- docs/migration-guide.md | 6 +++--- docs/snippets/common/storybook-upgrade.npm.js | 3 +++ docs/snippets/common/storybook-upgrade.pnpm.js | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 docs/snippets/common/storybook-upgrade.npm.js create mode 100644 docs/snippets/common/storybook-upgrade.pnpm.js diff --git a/docs/migration-guide.md b/docs/migration-guide.md index b253fba25d65..f78bb9f39096 100644 --- a/docs/migration-guide.md +++ b/docs/migration-guide.md @@ -23,8 +23,8 @@ To upgrade your Storybook: @@ -32,7 +32,7 @@ To upgrade your Storybook: This will: -1. Upgrade your Storybook dependencies to the latest prerelease version +1. Upgrade your Storybook dependencies to the latest version 2. Run a collection of _automigrations_, which will: - Check for common upgrade tasks - Explain the necessary changes with links to more information diff --git a/docs/snippets/common/storybook-upgrade.npm.js b/docs/snippets/common/storybook-upgrade.npm.js new file mode 100644 index 000000000000..2627dd4df0f9 --- /dev/null +++ b/docs/snippets/common/storybook-upgrade.npm.js @@ -0,0 +1,3 @@ +```shell +npx storybook@next upgrade +``` diff --git a/docs/snippets/common/storybook-upgrade.pnpm.js b/docs/snippets/common/storybook-upgrade.pnpm.js new file mode 100644 index 000000000000..d4f41d883fe7 --- /dev/null +++ b/docs/snippets/common/storybook-upgrade.pnpm.js @@ -0,0 +1,3 @@ +```shell +pnpx storybook@next upgrade +``` From cf7097e4a4649f4934eaaa5490406e4d71d5b4d9 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Tue, 4 Apr 2023 09:41:16 -0600 Subject: [PATCH 2/5] Remove @next from non-prerelease upgrade snippets --- docs/snippets/common/storybook-upgrade.npm.js | 2 +- docs/snippets/common/storybook-upgrade.pnpm.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/snippets/common/storybook-upgrade.npm.js b/docs/snippets/common/storybook-upgrade.npm.js index 2627dd4df0f9..6f1f9f5f1157 100644 --- a/docs/snippets/common/storybook-upgrade.npm.js +++ b/docs/snippets/common/storybook-upgrade.npm.js @@ -1,3 +1,3 @@ ```shell -npx storybook@next upgrade +npx storybook upgrade ``` diff --git a/docs/snippets/common/storybook-upgrade.pnpm.js b/docs/snippets/common/storybook-upgrade.pnpm.js index d4f41d883fe7..67ab5ab4bc78 100644 --- a/docs/snippets/common/storybook-upgrade.pnpm.js +++ b/docs/snippets/common/storybook-upgrade.pnpm.js @@ -1,3 +1,3 @@ ```shell -pnpx storybook@next upgrade +pnpx storybook upgrade ``` From 12d480d430c4ebe15df7c743ea310f62b8808953 Mon Sep 17 00:00:00 2001 From: jonniebigodes Date: Tue, 4 Apr 2023 20:09:52 +0100 Subject: [PATCH 3/5] Fix Addon API for main --- docs/addons/addons-api.md | 285 +++++++++--------- .../common/args-usage-with-addons.js.mdx | 2 +- .../storybook-addon-panel-initial.js.mdx | 9 +- ...ybook-addons-api-disablequeryparams.js.mdx | 4 +- .../storybook-addons-api-getchannel.js.mdx | 41 +++ .../storybook-addons-api-getqueryparam.js.mdx | 4 +- .../storybook-addons-api-geturlstate.js.mdx | 2 +- .../storybook-addons-api-imports.js.mdx | 4 +- .../storybook-addons-api-makedecorator.js.mdx | 24 +- .../common/storybook-addons-api-on.js.mdx | 5 +- .../storybook-addons-api-register.js.mdx | 2 +- ...book-addons-api-selectincurrentkind.js.mdx | 4 +- .../storybook-addons-api-selectstory.js.mdx | 4 +- ...storybook-addons-api-setqueryparams.js.mdx | 6 +- .../storybook-addons-api-useaddonstate.js.mdx | 27 +- .../common/storybook-addons-api-useapi.js.mdx | 28 +- .../storybook-addons-api-usechannel.js.mdx | 13 +- .../storybook-addons-api-useglobal.js.mdx | 14 +- .../storybook-addons-api-useparameter.js.mdx | 18 +- ...rybook-addons-api-usestorybookstate.js.mdx | 15 +- 20 files changed, 300 insertions(+), 211 deletions(-) create mode 100644 docs/snippets/common/storybook-addons-api-getchannel.js.mdx diff --git a/docs/addons/addons-api.md b/docs/addons/addons-api.md index 14bc9a186449..8208bf0f7c2c 100644 --- a/docs/addons/addons-api.md +++ b/docs/addons/addons-api.md @@ -2,9 +2,14 @@ title: 'Addon API' --- +Storybook's API allows developers to interact programmatically with Storybook. With the API, developers can build and deploy custom addons and other tools that enhance Storybook's functionality. + ## Core Addon API -This is the core addon API. This is how to get the addon API: +Our API is exposed via two distinct packages, each one with a different purpose: + +- `@storybook/manager-api` used to interact with the Storybook manager UI or access the Storybook API. +- `@storybook/preview-api` used to control and configure the addon's behavior. @@ -16,16 +21,31 @@ This is the core addon API. This is how to get the addon API: -### addons.getChannel() +### addons.add() -Get an instance to the channel to communicate with the manager and the preview. You can find this in both the addon register code and your addon’s wrapper component (where used inside a story). +The `add` method allows you to register the type of UI component associated with the addon (e.g., panels, toolbars, tabs). For a minimum viable Storybook addon, you should provide the following arguments: + +- `type`: The type of UI component to register. +- `title`: The title to feature in the Addon Panel. +- `render`: The function that renders the addon's UI component. + + + + -It has a NodeJS [EventEmitter](https://nodejs.org/api/events.html) compatible API. So, you can use it to emit events and listen for events. + + +
+ℹ️ The render function is called with `active` and `key`. The `active` value will be true when the panel is focused on the UI. +
### addons.register() -This method allows you to register an addon and get the storybook API. You can do this only in the Manager App. -See how we can use this: +Serves as the entry point for all addons. It allows you to register an addon and access the Storybook [API](#storybook-api). For example: @@ -39,27 +59,23 @@ See how we can use this: Now you'll get an instance to our StorybookAPI. See the [api docs](#storybook-api) for Storybook API regarding using that. -### addons.add() +### addons.getChannel() -This method allows you to add a panel to Storybook. (Storybook's Action Logger is a panel). You can do this only in the Manager App. -See how you can use this method: +Get an instance to the channel to communicate with the manager and the preview. You can find this in both the addon register code and your addon’s wrapper component (where used inside a story). + +It has a NodeJS [EventEmitter](https://nodejs.org/api/events.html) compatible API. So, you can use it to emit events and listen to events. -The render function is called with `active` and `key`. The `active` value will be true when the panel is focused on the UI. - -As you can see, you can set any React Component as the panel. Currently, it's one line of text. But you can do anything you want. -It's a good practice to specify the panel title with the `title` key. You can use any plain text with it. - -## makeDecorator API +### makeDecorator Use the `makeDecorator` API to create decorators in the style of the official addons. Like so: @@ -73,317 +89,288 @@ Use the `makeDecorator` API to create decorators in the style of the official ad -The options to `makeDecorator` are: - -- `name`: The name of the export (e.g. `withFoo`) -- `parameterName`: The name of the parameter your addon uses. This should be unique. -- `skipIfNoParametersOrOptions`: Don't run your decorator if the user hasn't set options (via `.addDecorator(withFoo(options)))`) or parameters (`.add('story', () => , { foo: 'param' })`, or `.addParameters({ foo: 'param' })`). -- `allowDeprecatedUsage`: support the deprecated "wrapper" usage (`.add('story', () => withFoo(options)(() => ))`). -- `wrapper`: your decorator function. Takes the `storyFn`, `context`, and both the `options` and `parameters` (as defined in `skipIfNoParametersOrOptions` above). -
-💡 If the story's parameters include `{ foo: { disable: true } }` (where `foo` is the `parameterName` of your addon), your decorator will not be called. +ℹ️ If the story's parameters include `{ exampleParameter: { disable: true } }` (where `exampleParameter` is the `parameterName` of your addon), your decorator will not be called.
+The `makeDecorator` API requires the following arguments: + +- `name`: Unique name to identify the custom addon decorator. +- `parameterName`: Sets a unique parameter to be consumed by the addon. +- `skipIfNoParametersOrOptions`: (Optional) Doesn't run the decorator if the user hasn't options either via [decorators](../writing-stories/decorators.md) or [parameters](../writing-stories/parameters.md). +- `wrapper`: your decorator function. Takes the `getStory`, `context`, and both the `options` and `parameters` (as defined in `skipIfNoParametersOrOptions` above). + --- -## Storybook hooks +## Storybook API -Writing addons can be simplified a lot by using these Storybook hooks: +Storybook's API allows you to access different functionalities of Storybook UI. -### useStorybookState +### api.selectStory() + +The `selectStory` API method allows you to select a single story. It accepts the following two parameters; story kind name and an optional story name. For example: -It allows full access to the entire storybook state. -Your component will re-render whenever the storybook state changes. - -If you use this, remember your component will be re-rendered a lot, and you may need to optimize for that using [`React.memo`](https://reactjs.org/docs/react-api.html#reactmemo) or [`useMemo`](https://reactjs.org/docs/hooks-reference.html#usememo) or [`PureComponent`](https://reactjs.org/docs/react-api.html#reactpurecomponent). - -### useStorybookApi +This is how you can select the above story: -It allows full access to the storybook API. - -Details on the Storybook API are further down. +### api.selectInCurrentKind() -### useChannel +Similar to the `selectStory` API method, but it only accepts the story as the only parameter. -Allows both setting subscriptions to events and getting the emitter for emitting custom events to the channel. - -The messages can be listened to on both the iframe and the manager side. +### api.setQueryParams() -### useAddonState +This method allows you to set query string parameters. You can use that as temporary storage for addons. Here's how you define query params: -Extremely useful for addons that need to persist in some form of state. - -Storybook may unmount your addon component, so keeping local state might not work well. - -Also, some addons consist of multiple parts, some parts in a panel, some in the toolbar, etc. - -With this hook, addons can access the same portion of the state, persisted even if the components are unmounted. - -### useParameter +Additionally, if you need to remove a query parameter, set it as `null` instead of removing them from the addon. For example: -This hook gets you the current story's parameter. +### api.getQueryParam() -If the parameter isn't set, the default value (second argument) is returned instead. - -### useGlobals +Allows retrieval of a query parameter enabled via the `setQueryParams` API method. For example: -Extremely useful hook for addons that rely on Storybook [Globals](../essentials/toolbars-and-globals.md). - -It allows you to retrieve and update any Storybook Globals you want. +### api.getUrlState(overrideParams) -If you use this hook, remember that your component will render a lot, and you may need to optimize for that using [`React.memo`](https://reactjs.org/docs/react-api.html#reactmemo) or [`useMemo`](https://reactjs.org/docs/hooks-reference.html#usememo) or [`useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback). - -### useArgs +This method allows you to get the application URL state, including any overridden or custom parameter values. For example: -You can use this handy Storybook hook in your addon if you need to read or update [`args`](../writing-stories/args.md). - ---- - -## Storybook API - -Storybook API allows you to access different functionalities of Storybook UI. You can move an instance to the Storybook API when registering an addon. - -Let's have a look at API methods. - -### api.selectStory() - -With this method, you can select a story via an API. This method accepts two parameters. - -1. story kind name -2. story name (optional) +### api.on(eventName, fn) -Let's say you've got a story like this: +This method allows you to register a handler function called whenever the user navigates between stories. -This is how you can select the above story: +### addons.setConfig(config) + +This method allows you to override the default Storybook UI configuration (e.g., set up a [theme](../configure/theming.md) or hide UI elements): -### api.selectInCurrentKind() +The following table details how to use the API values: + +| Name | Type | Description | Example Value | +| ------------------- | :-----------: | :------------------------------------------------: | :-----------------------------------: | +| **isFullscreen** | Boolean | Show story component as full screen | `false` | +| **showNav** | Boolean | Display panel that shows a list of stories | `true` | +| **showPanel** | Boolean | Display panel that shows addon configurations | `true` | +| **panelPosition** | String/Object | Where to show the addon panel | `bottom` or `right` | +| **enableShortcuts** | Boolean | Enable/disable shortcuts | `true` | +| **showToolbar** | Boolean | Show/hide toolbar | `true` | +| **theme** | Object | Storybook Theme, see next section | `undefined` | +| **selectedPanel** | String | Id to select an addon panel | `storybook/actions/panel` | +| **initialActive** | String | Select the default active tab on Mobile | `sidebar` or `canvas` or `addons` | +| **sidebar** | Object | Sidebar options, see below | `{ showRoots: false }` | +| **toolbar** | Object | Modify the tools in the toolbar using the addon id | `{ fullscreen: { hidden: false } } }` | -Same as `selectStory`, but accepts a story inside current kind as the only parameter: +The following options are configurable under the `sidebar` namespace: + +| Name | Type | Description | Example Value | +| ------------------ | :------: | :-----------------------------------------------------------: | :----------------------------------------------: | +| **showRoots** | Boolean | Display the top-level nodes as a "root" in the sidebar | `false` | +| **collapsedRoots** | Array | Set of root node IDs to visually collapse by default | `['misc', 'other']` | +| **renderLabel** | Function | Create a custom label for tree nodes; must return a ReactNode | `(item) => {item.name}` | + +The following options are configurable under the `toolbar` namespace: + +| Name | Type | Description | Example Value | +| ------ | :----: | :--------------------------------: | :-----------------: | +| **id** | String | Toggle visibility for toolbar item | `{ hidden: false }` | + +--- + +## Storybook hooks + +To help streamline addon development and reduce boilerplate code, the API exposes a set of hooks to access Storybook's internals. These hooks are an extension of the `@storybook/manager-api` package. + +### useStorybookState + +It allows access to Storybook's internal state. Similar to the [`useglobals`](#useglobals) hook, we recommend optimizing your addon to rely on [`React.memo`](https://reactjs.org/docs/react-api.html#reactmemo), or the following hooks; [`useMemo`](https://reactjs.org/docs/hooks-reference.html#usememo), [`useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback) to prevent a high volume of re-render cycles. -### api.setQueryParams() +### useStorybookApi -This method allows you to set query string parameters. You can use that as temporary storage for addons. Here's how you define query params: +The `useStorybookApi` hook is a convenient helper to allow you full access to the [Storybook API](#storybook-api) methods. -
+### useChannel -💡 If you need to remove a query param, use `null` for that. For example, we need to remove the `bbc` query param. See below how to do it: +Allows setting subscriptions to events and getting the emitter to emit custom events to the channel. -
+The messages can be listened to on both the iframe and the manager. -### api.getQueryParam() +### useAddonState -This method allows you to get a query param set by the above API `setQueryParams`. For example, we need to get the `bbc` query param. Then this is how we do it: +The `useAddonState` is a useful hook for addons that require data persistence, either due to Storybook's UI lifecycle or for more complex addons involving multiple types (e.g., toolbars, panels). -### api.getUrlState(overrideParams) +### useParameter -This method allows you to get the application URL state with some changed params. For example, if you want to get a link to a particular story: +The `useParameter` retrieves the current story's parameters. If the parameter's value is not defined, it will automatically default to the second value defined. -### api.on(eventName, fn) +### useGlobals -This method allows you to register a handler function called whenever the user navigates between stories. +Extremely useful hook for addons that rely on Storybook [Globals](../essentials/toolbars-and-globals.md). It allows you to obtain and update `global` values. We also recommend optimizing your addon to rely on [`React.memo`](https://reactjs.org/docs/react-api.html#reactmemo), or the following hooks; [`useMemo`](https://reactjs.org/docs/hooks-reference.html#usememo), [`useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback) to prevent a high volume of re-render cycles. -### addons.setConfig(config) +### useArgs -This method allows you to override the default Storybook UI configuration (e.g., set up a [theme](../configure/theming.md) or hide UI elements): +Hook that allows you to retrieve or update a story's [`args`](../writing-stories/args.md). - -The following table details how to use the API values: - -| Name | Type | Description | Example Value | -| ------------------- | :-----------: | :------------------------------------------------: | :-----------------------------------: | -| **isFullscreen** | Boolean | Show story component as full screen | `false` | -| **showNav** | Boolean | Display panel that shows a list of stories | `true` | -| **showPanel** | Boolean | Display panel that shows addon configurations | `true` | -| **panelPosition** | String/Object | Where to show the addon panel | `bottom` or `right` | -| **enableShortcuts** | Boolean | Enable/disable shortcuts | `true` | -| **showToolbar** | Boolean | Show/hide tool bar | `true` | -| **theme** | Object | Storybook Theme, see next section | `undefined` | -| **selectedPanel** | String | Id to select an addon panel | `storybook/actions/panel` | -| **initialActive** | String | Select the default active tab on Mobile | `sidebar` or `canvas` or `addons` | -| **sidebar** | Object | Sidebar options, see below | `{ showRoots: false }` | -| **toolbar** | Object | Modify the tools in the toolbar using the addon id | `{ fullscreen: { hidden: false } } }` | - -The following options are configurable under the `sidebar` namespace: - -| Name | Type | Description | Example Value | -| ------------------ | :------: | :-----------------------------------------------------------: | :----------------------------------------------: | -| **showRoots** | Boolean | Display the top-level nodes as a "root" in the sidebar | `false` | -| **collapsedRoots** | Array | Set of root node IDs to visually collapse by default | `['misc', 'other']` | -| **renderLabel** | Function | Create a custom label for tree nodes; must return a ReactNode | `(item) => {item.name}` | - -The following options are configurable under the `toolbar` namespace: - -| Name | Type | Description | Example Value | -| ------ | :----: | :--------------------------------: | :-----------------: | -| **id** | String | Toggle visibility for toolbar item | `{ hidden: false }` | diff --git a/docs/snippets/common/args-usage-with-addons.js.mdx b/docs/snippets/common/args-usage-with-addons.js.mdx index 3a5f6b34c006..650b25d62148 100644 --- a/docs/snippets/common/args-usage-with-addons.js.mdx +++ b/docs/snippets/common/args-usage-with-addons.js.mdx @@ -1,5 +1,5 @@ ```js -// your-addon/manager.js +// my-addon/src/manager.js|ts import { useArgs } from '@storybook/manager-api'; diff --git a/docs/snippets/common/storybook-addon-panel-initial.js.mdx b/docs/snippets/common/storybook-addon-panel-initial.js.mdx index dd1278823434..707e8bb199a7 100644 --- a/docs/snippets/common/storybook-addon-panel-initial.js.mdx +++ b/docs/snippets/common/storybook-addon-panel-initial.js.mdx @@ -1,25 +1,22 @@ ```js -// .storybook/my-addon/manager.js +// my-addon/src/manager.js|ts import React from 'react'; -import { addons, types } from '@storybook/manager-api'; +import { addons, types } from '@storybook/preview-api'; import { AddonPanel } from '@storybook/components'; const ADDON_ID = 'myaddon'; const PANEL_ID = `${ADDON_ID}/panel`; -// give a unique name for the panel -const MyPanel = () =>
MyAddon
; - addons.register(ADDON_ID, (api) => { addons.add(PANEL_ID, { type: types.PANEL, title: 'My Addon', render: ({ active, key }) => ( - +
Storybook addon panel
), }); diff --git a/docs/snippets/common/storybook-addons-api-disablequeryparams.js.mdx b/docs/snippets/common/storybook-addons-api-disablequeryparams.js.mdx index 1b36a81673fb..a9ce27043515 100644 --- a/docs/snippets/common/storybook-addons-api-disablequeryparams.js.mdx +++ b/docs/snippets/common/storybook-addons-api-disablequeryparams.js.mdx @@ -1,9 +1,9 @@ ```js -// /my-addon/manager.js +// my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { api.setQueryParams({ - bbc: null, + exampleParameter: null, }); }); ``` diff --git a/docs/snippets/common/storybook-addons-api-getchannel.js.mdx b/docs/snippets/common/storybook-addons-api-getchannel.js.mdx new file mode 100644 index 000000000000..0478812b03dd --- /dev/null +++ b/docs/snippets/common/storybook-addons-api-getchannel.js.mdx @@ -0,0 +1,41 @@ +```js +// my-addon/src/manager.js|ts + +import React, { useCallback } from 'react'; + +import { FORCE_RE_RENDER } from '@storybook/core-events'; + +import { addons } from '@storybook/preview-api'; + +import { useGlobals } from '@storybook/manager-api'; + +import { IconButton, Icons } from '@storybook/components'; + +const ExampleToolbar = () => { + const [globals, updateGlobals] = useGlobals(); + + const isActive = globals['my-param-key'] || false; + + // Function that will update the global value and trigger a UI refresh. + const refreshAndUpdateGlobal = () => { + updateGlobals({ + ['my-param-key']: !isActive, + }), + // Invokes Storybook's addon API method (with the FORCE_RE_RENDER) event to trigger a UI refresh + addons.getChannel().emit(FORCE_RE_RENDER); + }; + + const toggleToolbarAddon = useCallback(() => refreshAndUpdateGlobal(), [isActive]); + + return ( + + + + ); +}; +``` diff --git a/docs/snippets/common/storybook-addons-api-getqueryparam.js.mdx b/docs/snippets/common/storybook-addons-api-getqueryparam.js.mdx index 6379650acd22..954cc0f8f0de 100644 --- a/docs/snippets/common/storybook-addons-api-getqueryparam.js.mdx +++ b/docs/snippets/common/storybook-addons-api-getqueryparam.js.mdx @@ -1,7 +1,7 @@ ```js -// /my-addon/manager.js +// my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { - api.getQueryParam('bbc'); + api.getQueryParam('exampleParameter'); }); ``` diff --git a/docs/snippets/common/storybook-addons-api-geturlstate.js.mdx b/docs/snippets/common/storybook-addons-api-geturlstate.js.mdx index 9b560c295a10..35668c4d0c96 100644 --- a/docs/snippets/common/storybook-addons-api-geturlstate.js.mdx +++ b/docs/snippets/common/storybook-addons-api-geturlstate.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/manager.js +// my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { const href = api.getUrlState({ diff --git a/docs/snippets/common/storybook-addons-api-imports.js.mdx b/docs/snippets/common/storybook-addons-api-imports.js.mdx index 149ef7ce462a..43544272d504 100644 --- a/docs/snippets/common/storybook-addons-api-imports.js.mdx +++ b/docs/snippets/common/storybook-addons-api-imports.js.mdx @@ -1,5 +1,7 @@ ```js -// .storybook/my-addon/manager.js +// my-addon/src/manager.js|ts import { addons } from '@storybook/preview-api'; + +import { useStorybookApi } from '@storybook/manager-api'; ``` diff --git a/docs/snippets/common/storybook-addons-api-makedecorator.js.mdx b/docs/snippets/common/storybook-addons-api-makedecorator.js.mdx index a64d2ad8e5a3..18d2756412f3 100644 --- a/docs/snippets/common/storybook-addons-api-makedecorator.js.mdx +++ b/docs/snippets/common/storybook-addons-api-makedecorator.js.mdx @@ -1,18 +1,18 @@ ```js -// .storybook/my-addon/manager.js +// my-addon/src/decorator.js|ts import { makeDecorator } from '@storybook/preview-api'; -export makeDecorator({ +export const withAddonDecorator = makeDecorator({ name: 'withSomething', - parameterName: 'something', - wrapper: (storyFn, context, { parameters }) => { - // Do something with `parameters`, which are set via { something: ... } - - // Note you may alter the story output if you like. - // Although generally that's not advised. - - return storyFn(context); - } -}) + parameterName: 'CustomParameter', + skipIfNoParametersOrOptions: true + wrapper: (getStory, context, { parameters }) => { + /* + * Write your custom logic here based on the parameters passed in Storybook's stories. + * Although not advised, you can also alter the story output based on the parameters. + */ + return getStory(context); + }, +}); ``` diff --git a/docs/snippets/common/storybook-addons-api-on.js.mdx b/docs/snippets/common/storybook-addons-api-on.js.mdx index f80e1e005b5c..87be73cebfd1 100644 --- a/docs/snippets/common/storybook-addons-api-on.js.mdx +++ b/docs/snippets/common/storybook-addons-api-on.js.mdx @@ -1,7 +1,8 @@ ```js -// /my-addon/manager.js +// my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { - api.on('some-event', (eventData) => console.log(eventData)); + // Logs the event data to the browser console whenever the event is emitted. + api.on('custom-addon-event', (eventData) => console.log(eventData)); }); ``` diff --git a/docs/snippets/common/storybook-addons-api-register.js.mdx b/docs/snippets/common/storybook-addons-api-register.js.mdx index e1c84a004280..02ad360254d7 100644 --- a/docs/snippets/common/storybook-addons-api-register.js.mdx +++ b/docs/snippets/common/storybook-addons-api-register.js.mdx @@ -1,5 +1,5 @@ ```js -// .storybook/my-addon/manager.js +// my-addon/src/manager.js|ts import { addons } from '@storybook/preview-api'; diff --git a/docs/snippets/common/storybook-addons-api-selectincurrentkind.js.mdx b/docs/snippets/common/storybook-addons-api-selectincurrentkind.js.mdx index 67c9cc94542a..52b313da7a16 100644 --- a/docs/snippets/common/storybook-addons-api-selectincurrentkind.js.mdx +++ b/docs/snippets/common/storybook-addons-api-selectincurrentkind.js.mdx @@ -1,7 +1,7 @@ ```js -// /my-addon/manager.js +// my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { - api.selectInCurrentKind('Basic'); + api.selectInCurrentKind('Default'); }); ``` diff --git a/docs/snippets/common/storybook-addons-api-selectstory.js.mdx b/docs/snippets/common/storybook-addons-api-selectstory.js.mdx index 2a456b424067..b22af40898d8 100644 --- a/docs/snippets/common/storybook-addons-api-selectstory.js.mdx +++ b/docs/snippets/common/storybook-addons-api-selectstory.js.mdx @@ -1,7 +1,7 @@ ```js -// /my-addon/manager.js +// my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { - api.selectStory('Button', 'Basic'); + api.selectStory('Button', 'Default'); }); ``` diff --git a/docs/snippets/common/storybook-addons-api-setqueryparams.js.mdx b/docs/snippets/common/storybook-addons-api-setqueryparams.js.mdx index 83910ae18da6..e33f04e2889d 100644 --- a/docs/snippets/common/storybook-addons-api-setqueryparams.js.mdx +++ b/docs/snippets/common/storybook-addons-api-setqueryparams.js.mdx @@ -1,10 +1,10 @@ ```js -// /my-addon/manager.js +// my-addon/src/manager.js|ts addons.register('my-organisation/my-addon', (api) => { api.setQueryParams({ - abc: 'this is abc', - bbc: 'this is bbc', + exampleParameter: 'Sets the example parameter value', + anotherParameter: 'Sets the another parameter value', }); }); ``` diff --git a/docs/snippets/common/storybook-addons-api-useaddonstate.js.mdx b/docs/snippets/common/storybook-addons-api-useaddonstate.js.mdx index f9581809456c..953414806971 100644 --- a/docs/snippets/common/storybook-addons-api-useaddonstate.js.mdx +++ b/docs/snippets/common/storybook-addons-api-useaddonstate.js.mdx @@ -1,18 +1,35 @@ ```js -// /my-addon/manager.js +// my-addon/manager.js|ts import React from 'react'; import { useAddonState } from '@storybook/manager-api'; +import { AddonPanel, Button, IconButton } from '@storybook/components'; + export const Panel = () => { - const [state, setState] = useAddonState('my/addon-id', 'initial state'); + const [state, setState] = useAddonState('addon-unique-identifier', 'initial state'); - return ; + return ( + + + + ); }; export const Tool = () => { - const [state, setState] = useAddonState('my/addon-id', 'initial state'); + const [state, setState] = useAddonState('addon-unique-identifier', 'initial state'); - return ; + return ( + setState('Example')} + > + + + ); }; ``` diff --git a/docs/snippets/common/storybook-addons-api-useapi.js.mdx b/docs/snippets/common/storybook-addons-api-useapi.js.mdx index fed18884d9ca..f3b5b2091803 100644 --- a/docs/snippets/common/storybook-addons-api-useapi.js.mdx +++ b/docs/snippets/common/storybook-addons-api-useapi.js.mdx @@ -1,13 +1,33 @@ ```js -// /my-addon/manager.js +// my-addon/manager.js|ts -import React from 'react'; +import React, { useEffect, useCallback } from 'react'; + +import { Icons, IconButton } from '@storybook/components'; import { useStorybookApi } from '@storybook/manager-api'; export const Panel = () => { - const state = useStorybookApi(); + const api = useStorybookApi(); + + const toggleMyTool = useCallback(() => { + // Custom logic to toggle the addon here + }, []); + + useEffect(() => { + api.setAddonShortcut('custom-toolbar-addon', { + label: 'Enable toolbar addon', + defaultShortcut: ['G'], + actionName: 'Toggle', + showInMenu: false, + action: toggleAddon, + }); + }, [api]); - return
do something with storybook's api
; + return ( + + + + ); }; ``` diff --git a/docs/snippets/common/storybook-addons-api-usechannel.js.mdx b/docs/snippets/common/storybook-addons-api-usechannel.js.mdx index 13fb84dcb93a..0d66a5955350 100644 --- a/docs/snippets/common/storybook-addons-api-usechannel.js.mdx +++ b/docs/snippets/common/storybook-addons-api-usechannel.js.mdx @@ -1,19 +1,24 @@ ```js -// /my-addon/manager.js +// my-addon/manager.js|ts import React from 'react'; +import { AddonPanel, Button } from '@storybook/components'; + import { STORY_CHANGED } from '@storybook/core-events'; export const Panel = () => { + // Creates a Storybook API channel and subscribes to the STORY_CHANGED event const emit = useChannel({ STORY_CHANGED: (...args) => console.log(...args), }); return ( - + + + ); }; ``` diff --git a/docs/snippets/common/storybook-addons-api-useglobal.js.mdx b/docs/snippets/common/storybook-addons-api-useglobal.js.mdx index b3189929161f..541fefba9467 100644 --- a/docs/snippets/common/storybook-addons-api-useglobal.js.mdx +++ b/docs/snippets/common/storybook-addons-api-useglobal.js.mdx @@ -1,19 +1,23 @@ ```js -// /my-addon/manager.js +// my-addon/manager.js|ts import React from 'react'; +import { AddonPanel, Button } from '@storybook/components'; + import { useGlobals } from '@storybook/manager-api'; export const Panel = () => { const [globals, updateGlobals] = useGlobals(); - const isActive = globals['my-param-key'] || false; + const isActive = globals['my-param-key'] || false; // 👈 Sets visibility based on the global value. return ( - + + + ); }; ``` diff --git a/docs/snippets/common/storybook-addons-api-useparameter.js.mdx b/docs/snippets/common/storybook-addons-api-useparameter.js.mdx index 2ea5ade4f211..1ae5449f2ec8 100644 --- a/docs/snippets/common/storybook-addons-api-useparameter.js.mdx +++ b/docs/snippets/common/storybook-addons-api-useparameter.js.mdx @@ -1,18 +1,24 @@ ```js -// /my-addon/manager.js +// my-addon/manager.js|ts import React from 'react'; +import { AddonPanel } from '@storybook/components'; + import { useParameter } from '@storybook/manager-api'; export const Panel = () => { - const value = useParameter('parameter-key', 'default value'); + // Connects to Storybook's API and retrieves the value of the custom parameter for the current story + const value = useParameter('custom-parameter', 'initial value'); return ( -
- for the currently selected story, the parameter for "parameter-key" is: - {value} -
+ + {value === 'initial value' ? ( +

The story doesn't contain custom parameters. Defaulting to the initial value.

+ ) : ( +

You've set {value} as the parameter.

+ )} +
); }; ``` diff --git a/docs/snippets/common/storybook-addons-api-usestorybookstate.js.mdx b/docs/snippets/common/storybook-addons-api-usestorybookstate.js.mdx index 2ee507410a6f..1f897f7c31fe 100644 --- a/docs/snippets/common/storybook-addons-api-usestorybookstate.js.mdx +++ b/docs/snippets/common/storybook-addons-api-usestorybookstate.js.mdx @@ -1,13 +1,22 @@ ```js -// /my-addon/manager.js +// my-addon/src/manager.js|ts import React from 'react'; +import { AddonPanel } from '@storybook/components'; + import { useStorybookState } from '@storybook/manager-api'; export const Panel = () => { const state = useStorybookState(); - - return
do something with storybook's state
; + return ( + + {state.viewMode !== 'docs' ? ( +

Do something with the documentation

+ ) : ( +

Show the panel when viewing the story

+ )} +
+ ); }; ``` From 9867da02a2bd2dda12ee7368e28a00ae35c2f785 Mon Sep 17 00:00:00 2001 From: Kyle Gach Date: Tue, 4 Apr 2023 14:08:57 -0600 Subject: [PATCH 4/5] Update Migration Guide snippets --- docs/get-started/install.md | 4 ++-- docs/snippets/common/init-command.npx.js.mdx | 3 +++ docs/snippets/common/init-command.npx.mdx | 3 --- docs/snippets/common/init-command.pnpm.js.mdx | 3 +++ docs/snippets/common/init-command.pnpm.mdx | 3 --- ...{storybook-upgrade.npm.js => storybook-upgrade.npm.js.mdx} | 0 ...torybook-upgrade.pnpm.js => storybook-upgrade.pnpm.js.mdx} | 0 7 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 docs/snippets/common/init-command.npx.js.mdx delete mode 100644 docs/snippets/common/init-command.npx.mdx create mode 100644 docs/snippets/common/init-command.pnpm.js.mdx delete mode 100644 docs/snippets/common/init-command.pnpm.mdx rename docs/snippets/common/{storybook-upgrade.npm.js => storybook-upgrade.npm.js.mdx} (100%) rename docs/snippets/common/{storybook-upgrade.pnpm.js => storybook-upgrade.pnpm.js.mdx} (100%) diff --git a/docs/get-started/install.md b/docs/get-started/install.md index 7e6b2155e8a2..1d89b725936c 100644 --- a/docs/get-started/install.md +++ b/docs/get-started/install.md @@ -8,8 +8,8 @@ Use the Storybook CLI to install it in a single command. Run this inside your _e diff --git a/docs/snippets/common/init-command.npx.js.mdx b/docs/snippets/common/init-command.npx.js.mdx new file mode 100644 index 000000000000..97177a2cfd64 --- /dev/null +++ b/docs/snippets/common/init-command.npx.js.mdx @@ -0,0 +1,3 @@ +```shell +npx storybook init +``` diff --git a/docs/snippets/common/init-command.npx.mdx b/docs/snippets/common/init-command.npx.mdx deleted file mode 100644 index 43d159637237..000000000000 --- a/docs/snippets/common/init-command.npx.mdx +++ /dev/null @@ -1,3 +0,0 @@ -```shell -npx storybook@next init -``` diff --git a/docs/snippets/common/init-command.pnpm.js.mdx b/docs/snippets/common/init-command.pnpm.js.mdx new file mode 100644 index 000000000000..ea6bc0bf1bcc --- /dev/null +++ b/docs/snippets/common/init-command.pnpm.js.mdx @@ -0,0 +1,3 @@ +```shell +pnpm dlx storybook init +``` diff --git a/docs/snippets/common/init-command.pnpm.mdx b/docs/snippets/common/init-command.pnpm.mdx deleted file mode 100644 index 11533cd674b3..000000000000 --- a/docs/snippets/common/init-command.pnpm.mdx +++ /dev/null @@ -1,3 +0,0 @@ -```shell -pnpm dlx storybook@next init -``` diff --git a/docs/snippets/common/storybook-upgrade.npm.js b/docs/snippets/common/storybook-upgrade.npm.js.mdx similarity index 100% rename from docs/snippets/common/storybook-upgrade.npm.js rename to docs/snippets/common/storybook-upgrade.npm.js.mdx diff --git a/docs/snippets/common/storybook-upgrade.pnpm.js b/docs/snippets/common/storybook-upgrade.pnpm.js.mdx similarity index 100% rename from docs/snippets/common/storybook-upgrade.pnpm.js rename to docs/snippets/common/storybook-upgrade.pnpm.js.mdx From b8bfb185b00645f02c85b92eba174391fca20853 Mon Sep 17 00:00:00 2001 From: Kasper Peulen Date: Wed, 5 Apr 2023 09:54:05 +0200 Subject: [PATCH 5/5] Point upgrade script to latest --- docs/snippets/common/storybook-upgrade.npm.js.mdx | 2 +- docs/snippets/common/storybook-upgrade.pnpm.js.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/snippets/common/storybook-upgrade.npm.js.mdx b/docs/snippets/common/storybook-upgrade.npm.js.mdx index 6f1f9f5f1157..1778af1b3968 100644 --- a/docs/snippets/common/storybook-upgrade.npm.js.mdx +++ b/docs/snippets/common/storybook-upgrade.npm.js.mdx @@ -1,3 +1,3 @@ ```shell -npx storybook upgrade +npx storybook@latest upgrade ``` diff --git a/docs/snippets/common/storybook-upgrade.pnpm.js.mdx b/docs/snippets/common/storybook-upgrade.pnpm.js.mdx index 67ab5ab4bc78..0490b332dcb7 100644 --- a/docs/snippets/common/storybook-upgrade.pnpm.js.mdx +++ b/docs/snippets/common/storybook-upgrade.pnpm.js.mdx @@ -1,3 +1,3 @@ ```shell -pnpx storybook upgrade +pnpm dlx storybook@latest upgrade ```