From 0e475b63b1135c4a1ca86c475a5102bb38360191 Mon Sep 17 00:00:00 2001 From: nacho <25931366+ignaciosantise@users.noreply.github.com> Date: Tue, 4 Nov 2025 14:59:51 -0300 Subject: [PATCH 1/5] chore: round qr code logo borders --- packages/appkit/src/modal/w3m-modal/styles.ts | 3 +- .../partials/w3m-connecting-qrcode/index.tsx | 2 +- packages/ui/src/assets/svg/WalletConnect.tsx | 9 +- .../ui/src/composites/wui-qr-code/index.tsx | 121 ++++- .../ui/src/composites/wui-qr-code/styles.ts | 3 - packages/ui/src/utils/QRCodeUtil.tsx | 450 ++++++++++++------ 6 files changed, 412 insertions(+), 176 deletions(-) diff --git a/packages/appkit/src/modal/w3m-modal/styles.ts b/packages/appkit/src/modal/w3m-modal/styles.ts index f7109eb1a..041a7131d 100644 --- a/packages/appkit/src/modal/w3m-modal/styles.ts +++ b/packages/appkit/src/modal/w3m-modal/styles.ts @@ -3,6 +3,7 @@ import { StyleSheet } from 'react-native'; export default StyleSheet.create({ card: { borderBottomLeftRadius: 0, - borderBottomRightRadius: 0 + borderBottomRightRadius: 0, + borderWidth: 0 } }); diff --git a/packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx b/packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx index c82eb4389..a9bff00cb 100644 --- a/packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx +++ b/packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx @@ -65,7 +65,7 @@ export function ConnectingQrCode() { flexDirection={isPortrait ? 'column' : 'row'} padding={['xl', 'xl', 'xs', 'xl']} > - + Scan this QR code with your phone {showCopy ? ( diff --git a/packages/ui/src/assets/svg/WalletConnect.tsx b/packages/ui/src/assets/svg/WalletConnect.tsx index d8884b3b2..d3be9f9f6 100644 --- a/packages/ui/src/assets/svg/WalletConnect.tsx +++ b/packages/ui/src/assets/svg/WalletConnect.tsx @@ -1,14 +1,13 @@ import Svg, { ClipPath, Defs, G, Path, type SvgProps } from 'react-native-svg'; const SvgWalletConnect = (props: SvgProps) => ( - + ); diff --git a/packages/ui/src/composites/wui-qr-code/index.tsx b/packages/ui/src/composites/wui-qr-code/index.tsx index dd598dc7b..f4943d53f 100644 --- a/packages/ui/src/composites/wui-qr-code/index.tsx +++ b/packages/ui/src/composites/wui-qr-code/index.tsx @@ -1,10 +1,10 @@ -import { memo, useMemo } from 'react'; +import { memo, useEffect, useState } from 'react'; import { View, type StyleProp, type ViewStyle } from 'react-native'; -import Svg from 'react-native-svg'; +import Svg, { Circle, Line, Rect } from 'react-native-svg'; import { Icon } from '../../components/wui-icon'; import { Image } from '../../components/wui-image'; import { Shimmer } from '../../components/wui-shimmer'; -import { QRCodeUtil } from '../../utils/QRCodeUtil'; +import { QRCodeUtil, type QRData } from '../../utils/QRCodeUtil'; import { BorderRadius, LightTheme, Spacing } from '../../utils/ThemeUtil'; import type { IconType } from '../../utils/TypesUtil'; import styles from './styles'; @@ -17,18 +17,57 @@ export interface QrCodeProps { testID?: string; arenaClear?: boolean; style?: StyleProp; + logoSize?: number; + logoBorderRadius?: number; } -export function QrCode_({ size, uri, imageSrc, testID, arenaClear, icon, style }: QrCodeProps) { +export function QrCode_({ + size, + uri, + imageSrc, + testID, + arenaClear, + icon, + style, + logoSize, + logoBorderRadius +}: QrCodeProps) { const Theme = LightTheme; const containerPadding = Spacing.l; const qrSize = size - containerPadding * 2; - const logoSize = arenaClear ? 0 : qrSize / 4; + const _logoSize = arenaClear ? 0 : logoSize ?? qrSize / 4; - const dots = useMemo( - () => (uri ? QRCodeUtil.generate(uri, qrSize, logoSize) : []), - [uri, qrSize, logoSize] - ); + const [qrData, setQrData] = useState(null); + + const dotColor = Theme['inverse-000']; + const edgeColor = Theme['inverse-100']; + + useEffect(() => { + if (!uri) { + setQrData(null); + + return; + } + + let cancelled = false; + + // Run QR generation asynchronously + QRCodeUtil.generateAsync(uri, qrSize, _logoSize, logoBorderRadius) + .then(data => { + if (!cancelled) { + setQrData(data); + } + }) + .catch(() => { + if (!cancelled) { + setQrData(null); + } + }); + + return () => { + cancelled = true; + }; + }, [uri, qrSize, _logoSize, logoBorderRadius]); const logoTemplate = () => { if (arenaClear) { @@ -40,8 +79,12 @@ export function QrCode_({ size, uri, imageSrc, testID, arenaClear, icon, style } ); @@ -51,14 +94,18 @@ export function QrCode_({ size, uri, imageSrc, testID, arenaClear, icon, style } ); }; - return uri ? ( + if (!uri || !qrData) { + return ; + } + + return ( - {dots} + {/* Render rectangles */} + {qrData.rects.map((rect, idx) => ( + + ))} + + {/* Render circles */} + {qrData.circles.map((circle, idx) => ( + + ))} + + {/* Render lines */} + {qrData.lines.map((line, idx) => ( + + ))} {logoTemplate()} - ) : ( - ); } @@ -81,6 +163,7 @@ export const QrCode = memo(QrCode_, (prevProps, nextProps) => { return ( prevProps.size === nextProps.size && prevProps.uri === nextProps.uri && - prevProps.style === nextProps.style + prevProps.style === nextProps.style && + prevProps.logoBorderRadius === nextProps.logoBorderRadius ); }); diff --git a/packages/ui/src/composites/wui-qr-code/styles.ts b/packages/ui/src/composites/wui-qr-code/styles.ts index 9503ff74b..7b3c0b1bc 100644 --- a/packages/ui/src/composites/wui-qr-code/styles.ts +++ b/packages/ui/src/composites/wui-qr-code/styles.ts @@ -8,8 +8,5 @@ export default StyleSheet.create({ borderRadius: BorderRadius.l, padding: Spacing.l, alignSelf: 'center' - }, - icon: { - position: 'absolute' } }); diff --git a/packages/ui/src/utils/QRCodeUtil.tsx b/packages/ui/src/utils/QRCodeUtil.tsx index 3bb6f01eb..40f858aa3 100644 --- a/packages/ui/src/utils/QRCodeUtil.tsx +++ b/packages/ui/src/utils/QRCodeUtil.tsx @@ -1,15 +1,32 @@ -import type { ReactNode } from 'react'; -import { Line, Rect, Circle } from 'react-native-svg'; import QRCode from 'qrcode'; -import { LightTheme } from '../utils/ThemeUtil'; - -type CoordinateMapping = [number, number[]]; const CONNECTING_ERROR_MARGIN = 0.1; const CIRCLE_SIZE_MODIFIER = 2.5; const QRCODE_MATRIX_MARGIN = 7; +const LOGO_PADDING = 25; + +export interface QRData { + rects: { + x: number; + y: number; + size: number; + fillType: 'dot' | 'edge'; + }[]; + circles: { + cx: number; + cy: number; + r: number; + }[]; + lines: { + x1: number; + x2: number; + y1: number; + y2: number; + strokeWidth: number; + }[]; +} -function isAdjecentDots(cy: number, otherCy: number, cellSize: number) { +function isAdjacentDots(cy: number, otherCy: number, cellSize: number) { if (cy === otherCy) { return false; } @@ -18,7 +35,10 @@ function isAdjecentDots(cy: number, otherCy: number, cellSize: number) { return diff <= cellSize + CONNECTING_ERROR_MARGIN; } -function getMatrix(value: string, errorCorrectionLevel: QRCode.QRCodeErrorCorrectionLevel) { +function getMatrix( + value: string, + errorCorrectionLevel: QRCode.QRCodeErrorCorrectionLevel +): boolean[][] { const arr = Array.prototype.slice.call( QRCode.create(value, { errorCorrectionLevel }).modules.data, 0 @@ -32,154 +52,290 @@ function getMatrix(value: string, errorCorrectionLevel: QRCode.QRCodeErrorCorrec ); } -export const QRCodeUtil = { - generate(uri: string, size: number, logoSize: number) { - const dotColor = LightTheme['inverse-000']; - const edgeColor = LightTheme['inverse-100']; - const dots: ReactNode[] = []; - const matrix = getMatrix(uri, 'Q'); - const cellSize = size / matrix.length; - const qrList = [ - { x: 0, y: 0 }, - { x: 1, y: 0 }, - { x: 0, y: 1 } - ]; - - qrList.forEach(({ x, y }) => { - const x1 = (matrix.length - QRCODE_MATRIX_MARGIN) * cellSize * x; - const y1 = (matrix.length - QRCODE_MATRIX_MARGIN) * cellSize * y; - const borderRadius = 0.32; - for (let i = 0; i < qrList.length; i += 1) { - const dotSize = cellSize * (QRCODE_MATRIX_MARGIN - i * 2); - dots.push( - - ); +function processQRMatrix( + matrix: boolean[][], + size: number, + logoSize: number, + logoBorderRadius?: number +): QRData { + const matrixLength = matrix.length; + const cellSize = size / matrixLength; + const halfCellSize = cellSize / 2; + const strokeWidth = cellSize / (CIRCLE_SIZE_MODIFIER / 2); + const circleRadius = cellSize / CIRCLE_SIZE_MODIFIER; + + // Pre-allocate arrays with estimated capacity + const rects: QRData['rects'] = []; + rects.length = 27; // 3 corners × 3 layers × 3 = 27 rects max + let rectIndex = 0; + + // Estimate circle capacity (roughly half the matrix minus corners and logo area) + const estimatedCircles = Math.floor((matrixLength * matrixLength) / 2); + const circles: QRData['circles'] = []; + circles.length = estimatedCircles; + let circleIndex = 0; + + const lines: QRData['lines'] = []; + lines.length = Math.floor(estimatedCircles / 4); + let lineIndex = 0; + + // Generate corner rectangles - optimized with direct indexing + const qrList = [ + { x: 0, y: 0 }, + { x: 1, y: 0 }, + { x: 0, y: 1 } + ]; + const baseOffset = (matrixLength - QRCODE_MATRIX_MARGIN) * cellSize; + + for (let qrIdx = 0; qrIdx < 3; qrIdx++) { + const qr = qrList[qrIdx]; + if (!qr) continue; + + const x1 = baseOffset * qr.x; + const y1 = baseOffset * qr.y; + + for (let i = 0; i < 3; i++) { + const dotSize = cellSize * (QRCODE_MATRIX_MARGIN - i * 2); + rects[rectIndex++] = { + x: x1 + cellSize * i, + y: y1 + cellSize * i, + size: dotSize, + fillType: i % 2 === 0 ? 'dot' : 'edge' + }; + } + } + + const circleCoords: [number, number][] = []; + + // Determine if using circular or rounded rectangle hole + const isCircular = logoBorderRadius === undefined; + const effectiveBorderRadius = logoBorderRadius ?? (logoSize + LOGO_PADDING) / 2; + + // Calculate circle coordinates - optimized with configurable hole shape + for (let i = 0; i < matrixLength; i++) { + const row = matrix[i]; + if (!row) continue; + + const rowLength = row.length; + + for (let j = 0; j < rowLength; j++) { + if (!row[j]) continue; + + // Skip corners check + if ( + (i < QRCODE_MATRIX_MARGIN && j < QRCODE_MATRIX_MARGIN) || + (i > matrixLength - (QRCODE_MATRIX_MARGIN + 1) && j < QRCODE_MATRIX_MARGIN) || + (i < QRCODE_MATRIX_MARGIN && j > matrixLength - (QRCODE_MATRIX_MARGIN + 1)) + ) { + continue; } - }); - - const clearArenaSize = Math.floor((logoSize + 25) / cellSize); - const matrixMiddleStart = matrix.length / 2 - clearArenaSize / 2; - const matrixMiddleEnd = matrix.length / 2 + clearArenaSize / 2 - 1; - const circles: [number, number][] = []; - - // Getting coordinates for each of the QR code dots - matrix.forEach((row: QRCode.QRCode[], i: number) => { - row.forEach((_, j: number) => { - if (matrix[i][j]) { - if ( - !( - (i < QRCODE_MATRIX_MARGIN && j < QRCODE_MATRIX_MARGIN) || - (i > matrix.length - (QRCODE_MATRIX_MARGIN + 1) && j < QRCODE_MATRIX_MARGIN) || - (i < QRCODE_MATRIX_MARGIN && j > matrix.length - (QRCODE_MATRIX_MARGIN + 1)) - ) - ) { - if ( - !( - i > matrixMiddleStart && - i < matrixMiddleEnd && - j > matrixMiddleStart && - j < matrixMiddleEnd - ) - ) { - const cx = i * cellSize + cellSize / 2; - const cy = j * cellSize + cellSize / 2; - circles.push([cx, cy]); - } - } - } - }); - }); - // Cx to multiple cys - const circlesToConnect: Record = {}; + // Calculate pixel coordinates first + const cx = i * cellSize + halfCellSize; + const cy = j * cellSize + halfCellSize; + + // Skip hole calculation if logoSize is 0 (arenaClear) + if (logoSize === 0) { + circleCoords.push([cx, cy]); + continue; + } + + // Calculate distance from center in pixel space + const centerX = size / 2; + const centerY = size / 2; - // Mapping all dots cicles on the same x axis - circles.forEach(([cx, cy]) => { - if (circlesToConnect[cx]) { - circlesToConnect[cx]?.push(cy); + let isOutsideLogoArea = false; + + if (isCircular) { + // Circular hole + const dx = cx - centerX; + const dy = cy - centerY; + const distanceFromCenter = Math.sqrt(dx * dx + dy * dy); + const pixelRadius = (logoSize + LOGO_PADDING) / 2; + isOutsideLogoArea = distanceFromCenter >= pixelRadius; } else { - circlesToConnect[cx] = [cy]; + // Rounded rectangle hole + const halfLogoArea = (logoSize + LOGO_PADDING) / 2; + const dx = Math.abs(cx - centerX); + const dy = Math.abs(cy - centerY); + + // Check if point is outside the rounded rectangle + if (dx > halfLogoArea || dy > halfLogoArea) { + isOutsideLogoArea = true; + } else if ( + dx > halfLogoArea - effectiveBorderRadius && + dy > halfLogoArea - effectiveBorderRadius + ) { + // Check corner radius + const cornerDx = dx - (halfLogoArea - effectiveBorderRadius); + const cornerDy = dy - (halfLogoArea - effectiveBorderRadius); + const cornerDistance = Math.sqrt(cornerDx * cornerDx + cornerDy * cornerDy); + isOutsideLogoArea = cornerDistance >= effectiveBorderRadius; + } else { + isOutsideLogoArea = false; + } + } + + if (isOutsideLogoArea) { + circleCoords.push([cx, cy]); } - }); - - // Drawing lonely dots - Object.entries(circlesToConnect) - // Only get dots that have neighbors - .map(([cx, cys]) => { - const newCys = cys.filter(cy => - cys.every(otherCy => !isAdjecentDots(cy, otherCy, cellSize)) - ); - - return [Number(cx), newCys] as CoordinateMapping; - }) - .forEach(([cx, cys]) => { - cys.forEach(cy => { - dots.push( - - ); - }); - }); - - // Drawing lines for dots that are close to each other - Object.entries(circlesToConnect) - // Only get dots that have more than one dot on the x axis - .filter(([_, cys]) => cys.length > 1) - // Removing dots with no neighbors - .map(([cx, cys]) => { - const newCys = cys.filter(cy => cys.some(otherCy => isAdjecentDots(cy, otherCy, cellSize))); - - return [Number(cx), newCys] as CoordinateMapping; - }) - // Get the coordinates of the first and last dot of a line - .map(([cx, cys]) => { - cys.sort((a, b) => (a < b ? -1 : 1)); - const groups: number[][] = []; - - for (const cy of cys) { - const group = groups.find(item => - item.some(otherCy => isAdjecentDots(cy, otherCy, cellSize)) - ); - if (group) { - group.push(cy); + } + } + + // Build circlesToConnect - optimized loop + const circlesToConnect: Record = {}; + for (let k = 0; k < circleCoords.length; k++) { + const coord = circleCoords[k]; + if (!coord) continue; + + const [cx, cy] = coord; + const existing = circlesToConnect[cx]; + if (existing) { + existing.push(cy); + } else { + circlesToConnect[cx] = [cy]; + } + } + + // Process circles and lines - optimized to avoid Object.entries + for (const cxKey in circlesToConnect) { + const cx = Number(cxKey); + const cys = circlesToConnect[cxKey]; + if (!cys) continue; + + if (cys.length === 1) { + const firstCy = cys[0]; + if (firstCy === undefined) continue; + + // Single dot, add as circle + circles[circleIndex++] = { + cx, + cy: firstCy, + r: circleRadius + }; + continue; + } + + // Sort once for line grouping + cys.sort((a, b) => a - b); + + // Track which dots are connected and which are lonely + const isConnected = new Array(cys.length).fill(false); + + // Find all adjacent pairs + for (let i = 0; i < cys.length - 1; i++) { + const currentCy = cys[i]; + const nextCy = cys[i + 1]; + if ( + currentCy !== undefined && + nextCy !== undefined && + isAdjacentDots(currentCy, nextCy, cellSize) + ) { + isConnected[i] = true; + isConnected[i + 1] = true; + } + } + + // Add lonely dots as circles and build line groups + let groupStart = -1; + let groupEnd = -1; + + for (let i = 0; i < cys.length; i++) { + const cy = cys[i]; + if (cy === undefined) continue; + + if (!isConnected[i]) { + // Lonely dot - add as circle + circles[circleIndex++] = { + cx, + cy, + r: circleRadius + }; + + // Finish any ongoing line group + if (groupStart !== -1 && groupEnd !== -1 && groupStart !== groupEnd) { + lines[lineIndex++] = { + x1: cx, + x2: cx, + y1: groupStart, + y2: groupEnd, + strokeWidth + }; + } + groupStart = -1; + groupEnd = -1; + } else { + // Part of a line group + if (groupStart === -1) { + groupStart = cy; + groupEnd = cy; + } else { + // Check if adjacent to previous + const prevCy = cys[i - 1]; + if (i > 0 && prevCy !== undefined && isAdjacentDots(cy, prevCy, cellSize)) { + groupEnd = cy; } else { - groups.push([cy]); + // Gap in the group, finish previous line + if (groupStart !== groupEnd) { + lines[lineIndex++] = { + x1: cx, + x2: cx, + y1: groupStart, + y2: groupEnd, + strokeWidth + }; + } + groupStart = cy; + groupEnd = cy; } } + } + } - return [cx, groups.map(item => [item[0], item[item.length - 1]])] as [number, number[][]]; - }) - .forEach(([cx, groups]) => { - groups.forEach(([y1, y2]) => { - dots.push( - - ); - }); - }); - - return dots; + // Don't forget the last group + if (groupStart !== -1 && groupEnd !== -1 && groupStart !== groupEnd) { + lines[lineIndex++] = { + x1: cx, + x2: cx, + y1: groupStart, + y2: groupEnd, + strokeWidth + }; + } } + + // Trim arrays to actual size + rects.length = rectIndex; + circles.length = circleIndex; + lines.length = lineIndex; + + return { rects, circles, lines }; +} + +// Run asynchronously without blocking the UI +export async function generateQRDataAsync( + uri: string, + size: number, + logoSize: number, + logoBorderRadius?: number +): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + try { + if (!uri || size <= 0) { + throw new Error('Invalid QR code parameters'); + } + + const matrix = getMatrix(uri, 'Q'); + const data = processQRMatrix(matrix, size, logoSize, logoBorderRadius); + resolve(data); + } catch (error) { + reject(error); + } + }, 0); + }); +} + +export const QRCodeUtil = { + generateAsync: generateQRDataAsync }; From 5b8eb479880eda9c6d799692f5f48153111d16ad Mon Sep 17 00:00:00 2001 From: nacho <25931366+ignaciosantise@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:02:11 -0300 Subject: [PATCH 2/5] chore: changeset file --- .changeset/eager-walls-tease.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .changeset/eager-walls-tease.md diff --git a/.changeset/eager-walls-tease.md b/.changeset/eager-walls-tease.md new file mode 100644 index 000000000..73dd5a393 --- /dev/null +++ b/.changeset/eager-walls-tease.md @@ -0,0 +1,13 @@ +--- +'@reown/appkit-react-native': patch +'@reown/appkit-ui-react-native': patch +'@reown/appkit-bitcoin-react-native': patch +'@reown/appkit-coinbase-react-native': patch +'@reown/appkit-common-react-native': patch +'@reown/appkit-core-react-native': patch +'@reown/appkit-ethers-react-native': patch +'@reown/appkit-solana-react-native': patch +'@reown/appkit-wagmi-react-native': patch +--- + +chore: round logo from qr code + added borderWidth 0 to card component From a5c2e34ad97172602c42e55f69da31a4d4e93b6c Mon Sep 17 00:00:00 2001 From: nacho <25931366+ignaciosantise@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:15:11 -0300 Subject: [PATCH 3/5] chore: improvements --- .../partials/w3m-connecting-qrcode/index.tsx | 11 ++- .../ui/src/composites/wui-qr-code/index.tsx | 48 ++++--------- packages/ui/src/utils/QRCodeUtil.tsx | 67 ++++++------------- 3 files changed, 43 insertions(+), 83 deletions(-) diff --git a/packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx b/packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx index a9bff00cb..fc5aca8ca 100644 --- a/packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx +++ b/packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx @@ -20,6 +20,9 @@ import styles from './styles'; import { ReownButton } from './components/ReownButton'; import { useWindowDimensions } from 'react-native'; +const LOGO_SIZE = 60; +const LOGO_BORDER_RADIUS = 20; + export function ConnectingQrCode() { const { height, width } = useWindowDimensions(); const windowSize = Math.min(height, width); @@ -65,7 +68,13 @@ export function ConnectingQrCode() { flexDirection={isPortrait ? 'column' : 'row'} padding={['xl', 'xl', 'xs', 'xl']} > - + Scan this QR code with your phone {showCopy ? ( diff --git a/packages/ui/src/composites/wui-qr-code/index.tsx b/packages/ui/src/composites/wui-qr-code/index.tsx index f4943d53f..ccf0374ef 100644 --- a/packages/ui/src/composites/wui-qr-code/index.tsx +++ b/packages/ui/src/composites/wui-qr-code/index.tsx @@ -1,10 +1,10 @@ -import { memo, useEffect, useState } from 'react'; +import { memo, useMemo } from 'react'; import { View, type StyleProp, type ViewStyle } from 'react-native'; import Svg, { Circle, Line, Rect } from 'react-native-svg'; import { Icon } from '../../components/wui-icon'; import { Image } from '../../components/wui-image'; import { Shimmer } from '../../components/wui-shimmer'; -import { QRCodeUtil, type QRData } from '../../utils/QRCodeUtil'; +import { QRCodeUtil } from '../../utils/QRCodeUtil'; import { BorderRadius, LightTheme, Spacing } from '../../utils/ThemeUtil'; import type { IconType } from '../../utils/TypesUtil'; import styles from './styles'; @@ -37,37 +37,13 @@ export function QrCode_({ const qrSize = size - containerPadding * 2; const _logoSize = arenaClear ? 0 : logoSize ?? qrSize / 4; - const [qrData, setQrData] = useState(null); - const dotColor = Theme['inverse-000']; const edgeColor = Theme['inverse-100']; - useEffect(() => { - if (!uri) { - setQrData(null); - - return; - } - - let cancelled = false; - - // Run QR generation asynchronously - QRCodeUtil.generateAsync(uri, qrSize, _logoSize, logoBorderRadius) - .then(data => { - if (!cancelled) { - setQrData(data); - } - }) - .catch(() => { - if (!cancelled) { - setQrData(null); - } - }); - - return () => { - cancelled = true; - }; - }, [uri, qrSize, _logoSize, logoBorderRadius]); + const qrData = useMemo( + () => (uri ? QRCodeUtil.generate(uri, qrSize, _logoSize, logoBorderRadius) : null), + [uri, qrSize, _logoSize, logoBorderRadius] + ); const logoTemplate = () => { if (arenaClear) { @@ -116,9 +92,9 @@ export function QrCode_({ > {/* Render rectangles */} - {qrData.rects.map((rect, idx) => ( + {qrData.rects.map(rect => ( ( + {qrData.circles.map(circle => ( ( + {qrData.lines.map(line => ( { - return new Promise((resolve, reject) => { - setTimeout(() => { - try { - if (!uri || size <= 0) { - throw new Error('Invalid QR code parameters'); - } +): QRData { + if (!uri || size <= 0) { + throw new Error('Invalid QR code parameters'); + } - const matrix = getMatrix(uri, 'Q'); - const data = processQRMatrix(matrix, size, logoSize, logoBorderRadius); - resolve(data); - } catch (error) { - reject(error); - } - }, 0); - }); + const matrix = getMatrix(uri, 'Q'); + + return processQRMatrix(matrix, size, logoSize, logoBorderRadius); } export const QRCodeUtil = { - generateAsync: generateQRDataAsync + generate: generateQRData }; From 0e2c0edbd4a4249230488736591c12952eb9515b Mon Sep 17 00:00:00 2001 From: nacho <25931366+ignaciosantise@users.noreply.github.com> Date: Wed, 5 Nov 2025 14:49:35 -0300 Subject: [PATCH 4/5] chore: qr code improvements --- packages/ui/src/utils/QRCodeUtil.tsx | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/ui/src/utils/QRCodeUtil.tsx b/packages/ui/src/utils/QRCodeUtil.tsx index 9c5a1acca..26e2800bf 100644 --- a/packages/ui/src/utils/QRCodeUtil.tsx +++ b/packages/ui/src/utils/QRCodeUtil.tsx @@ -77,9 +77,7 @@ function processQRMatrix( const baseOffset = (matrixLength - QRCODE_MATRIX_MARGIN) * cellSize; for (let qrIdx = 0; qrIdx < 3; qrIdx++) { - const qr = qrList[qrIdx]; - if (!qr) continue; - + const qr = qrList[qrIdx]!; const x1 = baseOffset * qr.x; const y1 = baseOffset * qr.y; @@ -102,9 +100,7 @@ function processQRMatrix( // Calculate circle coordinates - optimized with configurable hole shape for (let i = 0; i < matrixLength; i++) { - const row = matrix[i]; - if (!row) continue; - + const row = matrix[i]!; const rowLength = row.length; for (let j = 0; j < rowLength; j++) { @@ -174,10 +170,7 @@ function processQRMatrix( // Build circlesToConnect - optimized loop const circlesToConnect: Record = {}; for (let k = 0; k < circleCoords.length; k++) { - const coord = circleCoords[k]; - if (!coord) continue; - - const [cx, cy] = coord; + const [cx, cy] = circleCoords[k]!; const existing = circlesToConnect[cx]; if (existing) { existing.push(cy); @@ -189,8 +182,7 @@ function processQRMatrix( // Process circles and lines - optimized to avoid Object.entries for (const cxKey in circlesToConnect) { const cx = Number(cxKey); - const cys = circlesToConnect[cxKey]; - if (!cys) continue; + const cys = circlesToConnect[cxKey]!; if (cys.length === 1) { const firstCy = cys[0]; From b92831db63e6fdc264dcbba987a8b0d79b2f5282 Mon Sep 17 00:00:00 2001 From: nacho <25931366+ignaciosantise@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:41:05 -0300 Subject: [PATCH 5/5] chore: changed border radius of qr code --- packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx b/packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx index fc5aca8ca..b2ef67a57 100644 --- a/packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx +++ b/packages/appkit/src/partials/w3m-connecting-qrcode/index.tsx @@ -21,7 +21,7 @@ import { ReownButton } from './components/ReownButton'; import { useWindowDimensions } from 'react-native'; const LOGO_SIZE = 60; -const LOGO_BORDER_RADIUS = 20; +const LOGO_BORDER_RADIUS = 10; export function ConnectingQrCode() { const { height, width } = useWindowDimensions();