@nuvui/barcodes 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +60 -2
- package/dist/components/barcode/barcode.cjs +94 -0
- package/dist/components/barcode/barcode.d.cts +70 -0
- package/dist/components/barcode/barcode.d.ts +70 -0
- package/dist/components/barcode/barcode.js +94 -0
- package/dist/components/barcode/encode.cjs +86 -0
- package/dist/components/barcode/encode.d.cts +52 -0
- package/dist/components/barcode/encode.d.ts +52 -0
- package/dist/components/barcode/encode.js +85 -0
- package/dist/components/barcode/index.cjs +6 -0
- package/dist/components/barcode/index.d.cts +3 -0
- package/dist/components/barcode/index.d.ts +3 -0
- package/dist/components/barcode/index.js +3 -0
- package/dist/components/qrcode/encode.cjs +28 -0
- package/dist/components/qrcode/encode.d.cts +29 -0
- package/dist/components/qrcode/encode.d.ts +29 -0
- package/dist/components/qrcode/encode.js +28 -0
- package/dist/components/qrcode/index.cjs +6 -0
- package/dist/components/qrcode/index.d.cts +3 -0
- package/dist/components/qrcode/index.d.ts +3 -0
- package/dist/components/qrcode/index.js +3 -0
- package/dist/components/qrcode/qrcode.cjs +121 -0
- package/dist/components/qrcode/qrcode.d.cts +59 -0
- package/dist/components/qrcode/qrcode.d.ts +59 -0
- package/dist/components/qrcode/qrcode.js +120 -0
- package/dist/css/barcode.css +26 -0
- package/dist/css/qrcode.css +28 -0
- package/dist/index.cjs +15 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +6 -0
- package/dist/save.cjs +120 -0
- package/dist/save.d.cts +38 -0
- package/dist/save.d.ts +38 -0
- package/dist/save.js +117 -0
- package/dist/styles.css +53 -0
- package/dist/utils/cx.cjs +6 -0
- package/dist/utils/cx.js +6 -0
- package/package.json +118 -3
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { CODE39 } from "jsbarcode/bin/barcodes/CODE39/index.js";
|
|
2
|
+
import { CODE128 } from "jsbarcode/bin/barcodes/CODE128/index.js";
|
|
3
|
+
import { codabar } from "jsbarcode/bin/barcodes/codabar/index.js";
|
|
4
|
+
import { EAN13, EAN8, UPC, UPCE } from "jsbarcode/bin/barcodes/EAN_UPC/index.js";
|
|
5
|
+
import { ITF, ITF14 } from "jsbarcode/bin/barcodes/ITF/index.js";
|
|
6
|
+
import { MSI, MSI10, MSI1010, MSI11, MSI1110 } from "jsbarcode/bin/barcodes/MSI/index.js";
|
|
7
|
+
import { pharmacode } from "jsbarcode/bin/barcodes/pharmacode/index.js";
|
|
8
|
+
//#region src/components/barcode/encode.ts
|
|
9
|
+
const encoders = {
|
|
10
|
+
code128: [CODE128, {}],
|
|
11
|
+
"gs1-128": [CODE128, { ean128: true }],
|
|
12
|
+
code39: [CODE39, {}],
|
|
13
|
+
"code39-mod43": [CODE39, { mod43: true }],
|
|
14
|
+
ean13: [EAN13, {}],
|
|
15
|
+
ean8: [EAN8, {}],
|
|
16
|
+
upca: [UPC, {}],
|
|
17
|
+
upce: [UPCE, {}],
|
|
18
|
+
itf: [ITF, {}],
|
|
19
|
+
itf14: [ITF14, {}],
|
|
20
|
+
msi: [MSI, {}],
|
|
21
|
+
"msi-mod10": [MSI10, {}],
|
|
22
|
+
"msi-mod11": [MSI11, {}],
|
|
23
|
+
"msi-mod1010": [MSI1010, {}],
|
|
24
|
+
"msi-mod1110": [MSI1110, {}],
|
|
25
|
+
codabar: [codabar, {}],
|
|
26
|
+
pharmacode: [pharmacode, {}]
|
|
27
|
+
};
|
|
28
|
+
/** Every kind of barcode there is here. */
|
|
29
|
+
const barcodeTypes = Object.keys(encoders);
|
|
30
|
+
const grouped = /* @__PURE__ */ new Set([
|
|
31
|
+
"ean13",
|
|
32
|
+
"ean8",
|
|
33
|
+
"upca",
|
|
34
|
+
"upce"
|
|
35
|
+
]);
|
|
36
|
+
const aligned = {
|
|
37
|
+
left: "start",
|
|
38
|
+
center: "center",
|
|
39
|
+
right: "end"
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The bars for a value, or `null` if this kind of barcode can't hold it:
|
|
43
|
+
* a letter in an EAN, a check digit that's wrong, an odd number of digits
|
|
44
|
+
* in an ITF, nothing at all.
|
|
45
|
+
*
|
|
46
|
+
* It needs no browser, so it runs wherever the value is checked.
|
|
47
|
+
*/
|
|
48
|
+
function encodeBarcode(value, type = "code128", { text, flat = false } = {}) {
|
|
49
|
+
const entry = encoders[type];
|
|
50
|
+
if (!entry || typeof value !== "string" || value === "") return null;
|
|
51
|
+
const [Encoder, extra] = entry;
|
|
52
|
+
let encoded;
|
|
53
|
+
try {
|
|
54
|
+
const encoder = new Encoder(value, {
|
|
55
|
+
...extra,
|
|
56
|
+
text: grouped.has(type) ? void 0 : text,
|
|
57
|
+
flat,
|
|
58
|
+
displayValue: true,
|
|
59
|
+
fontSize: 0,
|
|
60
|
+
height: 0,
|
|
61
|
+
textMargin: 0,
|
|
62
|
+
width: 1
|
|
63
|
+
});
|
|
64
|
+
if (!encoder.valid()) return null;
|
|
65
|
+
encoded = encoder.encode();
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const parts = (Array.isArray(encoded) ? encoded : [encoded]).filter((part) => part.data.length > 0).map((part) => ({
|
|
70
|
+
bars: part.data,
|
|
71
|
+
text: part.text === void 0 ? void 0 : String(part.text),
|
|
72
|
+
guard: part.options?.height !== void 0,
|
|
73
|
+
align: aligned[part.options?.textAlign ?? "center"]
|
|
74
|
+
}));
|
|
75
|
+
const modules = parts.reduce((sum, part) => sum + part.bars.length, 0);
|
|
76
|
+
if (modules === 0) return null;
|
|
77
|
+
return {
|
|
78
|
+
type,
|
|
79
|
+
parts,
|
|
80
|
+
modules,
|
|
81
|
+
text: parts.map((part) => part.text ?? "").join("")
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
export { barcodeTypes, encodeBarcode };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_encode = require("./encode.cjs");
|
|
3
|
+
const require_barcode = require("./barcode.cjs");
|
|
4
|
+
exports.Barcode = require_barcode.Barcode;
|
|
5
|
+
exports.barcodeTypes = require_encode.barcodeTypes;
|
|
6
|
+
exports.encodeBarcode = require_encode.encodeBarcode;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { BarcodeEncodeOptions, BarcodeEncoding, BarcodePart, BarcodeType, barcodeTypes, encodeBarcode } from "./encode.cjs";
|
|
2
|
+
import { Barcode, BarcodeOwnProps, BarcodeProps } from "./barcode.cjs";
|
|
3
|
+
export { Barcode, type BarcodeEncodeOptions, type BarcodeEncoding, type BarcodeOwnProps, type BarcodePart, type BarcodeProps, type BarcodeType, barcodeTypes, encodeBarcode };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { BarcodeEncodeOptions, BarcodeEncoding, BarcodePart, BarcodeType, barcodeTypes, encodeBarcode } from "./encode.js";
|
|
2
|
+
import { Barcode, BarcodeOwnProps, BarcodeProps } from "./barcode.js";
|
|
3
|
+
export { Barcode, type BarcodeEncodeOptions, type BarcodeEncoding, type BarcodeOwnProps, type BarcodePart, type BarcodeProps, type BarcodeType, barcodeTypes, encodeBarcode };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
let uqr = require("uqr");
|
|
2
|
+
//#region src/components/qrcode/encode.ts
|
|
3
|
+
/**
|
|
4
|
+
* The squares for a value, or `null` if there's nothing to encode or it's
|
|
5
|
+
* more than a QR code holds, which at the highest level is about 1,200
|
|
6
|
+
* bytes.
|
|
7
|
+
*
|
|
8
|
+
* It needs no browser, so it runs wherever the value is checked.
|
|
9
|
+
*/
|
|
10
|
+
function encodeQRCode(value, { errorCorrection = "M" } = {}) {
|
|
11
|
+
if (typeof value !== "string" || value === "") return null;
|
|
12
|
+
try {
|
|
13
|
+
const code = (0, uqr.encode)(value, {
|
|
14
|
+
ecc: errorCorrection,
|
|
15
|
+
border: 0
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
rows: code.data,
|
|
19
|
+
size: code.size,
|
|
20
|
+
version: code.version,
|
|
21
|
+
errorCorrection
|
|
22
|
+
};
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
exports.encodeQRCode = encodeQRCode;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/components/qrcode/encode.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* How much of the code can be lost and still be read: about 7% for `"L"`,
|
|
4
|
+
* 15% for `"M"`, 25% for `"Q"` and 30% for `"H"`. A higher level makes a
|
|
5
|
+
* code with more and smaller squares for the same value.
|
|
6
|
+
*/
|
|
7
|
+
export type QRCodeErrorCorrection = "L" | "M" | "Q" | "H";
|
|
8
|
+
export interface QRCodeEncoding {
|
|
9
|
+
/** The rows of squares, `true` for a dark one. */
|
|
10
|
+
rows: boolean[][];
|
|
11
|
+
/** How many squares there are along a side. */
|
|
12
|
+
size: number;
|
|
13
|
+
/** The code's version, 1 to 40: how big it had to be for the value. */
|
|
14
|
+
version: number;
|
|
15
|
+
errorCorrection: QRCodeErrorCorrection;
|
|
16
|
+
}
|
|
17
|
+
export interface QRCodeEncodeOptions {
|
|
18
|
+
/** @default "M" */
|
|
19
|
+
errorCorrection?: QRCodeErrorCorrection;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The squares for a value, or `null` if there's nothing to encode or it's
|
|
23
|
+
* more than a QR code holds, which at the highest level is about 1,200
|
|
24
|
+
* bytes.
|
|
25
|
+
*
|
|
26
|
+
* It needs no browser, so it runs wherever the value is checked.
|
|
27
|
+
*/
|
|
28
|
+
export declare function encodeQRCode(value: string, { errorCorrection }?: QRCodeEncodeOptions): QRCodeEncoding | null;
|
|
29
|
+
//#endregion
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/components/qrcode/encode.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* How much of the code can be lost and still be read: about 7% for `"L"`,
|
|
4
|
+
* 15% for `"M"`, 25% for `"Q"` and 30% for `"H"`. A higher level makes a
|
|
5
|
+
* code with more and smaller squares for the same value.
|
|
6
|
+
*/
|
|
7
|
+
export type QRCodeErrorCorrection = "L" | "M" | "Q" | "H";
|
|
8
|
+
export interface QRCodeEncoding {
|
|
9
|
+
/** The rows of squares, `true` for a dark one. */
|
|
10
|
+
rows: boolean[][];
|
|
11
|
+
/** How many squares there are along a side. */
|
|
12
|
+
size: number;
|
|
13
|
+
/** The code's version, 1 to 40: how big it had to be for the value. */
|
|
14
|
+
version: number;
|
|
15
|
+
errorCorrection: QRCodeErrorCorrection;
|
|
16
|
+
}
|
|
17
|
+
export interface QRCodeEncodeOptions {
|
|
18
|
+
/** @default "M" */
|
|
19
|
+
errorCorrection?: QRCodeErrorCorrection;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The squares for a value, or `null` if there's nothing to encode or it's
|
|
23
|
+
* more than a QR code holds, which at the highest level is about 1,200
|
|
24
|
+
* bytes.
|
|
25
|
+
*
|
|
26
|
+
* It needs no browser, so it runs wherever the value is checked.
|
|
27
|
+
*/
|
|
28
|
+
export declare function encodeQRCode(value: string, { errorCorrection }?: QRCodeEncodeOptions): QRCodeEncoding | null;
|
|
29
|
+
//#endregion
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { encode } from "uqr";
|
|
2
|
+
//#region src/components/qrcode/encode.ts
|
|
3
|
+
/**
|
|
4
|
+
* The squares for a value, or `null` if there's nothing to encode or it's
|
|
5
|
+
* more than a QR code holds, which at the highest level is about 1,200
|
|
6
|
+
* bytes.
|
|
7
|
+
*
|
|
8
|
+
* It needs no browser, so it runs wherever the value is checked.
|
|
9
|
+
*/
|
|
10
|
+
function encodeQRCode(value, { errorCorrection = "M" } = {}) {
|
|
11
|
+
if (typeof value !== "string" || value === "") return null;
|
|
12
|
+
try {
|
|
13
|
+
const code = encode(value, {
|
|
14
|
+
ecc: errorCorrection,
|
|
15
|
+
border: 0
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
rows: code.data,
|
|
19
|
+
size: code.size,
|
|
20
|
+
version: code.version,
|
|
21
|
+
errorCorrection
|
|
22
|
+
};
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { encodeQRCode };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_encode = require("./encode.cjs");
|
|
3
|
+
const require_qrcode = require("./qrcode.cjs");
|
|
4
|
+
exports.QRCode = require_qrcode.QRCode;
|
|
5
|
+
exports.QRCodeSwissCross = require_qrcode.QRCodeSwissCross;
|
|
6
|
+
exports.encodeQRCode = require_encode.encodeQRCode;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { QRCodeEncodeOptions, QRCodeEncoding, QRCodeErrorCorrection, encodeQRCode } from "./encode.cjs";
|
|
2
|
+
import { QRCode, QRCodeOwnProps, QRCodeProps, QRCodeSwissCross, QRCodeSwissCrossProps } from "./qrcode.cjs";
|
|
3
|
+
export { QRCode, type QRCodeEncodeOptions, type QRCodeEncoding, type QRCodeErrorCorrection, type QRCodeOwnProps, type QRCodeProps, QRCodeSwissCross, type QRCodeSwissCrossProps, encodeQRCode };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { QRCodeEncodeOptions, QRCodeEncoding, QRCodeErrorCorrection, encodeQRCode } from "./encode.js";
|
|
2
|
+
import { QRCode, QRCodeOwnProps, QRCodeProps, QRCodeSwissCross, QRCodeSwissCrossProps } from "./qrcode.js";
|
|
3
|
+
export { QRCode, type QRCodeEncodeOptions, type QRCodeEncoding, type QRCodeErrorCorrection, type QRCodeOwnProps, type QRCodeProps, QRCodeSwissCross, type QRCodeSwissCrossProps, encodeQRCode };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const require_cx = require("../../utils/cx.cjs");
|
|
2
|
+
const require_encode = require("./encode.cjs");
|
|
3
|
+
let react = require("react");
|
|
4
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
5
|
+
//#region src/components/qrcode/qrcode.tsx
|
|
6
|
+
const emptySize = 21;
|
|
7
|
+
/**
|
|
8
|
+
* A QR code, drawn as an SVG. It's a picture with a name: say what the
|
|
9
|
+
* code is for with `aria-label`, and without one the name is the value.
|
|
10
|
+
*
|
|
11
|
+
* It has no state and needs no browser, so it can be a server component.
|
|
12
|
+
*/
|
|
13
|
+
const QRCode = (0, react.forwardRef)(function QRCode({ value, size = 160, errorCorrection, quietZone = 4, overlay, overlaySize = .2, fallback, className, "aria-label": label, "aria-labelledby": labelledBy, ...props }, ref) {
|
|
14
|
+
const covered = overlay !== void 0 && overlay !== null && overlay !== false;
|
|
15
|
+
const encoding = require_encode.encodeQRCode(value, { errorCorrection: errorCorrection ?? (covered ? "H" : "M") });
|
|
16
|
+
if (!encoding && fallback !== void 0) return fallback;
|
|
17
|
+
const side = encoding?.size ?? emptySize;
|
|
18
|
+
const whole = side + quietZone * 2;
|
|
19
|
+
const name = labelledBy ? void 0 : label ?? value;
|
|
20
|
+
const root = {
|
|
21
|
+
ref,
|
|
22
|
+
width: size,
|
|
23
|
+
height: size,
|
|
24
|
+
viewBox: `0 0 ${whole} ${whole}`,
|
|
25
|
+
...props
|
|
26
|
+
};
|
|
27
|
+
if (!encoding) {
|
|
28
|
+
const hair = whole / size;
|
|
29
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
30
|
+
...root,
|
|
31
|
+
role: "img",
|
|
32
|
+
"aria-label": name,
|
|
33
|
+
"aria-labelledby": labelledBy,
|
|
34
|
+
className: require_cx.cx("nuv-qrcode", className),
|
|
35
|
+
"data-invalid": "",
|
|
36
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
37
|
+
className: "nuv-qrcode__ground",
|
|
38
|
+
width: "100%",
|
|
39
|
+
height: "100%"
|
|
40
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
41
|
+
className: "nuv-qrcode__mark",
|
|
42
|
+
strokeWidth: hair,
|
|
43
|
+
strokeDasharray: `${hair * 4} ${hair * 3}`,
|
|
44
|
+
d: `M${hair / 2} ${hair / 2}H${whole - hair / 2}V${whole - hair / 2}H${hair / 2}ZM${hair / 2} ${whole - hair / 2}L${whole - hair / 2} ${hair / 2}`
|
|
45
|
+
})]
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
let squares = "";
|
|
49
|
+
for (const [y, row] of encoding.rows.entries()) {
|
|
50
|
+
let x = 0;
|
|
51
|
+
while (x < side) {
|
|
52
|
+
if (!row[x]) {
|
|
53
|
+
x += 1;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
let end = x;
|
|
57
|
+
while (end < side && row[end]) end += 1;
|
|
58
|
+
squares += `M${x + quietZone} ${y + quietZone}h${end - x}v1h${x - end}z`;
|
|
59
|
+
x = end;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const box = Math.round(side * Math.min(.3, Math.max(.1, overlaySize)) * 1e3) / 1e3;
|
|
63
|
+
const corner = Math.round((quietZone + (side - box) / 2) * 1e3) / 1e3;
|
|
64
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
65
|
+
...root,
|
|
66
|
+
role: "img",
|
|
67
|
+
"aria-label": name,
|
|
68
|
+
"aria-labelledby": labelledBy,
|
|
69
|
+
className: require_cx.cx("nuv-qrcode", className),
|
|
70
|
+
"data-error-correction": encoding.errorCorrection,
|
|
71
|
+
"data-version": encoding.version,
|
|
72
|
+
children: [
|
|
73
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
74
|
+
className: "nuv-qrcode__ground",
|
|
75
|
+
width: "100%",
|
|
76
|
+
height: "100%"
|
|
77
|
+
}),
|
|
78
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
79
|
+
className: "nuv-qrcode__squares",
|
|
80
|
+
d: squares
|
|
81
|
+
}),
|
|
82
|
+
covered ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
83
|
+
className: "nuv-qrcode__overlay",
|
|
84
|
+
x: corner,
|
|
85
|
+
y: corner,
|
|
86
|
+
width: box,
|
|
87
|
+
height: box,
|
|
88
|
+
viewBox: "0 0 100 100",
|
|
89
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
90
|
+
className: "nuv-qrcode__ground",
|
|
91
|
+
width: "100",
|
|
92
|
+
height: "100"
|
|
93
|
+
}), overlay]
|
|
94
|
+
}) : null
|
|
95
|
+
]
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
/**
|
|
99
|
+
* The Swiss cross that marks a QR-bill's code, for `overlay`. The rules
|
|
100
|
+
* for a QR-bill ask for error correction `"M"` and a cross 7 mm wide on a
|
|
101
|
+
* code of 46 mm, which is an `overlaySize` of 0.152.
|
|
102
|
+
*/
|
|
103
|
+
const QRCodeSwissCross = (0, react.forwardRef)(function QRCodeSwissCross(props, ref) {
|
|
104
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
105
|
+
ref,
|
|
106
|
+
...props,
|
|
107
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
108
|
+
className: "nuv-qrcode__cross-ground",
|
|
109
|
+
x: "8",
|
|
110
|
+
y: "8",
|
|
111
|
+
width: "84",
|
|
112
|
+
height: "84"
|
|
113
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
114
|
+
className: "nuv-qrcode__cross-arms",
|
|
115
|
+
d: "M42.125 23.75h15.75v18.375h18.375v15.75H57.875v18.375h-15.75V57.875H23.75v-15.75h18.375z"
|
|
116
|
+
})]
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
//#endregion
|
|
120
|
+
exports.QRCode = QRCode;
|
|
121
|
+
exports.QRCodeSwissCross = QRCodeSwissCross;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { QRCodeErrorCorrection } from "./encode.cjs";
|
|
2
|
+
import { ReactNode, SVGAttributes } from "react";
|
|
3
|
+
//#region src/components/qrcode/qrcode.d.ts
|
|
4
|
+
export interface QRCodeOwnProps {
|
|
5
|
+
/** What the code holds: an address, most often, or any text. */
|
|
6
|
+
value: string;
|
|
7
|
+
/**
|
|
8
|
+
* The width and the height, in pixels, with the empty edge.
|
|
9
|
+
* @default 160
|
|
10
|
+
*/
|
|
11
|
+
size?: number;
|
|
12
|
+
/**
|
|
13
|
+
* How much of the code can be lost and still be read, from `"L"`, about
|
|
14
|
+
* 7%, to `"H"`, about 30%. Left out, it's `"M"`, or `"H"` when there's
|
|
15
|
+
* an `overlay`, which covers part of the code.
|
|
16
|
+
*/
|
|
17
|
+
errorCorrection?: QRCodeErrorCorrection;
|
|
18
|
+
/**
|
|
19
|
+
* The empty space around the code, counted in its squares. A scanner
|
|
20
|
+
* finds the code by it, and the standard asks for four.
|
|
21
|
+
* @default 4
|
|
22
|
+
*/
|
|
23
|
+
quietZone?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Something drawn over the middle, such as a logo. It's SVG, drawn in a
|
|
26
|
+
* box 100 by 100: an `<image>`, shapes of your own, or
|
|
27
|
+
* `<QRCodeSwissCross />`. The squares under it are lost, which the
|
|
28
|
+
* error correction makes up for.
|
|
29
|
+
*/
|
|
30
|
+
overlay?: ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* How much of the code's side the overlay takes, from 0.1 to 0.3. More
|
|
33
|
+
* than a fifth and some phones stop reading it: try the code you ship.
|
|
34
|
+
* @default 0.2
|
|
35
|
+
*/
|
|
36
|
+
overlaySize?: number;
|
|
37
|
+
/**
|
|
38
|
+
* What's drawn when the value can't be a QR code: nothing to encode, or
|
|
39
|
+
* more than one holds. Without it there's an empty box with a line
|
|
40
|
+
* through it, which no scanner reads as anything.
|
|
41
|
+
*/
|
|
42
|
+
fallback?: ReactNode;
|
|
43
|
+
}
|
|
44
|
+
export interface QRCodeProps extends QRCodeOwnProps, Omit<SVGAttributes<SVGSVGElement>, keyof QRCodeOwnProps> {}
|
|
45
|
+
/**
|
|
46
|
+
* A QR code, drawn as an SVG. It's a picture with a name: say what the
|
|
47
|
+
* code is for with `aria-label`, and without one the name is the value.
|
|
48
|
+
*
|
|
49
|
+
* It has no state and needs no browser, so it can be a server component.
|
|
50
|
+
*/
|
|
51
|
+
export declare const QRCode: import("react").ForwardRefExoticComponent<QRCodeProps & import("react").RefAttributes<SVGSVGElement>>;
|
|
52
|
+
export interface QRCodeSwissCrossProps extends SVGAttributes<SVGGElement> {}
|
|
53
|
+
/**
|
|
54
|
+
* The Swiss cross that marks a QR-bill's code, for `overlay`. The rules
|
|
55
|
+
* for a QR-bill ask for error correction `"M"` and a cross 7 mm wide on a
|
|
56
|
+
* code of 46 mm, which is an `overlaySize` of 0.152.
|
|
57
|
+
*/
|
|
58
|
+
export declare const QRCodeSwissCross: import("react").ForwardRefExoticComponent<QRCodeSwissCrossProps & import("react").RefAttributes<SVGGElement>>;
|
|
59
|
+
//#endregion
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { QRCodeErrorCorrection } from "./encode.js";
|
|
2
|
+
import { ReactNode, SVGAttributes } from "react";
|
|
3
|
+
//#region src/components/qrcode/qrcode.d.ts
|
|
4
|
+
export interface QRCodeOwnProps {
|
|
5
|
+
/** What the code holds: an address, most often, or any text. */
|
|
6
|
+
value: string;
|
|
7
|
+
/**
|
|
8
|
+
* The width and the height, in pixels, with the empty edge.
|
|
9
|
+
* @default 160
|
|
10
|
+
*/
|
|
11
|
+
size?: number;
|
|
12
|
+
/**
|
|
13
|
+
* How much of the code can be lost and still be read, from `"L"`, about
|
|
14
|
+
* 7%, to `"H"`, about 30%. Left out, it's `"M"`, or `"H"` when there's
|
|
15
|
+
* an `overlay`, which covers part of the code.
|
|
16
|
+
*/
|
|
17
|
+
errorCorrection?: QRCodeErrorCorrection;
|
|
18
|
+
/**
|
|
19
|
+
* The empty space around the code, counted in its squares. A scanner
|
|
20
|
+
* finds the code by it, and the standard asks for four.
|
|
21
|
+
* @default 4
|
|
22
|
+
*/
|
|
23
|
+
quietZone?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Something drawn over the middle, such as a logo. It's SVG, drawn in a
|
|
26
|
+
* box 100 by 100: an `<image>`, shapes of your own, or
|
|
27
|
+
* `<QRCodeSwissCross />`. The squares under it are lost, which the
|
|
28
|
+
* error correction makes up for.
|
|
29
|
+
*/
|
|
30
|
+
overlay?: ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* How much of the code's side the overlay takes, from 0.1 to 0.3. More
|
|
33
|
+
* than a fifth and some phones stop reading it: try the code you ship.
|
|
34
|
+
* @default 0.2
|
|
35
|
+
*/
|
|
36
|
+
overlaySize?: number;
|
|
37
|
+
/**
|
|
38
|
+
* What's drawn when the value can't be a QR code: nothing to encode, or
|
|
39
|
+
* more than one holds. Without it there's an empty box with a line
|
|
40
|
+
* through it, which no scanner reads as anything.
|
|
41
|
+
*/
|
|
42
|
+
fallback?: ReactNode;
|
|
43
|
+
}
|
|
44
|
+
export interface QRCodeProps extends QRCodeOwnProps, Omit<SVGAttributes<SVGSVGElement>, keyof QRCodeOwnProps> {}
|
|
45
|
+
/**
|
|
46
|
+
* A QR code, drawn as an SVG. It's a picture with a name: say what the
|
|
47
|
+
* code is for with `aria-label`, and without one the name is the value.
|
|
48
|
+
*
|
|
49
|
+
* It has no state and needs no browser, so it can be a server component.
|
|
50
|
+
*/
|
|
51
|
+
export declare const QRCode: import("react").ForwardRefExoticComponent<QRCodeProps & import("react").RefAttributes<SVGSVGElement>>;
|
|
52
|
+
export interface QRCodeSwissCrossProps extends SVGAttributes<SVGGElement> {}
|
|
53
|
+
/**
|
|
54
|
+
* The Swiss cross that marks a QR-bill's code, for `overlay`. The rules
|
|
55
|
+
* for a QR-bill ask for error correction `"M"` and a cross 7 mm wide on a
|
|
56
|
+
* code of 46 mm, which is an `overlaySize` of 0.152.
|
|
57
|
+
*/
|
|
58
|
+
export declare const QRCodeSwissCross: import("react").ForwardRefExoticComponent<QRCodeSwissCrossProps & import("react").RefAttributes<SVGGElement>>;
|
|
59
|
+
//#endregion
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { cx } from "../../utils/cx.js";
|
|
2
|
+
import { encodeQRCode } from "./encode.js";
|
|
3
|
+
import { forwardRef } from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/qrcode/qrcode.tsx
|
|
6
|
+
const emptySize = 21;
|
|
7
|
+
/**
|
|
8
|
+
* A QR code, drawn as an SVG. It's a picture with a name: say what the
|
|
9
|
+
* code is for with `aria-label`, and without one the name is the value.
|
|
10
|
+
*
|
|
11
|
+
* It has no state and needs no browser, so it can be a server component.
|
|
12
|
+
*/
|
|
13
|
+
const QRCode = forwardRef(function QRCode({ value, size = 160, errorCorrection, quietZone = 4, overlay, overlaySize = .2, fallback, className, "aria-label": label, "aria-labelledby": labelledBy, ...props }, ref) {
|
|
14
|
+
const covered = overlay !== void 0 && overlay !== null && overlay !== false;
|
|
15
|
+
const encoding = encodeQRCode(value, { errorCorrection: errorCorrection ?? (covered ? "H" : "M") });
|
|
16
|
+
if (!encoding && fallback !== void 0) return fallback;
|
|
17
|
+
const side = encoding?.size ?? emptySize;
|
|
18
|
+
const whole = side + quietZone * 2;
|
|
19
|
+
const name = labelledBy ? void 0 : label ?? value;
|
|
20
|
+
const root = {
|
|
21
|
+
ref,
|
|
22
|
+
width: size,
|
|
23
|
+
height: size,
|
|
24
|
+
viewBox: `0 0 ${whole} ${whole}`,
|
|
25
|
+
...props
|
|
26
|
+
};
|
|
27
|
+
if (!encoding) {
|
|
28
|
+
const hair = whole / size;
|
|
29
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
30
|
+
...root,
|
|
31
|
+
role: "img",
|
|
32
|
+
"aria-label": name,
|
|
33
|
+
"aria-labelledby": labelledBy,
|
|
34
|
+
className: cx("nuv-qrcode", className),
|
|
35
|
+
"data-invalid": "",
|
|
36
|
+
children: [/* @__PURE__ */ jsx("rect", {
|
|
37
|
+
className: "nuv-qrcode__ground",
|
|
38
|
+
width: "100%",
|
|
39
|
+
height: "100%"
|
|
40
|
+
}), /* @__PURE__ */ jsx("path", {
|
|
41
|
+
className: "nuv-qrcode__mark",
|
|
42
|
+
strokeWidth: hair,
|
|
43
|
+
strokeDasharray: `${hair * 4} ${hair * 3}`,
|
|
44
|
+
d: `M${hair / 2} ${hair / 2}H${whole - hair / 2}V${whole - hair / 2}H${hair / 2}ZM${hair / 2} ${whole - hair / 2}L${whole - hair / 2} ${hair / 2}`
|
|
45
|
+
})]
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
let squares = "";
|
|
49
|
+
for (const [y, row] of encoding.rows.entries()) {
|
|
50
|
+
let x = 0;
|
|
51
|
+
while (x < side) {
|
|
52
|
+
if (!row[x]) {
|
|
53
|
+
x += 1;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
let end = x;
|
|
57
|
+
while (end < side && row[end]) end += 1;
|
|
58
|
+
squares += `M${x + quietZone} ${y + quietZone}h${end - x}v1h${x - end}z`;
|
|
59
|
+
x = end;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const box = Math.round(side * Math.min(.3, Math.max(.1, overlaySize)) * 1e3) / 1e3;
|
|
63
|
+
const corner = Math.round((quietZone + (side - box) / 2) * 1e3) / 1e3;
|
|
64
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
65
|
+
...root,
|
|
66
|
+
role: "img",
|
|
67
|
+
"aria-label": name,
|
|
68
|
+
"aria-labelledby": labelledBy,
|
|
69
|
+
className: cx("nuv-qrcode", className),
|
|
70
|
+
"data-error-correction": encoding.errorCorrection,
|
|
71
|
+
"data-version": encoding.version,
|
|
72
|
+
children: [
|
|
73
|
+
/* @__PURE__ */ jsx("rect", {
|
|
74
|
+
className: "nuv-qrcode__ground",
|
|
75
|
+
width: "100%",
|
|
76
|
+
height: "100%"
|
|
77
|
+
}),
|
|
78
|
+
/* @__PURE__ */ jsx("path", {
|
|
79
|
+
className: "nuv-qrcode__squares",
|
|
80
|
+
d: squares
|
|
81
|
+
}),
|
|
82
|
+
covered ? /* @__PURE__ */ jsxs("svg", {
|
|
83
|
+
className: "nuv-qrcode__overlay",
|
|
84
|
+
x: corner,
|
|
85
|
+
y: corner,
|
|
86
|
+
width: box,
|
|
87
|
+
height: box,
|
|
88
|
+
viewBox: "0 0 100 100",
|
|
89
|
+
children: [/* @__PURE__ */ jsx("rect", {
|
|
90
|
+
className: "nuv-qrcode__ground",
|
|
91
|
+
width: "100",
|
|
92
|
+
height: "100"
|
|
93
|
+
}), overlay]
|
|
94
|
+
}) : null
|
|
95
|
+
]
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
/**
|
|
99
|
+
* The Swiss cross that marks a QR-bill's code, for `overlay`. The rules
|
|
100
|
+
* for a QR-bill ask for error correction `"M"` and a cross 7 mm wide on a
|
|
101
|
+
* code of 46 mm, which is an `overlaySize` of 0.152.
|
|
102
|
+
*/
|
|
103
|
+
const QRCodeSwissCross = forwardRef(function QRCodeSwissCross(props, ref) {
|
|
104
|
+
return /* @__PURE__ */ jsxs("g", {
|
|
105
|
+
ref,
|
|
106
|
+
...props,
|
|
107
|
+
children: [/* @__PURE__ */ jsx("rect", {
|
|
108
|
+
className: "nuv-qrcode__cross-ground",
|
|
109
|
+
x: "8",
|
|
110
|
+
y: "8",
|
|
111
|
+
width: "84",
|
|
112
|
+
height: "84"
|
|
113
|
+
}), /* @__PURE__ */ jsx("path", {
|
|
114
|
+
className: "nuv-qrcode__cross-arms",
|
|
115
|
+
d: "M42.125 23.75h15.75v18.375h18.375v15.75H57.875v18.375h-15.75V57.875H23.75v-15.75h18.375z"
|
|
116
|
+
})]
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
//#endregion
|
|
120
|
+
export { QRCode, QRCodeSwissCross };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
@layer tokens, base, components;
|
|
2
|
+
@layer components {
|
|
3
|
+
.nuv-barcode {
|
|
4
|
+
display: block;
|
|
5
|
+
max-inline-size: 100%;
|
|
6
|
+
block-size: auto;
|
|
7
|
+
forced-color-adjust: none;
|
|
8
|
+
}
|
|
9
|
+
.nuv-barcode__ground {
|
|
10
|
+
fill: var(--nuv-barcode-bg, var(--color-white));
|
|
11
|
+
}
|
|
12
|
+
.nuv-barcode__bars {
|
|
13
|
+
fill: var(--nuv-barcode-fg, var(--color-black));
|
|
14
|
+
}
|
|
15
|
+
.nuv-barcode__text {
|
|
16
|
+
direction: ltr;
|
|
17
|
+
fill: var(--nuv-barcode-fg, var(--color-black));
|
|
18
|
+
font-family: var(--nuv-barcode-font, var(--font-mono));
|
|
19
|
+
}
|
|
20
|
+
.nuv-barcode__mark {
|
|
21
|
+
fill: none;
|
|
22
|
+
stroke: var(--nuv-barcode-invalid, var(--color-danger));
|
|
23
|
+
stroke-width: 1;
|
|
24
|
+
stroke-dasharray: 4 3;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
@layer tokens, base, components;
|
|
2
|
+
@layer components {
|
|
3
|
+
.nuv-qrcode {
|
|
4
|
+
display: block;
|
|
5
|
+
max-inline-size: 100%;
|
|
6
|
+
block-size: auto;
|
|
7
|
+
forced-color-adjust: none;
|
|
8
|
+
}
|
|
9
|
+
.nuv-qrcode__ground {
|
|
10
|
+
fill: var(--nuv-qrcode-bg, var(--color-white));
|
|
11
|
+
}
|
|
12
|
+
.nuv-qrcode__squares {
|
|
13
|
+
fill: var(--nuv-qrcode-fg, var(--color-black));
|
|
14
|
+
}
|
|
15
|
+
.nuv-qrcode__overlay {
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
}
|
|
18
|
+
.nuv-qrcode__cross-ground {
|
|
19
|
+
fill: var(--color-black);
|
|
20
|
+
}
|
|
21
|
+
.nuv-qrcode__cross-arms {
|
|
22
|
+
fill: var(--color-white);
|
|
23
|
+
}
|
|
24
|
+
.nuv-qrcode__mark {
|
|
25
|
+
fill: none;
|
|
26
|
+
stroke: var(--nuv-qrcode-invalid, var(--color-danger));
|
|
27
|
+
}
|
|
28
|
+
}
|