@reown/appkit-ui-react-native 0.0.0-chore-added-import-20251002170458 → 0.0.0-chore-qr-borders-20251104183806

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 (28) hide show
  1. package/lib/commonjs/assets/svg/WalletConnect.js +4 -5
  2. package/lib/commonjs/assets/svg/WalletConnect.js.map +1 -1
  3. package/lib/commonjs/composites/wui-qr-code/index.js +51 -19
  4. package/lib/commonjs/composites/wui-qr-code/index.js.map +1 -1
  5. package/lib/commonjs/composites/wui-qr-code/styles.js +0 -3
  6. package/lib/commonjs/composites/wui-qr-code/styles.js.map +1 -1
  7. package/lib/commonjs/utils/QRCodeUtil.js +222 -116
  8. package/lib/commonjs/utils/QRCodeUtil.js.map +1 -1
  9. package/lib/module/assets/svg/WalletConnect.js +4 -5
  10. package/lib/module/assets/svg/WalletConnect.js.map +1 -1
  11. package/lib/module/composites/wui-qr-code/index.js +50 -19
  12. package/lib/module/composites/wui-qr-code/index.js.map +1 -1
  13. package/lib/module/composites/wui-qr-code/styles.js +0 -3
  14. package/lib/module/composites/wui-qr-code/styles.js.map +1 -1
  15. package/lib/module/utils/QRCodeUtil.js +221 -116
  16. package/lib/module/utils/QRCodeUtil.js.map +1 -1
  17. package/lib/typescript/assets/svg/WalletConnect.d.ts.map +1 -1
  18. package/lib/typescript/composites/wui-qr-code/index.d.ts +3 -1
  19. package/lib/typescript/composites/wui-qr-code/index.d.ts.map +1 -1
  20. package/lib/typescript/composites/wui-qr-code/styles.d.ts +0 -3
  21. package/lib/typescript/composites/wui-qr-code/styles.d.ts.map +1 -1
  22. package/lib/typescript/utils/QRCodeUtil.d.ts +22 -2
  23. package/lib/typescript/utils/QRCodeUtil.d.ts.map +1 -1
  24. package/package.json +2 -2
  25. package/src/assets/svg/WalletConnect.tsx +4 -5
  26. package/src/composites/wui-qr-code/index.tsx +75 -16
  27. package/src/composites/wui-qr-code/styles.ts +0 -3
  28. package/src/utils/QRCodeUtil.tsx +273 -142
@@ -1,15 +1,32 @@
1
- import type { ReactNode } from 'react';
2
- import { Line, Rect, Circle } from 'react-native-svg';
3
1
  import QRCode from 'qrcode';
4
- import { LightTheme } from '../utils/ThemeUtil';
5
-
6
- type CoordinateMapping = [number, number[]];
7
2
 
8
3
  const CONNECTING_ERROR_MARGIN = 0.1;
9
4
  const CIRCLE_SIZE_MODIFIER = 2.5;
10
5
  const QRCODE_MATRIX_MARGIN = 7;
6
+ const LOGO_PADDING = 25;
7
+
8
+ export interface QRData {
9
+ rects: {
10
+ x: number;
11
+ y: number;
12
+ size: number;
13
+ fillType: 'dot' | 'edge';
14
+ }[];
15
+ circles: {
16
+ cx: number;
17
+ cy: number;
18
+ r: number;
19
+ }[];
20
+ lines: {
21
+ x1: number;
22
+ x2: number;
23
+ y1: number;
24
+ y2: number;
25
+ strokeWidth: number;
26
+ }[];
27
+ }
11
28
 
