@arcblock/ux 2.6.9 → 2.7.1

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 (164) hide show
  1. package/babel.config.es.js +12 -0
  2. package/es/ActionButton/index.js +99 -0
  3. package/es/ActivityIndicator/index.js +180 -0
  4. package/es/Address/compact-text.js +105 -0
  5. package/es/Address/did-address.js +211 -0
  6. package/es/Address/index.js +23 -0
  7. package/es/Address/responsive-did-address.js +88 -0
  8. package/es/Alert/index.js +134 -0
  9. package/es/AnimationWaiter/default-animation.json +1 -0
  10. package/es/AnimationWaiter/index.js +239 -0
  11. package/es/Async/index.js +38 -0
  12. package/es/Avatar/did-motif.js +64 -0
  13. package/es/Avatar/etherscan-blockies.js +83 -0
  14. package/es/Avatar/index.js +176 -0
  15. package/es/Badge/index.js +98 -0
  16. package/es/Blocklet/blocklet.js +298 -0
  17. package/es/Blocklet/index.js +4 -0
  18. package/es/Blocklet/utils.js +52 -0
  19. package/es/BlockletNFT/index.js +412 -0
  20. package/es/Button/index.js +8 -0
  21. package/es/Button/wrap.js +140 -0
  22. package/es/ButtonGroup/index.js +6 -0
  23. package/es/CardSelector/index.js +131 -0
  24. package/es/Center/index.js +41 -0
  25. package/es/ClickToCopy/copy-button.js +72 -0
  26. package/es/ClickToCopy/hook.js +39 -0
  27. package/es/ClickToCopy/index.js +93 -0
  28. package/es/CodeBlock/LightBox.js +85 -0
  29. package/es/CodeBlock/index.js +226 -0
  30. package/es/Colors/index.js +2 -0
  31. package/es/Colors/themes/default.js +78 -0
  32. package/es/ContactForm/index.js +230 -0
  33. package/es/CookieConsent/index.js +113 -0
  34. package/es/CountDown/index.js +178 -0
  35. package/es/DID/index.js +105 -0
  36. package/es/Datatable/CustomToolbar.js +396 -0
  37. package/es/Datatable/DatatableContext.js +34 -0
  38. package/es/Datatable/TableSearch.js +165 -0
  39. package/es/Datatable/index.js +627 -0
  40. package/es/Datatable/utils.js +132 -0
  41. package/es/Dialog/confirm.js +90 -0
  42. package/es/Dialog/dialog.js +192 -0
  43. package/es/Dialog/index.js +3 -0
  44. package/es/DidLogo/index.js +31 -0
  45. package/es/DriftBot/index.js +70 -0
  46. package/es/Earth/countries.json +8057 -0
  47. package/es/Earth/index.js +521 -0
  48. package/es/Earth/util.js +51 -0
  49. package/es/Empty/index.js +64 -0
  50. package/es/ErrorBoundary/fallback.js +73 -0
  51. package/es/ErrorBoundary/index.js +1 -0
  52. package/es/Footer/index.js +172 -0
  53. package/es/Header/auto-hidden.js +35 -0
  54. package/es/Header/header.js +211 -0
  55. package/es/Header/index.js +2 -0
  56. package/es/Header/responsive-header.js +111 -0
  57. package/es/Icon/image.js +65 -0
  58. package/es/Icon/index.js +84 -0
  59. package/es/Img/index.js +217 -0
  60. package/es/InfoRow/index.js +87 -0
  61. package/es/Layout/dashboard/external-link.js +58 -0
  62. package/es/Layout/dashboard/full-page.js +53 -0
  63. package/es/Layout/dashboard/index.js +275 -0
  64. package/es/Layout/dashboard/sidebar.js +209 -0
  65. package/es/Layout/dashboard-legacy/header.js +174 -0
  66. package/es/Layout/dashboard-legacy/index.js +149 -0
  67. package/es/Layout/dashboard-legacy/sidebar.js +129 -0
  68. package/es/Layout/index.js +335 -0
  69. package/es/Locale/browser-lang.js +52 -0
  70. package/es/Locale/context.js +114 -0
  71. package/es/Locale/languages.js +60 -0
  72. package/es/Locale/selector.js +180 -0
  73. package/es/Locale/util.js +13 -0
  74. package/es/Logo/images/logo-dark-text.svg +3 -0
  75. package/es/Logo/images/logo-dark-top.svg +6 -0
  76. package/es/Logo/images/logo-light-text.svg +3 -0
  77. package/es/Logo/images/logo-light-top.svg +6 -0
  78. package/es/Logo/index.js +136 -0
  79. package/es/Metric/index.js +132 -0
  80. package/es/NFTDisplay/README.md +59 -0
  81. package/es/NFTDisplay/aspect-ratio-container.js +39 -0
  82. package/es/NFTDisplay/broken.js +18 -0
  83. package/es/NFTDisplay/demo/data/asset-state-display-url.json +7 -0
  84. package/es/NFTDisplay/demo/data/asset-state-gzipped-svg-1-1.json +10 -0
  85. package/es/NFTDisplay/demo/data/asset-state-gzipped-svg-374-130.json +10 -0
  86. package/es/NFTDisplay/demo/data/asset-state-gzipped-svg-with-foreign-object.json +20 -0
  87. package/es/NFTDisplay/demo/data/asset-state-svg.json +29 -0
  88. package/es/NFTDisplay/demo/data/asset-state-url.json +10 -0
  89. package/es/NFTDisplay/index.js +323 -0
  90. package/es/NFTDisplay/loading.js +18 -0
  91. package/es/NFTDisplay/svg-embedder/img.js +45 -0
  92. package/es/NFTDisplay/svg-embedder/inline-svg.js +39 -0
  93. package/es/NavMenu/index.js +2 -0
  94. package/es/NavMenu/nav-menu.js +286 -0
  95. package/es/NavMenu/style.js +176 -0
  96. package/es/PageScroller/index.js +286 -0
  97. package/es/PageScroller/story/FifthComponent.js +9 -0
  98. package/es/PageScroller/story/FirstComponent.js +9 -0
  99. package/es/PageScroller/story/FourthComponent.js +12 -0
  100. package/es/PageScroller/story/FullPage.js +47 -0
  101. package/es/PageScroller/story/PageContain.js +59 -0
  102. package/es/PageScroller/story/SecondComponent.js +9 -0
  103. package/es/PageScroller/story/ThirdComponent.js +9 -0
  104. package/es/PageScroller/story/index.css +115 -0
  105. package/es/PageScroller/usePrevValue.js +9 -0
  106. package/es/PricingTable/PricingPlan.js +124 -0
  107. package/es/PricingTable/index.js +53 -0
  108. package/es/QRCode/index.js +72 -0
  109. package/es/RelativeTime/index.js +98 -0
  110. package/es/Result/common.js +140 -0
  111. package/es/Result/demo/fixtures/result-image-404.svg +1 -0
  112. package/es/Result/index.js +33 -0
  113. package/es/Result/result.js +59 -0
  114. package/es/Result/translations.js +54 -0
  115. package/es/Screenshot/BaseScreenshot/index.js +91 -0
  116. package/es/Screenshot/BaseScreenshot/shells/Macbook.js +51 -0
  117. package/es/Screenshot/BaseScreenshot/shells/Phone.js +36 -0
  118. package/es/Screenshot/demo/images/bg-00.jpg +0 -0
  119. package/es/Screenshot/demo/images/bg-01.jpg +0 -0
  120. package/es/Screenshot/demo/images/bg-02.jpg +0 -0
  121. package/es/Screenshot/demo/images/bg-03.jpg +0 -0
  122. package/es/Screenshot/demo/images/bg-04.jpg +0 -0
  123. package/es/Screenshot/demo/images/bg-05.jpg +0 -0
  124. package/es/Screenshot/demo/images/bg-06.jpg +0 -0
  125. package/es/Screenshot/demo/images/bg-07.jpg +0 -0
  126. package/es/Screenshot/demo/images/bg-08.jpg +0 -0
  127. package/es/Screenshot/demo/images/bg-09.jpg +0 -0
  128. package/es/Screenshot/devices.css +1366 -0
  129. package/es/Screenshot/index.js +299 -0
  130. package/es/SessionManager/federated-login-detecter.js +166 -0
  131. package/es/SessionManager/index.js +468 -0
  132. package/es/SessionManager/user-popper.js +132 -0
  133. package/es/Sparkline/index.js +193 -0
  134. package/es/Spinner/index.js +28 -0
  135. package/es/SplitButton/index.js +144 -0
  136. package/es/Switch/index.js +96 -0
  137. package/es/Tabs/index.js +48 -0
  138. package/es/Tag/index.js +108 -0
  139. package/es/TextCollapse/index.js +92 -0
  140. package/es/Theme/index.js +16 -0
  141. package/es/Theme/theme-provider.js +39 -0
  142. package/es/Theme/theme.js +133 -0
  143. package/es/Toast/index.js +95 -0
  144. package/es/Util/deprecate.js +28 -0
  145. package/es/Util/index.js +298 -0
  146. package/es/Util/wallet.js +32 -0
  147. package/es/Video/index.js +89 -0
  148. package/es/Wallet/Action.js +119 -0
  149. package/es/Wallet/Download.js +331 -0
  150. package/es/Wallet/Open.js +45 -0
  151. package/es/Wallet/images/abtwallet.png +0 -0
  152. package/es/Wallet/images/android_download.svg +23 -0
  153. package/es/Wallet/images/app-store.svg +20 -0
  154. package/es/Wallet/images/google-play.svg +70 -0
  155. package/es/WebWalletSWKeeper/index.js +115 -0
  156. package/es/WechatPrompt/images/android.png +0 -0
  157. package/es/WechatPrompt/images/ios.png +0 -0
  158. package/es/WechatPrompt/index.js +88 -0
  159. package/es/index.js +38 -0
  160. package/es/withTheme/index.js +69 -0
  161. package/es/withTracker/README.md +34 -0
  162. package/es/withTracker/error_boundary.js +34 -0
  163. package/es/withTracker/index.js +56 -0
  164. package/package.json +272 -5
