@reown/appkit-ui-react-native 0.0.0-develop-20251030154825 → 0.0.0-develop-20251114173726

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 +217 -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 +216 -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 +265 -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,257 @@ 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
+ const x1 = baseOffset * qr.x;
82
+ const y1 = baseOffset * qr.y;
83
+
84
+ for (let i = 0; i < 3; i++) {
85
+ const dotSize = cellSize * (QRCODE_MATRIX_MARGIN - i * 2);
86
+ rects.push({
87
+ x: x1 + cellSize * i,
88
+ y: y1 + cellSize * i,
89
+ size: dotSize,
90
+ fillType: i % 2 === 0 ? 'dot' : 'edge'
91
+ });
92
+ }
93
+ }
94
+
95
+ const circleCoords: [number, number][] = [];
96
+
97
+ // Determine if using circular or rounded rectangle hole
98
+ const isCircular = logoBorderRadius === undefined;
99
+ const effectiveBorderRadius = logoBorderRadius ?? (logoSize + LOGO_PADDING) / 2;
100
+
101
+ // Calculate circle coordinates - optimized with configurable hole shape
102
+ for (let i = 0; i < matrixLength; i++) {
103
+ const row = matrix[i]!;
104
+ const rowLength = row.length;
105
+
106
+ for (let j = 0; j < rowLength; j++) {
107
+ if (!row[j]) continue;
108
+
109
+ // Skip corners check
110
+ if (
111
+ (i < QRCODE_MATRIX_MARGIN && j < QRCODE_MATRIX_MARGIN) ||
112
+ (i > matrixLength - (QRCODE_MATRIX_MARGIN + 1) && j < QRCODE_MATRIX_MARGIN) ||
113
+ (i < QRCODE_MATRIX_MARGIN && j > matrixLength - (QRCODE_MATRIX_MARGIN + 1))
114
+ ) {
115
+ continue;
66
116
  }
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
- }
117
+
118
+ // Calculate pixel coordinates first
119
+ const cx = i * cellSize + halfCellSize;
120
+ const cy = j * cellSize + halfCellSize;
121
+
122
+ // Skip hole calculation if logoSize is 0 (arenaClear)
123
+ if (logoSize === 0) {
124
+ circleCoords.push([cx, cy]);
125
+ continue;
126
+ }
127
+
128
+ // Calculate distance from center in pixel space
129
+ const centerX = size / 2;
130
+ const centerY = size / 2;
131
+
132
+ let isOutsideLogoArea = false;
133
+
134
+ if (isCircular) {
135
+ // Circular hole
136
+ const dx = cx - centerX;
137
+ const dy = cy - centerY;
138
+ const distanceFromCenter = Math.sqrt(dx * dx + dy * dy);
139
+ const pixelRadius = (logoSize + LOGO_PADDING) / 2;
140
+ isOutsideLogoArea = distanceFromCenter >= pixelRadius;
141
+ } else {
142
+ // Rounded rectangle hole
143
+ const halfLogoArea = (logoSize + LOGO_PADDING) / 2;
144
+ const dx = Math.abs(cx - centerX);
145
+ const dy = Math.abs(cy - centerY);
146
+
147
+ // Check if point is outside the rounded rectangle
148
+ if (dx > halfLogoArea || dy > halfLogoArea) {
149
+ isOutsideLogoArea = true;
150
+ } else if (
151
+ dx > halfLogoArea - effectiveBorderRadius &&
152
+ dy > halfLogoArea - effectiveBorderRadius
153
+ ) {
154
+ // Check corner radius
155
+ const cornerDx = dx - (halfLogoArea - effectiveBorderRadius);
156
+ const cornerDy = dy - (halfLogoArea - effectiveBorderRadius);
157
+ const cornerDistance = Math.sqrt(cornerDx * cornerDx + cornerDy * cornerDy);
158
+ isOutsideLogoArea = cornerDistance >= effectiveBorderRadius;
159
+ } else {
160
+ isOutsideLogoArea = false;
98
161
  }
162
+ }
163
+
164
+ if (isOutsideLogoArea) {
165
+ circleCoords.push([cx, cy]);
166
+ }
167
+ }
168
+ }
169
+
170
+ // Build circlesToConnect - optimized loop
171
+ const circlesToConnect: Record<number, number[]> = {};
172
+ for (let k = 0; k < circleCoords.length; k++) {
173
+ const [cx, cy] = circleCoords[k]!;
174
+ const existing = circlesToConnect[cx];
175
+ if (existing) {
176
+ existing.push(cy);
177
+ } else {
178
+ circlesToConnect[cx] = [cy];
179
+ }
180
+ }
181
+
182
+ // Process circles and lines - optimized to avoid Object.entries
183
+ for (const cxKey in circlesToConnect) {
184
+ const cx = Number(cxKey);
185
+ const cys = circlesToConnect[cxKey]!;
186
+
187
+ if (cys.length === 1) {
188
+ const firstCy = cys[0];
189
+ if (firstCy === undefined) continue;
190
+
191
+ // Single dot, add as circle
192
+ circles.push({
193
+ cx,
194
+ cy: firstCy,
195
+ r: circleRadius
99
196
  });
100
- });
197
+ continue;
198
+ }
101
199
 
