@zerodev/smart-routing-address-react-ui 0.0.3 → 0.0.4
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/dist/_types/components/QrSheet/index.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +667 -781
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/components/QrSheet/index.tsx +3 -12
- package/dist/_types/components/QrSheet/QrCode.d.ts +0 -28
- package/dist/_types/components/QrSheet/QrCode.d.ts.map +0 -1
- package/src/components/QrSheet/QrCode.tsx +0 -163
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zerodev/smart-routing-address-react-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "React hooks, provider, and UI for ZeroDev Smart Routing Address deposits",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@zerodev/smart-routing-address": "^0.2.6",
|
|
46
46
|
"uqr": "^0.1.2",
|
|
47
47
|
"zod": "^4.4.3",
|
|
48
|
-
"@zerodev/react-ui": "0.0.
|
|
48
|
+
"@zerodev/react-ui": "0.0.8"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
BottomSheetContent,
|
|
5
5
|
BottomSheetTitle,
|
|
6
6
|
Button,
|
|
7
|
+
QrCode,
|
|
7
8
|
Text,
|
|
8
9
|
} from '@zerodev/react-ui'
|
|
9
|
-
import { QrCode } from './QrCode'
|
|
10
10
|
|
|
11
11
|
export interface QrSheetProps {
|
|
12
12
|
/** Whether the modal is open. Controlled. */
|
|
@@ -28,17 +28,8 @@ export function QrSheet({ open, onOpenChange, address, onCopy }: QrSheetProps) {
|
|
|
28
28
|
<BottomSheet open={open} onOpenChange={onOpenChange}>
|
|
29
29
|
<BottomSheetContent>
|
|
30
30
|
<BottomSheetTitle>Your deposit address</BottomSheetTitle>
|
|
31
|
-
{/*
|
|
32
|
-
|
|
33
|
-
in the Figma design. Colors echo `MultiRadialBackground`. */}
|
|
34
|
-
<div
|
|
35
|
-
aria-hidden
|
|
36
|
-
className="zd:absolute zd:inset-0 zd:pointer-events-none"
|
|
37
|
-
style={{
|
|
38
|
-
background:
|
|
39
|
-
'radial-gradient(ellipse 78% 65% at 5% 105%, rgba(69,171,251,0.35) 0%, rgba(69,171,251,0) 72%), radial-gradient(ellipse 82% 65% at 100% 105%, rgba(250,200,172,0.65) 0%, rgba(250,200,172,0) 72%), radial-gradient(ellipse 58% 52% at 100% 100%, rgba(242,123,62,0.35) 0%, rgba(242,123,62,0) 72%)',
|
|
40
|
-
}}
|
|
41
|
-
/>
|
|
31
|
+
{/* Accent gradient is baked into `BottomSheetContent`; content sits
|
|
32
|
+
above it via `zd:relative`. */}
|
|
42
33
|
<div className="zd:relative zd:flex zd:flex-col zd:gap-6 zd:items-center zd:pt-6 zd:px-4 zd:pb-3">
|
|
43
34
|
<div className="zd:flex zd:flex-col zd:gap-3 zd:items-center">
|
|
44
35
|
<Text className="zd:text-h2 zd:text-center">
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
interface QrCodeProps {
|
|
2
|
-
/** Data to encode. */
|
|
3
|
-
value: string;
|
|
4
|
-
/** Pixel size of the rendered SVG square. */
|
|
5
|
-
size: number;
|
|
6
|
-
/** Error correction level. Defaults to `'M'`. */
|
|
7
|
-
errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H';
|
|
8
|
-
/** Corner radius (in modules, scaled to px internally) for finder patterns. */
|
|
9
|
-
eyeRadius?: number;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Custom QR renderer that draws runs of horizontally-adjacent data modules as
|
|
13
|
-
* a single rounded pill. Finder patterns stay as sharp concentric squares
|
|
14
|
-
* (rounding them breaks the 1:1:3:1:1 corner ratio scanners use to locate the
|
|
15
|
-
* code). Isolated data modules render as pill-ish rects — visually close to
|
|
16
|
-
* circles at very small `PILL_PAD_RATIO`, still square-adjacent for scanners.
|
|
17
|
-
*
|
|
18
|
-
* Default `errorCorrectionLevel` is `'H'` (30% recovery) so the decorative
|
|
19
|
-
* rounding + shrinkage has plenty of headroom before scans fail.
|
|
20
|
-
*
|
|
21
|
-
* Quiet zone (spec: ≥4 modules of white around the code) is expected to be
|
|
22
|
-
* provided by the caller — e.g. via a white-background padded wrapper. This
|
|
23
|
-
* component fills the given `size` with the QR data area itself so the
|
|
24
|
-
* consumer controls the visual footprint.
|
|
25
|
-
*/
|
|
26
|
-
export declare function QrCode({ value, size, errorCorrectionLevel, eyeRadius, }: QrCodeProps): import("react").JSX.Element;
|
|
27
|
-
export {};
|
|
28
|
-
//# sourceMappingURL=QrCode.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"QrCode.d.ts","sourceRoot":"","sources":["../../../../src/components/QrSheet/QrCode.tsx"],"names":[],"mappings":"AAEA,UAAU,WAAW;IACnB,sBAAsB;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IAC5C,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAUD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,IAAI,EACJ,oBAA0B,EAC1B,SAAa,GACd,EAAE,WAAW,+BAyHb"}
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { encode } from 'uqr'
|
|
2
|
-
|
|
3
|
-
interface QrCodeProps {
|
|
4
|
-
/** Data to encode. */
|
|
5
|
-
value: string
|
|
6
|
-
/** Pixel size of the rendered SVG square. */
|
|
7
|
-
size: number
|
|
8
|
-
/** Error correction level. Defaults to `'M'`. */
|
|
9
|
-
errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H'
|
|
10
|
-
/** Corner radius (in modules, scaled to px internally) for finder patterns. */
|
|
11
|
-
eyeRadius?: number
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const FINDER_SIZE = 7 // every QR has three 7×7 finder patterns
|
|
15
|
-
const MODULE_COLOR = '#000'
|
|
16
|
-
const BG_COLOR = '#fff'
|
|
17
|
-
/** Vertical shrink applied to data-module pills so rows read as distinct
|
|
18
|
-
* without introducing white slivers wide enough to look like transitions
|
|
19
|
-
* to a scanner. Kept small (5%) so total black area stays close to spec. */
|
|
20
|
-
const PILL_PAD_RATIO = 0.05
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Custom QR renderer that draws runs of horizontally-adjacent data modules as
|
|
24
|
-
* a single rounded pill. Finder patterns stay as sharp concentric squares
|
|
25
|
-
* (rounding them breaks the 1:1:3:1:1 corner ratio scanners use to locate the
|
|
26
|
-
* code). Isolated data modules render as pill-ish rects — visually close to
|
|
27
|
-
* circles at very small `PILL_PAD_RATIO`, still square-adjacent for scanners.
|
|
28
|
-
*
|
|
29
|
-
* Default `errorCorrectionLevel` is `'H'` (30% recovery) so the decorative
|
|
30
|
-
* rounding + shrinkage has plenty of headroom before scans fail.
|
|
31
|
-
*
|
|
32
|
-
* Quiet zone (spec: ≥4 modules of white around the code) is expected to be
|
|
33
|
-
* provided by the caller — e.g. via a white-background padded wrapper. This
|
|
34
|
-
* component fills the given `size` with the QR data area itself so the
|
|
35
|
-
* consumer controls the visual footprint.
|
|
36
|
-
*/
|
|
37
|
-
export function QrCode({
|
|
38
|
-
value,
|
|
39
|
-
size,
|
|
40
|
-
errorCorrectionLevel = 'H',
|
|
41
|
-
eyeRadius = 0,
|
|
42
|
-
}: QrCodeProps) {
|
|
43
|
-
// `uqr` returns a 2D boolean matrix (`data[row][col]`) and the module count
|
|
44
|
-
// per side. Same information as `qrcode`, just shaped differently — the
|
|
45
|
-
// pill/finder rendering below is unchanged.
|
|
46
|
-
const qr = encode(value, { ecc: errorCorrectionLevel, border: 0 })
|
|
47
|
-
const matrix = qr.data
|
|
48
|
-
const moduleCount = qr.size
|
|
49
|
-
const cellSize = size / moduleCount
|
|
50
|
-
const eyeRadiusPx = eyeRadius * cellSize
|
|
51
|
-
|
|
52
|
-
const finders = [
|
|
53
|
-
{ row: 0, col: 0 },
|
|
54
|
-
{ row: 0, col: moduleCount - FINDER_SIZE },
|
|
55
|
-
{ row: moduleCount - FINDER_SIZE, col: 0 },
|
|
56
|
-
]
|
|
57
|
-
|
|
58
|
-
const inFinder = (row: number, col: number) =>
|
|
59
|
-
finders.some(
|
|
60
|
-
(f) =>
|
|
61
|
-
row >= f.row &&
|
|
62
|
-
row < f.row + FINDER_SIZE &&
|
|
63
|
-
col >= f.col &&
|
|
64
|
-
col < f.col + FINDER_SIZE,
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
// Collect maximal horizontal runs of `on` modules, skipping finder regions.
|
|
68
|
-
const runs: { row: number; col: number; length: number }[] = []
|
|
69
|
-
for (let row = 0; row < moduleCount; row++) {
|
|
70
|
-
let col = 0
|
|
71
|
-
while (col < moduleCount) {
|
|
72
|
-
if (inFinder(row, col)) {
|
|
73
|
-
col++
|
|
74
|
-
continue
|
|
75
|
-
}
|
|
76
|
-
if (matrix[row]?.[col]) {
|
|
77
|
-
let length = 1
|
|
78
|
-
while (
|
|
79
|
-
col + length < moduleCount &&
|
|
80
|
-
!inFinder(row, col + length) &&
|
|
81
|
-
matrix[row]?.[col + length]
|
|
82
|
-
) {
|
|
83
|
-
length++
|
|
84
|
-
}
|
|
85
|
-
runs.push({ row, col, length })
|
|
86
|
-
col += length
|
|
87
|
-
} else {
|
|
88
|
-
col++
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return (
|
|
94
|
-
<svg
|
|
95
|
-
width={size}
|
|
96
|
-
height={size}
|
|
97
|
-
viewBox={`0 0 ${size} ${size}`}
|
|
98
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
99
|
-
role="img"
|
|
100
|
-
aria-label={`QR code for ${value}`}
|
|
101
|
-
>
|
|
102
|
-
<rect width={size} height={size} fill={BG_COLOR} />
|
|
103
|
-
{runs.map(({ row, col, length }) => {
|
|
104
|
-
// Shrink each pill vertically so rows read as distinct without
|
|
105
|
-
// creating scanner-confusing white gaps mid-run. Isolated modules
|
|
106
|
-
// (length === 1) also shrink horizontally so they render close to a
|
|
107
|
-
// circle instead of an oval.
|
|
108
|
-
const pad = cellSize * PILL_PAD_RATIO
|
|
109
|
-
const pillHeight = cellSize - 2 * pad
|
|
110
|
-
const isSingle = length === 1
|
|
111
|
-
return (
|
|
112
|
-
<rect
|
|
113
|
-
key={`r${row}-${col}`}
|
|
114
|
-
x={col * cellSize + (isSingle ? pad : 0)}
|
|
115
|
-
y={row * cellSize + pad}
|
|
116
|
-
width={length * cellSize - (isSingle ? 2 * pad : 0)}
|
|
117
|
-
height={pillHeight}
|
|
118
|
-
rx={pillHeight / 2}
|
|
119
|
-
ry={pillHeight / 2}
|
|
120
|
-
fill={MODULE_COLOR}
|
|
121
|
-
/>
|
|
122
|
-
)
|
|
123
|
-
})}
|
|
124
|
-
{finders.map(({ row, col }) => {
|
|
125
|
-
const x = col * cellSize
|
|
126
|
-
const y = row * cellSize
|
|
127
|
-
const outerSize = FINDER_SIZE * cellSize
|
|
128
|
-
const innerSize = 3 * cellSize
|
|
129
|
-
return (
|
|
130
|
-
<g key={`f${row}-${col}`}>
|
|
131
|
-
<rect
|
|
132
|
-
x={x}
|
|
133
|
-
y={y}
|
|
134
|
-
width={outerSize}
|
|
135
|
-
height={outerSize}
|
|
136
|
-
rx={eyeRadiusPx}
|
|
137
|
-
ry={eyeRadiusPx}
|
|
138
|
-
fill={MODULE_COLOR}
|
|
139
|
-
/>
|
|
140
|
-
<rect
|
|
141
|
-
x={x + cellSize}
|
|
142
|
-
y={y + cellSize}
|
|
143
|
-
width={outerSize - 2 * cellSize}
|
|
144
|
-
height={outerSize - 2 * cellSize}
|
|
145
|
-
rx={Math.max(eyeRadiusPx - cellSize, 0)}
|
|
146
|
-
ry={Math.max(eyeRadiusPx - cellSize, 0)}
|
|
147
|
-
fill={BG_COLOR}
|
|
148
|
-
/>
|
|
149
|
-
<rect
|
|
150
|
-
x={x + 2 * cellSize}
|
|
151
|
-
y={y + 2 * cellSize}
|
|
152
|
-
width={innerSize}
|
|
153
|
-
height={innerSize}
|
|
154
|
-
rx={Math.max(eyeRadiusPx - 2 * cellSize, 0)}
|
|
155
|
-
ry={Math.max(eyeRadiusPx - 2 * cellSize, 0)}
|
|
156
|
-
fill={MODULE_COLOR}
|
|
157
|
-
/>
|
|
158
|
-
</g>
|
|
159
|
-
)
|
|
160
|
-
})}
|
|
161
|
-
</svg>
|
|
162
|
-
)
|
|
163
|
-
}
|