@arcblock/ux 1.16.1 → 1.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/package.json +6 -5
  2. package/src/ActionButton/index.js +65 -0
  3. package/src/ActivityIndicator/index.js +186 -0
  4. package/src/Alert/index.js +104 -0
  5. package/src/Async/index.js +39 -0
  6. package/src/Badge/index.js +71 -0
  7. package/src/Blocklet/index.js +335 -0
  8. package/src/Button/index.js +4 -0
  9. package/src/Button/wrap.js +88 -0
  10. package/src/ButtonGroup/index.js +19 -0
  11. package/src/Center/index.js +17 -0
  12. package/src/ClickToCopy/index.js +90 -0
  13. package/src/CodeBlock/index.js +151 -0
  14. package/src/Colors/index.js +1 -0
  15. package/src/Colors/themes/default.js +53 -0
  16. package/src/ContactForm/index.js +240 -0
  17. package/src/CookieConsent/index.js +90 -0
  18. package/src/CountDown/index.js +151 -0
  19. package/src/Dialog/confirm.js +76 -0
  20. package/src/Dialog/dialog.js +162 -0
  21. package/src/Dialog/index.js +2 -0
  22. package/src/DriftBot/index.js +81 -0
  23. package/src/Earth/countries.json +8057 -0
  24. package/src/Earth/index.js +511 -0
  25. package/src/Earth/util.js +69 -0
  26. package/src/Empty/index.js +41 -0
  27. package/src/Footer/index.js +84 -0
  28. package/src/Icon/image.js +55 -0
  29. package/src/Icon/index.js +69 -0
  30. package/src/Img/index.js +172 -0
  31. package/src/InfoRow/index.js +83 -0
  32. package/src/Layout/dashboard/header.js +145 -0
  33. package/src/Layout/dashboard/index.js +140 -0
  34. package/src/Layout/dashboard/sidebar.js +120 -0
  35. package/src/Layout/index.js +318 -0
  36. package/src/Locale/browser-lang.js +63 -0
  37. package/src/Locale/context.js +88 -0
  38. package/src/Locale/images/globe-dark.png +0 -0
  39. package/src/Locale/images/globe-light.png +0 -0
  40. package/src/Locale/selector.js +138 -0
  41. package/src/Logo/images/logo-dark-text.svg +3 -0
  42. package/src/Logo/images/logo-dark-top.svg +6 -0
  43. package/src/Logo/images/logo-light-text.svg +3 -0
  44. package/src/Logo/images/logo-light-top.svg +6 -0
  45. package/src/Logo/index.js +47 -0
  46. package/src/Metric/index.js +115 -0
  47. package/src/NFTDisplay/README.md +59 -0
  48. package/src/NFTDisplay/aspect-ratio-container.js +34 -0
  49. package/src/NFTDisplay/broken.js +18 -0
  50. package/src/NFTDisplay/index.js +230 -0
  51. package/src/NFTDisplay/loading.js +17 -0
  52. package/src/NFTDisplay/svg-embedder/img.js +36 -0
  53. package/src/NFTDisplay/svg-embedder/inline-svg.js +37 -0
  54. package/src/PageScroller/index.js +342 -0
  55. package/src/PageScroller/usePrevValue.js +12 -0
  56. package/src/PricingTable/PricingPlan.js +112 -0
  57. package/src/PricingTable/index.js +43 -0
  58. package/src/Screenshot/devices.css +1366 -0
  59. package/src/Screenshot/index.js +181 -0
  60. package/src/Spinner/index.js +33 -0
  61. package/src/Switch/index.js +78 -0
  62. package/src/Tabs/index.js +46 -0
  63. package/src/Tag/index.js +73 -0
  64. package/src/Terminal/Player.js +364 -0
  65. package/src/Terminal/index.js +150 -0
  66. package/src/Terminal/player.css +378 -0
  67. package/src/Terminal/util.js +167 -0
  68. package/src/Terminal/xterm.css +171 -0
  69. package/src/TextCollapse/index.js +92 -0
  70. package/src/Theme/index.js +169 -0
  71. package/src/Theme/responsiveFontSizes.js +94 -0
  72. package/src/Toast/index.js +118 -0
  73. package/src/Util/index.js +264 -0
  74. package/src/Video/index.js +72 -0
  75. package/src/Wallet/Action.js +105 -0
  76. package/src/Wallet/Download.js +130 -0
  77. package/src/Wallet/Open.js +50 -0
  78. package/src/Wallet/images/abtwallet.png +0 -0
  79. package/src/Wallet/images/android_download.svg +23 -0
  80. package/src/Wallet/images/app-store.svg +20 -0
  81. package/src/Wallet/images/google-play.svg +70 -0
  82. package/src/WechatPrompt/images/android.png +0 -0
  83. package/src/WechatPrompt/images/ios.png +0 -0
  84. package/src/WechatPrompt/index.js +81 -0
  85. package/src/index.js +63 -0
  86. package/src/withTheme/index.js +72 -0
  87. package/src/withTracker/README.md +34 -0
  88. package/src/withTracker/error_boundary.js +34 -0
  89. package/src/withTracker/index.js +70 -0
