Skip to content

Commit e4b1666

Browse files
authored
docs: migrate Storybook to v9 (#7466)
This commit also includes: - Reordering the "Charts" section to appear after the main components. - ToC on large screens (fixed position) only shows scrollbar when required
1 parent 6f42bcc commit e4b1666

File tree

268 files changed

+1148
-5996
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

268 files changed

+1148
-5996
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,5 @@ packages/*/src/generated/
2929
cypress/downloads
3030

3131
.nx
32+
33+
debug-storybook.log

.storybook/components/ArgTypesWithNote.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { DomRefTable } from '@sb/components/DomRefTable.js';
2-
import { ArgTypes } from '@storybook/blocks';
2+
import { ArgTypes, type Controls } from '@storybook/addon-docs/blocks';
33
import MessageStripDesign from '@ui5/webcomponents/dist/types/MessageStripDesign.js';
44
import { MessageStrip } from '@ui5/webcomponents-react';
55
import type { ComponentProps, ReactNode } from 'react';
@@ -17,16 +17,20 @@ interface ArgTypesWithNotePropTypes {
1717
* If `true` all headings are rendered as `Heading`s instead of `Subheading`s.
1818
*/
1919
isHeading?: boolean;
20+
/**
21+
* Story meta module.
22+
*/
23+
metaOf: ComponentProps<typeof Controls>['of'];
2024
}
2125

2226
export function ArgTypesWithNote(props: ComponentProps<typeof ArgTypes> & ArgTypesWithNotePropTypes) {
23-
const { hideHTMLPropsNote, noteText, isHeading, ...rest } = props;
27+
const { hideHTMLPropsNote, noteText, isHeading, metaOf, ...rest } = props;
2428

2529
if (hideHTMLPropsNote) {
2630
return (
2731
<>
2832
<ArgTypes {...rest} />
29-
<DomRefTable of={rest.of} isSubheading={!isHeading} />
33+
<DomRefTable of={rest.of} metaOf={metaOf} isSubheading={!isHeading} />
3034
</>
3135
);
3236
}
@@ -36,7 +40,7 @@ export function ArgTypesWithNote(props: ComponentProps<typeof ArgTypes> & ArgTyp
3640
{noteText ?? 'This component supports all HTML attributes.'}
3741
</MessageStrip>
3842
<ArgTypes {...rest} />
39-
<DomRefTable of={rest.of} isSubheading={!isHeading} />
43+
<DomRefTable of={rest.of} metaOf={metaOf} isSubheading={!isHeading} />
4044
</div>
4145
);
4246
}

.storybook/components/CommandsAndQueries.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Heading, Markdown } from '@storybook/blocks';
1+
import { Heading, Markdown } from '@storybook/addon-docs/blocks';
22
import { Tag as WCRTag } from '@ui5/webcomponents-react';
33
import dedent from 'dedent';
44
import { Fragment } from 'react';

.storybook/components/ControlsWithNote.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Controls } from '@storybook/blocks';
1+
import { Controls } from '@storybook/addon-docs/blocks';
22
import MessageStripDesign from '@ui5/webcomponents/dist/types/MessageStripDesign.js';
33
import { MessageStrip } from '@ui5/webcomponents-react';
44
import type { ComponentProps, ReactNode } from 'react';
@@ -26,7 +26,7 @@ export function ControlsWithNote(props: ComponentProps<typeof Controls> & Contro
2626
</MessageStrip>
2727
)}
2828
<Controls {...rest} />
29-
<DomRefTable />
29+
<DomRefTable of={props.of} />
3030
</div>
3131
);
3232
}

.storybook/components/DocsHeader.tsx

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Description, DocsContext, Subtitle, Title } from '@storybook/addon-docs';
1+
import type { Controls } from '@storybook/addon-docs/blocks';
2+
import { Description, Subtitle, Title, useOf } from '@storybook/addon-docs/blocks';
23
import ButtonDesign from '@ui5/webcomponents/dist/types/ButtonDesign.js';
34
import MessageStripDesign from '@ui5/webcomponents/dist/types/MessageStripDesign.js';
45
import copyIcon from '@ui5/webcomponents-icons/dist/copy.js';
@@ -13,21 +14,14 @@ import {
1314
ThemeProvider,
1415
} from '@ui5/webcomponents-react';
1516
import { clsx } from 'clsx';
16-
import { useContext } from 'react';
17+
import type { ComponentProps } from 'react';
1718
import { useGetSubComponentsOfModule } from '../utils';
1819
import classes from './DocsHeader.module.css';
1920
import { GitHubLogo } from './GitHub-Mark';
2021
import { Import } from './Import';
2122
import { TableOfContent } from './TableOfContent';
2223

