Skip to content

Commit b0b62d6

Browse files
committed
Copy button component
1 parent 2d20cfd commit b0b62d6

File tree

5 files changed

+138
-1
lines changed

5 files changed

+138
-1
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
one line:
2+
3+
```js
4+
const x = 2
5+
```
6+
7+
no editor:
8+
9+
```js
10+
function foo() {
11+
return 2
12+
}
13+
```
14+
15+
one file editor:
16+
17+
```js foo.js
18+
function foo() {
19+
return 2
20+
}
21+
```
22+
23+
two files:
24+
25+
<CH.Code>
26+
27+
```js foo.js
28+
function foo() {
29+
return 2
30+
}
31+
```
32+
33+
```js bar.js
34+
function bar() {
35+
return 2
36+
}
37+
```
38+
39+
</CH.Code>

packages/mdx/src/mini-editor/editor-shift.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
CodeStep,
55
} from "../smooth-code"
66
import React from "react"
7+
import { codeToText } from "utils"
78

89
export type CodeFile = CodeStep & {
910
name: string
@@ -37,6 +38,8 @@ type OutputPanel = {
3738
type Transition = {
3839
northPanel: OutputPanel
3940
southPanel?: OutputPanel | null
41+
northContent: string
42+
southContent: string
4043
}
4144

4245
type TabsSnapshot = Record<
@@ -110,6 +113,7 @@ export function useTransition(
110113
)
111114

112115
return {
116+
northContent: getContentFromFile(nextNorthFile),
113117
northPanel: {
114118
tabs: northTabs,
115119
style: northStyle,
@@ -126,6 +130,7 @@ export function useTransition(
126130
/>
127131
),
128132
},
133+
southContent: getContentFromFile(nextSouthFile),
129134
southPanel: inputSouthPanel && {
130135
tabs: southTabs!,
131136
style: southStyle!,
@@ -162,6 +167,7 @@ function startingPosition(
162167
} = getStepFiles(prev, next, true)
163168

164169
return {
170+
northContent: getContentFromFile(prevNorthFile),
165171
northPanel: {
166172
tabs: inputNorthPanel.tabs.map(title => ({
167173
title,
@@ -182,6 +188,7 @@ function startingPosition(
182188
/>
183189
),
184190
},
191+
southContent: getContentFromFile(prevSouthFile),
185192
southPanel: inputSouthPanel && {
186193
tabs: inputSouthPanel.tabs.map(title => ({
187194
title,
@@ -229,6 +236,7 @@ function endingPosition(
229236
}
230237

231238
return {
239+
northContent: getContentFromFile(nextNorthFile),
232240
northPanel: {
233241
tabs: inputNorthPanel.tabs.map(title => ({
234242
title,
@@ -249,6 +257,7 @@ function endingPosition(
249257
/>
250258
),
251259
},
260+
southContent: getContentFromFile(nextSouthFile),
252261
southPanel: inputSouthPanel && {
253262
tabs: inputSouthPanel.tabs.map(title => ({
254263
title,
@@ -305,6 +314,10 @@ function CodeTransition({
305314
)
306315
}
307316

317+
function getContentFromFile(file?: CodeFile) {
318+
return file ? codeToText(file.code) : ""
319+
}
320+
308321
/**
309322
* Get the StepFiles for a transition
310323
* in each panel, if the prev and next active files are the same

packages/mdx/src/mini-editor/editor-tween.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { TerminalPanel } from "./terminal-panel"
77
import { useTransition, EditorStep } from "./editor-shift"
88
import { CodeConfig } from "../smooth-code"
99
import { useLayoutEffect } from "../utils"
10+
import { CopyButton } from "smooth-code/copy-button"
1011

1112
export { EditorTransition, EditorTween }
1213
export type { EditorTransitionProps, EditorTweenProps }
@@ -53,7 +54,12 @@ function EditorTween({
5354
...divProps
5455
}: EditorTweenProps) {
5556
const ref = React.createRef<HTMLDivElement>()
56-
const { northPanel, southPanel } = useTransition(
57+
const {
58+
northPanel,
59+
southPanel,
60+
northContent,
61+
southContent,
62+
} = useTransition(
5763
ref,
5864
prev,
5965
next || prev,
@@ -102,6 +108,8 @@ function EditorTween({
102108
southPanel={southPanel}
103109
terminalPanel={terminalPanel}
104110
theme={codeConfig.theme}
111+
// TODO same for south
112+
button={<CopyButton content={northContent} />}
105113
/>
106114
)
107115
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
export function CopyButton({
2+
content,
3+
}: {
4+
content: string
5+
}) {
6+
return (
7+
<svg
8+
style={{
9+
width: "1.5em",
10+
height: "1.5em",
11+
margin: "0 0.8em",
12+
cursor: "pointer",
13+
}}
14+
onClick={() => copyToClipboard(content)}
15+
fill="none"
16+
stroke="currentColor"
17+
viewBox="0 0 24 24"
18+
xmlns="http://www.w3.org/2000/svg"
19+
>
20+
<path
21+
strokeLinecap="round"
22+
strokeLinejoin="round"
23+
strokeWidth="2"
24+
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
25+
></path>
26+
</svg>
27+
)
28+
}
29+
30+
function copyToClipboard(text: string) {
31+
if (!navigator.clipboard) {
32+
fallbackCopyTextToClipboard(text)
33+
return
34+
}
35+
navigator.clipboard.writeText(text).then(
36+
function () {
37+
console.log(
38+
"Async: Copying to clipboard was successful!"
39+
)
40+
},
41+
function (err) {
42+
console.error("Async: Could not copy text: ", err)
43+
}
44+
)
45+
}
46+
47+
function fallbackCopyTextToClipboard(text: string) {
48+
var textArea = document.createElement("textarea")
49+
textArea.value = text
50+
51+
// Avoid scrolling to bottom
52+
textArea.style.top = "0"
53+
textArea.style.left = "0"
54+
textArea.style.position = "fixed"
55+
56+
document.body.appendChild(textArea)
57+
textArea.focus()
58+
textArea.select()
59+
60+
try {
61+
var successful = document.execCommand("copy")
62+
var msg = successful ? "successful" : "unsuccessful"
63+
console.log("Fallback: Copying text command was " + msg)
64+
} catch (err) {
65+
console.error("Fallback: Oops, unable to copy", err)
66+
}
67+
68+
document.body.removeChild(textArea)
69+
}

packages/mdx/src/utils/code.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,11 @@ export type Code = {
1111
lines: HighlightedLine[]
1212
lang: string
1313
}
14+
15+
export function codeToText(code: Code) {
16+
return code.lines
17+
.map(line =>
18+
line.tokens.map(token => token.content).join("")
19+
)
20+
.join("\n")
21+
}

0 commit comments

Comments
 (0)