@nuvui/barcodes 0.0.0-stage → 0.1.1

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 (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +60 -2
  3. package/dist/components/barcode/barcode.cjs +94 -0
  4. package/dist/components/barcode/barcode.d.cts +70 -0
  5. package/dist/components/barcode/barcode.d.ts +70 -0
  6. package/dist/components/barcode/barcode.js +94 -0
  7. package/dist/components/barcode/encode.cjs +86 -0
  8. package/dist/components/barcode/encode.d.cts +52 -0
  9. package/dist/components/barcode/encode.d.ts +52 -0
  10. package/dist/components/barcode/encode.js +85 -0
  11. package/dist/components/barcode/index.cjs +6 -0
  12. package/dist/components/barcode/index.d.cts +3 -0
  13. package/dist/components/barcode/index.d.ts +3 -0
  14. package/dist/components/barcode/index.js +3 -0
  15. package/dist/components/qrcode/encode.cjs +28 -0
  16. package/dist/components/qrcode/encode.d.cts +29 -0
  17. package/dist/components/qrcode/encode.d.ts +29 -0
  18. package/dist/components/qrcode/encode.js +28 -0
  19. package/dist/components/qrcode/index.cjs +6 -0
  20. package/dist/components/qrcode/index.d.cts +3 -0
  21. package/dist/components/qrcode/index.d.ts +3 -0
  22. package/dist/components/qrcode/index.js +3 -0
  23. package/dist/components/qrcode/qrcode.cjs +121 -0
  24. package/dist/components/qrcode/qrcode.d.cts +59 -0
  25. package/dist/components/qrcode/qrcode.d.ts +59 -0
  26. package/dist/components/qrcode/qrcode.js +120 -0
  27. package/dist/css/barcode.css +26 -0
  28. package/dist/css/qrcode.css +28 -0
  29. package/dist/index.cjs +15 -0
  30. package/dist/index.d.cts +8 -0
  31. package/dist/index.d.ts +8 -0
  32. package/dist/index.js +6 -0
  33. package/dist/save.cjs +120 -0
  34. package/dist/save.d.cts +38 -0
  35. package/dist/save.d.ts +38 -0
  36. package/dist/save.js +117 -0
  37. package/dist/styles.css +53 -0
  38. package/dist/utils/cx.cjs +6 -0
  39. package/dist/utils/cx.js +6 -0
  40. 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,3 @@
1
+ import { barcodeTypes, encodeBarcode } from "./encode.js";
2
+ import { Barcode } from "./barcode.js";
3
+ export { Barcode, 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,3 @@
1
+ import { encodeQRCode } from "./encode.js";
2
+ import { QRCode, QRCodeSwissCross } from "./qrcode.js";
3
+ export { QRCode, QRCodeSwissCross, 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
+ }