Skip to content

Commit 258ca99

Browse files
authored
feat(stories): new docs system (#94005)
This PR is the base branch for a number of related PRs that upgrade our stories layout and design system documentation. Closes DE-162. [Deploy Preview](https://sentry-git-ui2-nmdocs-new.sentry.dev/stories/?name=app%2Fcomponents%2Fcore%2Fbutton%2Findex.mdx&query=button) ## Stacked PRs - #94006 - #94008 - #94009 - #94007 - #94744 - #94989
1 parent aa14ddb commit 258ca99

25 files changed

+1729
-380
lines changed

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@mdx-js/loader": "^3.1.0",
2828
"@mdx-js/mdx": "^3.1.0",
2929
"@popperjs/core": "^2.11.5",
30+
"@r4ai/remark-callout": "^0.6.2",
3031
"@react-aria/button": "^3.13.1",
3132
"@react-aria/combobox": "^3.12.3",
3233
"@react-aria/focus": "^3.20.3",
@@ -163,6 +164,10 @@
163164
"react-textarea-autosize": "8.5.7",
164165
"react-virtualized": "^9.22.6",
165166
"reflux": "0.4.1",
167+
"rehype-expressive-code": "^0.41.2",
168+
"remark-frontmatter": "^5.0.0",
169+
"remark-gfm": "^4.0.1",
170+
"remark-mdx-frontmatter": "^5.2.0",
166171
"screenfull": "^6.0.2",
167172
"scroll-to-element": "^2.0.0",
168173
"sprintf-js": "1.0.3",

pnpm-lock.yaml

Lines changed: 592 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rspack.config.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-env node */
22
/* eslint import/no-nodejs-modules:0 */
3-
3+
import remarkCallout from '@r4ai/remark-callout';
44
import {RsdoctorRspackPlugin} from '@rsdoctor/rspack-plugin';
55
import type {
66
Configuration,
@@ -16,6 +16,10 @@ import HtmlWebpackPlugin from 'html-webpack-plugin';
1616
import fs from 'node:fs';
1717
import {createRequire} from 'node:module';
1818
import path from 'node:path';
19+
import rehypeExpressiveCode from 'rehype-expressive-code';
20+
import remarkFrontmatter from 'remark-frontmatter';
21+
import remarkGfm from 'remark-gfm';
22+
import remarkMdxFrontmatter from 'remark-mdx-frontmatter';
1923
import {TsCheckerRspackPlugin} from 'ts-checker-rspack-plugin';
2024

2125
// @ts-expect-error: ts(5097) importing `.ts` extension is required for resolution, but not enabled until `allowImportingTsExtensions` is added to tsconfig
@@ -290,6 +294,15 @@ const appConfig: Configuration = {
290294
},
291295
{
292296
loader: '@mdx-js/loader',
297+
options: {
298+
remarkPlugins: [
299+
remarkFrontmatter,
300+
remarkMdxFrontmatter,
301+
remarkGfm,
302+
remarkCallout,
303+
],
304+
rehypePlugins: [rehypeExpressiveCode],
305+
},
293306
},
294307
],
295308
},
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
---
2+
title: Button
3+
description: Buttons are clickable elements that trigger an action that does not change the current URL.
4+
source: 'sentry/components/core/button'
5+
resources:
6+
figma: https://www.figma.com/design/eTJz6aPgudMY9E6mzyZU0B/ChonkUI--App-Components--WIP-?node-id=384-2119&t=DdXZ7WIgTdURJlRv-4
7+
js: https://github.com/getsentry/sentry/blob/481d8d642e9cf549eb46fbaac1d0527395e8b490/static/app/components/core/button/index.tsx#L22
8+
a11y:
9+
WCAG 1.4.3: https://www.w3.org/TR/WCAG22/#contrast-minimum
10+
WCAG 2.1.1: https://www.w3.org/TR/WCAG22/#keyboard
11+
WCAG 2.4.7: https://www.w3.org/TR/WCAG22/#focus-visible
12+
WCAG 2.5.8: https://www.w3.org/TR/WCAG22/#target-size-minimum
13+
WAI-ARIA Button Practices: https://www.w3.org/WAI/ARIA/apg/patterns/button/
14+
next:
15+
link: '/stories/?name=app%2Fcomponents%2Fcore%2Fbutton%2FbuttonBar.stories.tsx'
16+
label: ButtonBar
17+
prev:
18+
link: '?name=app%2Fcomponents%2Fcore%2Fbadge%2Ftag.stories.tsx'
19+
label: Tag
20+
---
21+
22+
import {Button} from 'sentry/components/core/button';
23+
import {
24+
IconAdd,
25+
IconArrow,
26+
IconChevron,
27+
IconClock,
28+
IconClose,
29+
IconDelete,
30+
IconDocs,
31+
IconEdit,
32+
IconEllipsis,
33+
IconLightning,
34+
IconLink,
35+
IconOpen,
36+
IconStar,
37+
IconZoom,
38+
} from 'sentry/icons';
39+
import * as Storybook from 'sentry/stories';
40+
41+
import types from '!!type-loader!sentry/components/core/button/index';
42+
43+
export {types};
44+
45+
To create a basic button, wrap text in a `<Button>` and pass an `onClick` callback.
46+
47+
```jsx
48+
<Button onClick={() => alert('Hello world')}>Click here</Button>
49+
```
50+
51+
### Priorities
52+
53+
Buttons come in a few different styles: `muted` (default), `primary`, `warning`, `danger`, and `transparent`.
54+
55+
<Storybook.Demo>
56+
<Button priority="muted">Muted (default)</Button>
57+
<Button priority="primary">Primary</Button>
58+
<Button priority="warning">Warning</Button>
59+
<Button priority="danger">Danger</Button>
60+
<Button priority="transparent">Transparent</Button>
61+
</Storybook.Demo>
62+
```jsx
63+
<Button priority="muted">Muted (default)</Button>
64+
<Button priority="primary">Primary</Button>
65+
<Button priority="warning">Warning</Button>
66+
<Button priority="danger">Danger</Button>
67+
<Button priority="transparent">Transparent</Button>
68+
```
69+
70+
### Sizes
71+
72+
Buttons are available in different sizes: `md` (default), `sm`, `xs`, and `zero`.
73+
74+
<Storybook.Demo>
75+
<Button size="md">Medium (default)</Button>
76+
<Button size="sm">Small</Button>
77+
<Button size="xs">Extra small</Button>
78+
<Button size="zero">Zero</Button>
79+
</Storybook.Demo>
80+
```jsx
81+
<Button size="md">Medium (default)</Button>
82+
<Button size="sm">Small</Button>
83+
<Button size="xs">Extra small</Button>
84+
<Button size="zero">Zero</Button>
85+
```
86+
87+
### Icons
88+
89+
Buttons support an optional leading icon.
90+
91+
<Storybook.Demo>
92+
<Button icon={<IconAdd />} priority="primary">
93+
Add
94+
</Button>
95+
</Storybook.Demo>
96+
```jsx
97+
<Button icon={<IconAdd />} priority="primary">
98+
Add
99+
</Button>
100+
```
101+
102+
We have standardized call to action copy and specific icon pairings. When creating an icon button, please use a pairing from the following list.
103+
104+
| Icon | Name | Copy | Meaning |
105+
| ------------------------------------------ | ----------- | -------------------------------------- | --------------------------------------------------------- |
106+
| <IconAdd /> | `add` | Create | Spawn something from nothing |
107+
| <IconAdd /> | `add` | Add | Append another thing in the group |
108+
| <IconDelete /> | `trash` | Delete | Destroy thing in the group |
109+
| | | Manage | Broader meaning, includes bulk order, add, remove, etc. |
110+
| <IconEdit /> | `edit` | Edit | Modifies fundamental attribute of the thing |
111+
| <IconOpen /> | `open` | Open in `Product` | Leaves existing view and goes to another product |
112+
| <IconClose /> | `close` | Close | Potentially reopen this again later |
113+
| <IconDocs /> | `docs` | Read Docs | Similar to “Open In” but always goes to Sentry Docs |
114+
| <IconEllipsis /> | `ellipses` | More `Samples` | See more of the same thing |
115+
| | Show More | Accordions down to reveal more content |
116+
| <IconChevron direction="up" /> | `chevron` | Expand | Content is completely hidden except for title |
117+
| <IconChevron direction='down' /> | `chevron` | Collapse | Content is completely shown and need to hide except title |
118+
| <IconChevron isDouble direction="left" /> | `chevron` | Expand | Content is completely hidden (depends on direction) |
119+
| <IconChevron isDouble direction="right" /> | `chevron` | Collapse | Content is completely shown (depends on direction) |
120+
| | | Dismiss | Get rid of forever |
121+
| <IconClock /> | `clock` | Remind Me Later | Get rid of temporarily |
122+
| <IconArrow /> | `arrow` | Back | Go to previous screen |
123+
| <IconLightning /> | `lightning` | Upgrade | Upgrade to Business Plan |
124+
| | | Save `Item` | Preserve changes |
125+
| <IconClose /> | `close` | Cancel | Exit without saving changes |
126+
| <IconLink /> | `link` | Share | Copies link to paste anywhere |
127+
| | | Connect | Create link between two objects |
128+
| | | Disconnect | Break link between two objects |
129+
| <IconZoom isZoomIn /> | `zoom` | Zoom In | Applies to charts and zooms to fit |
130+
| <IconZoom /> | `zoom` | Zoom Out | Applies to charts and zooms out (i.e. 200%) |
131+
| <IconStar /> | `star` | Favorite | Hoisting item to primary view |
132+
133+
### Icon-only Buttons
134+
135+
In scenarios where high information density is critical, buttons may be displayed without text.
136+
137+
> [!WARNING]
138+
> Buttons with icons and no `children` **must** include a `label` for screen readers!
139+
140+
<Storybook.Demo>
141+
<Button icon={<IconAdd />} label="Add" />
142+
</Storybook.Demo>
143+
```jsx
144+
<Button icon={<IconAdd />} label="Add" />
145+
```
146+
147+
### Accessibility
148+
149+
To meet WCAG 2.2 AA compliance, `<Button>` automatically meets the [WCAG 1.4.3](https://www.w3.org/TR/WCAG22/#contrast-minimum), [WCAG 2.1.1](https://www.w3.org/TR/WCAG22/#keyboard), [WCAG 2.4.7](https://www.w3.org/TR/WCAG22/#focus-visible), [WCAG 2.5.8](https://www.w3.org/TR/WCAG22/#target-size-minimum) success criteria.
150+
151+
Developers should take care to ensure that their implementations additionally follow the [WAI-ARIA Button Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/button/) and properly handle focus changes when an action is triggered.

static/app/components/core/button/index.stories.tsx

Lines changed: 0 additions & 47 deletions
This file was deleted.

static/app/components/core/button/styles.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const getBoxShadow = ({
2727
}
2828

2929
const themeName = disabled ? 'disabled' : priority || 'default';
30-
const {borderTranslucent} = theme.button[themeName];
30+
const {borderTranslucent} = theme.button[themeName] ?? theme.button.default;
3131
const translucentBorderString = translucentBorder
3232
? `0 0 0 1px ${borderTranslucent},`
3333
: '';
@@ -51,7 +51,7 @@ const getColors = ({
5151
}: (ButtonProps | LinkButtonProps) & {theme: Theme}): SerializedStyles => {
5252
const themeName = disabled ? 'disabled' : priority || 'default';
5353
const {color, colorActive, background, border, borderActive, focusBorder, focusShadow} =
54-
theme.button[themeName];
54+
theme.button[themeName] ?? theme.button.default;
5555

5656
const getFocusState = (): SerializedStyles => {
5757
switch (priority) {

static/app/stories/apiReference.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ export function APIReference(props: APIReferenceProps) {
2121

2222
return (
2323
<Storybook.Section>
24-
<Storybook.Title>API Reference</Storybook.Title>
25-
<p>{props.types?.description}</p>
24+
{props.types?.description && <p>{props.types.description}</p>}
2625
<StoryTypesSearchContainer>
2726
<InputGroup>
2827
<InputGroup.LeadingItems disablePointerEvents>

static/app/stories/demo.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import styled from '@emotion/styled';
2+
3+
import {space} from 'sentry/styles/space';
4+
5+
export const Demo = styled('div')`
6+
margin-top: 8px;
7+
margin-bottom: -16px;
8+
width: 100%;
9+
background: ${p => p.theme.tokens.background.secondary};
10+
border: 1px solid ${p => p.theme.tokens.border.primary};
11+
border-bottom: 0;
12+
display: flex;
13+
align-items: flex-end;
14+
justify-content: center;
15+
gap: ${space(1)};
16+
padding: 64px 16px;
17+
min-height: 160px;
18+
max-height: 512px;
19+
border-radius: ${p => p.theme.borderRadius} ${p => p.theme.borderRadius} 0 0;
20+
box-shadow: inset 0 0 0 1px ${p => p.theme.tokens.background.tertiary};
21+
`;

static/app/stories/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export {PropMatrix} from './props';
33
export {Section, Title} from './layout';
44
export {SideBySide} from './layout';
55
export {SizingWindow, Grid} from './layout';
6+
export {Demo} from './demo';
67
export {story} from './storybook';
78
export {ThemeSwitcher, ThemeToggle} from './theme';
89
export {APIReference} from './apiReference';

static/app/stories/layout.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,14 @@ export const SizingWindow = styled(NegativeSpaceContainer)<{display?: 'block' |
3030
`;
3131

3232
export const Section = styled('section')`
33-
padding-top: ${space(2)};
33+
padding-top: ${space(4)};
34+
display: flex;
35+
flex-direction: column;
36+
gap: ${space(2)};
3437
`;
3538

36-
export const Title = styled('h2')`
39+
export const Title = styled('h3')`
3740
margin: 0;
3841
scroll-margin-top: ${space(2)};
42+
border-bottom: 1px solid ${p => p.theme.border};
3943
`;

0 commit comments

Comments
 (0)