23-
const Links = () => {
24-
const docsContext = useContext(DocsContext);
25-
const isChart = docsContext.componentStories().at(0).id.startsWith('charts-');
26-
27-
// const filePath = docsContext.parameters.fileName.replace(/^\.\//, '');
28-
// const folderPath = filePath.substr(0, filePath.lastIndexOf('/'));
29-
30-
// const githubUrl = `https://github.com/SAP/ui5-webcomponents-react/tree/main/${folderPath}`;
24+
const Links = ({ isChart }: { isChart?: boolean }) => {
3125
const githubUrl = `https://github.com/SAP/ui5-webcomponents-react`;
3226

3327
const packageName = `@ui5/webcomponents-react${isChart ? '-charts' : ''}`;
@@ -50,14 +44,15 @@ interface InfoTableProps {
5044
mergeSubComponents?: boolean;
5145
isChart?: boolean;
5246
experimental?: boolean;
47+
of: ComponentProps<typeof Controls>['of'];
5348
}
5449

55-
export const InfoTable = ({ since, subComponents, mergeSubComponents }: InfoTableProps) => {
56-
const context = useContext(DocsContext);
57-
const groups = context.componentStories().at(0).kind.split('/');
58-
const moduleName = groups[groups.length - 1].replace('(experimental)', '').trim();
50+
export const InfoTable = ({ of, since, subComponents, mergeSubComponents }: InfoTableProps) => {
51+
const context = useOf<'meta'>(of);
52+
const { csfFile, preparedMeta } = context;
53+
const moduleName = csfFile.meta.component.displayName;
5954

60-
const wcSubComponents = useGetSubComponentsOfModule(moduleName.replace('V2', ''));
55+
const wcSubComponents = useGetSubComponentsOfModule(moduleName.replace('V2', ''), preparedMeta.tags);
6156
const subComps = mergeSubComponents
6257
? [...(subComponents ?? []), ...(wcSubComponents ?? [])]
6358
: (subComponents ?? wcSubComponents);
@@ -81,7 +76,7 @@ export const InfoTable = ({ since, subComponents, mergeSubComponents }: InfoTabl
8176
<Label>Usage</Label>
8277
</th>
8378
<td data-import-cell={supportsClipboardApi}>
84-
<Import />
79+
<Import moduleNames={[moduleName]} componentId={preparedMeta.componentId} />
8580
{supportsClipboardApi && (
8681
<Button
8782
design={ButtonDesign.Transparent}
@@ -110,7 +105,7 @@ export const InfoTable = ({ since, subComponents, mergeSubComponents }: InfoTabl
110105
<Label>Subcomponents</Label>
111106
</th>
112107
<td data-import-cell={supportsClipboardApi}>
113-
<Import moduleNames={subComps} />
108+
<Import moduleNames={subComps} componentId={preparedMeta.componentId} />
114109
{supportsClipboardApi && (
115110
<Button
116111
design={ButtonDesign.Transparent}
@@ -129,17 +124,17 @@ export const InfoTable = ({ since, subComponents, mergeSubComponents }: InfoTabl
129124
);
130125
};
131126

132-
export const DocsHeader = ({ since, subComponents, mergeSubComponents, isChart, experimental }: InfoTableProps) => {
127+
export const DocsHeader = ({ of, since, subComponents, mergeSubComponents, isChart, experimental }: InfoTableProps) => {
133128
return (
134129
<ThemeProvider>
135130
<FlexBox alignItems={FlexBoxAlignItems.Center} className={classes.titleRow}>
136131
<Title />
137132
{experimental && <Label className={classes.experimentalLabel}>experimental</Label>}
138133
<span style={{ flexGrow: 1 }} />
139-
<Links />
134+
<Links isChart={isChart} />
140135
</FlexBox>
141136
<Subtitle />
142-
<InfoTable since={since} subComponents={subComponents} mergeSubComponents={mergeSubComponents} />
137+
<InfoTable of={of} since={since} subComponents={subComponents} mergeSubComponents={mergeSubComponents} />
143138
<TableOfContent />
144139
<Description />
145140
{isChart && (

.storybook/components/DomRefTable.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import type { ArgTypes } from '@storybook/blocks';
2-
import { DocsContext, Heading, Subheading } from '@storybook/blocks';
1+
import type { Controls } from '@storybook/addon-docs/blocks';
2+
import { Heading, Subheading, useOf } from '@storybook/addon-docs/blocks';
33
import TagDesign from '@ui5/webcomponents/dist/types/TagDesign.js';
44
import { Tag, Link, MessageStrip, Popover } from '@ui5/webcomponents-react';
55
import type * as CEM from '@ui5/webcomponents-tools/lib/cem/types';
66
import type { ComponentProps, ReactNode } from 'react';
7-
import { Fragment, useContext, useRef } from 'react';
7+
import { Fragment, useRef } from 'react';
88
import { createPortal } from 'react-dom';
9-
import { useGetCem } from '../utils';
9+
import { useGetCem } from '../utils.js';
1010
import classes from './DomRefTable.module.css';
1111

1212
export function CodeBlock(props: { children: ReactNode }) {
@@ -51,19 +51,23 @@ function Name(props: CEM.ClassMember) {
5151
export function DomRefTable({
5252
of,
5353
isSubheading,
54+
metaOf,
5455
}: {
55-
of?: ComponentProps<typeof ArgTypes>['of'];
56+
of: ComponentProps<typeof Controls>['of'];
5657
isSubheading?: boolean;
58+
metaOf?: ComponentProps<typeof Controls>['of'];
5759
}) {
58-
const docsContext = useContext(DocsContext);
59-
const storyTags: string[] = docsContext.attachedCSFFile?.meta?.tags;
60+
const resolvedOf = useOf<'story' | 'component'>(of);
61+
const resolvedMetaOf = useOf<'meta'>(metaOf);
62+
63+
const { story: storyContext, component: componentContext } = resolvedOf;
64+
const storyTags: string[] = storyContext?.tags ?? resolvedMetaOf?.preparedMeta?.tags;
6065
const cemModuleName = storyTags?.find((tag) => tag.startsWith('cem-module:'));
61-
const componentName = of?.displayName ?? docsContext.componentStories().at(0)?.component?.displayName;
66+
const componentName = of?.displayName ?? storyContext.component.displayName;
6267
const popoverRef = useRef(null);
6368

64-
const knownAttributes = new Set(Object.keys(of?.__docgenInfo?.props ?? docsContext.primaryStory?.argTypes ?? {}));
65-
const cem = useGetCem();
66-
69+
const knownAttributes = new Set(Object.keys(componentContext?.__docgenInfo?.props ?? storyContext.argTypes));
70+
const cem = useGetCem(storyTags);
6771
const moduleName = cemModuleName ? cemModuleName.split(':')[1] : componentName;
6872

6973
const componentMembers =

.storybook/components/Import.tsx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { DocsContext } from '@storybook/addon-docs';
2-
import { Fragment, useContext } from 'react';
1+
import { Fragment } from 'react';
32

43
interface ImportStatementPropTypes {
54
/**
@@ -119,16 +118,14 @@ interface ImportProps {
119118
/**
120119
* Names of module/component (e.g. "Button")
121120
*/
122-
moduleNames?: ImportStatementPropTypes['moduleNames'];
121+
moduleNames: ImportStatementPropTypes['moduleNames'];
122+
componentId: string;
123123
}
124124

125125
export const Import = (props: ImportProps) => {
126-
const context = useContext(DocsContext);
127-
const isChart = context.componentStories().at(0).id.startsWith('charts-');
128-
const isCompat = context.componentStories().at(0).id.startsWith('legacy-');
129-
const groups = context.componentStories().at(0).kind.split('/');
130-
const module = groups[groups.length - 1].replace('(experimental)', '').trim();
131-
const moduleNames = props.moduleNames ?? [module];
126+
const { componentId, moduleNames } = props;
127+
const isChart = componentId.startsWith('charts-');
128+
const isCompat = componentId.startsWith('legacy-');
132129

133130
return (
134131
<ImportStatement

.storybook/components/TableOfContent.tsx

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
1-
import { useEffect } from 'react';
1+
import { useCallback, useEffect } from 'react';
22
import * as tocbot from 'tocbot';
33
import classes from './ToC.module.css';
44

55
export function TableOfContent({
66
headingSelector = 'h2:not(.noAnchor), h3:not(.noAnchor), h4:not(.noAnchor)',
77
onlyDisplaySideNav = false,
8+
tocOverflowHeight = 1080,
89
}: {
910
headingSelector?: string;
1011
onlyDisplaySideNav?: boolean;
12+
tocOverflowHeight?: number;
1113
}) {
14+
const refCallback = useCallback(
15+
(node: HTMLDivElement) => {
16+
if (node) {
17+
if (
18+
window.matchMedia('(min-width:1330px)').matches &&
19+
window.matchMedia(`(min-height:${tocOverflowHeight}px)`).matches
20+
) {
21+
node.style.overflowY = 'hidden';
22+
} else {
23+
node.style.overflowY = undefined;
24+
}
25+
}
26+
},
27+
[tocOverflowHeight],
28+
);
29+
1230
useEffect(() => {
1331
tocbot.init({
1432
tocSelector: '.js-toc',
@@ -25,13 +43,12 @@ export function TableOfContent({
2543
tocbot.destroy();
2644
};
2745
}, [headingSelector]);
28-
2946
return (
3047
<>
3148
<h3 className={`${classes.header} noAnchor`} data-show-small={!onlyDisplaySideNav}>
3249
Contents
3350
</h3>
34-
<div className={classes.fixedContainer} data-show-small={!onlyDisplaySideNav}>
51+
<div ref={refCallback} className={classes.fixedContainer} data-show-small={!onlyDisplaySideNav}>
3552
<div className={`js-toc ${classes.toc}`} id="toc-container" />
3653
</div>
3754
</>

.storybook/components/ToC.module.css

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
.toc :global(.toc-link) {
2222
font-family: var(--sapFontFamily) !important;
2323
font-size: var(--sapFontSize) !important;
24-
-webkit-font-smoothing: auto;
2524
line-height: normal;
2625
}
2726

@@ -75,13 +74,14 @@
7574
.fixedContainer {
7675
width: 200px;
7776
position: fixed;
78-
top: 75px;
77+
top: 38px;
7978
right: 6px;
8079
overflow-x: hidden;
8180
overflow-y: auto;
8281
}
8382

8483
.toc :global(.toc-list) {
84+
margin-block-start: 0;
8585
padding-inline-start: 1rem;
8686
}
8787

@@ -93,13 +93,13 @@
9393
width: 4px;
9494
}
9595

96-
.toc :global(.toc-list-item) {
97-
/*overflow: hidden;*/
98-
/*text-overflow: ellipsis;*/
99-
/*white-space: nowrap;*/
100-
}
101-
10296
.toc :global(.is-active-link)::before {
10397
background-color: #0a6ed1;
10498
}
10599
}
100+
101+
@media (min-width: 1650px) {
102+
.fixedContainer {
103+
width: 250px;
104+
}
105+
}

.storybook/components/VersionSwitch.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/* eslint-disable react-hooks/rules-of-hooks */
22

3-
import { IconButton } from '@storybook/components';
4-
import { addons, types } from '@storybook/manager-api';
53
import '@ui5/webcomponents/dist/Menu.js';
64
import '@ui5/webcomponents/dist/MenuItem.js';
75
import * as React from 'react';
6+
import { IconButton } from 'storybook/internal/components';
7+
import { addons, types } from 'storybook/manager-api';
88

99
const ADDON_ID = 'version-switch';
1010
const TOOL_ID = `${ADDON_ID}/toolbar`;

0 commit comments

Comments
 (0)