@urbicon-ui/blocks 6.35.0 → 6.37.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.
Files changed (124) hide show
  1. package/dist/components/Chat/Chat/Chat.svelte +53 -0
  2. package/dist/components/Chat/Chat/Chat.svelte.d.ts +4 -0
  3. package/dist/components/Chat/Chat/chat.variants.d.ts +20 -0
  4. package/dist/components/Chat/Chat/chat.variants.js +15 -0
  5. package/dist/components/Chat/Chat/index.d.ts +47 -0
  6. package/dist/components/Chat/Chat/index.js +2 -0
  7. package/dist/components/Chat/ChatMessage/ChatMessage.svelte +342 -0
  8. package/dist/components/Chat/ChatMessage/ChatMessage.svelte.d.ts +4 -0
  9. package/dist/components/Chat/ChatMessage/chat-message.variants.d.ts +138 -0
  10. package/dist/components/Chat/ChatMessage/chat-message.variants.js +118 -0
  11. package/dist/components/Chat/ChatMessage/index.d.ts +102 -0
  12. package/dist/components/Chat/ChatMessage/index.js +2 -0
  13. package/dist/components/Chat/ChatMessageList/ChatMessageList.svelte +301 -0
  14. package/dist/components/Chat/ChatMessageList/ChatMessageList.svelte.d.ts +6 -0
  15. package/dist/components/Chat/ChatMessageList/chat-message-list.variants.d.ts +23 -0
  16. package/dist/components/Chat/ChatMessageList/chat-message-list.variants.js +32 -0
  17. package/dist/components/Chat/ChatMessageList/chat-scroll.d.ts +45 -0
  18. package/dist/components/Chat/ChatMessageList/chat-scroll.js +52 -0
  19. package/dist/components/Chat/ChatMessageList/index.d.ts +93 -0
  20. package/dist/components/Chat/ChatMessageList/index.js +3 -0
  21. package/dist/components/Chat/CitationChip/CitationChip.svelte +107 -0
  22. package/dist/components/Chat/CitationChip/CitationChip.svelte.d.ts +4 -0
  23. package/dist/components/Chat/CitationChip/citation-chip.variants.d.ts +40 -0
  24. package/dist/components/Chat/CitationChip/citation-chip.variants.js +42 -0
  25. package/dist/components/Chat/CitationChip/index.d.ts +69 -0
  26. package/dist/components/Chat/CitationChip/index.js +2 -0
  27. package/dist/components/Chat/CodeBlock/CodeBlock.svelte +120 -0
  28. package/dist/components/Chat/CodeBlock/CodeBlock.svelte.d.ts +4 -0
  29. package/dist/components/Chat/CodeBlock/code-block.variants.d.ts +40 -0
  30. package/dist/components/Chat/CodeBlock/code-block.variants.js +51 -0
  31. package/dist/components/Chat/CodeBlock/index.d.ts +55 -0
  32. package/dist/components/Chat/CodeBlock/index.js +2 -0
  33. package/dist/components/Chat/PromptInput/PromptInput.svelte +432 -0
  34. package/dist/components/Chat/PromptInput/PromptInput.svelte.d.ts +4 -0
  35. package/dist/components/Chat/PromptInput/index.d.ts +165 -0
  36. package/dist/components/Chat/PromptInput/index.js +2 -0
  37. package/dist/components/Chat/PromptInput/prompt-input.variants.d.ts +90 -0
  38. package/dist/components/Chat/PromptInput/prompt-input.variants.js +102 -0
  39. package/dist/components/Chat/ReasoningDisclosure/ReasoningDisclosure.svelte +107 -0
  40. package/dist/components/Chat/ReasoningDisclosure/ReasoningDisclosure.svelte.d.ts +4 -0
  41. package/dist/components/Chat/ReasoningDisclosure/index.d.ts +85 -0
  42. package/dist/components/Chat/ReasoningDisclosure/index.js +2 -0
  43. package/dist/components/Chat/ReasoningDisclosure/reasoning-disclosure.variants.d.ts +20 -0
  44. package/dist/components/Chat/ReasoningDisclosure/reasoning-disclosure.variants.js +31 -0
  45. package/dist/components/Chat/StreamingMarkdown/MdBlock.svelte +99 -0
  46. package/dist/components/Chat/StreamingMarkdown/MdBlock.svelte.d.ts +9 -0
  47. package/dist/components/Chat/StreamingMarkdown/MdInline.svelte +82 -0
  48. package/dist/components/Chat/StreamingMarkdown/MdInline.svelte.d.ts +9 -0
  49. package/dist/components/Chat/StreamingMarkdown/StreamingMarkdown.svelte +118 -0
  50. package/dist/components/Chat/StreamingMarkdown/StreamingMarkdown.svelte.d.ts +4 -0
  51. package/dist/components/Chat/StreamingMarkdown/index.d.ts +86 -0
  52. package/dist/components/Chat/StreamingMarkdown/index.js +2 -0
  53. package/dist/components/Chat/StreamingMarkdown/md-context.d.ts +58 -0
  54. package/dist/components/Chat/StreamingMarkdown/md-context.js +1 -0
  55. package/dist/components/Chat/StreamingMarkdown/streaming-markdown.variants.d.ts +145 -0
  56. package/dist/components/Chat/StreamingMarkdown/streaming-markdown.variants.js +73 -0
  57. package/dist/components/Chat/ToolCallCard/ToolCallCard.svelte +174 -0
  58. package/dist/components/Chat/ToolCallCard/ToolCallCard.svelte.d.ts +4 -0
  59. package/dist/components/Chat/ToolCallCard/index.d.ts +84 -0
  60. package/dist/components/Chat/ToolCallCard/index.js +2 -0
  61. package/dist/components/Chat/ToolCallCard/tool-call-card.variants.d.ts +38 -0
  62. package/dist/components/Chat/ToolCallCard/tool-call-card.variants.js +38 -0
  63. package/dist/components/Chat/chat.types.d.ts +82 -0
  64. package/dist/components/Chat/chat.types.js +7 -0
  65. package/dist/components/Chat/index.d.ts +22 -0
  66. package/dist/components/Chat/index.js +14 -0
  67. package/dist/components/Chat/markdown/blocks.d.ts +54 -0
  68. package/dist/components/Chat/markdown/blocks.js +462 -0
  69. package/dist/components/Chat/markdown/inline.d.ts +31 -0
  70. package/dist/components/Chat/markdown/inline.js +446 -0
  71. package/dist/components/Chat/markdown/repair.d.ts +23 -0
  72. package/dist/components/Chat/markdown/repair.js +337 -0
  73. package/dist/components/Chat/markdown/streaming-harness.d.ts +23 -0
  74. package/dist/components/Chat/markdown/streaming-harness.js +62 -0
  75. package/dist/components/Chat/markdown/types.d.ts +139 -0
  76. package/dist/components/Chat/markdown/types.js +13 -0
  77. package/dist/components/Chat/markdown/url-policy.d.ts +33 -0
  78. package/dist/components/Chat/markdown/url-policy.js +109 -0
  79. package/dist/components/FileUpload/FileUpload.svelte +35 -123
  80. package/dist/components/FileUpload/FileUpload.svelte.d.ts +1 -1
  81. package/dist/components/FileUpload/index.d.ts +2 -28
  82. package/dist/components/PinInput/PinInput.svelte +321 -0
  83. package/dist/components/PinInput/PinInput.svelte.d.ts +4 -0
  84. package/dist/components/PinInput/index.d.ts +98 -0
  85. package/dist/components/PinInput/index.js +2 -0
  86. package/dist/components/PinInput/pin-input.variants.d.ts +96 -0
  87. package/dist/components/PinInput/pin-input.variants.js +111 -0
  88. package/dist/components/QRCode/QRCode.svelte +107 -0
  89. package/dist/components/QRCode/QRCode.svelte.d.ts +4 -0
  90. package/dist/components/QRCode/index.d.ts +74 -0
  91. package/dist/components/QRCode/index.js +3 -0
  92. package/dist/components/QRCode/qr-code.variants.d.ts +25 -0
  93. package/dist/components/QRCode/qr-code.variants.js +24 -0
  94. package/dist/components/QRCode/qr-encode.d.ts +22 -0
  95. package/dist/components/QRCode/qr-encode.js +528 -0
  96. package/dist/components/TimeInput/TimeInput.svelte +521 -0
  97. package/dist/components/TimeInput/TimeInput.svelte.d.ts +4 -0
  98. package/dist/components/TimeInput/index.d.ts +93 -0
  99. package/dist/components/TimeInput/index.js +2 -0
  100. package/dist/components/TimeInput/time-input.variants.d.ts +131 -0
  101. package/dist/components/TimeInput/time-input.variants.js +120 -0
  102. package/dist/components/index.d.ts +7 -0
  103. package/dist/components/index.js +4 -0
  104. package/dist/i18n/index.d.ts +18 -0
  105. package/dist/primitives/Collapsible/Collapsible.svelte +5 -0
  106. package/dist/primitives/SplitPane/SplitPane.svelte +293 -0
  107. package/dist/primitives/SplitPane/SplitPane.svelte.d.ts +4 -0
  108. package/dist/primitives/SplitPane/index.d.ts +88 -0
  109. package/dist/primitives/SplitPane/index.js +2 -0
  110. package/dist/primitives/SplitPane/split-pane.utils.d.ts +73 -0
  111. package/dist/primitives/SplitPane/split-pane.utils.js +94 -0
  112. package/dist/primitives/SplitPane/split-pane.variants.d.ts +40 -0
  113. package/dist/primitives/SplitPane/split-pane.variants.js +56 -0
  114. package/dist/primitives/index.d.ts +2 -0
  115. package/dist/primitives/index.js +1 -0
  116. package/dist/translations/de.d.ts +6 -0
  117. package/dist/translations/de.js +6 -0
  118. package/dist/translations/en.d.ts +6 -0
  119. package/dist/translations/en.js +6 -0
  120. package/dist/utils/file-intake.d.ts +78 -0
  121. package/dist/utils/file-intake.js +144 -0
  122. package/dist/utils/index.d.ts +1 -0
  123. package/dist/utils/index.js +1 -0
  124. package/package.json +3 -3
