Skip to content

Commit 4eacaf8

Browse files
feat(stories): add story for CodeSnippet (#68955)
1 parent b356c5a commit 4eacaf8

File tree

2 files changed

+228
-2
lines changed

2 files changed

+228
-2
lines changed
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
import {Fragment, useState} from 'react';
2+
3+
import {addSuccessMessage} from 'sentry/actionCreators/indicator';
4+
import {CodeSnippet} from 'sentry/components/codeSnippet';
5+
import JSXNode from 'sentry/components/stories/jsxNode';
6+
import JSXProperty from 'sentry/components/stories/jsxProperty';
7+
import {IconStar} from 'sentry/icons';
8+
import storyBook from 'sentry/stories/storyBook';
9+
10+
export default storyBook(CodeSnippet, story => {
11+
story('Defaults', () => (
12+
<Fragment>
13+
<p>
14+
The <JSXNode name="CodeSnippet" /> component is useful when you want to render
15+
code instructions in onboarding or other setup situations. By default, the code
16+
snippet is able to be copied, selected, and has rounded corners and shows in light
17+
mode. It'll also apply formatting automatically, if the language (passed in with
18+
the <JSXProperty name="language" value={String} />
19+
prop) is known.
20+
</p>
21+
22+
<p>JavaScript example:</p>
23+
<CodeSnippet language="javascript">{`Sentry.init({
24+
// Note, Replay is NOT instantiated below:
25+
integrations: [],
26+
});
27+
28+
// Sometime later
29+
const { replayIntegration } = await import("@sentry/browser");
30+
Sentry.addIntegration(replayIntegration());`}</CodeSnippet>
31+
32+
<p>Python example:</p>
33+
<CodeSnippet language="python">{`sentry_sdk.metrics.incr(
34+
key="button_click",
35+
value=1,
36+
tags={
37+
"browser": "Firefox",
38+
"app_version": "1.0.0"
39+
}
40+
)`}</CodeSnippet>
41+
</Fragment>
42+
));
43+
44+
story('Props', () => {
45+
const [tab, setTab] = useState('npm');
46+
47+
return (
48+
<Fragment>
49+
<p>
50+
You can customize the display of the <JSXNode name="CodeSnippet" />:
51+
</p>
52+
53+
<h2>
54+
<JSXProperty name="dark" value />
55+
</h2>
56+
<CodeSnippet dark language="javascript">{`Sentry.init({
57+
// Note, Replay is NOT instantiated below:
58+
integrations: [],
59+
});
60+
61+
// Sometime later
62+
const { replayIntegration } = await import("@sentry/browser");
63+
Sentry.addIntegration(replayIntegration());`}</CodeSnippet>
64+
<br />
65+
<h2>with tabs</h2>
66+
<CodeSnippet
67+
tabs={[
68+
{label: 'npm', value: 'npm'},
69+
{label: 'Yarn', value: 'yarn'},
70+
]}
71+
selectedTab={tab}
72+
onTabClick={t => setTab(t)}
73+
language="javascript"
74+
>
75+
{tab === 'npm'
76+
? `npm install --save @sentry/browser`
77+
: 'yarn add @sentry/browser'}
78+
</CodeSnippet>
79+
<br />
80+
<h2>
81+
<JSXProperty name="isRounded" value={false} />
82+
</h2>
83+
<CodeSnippet isRounded={false} dark language="javascript">{`Sentry.init({
84+
// Note, Replay is NOT instantiated below:
85+
integrations: [],
86+
});
87+
88+
// Sometime later
89+
const { replayIntegration } = await import("@sentry/browser");
90+
Sentry.addIntegration(replayIntegration());`}</CodeSnippet>
91+
<br />
92+
<h2>
93+
<JSXProperty name="hideCopyButton" value />
94+
</h2>
95+
<CodeSnippet hideCopyButton language="javascript">{`Sentry.init({
96+
// Note, Replay is NOT instantiated below:
97+
integrations: [],
98+
});
99+
100+
// Sometime later
101+
const { replayIntegration } = await import("@sentry/browser");
102+
Sentry.addIntegration(replayIntegration());`}</CodeSnippet>
103+
<br />
104+
<h2>
105+
<JSXProperty name="disableUserSelection" value />
106+
</h2>
107+
<CodeSnippet disableUserSelection language="javascript">{`Sentry.init({
108+
// Note, Replay is NOT instantiated below:
109+
integrations: [],
110+
});
111+
112+
// Sometime later
113+
const { replayIntegration } = await import("@sentry/browser");
114+
Sentry.addIntegration(replayIntegration());`}</CodeSnippet>
115+
<br />
116+
<h2>
117+
<JSXProperty name="filename" value="index.jsx" />
118+
</h2>
119+
<CodeSnippet filename={'index.jsx'} language="javascript">{`Sentry.init({
120+
// Note, Replay is NOT instantiated below:
121+
integrations: [],
122+
});
123+
124+
// Sometime later
125+
const { replayIntegration } = await import("@sentry/browser");
126+
Sentry.addIntegration(replayIntegration());`}</CodeSnippet>
127+
<br />
128+
<h2>
129+
<JSXProperty name="icon" value />
130+
</h2>
131+
<CodeSnippet icon={<IconStar />} language="javascript">{`Sentry.init({
132+
// Note, Replay is NOT instantiated below:
133+
integrations: [],
134+
});
135+
136+
// Sometime later
137+
const { replayIntegration } = await import("@sentry/browser");
138+
Sentry.addIntegration(replayIntegration());`}</CodeSnippet>
139+
</Fragment>
140+
);
141+
});
142+
143+
story('Callbacks', () => {
144+
const [tab, setTab] = useState('npm');
145+
const onCopy = () => addSuccessMessage('Copied!');
146+
const onSelectAndCopy = () =>
147+
addSuccessMessage(
148+
'Copied...but you know you can just press the copy button to copy it all, right?'
149+
);
150+
const onTabClick = () => addSuccessMessage('Clicked a different tab');
151+
152+
return (
153+
<Fragment>
154+
<p>
155+
You can customize what happens when the user clicks the copy button, after the
156+
user highlights a part of the code snippet, after the user selects and manually
157+
copies the code snippet, or when a tab is clicked by specifying the callback.
158+
</p>
159+
<h2>
160+
<JSXProperty name="onCopy" value />
161+
</h2>
162+
<p>Try pressing the copy button:</p>
163+
<CodeSnippet onCopy={onCopy} language="javascript">{`Sentry.init({
164+
// Note, Replay is NOT instantiated below:
165+
integrations: [],
166+
});
167+
168+
// Sometime later
169+
const { replayIntegration } = await import("@sentry/browser");
170+
Sentry.addIntegration(replayIntegration());`}</CodeSnippet>
171+
<br />
172+
<h2>
173+
<JSXProperty name="onSelectAndCopy" value />
174+
</h2>
175+
<p>Try manually selecting and copying code:</p>
176+
<CodeSnippet
177+
onSelectAndCopy={onSelectAndCopy}
178+
language="javascript"
179+
>{`Sentry.init({
180+
// Note, Replay is NOT instantiated below:
181+
integrations: [],
182+
});
183+
184+
// Sometime later
185+
const { replayIntegration } = await import("@sentry/browser");
186+
Sentry.addIntegration(replayIntegration());`}</CodeSnippet>
187+
<br />
188+
<h2>
189+
<JSXProperty name="onTabClick" value />
190+
</h2>
191+
<p>Try switching tabs:</p>
192+
<CodeSnippet
193+
tabs={[
194+
{label: 'npm', value: 'npm'},
195+
{label: 'Yarn', value: 'yarn'},
196+
]}
197+
selectedTab={tab}
198+
onTabClick={t => {
199+
setTab(t);
200+
onTabClick();
201+
}}
202+
language="javascript"
203+
>
204+
{tab === 'npm'
205+
? `npm install --save @sentry/browser`
206+
: 'yarn add @sentry/browser'}
207+
</CodeSnippet>{' '}
208+
</Fragment>
209+
);
210+
});
211+
});

