CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/components/copy-to-clipboard.tsx
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { CopyOutlined } from "@ant-design/icons";
7
import { Button, Input, Space, Tooltip } from "antd";
8
import { ReactNode, useEffect, useMemo, useState } from "react";
9
import { CopyToClipboard } from "react-copy-to-clipboard";
10
11
import { CSS } from "@cocalc/frontend/app-framework";
12
13
interface Props {
14
value: string;
15
display?: string;
16
style?: CSS;
17
label?: ReactNode;
18
labelStyle?: CSS;
19
inputStyle?: CSS;
20
outerStyle?: CSS;
21
inputWidth?: string;
22
size?: "large" | "middle" | "small";
23
before?: boolean;
24
}
25
26
const INPUT_STYLE: CSS = { display: "inline-block", flex: 1 } as const;
27
28
const LABEL_STYLE: CSS = {
29
marginRight: "15px",
30
display: "flex",
31
flex: "0 0 auto",
32
justifyContent: "center",
33
alignContent: "center",
34
flexDirection: "column",
35
} as const;
36
37
export default function CopyToClipBoard({
38
value,
39
display,
40
style,
41
size,
42
label,
43
labelStyle,
44
inputStyle,
45
outerStyle,
46
inputWidth,
47
before,
48
}: Props) {
49
const [copied, setCopied] = useState<boolean>(false);
50
51
useEffect(() => {
52
setCopied(false);
53
}, [value]);
54
55
let copy = useMemo(() => {
56
const btn = (
57
<CopyToClipboard text={value} onCopy={() => setCopied(true)}>
58
<Button size={size} icon={<CopyOutlined />} />
59
</CopyToClipboard>
60
);
61
if (!copied) return btn;
62
return (
63
<Tooltip title="Copied!" defaultOpen>
64
{btn}
65
</Tooltip>
66
);
67
}, [value, copied, size]);
68
69
// ws: See https://ant.design/components/input for why using Input.Group is the
70
// right way to do this.
71
// hsy: Input.Group is deprecated, using Space.Compact instead
72
const input = (
73
<Space.Compact style={outerStyle}>
74
{before ? copy : undefined}
75
<Input
76
style={{
77
width: inputWidth ?? `${(display ?? value).length + 8}ex`,
78
fontFamily: "monospace",
79
}}
80
readOnly
81
size={size}
82
value={display ?? value}
83
onFocus={(e) => e.target.select()}
84
/>
85
{!before ? copy : undefined}
86
</Space.Compact>
87
);
88
if (!label) return <div style={style}>{input}</div>;
89
return (
90
<div style={{ display: "flex", ...style }}>
91
<div style={{ ...LABEL_STYLE, ...labelStyle }}>{label}</div>{" "}
92
<div style={{ ...INPUT_STYLE, ...inputStyle }}>{input}</div>
93
</div>
94
);
95
}
96
97