@@ -0,0 +1,528 @@
1
+ /**
2
+ * Zero-dependency QR Code encoder (ISO/IEC 18004).
3
+ *
4
+ * Produces the module matrix for a piece of text — no rendering, no runtime
5
+ * dependency. Supports numeric / alphanumeric / byte segment modes (whichever
6
+ * is most compact for the input), all 40 versions, the four error-correction
7
+ * levels, and automatic data-mask selection by the standard penalty rules.
8
+ *
9
+ * The algorithm follows the reference structure of Project Nayuki's public
10
+ * QR generator (the canonical, spec-faithful design); the code here is an
11
+ * independent TypeScript implementation of the ISO standard.
12
+ */
13
+ /** ECC level → ordinal used to index the correction tables. */
14
+ const ECL_ORDINAL = { L: 0, M: 1, Q: 2, H: 3 };
15
+ /** ECC level → the 2 format bits it contributes (L=01, M=00, Q=11, H=10). */
16
+ const ECL_FORMAT_BITS = { L: 1, M: 0, Q: 3, H: 2 };
17
+ const MIN_VERSION = 1;
18
+ const MAX_VERSION = 40;
19
+ const PENALTY_N1 = 3;
20
+ const PENALTY_N2 = 3;
21
+ const PENALTY_N3 = 40;
22
+ const PENALTY_N4 = 10;
23
+ // Number of error-correction codewords per block, indexed [ecl][version].
24
+ // Index 0 of each row is unused padding.
25
+ const ECC_CODEWORDS_PER_BLOCK = [
26
+ // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
27
+ [
28
+ -1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30,
29
+ 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30
30
+ ], // Low
31
+ [
32
+ -1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28,
33
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28
34
+ ], // Medium
35
+ [
36
+ -1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30,
37
+ 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30
38
+ ], // Quartile
39
+ [
40
+ -1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30,
41
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30
42
+ ] // High
43
+ ];
44
+ // Number of error-correction blocks, indexed [ecl][version].
45
+ const NUM_ERROR_CORRECTION_BLOCKS = [
46
+ // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
47
+ [
48
+ -1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14,
49
+ 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25
50
+ ], // Low
51
+ [
52
+ -1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23,
53
+ 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49
54
+ ], // Medium
55
+ [
56
+ -1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34,
57
+ 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68
58
+ ], // Quartile
59
+ [
60
+ -1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35,
61
+ 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81
62
+ ] // High
63
+ ];
64
+ const ALPHANUMERIC_CHARSET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';
65
+ /** Mode indicator (4-bit) values. */
66
+ const MODE_BITS = { numeric: 0x1, alphanumeric: 0x2, byte: 0x4 };
67
+ /** Character-count-indicator bit width for a mode within a version's group. */
68
+ function charCountBits(mode, version) {
69
+ const group = version <= 9 ? 0 : version <= 26 ? 1 : 2;
70
+ if (mode === 'numeric')
71
+ return [10, 12, 14][group];
72
+ if (mode === 'alphanumeric')
73
+ return [9, 11, 13][group];
74
+ return [8, 16, 16][group]; // byte
75
+ }
76
+ /** A growable bit buffer (MSB-first). */
77
+ class BitBuffer {
78
+ bits = [];
79
+ append(value, length) {
80
+ for (let i = length - 1; i >= 0; i--)
81
+ this.bits.push((value >>> i) & 1);
82
+ }
83
+ }
84
+ function selectMode(text) {
85
+ if (/^[0-9]*$/.test(text))
86
+ return 'numeric';
87
+ for (const ch of text)
88
+ if (!ALPHANUMERIC_CHARSET.includes(ch))
89
+ return 'byte';
90
+ return 'alphanumeric';
91
+ }
92
+ function utf8Bytes(text) {
93
+ return Array.from(new TextEncoder().encode(text));
94
+ }
95
+ /** Encode the payload (mode + count + data) into a bit buffer, given version. */
96
+ function encodeData(text, mode, version, bytes) {
97
+ const bb = new BitBuffer();
98
+ bb.append(MODE_BITS[mode], 4);
99
+ if (mode === 'numeric') {
100
+ bb.append(text.length, charCountBits(mode, version));
101
+ for (let i = 0; i < text.length; i += 3) {
102
+ const chunk = text.substring(i, i + 3);
103
+ bb.append(Number.parseInt(chunk, 10), chunk.length * 3 + 1);
104
+ }
105
+ }
106
+ else if (mode === 'alphanumeric') {
107
+ bb.append(text.length, charCountBits(mode, version));
108
+ for (let i = 0; i < text.length; i += 2) {
109
+ if (i + 1 < text.length) {
110
+ const v = ALPHANUMERIC_CHARSET.indexOf(text[i]) * 45 + ALPHANUMERIC_CHARSET.indexOf(text[i + 1]);
111
+ bb.append(v, 11);
112
+ }
113
+ else {
114
+ bb.append(ALPHANUMERIC_CHARSET.indexOf(text[i]), 6);
115
+ }
116
+ }
117
+ }
118
+ else {
119
+ bb.append(bytes.length, charCountBits(mode, version));
120
+ for (const b of bytes)
121
+ bb.append(b, 8);
122
+ }
123
+ return bb;
124
+ }
125
+ function getNumRawDataModules(ver) {
126
+ let result = (16 * ver + 128) * ver + 64;
127
+ if (ver >= 2) {
128
+ const numAlign = Math.floor(ver / 7) + 2;
129
+ result -= (25 * numAlign - 10) * numAlign - 55;
130
+ if (ver >= 7)
131
+ result -= 36;
132
+ }
133
+ return result;
134
+ }
135
+ function getNumDataCodewords(ver, ecl) {
136
+ const o = ECL_ORDINAL[ecl];
137
+ return (Math.floor(getNumRawDataModules(ver) / 8) -
138
+ ECC_CODEWORDS_PER_BLOCK[o][ver] * NUM_ERROR_CORRECTION_BLOCKS[o][ver]);
139
+ }
140
+ // --- Reed–Solomon over GF(2^8) with primitive polynomial 0x11D ---
141
+ function rsMultiply(x, y) {
142
+ let z = 0;
143
+ for (let i = 7; i >= 0; i--) {
144
+ z = (z << 1) ^ ((z >>> 7) * 0x11d);
145
+ z ^= ((y >>> i) & 1) * x;
146
+ }
147
+ return z & 0xff;
148
+ }
149
+ function rsComputeDivisor(degree) {
150
+ const result = new Array(degree).fill(0);
151
+ result[degree - 1] = 1;
152
+ let root = 1;
153
+ for (let i = 0; i < degree; i++) {
154
+ for (let j = 0; j < result.length; j++) {
155
+ result[j] = rsMultiply(result[j], root);
156
+ if (j + 1 < result.length)
157
+ result[j] ^= result[j + 1];
158
+ }
159
+ root = rsMultiply(root, 0x02);
160
+ }
161
+ return result;
162
+ }
163
+ function rsComputeRemainder(data, divisor) {
164
+ const result = new Array(divisor.length).fill(0);
165
+ for (const b of data) {
166
+ const factor = b ^ result.shift();
167
+ result.push(0);
168
+ for (let i = 0; i < result.length; i++)
169
+ result[i] ^= rsMultiply(divisor[i], factor);
170
+ }
171
+ return result;
172
+ }
173
+ /** Split data codewords into EC blocks, compute EC, and interleave. */
174
+ function addEccAndInterleave(data, ver, ecl) {
175
+ const o = ECL_ORDINAL[ecl];
176
+ const numBlocks = NUM_ERROR_CORRECTION_BLOCKS[o][ver];
177
+ const blockEccLen = ECC_CODEWORDS_PER_BLOCK[o][ver];
178
+ const rawCodewords = Math.floor(getNumRawDataModules(ver) / 8);
179
+ const numShortBlocks = numBlocks - (rawCodewords % numBlocks);
180
+ const shortBlockLen = Math.floor(rawCodewords / numBlocks);
181
+ const blocks = [];
182
+ const rsDiv = rsComputeDivisor(blockEccLen);
183
+ for (let i = 0, k = 0; i < numBlocks; i++) {
184
+ const dat = data.slice(k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1));
185
+ k += dat.length;
186
+ const ecc = rsComputeRemainder(dat, rsDiv);
187
+ const block = dat.slice();
188
+ if (i < numShortBlocks)
189
+ block.push(0); // padding placeholder, skipped on interleave
190
+ blocks.push(block.concat(ecc));
191
+ }
192
+ const result = [];
193
+ for (let i = 0; i < blocks[0].length; i++) {
194
+ for (let j = 0; j < blocks.length; j++) {
195
+ // Skip the padding cell in short blocks.
196
+ if (i !== shortBlockLen - blockEccLen || j >= numShortBlocks)
197
+ result.push(blocks[j][i]);
198
+ }
199
+ }
200
+ return result;
201
+ }
202
+ // --- Matrix construction ---
203
+ class QrMatrix {
204
+ version;
205
+ ecl;
206
+ size;
207
+ modules;
208
+ isFunction;
209
+ constructor(version, ecl, dataCodewords) {
210
+ this.version = version;
211
+ this.ecl = ecl;
212
+ this.size = version * 4 + 17;
213
+ this.modules = Array.from({ length: this.size }, () => new Array(this.size).fill(false));
214
+ this.isFunction = Array.from({ length: this.size }, () => new Array(this.size).fill(false));
215
+ this.drawFunctionPatterns();
216
+ const allCodewords = addEccAndInterleave(dataCodewords, version, ecl);
217
+ this.drawCodewords(allCodewords);
218
+ // Pick the mask that minimises the penalty score.
219
+ let minPenalty = Infinity;
220
+ let bestMask = 0;
221
+ for (let mask = 0; mask < 8; mask++) {
222
+ this.applyMask(mask);
223
+ this.drawFormatBits(mask);
224
+ const penalty = this.getPenaltyScore();
225
+ if (penalty < minPenalty) {
226
+ minPenalty = penalty;
227
+ bestMask = mask;
228
+ }
229
+ this.applyMask(mask); // undo (XOR is its own inverse)
230
+ }
231
+ this.applyMask(bestMask);
232
+ this.drawFormatBits(bestMask);
233
+ }
234
+ setFunctionModule(x, y, isDark) {
235
+ this.modules[y][x] = isDark;
236
+ this.isFunction[y][x] = true;
237
+ }
238
+ drawFunctionPatterns() {
239
+ // Timing patterns.
240
+ for (let i = 0; i < this.size; i++) {
241
+ this.setFunctionModule(6, i, i % 2 === 0);
242
+ this.setFunctionModule(i, 6, i % 2 === 0);
243
+ }
244
+ // Finder patterns (with their separators via the 8×8 boxes).
245
+ this.drawFinderPattern(3, 3);
246
+ this.drawFinderPattern(this.size - 4, 3);
247
+ this.drawFinderPattern(3, this.size - 4);
248
+ // Alignment patterns.
249
+ const alignPos = this.getAlignmentPatternPositions();
250
+ const n = alignPos.length;
251
+ for (let i = 0; i < n; i++) {
252
+ for (let j = 0; j < n; j++) {
253
+ // Skip the three finder corners.
254
+ if (!((i === 0 && j === 0) || (i === 0 && j === n - 1) || (i === n - 1 && j === 0))) {
255
+ this.drawAlignmentPattern(alignPos[i], alignPos[j]);
256
+ }
257
+ }
258
+ }
259
+ // Reserve format + version areas (filled with placeholders now, real bits later).
260
+ this.drawFormatBits(0);
261
+ this.drawVersion();
262
+ }
263
+ drawFinderPattern(cx, cy) {
264
+ for (let dy = -4; dy <= 4; dy++) {
265
+ for (let dx = -4; dx <= 4; dx++) {
266
+ const dist = Math.max(Math.abs(dx), Math.abs(dy));
267
+ const x = cx + dx;
268
+ const y = cy + dy;
269
+ if (x >= 0 && x < this.size && y >= 0 && y < this.size) {
270
+ this.setFunctionModule(x, y, dist !== 2 && dist !== 4);
271
+ }
272
+ }
273
+ }
274
+ }
275
+ drawAlignmentPattern(cx, cy) {
276
+ for (let dy = -2; dy <= 2; dy++) {
277
+ for (let dx = -2; dx <= 2; dx++) {
278
+ this.setFunctionModule(cx + dx, cy + dy, Math.max(Math.abs(dx), Math.abs(dy)) !== 1);
279
+ }
280
+ }
281
+ }
282
+ getAlignmentPatternPositions() {
283
+ if (this.version === 1)
284
+ return [];
285
+ const numAlign = Math.floor(this.version / 7) + 2;
286
+ const step = this.version === 32 ? 26 : Math.ceil((this.size - 13) / (numAlign * 2 - 2)) * 2;
287
+ const result = [6];
288
+ for (let pos = this.size - 7; result.length < numAlign; pos -= step)
289
+ result.splice(1, 0, pos);
290
+ return result;
291
+ }
292
+ drawFormatBits(mask) {
293
+ const data = (ECL_FORMAT_BITS[this.ecl] << 3) | mask;
294
+ let rem = data;
295
+ for (let i = 0; i < 10; i++)
296
+ rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
297
+ const bits = ((data << 10) | rem) ^ 0x5412;
298
+ // First copy (around the top-left finder).
299
+ for (let i = 0; i <= 5; i++)
300
+ this.setFunctionModule(8, i, ((bits >>> i) & 1) !== 0);
301
+ this.setFunctionModule(8, 7, ((bits >>> 6) & 1) !== 0);
302
+ this.setFunctionModule(8, 8, ((bits >>> 7) & 1) !== 0);
303
+ this.setFunctionModule(7, 8, ((bits >>> 8) & 1) !== 0);
304
+ for (let i = 9; i < 15; i++)
305
+ this.setFunctionModule(14 - i, 8, ((bits >>> i) & 1) !== 0);
306
+ // Second copy (split across the other two finders).
307
+ for (let i = 0; i < 8; i++)
308
+ this.setFunctionModule(this.size - 1 - i, 8, ((bits >>> i) & 1) !== 0);
309
+ for (let i = 8; i < 15; i++)
310
+ this.setFunctionModule(8, this.size - 15 + i, ((bits >>> i) & 1) !== 0);
311
+ this.setFunctionModule(8, this.size - 8, true); // always-dark module
312
+ }
313
+ drawVersion() {
314
+ if (this.version < 7)
315
+ return;
316
+ let rem = this.version;
317
+ for (let i = 0; i < 12; i++)
318
+ rem = (rem << 1) ^ ((rem >>> 11) * 0x1f25);
319
+ const bits = (this.version << 12) | rem;
320
+ for (let i = 0; i < 18; i++) {
321
+ const bit = ((bits >>> i) & 1) !== 0;
322
+ const a = this.size - 11 + (i % 3);
323
+ const b = Math.floor(i / 3);
324
+ this.setFunctionModule(a, b, bit);
325
+ this.setFunctionModule(b, a, bit);
326
+ }
327
+ }
328
+ drawCodewords(data) {
329
+ let i = 0; // bit index into data
330
+ for (let right = this.size - 1; right >= 1; right -= 2) {
331
+ // Reassign `right` (not a local copy) when it hits the vertical timing
332
+ // column so the following `-= 2` keeps the column pairs odd-aligned —
333
+ // otherwise columns past 6 double up and the leftmost pair is dropped.
334
+ if (right === 6)
335
+ right = 5;
336
+ for (let vert = 0; vert < this.size; vert++) {
337
+ for (let j = 0; j < 2; j++) {
338
+ const x = right - j;
339
+ const upward = ((right + 1) & 2) === 0;
340
+ const y = upward ? this.size - 1 - vert : vert;
341
+ if (!this.isFunction[y][x] && i < data.length * 8) {
342
+ this.modules[y][x] = ((data[i >>> 3] >>> (7 - (i & 7))) & 1) !== 0;
343
+ i++;
344
+ }
345
+ }
346
+ }
347
+ }
348
+ }
349
+ applyMask(mask) {
350
+ for (let y = 0; y < this.size; y++) {
351
+ for (let x = 0; x < this.size; x++) {
352
+ if (this.isFunction[y][x])
353
+ continue;
354
+ let invert;
355
+ switch (mask) {
356
+ case 0:
357
+ invert = (x + y) % 2 === 0;
358
+ break;
359
+ case 1:
360
+ invert = y % 2 === 0;
361
+ break;
362
+ case 2:
363
+ invert = x % 3 === 0;
364
+ break;
365
+ case 3:
366
+ invert = (x + y) % 3 === 0;
367
+ break;
368
+ case 4:
369
+ invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 === 0;
370
+ break;
371
+ case 5:
372
+ invert = ((x * y) % 2) + ((x * y) % 3) === 0;
373
+ break;
374
+ case 6:
375
+ invert = (((x * y) % 2) + ((x * y) % 3)) % 2 === 0;
376
+ break;
377
+ case 7:
378
+ invert = (((x + y) % 2) + ((x * y) % 3)) % 2 === 0;
379
+ break;
380
+ default:
381
+ throw new Error('unreachable mask');
382
+ }
383
+ if (invert)
384
+ this.modules[y][x] = !this.modules[y][x];
385
+ }
386
+ }
387
+ }
388
+ getPenaltyScore() {
389
+ let result = 0;
390
+ const size = this.size;
391
+ // N1: rows/columns of ≥5 same-coloured modules.
392
+ for (let y = 0; y < size; y++) {
393
+ let runColor = false;
394
+ let runLen = 0;
395
+ const history = [0, 0, 0, 0, 0, 0, 0];
396
+ for (let x = 0; x < size; x++) {
397
+ if (this.modules[y][x] === runColor) {
398
+ runLen++;
399
+ if (runLen === 5)
400
+ result += PENALTY_N1;
401
+ else if (runLen > 5)
402
+ result++;
403
+ }
404
+ else {
405
+ this.finderPenaltyAddHistory(runLen, history);
406
+ if (!runColor)
407
+ result += this.finderPenaltyCountPatterns(history) * PENALTY_N3;
408
+ runColor = this.modules[y][x];
409
+ runLen = 1;
410
+ }
411
+ }
412
+ result += this.finderPenaltyTerminateAndCount(runColor, runLen, history) * PENALTY_N3;
413
+ }
414
+ for (let x = 0; x < size; x++) {
415
+ let runColor = false;
416
+ let runLen = 0;
417
+ const history = [0, 0, 0, 0, 0, 0, 0];
418
+ for (let y = 0; y < size; y++) {
419
+ if (this.modules[y][x] === runColor) {
420
+ runLen++;
421
+ if (runLen === 5)
422
+ result += PENALTY_N1;
423
+ else if (runLen > 5)
424
+ result++;
425
+ }
426
+ else {
427
+ this.finderPenaltyAddHistory(runLen, history);
428
+ if (!runColor)
429
+ result += this.finderPenaltyCountPatterns(history) * PENALTY_N3;
430
+ runColor = this.modules[y][x];
431
+ runLen = 1;
432
+ }
433
+ }
434
+ result += this.finderPenaltyTerminateAndCount(runColor, runLen, history) * PENALTY_N3;
435
+ }
436
+ // N2: 2×2 blocks of the same colour.
437
+ for (let y = 0; y < size - 1; y++) {
438
+ for (let x = 0; x < size - 1; x++) {
439
+ const c = this.modules[y][x];
440
+ if (c === this.modules[y][x + 1] &&
441
+ c === this.modules[y + 1][x] &&
442
+ c === this.modules[y + 1][x + 1]) {
443
+ result += PENALTY_N2;
444
+ }
445
+ }
446
+ }
447
+ // N4: proportion of dark modules deviating from 50%.
448
+ let dark = 0;
449
+ for (const row of this.modules)
450
+ for (const cell of row)
451
+ if (cell)
452
+ dark++;
453
+ const total = size * size;
454
+ const k = Math.ceil(Math.abs(dark * 20 - total * 10) / total) - 1;
455
+ result += k * PENALTY_N4;
456
+ return result;
457
+ }
458
+ finderPenaltyCountPatterns(runHistory) {
459
+ const n = runHistory[1];
460
+ const core = n > 0 &&
461
+ runHistory[2] === n &&
462
+ runHistory[3] === n * 3 &&
463
+ runHistory[4] === n &&
464
+ runHistory[5] === n;
465
+ return ((core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) +
466
+ (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0));
467
+ }
468
+ finderPenaltyTerminateAndCount(currentRunColor, currentRunLength, runHistory) {
469
+ let runLen = currentRunLength;
470
+ if (currentRunColor) {
471
+ this.finderPenaltyAddHistory(runLen, runHistory);
472
+ runLen = 0;
473
+ }
474
+ runLen += this.size;
475
+ this.finderPenaltyAddHistory(runLen, runHistory);
476
+ return this.finderPenaltyCountPatterns(runHistory);
477
+ }
478
+ finderPenaltyAddHistory(currentRunLength, runHistory) {
479
+ if (runHistory[0] === 0)
480
+ currentRunLength += this.size; // add light border to first run
481
+ runHistory.pop();
482
+ runHistory.unshift(currentRunLength);
483
+ }
484
+ }
485
+ /**
486
+ * Encode `text` into a QR module matrix (`true` = dark). The returned matrix has
487
+ * no quiet zone — the renderer adds it. Throws when the text does not fit any
488
+ * version at the requested ECC level.
489
+ */
490
+ export function encodeQr(text, ecl = 'M', opts = {}) {
491
+ const minV = Math.max(MIN_VERSION, opts.minVersion ?? MIN_VERSION);
492
+ const maxV = Math.min(MAX_VERSION, opts.maxVersion ?? MAX_VERSION);
493
+ const mode = selectMode(text);
494
+ const bytes = mode === 'byte' ? utf8Bytes(text) : [];
495
+ // Find the smallest version that fits.
496
+ let version = -1;
497
+ let dataUsedBits = -1;
498
+ for (let v = minV; v <= maxV; v++) {
499
+ const capacityBits = getNumDataCodewords(v, ecl) * 8;
500
+ const bb = encodeData(text, mode, v, bytes);
501
+ if (bb.bits.length <= capacityBits) {
502
+ version = v;
503
+ dataUsedBits = bb.bits.length;
504
+ break;
505
+ }
506
+ }
507
+ if (version === -1) {
508
+ throw new Error('QR data too long for the given error-correction level');
509
+ }
510
+ const capacityBits = getNumDataCodewords(version, ecl) * 8;
511
+ const bb = encodeData(text, mode, version, bytes);
512
+ // Terminator + bit padding to a byte boundary.
513
+ const terminator = Math.min(4, capacityBits - dataUsedBits);
514
+ bb.append(0, terminator);
515
+ bb.append(0, (8 - (bb.bits.length % 8)) % 8);
516
+ // Byte padding (alternating 0xEC, 0x11) up to capacity.
517
+ for (let pad = 0xec; bb.bits.length < capacityBits; pad ^= 0xec ^ 0x11)
518
+ bb.append(pad, 8);
519
+ // Pack bits into codewords.
520
+ const dataCodewords = [];
521
+ for (let i = 0; i < bb.bits.length; i += 8) {
522
+ let byte = 0;
523
+ for (let j = 0; j < 8; j++)
524
+ byte = (byte << 1) | bb.bits[i + j];
525
+ dataCodewords.push(byte);
526
+ }
527
+ return new QrMatrix(version, ecl, dataCodewords).modules;
528
+ }