@@ -0,0 +1,239 @@
1
+ import { useState, useEffect, useRef } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import Lottie from 'react-lottie-player';
4
+ import lottieJson from './default-animation.json';
5
+ import { styled } from '../Theme';
6
+
7
+ /**
8
+ * 用于长时间等待的用的动画组件
9
+ * 动画会随着时间的变化而逐步加快播放速度,好适应用户的等待心理
10
+ * @param {Object} animationData lottie json 动画数据
11
+ * @param {Number} size 动画的尺寸,单位px
12
+ * @param {String|Array} message 动画下方的文字;数组情况下会在一定时间切换文案
13
+ * @param {Number} messageDuration 动画下方的文字为数组时,每个文案的持续时间;默认5000ms
14
+ * @param {Number} messageLoop 动画下方的文字为数组时,文案是否循环播放
15
+ * @param {Array} tips 底部的提示元素
16
+ * @param {Number} tipsDuration 底部提示的切换时间,单位毫秒,默认3000ms
17
+ * @param {Number} speed 动画默认的播放速度
18
+ * @param {Number} maybeDuration 整个动画大概的持续时间,单位毫秒,用于计算增量下的动画速度,默认两分钟(120000ms)
19
+ * @param {Number} increaseSpeed 在 maybeDuration 时间下增加的速度,默认为0(不增加速度)
20
+ * @returns element
21
+ */
22
+ import { jsx as _jsx } from "react/jsx-runtime";
23
+ import { jsxs as _jsxs } from "react/jsx-runtime";
24
+ export default function AnimationWaiter({
25
+ animationData,
26
+ size,
27
+ message,
28
+ messageDuration,
29
+ messageLoop,
30
+ tips,
31
+ tipsDuration,
32
+ maybeDuration,
33
+ speed,
34
+ increaseSpeed,
35
+ ...rest
36
+ }) {
37
+ const [tipsId, setTipsId] = useState(0);
38
+ const [currentSpeed, setCurrentSpeed] = useState(speed);
39
+ const [messageId, setMessageId] = useState(0);
40
+ // 动画的开始时间
41
+ const startTime = useRef(new Date().getTime());
42
+ if (!Array.isArray(message)) {
43
+ // eslint-disable-next-line no-param-reassign
44
+ message = [message];
45
+ }
46
+ useEffect(() => {
47
+ if (!message) {
48
+ return;
49
+ }
50
+ let msgIndex = 0;
51
+ const timer = setInterval(() => {
52
+ msgIndex++;
53
+ if (msgIndex >= message.length) {
54
+ if (messageLoop) {
55
+ msgIndex = 0;
56
+ } else {
57
+ msgIndex = message.length - 1;
58
+ }
59
+ }
60
+ setMessageId(msgIndex);
61
+ }, messageDuration);
62
+
63
+ // eslint-disable-next-line consistent-return
64
+ return () => {
65
+ clearInterval(timer);
66
+ };
67
+ // eslint-disable-next-line react-hooks/exhaustive-deps
68
+ }, [message, messageDuration]);
69
+
70
+ // tips
71
+ useEffect(() => {
72
+ if (!tips.length) {
73
+ return () => {};
74
+ }
75
+ const timer = setTimeout(() => {
76
+ let nextId = tipsId + 1;
77
+ if (nextId >= tips.length) {
78
+ nextId = 0;
79
+ }
80
+ setTipsId(nextId);
81
+ }, tipsDuration);
82
+ return () => clearTimeout(timer);
83
+ }, [tips, tipsDuration, tipsId]);
84
+
85
+ // 动画speed
86
+ useEffect(() => {
87
+ const timer = setTimeout(() => {
88
+ const diffTime = new Date().getTime() - startTime.current;
89
+ let percentage = diffTime / maybeDuration;
90
+ if (percentage > 1) {
91
+ percentage = 1;
92
+ }
93
+ const newSpeed = speed + increaseSpeed * percentage;
94
+ setCurrentSpeed(newSpeed);
95
+ }, 1000);
96
+ return () => clearTimeout(timer);
97
+ // eslint-disable-next-line react-hooks/exhaustive-deps
98
+ }, [currentSpeed]);
99
+ const getMsgClassName = index => {
100
+ let className = 'message-before';
101
+ if (messageId === index) {
102
+ className = 'show-message';
103
+ } else if (messageId < index) {
104
+ className = 'message-after';
105
+ }
106
+ return className;
107
+ };
108
+ return /*#__PURE__*/_jsxs(Container, {
109
+ ...rest,
110
+ children: [/*#__PURE__*/_jsx(Lottie, {
111
+ loop: true,
112
+ animationData: animationData || lottieJson,
113
+ play: true,
114
+ speed: currentSpeed,
115
+ style: {
116
+ width: size,
117
+ height: size
118
+ }
119
+ }), message && /*#__PURE__*/_jsx("div", {
120
+ className: "waiter-message",
121
+ children: message.map((text, index) => {
122
+ const className = getMsgClassName(index);
123
+ return /*#__PURE__*/_jsxs("div", {
124
+ children: [/*#__PURE__*/_jsx("span", {
125
+ className: `message-block ${className}`,
126
+ children: text
127
+ }), /*#__PURE__*/_jsx("span", {
128
+ className: `placeholder-message ${className}`,
129
+ children: text
130
+ })]
131
+ }, index);
132
+ })
133
+ }), tips.length ? /*#__PURE__*/_jsx("div", {
134
+ className: "waiter-tips-container",
135
+ children: tips.map((e, index) => {
136
+ return /*#__PURE__*/_jsx("div", {
137
+ className: `waiter-tips-block ${tipsId === index ? 'show-tips' : ''}`
138
+ // eslint-disable-next-line react/no-array-index-key
139
+ ,
140
+ children: e
141
+ }, index);
142
+ })
143
+ }) : '']
144
+ });
145
+ }
146
+ AnimationWaiter.propTypes = {
147
+ animationData: PropTypes.any,
148
+ size: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
149
+ message: PropTypes.any,
150
+ messageDuration: PropTypes.number,
151
+ messageLoop: PropTypes.bool,
152
+ tips: PropTypes.array,
153
+ tipsDuration: PropTypes.number,
154
+ speed: PropTypes.number,
155
+ maybeDuration: PropTypes.number,
156
+ increaseSpeed: PropTypes.number
157
+ };
158
+ AnimationWaiter.defaultProps = {
159
+ animationData: null,
160
+ size: '',
161
+ message: '',
162
+ messageDuration: 5000,
163
+ messageLoop: true,
164
+ tips: [],
165
+ tipsDuration: 5000,
166
+ speed: 1,
167
+ maybeDuration: 120000,
168
+ increaseSpeed: 0
169
+ };
170
+ const Container = styled('div')`
171
+ display: flex;
172
+ justify-content: center;
173
+ align-items: center;
174
+ flex-direction: column;
175
+ width: 100%;
176
+ height: 100%;
177
+
178
+ .waiter-message {
179
+ position: relative;
180
+ width: 100%;
181
+ font-weight: 700;
182
+ font-size: 18px;
183
+ line-height: 22px;
184
+ text-align: center;
185
+ overflow: hidden;
186
+ .message-block {
187
+ position: absolute;
188
+ left: 0;
189
+ width: 100%;
190
+ opacity: 0;
191
+ transition: all ease 0.3s;
192
+ user-select: none;
193
+ &.message-before {
194
+ transform: translate(-20px, 0);
195
+ }
196
+ &.message-after {
197
+ transform: translate(20px, 0);
198
+ }
199
+ &.show-message {
200
+ transform: translate(0, 0);
201
+ opacity: 1;
202
+ user-select: text;
203
+ z-index: 2;
204
+ }
205
+ }
206
+
207
+ .placeholder-message {
208
+ user-select: none;
209
+ display: none;
210
+ opacity: 0;
211
+ &.show-message {
212
+ display: block;
213
+ }
214
+ }
215
+ }
216
+
217
+ .waiter-tips-container {
218
+ position: relative;
219
+ margin-top: auto;
220
+ width: 100%;
221
+ .waiter-tips-block {
222
+ position: absolute;
223
+ bottom: 0;
224
+ left: 0;
225
+ width: 100%;
226
+ opacity: 0;
227
+ pointer-events: none;
228
+ z-index: 1;
229
+ transform: translate(-20px, 0);
230
+ transition: all ease 0.4s;
231
+ &.show-tips {
232
+ opacity: 1;
233
+ pointer-events: auto;
234
+ z-index: 2;
235
+ transform: translate(0, 0);
236
+ }
237
+ }
238
+ }
239
+ `;
@@ -0,0 +1,38 @@
1
+ import * as React from 'react';
2
+ import CircularProgress from '@mui/material/CircularProgress';
3
+ import { jsx as _jsx } from "react/jsx-runtime";
4
+ export default function LoadAsyncComponent(importComponent, key = 'default', showProgress = true) {
5
+ class AsyncComponent extends React.Component {
6
+ constructor(props) {
7
+ super(props);
8
+ this.state = {
9
+ Component: null,
10
+ error: null
11
+ };
12
+ }
13
+ componentDidMount() {
14
+ importComponent().then(asyncModule => this.setState({
15
+ Component: asyncModule[key]
16
+ })).catch(err => this.setState({
17
+ error: `Failed to load async component: ${err.message}`
18
+ }));
19
+ }
20
+ render() {
21
+ const {
22
+ Component,
23
+ error
24
+ } = this.state;
25
+ if (error) {
26
+ return error;
27
+ }
28
+
29
+ // eslint-disable-next-line no-nested-ternary
30
+ return Component ? /*#__PURE__*/_jsx(Component, {
31
+ ...this.props
32
+ }) : showProgress ? /*#__PURE__*/_jsx(CircularProgress, {
33
+ color: "primary"
34
+ }) : null;
35
+ }
36
+ }
37
+ return AsyncComponent;
38
+ }
@@ -0,0 +1,64 @@
1
+ import { useRef, useLayoutEffect } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { update } from '@arcblock/did-motif';
4
+ import { jsx as _jsx } from "react/jsx-runtime";
5
+ function DIDMotif({
6
+ did,
7
+ size,
8
+ animation,
9
+ shape,
10
+ responsive,
11
+ ...rest
12
+ }) {
13
+ const svgRef = useRef(null);
14
+ useLayoutEffect(() => {
15
+ update(svgRef.current, did, {
16
+ size,
17
+ animation,
18
+ shape
19
+ });
20
+ // eslint-disable-next-line react-hooks/exhaustive-deps
21
+ }, [did, size, shape]);
22
+ if (responsive) {
23
+ // fix avatar 显示问题 (safari 下父容器为 flex 时 inline svg 显示不出来, 需要明确指定 width)
24
+ const styles = {
25
+ ...rest.style,
26
+ width: '100%'
27
+ };
28
+ return /*#__PURE__*/_jsx("svg", {
29
+ ref: svgRef,
30
+ ...rest,
31
+ style: styles
32
+ });
33
+ }
34
+ return /*#__PURE__*/_jsx("span", {
35
+ ...rest,
36
+ style: {
37
+ display: 'inline-block',
38
+ width: size,
39
+ height: size,
40
+ ...rest.style
41
+ },
42
+ children: /*#__PURE__*/_jsx("svg", {
43
+ ref: svgRef,
44
+ style: {
45
+ width: '100%'
46
+ }
47
+ })
48
+ });
49
+ }
50
+ DIDMotif.propTypes = {
51
+ did: PropTypes.string.isRequired,
52
+ size: PropTypes.number,
53
+ animation: PropTypes.bool,
54
+ // 直接返回 svg 元素, svg 尺寸由父窗口决定 (撑满父窗口)
55
+ responsive: PropTypes.bool,
56
+ shape: PropTypes.number
57
+ };
58
+ DIDMotif.defaultProps = {
59
+ size: 200,
60
+ animation: false,
61
+ responsive: false,
62
+ shape: null
63
+ };
64
+ export default DIDMotif;
@@ -0,0 +1,83 @@
1
+ /* eslint-disable prefer-destructuring */
2
+ /* eslint-disable no-bitwise */
3
+ // copy from https://etherscan.io/jss/blockies.js
4
+ const randseed = new Array(4);
5
+ function seedrand(seed) {
6
+ for (let i = 0; i < randseed.length; i++) {
7
+ randseed[i] = 0;
8
+ }
9
+ for (let i = 0; i < seed.length; i++) {
10
+ randseed[i % 4] = (randseed[i % 4] << 5) - randseed[i % 4] + seed.charCodeAt(i);
11
+ }
12
+ }
13
+ function rand() {
14
+ const t = randseed[0] ^ randseed[0] << 11;
15
+ randseed[0] = randseed[1];
16
+ randseed[1] = randseed[2];
17
+ randseed[2] = randseed[3];
18
+ randseed[3] = randseed[3] ^ randseed[3] >> 19 ^ t ^ t >> 8;
19
+ return (randseed[3] >>> 0) / (1 << 31 >>> 0);
20
+ }
21
+ function createColor() {
22
+ const h = Math.floor(rand() * 360);
23
+ const s = `${rand() * 60 + 40}%`;
24
+ const l = `${(rand() + rand() + rand() + rand()) * 25}%`;
25
+ const color = `hsl(${h},${s},${l})`;
26
+ return color;
27
+ }
28
+ function createImageData(size) {
29
+ const width = size;
30
+ const height = size;
31
+ const dataWidth = Math.ceil(width / 2);
32
+ const mirrorWidth = width - dataWidth;
33
+ const data = [];
34
+ for (let y = 0; y < height; y++) {
35
+ let row = [];
36
+ for (let x = 0; x < dataWidth; x++) {
37
+ row[x] = Math.floor(rand() * 2.3);
38
+ }
39
+ const r = row.slice(0, mirrorWidth);
40
+ r.reverse();
41
+ row = row.concat(r);
42
+ for (let i = 0; i < row.length; i++) {
43
+ data.push(row[i]);
44
+ }
45
+ }
46
+ return data;
47
+ }
48
+ function createCanvas(imageData, color, scale, bgcolor, spotcolor) {
49
+ const c = document.createElement('canvas');
50
+ const width = Math.sqrt(imageData.length);
51
+ // eslint-disable-next-line no-multi-assign
52
+ c.width = c.height = width * scale;
53
+ const cc = c.getContext('2d');
54
+ cc.fillStyle = bgcolor;
55
+ cc.fillRect(0, 0, c.width, c.height);
56
+ cc.fillStyle = color;
57
+ for (let i = 0; i < imageData.length; i++) {
58
+ const row = Math.floor(i / width);
59
+ const col = i % width;
60
+ cc.fillStyle = imageData[i] === 1 ? color : spotcolor;
61
+ if (imageData[i]) {
62
+ cc.fillRect(col * scale, row * scale, scale, scale);
63
+ }
64
+ }
65
+ return c;
66
+ }
67
+ function createIcon(opts) {
68
+ // eslint-disable-next-line no-param-reassign
69
+ opts = opts || {};
70
+ const size = opts.size || 8;
71
+ const scale = opts.scale || 4;
72
+ const seed = opts.seed || Math.floor(Math.random() * 10 ** 16).toString(16);
73
+ seedrand(seed);
74
+ const color = opts.color || createColor();
75
+ const bgcolor = opts.bgcolor || createColor();
76
+ const spotcolor = opts.spotcolor || createColor();
77
+ const imageData = createImageData(size);
78
+ const canvas = createCanvas(imageData, color, scale, bgcolor, spotcolor);
79
+ return canvas;
80
+ }
81
+ export default {
82
+ createIcon
83
+ };
@@ -0,0 +1,176 @@
1
+ /* eslint-disable react/no-unused-prop-types */
2
+ import { useState, useMemo } from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import { ErrorBoundary } from 'react-error-boundary';
5
+ import { Shape } from '@arcblock/did-motif';
6
+ import Box from '@mui/material/Box';
7
+ import Img from '../Img';
8
+ import { mergeProps, isEthereumDid } from '../Util';
9
+ import { styled } from '../Theme';
10
+ import DIDMotif from './did-motif';
11
+ import blockies from './etherscan-blockies';
12
+
13
+ /**
14
+ * Avatar component
15
+ * @typedef {{
16
+ * did: string;
17
+ * size?: number;
18
+ * variant?: 'circle' | 'rounded' | 'default';
19
+ * animation?: boolean;
20
+ * shape?: '' | 'rectangle' | 'square' | 'hexagon' | 'circle';
21
+ * src?: string;
22
+ * responsive?: boolean;
23
+ * }} AvatarProps
24
+ */
25
+
26
+ /**
27
+ * Avatar component
28
+ * @see 参考: https://github.com/blocklet/block-explorer/issues/478#issuecomment-1038954976
29
+ * @param {AvatarProps} props
30
+ * @returns {JSX.Element}
31
+ */
32
+ import { jsx as _jsx } from "react/jsx-runtime";
33
+ function Avatar(props) {
34
+ const [imgError, setImgError] = useState(false);
35
+ const newProps = mergeProps(props, Avatar, []);
36
+ const {
37
+ did = '',
38
+ size,
39
+ src,
40
+ variant,
41
+ animation,
42
+ shape,
43
+ blockiesPadding,
44
+ responsive,
45
+ ...rest
46
+ } = newProps;
47
+
48
+ // ethereum blockies
49
+ const blockyIcon = useMemo(() => {
50
+ if (isEthereumDid(did)) {
51
+ return blockies.createIcon({
52
+ seed: did.replace('did:abt:', '').toLowerCase(),
53
+ size: 8,
54
+ scale: 16
55
+ }).toDataURL();
56
+ }
57
+ return null;
58
+ }, [did]);
59
+
60
+ // 如果显式传入 src 则直接使用 src
61
+ if (src && !imgError) {
62
+ return /*#__PURE__*/_jsx(StyledImg, {
63
+ width: size,
64
+ src: src,
65
+ alt: did,
66
+ onError: () => setImgError(true),
67
+ ...rest,
68
+ className: `avatar-img--${variant} ${rest.className}`
69
+ });
70
+ }
71
+ // 对于 eth address, 渲染成 blocky icon, 形状与 account role type 的 did motif 相似都为矩形, 高宽比为 0.7
72
+ if (blockyIcon) {
73
+ if (blockiesPadding) {
74
+ // blocky icon 要与灰色卡片矩形留有空间
75
+ const padding = size > 24 ? 4 : 2;
76
+ return /*#__PURE__*/_jsx(BlockyIconContainer, {
77
+ $size: size,
78
+ ...rest,
79
+ children: /*#__PURE__*/_jsx("div", {
80
+ className: "blocky-icon-inner",
81
+ children: /*#__PURE__*/_jsx(Img, {
82
+ width: size * 0.7 - padding * 2,
83
+ src: blockyIcon,
84
+ alt: did
85
+ })
86
+ })
87
+ });
88
+ }
89
+ return /*#__PURE__*/_jsx(Img, {
90
+ width: size,
91
+ src: blockyIcon,
92
+ alt: did,
93
+ style: {
94
+ marginRight: 4
95
+ }
96
+ });
97
+ }
98
+ if (did) {
99
+ // 渲染 did motif
100
+ return /*#__PURE__*/_jsx(DIDMotif, {
101
+ did: did.replace('did:abt:', ''),
102
+ size: size,
103
+ animation: animation,
104
+ shape: Shape[(shape || '').toUpperCase()],
105
+ responsive: responsive,
106
+ ...rest
107
+ });
108
+ }
109
+ throw new Error(`Invalid DID: ${did}`);
110
+ }
111
+ Avatar.propTypes = {
112
+ did: PropTypes.string.isRequired,
113
+ size: PropTypes.number,
114
+ variant: PropTypes.oneOf(['circle', 'rounded', 'default']),
115
+ // animation 仅对 did motif 有效
116
+ animation: PropTypes.bool,
117
+ // shape 仅对 did motif 有效, 明确指定 motif shape, 而非由 did role type 自动推断 shape
118
+ shape: PropTypes.oneOf(['', 'rectangle', 'square', 'hexagon', 'circle']),
119
+ blockiesPadding: PropTypes.bool,
120
+ responsive: PropTypes.bool
121
+ };
122
+ Avatar.defaultProps = {
123
+ size: 36,
124
+ variant: 'default',
125
+ animation: false,
126
+ blockiesPadding: true,
127
+ shape: '',
128
+ responsive: false
129
+ };
130
+ const BlockyIconContainer = styled('div')`
131
+ display: flex;
132
+ align-items: center;
133
+ width: ${props => props.$size}px;
134
+ height: ${props => props.$size}px;
135
+ .blocky-icon-inner {
136
+ box-sizing: border-box;
137
+ display: flex;
138
+ justify-content: center;
139
+ align-items: center;
140
+ width: ${props => props.$size}px;
141
+ height: ${props => props.$size * 0.7}px;
142
+ border-radius: ${props => Math.min(10, Math.floor(0.1 * props.$size + 2))}px;
143
+ background: #ddd;
144
+ }
145
+ `;
146
+ const StyledImg = styled(Img)`
147
+ &.avatar-img--rounded {
148
+ border-radius: 4px;
149
+ overflow: hidden;
150
+ }
151
+ &.avatar-img--circle {
152
+ border-radius: 100%;
153
+ overflow: hidden;
154
+ }
155
+ `;
156
+ export default function AvatarWithErrorBoundary(props) {
157
+ const size = props.size || 36;
158
+ const borderRadius = {
159
+ rounded: '4px',
160
+ circle: '100%'
161
+ }[props.variant] || 0;
162
+ return /*#__PURE__*/_jsx(ErrorBoundary
163
+ // eslint-disable-next-line react/no-unstable-nested-components
164
+ , {
165
+ fallbackRender: () => /*#__PURE__*/_jsx(Box, {
166
+ width: size,
167
+ height: size,
168
+ bgcolor: "grey.300",
169
+ borderRadius: borderRadius
170
+ }),
171
+ children: /*#__PURE__*/_jsx(Avatar, {
172
+ ...props
173
+ })
174
+ });
175
+ }
176
+ AvatarWithErrorBoundary.propTypes = Avatar.propTypes;
@@ -0,0 +1,98 @@
1
+ import { forwardRef } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import Typography from '@mui/material/Typography';
4
+ import colors from '../Colors';
5
+ import { mergeProps } from '../Util';
6
+ import { withDeprecated } from '../Util/deprecate';
7
+ import { styled } from '../Theme';
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ const types = {
10
+ error: {
11
+ color: colors.common.white,
12
+ backgroundColor: colors.error.main
13
+ },
14
+ warning: {
15
+ color: colors.common.white,
16
+ backgroundColor: colors.warning.main
17
+ },
18
+ success: {
19
+ color: colors.common.white,
20
+ backgroundColor: colors.success.main
21
+ },
22
+ primary: {
23
+ color: colors.common.white,
24
+ backgroundColor: colors.primary.main
25
+ },
26
+ reverse: {
27
+ color: colors.common.white,
28
+ backgroundColor: colors.grey[900]
29
+ }
30
+ };
31
+
32
+ /**
33
+ * Badge component to display notification badge
34
+ * @typedef {{
35
+ * children: import('react').ReactNode;
36
+ * content?: string;
37
+ * type?: 'error' | 'warning' | 'success' | 'primary' | 'reverse';
38
+ * className?: string;
39
+ * style?: object | string;
40
+ * } & import('@mui/material').TypographyProps } BadgeProps
41
+ */
42
+
43
+ /**
44
+ * Badge notification component
45
+ * @param {BadgeProps} props
46
+ * @returns {JSX.Element}
47
+ */
48
+ function Badge(props) {
49
+ const newProps = mergeProps(props, Badge, ['style']);
50
+ const {
51
+ type,
52
+ content,
53
+ children,
54
+ style,
55
+ className,
56
+ forwardedRef,
57
+ ...rest
58
+ } = newProps;
59
+ const styles = Object.assign(types[type] || types.primary, style);
60
+ return /*#__PURE__*/_jsx(Span, {
61
+ ref: forwardedRef,
62
+ component: "span",
63
+ className: className,
64
+ style: styles,
65
+ ...rest,
66
+ children: content || children
67
+ });
68
+ }
69
+ Badge.propTypes = {
70
+ children: PropTypes.any.isRequired,
71
+ content: PropTypes.string,
72
+ type: PropTypes.oneOf(Object.keys(types)),
73
+ className: PropTypes.string,
74
+ style: PropTypes.oneOfType([PropTypes.object, PropTypes.string])
75
+ };
76
+ Badge.defaultProps = {
77
+ type: 'primary',
78
+ content: '',
79
+ className: '',
80
+ style: '{}'
81
+ };
82
+ export default withDeprecated( /*#__PURE__*/forwardRef((props, ref) => /*#__PURE__*/_jsx(Badge, {
83
+ ...props,
84
+ forwardedRef: ref
85
+ })), {
86
+ name: 'Badge',
87
+ alternative: '@arcblock/ux/lib/Tag'
88
+ });
89
+ const Span = styled(Typography)`
90
+ && {
91
+ display: inline-flex;
92
+ justify-content: center;
93
+ align-items: center;
94
+ padding: 2px 10px;
95
+ height: 24px;
96
+ line-height: 24px;
97
+ }
98
+ `;