102
- // Cx to multiple cys
103
- const circlesToConnect: Record<number, number[]> = {};
200
+ // Sort once for line grouping
201
+ cys.sort((a, b) => a - b);
104
202
 
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];
203
+ // Track which dots are connected and which are lonely
204
+ const isConnected = new Array(cys.length).fill(false);
205
+
206
+ // Find all adjacent pairs
207
+ for (let i = 0; i < cys.length - 1; i++) {
208
+ const currentCy = cys[i];
209
+ const nextCy = cys[i + 1];
210
+ if (
211
+ currentCy !== undefined &&
212
+ nextCy !== undefined &&
213
+ isAdjacentDots(currentCy, nextCy, cellSize)
214
+ ) {
215
+ isConnected[i] = true;
216
+ isConnected[i + 1] = true;
111
217
  }
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
- );
218
+ }
219
+
220
+ // Add lonely dots as circles and build line groups
221
+ let groupStart = -1;
222
+ let groupEnd = -1;
223
+
224
+ for (let i = 0; i < cys.length; i++) {
225
+ const cy = cys[i];
226
+ if (cy === undefined) continue;
227
+
228
+ if (!isConnected[i]) {
229
+ // Lonely dot - add as circle
230
+ circles.push({
231
+ cx,
232
+ cy,
233
+ r: circleRadius
135
234
  });
136
- });
137
235
 
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);
236
+ // Finish any ongoing line group
237
+ if (groupStart !== -1 && groupEnd !== -1 && groupStart !== groupEnd) {
238
+ lines.push({
239
+ x1: cx,
240
+ x2: cx,
241
+ y1: groupStart,
242
+ y2: groupEnd,
243
+ strokeWidth
244
+ });
245
+ }
246
+ groupStart = -1;
247
+ groupEnd = -1;
248
+ } else {
249
+ // Part of a line group
250
+ if (groupStart === -1) {
251
+ groupStart = cy;
252
+ groupEnd = cy;
253
+ } else {
254
+ // Check if adjacent to previous
255
+ const prevCy = cys[i - 1];
256
+ if (i > 0 && prevCy !== undefined && isAdjacentDots(cy, prevCy, cellSize)) {
257
+ groupEnd = cy;
159
258
  } else {
160
- groups.push([cy]);
259
+ // Gap in the group, finish previous line
260
+ if (groupStart !== groupEnd) {
261
+ lines.push({
262
+ x1: cx,
263
+ x2: cx,
264
+ y1: groupStart,
265
+ y2: groupEnd,
266
+ strokeWidth
267
+ });
268
+ }
269
+ groupStart = cy;
270
+ groupEnd = cy;
161
271
  }
162
272
  }
273
+ }
274
+ }
163
275
 
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
- });
276
+ // Don't forget the last group
277
+ if (groupStart !== -1 && groupEnd !== -1 && groupStart !== groupEnd) {
278
+ lines.push({
279
+ x1: cx,
280
+ x2: cx,
281
+ y1: groupStart,
282
+ y2: groupEnd,
283
+ strokeWidth
181
284
  });
285
+ }
286
+ }
182
287
 
183
- return dots;
288
+ return { rects, circles, lines };
289
+ }
290
+
291
+ export function generateQRData(
292
+ uri: string,
293
+ size: number,
294
+ logoSize: number,
295
+ logoBorderRadius?: number
296
+ ): QRData {
297
+ if (!uri || size <= 0) {
298
+ throw new Error('Invalid QR code parameters');
184
299
  }
300
+
301
+ const matrix = getMatrix(uri, 'Q');
302
+
303
+ return processQRMatrix(matrix, size, logoSize, logoBorderRadius);
304
+ }
305
+
306
+ export const QRCodeUtil = {
307
+ generate: generateQRData
185
308
  };