@arcblock/ux 2.4.44 → 2.4.46

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.
package/lib/index.js CHANGED
@@ -15,6 +15,12 @@ Object.defineProperty(exports, "ActivityIndicator", {
15
15
  return _ActivityIndicator.default;
16
16
  }
17
17
  });
18
+ Object.defineProperty(exports, "Address", {
19
+ enumerable: true,
20
+ get: function get() {
21
+ return _Address.default;
22
+ }
23
+ });
18
24
  Object.defineProperty(exports, "Alert", {
19
25
  enumerable: true,
20
26
  get: function get() {
@@ -33,6 +39,12 @@ Object.defineProperty(exports, "Async", {
33
39
  return _Async.default;
34
40
  }
35
41
  });
42
+ Object.defineProperty(exports, "Avatar", {
43
+ enumerable: true,
44
+ get: function get() {
45
+ return _Avatar.default;
46
+ }
47
+ });
36
48
  Object.defineProperty(exports, "Badge", {
37
49
  enumerable: true,
38
50
  get: function get() {
@@ -75,6 +87,18 @@ Object.defineProperty(exports, "Datatable", {
75
87
  return _Datatable.default;
76
88
  }
77
89
  });
90
+ Object.defineProperty(exports, "Dialog", {
91
+ enumerable: true,
92
+ get: function get() {
93
+ return _Dialog.default;
94
+ }
95
+ });
96
+ Object.defineProperty(exports, "DidLogo", {
97
+ enumerable: true,
98
+ get: function get() {
99
+ return _DidLogo.default;
100
+ }
101
+ });
78
102
  Object.defineProperty(exports, "Earth", {
79
103
  enumerable: true,
80
104
  get: function get() {
@@ -117,6 +141,12 @@ Object.defineProperty(exports, "RelativeTime", {
117
141
  return _RelativeTime.default;
118
142
  }
119
143
  });
144
+ Object.defineProperty(exports, "SessionManager", {
145
+ enumerable: true,
146
+ get: function get() {
147
+ return _SessionManager.default;
148
+ }
149
+ });
120
150
  Object.defineProperty(exports, "Tabs", {
121
151
  enumerable: true,
122
152
  get: function get() {
@@ -171,6 +201,12 @@ Object.defineProperty(exports, "WalletDownload", {
171
201
  return _Download.default;
172
202
  }
173
203
  });
204
+ Object.defineProperty(exports, "WebWalletSWKeeper", {
205
+ enumerable: true,
206
+ get: function get() {
207
+ return _WebWalletSWKeeper.default;
208
+ }
209
+ });
174
210
  Object.defineProperty(exports, "WechatPrompt", {
175
211
  enumerable: true,
176
212
  get: function get() {
@@ -194,12 +230,16 @@ var _ActionButton = _interopRequireDefault(require("./ActionButton"));
194
230
 
195
231
  var _ActivityIndicator = _interopRequireDefault(require("./ActivityIndicator"));
196
232
 
233
+ var _Address = _interopRequireDefault(require("./Address"));
234
+
197
235
  var _Alert = _interopRequireDefault(require("./Alert"));
198
236
 
199
237
  var _AnimationWaiter = _interopRequireDefault(require("./AnimationWaiter"));
200
238
 
201
239
  var _Async = _interopRequireDefault(require("./Async"));
202
240
 
241
+ var _Avatar = _interopRequireDefault(require("./Avatar"));
242
+
203
243
  var _Badge = _interopRequireDefault(require("./Badge"));
204
244
 
205
245
  var _Button = _interopRequireDefault(require("./Button"));
@@ -224,8 +264,14 @@ var _Logo = _interopRequireDefault(require("./Logo"));
224
264
 
225
265
  var _RelativeTime = _interopRequireDefault(require("./RelativeTime"));
226
266
 
267
+ var _SessionManager = _interopRequireDefault(require("./SessionManager"));
268
+
227
269
  var _Datatable = _interopRequireDefault(require("./Datatable"));
228
270
 
271
+ var _Dialog = _interopRequireDefault(require("./Dialog"));
272
+
273
+ var _DidLogo = _interopRequireDefault(require("./DidLogo"));
274
+
229
275
  var _Tabs = _interopRequireDefault(require("./Tabs"));
230
276
 
231
277
  var _Tag = _interopRequireDefault(require("./Tag"));
@@ -240,6 +286,8 @@ var _Util = _interopRequireDefault(require("./Util"));
240
286
 
241
287
  var _Video = _interopRequireDefault(require("./Video"));
242
288
 
289
+ var _WebWalletSWKeeper = _interopRequireDefault(require("./WebWalletSWKeeper"));
290
+
243
291
  var _Action = _interopRequireDefault(require("./Wallet/Action"));
244
292
 
245
293
  var _Download = _interopRequireDefault(require("./Wallet/Download"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ux",
3
- "version": "2.4.44",
3
+ "version": "2.4.46",
4
4
  "description": "Common used react components for arcblock products",
5
5
  "keywords": [
6
6
  "react",
@@ -47,14 +47,16 @@
47
47
  "react": ">=18.1.0",
48
48
  "react-ga": "^2.7.0"
49
49
  },
50
- "gitHead": "83a9031c15ca6eca79656f0fb76d4ed2c44cf041",
50
+ "gitHead": "4d17961e1473b89161b14d574e5cfade7287939b",
51
51
  "dependencies": {
52
- "@arcblock/icons": "^2.4.44",
53
- "@arcblock/react-hooks": "^2.4.44",
52
+ "@arcblock/did-motif": "^1.1.10",
53
+ "@arcblock/icons": "^2.4.46",
54
+ "@arcblock/react-hooks": "^2.4.46",
54
55
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
55
56
  "@emotion/react": "^11.10.4",
56
57
  "@emotion/styled": "^11.10.4",
57
58
  "@fontsource/lato": "^4.5.10",
59
+ "@fontsource/ubuntu-mono": "^4.5.11",
58
60
  "@mui/icons-material": "^5.10.6",
59
61
  "@mui/material": "^5.10.8",
60
62
  "@solana/qr-code-styling": "^1.6.0-beta.0",
@@ -0,0 +1,77 @@
1
+ import { Children } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import Tooltip, { tooltipClasses } from '@mui/material/Tooltip';
4
+ import Box from '@mui/material/Box';
5
+ import { styled } from '../Theme';
6
+ import { CopyButton } from '../ClickToCopy';
7
+
8
+ const StyledTooltip = styled(({ className, ...props }) => <Tooltip {...props} classes={{ popper: className }} />)({
9
+ [`& .${tooltipClasses.tooltip}`]: {
10
+ maxWidth: 360,
11
+ wordBreak: 'break-all',
12
+ },
13
+ });
14
+
15
+ // 递归, 将 text (string) 部分替换为 CompactText (保持元素结构)
16
+ // eslint-disable-next-line react/prop-types
17
+ function RecursiveWrapper({ children, ...rest }) {
18
+ const wrappedChildren = Children.map(children, (child) => {
19
+ if (typeof child === 'string') {
20
+ return <CompactText {...rest}>{child}</CompactText>;
21
+ }
22
+ if (child.props && child.props.children) {
23
+ return (
24
+ <child.type {...child.props}>
25
+ <RecursiveWrapper {...rest}>{child.props.children}</RecursiveWrapper>
26
+ </child.type>
27
+ );
28
+ }
29
+ return child;
30
+ });
31
+ return wrappedChildren;
32
+ }
33
+
34
+ /**
35
+ * 紧凑文本组件 (显示首尾, 中间截断显示省略号), 仅考虑等宽字体的情况
36
+ */
37
+ export default function CompactText({ startChars, endChars, children, showCopyButtonInTooltip }) {
38
+ if (typeof children !== 'string') {
39
+ return (
40
+ <RecursiveWrapper startChars={startChars} endChars={endChars} showCopyButtonInTooltip={showCopyButtonInTooltip}>
41
+ {children}
42
+ </RecursiveWrapper>
43
+ );
44
+ }
45
+
46
+ // stopPropagation: 当 tooltip 处于 link 中时, 避免点击复制时触发链接跳转
47
+ const tooltipContent = (
48
+ <Box display="flex" alignItems="center" lineHeight={1} onClick={(e) => e.stopPropagation()}>
49
+ <Box>{children}</Box>
50
+ {showCopyButtonInTooltip && (
51
+ <CopyButton content={children} showTooltip={false} style={{ fontSize: 16, marginLeft: 4 }} />
52
+ )}
53
+ </Box>
54
+ );
55
+
56
+ return (
57
+ <StyledTooltip title={tooltipContent} placement="top">
58
+ <span>
59
+ {children.slice(0, startChars)}...{children.slice(children.length - endChars)}
60
+ </span>
61
+ </StyledTooltip>
62
+ );
63
+ }
64
+
65
+ CompactText.propTypes = {
66
+ startChars: PropTypes.number,
67
+ endChars: PropTypes.number,
68
+ children: PropTypes.node.isRequired,
69
+ // 在 tooltip 中完整地址后显示复制按钮
70
+ showCopyButtonInTooltip: PropTypes.bool,
71
+ };
72
+
73
+ CompactText.defaultProps = {
74
+ startChars: 6,
75
+ endChars: 6,
76
+ showCopyButtonInTooltip: false,
77
+ };
@@ -0,0 +1,215 @@
1
+ import { useRef, useState, forwardRef } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import '@fontsource/ubuntu-mono/400.css';
4
+ import useMountedState from 'react-use/lib/useMountedState';
5
+ import Tooltip from '@mui/material/Tooltip';
6
+ import { green } from '@mui/material/colors';
7
+ import copy from 'copy-to-clipboard';
8
+ import CopyIcon from '@mui/icons-material/ContentCopy';
9
+ import CheckIcon from '@mui/icons-material/Check';
10
+ import { styled } from '../Theme';
11
+
12
+ import CompactText from './compact-text';
13
+
14
+ export const formatAddress = (str) => str.split(':').pop();
15
+
16
+ const translations = {
17
+ en: {
18
+ copy: 'Click To Copy',
19
+ copied: 'Copied!',
20
+ },
21
+ zh: {
22
+ copy: '点击复制',
23
+ copied: '已复制!',
24
+ },
25
+ };
26
+
27
+ /**
28
+ * DidAddress 组件 (新版设计)
29
+ *
30
+ * - 样式调整
31
+ * - click-to-copy 调整
32
+ * - 长文本截断处理 (Ellipsis)
33
+ * - 支持 inline 或 block 的显示方式
34
+ * - 支持紧凑模式, 该模式下:
35
+ * - 占用宽度较小, 因此不考虑水平空间不够用的情况, 且忽略末尾省略号
36
+ * - 对于多层元素结构的 children, 保持元素结构, 将最内层 text 替换为 CompactText 组件
37
+ * - 为保证 copy 功能正常工作, 原 children 始终渲染, 但在紧凑式下会隐藏
38
+ * - 可配合 useMediaQuery 使用
39
+ */
40
+ const DidAddress = forwardRef(
41
+ (
42
+ {
43
+ component,
44
+ size,
45
+ copyable,
46
+ content,
47
+ children,
48
+ prepend,
49
+ append,
50
+ compact,
51
+ startChars,
52
+ endChars,
53
+ locale,
54
+ showCopyButtonInTooltip,
55
+ ...rest
56
+ },
57
+ ref
58
+ ) => {
59
+ if (!translations[locale]) {
60
+ // eslint-disable-next-line no-param-reassign
61
+ locale = 'en';
62
+ }
63
+ // 避免 unmounted 后 setTimeout handler 依然改变 state
64
+ const isMounted = useMountedState();
65
+
66
+ const [copied, setCopied] = useState(false);
67
+ const textRef = useRef();
68
+ const onCopy = (e) => {
69
+ e.stopPropagation();
70
+ copy(content || textRef.current.textContent);
71
+ setCopied(true);
72
+ // 恢复 copied 状态
73
+ setTimeout(() => {
74
+ if (isMounted()) {
75
+ setCopied(false);
76
+ }
77
+ }, 1500);
78
+ };
79
+
80
+ let copyElement = null;
81
+ if (copyable) {
82
+ copyElement = (
83
+ <span className="did-address-copy-wrapper" title={copied ? '' : translations[locale].copy}>
84
+ {copied ? (
85
+ <Tooltip title={translations[locale].copied} placement="bottom" arrow open={copied}>
86
+ <CheckIcon className="did-address-copy" style={{ color: green[500] }} />
87
+ </Tooltip>
88
+ ) : (
89
+ /* title prop 直接加在 icon 上不生效 */
90
+ <CopyIcon className="did-address-copy" onClick={onCopy} />
91
+ )}
92
+ </span>
93
+ );
94
+ }
95
+
96
+ return (
97
+ <Root as={component} size={size} {...rest} ref={ref}>
98
+ {prepend}
99
+ {/* 注意: 该元素必须渲染(可以隐藏), 以便 compact 模式下复制的文本是完整的 */}
100
+ <span
101
+ ref={textRef}
102
+ className="did-address-text did-address-truncate"
103
+ style={{ display: compact ? 'none' : 'inline' }}>
104
+ {children}
105
+ </span>
106
+ {compact && (
107
+ <span className="did-address-text">
108
+ <CompactText startChars={startChars} endChars={endChars} showCopyButtonInTooltip={showCopyButtonInTooltip}>
109
+ {children}
110
+ </CompactText>
111
+ </span>
112
+ )}
113
+ {copyElement}
114
+ {append}
115
+ </Root>
116
+ );
117
+ }
118
+ );
119
+
120
+ export default DidAddress;
121
+
122
+ DidAddress.propTypes = {
123
+ component: PropTypes.string,
124
+ size: PropTypes.number,
125
+ copyable: PropTypes.bool,
126
+ // compact mode 下, hover 时会在 tooltip 中显示完整地址, showCopyButtonInTooltip = true 时会在完整地址后显示一个复制按钮
127
+ showCopyButtonInTooltip: PropTypes.bool,
128
+ children: PropTypes.any,
129
+ content: PropTypes.string,
130
+ inline: PropTypes.bool,
131
+ prepend: PropTypes.any,
132
+ append: PropTypes.any,
133
+ // 紧凑模式
134
+ compact: PropTypes.bool,
135
+ startChars: PropTypes.number,
136
+ endChars: PropTypes.number,
137
+ locale: PropTypes.oneOf(['en', 'zh']),
138
+ };
139
+
140
+ DidAddress.defaultProps = {
141
+ component: 'span',
142
+ size: 0,
143
+ copyable: true,
144
+ showCopyButtonInTooltip: false,
145
+ children: null,
146
+ content: '',
147
+ inline: false,
148
+ prepend: null,
149
+ append: null,
150
+ compact: false,
151
+ startChars: 6,
152
+ endChars: 6,
153
+ locale: 'en',
154
+ };
155
+
156
+ const getFontSize = (size) => {
157
+ // 12px 及以上的 size 有效, 否则返回 inherit
158
+ if (size && Number(size) >= 12) {
159
+ return `${Number(size)}px`;
160
+ }
161
+ return 'inherit';
162
+ };
163
+
164
+ const Root = styled('div', { shouldForwardProp: (prop) => prop !== 'inline' })`
165
+ font-family: 'Ubuntu Mono', monospace;
166
+ && {
167
+ display: ${({ inline }) => (inline ? 'inline-flex' : 'flex')};
168
+ align-items: center;
169
+ max-width: 100%;
170
+ overflow: hidden;
171
+ color: #ccc;
172
+ font-size: ${(props) => getFontSize(props.size)};
173
+ font-weight: 400;
174
+
175
+ svg {
176
+ fill: currentColor;
177
+ }
178
+ }
179
+
180
+ .did-address-text {
181
+ color: #666;
182
+ }
183
+ /* truncate string with ellipsis */
184
+ .did-address-truncate {
185
+ white-space: nowrap;
186
+ overflow: hidden;
187
+ text-overflow: ellipsis;
188
+ }
189
+
190
+ .did-address-copy {
191
+ flex: 0 0 auto;
192
+ }
193
+ .did-address-copy-wrapper {
194
+ display: flex;
195
+ justify-content: center;
196
+ align-items: center;
197
+ width: 1em;
198
+ height: 1em;
199
+ margin-left: 8px;
200
+ }
201
+ .did-address-copy {
202
+ font-size: 1em;
203
+ color: #999;
204
+ cursor: pointer;
205
+ }
206
+
207
+ /* link */
208
+ a {
209
+ color: #666;
210
+ }
211
+ &:hover a {
212
+ color: #222;
213
+ text-decoration: underline;
214
+ }
215
+ `;
@@ -0,0 +1,22 @@
1
+ import PropTypes from 'prop-types';
2
+ import DidAddress from './did-address';
3
+ import ResponsiveDidAddress from './responsive-did-address';
4
+
5
+ export const formatAddress = (str) => str.split(':').pop();
6
+
7
+ function DidAddressWrapper({ responsive, ...rest }) {
8
+ if (responsive) {
9
+ return <ResponsiveDidAddress {...rest} />;
10
+ }
11
+ return <DidAddress {...rest} />;
12
+ }
13
+
14
+ export default DidAddressWrapper;
15
+
16
+ DidAddressWrapper.propTypes = {
17
+ responsive: PropTypes.bool,
18
+ };
19
+
20
+ DidAddressWrapper.defaultProps = {
21
+ responsive: true,
22
+ };
@@ -0,0 +1,77 @@
1
+ import { useState, createRef, useEffect } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import useMeasure from 'react-use/lib/useMeasure';
4
+ import { styled } from '../Theme';
5
+
6
+ import DidAddress from './did-address';
7
+
8
+ /**
9
+ * 根据父容器宽度自动切换 compact 模式
10
+ *
11
+ * 实现逻辑:
12
+ * - DidAddress 外层包裹一个容器, 其宽度自动撑满父容器宽度 (即这个容器需要是块级元素或 100% 宽的 inline-block)
13
+ * - DidAddress 本身以 inlne 形式渲染 (方便探测 did-address 的 full-width)
14
+ * - 组件 mounted 时记录 did address 的 full-width (非 compact 模式的宽度)
15
+ * - 监听容器宽度变化, 当容器宽度变化时, 对比容器宽度和 did address full-width, => 切换 compact 模式
16
+ * - TODO: 初始化时, 在确定是否应该以 compact 模式渲染前, 隐藏显示, 避免闪烁问题
17
+ */
18
+ export default function ResponsiveDidAddress({ style, className, component, ...rest }) {
19
+ const [compact, setCompact] = useState(false);
20
+ // did address 完整显示时的宽度
21
+ const [addressFullWidth, setAddressFullWidth] = useState(null);
22
+ const [containerRef, { width: containerWidth }] = useMeasure();
23
+ const ref = createRef();
24
+ // 存储完整显示时 address 组件的宽度
25
+ useEffect(() => {
26
+ if (!compact && addressFullWidth === null) {
27
+ setAddressFullWidth(ref.current.offsetWidth);
28
+ }
29
+ // eslint-disable-next-line react-hooks/exhaustive-deps
30
+ }, []);
31
+
32
+ useEffect(() => {
33
+ if (containerWidth && addressFullWidth) {
34
+ setCompact(containerWidth < addressFullWidth);
35
+ }
36
+ }, [containerWidth, addressFullWidth]);
37
+ return (
38
+ <Root as={component} inline={rest.inline} ref={containerRef} style={style} className={className}>
39
+ <StyledDidAddress {...rest} component={component} inline compact={compact} ref={ref} />
40
+ </Root>
41
+ );
42
+ }
43
+
44
+ ResponsiveDidAddress.propTypes = {
45
+ style: PropTypes.object,
46
+ className: PropTypes.string,
47
+ component: PropTypes.string,
48
+ };
49
+
50
+ ResponsiveDidAddress.defaultProps = {
51
+ style: {},
52
+ className: '',
53
+ component: 'span',
54
+ };
55
+
56
+ const Root = styled('div')`
57
+ display: block;
58
+ overflow: hidden;
59
+ ${({ inline }) =>
60
+ inline &&
61
+ `
62
+ display: inline-block;
63
+ width: 100%;
64
+ `}
65
+ `;
66
+
67
+ const StyledDidAddress = styled(DidAddress)`
68
+ && {
69
+ max-width: none;
70
+ }
71
+ .did-address-text {
72
+ /* 禁止文本 Ellipsis/截断, 以便测量真实的宽度 */
73
+ white-space: nowrap;
74
+ overflow: visible;
75
+ text-overflow: unset;
76
+ }
77
+ `;
@@ -0,0 +1,40 @@
1
+ import { useRef, useLayoutEffect } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { update } from '@arcblock/did-motif';
4
+
5
+ function DIDMotif({ did, size, animation, shape, responsive, ...rest }) {
6
+ const svgRef = useRef(null);
7
+
8
+ useLayoutEffect(() => {
9
+ update(svgRef.current, did, { size, animation, shape });
10
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11
+ }, [did, size, shape]);
12
+ if (responsive) {
13
+ // fix avatar 显示问题 (safari 下父容器为 flex 时 inline svg 显示不出来, 需要明确指定 width)
14
+ const styles = { ...rest.style, width: '100%' };
15
+ return <svg ref={svgRef} {...rest} style={styles} />;
16
+ }
17
+ return (
18
+ <span {...rest} style={{ display: 'inline-block', width: size, height: size, ...rest.style }}>
19
+ <svg ref={svgRef} />
20
+ </span>
21
+ );
22
+ }
23
+
24
+ DIDMotif.propTypes = {
25
+ did: PropTypes.string.isRequired,
26
+ size: PropTypes.number,
27
+ animation: PropTypes.bool,
28
+ // 直接返回 svg 元素, svg 尺寸由父窗口决定 (撑满父窗口)
29
+ responsive: PropTypes.bool,
30
+ shape: PropTypes.number,
31
+ };
32
+
33
+ DIDMotif.defaultProps = {
34
+ size: 200,
35
+ animation: false,
36
+ responsive: false,
37
+ shape: null,
38
+ };
39
+
40
+ export default DIDMotif;
@@ -0,0 +1,81 @@
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 { createIcon };