Skip to content

Commit

Permalink
Merge pull request #29253 from storybookjs/larsrickert/1898-story-cod…
Browse files Browse the repository at this point in the history
…e-panel

Docs: Add code snippet to addons panel
  • Loading branch information
shilman authored Dec 13, 2024
2 parents d3cce51 + f2a8af8 commit b98a73b
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 12 deletions.
17 changes: 17 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<h1>Migration</h1>

- [From version 8.4.x to 8.5.x](#from-version-84x-to-85x)
- [Added source code panel to docs](#added-source-code-panel-to-docs)
- [Addon-a11y: Component test integration](#addon-a11y-component-test-integration)
- [Addon-a11y: Deprecated `parameters.a11y.manual`](#addon-a11y-deprecated-parametersa11ymanual)
- [Indexing behavior of @storybook/experimental-addon-test is changed](#indexing-behavior-of-storybookexperimental-addon-test-is-changed)
Expand Down Expand Up @@ -425,6 +426,22 @@

## From version 8.4.x to 8.5.x

### Added source code panel to docs

Starting in 8.5, Storybook Docs (`@storybook/addon-docs`) automatically adds a new addon panel to stories that displays a source snippet beneath each story. This works similarly to the existing [source snippet doc block](https://storybook.js.org/docs/writing-docs/doc-blocks#source), but in the story view. It is intended to replace the [Storysource addon](https://storybook.js.org/addons/@storybook/addon-storysource).

If you wish to disable this panel globally, add the following line to your `.storybook/preview.js` project configuration. You can also selectively disable/enable at the story level.

```js
export default {
parameters: {
docs: {
codePanel: false,
},
},
};
```

### Addon-a11y: Component test integration

In Storybook 8.4, we introduced the [Test addon](https://storybook.js.org/docs/writing-tests/test-addon) (`@storybook/experimental-addon-test`). Powered by Vitest under the hood, this addon lets you watch, run, and debug your component tests directly in Storybook.
Expand Down
13 changes: 11 additions & 2 deletions code/addons/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,12 @@
"./angular": "./angular/index.js",
"./angular/index.js": "./angular/index.js",
"./web-components/index.js": "./web-components/index.js",
"./package.json": "./package.json"
"./package.json": "./package.json",
"./manager": {
"types": "./dist/manager.d.ts",
"import": "./dist/manager.mjs",
"require": "./dist/manager.js"
}
},
"main": "dist/index.js",
"module": "dist/index.mjs",
Expand Down Expand Up @@ -129,7 +134,11 @@
"./src/preview.ts",
"./src/blocks.ts",
"./src/shims/mdx-react-shim.ts",
"./src/mdx-loader.ts"
"./src/mdx-loader.ts",
"./src/manager.tsx"
],
"managerEntries": [
"./src/manager.tsx"
]
},
"gitHead": "e6a7fd8a655c69780bc20b9749c2699e44beae16",
Expand Down
57 changes: 57 additions & 0 deletions code/addons/docs/src/manager.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';

import { AddonPanel, type SyntaxHighlighterFormatTypes } from 'storybook/internal/components';
import { ADDON_ID, PANEL_ID, PARAM_KEY, SNIPPET_RENDERED } from 'storybook/internal/docs-tools';
import { addons, types, useAddonState, useChannel } from 'storybook/internal/manager-api';

import { Source } from '@storybook/blocks';

addons.register(ADDON_ID, (api) => {
addons.add(PANEL_ID, {
title: 'Code',
type: types.PANEL,
paramKey: PARAM_KEY,
/**
* This code panel can be disabled by the user by adding this parameter:
*
* @example
*
* ```ts
* parameters: {
* docs: {
* codePanel: false,
* },
* },
* ```
*/
disabled: (parameters) => {
return (
!!parameters &&
typeof parameters[PARAM_KEY] === 'object' &&
parameters[PARAM_KEY].codePanel === false
);
},
match: ({ viewMode }) => viewMode === 'story',
render: ({ active }) => {
const [codeSnippet, setSourceCode] = useAddonState<{
source: string;
format: SyntaxHighlighterFormatTypes;
}>(ADDON_ID, {
source: '',
format: 'html',
});

useChannel({
[SNIPPET_RENDERED]: ({ source, format }) => {
setSourceCode({ source, format });
},
});

return (
<AddonPanel active={!!active}>
<Source code={codeSnippet.source} format={codeSnippet.format} dark />
</AddonPanel>
);
},
});
});
23 changes: 23 additions & 0 deletions code/addons/docs/template/stories/sourcePanel/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export default {
component: globalThis.Components.Button,
tags: ['autodocs'],
parameters: {
chromatic: { disable: true },
docs: {
codePanel: false,
},
},
};

export const One = { args: { label: 'One' } };

export const Two = { args: { label: 'Two' } };

export const WithSource = {
args: { label: 'Three' },
parameters: {
docs: {
codePanel: true,
},
},
};
5 changes: 5 additions & 0 deletions code/addons/essentials/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
},
"./backgrounds/manager": "./dist/backgrounds/manager.js",
"./controls/manager": "./dist/controls/manager.js",
"./docs/manager": "./dist/docs/manager.js",
"./docs/preview": {
"types": "./dist/docs/preview.d.ts",
"import": "./dist/docs/preview.mjs",
Expand Down Expand Up @@ -114,10 +115,14 @@
"./src/docs/preset.ts",
"./src/docs/mdx-react-shim.ts"
],
"entries": [
"./src/docs/manager.ts"
],
"managerEntries": [
"./src/actions/manager.ts",
"./src/backgrounds/manager.ts",
"./src/controls/manager.ts",
"./src/docs/manager.ts",
"./src/measure/manager.ts",
"./src/outline/manager.ts",
"./src/toolbars/manager.ts",
Expand Down
2 changes: 2 additions & 0 deletions code/addons/essentials/src/docs/manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// @ts-expect-error (no types needed for this)
export * from '@storybook/addon-docs/manager';
2 changes: 1 addition & 1 deletion code/addons/essentials/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ export function addons(options: PresetOptions) {

// NOTE: The order of these addons is important.
return [
'docs',
'controls',
'actions',
'docs',
'backgrounds',
'viewport',
'toolbars',
Expand Down
4 changes: 2 additions & 2 deletions code/core/src/manager/components/preview/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const createTabsTool = (tabs: Addon_BaseType[]): Addon_BaseType => ({
const isActive = rp.path.includes(`tab=${tab.id}`);
return (
<TabButton
disabled={tab.disabled}
disabled={!!tab.disabled}
active={isActive}
onClick={() => {
rp.applyQueryParams({ tab: tabIdToApply });
Expand Down Expand Up @@ -146,7 +146,7 @@ export const ToolbarComp = React.memo<ToolData>(function ToolbarComp({
{tabs.map((tab, index) => {
return (
<TabButton
disabled={tab.disabled}
disabled={!!tab.disabled}
active={tab.id === tabId || (tab.id === 'canvas' && !tabId)}
onClick={() => {
api.applyQueryParams({ tab: tab.id === 'canvas' ? undefined : tab.id });
Expand Down
6 changes: 6 additions & 0 deletions code/core/src/manager/container/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ const getPanels = (api: API) => {
if (paramKey && parameters && parameters[paramKey] && parameters[paramKey].disable) {
return;
}
if (
panel.disabled === true ||
(typeof panel.disabled === 'function' && panel.disabled(parameters))
) {
return;
}
filteredPanels[id] = panel;
});

Expand Down
4 changes: 2 additions & 2 deletions code/core/src/types/modules/addons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { TestProviderConfig, TestingModuleProgressReportProgress } from '..
import type { RenderData as RouterData } from '../../router/types';
import type { ThemeVars } from '../../theming/types';
import type { API_SidebarOptions } from './api';
import type { API_HashEntry, API_StatusState, API_StatusUpdate } from './api-stories';
import type { API_HashEntry, API_StoryEntry } from './api-stories';
import type {
Args,
ArgsStoryFn as ArgsStoryFnForFramework,
Expand Down Expand Up @@ -392,7 +392,7 @@ export interface Addon_BaseType {
/** @unstable */
paramKey?: string;
/** @unstable */
disabled?: boolean;
disabled?: boolean | ((parameters: API_StoryEntry['parameters']) => boolean);
/** @unstable */
hidden?: boolean;
}
Expand Down
6 changes: 1 addition & 5 deletions code/renderers/vue3/src/docs/sourceDecorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ ${template}`;
* Checks if the source code generation should be skipped for the given Story context. Will be true
* if one of the following is true:
*
* - View mode is not "docs"
* - Story is no arg story
* - Story has set custom source code via parameters.docs.source.code
* - Story has set source type to "code" via parameters.docs.source.type
Expand All @@ -120,13 +119,10 @@ export const shouldSkipSourceCodeGeneration = (context: StoryContext): boolean =
}

const isArgsStory = context?.parameters.__isArgsStory;
const isDocsViewMode = context?.viewMode === 'docs';

// never render if the user is forcing the block to render code, or
// if the user provides code, or if it's not an args story.
return (
!isDocsViewMode || !isArgsStory || sourceParams?.code || sourceParams?.type === SourceType.CODE
);
return !isArgsStory || sourceParams?.code || sourceParams?.type === SourceType.CODE;
};

/**
Expand Down

0 comments on commit b98a73b

Please sign in to comment.