@reown/appkit-ui
Version:
The full stack toolkit to build onchain app UX.
129 lines • 5.49 kB
JavaScript
import QRCodeUtil from 'qrcode';
import { svg } from 'lit';
const CONNECTING_ERROR_MARGIN = 0.1;
const CIRCLE_SIZE_MODIFIER = 2.5;
const QRCODE_MATRIX_MARGIN = 7;
function isAdjecentDots(cy, otherCy, cellSize) {
if (cy === otherCy) {
return false;
}
const diff = cy - otherCy < 0 ? otherCy - cy : cy - otherCy;
return diff <= cellSize + CONNECTING_ERROR_MARGIN;
}
function getMatrix(value, errorCorrectionLevel) {
const arr = Array.prototype.slice.call(QRCodeUtil.create(value, { errorCorrectionLevel }).modules.data, 0);
const sqrt = Math.sqrt(arr.length);
return arr.reduce((rows, key, index) => (index % sqrt === 0 ? rows.push([key]) : rows[rows.length - 1].push(key)) && rows, []);
}
export const QrCodeUtil = {
generate({ uri, size, logoSize, padding = 8, dotColor = 'var(--apkt-colors-black)' }) {
const strokeWidth = 10;
const dots = [];
const matrix = getMatrix(uri, 'Q');
const cellSize = (size - 2 * padding) / 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 + padding;
const y1 = (matrix.length - QRCODE_MATRIX_MARGIN) * cellSize * y + padding;
const borderRadius = 0.45;
for (let i = 0; i < qrList.length; i += 1) {
const dotSize = cellSize * (QRCODE_MATRIX_MARGIN - i * 2);
dots.push(svg `
<rect
fill=${i === 2 ? 'var(--apkt-colors-black)' : 'var(--apkt-colors-white)'}
width=${i === 0 ? dotSize - strokeWidth : dotSize}
rx= ${i === 0 ? (dotSize - strokeWidth) * borderRadius : dotSize * borderRadius}
ry= ${i === 0 ? (dotSize - strokeWidth) * borderRadius : dotSize * borderRadius}
stroke=${dotColor}
stroke-width=${i === 0 ? strokeWidth : 0}
height=${i === 0 ? dotSize - strokeWidth : dotSize}
x= ${i === 0 ? y1 + cellSize * i + strokeWidth / 2 : y1 + cellSize * i}
y= ${i === 0 ? x1 + cellSize * i + strokeWidth / 2 : x1 + cellSize * i}
/>
`);
}
});
const clearArenaSize = Math.floor((logoSize + 25) / cellSize);
const matrixMiddleStart = matrix.length / 2 - clearArenaSize / 2;
const matrixMiddleEnd = matrix.length / 2 + clearArenaSize / 2 - 1;
const circles = [];
matrix.forEach((row, i) => {
row.forEach((_, j) => {
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 + padding;
const cy = j * cellSize + cellSize / 2 + padding;
circles.push([cx, cy]);
}
}
}
});
});
const circlesToConnect = {};
circles.forEach(([cx, cy]) => {
if (circlesToConnect[cx]) {
circlesToConnect[cx]?.push(cy);
}
else {
circlesToConnect[cx] = [cy];
}
});
Object.entries(circlesToConnect)
.map(([cx, cys]) => {
const newCys = cys.filter(cy => cys.every(otherCy => !isAdjecentDots(cy, otherCy, cellSize)));
return [Number(cx), newCys];
})
.forEach(([cx, cys]) => {
cys.forEach(cy => {
dots.push(svg `<circle cx=${cx} cy=${cy} fill=${dotColor} r=${cellSize / CIRCLE_SIZE_MODIFIER} />`);
});
});
Object.entries(circlesToConnect)
.filter(([_, cys]) => cys.length > 1)
.map(([cx, cys]) => {
const newCys = cys.filter(cy => cys.some(otherCy => isAdjecentDots(cy, otherCy, cellSize)));
return [Number(cx), newCys];
})
.map(([cx, cys]) => {
cys.sort((a, b) => (a < b ? -1 : 1));
const groups = [];
for (const cy of cys) {
const group = groups.find(item => item.some(otherCy => isAdjecentDots(cy, otherCy, cellSize)));
if (group) {
group.push(cy);
}
else {
groups.push([cy]);
}
}
return [cx, groups.map(item => [item[0], item[item.length - 1]])];
})
.forEach(([cx, groups]) => {
groups.forEach(([y1, y2]) => {
dots.push(svg `
<line
x1=${cx}
x2=${cx}
y1=${y1}
y2=${y2}
stroke=${dotColor}
stroke-width=${cellSize / (CIRCLE_SIZE_MODIFIER / 2)}
stroke-linecap="round"
/>
`);
});
});
return dots;
}
};
//# sourceMappingURL=QrCode.js.map