@@ -0,0 +1,335 @@
1
+ import React, { useRef } from 'react';
2
+ import styled from 'styled-components';
3
+ import PropTypes from 'prop-types';
4
+ import Portal from '@material-ui/core/Portal';
5
+ import Typography from '@material-ui/core/Typography';
6
+ import CircularProgress from '@material-ui/core/CircularProgress';
7
+ import useMediaQuery from '@material-ui/core/useMediaQuery';
8
+ import useTheme from '@material-ui/core/styles/useTheme';
9
+
10
+ import Icon from '../Icon';
11
+ import Button from '../Button';
12
+ import Img from '../Img';
13
+
14
+ const Div = styled.div`
15
+ &.arcblock-blocklet {
16
+ border: 1px solid #f2f2f2;
17
+ padding: 0 16px;
18
+ border-radius: 12px;
19
+ background: #fff;
20
+ overflow: hidden;
21
+ &:hover {
22
+ filter: drop-shadow(0px 4px 12px rgba(92, 92, 92, 0.04));
23
+ }
24
+ }
25
+ .arcblock-blocklet__content {
26
+ padding: 16px 0;
27
+ }
28
+
29
+ .arcblock-blocklet__content--main {
30
+ display: flex;
31
+ align-items: center;
32
+ cursor: pointer;
33
+ }
34
+ .arcblock-blocklet__content--body {
35
+ overflow: hidden;
36
+ flex: 1;
37
+ display: flex;
38
+ align-items: flex-start;
39
+ }
40
+ .arcblock-blocklet__addons {
41
+ padding: 16px 0;
42
+ border-top: 1px solid #f2f2f2;
43
+ }
44
+ .arcblock-blocklet__cover {
45
+ width: 100px;
46
+ height: 100px;
47
+ margin-right: 16px;
48
+ overflow: hidden;
49
+ border-radius: 12px;
50
+ }
51
+
52
+ .arcblock-blocklet__info {
53
+ flex: 1;
54
+ overflow: hidden;
55
+ .arcblock-blocklet__button {
56
+ margin-top: 16px;
57
+ display: inline-block;
58
+ }
59
+ }
60
+ .arcblock-blocklet__button {
61
+ & > * {
62
+ position: relative;
63
+ &::before {
64
+ content: '';
65
+ position: absolute;
66
+ display: block;
67
+ left: 50%;
68
+ top: 50%;
69
+ height: ${props => props.scaleClickZone * 100}%;
70
+ width: ${props => props.scaleClickZone * 100}%;
71
+ transform: translate(-50%, -50%);
72
+ }
73
+ }
74
+ & > *:not(.Mui-disabled) {
75
+ background-color: rgba(79, 106, 246, 0.06);
76
+ color: ${props => props.theme.palette.primary.main};
77
+ }
78
+ }
79
+ .arcblock-blocklet__title {
80
+ margin: 0;
81
+ font-size: 18px;
82
+ font-weight: 600;
83
+ overflow: hidden;
84
+ text-overflow: ellipsis;
85
+ white-space: nowrap;
86
+ }
87
+ .arcblock-blocklet__describe {
88
+ margin: 2px 0 0;
89
+ color: #999;
90
+ font-size: 14px;
91
+ overflow: hidden;
92
+ text-overflow: ellipsis;
93
+ white-space: nowrap;
94
+ }
95
+
96
+ .arcblock-blocklet__addons {
97
+ display: flex;
98
+ justify-content: space-between;
99
+ color: #999;
100
+ font-size: 14px;
101
+ position: relative;
102
+ }
103
+ .arcblock-blocklet__addons--item {
104
+ white-space: nowrap;
105
+ }
106
+
107
+ &.arcblock-blocklet--size-md {
108
+ &:hover {
109
+ position: relative;
110
+ }
111
+ .arcblock-blocklet__title {
112
+ margin-bottom: 3px;
113
+ }
114
+ .arcblock-blocklet__describe {
115
+ white-space: normal;
116
+ height: 2.86em;
117
+ }
118
+ .arcblock-blocklet__button {
119
+ margin-top: 5px;
120
+ }
121
+ }
122
+ &.arcblock-blocklet--size-sm,
123
+ &.arcblock-blocklet--size-xs {
124
+ .arcblock-blocklet__content {
125
+ padding: 12px 0;
126
+ }
127
+ .arcblock-blocklet__cover {
128
+ width: 48px;
129
+ height: 48px;
130
+ border-radius: 6px;
131
+ }
132
+ .arcblock-blocklet__addons {
133
+ padding: 8px 0;
134
+ .arcblock-blocklet__addons--item {
135
+ font-size: 12px;
136
+ }
137
+ }
138
+ }
139
+ &.arcblock-blocklet--size-xs {
140
+ .arcblock-blocklet__addons {
141
+ display: none !important;
142
+ }
143
+ }
144
+ `;
145
+
146
+ function BlockletIcon({ name }) {
147
+ return <Icon name={name} color="inherit" size={15} style={{ marginRight: 8 }} />;
148
+ }
149
+ BlockletIcon.propTypes = {
150
+ name: PropTypes.string.isRequired,
151
+ };
152
+
153
+ function prettySize(_size) {
154
+ let size = _size;
155
+ const list = ['', 'k', 'm', 'b'];
156
+ let index = 0;
157
+ while (size > 1000 && index < list.length - 1) {
158
+ size = (size / 1000).toFixed(1);
159
+ index += 1;
160
+ }
161
+ return _size && `${size}${list[index]}`;
162
+ }
163
+
164
+ export default function Blocklet({
165
+ title,
166
+ description,
167
+ cover,
168
+ type,
169
+ size,
170
+ addons,
171
+ button,
172
+ buttonText,
173
+ buttonDisabled,
174
+ buttonLoading,
175
+ isStickyButton,
176
+ onButtonClick,
177
+ onMainClick,
178
+ onTagClick,
179
+ className,
180
+ scaleClickZone,
181
+ ...rest
182
+ }) {
183
+ const wrapHandler =
184
+ (handler, stopFn = () => false) =>
185
+ (e, ...args) => {
186
+ if (stopFn()) {
187
+ e.preventDefault();
188
+ e.stopPropagation();
189
+ } else if (handler instanceof Function) {
190
+ e.preventDefault();
191
+ e.stopPropagation();
192
+ handler(...args);
193
+ }
194
+ };
195
+ const _onButtonClick = wrapHandler(onButtonClick, () => {
196
+ // stop click while custom button or buttonDisabled or buttondLoading
197
+ if (button || buttonDisabled || buttonLoading) {
198
+ return true;
199
+ }
200
+ return false;
201
+ });
202
+ const _onMainClick = wrapHandler(onMainClick);
203
+
204
+ const theme = useTheme();
205
+ const isDownSm = useMediaQuery(theme.breakpoints.down('sm'));
206
+ const isDownMd = useMediaQuery(theme.breakpoints.down('md'));
207
+
208
+ // If size is auto, need calculate actual size according to screen size
209
+ // eslint-disable-next-line no-nested-ternary
210
+ const actualSize = size === 'auto' ? (isDownSm ? 'xs' : isDownMd ? 'sm' : 'md') : size;
211
+ const container = useRef(null);
212
+
213
+ return (
214
+ <Div
215
+ {...rest}
216
+ scaleClickZone={scaleClickZone}
217
+ className={`${className} arcblock-blocklet arcblock-blocklet--size-${actualSize}`}>
218
+ <div className="arcblock-blocklet__content">
219
+ <div className="arcblock-blocklet__content--main" onClick={_onMainClick} ref={container}>
220
+ <div className="arcblock-blocklet__content--body">
221
+ {cover && (
222
+ <div className="arcblock-blocklet__cover">
223
+ <Img src={cover} />
224
+ </div>
225
+ )}
226
+ <div className="arcblock-blocklet__info">
227
+ <Typography
228
+ component="h3"
229
+ variant="h3"
230
+ className="arcblock-blocklet__title"
231
+ title={title}>
232
+ {title}
233
+ </Typography>
234
+ {description && (
235
+ <Typography
236
+ component="div"
237
+ variant="body2"
238
+ className="arcblock-blocklet__describe"
239
+ title={description}>
240
+ {description}
241
+ </Typography>
242
+ )}
243
+ {['md', 'sm', 'xs'].includes(actualSize) && (
244
+ <Portal container={container.current} disablePortal={actualSize === 'md'}>
245
+ <div
246
+ className="arcblock-blocklet__button"
247
+ onClick={_onButtonClick}
248
+ style={{ display: isStickyButton ? 'block' : '' }}>
249
+ {button ||
250
+ (onButtonClick && (
251
+ <Button
252
+ rounded
253
+ variant="contained"
254
+ color="primary"
255
+ size="small"
256
+ disabled={buttonDisabled || buttonLoading}
257
+ style={
258
+ actualSize === 'md'
259
+ ? { padding: '3px 20px', fontSize: '14px' }
260
+ : { padding: '3px 15px', minWidth: '54px', fontSize: '13px' }
261
+ }>
262
+ {buttonLoading && (
263
+ <CircularProgress
264
+ size={actualSize === 'md' ? 15 : 13}
265
+ style={{ marginRight: 3, color: 'inherit' }}
266
+ />
267
+ )}
268
+ {buttonText}
269
+ </Button>
270
+ ))}
271
+ </div>
272
+ </Portal>
273
+ )}
274
+ </div>
275
+ </div>
276
+ </div>
277
+ </div>
278
+ <div className="arcblock-blocklet__addons">
279
+ {addons.map((item, index) => (
280
+ <Typography
281
+ component="span"
282
+ variant="caption"
283
+ className="arcblock-blocklet__addons--item"
284
+ // eslint-disable-next-line react/no-array-index-key
285
+ key={index}
286
+ title={item.title}>
287
+ {item.empty ? null : (
288
+ <>
289
+ <BlockletIcon name={item.icon} />
290
+ {item.pretty ? prettySize(item.value) : item.value}
291
+ </>
292
+ )}
293
+ </Typography>
294
+ ))}
295
+ </div>
296
+ </Div>
297
+ );
298
+ }
299
+
300
+ Blocklet.propTypes = {
301
+ title: PropTypes.string.isRequired,
302
+ isStickyButton: PropTypes.bool,
303
+ description: PropTypes.string,
304
+ cover: PropTypes.string,
305
+ buttonText: PropTypes.string,
306
+ buttonDisabled: PropTypes.bool,
307
+ buttonLoading: PropTypes.bool,
308
+ button: PropTypes.element,
309
+ type: PropTypes.string,
310
+ addons: PropTypes.arrayOf(PropTypes.object),
311
+ size: PropTypes.oneOf(['xs', 'sm', 'md', 'auto']),
312
+ onButtonClick: PropTypes.func,
313
+ onMainClick: PropTypes.func,
314
+ onTagClick: PropTypes.func,
315
+ className: PropTypes.string,
316
+ scaleClickZone: PropTypes.number,
317
+ };
318
+
319
+ Blocklet.defaultProps = {
320
+ description: null,
321
+ cover: null,
322
+ isStickyButton: false,
323
+ buttonText: 'Install',
324
+ buttonDisabled: false,
325
+ buttonLoading: false,
326
+ button: null,
327
+ type: null,
328
+ size: 'auto',
329
+ addons: [],
330
+ onButtonClick: null,
331
+ onMainClick: null,
332
+ onTagClick: null,
333
+ className: null,
334
+ scaleClickZone: 1.5,
335
+ };
@@ -0,0 +1,4 @@
1
+ import Button from '@material-ui/core/Button';
2
+ import wrap from './wrap';
3
+
4
+ export default wrap(Button);
@@ -0,0 +1,88 @@
1
+ /* eslint-disable prefer-destructuring */
2
+ /* eslint-disable func-names */
3
+ import React from 'react';
4
+ import PropTypes from 'prop-types';
5
+
6
+ import Spinner from '../Spinner';
7
+ import colors from '../Colors';
8
+ import { mergeProps } from '../Util';
9
+
10
+ export default function (BaseComponent) {
11
+ function WrappedComponent(props) {
12
+ const newProps = mergeProps(props, WrappedComponent, ['style']);
13
+ const { children, rounded, loading, disabled, style, forwardedRef, ...rest } = newProps;
14
+
15
+ const isDisabled = disabled || loading;
16
+
17
+ let loadingSize = 16;
18
+ switch (rest.size) {
19
+ case 'small':
20
+ loadingSize = 14;
21
+ break;
22
+ case 'large':
23
+ loadingSize = 18;
24
+ break;
25
+ default:
26
+ }
27
+ const styles = Object.assign({}, style, {
28
+ boxShadow: 'none',
29
+ textTransform: 'capitalize',
30
+ });
31
+
32
+ if (rest.color === 'danger') {
33
+ if (rest.variant === 'contained') {
34
+ styles.backgroundColor = colors.error.main;
35
+ styles.color = colors.common.white;
36
+ } else {
37
+ styles.borderColor = colors.error.main;
38
+ styles.color = colors.error.main;
39
+ }
40
+ }
41
+ if (!rest.color || rest.color === 'default') {
42
+ if (rest.variant === 'contained') {
43
+ styles.backgroundColor = isDisabled ? colors.grey[400] : colors.grey[900];
44
+ styles.color = colors.common.white;
45
+ } else {
46
+ styles.borderColor = isDisabled ? colors.grey[400] : colors.grey[900];
47
+ styles.color = isDisabled ? colors.grey[400] : colors.grey[900];
48
+ }
49
+ }
50
+ if (rest.color === 'reverse') {
51
+ if (rest.variant === 'contained') {
52
+ styles.backgroundColor = 'rgba(255, 255, 255, 0.9)';
53
+ styles.color = colors.grey[900];
54
+ } else {
55
+ styles.borderColor = colors.grey[900];
56
+ styles.color = colors.grey[900];
57
+ }
58
+ }
59
+ if (rounded) {
60
+ // styles.borderRadius = { small: 16, medium: 18, large: 20 }[rest.size];
61
+ styles.borderRadius = '100vw';
62
+ }
63
+
64
+ return (
65
+ <BaseComponent style={styles} ref={forwardedRef} disabled={isDisabled} {...rest}>
66
+ {loading && <Spinner size={loadingSize} style={{ marginRight: 5 }} />}
67
+ {children}
68
+ </BaseComponent>
69
+ );
70
+ }
71
+
72
+ WrappedComponent.propTypes = {
73
+ children: PropTypes.any.isRequired,
74
+ style: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
75
+ size: PropTypes.oneOf(['large', 'medium', 'small']),
76
+ forwardedRef: PropTypes.any,
77
+ rounded: PropTypes.bool,
78
+ };
79
+
80
+ WrappedComponent.defaultProps = {
81
+ rounded: false,
82
+ size: 'medium',
83
+ forwardedRef: null,
84
+ style: {},
85
+ };
86
+
87
+ return React.forwardRef((props, ref) => <WrappedComponent {...props} forwardedRef={ref} />);
88
+ }
@@ -0,0 +1,19 @@
1
+ import styled from 'styled-components';
2
+ import ButtonGroup from '@material-ui/core/ButtonGroup';
3
+ import wrap from '../Button/wrap';
4
+
5
+ const sizes = { small: 16, medium: 18, large: 20 };
6
+ const getBorderRadius = size => sizes[size || 'medium'];
7
+
8
+ const StyledButtonGroup = styled(ButtonGroup)`
9
+ .MuiButton-root:first-of-type {
10
+ border-radius: ${props => getBorderRadius(props.size)}px 0 0
11
+ ${props => getBorderRadius(props.size)}px;
12
+ }
13
+ .MuiButton-root:last-of-type {
14
+ border-radius: 0 ${props => getBorderRadius(props.size)}px
15
+ ${props => getBorderRadius(props.size)}px 0;
16
+ }
17
+ `;
18
+
19
+ export default wrap(StyledButtonGroup);
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ // eslint-disable-next-line react/prop-types
5
+ export default function Center({ children }) {
6
+ return <Div>{children}</Div>;
7
+ }
8
+
9
+ const Div = styled.div`
10
+ flex: 1;
11
+ width: 100vw;
12
+ height: 100vh;
13
+
14
+ display: flex;
15
+ justify-content: center;
16
+ align-items: center;
17
+ `;
@@ -0,0 +1,90 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import Copy from 'copy-to-clipboard';
3
+ import PropTypes from 'prop-types';
4
+ import useWindowSize from 'react-use/lib/useWindowSize';
5
+
6
+ import Tooltip from '@material-ui/core/Tooltip';
7
+ import Typography from '@material-ui/core/Typography';
8
+ import styled from 'styled-components';
9
+
10
+ import Toast from '../Toast';
11
+ import { mergeProps } from '../Util';
12
+
13
+ export default function ClickToCopy(props) {
14
+ const newProps = mergeProps(props, ClickToCopy, ['style']);
15
+ const { children, content, tip, copiedTip, tipPlacement, style, ...rest } = newProps;
16
+
17
+ const [copied, setCopied] = useState(false);
18
+ const childrenRef = React.createRef();
19
+ const { width } = useWindowSize();
20
+
21
+ const onCopy = e => {
22
+ Copy(content || e.current.textContent);
23
+ setCopied(true);
24
+ };
25
+
26
+ useEffect(() => {
27
+ let timer = null;
28
+ if (copied) {
29
+ timer = setTimeout(() => {
30
+ setCopied(false);
31
+ }, 2000);
32
+ }
33
+
34
+ return () => {
35
+ if (timer) {
36
+ clearTimeout(timer);
37
+ }
38
+ };
39
+ });
40
+
41
+ return (
42
+ <Tooltip
43
+ title={copied ? copiedTip : tip}
44
+ {...rest}
45
+ placement={tipPlacement}
46
+ disableFocusListener>
47
+ <Container
48
+ ref={childrenRef}
49
+ component="span"
50
+ style={Object.assign(
51
+ { fontSize: 'inherit', color: 'inherit', fontWeight: 'inherit' },
52
+ style
53
+ )}
54
+ onClick={() => onCopy(childrenRef)}>
55
+ {children || content}
56
+ {copied && width < 600 && <Toast variant="success" message={copiedTip} />}
57
+ </Container>
58
+ </Tooltip>
59
+ );
60
+ }
61
+
62
+ ClickToCopy.propTypes = {
63
+ children: PropTypes.any.isRequired,
64
+ content: PropTypes.string,
65
+ tip: PropTypes.string,
66
+ tipPlacement: PropTypes.string,
67
+ copiedTip: PropTypes.string,
68
+ style: PropTypes.object,
69
+ };
70
+
71
+ ClickToCopy.defaultProps = {
72
+ content: '',
73
+ tip: 'Click To Copy',
74
+ copiedTip: 'Copied',
75
+ tipPlacement: 'right',
76
+ style: {},
77
+ };
78
+
79
+ const Container = styled(Typography)`
80
+ display: inline;
81
+ white-space: pre-wrap;
82
+ word-wrap: break-word;
83
+ overflow-wrap: break-word;
84
+ align-items: center;
85
+ justify-content: start;
86
+ border-radius: 15px;
87
+ padding: 1px 12px;
88
+ background-color: rgba(0, 0, 0, 0.08);
89
+ cursor: pointer;
90
+ `;
@@ -0,0 +1,151 @@
1
+ /* eslint-disable react/no-danger */
2
+ import React, { useState } from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import styled from 'styled-components';
5
+ import Copy from 'copy-to-clipboard';
6
+ import Button from '@material-ui/core/IconButton';
7
+ import useMountedState from 'react-use/lib/useMountedState';
8
+
9
+ import hljs from 'highlight.js/lib/highlight';
10
+ import javascript from 'highlight.js/lib/languages/javascript';
11
+ import json from 'highlight.js/lib/languages/json';
12
+ import elixir from 'highlight.js/lib/languages/elixir';
13
+ import java from 'highlight.js/lib/languages/java';
14
+ import swift from 'highlight.js/lib/languages/swift';
15
+ import objectivec from 'highlight.js/lib/languages/objectivec';
16
+ import kotlin from 'highlight.js/lib/languages/kotlin';
17
+ import protobuf from 'highlight.js/lib/languages/protobuf';
18
+ import python from 'highlight.js/lib/languages/python';
19
+ import yaml from 'highlight.js/lib/languages/yaml';
20
+ import shell from 'highlight.js/lib/languages/shell';
21
+ import diff from 'highlight.js/lib/languages/diff';
22
+ import plaintext from 'highlight.js/lib/languages/plaintext';
23
+
24
+ import 'highlight.js/styles/atom-one-dark.css';
25
+
26
+ import CopyIcon from '@material-ui/icons/FileCopy';
27
+ import CheckIcon from '@material-ui/icons/Check';
28
+
29
+ hljs.registerLanguage('javascript', javascript);
30
+ hljs.registerLanguage('js', javascript);
31
+ hljs.registerLanguage('json', json);
32
+ hljs.registerLanguage('elixir', elixir);
33
+ hljs.registerLanguage('java', java);
34
+ hljs.registerLanguage('kotlin', kotlin);
35
+ hljs.registerLanguage('kt', kotlin);
36
+ hljs.registerLanguage('protobuf', protobuf);
37
+ hljs.registerLanguage('protobuffer', protobuf);
38
+ hljs.registerLanguage('python', python);
39
+ hljs.registerLanguage('py', python);
40
+ hljs.registerLanguage('yaml', yaml);
41
+ hljs.registerLanguage('yml', yaml);
42
+ hljs.registerLanguage('shell', shell);
43
+ hljs.registerLanguage('sh', shell);
44
+ hljs.registerLanguage('plaintext', plaintext);
45
+ hljs.registerLanguage('text', plaintext);
46
+ hljs.registerLanguage('patch', diff);
47
+ hljs.registerLanguage('diff', diff);
48
+ hljs.registerLanguage('swift', swift);
49
+ hljs.registerLanguage('objectivec', objectivec);
50
+ hljs.registerLanguage('oc', objectivec);
51
+
52
+ export default function CodeBlock({ code, language, children, ...rest }) {
53
+ const [copied, setCopied] = useState(false);
54
+ const isMounted = useMountedState();
55
+ const source = code || children;
56
+
57
+ const onCopy = () => {
58
+ Copy(source);
59
+ setCopied(true);
60
+ // 恢复 copied 状态
61
+ setTimeout(() => {
62
+ if (isMounted()) {
63
+ setCopied(false);
64
+ }
65
+ }, 1500);
66
+ };
67
+
68
+ return (
69
+ <Pre {...rest}>
70
+ <span className="codeblock__inner">
71
+ <code
72
+ className={`hljs ${language}`}
73
+ dangerouslySetInnerHTML={{ __html: hljs.highlightAuto(source, [language]).value }}
74
+ />
75
+ </span>
76
+ <Button
77
+ className="copy-button"
78
+ onClick={onCopy}
79
+ tabIndex="-1"
80
+ color="primary"
81
+ disabled={copied}>
82
+ {!copied && <CopyIcon style={{ color: '#fff', fontSize: 16 }} />}
83
+ {copied && <CheckIcon style={{ color: '#fff', fontSize: 16 }} />}
84
+ </Button>
85
+ </Pre>
86
+ );
87
+ }
88
+
89
+ CodeBlock.propTypes = {
90
+ code: PropTypes.string,
91
+ language: PropTypes.string,
92
+ children: PropTypes.any,
93
+ };
94
+
95
+ CodeBlock.defaultProps = {
96
+ code: '',
97
+ language: 'text',
98
+ children: null,
99
+ };
100
+
101
+ const fontFamily = 'source-code-pro, Menlo, Monaco, Consolas, Courier New, monospace !important';
102
+ const Pre = styled.pre`
103
+ font-family: ${fontFamily};
104
+ display: block;
105
+ font-size: 14px;
106
+ line-height: 1.42857143;
107
+ margin: 0 0 32px;
108
+ word-break: break-word;
109
+ word-wrap: break-word;
110
+ text-align: left;
111
+ border-radius: 5px;
112
+ border: 1px solid #dedede;
113
+ background: #222;
114
+ color: #fff;
115
+ position: relative;
116
+
117
+ .codeblock__inner {
118
+ display: block;
119
+ width: 100%;
120
+ max-height: 46.25rem;
121
+ overflow: scroll;
122
+ }
123
+
124
+ .copy-button {
125
+ display: none;
126
+ position: absolute;
127
+ top: 8px;
128
+ right: 24px;
129
+ }
130
+
131
+ &:hover {
132
+ .copy-button {
133
+ display: block;
134
+ }
135
+ }
136
+
137
+ code {
138
+ counter-reset: line;
139
+ counter-increment: line;
140
+ padding: 16px;
141
+ font-family: ${fontFamily};
142
+ color: #fff;
143
+ * {
144
+ font-family: ${fontFamily};
145
+ }
146
+ }
147
+
148
+ .hljs * {
149
+ white-space: normal; // autowrap
150
+ }
151
+ `;
@@ -0,0 +1 @@
1
+ export { default } from './themes/default';