Skip to content

Commit 8e94889

Browse files
authored
stories: fix api reference table (#95396)
Fixes API reference table - we need to export only the types we want to show, as some components will have multiple. I have also improved the story types, which surfaced some potential runtime cases we weren't handling correctly
1 parent e5df1ff commit 8e94889

File tree

6 files changed

+53
-18
lines changed

6 files changed

+53
-18
lines changed

static/app/components/core/alert/index.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import {Button} from 'sentry/components/core/button';
1717
import {IconAdd, IconDelete, IconEdit} from 'sentry/icons';
1818
import * as Storybook from 'sentry/stories';
1919

20-
import types from '!!type-loader!sentry/components/core/alert/index';
20+
import APIReference from '!!type-loader!sentry/components/core/alert/index';
2121

22-
export {types};
22+
export const types = {Alert: APIReference.Alert};
2323

2424
To create a basic alert, wrap your message in an `<Alert>` component and specify the appropriate type.
2525

static/app/components/core/button/index.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ import {
3838
} from 'sentry/icons';
3939
import * as Storybook from 'sentry/stories';
4040

41-
import types from '!!type-loader!sentry/components/core/button/index';
41+
import APIReference from '!!type-loader!sentry/components/core/button/index';
4242

43-
export {types};
43+
export const types = {Button: APIReference.Button};
4444

4545
To create a basic button, wrap text in a `<Button>` and pass an `onClick` callback.
4646

static/app/stories/view/storyExports.tsx

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {space} from 'sentry/styles/space';
1212

1313
import {StoryResources} from './storyResources';
1414
import {StorySourceLinks} from './storySourceLinks';
15-
import type {StoryDescriptor} from './useStoriesLoader';
15+
import {isMDXStory, type StoryDescriptor} from './useStoriesLoader';
1616
import type {StoryExports as StoryExportValues} from './useStory';
1717
import {StoryContextProvider, useStory} from './useStory';
1818

@@ -47,11 +47,11 @@ function StoryLayout() {
4747
function StoryTitlebar() {
4848
const {story} = useStory();
4949

50+
if (!isMDXStory(story)) return null;
51+
5052
const title = story.exports.frontmatter?.title;
5153
const description = story.exports.frontmatter?.description;
5254

53-
if (!story.filename.endsWith('.mdx')) return null;
54-
5555
return (
5656
<StoryHeader>
5757
<StoryGrid>
@@ -74,7 +74,8 @@ function StoryTabList() {
7474
<TabList>
7575
<TabList.Item key="usage">{t('Usage')}</TabList.Item>
7676
{story.exports.types ? <TabList.Item key="api">{t('API')}</TabList.Item> : null}
77-
{story.exports.frontmatter?.resources ? (
77+
78+
{isMDXStory(story) && story.exports.frontmatter?.resources ? (
7879
<TabList.Item key="resources">{t('Resources')}</TabList.Item>
7980
) : null}
8081
</TabList>
@@ -109,6 +110,7 @@ function StoryUsage() {
109110
filename,
110111
},
111112
} = useStory();
113+
112114
return (
113115
<Fragment>
114116
{Story && (
@@ -129,9 +131,10 @@ function StoryUsage() {
129131
return null;
130132
}
131133
if (typeof MaybeComponent === 'function') {
134+
const Component = MaybeComponent as React.ComponentType;
132135
return (
133136
<Storybook.Section key={name}>
134-
<MaybeComponent />
137+
<Component />
135138
</Storybook.Section>
136139
);
137140
}
@@ -148,7 +151,26 @@ function StoryUsage() {
148151
function StoryAPI() {
149152
const {story} = useStory();
150153
if (!story.exports.types) return null;
151-
return <Storybook.APIReference types={story.exports.types} />;
154+
155+
if (
156+
typeof story.exports.types === 'object' &&
157+
story.exports.types !== null &&
158+
'filename' in story.exports.types
159+
) {
160+
return (
161+
<Storybook.APIReference
162+
types={story.exports.types as TypeLoader.ComponentDocWithFilename}
163+
/>
164+
);
165+
}
166+
167+
return (
168+
<Fragment>
169+
{Object.entries(story.exports.types).map(([key, value]) => {
170+
return <Storybook.APIReference key={key} types={value} />;
171+
})}
172+
</Fragment>
173+
);
152174
}
153175

154176
const StoryHeader = styled('header')`

static/app/stories/view/storyFooter.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,24 @@ import styled from '@emotion/styled';
33
import {LinkButton} from 'sentry/components/core/button/linkButton';
44
import {Flex} from 'sentry/components/core/layout';
55
import {IconArrow} from 'sentry/icons';
6+
import {isMDXStory} from 'sentry/stories/view/useStoriesLoader';
67
import {useStory} from 'sentry/stories/view/useStory';
78
import {space} from 'sentry/styles/space';
89

910
export function StoryFooter() {
1011
const {story} = useStory();
11-
if (!story.filename.endsWith('.mdx')) return null;
12+
if (!isMDXStory(story)) return null;
1213
const {prev, next} = story.exports.frontmatter ?? {};
14+
1315
return (
1416
<Flex align="center" justify="space-between" gap={space(2)}>
15-
{prev && (
17+
{typeof prev === 'object' && 'link' in prev && (
1618
<Card to={prev.link} icon={<IconArrow direction="left" />}>
1719
<CardLabel>Previous</CardLabel>
1820
<CardTitle>{prev.label}</CardTitle>
1921
</Card>
2022
)}
21-
{next && (
23+
{typeof next === 'object' && 'link' in next && (
2224
<Card data-flip to={next.link} icon={<IconArrow direction="right" />}>
2325
<CardLabel>Next</CardLabel>
2426
<CardTitle>{next.label}</CardTitle>

static/app/stories/view/storyResources.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
import {Badge} from 'sentry/components/core/badge';
22
import {LinkButton} from 'sentry/components/core/button/linkButton';
33
import {IconGithub} from 'sentry/icons';
4-
import type {StoryResources as Resources} from 'sentry/stories/view/useStoriesLoader';
4+
import {
5+
isMDXStory,
6+
type StoryResources as Resources,
7+
} from 'sentry/stories/view/useStoriesLoader';
58
import {useStory} from 'sentry/stories/view/useStory';
69
import {space} from 'sentry/styles/space';
710

811
export function StoryResources() {
912
const {story} = useStory();
10-
if (!story.exports.frontmatter?.resources) {
13+
14+
if (!isMDXStory(story)) {
1115
return null;
1216
}
13-
const resources: Resources = story.exports.frontmatter.resources;
17+
18+
const resources: Resources = story.exports.frontmatter?.resources ?? {};
1419

1520
return (
1621
<table style={{marginTop: space(4)}}>

static/app/stories/view/useStoriesLoader.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,24 @@ interface MDXStoryDescriptor {
2626
source?: string;
2727
types?: string;
2828
};
29-
types?: TypeLoader.ComponentDocWithFilename;
29+
types?:
30+
| TypeLoader.ComponentDocWithFilename
31+
| Record<string, TypeLoader.ComponentDocWithFilename>;
3032
};
3133
filename: string;
3234
}
3335

3436
interface TSStoryDescriptor {
35-
exports: Record<string, React.ComponentType | any>;
37+
exports: Record<string, React.ComponentType | unknown>;
3638
filename: string;
3739
}
3840

3941
export type StoryDescriptor = MDXStoryDescriptor | TSStoryDescriptor;
4042

43+
export function isMDXStory(story: StoryDescriptor): story is MDXStoryDescriptor {
44+
return story.filename.endsWith('.mdx');
45+
}
46+
4147
export function useStoryBookFiles() {
4248
return useMemo(
4349
() =>

0 commit comments

Comments
 (0)