12
- function isAdjecentDots(cy: number, otherCy: number, cellSize: number) {
29
+ function isAdjacentDots(cy: number, otherCy: number, cellSize: number) {
13
30
  if (cy === otherCy) {
14
31
  return false;
15
32
  }
@@ -18,7 +35,10 @@ function isAdjecentDots(cy: number, otherCy: number, cellSize: number) {
18
35
  return diff <= cellSize + CONNECTING_ERROR_MARGIN;
19
36
  }
20
37
 
21
- function getMatrix(value: string, errorCorrectionLevel: QRCode.QRCodeErrorCorrectionLevel) {
38
+ function getMatrix(
39
+ value: string,
40
+ errorCorrectionLevel: QRCode.QRCodeErrorCorrectionLevel
41
+ ): boolean[][] {
22
42
  const arr = Array.prototype.slice.call(
23
43
  QRCode.create(value, { errorCorrectionLevel }).modules.data,
24
44
  0
@@ -32,154 +52,265 @@ function getMatrix(value: string, errorCorrectionLevel: QRCode.QRCodeErrorCorrec
32
52
  );
33
53
  }
34
54
 
35
- export const QRCodeUtil = {
36
- generate(uri: string, size: number, logoSize: number) {
37
- const dotColor = LightTheme['inverse-000'];
38
- const edgeColor = LightTheme['inverse-100'];
39
- const dots: ReactNode[] = [];
40
- const matrix = getMatrix(uri, 'Q');
41
- const cellSize = size / matrix.length;
42
- const qrList = [
43
- { x: 0, y: 0 },
44
- { x: 1, y: 0 },
45
- { x: 0, y: 1 }
46
- ];
47
-
48
- qrList.forEach(({ x, y }) => {
49
- const x1 = (matrix.length - QRCODE_MATRIX_MARGIN) * cellSize * x;
50
- const y1 = (matrix.length - QRCODE_MATRIX_MARGIN) * cellSize * y;
51
- const borderRadius = 0.32;
52
- for (let i = 0; i < qrList.length; i += 1) {
53
- const dotSize = cellSize * (QRCODE_MATRIX_MARGIN - i * 2);
54
- dots.push(
55
- <Rect
56
- key={`rect_${x1 + cellSize * i}_${y1 + cellSize * i}`}
57
- fill={i % 2 === 0 ? dotColor : edgeColor}
58
- height={dotSize}
59
- rx={dotSize * borderRadius}
60
- ry={dotSize * borderRadius}
61
- width={dotSize}
62
- x={x1 + cellSize * i}
63
- y={y1 + cellSize * i}
64
- />
65
- );
55
+ function processQRMatrix(
56
+ matrix: boolean[][],
57
+ size: number,
58
+ logoSize: number,
59
+ logoBorderRadius?: number
60
+ ): QRData {
61
+ const matrixLength = matrix.length;
62
+ const cellSize = size / matrixLength;
63
+ const halfCellSize = cellSize / 2;
64
+ const strokeWidth = cellSize / (CIRCLE_SIZE_MODIFIER / 2);
65
+ const circleRadius = cellSize / CIRCLE_SIZE_MODIFIER;
66
+
67
+ const rects: QRData['rects'] = [];
68
+ const circles: QRData['circles'] = [];
69
+ const lines: QRData['lines'] = [];
70
+
71
+ // Generate corner rectangles - optimized with direct indexing
72
+ const qrList = [
73
+ { x: 0, y: 0 },
74
+ { x: 1, y: 0 },
75
+ { x: 0, y: 1 }
76
+ ];
77
+ const baseOffset = (matrixLength - QRCODE_MATRIX_MARGIN) * cellSize;
78
+
79
+ for (let qrIdx = 0; qrIdx < 3; qrIdx++) {
80
+ const qr = qrList[qrIdx];
81
+ if (!qr) continue;
82
+
83
+ const x1 = baseOffset * qr.x;
84
+ const y1 = baseOffset * qr.y;
85
+
86
+ for (let i = 0; i < 3; i++) {
87
+ const dotSize = cellSize * (QRCODE_MATRIX_MARGIN - i * 2);
88
+ rects.push({
89
+ x: x1 + cellSize * i,
90
+ y: y1 + cellSize * i,
91
+ size: dotSize,
92
+ fillType: i % 2 === 0 ? 'dot' : 'edge'
93
+ });
94
+ }
95
+ }
96
+
97
+ const circleCoords: [number, number][] = [];
98
+
99
+ // Determine if using circular or rounded rectangle hole
100
+ const isCircular = logoBorderRadius === undefined;
101
+ const effectiveBorderRadius = logoBorderRadius ?? (logoSize + LOGO_PADDING) / 2;
102
+
103
+ // Calculate circle coordinates - optimized with configurable hole shape
104
+ for (let i = 0; i < matrixLength; i++) {
105
+ const row = matrix[i];
106
+ if (!row) continue;
107
+
108
+ const rowLength = row.length;
109
+
110
+ for (let j = 0; j < rowLength; j++) {
111
+ if (!row[j]) continue;
112
+
113
+ // Skip corners check
114
+ if (
115
+ (i < QRCODE_MATRIX_MARGIN && j < QRCODE_MATRIX_MARGIN) ||
116
+ (i > matrixLength - (QRCODE_MATRIX_MARGIN + 1) && j < QRCODE_MATRIX_MARGIN) ||
117
+ (i < QRCODE_MATRIX_MARGIN && j > matrixLength - (QRCODE_MATRIX_MARGIN + 1))
118
+ ) {
119
+ continue;
66
120
  }
67
- });
68
-
69
- const clearArenaSize = Math.floor((logoSize + 25) / cellSize);
70
- const matrixMiddleStart = matrix.length / 2 - clearArenaSize / 2;
71
- const matrixMiddleEnd = matrix.length / 2 + clearArenaSize / 2 - 1;
72
- const circles: [number, number][] = [];
73
-
74
- // Getting coordinates for each of the QR code dots
75
- matrix.forEach((row: QRCode.QRCode[], i: number) => {
76
- row.forEach((_, j: number) => {
77
- if (matrix[i][j]) {
78
- if (
79
- !(
80
- (i < QRCODE_MATRIX_MARGIN && j < QRCODE_MATRIX_MARGIN) ||
81
- (i > matrix.length - (QRCODE_MATRIX_MARGIN + 1) && j < QRCODE_MATRIX_MARGIN) ||
82
- (i < QRCODE_MATRIX_MARGIN && j > matrix.length - (QRCODE_MATRIX_MARGIN + 1))
83
- )
84
- ) {
85
- if (
86
- !(
87
- i > matrixMiddleStart &&
88
- i < matrixMiddleEnd &&
89
- j > matrixMiddleStart &&
90
- j < matrixMiddleEnd
91
- )
92
- ) {
93
- const cx = i * cellSize + cellSize / 2;
94
- const cy = j * cellSize + cellSize / 2;
95
- circles.push([cx, cy]);
96
- }
97
- }
121
+
122
+ // Calculate pixel coordinates first
123
+ const cx = i * cellSize + halfCellSize;
124
+ const cy = j * cellSize + halfCellSize;
125
+
126
+ // Skip hole calculation if logoSize is 0 (arenaClear)
127
+ if (logoSize === 0) {
128
+ circleCoords.push([cx, cy]);
129
+ continue;
130
+ }
131
+
132
+ // Calculate distance from center in pixel space
133
+ const centerX = size / 2;
134
+ const centerY = size / 2;
135
+
136
+ let isOutsideLogoArea = false;
137
+
138
+ if (isCircular) {
139
+ // Circular hole
140
+ const dx = cx - centerX;
141
+ const dy = cy - centerY;
142
+ const distanceFromCenter = Math.sqrt(dx * dx + dy * dy);
143
+ const pixelRadius = (logoSize + LOGO_PADDING) / 2;
144
+ isOutsideLogoArea = distanceFromCenter >= pixelRadius;
145
+ } else {
146
+ // Rounded rectangle hole
147
+ const halfLogoArea = (logoSize + LOGO_PADDING) / 2;
148
+ const dx = Math.abs(cx - centerX);
149
+ const dy = Math.abs(cy - centerY);
150
+
151
+ // Check if point is outside the rounded rectangle
152
+ if (dx > halfLogoArea || dy > halfLogoArea) {
153
+ isOutsideLogoArea = true;
154
+ } else if (
155
+ dx > halfLogoArea - effectiveBorderRadius &&
156
+ dy > halfLogoArea - effectiveBorderRadius
157
+ ) {
158
+ // Check corner radius
159
+ const cornerDx = dx - (halfLogoArea - effectiveBorderRadius);
160
+ const cornerDy = dy - (halfLogoArea - effectiveBorderRadius);
161
+ const cornerDistance = Math.sqrt(cornerDx * cornerDx + cornerDy * cornerDy);
162
+ isOutsideLogoArea = cornerDistance >= effectiveBorderRadius;
163
+ } else {
164
+ isOutsideLogoArea = false;
98
165
  }
166
+ }
167
+
168
+ if (isOutsideLogoArea) {
169
+ circleCoords.push([cx, cy]);
170
+ }
171
+ }
172
+ }
173
+
174
+ // Build circlesToConnect - optimized loop
175
+ const circlesToConnect: Record<number, number[]> = {};
176
+ for (let k = 0; k < circleCoords.length; k++) {
177
+ const coord = circleCoords[k];
178
+ if (!coord) continue;
179
+
180
+ const [cx, cy] = coord;
181
+ const existing = circlesToConnect[cx];
182
+ if (existing) {
183
+ existing.push(cy);
184
+ } else {
185
+ circlesToConnect[cx] = [cy];
186
+ }
187
+ }
188
+
189
+ // Process circles and lines - optimized to avoid Object.entries
190
+ for (const cxKey in circlesToConnect) {
191
+ const cx = Number(cxKey);
192
+ const cys = circlesToConnect[cxKey];
193
+ if (!cys) continue;
194
+
195
+ if (cys.length === 1) {
196
+ const firstCy = cys[0];
197
+ if (firstCy === undefined) continue;
198
+
199
+ // Single dot, add as circle
200
+ circles.push({
201
+ cx,
202
+ cy: firstCy,
203
+ r: circleRadius
99
204
  });
100
- });
205
+ continue;
206
+ }
101
207
 
102
- // Cx to multiple cys
103
- const circlesToConnect: Record<number, number[]> = {};
208
+ // Sort once for line grouping
209
+ cys.sort((a, b) => a - b);
104
210
 
105
- // Mapping all dots cicles on the same x axis
106
- circles.forEach(([cx, cy]) => {
107
- if (circlesToConnect[cx]) {
108
- circlesToConnect[cx]?.push(cy);
109
- } else {
110
- circlesToConnect[cx] = [cy];
211
+ // Track which dots are connected and which are lonely
212
+ const isConnected = new Array(cys.length).fill(false);
213
+
214
+ // Find all adjacent pairs
215
+ for (let i = 0; i < cys.length - 1; i++) {
216
+ const currentCy = cys[i];
217
+ const nextCy = cys[i + 1];
218
+ if (
219
+ currentCy !== undefined &&
220
+ nextCy !== undefined &&
221
+ isAdjacentDots(currentCy, nextCy, cellSize)
222
+ ) {
223
+ isConnected[i] = true;
224
+ isConnected[i + 1] = true;
111
225
  }
112
- });
113
-
114
- // Drawing lonely dots
115
- Object.entries(circlesToConnect)
116
- // Only get dots that have neighbors
117
- .map(([cx, cys]) => {
118
- const newCys = cys.filter(cy =>
119
- cys.every(otherCy => !isAdjecentDots(cy, otherCy, cellSize))
120
- );
121
-
122
- return [Number(cx), newCys] as CoordinateMapping;
123
- })
124
- .forEach(([cx, cys]) => {
125
- cys.forEach(cy => {
126
- dots.push(
127
- <Circle
128
- key={`circle_${cx}_${cy}`}
129
- cx={cx}
130
- cy={cy}
131
- fill={dotColor}
132
- r={cellSize / CIRCLE_SIZE_MODIFIER}
133
- />
134
- );
226
+ }
227
+
228
+ // Add lonely dots as circles and build line groups
229
+ let groupStart = -1;
230
+ let groupEnd = -1;
231
+
232
+ for (let i = 0; i < cys.length; i++) {
233
+ const cy = cys[i];
234
+ if (cy === undefined) continue;
235
+
236
+ if (!isConnected[i]) {
237
+ // Lonely dot - add as circle
238
+ circles.push({
239
+ cx,
240
+ cy,
241
+ r: circleRadius
135
242
  });
136
- });
137
243
 
138
- // Drawing lines for dots that are close to each other
139
- Object.entries(circlesToConnect)
140
- // Only get dots that have more than one dot on the x axis
141
- .filter(([_, cys]) => cys.length > 1)
142
- // Removing dots with no neighbors
143
- .map(([cx, cys]) => {
144
- const newCys = cys.filter(cy => cys.some(otherCy => isAdjecentDots(cy, otherCy, cellSize)));
145
-
146
- return [Number(cx), newCys] as CoordinateMapping;
147
- })
148
- // Get the coordinates of the first and last dot of a line
149
- .map(([cx, cys]) => {
150
- cys.sort((a, b) => (a < b ? -1 : 1));
151
- const groups: number[][] = [];
152
-
153
- for (const cy of cys) {
154
- const group = groups.find(item =>
155
- item.some(otherCy => isAdjecentDots(cy, otherCy, cellSize))
156
- );
157
- if (group) {
158
- group.push(cy);
244
+ // Finish any ongoing line group
245
+ if (groupStart !== -1 && groupEnd !== -1 && groupStart !== groupEnd) {
246
+ lines.push({
247
+ x1: cx,
248
+ x2: cx,
249
+ y1: groupStart,
250
+ y2: groupEnd,
251
+ strokeWidth
252
+ });
253
+ }
254
+ groupStart = -1;
255
+ groupEnd = -1;
256
+ } else {
257
+ // Part of a line group
258
+ if (groupStart === -1) {
259
+ groupStart = cy;
260
+ groupEnd = cy;
261
+ } else {
262
+ // Check if adjacent to previous
263
+ const prevCy = cys[i - 1];
264
+ if (i > 0 && prevCy !== undefined && isAdjacentDots(cy, prevCy, cellSize)) {
265
+ groupEnd = cy;
159
266
  } else {
160
- groups.push([cy]);
267
+ // Gap in the group, finish previous line
268
+ if (groupStart !== groupEnd) {
269
+ lines.push({
270
+ x1: cx,
271
+ x2: cx,
272
+ y1: groupStart,
273
+ y2: groupEnd,
274
+ strokeWidth
275
+ });
276
+ }
277
+ groupStart = cy;
278
+ groupEnd = cy;
161
279
  }
162
280
  }
281
+ }
282
+ }
163
283
 
164
- return [cx, groups.map(item => [item[0], item[item.length - 1]])] as [number, number[][]];
165
- })
166
- .forEach(([cx, groups]) => {
167
- groups.forEach(([y1, y2]) => {
168
- dots.push(
169
- <Line
170
- key={`line_${cx}_${y1}_${y2}`}
171
- x1={cx}
172
- x2={cx}
173
- y1={y1}
174
- y2={y2}
175
- stroke={dotColor}
176
- strokeWidth={cellSize / (CIRCLE_SIZE_MODIFIER / 2)}
177
- strokeLinecap="round"
178
- />
179
- );
180
- });
284
+ // Don't forget the last group
285
+ if (groupStart !== -1 && groupEnd !== -1 && groupStart !== groupEnd) {
286
+ lines.push({
287
+ x1: cx,
288
+ x2: cx,
289
+ y1: groupStart,
290
+ y2: groupEnd,
291
+ strokeWidth
181
292
  });
293
+ }
294
+ }
182
295
 
183
- return dots;
296
+ return { rects, circles, lines };
297
+ }
298
+
299
+ export function generateQRData(
300
+ uri: string,
301
+ size: number,
302
+ logoSize: number,
303
+ logoBorderRadius?: number
304
+ ): QRData {
305
+ if (!uri || size <= 0) {
306
+ throw new Error('Invalid QR code parameters');
184
307
  }
308
+
309
+ const matrix = getMatrix(uri, 'Q');
310
+
311
+ return processQRMatrix(matrix, size, logoSize, logoBorderRadius);
312
+ }
313
+
314
+ export const QRCodeUtil = {
315
+ generate: generateQRData
185
316
  };