static/app/components/codeSnippet.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,21 @@ interface CodeSnippetProps {
1616
['data-render-inline']?: boolean;
1717
/**
1818
* Makes the text of the element and its sub-elements not selectable.
19-
* Userful when loading parts of a code snippet, and
19+
* Useful when loading parts of a code snippet, and
2020
* we wish to avoid users copying them manually.
2121
*/
2222
disableUserSelection?: boolean;
23+
/**
24+
* Name of the file to be displayed at the top of the code snippet.
25+
*/
2326
filename?: string;
27+
/**
28+
* Hides the copy button in the top right.
29+
*/
2430
hideCopyButton?: boolean;
31+
/**
32+
* Adds an icon to the top right, next to the copy button.
33+
*/
2534
icon?: React.ReactNode;
2635
/**
2736
* Controls whether the snippet wrapper has rounded corners.
@@ -33,11 +42,17 @@ interface CodeSnippetProps {
3342
* @param element The root element of the code snippet
3443
*/
3544
onAfterHighlight?: (element: HTMLElement) => void;
45+
/**
46+
* Fires with the user presses the copy button.
47+
*/
3648
onCopy?: (copiedCode: string) => void;
3749
/**
38-
* Fired when the user selects and copies code snippet manually
50+
* Fires when the user selects and copies code snippet manually
3951
*/
4052
onSelectAndCopy?: () => void;
53+
/**
54+
* Fires when the user switches tabs.
55+
*/
4156
onTabClick?: (tab: string) => void;
4257
selectedTab?: string;
4358
tabs?: {

0 commit comments

Comments
 (0)