@c2n/qr-code 0.0.9

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Nguyen Thai Vinh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # QR Code
2
+
3
+ Accessible, themeable SVG QR codes for Lit and any framework that supports web components.
4
+
5
+ ```html
6
+ <script type="module" src="@c2n/qr-code"></script>
7
+
8
+ <c2-qr-code value="https://example.com" aria-label="Example website QR code"></c2-qr-code>
9
+ ```
@@ -0,0 +1,1022 @@
1
+ import { LitElement, html, unsafeCSS } from "lit";
2
+ import { property, state } from "lit/decorators.js";
3
+ import { styleMap } from "lit/directives/style-map.js";
4
+ import { customElement } from "@c2n/core/element-helper.js";
5
+ //#region ../../../node_modules/uqr/dist/index.mjs
6
+ var QrCodeDataType = /* @__PURE__ */ ((QrCodeDataType2) => {
7
+ QrCodeDataType2[QrCodeDataType2["Border"] = -1] = "Border";
8
+ QrCodeDataType2[QrCodeDataType2["Data"] = 0] = "Data";
9
+ QrCodeDataType2[QrCodeDataType2["Function"] = 1] = "Function";
10
+ QrCodeDataType2[QrCodeDataType2["Position"] = 2] = "Position";
11
+ QrCodeDataType2[QrCodeDataType2["Timing"] = 3] = "Timing";
12
+ QrCodeDataType2[QrCodeDataType2["Alignment"] = 4] = "Alignment";
13
+ return QrCodeDataType2;
14
+ })(QrCodeDataType || {});
15
+ var LOW = [0, 1];
16
+ var MEDIUM = [1, 0];
17
+ var QUARTILE = [2, 3];
18
+ var HIGH = [3, 2];
19
+ var EccMap = {
20
+ L: LOW,
21
+ M: MEDIUM,
22
+ Q: QUARTILE,
23
+ H: HIGH
24
+ };
25
+ var NUMERIC_REGEX = /^\d*$/;
26
+ var ALPHANUMERIC_REGEX = /^[A-Z0-9 $%*+./:-]*$/;
27
+ var ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
28
+ var MIN_VERSION = 1;
29
+ var MAX_VERSION = 40;
30
+ var PENALTY_N1 = 3;
31
+ var PENALTY_N2 = 3;
32
+ var PENALTY_N3 = 40;
33
+ var PENALTY_N4 = 10;
34
+ var ECC_CODEWORDS_PER_BLOCK = [
35
+ [
36
+ -1,
37
+ 7,
38
+ 10,
39
+ 15,
40
+ 20,
41
+ 26,
42
+ 18,
43
+ 20,
44
+ 24,
45
+ 30,
46
+ 18,
47
+ 20,
48
+ 24,
49
+ 26,
50
+ 30,
51
+ 22,
52
+ 24,
53
+ 28,
54
+ 30,
55
+ 28,
56
+ 28,
57
+ 28,
58
+ 28,
59
+ 30,
60
+ 30,
61
+ 26,
62
+ 28,
63
+ 30,
64
+ 30,
65
+ 30,
66
+ 30,
67
+ 30,
68
+ 30,
69
+ 30,
70
+ 30,
71
+ 30,
72
+ 30,
73
+ 30,
74
+ 30,
75
+ 30,
76
+ 30
77
+ ],
78
+ [
79
+ -1,
80
+ 10,
81
+ 16,
82
+ 26,
83
+ 18,
84
+ 24,
85
+ 16,
86
+ 18,
87
+ 22,
88
+ 22,
89
+ 26,
90
+ 30,
91
+ 22,
92
+ 22,
93
+ 24,
94
+ 24,
95
+ 28,
96
+ 28,
97
+ 26,
98
+ 26,
99
+ 26,
100
+ 26,
101
+ 28,
102
+ 28,
103
+ 28,
104
+ 28,
105
+ 28,
106
+ 28,
107
+ 28,
108
+ 28,
109
+ 28,
110
+ 28,
111
+ 28,
112
+ 28,
113
+ 28,
114
+ 28,
115
+ 28,
116
+ 28,
117
+ 28,
118
+ 28,
119
+ 28
120
+ ],
121
+ [
122
+ -1,
123
+ 13,
124
+ 22,
125
+ 18,
126
+ 26,
127
+ 18,
128
+ 24,
129
+ 18,
130
+ 22,
131
+ 20,
132
+ 24,
133
+ 28,
134
+ 26,
135
+ 24,
136
+ 20,
137
+ 30,
138
+ 24,
139
+ 28,
140
+ 28,
141
+ 26,
142
+ 30,
143
+ 28,
144
+ 30,
145
+ 30,
146
+ 30,
147
+ 30,
148
+ 28,
149
+ 30,
150
+ 30,
151
+ 30,
152
+ 30,
153
+ 30,
154
+ 30,
155
+ 30,
156
+ 30,
157
+ 30,
158
+ 30,
159
+ 30,
160
+ 30,
161
+ 30,
162
+ 30
163
+ ],
164
+ [
165
+ -1,
166
+ 17,
167
+ 28,
168
+ 22,
169
+ 16,
170
+ 22,
171
+ 28,
172
+ 26,
173
+ 26,
174
+ 24,
175
+ 28,
176
+ 24,
177
+ 28,
178
+ 22,
179
+ 24,
180
+ 24,
181
+ 30,
182
+ 28,
183
+ 28,
184
+ 26,
185
+ 28,
186
+ 30,
187
+ 24,
188
+ 30,
189
+ 30,
190
+ 30,
191
+ 30,
192
+ 30,
193
+ 30,
194
+ 30,
195
+ 30,
196
+ 30,
197
+ 30,
198
+ 30,
199
+ 30,
200
+ 30,
201
+ 30,
202
+ 30,
203
+ 30,
204
+ 30,
205
+ 30
206
+ ]
207
+ ];
208
+ var NUM_ERROR_CORRECTION_BLOCKS = [
209
+ [
210
+ -1,
211
+ 1,
212
+ 1,
213
+ 1,
214
+ 1,
215
+ 1,
216
+ 2,
217
+ 2,
218
+ 2,
219
+ 2,
220
+ 4,
221
+ 4,
222
+ 4,
223
+ 4,
224
+ 4,
225
+ 6,
226
+ 6,
227
+ 6,
228
+ 6,
229
+ 7,
230
+ 8,
231
+ 8,
232
+ 9,
233
+ 9,
234
+ 10,
235
+ 12,
236
+ 12,
237
+ 12,
238
+ 13,
239
+ 14,
240
+ 15,
241
+ 16,
242
+ 17,
243
+ 18,
244
+ 19,
245
+ 19,
246
+ 20,
247
+ 21,
248
+ 22,
249
+ 24,
250
+ 25
251
+ ],
252
+ [
253
+ -1,
254
+ 1,
255
+ 1,
256
+ 1,
257
+ 2,
258
+ 2,
259
+ 4,
260
+ 4,
261
+ 4,
262
+ 5,
263
+ 5,
264
+ 5,
265
+ 8,
266
+ 9,
267
+ 9,
268
+ 10,
269
+ 10,
270
+ 11,
271
+ 13,
272
+ 14,
273
+ 16,
274
+ 17,
275
+ 17,
276
+ 18,
277
+ 20,
278
+ 21,
279
+ 23,
280
+ 25,
281
+ 26,
282
+ 28,
283
+ 29,
284
+ 31,
285
+ 33,
286
+ 35,
287
+ 37,
288
+ 38,
289
+ 40,
290
+ 43,
291
+ 45,
292
+ 47,
293
+ 49
294
+ ],
295
+ [
296
+ -1,
297
+ 1,
298
+ 1,
299
+ 2,
300
+ 2,
301
+ 4,
302
+ 4,
303
+ 6,
304
+ 6,
305
+ 8,
306
+ 8,
307
+ 8,
308
+ 10,
309
+ 12,
310
+ 16,
311
+ 12,
312
+ 17,
313
+ 16,
314
+ 18,
315
+ 21,
316
+ 20,
317
+ 23,
318
+ 23,
319
+ 25,
320
+ 27,
321
+ 29,
322
+ 34,
323
+ 34,
324
+ 35,
325
+ 38,
326
+ 40,
327
+ 43,
328
+ 45,
329
+ 48,
330
+ 51,
331
+ 53,
332
+ 56,
333
+ 59,
334
+ 62,
335
+ 65,
336
+ 68
337
+ ],
338
+ [
339
+ -1,
340
+ 1,
341
+ 1,
342
+ 2,
343
+ 4,
344
+ 4,
345
+ 4,
346
+ 5,
347
+ 6,
348
+ 8,
349
+ 8,
350
+ 11,
351
+ 11,
352
+ 16,
353
+ 16,
354
+ 18,
355
+ 16,
356
+ 19,
357
+ 21,
358
+ 25,
359
+ 25,
360
+ 25,
361
+ 34,
362
+ 30,
363
+ 32,
364
+ 35,
365
+ 37,
366
+ 40,
367
+ 42,
368
+ 45,
369
+ 48,
370
+ 51,
371
+ 54,
372
+ 57,
373
+ 60,
374
+ 63,
375
+ 66,
376
+ 70,
377
+ 74,
378
+ 77,
379
+ 81
380
+ ]
381
+ ];
382
+ var QrCode$1 = class {
383
+ constructor(version, ecc, dataCodewords, msk) {
384
+ this.version = version;
385
+ this.ecc = ecc;
386
+ if (version < MIN_VERSION || version > MAX_VERSION) throw new RangeError("Version value out of range");
387
+ if (msk < -1 || msk > 7) throw new RangeError("Mask value out of range");
388
+ this.size = version * 4 + 17;
389
+ const row = Array.from({ length: this.size }).fill(false);
390
+ for (let i = 0; i < this.size; i++) {
391
+ this.modules.push(row.slice());
392
+ this.types.push(row.map(() => 0));
393
+ }
394
+ this.drawFunctionPatterns();
395
+ const allCodewords = this.addEccAndInterleave(dataCodewords);
396
+ this.drawCodewords(allCodewords);
397
+ if (msk === -1) {
398
+ let minPenalty = 1e9;
399
+ for (let i = 0; i < 8; i++) {
400
+ this.applyMask(i);
401
+ this.drawFormatBits(i);
402
+ const penalty = this.getPenaltyScore();
403
+ if (penalty < minPenalty) {
404
+ msk = i;
405
+ minPenalty = penalty;
406
+ }
407
+ this.applyMask(i);
408
+ }
409
+ }
410
+ this.mask = msk;
411
+ this.applyMask(msk);
412
+ this.drawFormatBits(msk);
413
+ }
414
+ size;
415
+ mask;
416
+ modules = [];
417
+ types = [];
418
+ getModule(x, y) {
419
+ return x >= 0 && x < this.size && y >= 0 && y < this.size && this.modules[y][x];
420
+ }
421
+ drawFunctionPatterns() {
422
+ for (let i = 0; i < this.size; i++) {
423
+ this.setFunctionModule(6, i, i % 2 === 0, QrCodeDataType.Timing);
424
+ this.setFunctionModule(i, 6, i % 2 === 0, QrCodeDataType.Timing);
425
+ }
426
+ this.drawFinderPattern(3, 3);
427
+ this.drawFinderPattern(this.size - 4, 3);
428
+ this.drawFinderPattern(3, this.size - 4);
429
+ const alignPatPos = this.getAlignmentPatternPositions();
430
+ const numAlign = alignPatPos.length;
431
+ for (let i = 0; i < numAlign; i++) for (let j = 0; j < numAlign; j++) if (!(i === 0 && j === 0 || i === 0 && j === numAlign - 1 || i === numAlign - 1 && j === 0)) this.drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
432
+ this.drawFormatBits(0);
433
+ this.drawVersion();
434
+ }
435
+ drawFormatBits(mask) {
436
+ const data = this.ecc[1] << 3 | mask;
437
+ let rem = data;
438
+ for (let i = 0; i < 10; i++) rem = rem << 1 ^ (rem >>> 9) * 1335;
439
+ const bits = (data << 10 | rem) ^ 21522;
440
+ for (let i = 0; i <= 5; i++) this.setFunctionModule(8, i, getBit(bits, i));
441
+ this.setFunctionModule(8, 7, getBit(bits, 6));
442
+ this.setFunctionModule(8, 8, getBit(bits, 7));
443
+ this.setFunctionModule(7, 8, getBit(bits, 8));
444
+ for (let i = 9; i < 15; i++) this.setFunctionModule(14 - i, 8, getBit(bits, i));
445
+ for (let i = 0; i < 8; i++) this.setFunctionModule(this.size - 1 - i, 8, getBit(bits, i));
446
+ for (let i = 8; i < 15; i++) this.setFunctionModule(8, this.size - 15 + i, getBit(bits, i));
447
+ this.setFunctionModule(8, this.size - 8, true);
448
+ }
449
+ drawVersion() {
450
+ if (this.version < 7) return;
451
+ let rem = this.version;
452
+ for (let i = 0; i < 12; i++) rem = rem << 1 ^ (rem >>> 11) * 7973;
453
+ const bits = this.version << 12 | rem;
454
+ for (let i = 0; i < 18; i++) {
455
+ const color = getBit(bits, i);
456
+ const a = this.size - 11 + i % 3;
457
+ const b = Math.floor(i / 3);
458
+ this.setFunctionModule(a, b, color);
459
+ this.setFunctionModule(b, a, color);
460
+ }
461
+ }
462
+ drawFinderPattern(x, y) {
463
+ for (let dy = -4; dy <= 4; dy++) for (let dx = -4; dx <= 4; dx++) {
464
+ const dist = Math.max(Math.abs(dx), Math.abs(dy));
465
+ const xx = x + dx;
466
+ const yy = y + dy;
467
+ if (xx >= 0 && xx < this.size && yy >= 0 && yy < this.size) this.setFunctionModule(xx, yy, dist !== 2 && dist !== 4, QrCodeDataType.Position);
468
+ }
469
+ }
470
+ drawAlignmentPattern(x, y) {
471
+ for (let dy = -2; dy <= 2; dy++) for (let dx = -2; dx <= 2; dx++) this.setFunctionModule(x + dx, y + dy, Math.max(Math.abs(dx), Math.abs(dy)) !== 1, QrCodeDataType.Alignment);
472
+ }
473
+ setFunctionModule(x, y, isDark, type = QrCodeDataType.Function) {
474
+ this.modules[y][x] = isDark;
475
+ this.types[y][x] = type;
476
+ }
477
+ addEccAndInterleave(data) {
478
+ const ver = this.version;
479
+ const ecl = this.ecc;
480
+ if (data.length !== getNumDataCodewords(ver, ecl)) throw new RangeError("Invalid argument");
481
+ const numBlocks = NUM_ERROR_CORRECTION_BLOCKS[ecl[0]][ver];
482
+ const blockEccLen = ECC_CODEWORDS_PER_BLOCK[ecl[0]][ver];
483
+ const rawCodewords = Math.floor(getNumRawDataModules(ver) / 8);
484
+ const numShortBlocks = numBlocks - rawCodewords % numBlocks;
485
+ const shortBlockLen = Math.floor(rawCodewords / numBlocks);
486
+ const blocks = [];
487
+ const rsDiv = reedSolomonComputeDivisor(blockEccLen);
488
+ for (let i = 0, k = 0; i < numBlocks; i++) {
489
+ const dat = data.slice(k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1));
490
+ k += dat.length;
491
+ const ecc = reedSolomonComputeRemainder(dat, rsDiv);
492
+ if (i < numShortBlocks) dat.push(0);
493
+ blocks.push(dat.concat(ecc));
494
+ }
495
+ const result = [];
496
+ for (let i = 0; i < blocks[0].length; i++) blocks.forEach((block, j) => {
497
+ if (i !== shortBlockLen - blockEccLen || j >= numShortBlocks) result.push(block[i]);
498
+ });
499
+ return result;
500
+ }
501
+ drawCodewords(data) {
502
+ if (data.length !== Math.floor(getNumRawDataModules(this.version) / 8)) throw new RangeError("Invalid argument");
503
+ let i = 0;
504
+ for (let right = this.size - 1; right >= 1; right -= 2) {
505
+ if (right === 6) right = 5;
506
+ for (let vert = 0; vert < this.size; vert++) for (let j = 0; j < 2; j++) {
507
+ const x = right - j;
508
+ const y = (right + 1 & 2) === 0 ? this.size - 1 - vert : vert;
509
+ if (!this.types[y][x] && i < data.length * 8) {
510
+ this.modules[y][x] = getBit(data[i >>> 3], 7 - (i & 7));
511
+ i++;
512
+ }
513
+ }
514
+ }
515
+ }
516
+ applyMask(mask) {
517
+ if (mask < 0 || mask > 7) throw new RangeError("Mask value out of range");
518
+ for (let y = 0; y < this.size; y++) for (let x = 0; x < this.size; x++) {
519
+ let invert;
520
+ switch (mask) {
521
+ case 0:
522
+ invert = (x + y) % 2 === 0;
523
+ break;
524
+ case 1:
525
+ invert = y % 2 === 0;
526
+ break;
527
+ case 2:
528
+ invert = x % 3 === 0;
529
+ break;
530
+ case 3:
531
+ invert = (x + y) % 3 === 0;
532
+ break;
533
+ case 4:
534
+ invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 === 0;
535
+ break;
536
+ case 5:
537
+ invert = x * y % 2 + x * y % 3 === 0;
538
+ break;
539
+ case 6:
540
+ invert = (x * y % 2 + x * y % 3) % 2 === 0;
541
+ break;
542
+ case 7:
543
+ invert = ((x + y) % 2 + x * y % 3) % 2 === 0;
544
+ break;
545
+ default: throw new Error("Unreachable");
546
+ }
547
+ if (!this.types[y][x] && invert) this.modules[y][x] = !this.modules[y][x];
548
+ }
549
+ }
550
+ getPenaltyScore() {
551
+ let result = 0;
552
+ for (let y = 0; y < this.size; y++) {
553
+ let runColor = false;
554
+ let runX = 0;
555
+ const runHistory = [
556
+ 0,
557
+ 0,
558
+ 0,
559
+ 0,
560
+ 0,
561
+ 0,
562
+ 0
563
+ ];
564
+ for (let x = 0; x < this.size; x++) if (this.modules[y][x] === runColor) {
565
+ runX++;
566
+ if (runX === 5) result += PENALTY_N1;
567
+ else if (runX > 5) result++;
568
+ } else {
569
+ this.finderPenaltyAddHistory(runX, runHistory);
570
+ if (!runColor) result += this.finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
571
+ runColor = this.modules[y][x];
572
+ runX = 1;
573
+ }
574
+ result += this.finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3;
575
+ }
576
+ for (let x = 0; x < this.size; x++) {
577
+ let runColor = false;
578
+ let runY = 0;
579
+ const runHistory = [
580
+ 0,
581
+ 0,
582
+ 0,
583
+ 0,
584
+ 0,
585
+ 0,
586
+ 0
587
+ ];
588
+ for (let y = 0; y < this.size; y++) if (this.modules[y][x] === runColor) {
589
+ runY++;
590
+ if (runY === 5) result += PENALTY_N1;
591
+ else if (runY > 5) result++;
592
+ } else {
593
+ this.finderPenaltyAddHistory(runY, runHistory);
594
+ if (!runColor) result += this.finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
595
+ runColor = this.modules[y][x];
596
+ runY = 1;
597
+ }
598
+ result += this.finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3;
599
+ }
600
+ for (let y = 0; y < this.size - 1; y++) for (let x = 0; x < this.size - 1; x++) {
601
+ const color = this.modules[y][x];
602
+ if (color === this.modules[y][x + 1] && color === this.modules[y + 1][x] && color === this.modules[y + 1][x + 1]) result += PENALTY_N2;
603
+ }
604
+ let dark = 0;
605
+ for (const row of this.modules) dark = row.reduce((sum, color) => sum + (color ? 1 : 0), dark);
606
+ const total = this.size * this.size;
607
+ const k = Math.ceil(Math.abs(dark * 20 - total * 10) / total) - 1;
608
+ result += k * PENALTY_N4;
609
+ return result;
610
+ }
611
+ getAlignmentPatternPositions() {
612
+ if (this.version === 1) return [];
613
+ else {
614
+ const numAlign = Math.floor(this.version / 7) + 2;
615
+ const step = this.version === 32 ? 26 : Math.ceil((this.version * 4 + 4) / (numAlign * 2 - 2)) * 2;
616
+ const result = [6];
617
+ for (let pos = this.size - 7; result.length < numAlign; pos -= step) result.splice(1, 0, pos);
618
+ return result;
619
+ }
620
+ }
621
+ finderPenaltyCountPatterns(runHistory) {
622
+ const n = runHistory[1];
623
+ const core = n > 0 && runHistory[2] === n && runHistory[3] === n * 3 && runHistory[4] === n && runHistory[5] === n;
624
+ return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0);
625
+ }
626
+ finderPenaltyTerminateAndCount(currentRunColor, currentRunLength, runHistory) {
627
+ if (currentRunColor) {
628
+ this.finderPenaltyAddHistory(currentRunLength, runHistory);
629
+ currentRunLength = 0;
630
+ }
631
+ currentRunLength += this.size;
632
+ this.finderPenaltyAddHistory(currentRunLength, runHistory);
633
+ return this.finderPenaltyCountPatterns(runHistory);
634
+ }
635
+ finderPenaltyAddHistory(currentRunLength, runHistory) {
636
+ if (runHistory[0] === 0) currentRunLength += this.size;
637
+ runHistory.pop();
638
+ runHistory.unshift(currentRunLength);
639
+ }
640
+ };
641
+ function appendBits(val, len, bb) {
642
+ if (len < 0 || len > 31 || val >>> len !== 0) throw new RangeError("Value out of range");
643
+ for (let i = len - 1; i >= 0; i--) bb.push(val >>> i & 1);
644
+ }
645
+ function getBit(x, i) {
646
+ return (x >>> i & 1) !== 0;
647
+ }
648
+ var QrSegment = class {
649
+ constructor(mode, numChars, bitData) {
650
+ this.mode = mode;
651
+ this.numChars = numChars;
652
+ this.bitData = bitData;
653
+ if (numChars < 0) throw new RangeError("Invalid argument");
654
+ this.bitData = bitData.slice();
655
+ }
656
+ getData() {
657
+ return this.bitData.slice();
658
+ }
659
+ };
660
+ var MODE_NUMERIC = [
661
+ 1,
662
+ 10,
663
+ 12,
664
+ 14
665
+ ];
666
+ var MODE_ALPHANUMERIC = [
667
+ 2,
668
+ 9,
669
+ 11,
670
+ 13
671
+ ];
672
+ var MODE_BYTE = [
673
+ 4,
674
+ 8,
675
+ 16,
676
+ 16
677
+ ];
678
+ function numCharCountBits(mode, ver) {
679
+ return mode[Math.floor((ver + 7) / 17) + 1];
680
+ }
681
+ function makeBytes(data) {
682
+ const bb = [];
683
+ for (const b of data) appendBits(b, 8, bb);
684
+ return new QrSegment(MODE_BYTE, data.length, bb);
685
+ }
686
+ function makeNumeric(digits) {
687
+ if (!isNumeric(digits)) throw new RangeError("String contains non-numeric characters");
688
+ const bb = [];
689
+ for (let i = 0; i < digits.length;) {
690
+ const n = Math.min(digits.length - i, 3);
691
+ appendBits(Number.parseInt(digits.substring(i, i + n), 10), n * 3 + 1, bb);
692
+ i += n;
693
+ }
694
+ return new QrSegment(MODE_NUMERIC, digits.length, bb);
695
+ }
696
+ function makeAlphanumeric(text) {
697
+ if (!isAlphanumeric(text)) throw new RangeError("String contains unencodable characters in alphanumeric mode");
698
+ const bb = [];
699
+ let i = 0;
700
+ for (; i + 2 <= text.length; i += 2) {
701
+ let temp = ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)) * 45;
702
+ temp += ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1));
703
+ appendBits(temp, 11, bb);
704
+ }
705
+ if (i < text.length) appendBits(ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6, bb);
706
+ return new QrSegment(MODE_ALPHANUMERIC, text.length, bb);
707
+ }
708
+ function makeSegments(text) {
709
+ if (text === "") return [];
710
+ else if (isNumeric(text)) return [makeNumeric(text)];
711
+ else if (isAlphanumeric(text)) return [makeAlphanumeric(text)];
712
+ else return [makeBytes(toUtf8ByteArray(text))];
713
+ }
714
+ function isNumeric(text) {
715
+ return NUMERIC_REGEX.test(text);
716
+ }
717
+ function isAlphanumeric(text) {
718
+ return ALPHANUMERIC_REGEX.test(text);
719
+ }
720
+ function getTotalBits(segs, version) {
721
+ let result = 0;
722
+ for (const seg of segs) {
723
+ const ccbits = numCharCountBits(seg.mode, version);
724
+ if (seg.numChars >= 1 << ccbits) return Number.POSITIVE_INFINITY;
725
+ result += 4 + ccbits + seg.bitData.length;
726
+ }
727
+ return result;
728
+ }
729
+ function toUtf8ByteArray(str) {
730
+ str = encodeURI(str);
731
+ const result = [];
732
+ for (let i = 0; i < str.length; i++) if (str.charAt(i) !== "%") result.push(str.charCodeAt(i));
733
+ else {
734
+ result.push(Number.parseInt(str.substring(i + 1, i + 3), 16));
735
+ i += 2;
736
+ }
737
+ return result;
738
+ }
739
+ function getNumRawDataModules(ver) {
740
+ if (ver < MIN_VERSION || ver > MAX_VERSION) throw new RangeError("Version number out of range");
741
+ let result = (16 * ver + 128) * ver + 64;
742
+ if (ver >= 2) {
743
+ const numAlign = Math.floor(ver / 7) + 2;
744
+ result -= (25 * numAlign - 10) * numAlign - 55;
745
+ if (ver >= 7) result -= 36;
746
+ }
747
+ return result;
748
+ }
749
+ function getNumDataCodewords(ver, ecl) {
750
+ return Math.floor(getNumRawDataModules(ver) / 8) - ECC_CODEWORDS_PER_BLOCK[ecl[0]][ver] * NUM_ERROR_CORRECTION_BLOCKS[ecl[0]][ver];
751
+ }
752
+ function reedSolomonComputeDivisor(degree) {
753
+ if (degree < 1 || degree > 255) throw new RangeError("Degree out of range");
754
+ const result = [];
755
+ for (let i = 0; i < degree - 1; i++) result.push(0);
756
+ result.push(1);
757
+ let root = 1;
758
+ for (let i = 0; i < degree; i++) {
759
+ for (let j = 0; j < result.length; j++) {
760
+ result[j] = reedSolomonMultiply(result[j], root);
761
+ if (j + 1 < result.length) result[j] ^= result[j + 1];
762
+ }
763
+ root = reedSolomonMultiply(root, 2);
764
+ }
765
+ return result;
766
+ }
767
+ function reedSolomonComputeRemainder(data, divisor) {
768
+ const result = divisor.map((_) => 0);
769
+ for (const b of data) {
770
+ const factor = b ^ result.shift();
771
+ result.push(0);
772
+ divisor.forEach((coef, i) => result[i] ^= reedSolomonMultiply(coef, factor));
773
+ }
774
+ return result;
775
+ }
776
+ function reedSolomonMultiply(x, y) {
777
+ if (x >>> 8 !== 0 || y >>> 8 !== 0) throw new RangeError("Byte out of range");
778
+ let z = 0;
779
+ for (let i = 7; i >= 0; i--) {
780
+ z = z << 1 ^ (z >>> 7) * 285;
781
+ z ^= (y >>> i & 1) * x;
782
+ }
783
+ return z;
784
+ }
785
+ function encodeSegments(segs, ecl, minVersion = 1, maxVersion = 40, mask = -1, boostEcl = true) {
786
+ if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7) throw new RangeError("Invalid value");
787
+ let version;
788
+ let dataUsedBits;
789
+ for (version = minVersion;; version++) {
790
+ const dataCapacityBits2 = getNumDataCodewords(version, ecl) * 8;
791
+ const usedBits = getTotalBits(segs, version);
792
+ if (usedBits <= dataCapacityBits2) {
793
+ dataUsedBits = usedBits;
794
+ break;
795
+ }
796
+ if (version >= maxVersion) throw new RangeError("Data too long");
797
+ }
798
+ for (const newEcl of [
799
+ MEDIUM,
800
+ QUARTILE,
801
+ HIGH
802
+ ]) if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8) ecl = newEcl;
803
+ const bb = [];
804
+ for (const seg of segs) {
805
+ appendBits(seg.mode[0], 4, bb);
806
+ appendBits(seg.numChars, numCharCountBits(seg.mode, version), bb);
807
+ for (const b of seg.getData()) bb.push(b);
808
+ }
809
+ const dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
810
+ appendBits(0, Math.min(4, dataCapacityBits - bb.length), bb);
811
+ appendBits(0, (8 - bb.length % 8) % 8, bb);
812
+ for (let padByte = 236; bb.length < dataCapacityBits; padByte ^= 253) appendBits(padByte, 8, bb);
813
+ const dataCodewords = Array.from({ length: Math.ceil(bb.length / 8) }, () => 0);
814
+ bb.forEach((b, i) => dataCodewords[i >>> 3] |= b << 7 - (i & 7));
815
+ return new QrCode$1(version, ecl, dataCodewords, mask);
816
+ }
817
+ function encode(data, options) {
818
+ const { ecc = "L", boostEcc = false, minVersion = 1, maxVersion = 40, maskPattern = -1, border = 1 } = options || {};
819
+ const segment = typeof data === "string" ? makeSegments(data) : Array.isArray(data) ? [makeBytes(data)] : void 0;
820
+ if (!segment) throw new Error(`uqr only supports encoding string and binary data, but got: ${typeof data}`);
821
+ const qr = encodeSegments(segment, EccMap[ecc], minVersion, maxVersion, maskPattern, boostEcc);
822
+ const result = addBorder({
823
+ version: qr.version,
824
+ maskPattern: qr.mask,
825
+ size: qr.size,
826
+ data: qr.modules,
827
+ types: qr.types
828
+ }, border);
829
+ if (options?.invert) result.data = result.data.map((row) => row.map((mod) => !mod));
830
+ options?.onEncoded?.(result);
831
+ return result;
832
+ }
833
+ function addBorder(input, border = 1) {
834
+ if (!border) return input;
835
+ const { size } = input;
836
+ const newSize = size + border * 2;
837
+ input.size = newSize;
838
+ input.data.forEach((row) => {
839
+ for (let i = 0; i < border; i++) {
840
+ row.unshift(false);
841
+ row.push(false);
842
+ }
843
+ });
844
+ for (let i = 0; i < border; i++) {
845
+ input.data.unshift(Array.from({ length: newSize }, (_) => false));
846
+ input.data.push(Array.from({ length: newSize }, (_) => false));
847
+ }
848
+ const b = QrCodeDataType.Border;
849
+ input.types.forEach((row) => {
850
+ for (let i = 0; i < border; i++) {
851
+ row.unshift(b);
852
+ row.push(b);
853
+ }
854
+ });
855
+ for (let i = 0; i < border; i++) {
856
+ input.types.unshift(Array.from({ length: newSize }, (_) => b));
857
+ input.types.push(Array.from({ length: newSize }, (_) => b));
858
+ }
859
+ return input;
860
+ }
861
+ //#endregion
862
+ //#region src/qr-code.scss?inline
863
+ var qr_code_default = "/* ex : var((width: 24px), width, c2-checkbox) returns var(--c2-checkbox-width, 24px) */\n:host {\n display: inline-flex;\n vertical-align: middle;\n}\n\n:host([hidden]),\n.center[hidden] {\n display: none;\n}\n\n.container,\n.placeholder {\n box-sizing: border-box;\n width: var(--c2-qr-code--size,200px);\n height: var(--c2-qr-code--size,200px);\n border-radius: var(--c2-qr-code__container--border-radius,8px);\n}\n\n.container {\n position: relative;\n display: inline-flex;\n overflow: hidden;\n background: var(--c2-qr-code__background--color,#ffffff);\n}\n\n.code {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n.background {\n fill: var(--c2-qr-code__background--color,#ffffff);\n}\n\n.modules {\n fill: var(--c2-qr-code__module--color,#18181b);\n}\n\n.placeholder {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: 1px dashed #bcbcc6;\n color: var(--c2-qr-code__placeholder--color,#71717a);\n font-size: var(--c2-qr-code__placeholder--font-size,12px);\n text-align: center;\n}\n\n.center {\n position: absolute;\n top: 50%;\n left: 50%;\n display: flex;\n box-sizing: border-box;\n width: var(--c2-qr-code__center--size,20%);\n height: var(--c2-qr-code__center--size,20%);\n padding: var(--c2-qr-code__center--padding,4px);\n transform: translate(-50%, -50%);\n align-items: center;\n justify-content: center;\n border-radius: var(--c2-qr-code__center--border-radius,6px);\n background: var(--c2-qr-code__center--background-color,#ffffff);\n}\n\n::slotted([slot=center]) {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: contain;\n}";
864
+ //#endregion
865
+ //#region \0@oxc-project+runtime@0.148.0/helpers/esm/decorate.js
866
+ function __decorate(decorators, target, key, desc) {
867
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
868
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
869
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
870
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
871
+ }
872
+ //#endregion
873
+ //#region src/qr-code.ts
874
+ var QrCode = class QrCode extends LitElement {
875
+ constructor(..._args) {
876
+ super(..._args);
877
+ this.value = "";
878
+ this.size = 200;
879
+ this.errorCorrection = "M";
880
+ this.margin = 4;
881
+ this.boostErrorCorrection = false;
882
+ this.ariaLabel = null;
883
+ this.modules = [];
884
+ this.encodingError = null;
885
+ this.hasCenter = false;
886
+ }
887
+ static {
888
+ this.styles = unsafeCSS(qr_code_default);
889
+ }
890
+ willUpdate(changed) {
891
+ if (changed.has("size")) this.size = Number.isFinite(this.size) ? Math.max(0, Math.floor(this.size)) : 200;
892
+ if (changed.has("margin")) this.margin = Number.isFinite(this.margin) ? Math.max(0, Math.floor(this.margin)) : 4;
893
+ if (changed.has("errorCorrection") && ![
894
+ "L",
895
+ "M",
896
+ "Q",
897
+ "H"
898
+ ].includes(this.errorCorrection)) this.errorCorrection = "M";
899
+ if (changed.has("value") || changed.has("margin") || changed.has("errorCorrection") || changed.has("boostErrorCorrection")) this.encodeValue();
900
+ }
901
+ /** Returns a standalone SVG string using the component's current value and options. */
902
+ toSVG() {
903
+ if (!this.modules.length) return "";
904
+ const dimension = this.modules.length;
905
+ const foreground = this.resolvedColor("--c2-qr-code__module--color", "#18181b");
906
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${dimension} ${dimension}" shape-rendering="crispEdges"><rect width="${dimension}" height="${dimension}" fill="${this.resolvedColor("--c2-qr-code__background--color", "#ffffff")}"/><path d="${this.modulePath}" fill="${foreground}"/></svg>`;
907
+ }
908
+ /** Returns a data URL for the current code. PNG export requires a browser document. */
909
+ async toDataURL(format = "png", scale = 4) {
910
+ const svg = this.toSVG();
911
+ if (!svg) return "";
912
+ const svgUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
913
+ if (format === "svg") return svgUrl;
914
+ const image = new Image();
915
+ image.src = svgUrl;
916
+ await image.decode();
917
+ const outputSize = Math.max(1, (this.size || 200) * Math.max(1, scale));
918
+ const canvas = document.createElement("canvas");
919
+ canvas.width = outputSize;
920
+ canvas.height = outputSize;
921
+ const context = canvas.getContext("2d");
922
+ if (!context) throw new Error("Canvas rendering is unavailable.");
923
+ context.imageSmoothingEnabled = false;
924
+ context.drawImage(image, 0, 0, outputSize, outputSize);
925
+ return canvas.toDataURL("image/png");
926
+ }
927
+ /** Downloads the current QR code as SVG or PNG. */
928
+ async download(filename = "qr-code", format = "png") {
929
+ const url = await this.toDataURL(format);
930
+ if (!url) return;
931
+ const anchor = document.createElement("a");
932
+ anchor.href = url;
933
+ anchor.download = `${filename}.${format}`;
934
+ anchor.click();
935
+ }
936
+ encodeValue() {
937
+ if (!this.value) {
938
+ this.modules = [];
939
+ this.encodingError = null;
940
+ return;
941
+ }
942
+ try {
943
+ this.modules = encode(this.value, {
944
+ ecc: this.errorCorrection,
945
+ border: this.margin,
946
+ boostEcc: this.boostErrorCorrection
947
+ }).data;
948
+ this.encodingError = null;
949
+ } catch (cause) {
950
+ const error = cause instanceof Error ? cause : new Error(String(cause));
951
+ this.modules = [];
952
+ this.encodingError = error;
953
+ queueMicrotask(() => this.dispatchEvent(new CustomEvent("qr-code-error", {
954
+ detail: {
955
+ error,
956
+ value: this.value
957
+ },
958
+ bubbles: true,
959
+ composed: true
960
+ })));
961
+ }
962
+ }
963
+ resolvedColor(name, fallback) {
964
+ if (typeof getComputedStyle !== "function") return fallback;
965
+ return getComputedStyle(this).getPropertyValue(name).trim() || fallback;
966
+ }
967
+ get modulePath() {
968
+ return this.modules.flatMap((row, y) => row.flatMap((active, x) => active ? `M${x} ${y}h1v1h-1z` : [])).join("");
969
+ }
970
+ handleCenterSlot(event) {
971
+ this.hasCenter = event.target.assignedElements().length > 0;
972
+ }
973
+ render() {
974
+ const label = this.ariaLabel || "QR code";
975
+ const hostSize = this.size > 0 ? `${this.size}px` : void 0;
976
+ if (!this.modules.length) return html`<div class="placeholder" style=${styleMap({
977
+ width: hostSize,
978
+ height: hostSize
979
+ })} role="img" aria-label=${label}>
980
+ ${this.encodingError ? "Unable to generate QR code" : "No value"}
981
+ </div>`;
982
+ const dimension = this.modules.length;
983
+ return html`
984
+ <div class="container" style=${styleMap({
985
+ width: hostSize,
986
+ height: hostSize
987
+ })}>
988
+ <svg class="code" viewBox="0 0 ${dimension} ${dimension}" role="img" aria-label=${label} shape-rendering="crispEdges">
989
+ <rect class="background" width=${dimension} height=${dimension}></rect>
990
+ <path class="modules" d=${this.modulePath}></path>
991
+ </svg>
992
+ <div class="center" ?hidden=${!this.hasCenter}><slot name="center" @slotchange=${this.handleCenterSlot}></slot></div>
993
+ </div>
994
+ `;
995
+ }
996
+ };
997
+ __decorate([property({ type: String })], QrCode.prototype, "value", void 0);
998
+ __decorate([property({
999
+ type: Number,
1000
+ reflect: true
1001
+ })], QrCode.prototype, "size", void 0);
1002
+ __decorate([property({
1003
+ type: String,
1004
+ attribute: "error-correction",
1005
+ reflect: true
1006
+ })], QrCode.prototype, "errorCorrection", void 0);
1007
+ __decorate([property({
1008
+ type: Number,
1009
+ reflect: true
1010
+ })], QrCode.prototype, "margin", void 0);
1011
+ __decorate([property({
1012
+ type: Boolean,
1013
+ attribute: "boost-error-correction",
1014
+ reflect: true
1015
+ })], QrCode.prototype, "boostErrorCorrection", void 0);
1016
+ __decorate([property({ attribute: "aria-label" })], QrCode.prototype, "ariaLabel", void 0);
1017
+ __decorate([state()], QrCode.prototype, "modules", void 0);
1018
+ __decorate([state()], QrCode.prototype, "encodingError", void 0);
1019
+ __decorate([state()], QrCode.prototype, "hasCenter", void 0);
1020
+ QrCode = __decorate([customElement("c2-qr-code")], QrCode);
1021
+ //#endregion
1022
+ export { QrCode };
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@c2n/qr-code",
3
+ "version": "0.0.9",
4
+ "type": "module",
5
+ "main": "dist/qr-code.js",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./types/src/qr-code.d.ts",
9
+ "default": "./dist/qr-code.js"
10
+ },
11
+ "./react": {
12
+ "types": "./react.d.ts",
13
+ "default": "./react.js"
14
+ },
15
+ "./vue": {
16
+ "types": "./vue.d.ts",
17
+ "default": "./vue.js"
18
+ },
19
+ "./custom-elements.json": "./custom-elements.json"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "types",
24
+ "react.d.ts",
25
+ "react.js",
26
+ "vue.d.ts",
27
+ "vue.js"
28
+ ],
29
+ "keywords": [
30
+ "qr-code",
31
+ "web component",
32
+ "lit"
33
+ ],
34
+ "license": "MIT",
35
+ "author": "code2nguyen@gmail.com",
36
+ "publishConfig": {
37
+ "registry": "https://registry.npmjs.org",
38
+ "access": "public"
39
+ },
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/code2nguyen/web-components.git"
43
+ },
44
+ "scripts": {
45
+ "dev": "vite",
46
+ "build": "wireit",
47
+ "build:only": "vite build",
48
+ "type-check": "wireit"
49
+ },
50
+ "wireit": {
51
+ "type-check": {
52
+ "dependencies": [
53
+ "../../core:build"
54
+ ],
55
+ "command": "tsc -p tsconfig.lib.json --composite false"
56
+ },
57
+ "build": {
58
+ "dependencies": [
59
+ "type-check"
60
+ ],
61
+ "command": "vite build"
62
+ }
63
+ },
64
+ "dependencies": {
65
+ "@c2n/core": "0.0.9",
66
+ "lit": "3.3.3",
67
+ "uqr": "^0.1.3"
68
+ },
69
+ "devDependencies": {
70
+ "@c2n/config": "*"
71
+ },
72
+ "customElements": "custom-elements.json",
73
+ "gitHead": "e4768cce5e0fbd5bc3165cd493a1e8d57cf0fff4"
74
+ }
package/react.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ // GENERATED by @c2n/framework-types. Do not edit by hand.
2
+ //
3
+ // JSX types for the custom elements of @c2n/qr-code. Import once, anywhere in the program:
4
+ //
5
+ // import '@c2n/qr-code/react'
6
+ //
7
+ // Register the elements at module scope before React renders, or React writes an object prop as an
8
+ // attribute and it stringifies.
9
+
10
+ import type { DetailedHTMLProps, HTMLAttributes } from 'react'
11
+ import type { QrCode } from '@c2n/qr-code'
12
+
13
+ /** Standard React host-element attributes plus the element's own public properties. */
14
+ type C2Props<T> = DetailedHTMLProps<HTMLAttributes<T>, T> & Partial<Omit<T, keyof HTMLElement>>
15
+
16
+ declare module 'react' {
17
+ namespace JSX {
18
+ interface IntrinsicElements {
19
+ 'c2-qr-code': C2Props<QrCode>
20
+ }
21
+ }
22
+ }
23
+
24
+ export {}
package/react.js ADDED
@@ -0,0 +1,3 @@
1
+ // GENERATED by @c2n/framework-types. Do not edit by hand.
2
+ // Types only — see the matching .d.ts.
3
+ export {}
@@ -0,0 +1,71 @@
1
+ import { LitElement, type PropertyValues } from 'lit';
2
+ import type { TypedAddEventListener, TypedRemoveEventListener } from '@c2n/core/event-helper.js';
3
+ export type QrCodeErrorCorrection = 'L' | 'M' | 'Q' | 'H';
4
+ export interface QrCodeErrorEventDetail {
5
+ error: Error;
6
+ value: string;
7
+ }
8
+ /** Events fired by {@link QrCode}, keyed for `addEventListener`. */
9
+ export interface QrCodeEventMap {
10
+ 'qr-code-error': CustomEvent<QrCodeErrorEventDetail>;
11
+ }
12
+ export interface QrCode {
13
+ addEventListener: TypedAddEventListener<QrCode, QrCodeEventMap>;
14
+ removeEventListener: TypedRemoveEventListener<QrCode, QrCodeEventMap>;
15
+ }
16
+ /**
17
+ * Generates an accessible, themeable SVG QR code without sending its value to a remote service.
18
+ *
19
+ * @tag c2-qr-code
20
+ *
21
+ * @slot center - Optional logo or mark centered over the code. Prefer `error-correction="H"` and keep the mark small so the code remains scannable.
22
+ *
23
+ * @event {CustomEvent<QrCodeErrorEventDetail>} qr-code-error - Fired when the value cannot be encoded. `detail` contains the error and rejected value.
24
+ *
25
+ * @cssproperty {pixel} [--c2-qr-code--size=200px]
26
+ * @cssproperty {color} [--c2-qr-code__module--color=#18181b]
27
+ * @cssproperty {color} [--c2-qr-code__background--color=#ffffff]
28
+ * @cssproperty {border-radius} [--c2-qr-code__container--border-radius=8px]
29
+ * @cssproperty {color} [--c2-qr-code__placeholder--color=#71717a]
30
+ * @cssproperty {font-size} [--c2-qr-code__placeholder--font-size=12px]
31
+ * @cssproperty {length} [--c2-qr-code__center--size=20%]
32
+ * @cssproperty {color} [--c2-qr-code__center--background-color=#ffffff]
33
+ * @cssproperty {padding} [--c2-qr-code__center--padding=4px]
34
+ * @cssproperty {border-radius} [--c2-qr-code__center--border-radius=6px]
35
+ */
36
+ export declare class QrCode extends LitElement {
37
+ static styles: import("lit").CSSResult;
38
+ /** Text or URL encoded by the QR code. */
39
+ value: string;
40
+ /** Rendered width and height in CSS pixels. Set to `0` to use `--c2-qr-code--size`. */
41
+ size: number;
42
+ /** Error correction level: L (7%), M (15%), Q (25%), or H (30%). */
43
+ errorCorrection: QrCodeErrorCorrection;
44
+ /** Quiet-zone width measured in QR modules. Four is recommended for reliable scanning. */
45
+ margin: number;
46
+ /** Raises error correction when the encoded version has spare capacity. */
47
+ boostErrorCorrection: boolean;
48
+ /** Accessible name announced for the generated image. Defaults to `QR code`. */
49
+ ariaLabel: string | null;
50
+ private modules;
51
+ private encodingError;
52
+ private hasCenter;
53
+ protected willUpdate(changed: PropertyValues<this>): void;
54
+ /** Returns a standalone SVG string using the component's current value and options. */
55
+ toSVG(): string;
56
+ /** Returns a data URL for the current code. PNG export requires a browser document. */
57
+ toDataURL(format?: 'svg' | 'png', scale?: number): Promise<string>;
58
+ /** Downloads the current QR code as SVG or PNG. */
59
+ download(filename?: string, format?: 'svg' | 'png'): Promise<void>;
60
+ private encodeValue;
61
+ private resolvedColor;
62
+ private get modulePath();
63
+ private handleCenterSlot;
64
+ render(): import("lit-html").TemplateResult<1>;
65
+ }
66
+ declare global {
67
+ interface HTMLElementTagNameMap {
68
+ 'c2-qr-code': QrCode;
69
+ }
70
+ }
71
+ //# sourceMappingURL=qr-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qr-code.d.ts","sourceRoot":"","sources":["../../src/qr-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAmB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAA;AAItE,OAAO,KAAK,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAA;AAIhG,MAAM,MAAM,qBAAqB,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;AAEzD,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,KAAK,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;AAED,oEAAoE;AACpE,MAAM,WAAW,cAAc;IAC7B,eAAe,EAAE,WAAW,CAAC,sBAAsB,CAAC,CAAA;CACrD;AAED,MAAM,WAAW,MAAM;IACrB,gBAAgB,EAAE,qBAAqB,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IAC/D,mBAAmB,EAAE,wBAAwB,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;CACtE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,MAAO,SAAQ,UAAU;IACpC,OAAgB,MAAM,0BAAoB;IAE1C,0CAA0C;IACd,KAAK,SAAK;IAEtC,uFAAuF;IAC5C,IAAI,SAAM;IAErD,oEAAoE;IACM,eAAe,EAAE,qBAAqB,CAAM;IAEtH,0FAA0F;IAC/C,MAAM,SAAI;IAErD,2EAA2E;IACM,oBAAoB,UAAQ;IAE7G,gFAAgF;IAChC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAO;IAEtE,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,SAAS,CAAQ;cAEf,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI;IAOlE,uFAAuF;IACvF,KAAK,IAAI,MAAM;IAQf,uFAAuF;IACjF,SAAS,CAAC,MAAM,GAAE,KAAK,GAAG,KAAa,EAAE,KAAK,SAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAmB1E,mDAAmD;IAC7C,QAAQ,CAAC,QAAQ,SAAY,EAAE,MAAM,GAAE,KAAK,GAAG,KAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IASlF,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,aAAa;IAKrB,OAAO,KAAK,UAAU,GAErB;IAED,OAAO,CAAC,gBAAgB;IAIf,MAAM;CAmBhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,YAAY,EAAE,MAAM,CAAA;KACrB;CACF"}
package/vue.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ // GENERATED by @c2n/framework-types. Do not edit by hand.
2
+ //
3
+ // Vue template types for the custom elements of @c2n/qr-code. Import once, anywhere in the program:
4
+ //
5
+ // import '@c2n/qr-code/vue'
6
+ //
7
+ // Tell the compiler about the tags as well, or every c2-* tag is resolved as a Vue component and renders
8
+ // nothing: template.compilerOptions.isCustomElement = (tag) => tag.startsWith('c2-') in vite.config.ts.
9
+
10
+ import type { DefineComponent, HTMLAttributes } from 'vue'
11
+ import type { QrCode, QrCodeEventMap } from '@c2n/qr-code'
12
+
13
+ /** The element's own public properties, plus every attribute Vue understands on a host element. */
14
+ type C2Props<T> = Partial<Omit<T, keyof HTMLElement>> & HTMLAttributes
15
+
16
+ declare module 'vue' {
17
+ interface GlobalComponents {
18
+ 'c2-qr-code': DefineComponent<
19
+ C2Props<QrCode> & {
20
+ 'error-correction'?: unknown
21
+ 'boost-error-correction'?: unknown
22
+ 'aria-label'?: unknown
23
+ onQrCodeError?: (event: QrCodeEventMap['qr-code-error']) => void
24
+ }
25
+ >
26
+ }
27
+ }
28
+
29
+ declare module '@vue/runtime-dom' {
30
+ interface HTMLAttributes {
31
+ /** Vue's own definition omits it, and slotting a plain element into a component needs it. */
32
+ slot?: string
33
+ }
34
+ }
35
+
36
+ export {}
package/vue.js ADDED
@@ -0,0 +1,3 @@
1
+ // GENERATED by @c2n/framework-types. Do not edit by hand.
2
+ // Types only — see the matching .d.ts.
3
+ export {}