@twentyfirstmedia/ui-core 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ICONS-LICENSE +175 -0
- package/dist/components/admin.d.ts.map +1 -1
- package/dist/components/admin.js +31 -21
- package/dist/components/admin.js.map +1 -1
- package/dist/components/agents.d.ts.map +1 -1
- package/dist/components/agents.js +21 -18
- package/dist/components/agents.js.map +1 -1
- package/dist/components/app-chrome.d.ts.map +1 -1
- package/dist/components/app-chrome.js +5 -5
- package/dist/components/app-chrome.js.map +1 -1
- package/dist/components/approvals.d.ts.map +1 -1
- package/dist/components/approvals.js +2 -2
- package/dist/components/approvals.js.map +1 -1
- package/dist/components/building-blocks.d.ts.map +1 -1
- package/dist/components/building-blocks.js +13 -10
- package/dist/components/building-blocks.js.map +1 -1
- package/dist/components/charts.d.ts +2 -2
- package/dist/components/charts.d.ts.map +1 -1
- package/dist/components/charts.js +14 -11
- package/dist/components/charts.js.map +1 -1
- package/dist/components/chat.d.ts +2 -2
- package/dist/components/chat.d.ts.map +1 -1
- package/dist/components/chat.js +22 -18
- package/dist/components/chat.js.map +1 -1
- package/dist/components/commerce.d.ts.map +1 -1
- package/dist/components/commerce.js +20 -16
- package/dist/components/commerce.js.map +1 -1
- package/dist/components/data-display.d.ts +0 -5
- package/dist/components/data-display.d.ts.map +1 -1
- package/dist/components/data-display.js +41 -22
- package/dist/components/data-display.js.map +1 -1
- package/dist/components/data-table.d.ts +2 -2
- package/dist/components/data-table.d.ts.map +1 -1
- package/dist/components/data-table.js +3 -3
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/developer.d.ts.map +1 -1
- package/dist/components/developer.js +7 -6
- package/dist/components/developer.js.map +1 -1
- package/dist/components/feedback.d.ts.map +1 -1
- package/dist/components/feedback.js +5 -4
- package/dist/components/feedback.js.map +1 -1
- package/dist/components/forms.d.ts.map +1 -1
- package/dist/components/forms.js +63 -21
- package/dist/components/forms.js.map +1 -1
- package/dist/components/foundation.d.ts.map +1 -1
- package/dist/components/foundation.js +13 -9
- package/dist/components/foundation.js.map +1 -1
- package/dist/components/index.d.ts +2 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -1
- package/dist/components/index.js.map +1 -1
- package/dist/components/inputs.d.ts.map +1 -1
- package/dist/components/inputs.js +33 -8
- package/dist/components/inputs.js.map +1 -1
- package/dist/components/mail.d.ts.map +1 -1
- package/dist/components/mail.js +5 -5
- package/dist/components/mail.js.map +1 -1
- package/dist/components/media.d.ts.map +1 -1
- package/dist/components/media.js +62 -11
- package/dist/components/media.js.map +1 -1
- package/dist/components/navigation.d.ts +3 -1
- package/dist/components/navigation.d.ts.map +1 -1
- package/dist/components/navigation.js +287 -20
- package/dist/components/navigation.js.map +1 -1
- package/dist/components/operations.d.ts.map +1 -1
- package/dist/components/operations.js +10 -10
- package/dist/components/operations.js.map +1 -1
- package/dist/components/overlays.d.ts.map +1 -1
- package/dist/components/overlays.js +2 -2
- package/dist/components/overlays.js.map +1 -1
- package/dist/components/previews.js +2 -2
- package/dist/components/previews.js.map +1 -1
- package/dist/components/primitives.js +2 -2
- package/dist/components/primitives.js.map +1 -1
- package/dist/components/qr-code.d.ts +8 -0
- package/dist/components/qr-code.d.ts.map +1 -0
- package/dist/components/qr-code.js +18 -0
- package/dist/components/qr-code.js.map +1 -0
- package/dist/components/real-estate.d.ts.map +1 -1
- package/dist/components/real-estate.js +5 -5
- package/dist/components/real-estate.js.map +1 -1
- package/dist/components/rich-text-editor.d.ts.map +1 -1
- package/dist/components/rich-text-editor.js +1 -1
- package/dist/components/rich-text-editor.js.map +1 -1
- package/dist/components/select-menu.js +1 -1
- package/dist/components/select-menu.js.map +1 -1
- package/dist/components/shell.d.ts +0 -4
- package/dist/components/shell.d.ts.map +1 -1
- package/dist/components/shell.js +100 -7
- package/dist/components/shell.js.map +1 -1
- package/dist/components/site.d.ts.map +1 -1
- package/dist/components/site.js +8 -6
- package/dist/components/site.js.map +1 -1
- package/dist/components/status.d.ts.map +1 -1
- package/dist/components/status.js +2 -2
- package/dist/components/status.js.map +1 -1
- package/dist/components/system.d.ts.map +1 -1
- package/dist/components/system.js +3 -2
- package/dist/components/system.js.map +1 -1
- package/dist/components/types.d.ts +257 -18
- package/dist/components/types.d.ts.map +1 -1
- package/dist/components/workspace.d.ts.map +1 -1
- package/dist/components/workspace.js +15 -12
- package/dist/components/workspace.js.map +1 -1
- package/dist/icon-library.d.ts +254 -3
- package/dist/icon-library.d.ts.map +1 -1
- package/dist/icon-library.js +518 -14
- package/dist/icon-library.js.map +1 -1
- package/dist/qr.d.ts +14 -0
- package/dist/qr.d.ts.map +1 -0
- package/dist/qr.js +298 -0
- package/dist/qr.js.map +1 -0
- package/dist/strings.d.ts +30 -4
- package/dist/strings.d.ts.map +1 -1
- package/dist/strings.js +15 -0
- package/dist/strings.js.map +1 -1
- package/dist/themes.css +2345 -176
- package/package.json +2 -1
- package/src/components/admin.tsx +66 -23
- package/src/components/agents.tsx +22 -20
- package/src/components/app-chrome.tsx +9 -5
- package/src/components/approvals.tsx +3 -1
- package/src/components/building-blocks.tsx +24 -13
- package/src/components/charts.tsx +17 -12
- package/src/components/chat.tsx +54 -31
- package/src/components/commerce.tsx +58 -24
- package/src/components/data-display.tsx +106 -38
- package/src/components/data-table.tsx +11 -7
- package/src/components/developer.tsx +15 -6
- package/src/components/feedback.tsx +5 -3
- package/src/components/forms.tsx +101 -23
- package/src/components/foundation.tsx +9 -5
- package/src/components/index.ts +10 -1
- package/src/components/inputs.tsx +44 -7
- package/src/components/mail.tsx +7 -3
- package/src/components/media.tsx +88 -16
- package/src/components/navigation.tsx +651 -71
- package/src/components/operations.tsx +17 -8
- package/src/components/overlays.tsx +7 -2
- package/src/components/previews.tsx +2 -2
- package/src/components/primitives.tsx +2 -2
- package/src/components/qr-code.tsx +30 -0
- package/src/components/real-estate.tsx +7 -4
- package/src/components/rich-text-editor.tsx +7 -1
- package/src/components/select-menu.tsx +1 -1
- package/src/components/shell.tsx +237 -11
- package/src/components/site.tsx +18 -4
- package/src/components/status.tsx +2 -0
- package/src/components/system.tsx +3 -2
- package/src/components/types.ts +261 -18
- package/src/components/workspace.tsx +37 -15
- package/src/icon-library.ts +523 -18
- package/src/qr.ts +300 -0
- package/src/strings.ts +56 -1
package/src/qr.ts
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small QR code encoder (ISO/IEC 18004): byte mode, versions 1–40, error correction L/M/Q/H,
|
|
3
|
+
* the mask with the lowest penalty. Enough for otpauth:// links, URLs and short texts; it runs
|
|
4
|
+
* locally, so nothing leaves the app.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type QrLevel = "L" | "M" | "Q" | "H";
|
|
8
|
+
|
|
9
|
+
const LEVEL_BITS: Record<QrLevel, number> = { L: 1, M: 0, Q: 3, H: 2 };
|
|
10
|
+
const LEVEL_INDEX: Record<QrLevel, number> = { L: 0, M: 1, Q: 2, H: 3 };
|
|
11
|
+
|
|
12
|
+
// error correction codewords per block, and number of blocks, by level (L, M, Q, H) and version
|
|
13
|
+
// prettier-ignore
|
|
14
|
+
const ECC_PER_BLOCK: number[][] = [
|
|
15
|
+
[-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
|
|
16
|
+
[-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28],
|
|
17
|
+
[-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
|
|
18
|
+
[-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
|
|
19
|
+
];
|
|
20
|
+
// prettier-ignore
|
|
21
|
+
const BLOCKS: number[][] = [
|
|
22
|
+
[-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, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25],
|
|
23
|
+
[-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, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49],
|
|
24
|
+
[-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, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68],
|
|
25
|
+
[-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, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81],
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
/** Modules of all function patterns and data for a version. */
|
|
29
|
+
function rawModules(ver: number): number {
|
|
30
|
+
let r = (16 * ver + 128) * ver + 64;
|
|
31
|
+
if (ver >= 2) {
|
|
32
|
+
const n = Math.floor(ver / 7) + 2;
|
|
33
|
+
r -= (25 * n - 10) * n - 55;
|
|
34
|
+
if (ver >= 7) r -= 36;
|
|
35
|
+
}
|
|
36
|
+
return r;
|
|
37
|
+
}
|
|
38
|
+
function dataCodewords(ver: number, lvl: number): number {
|
|
39
|
+
return Math.floor(rawModules(ver) / 8) - ECC_PER_BLOCK[lvl]![ver]! * BLOCKS[lvl]![ver]!;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Reed–Solomon over GF(256) with the polynomial 0x11d */
|
|
43
|
+
function mul(x: number, y: number): number {
|
|
44
|
+
let z = 0;
|
|
45
|
+
for (let i = 7; i >= 0; i--) {
|
|
46
|
+
z = (z << 1) ^ ((z >>> 7) * 0x11d);
|
|
47
|
+
z ^= ((y >>> i) & 1) * x;
|
|
48
|
+
}
|
|
49
|
+
return z & 0xff;
|
|
50
|
+
}
|
|
51
|
+
function divisor(degree: number): number[] {
|
|
52
|
+
const r = new Array<number>(degree).fill(0);
|
|
53
|
+
r[degree - 1] = 1;
|
|
54
|
+
let root = 1;
|
|
55
|
+
for (let i = 0; i < degree; i++) {
|
|
56
|
+
for (let j = 0; j < r.length; j++) {
|
|
57
|
+
r[j] = mul(r[j]!, root);
|
|
58
|
+
if (j + 1 < r.length) r[j] = r[j]! ^ r[j + 1]!;
|
|
59
|
+
}
|
|
60
|
+
root = mul(root, 0x02);
|
|
61
|
+
}
|
|
62
|
+
return r;
|
|
63
|
+
}
|
|
64
|
+
function remainder(data: number[], div: number[]): number[] {
|
|
65
|
+
const r = new Array<number>(div.length).fill(0);
|
|
66
|
+
for (const b of data) {
|
|
67
|
+
const f = b ^ r.shift()!;
|
|
68
|
+
r.push(0);
|
|
69
|
+
div.forEach((c, i) => (r[i] = r[i]! ^ mul(c, f)));
|
|
70
|
+
}
|
|
71
|
+
return r;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function alignment(ver: number): number[] {
|
|
75
|
+
if (ver === 1) return [];
|
|
76
|
+
const n = Math.floor(ver / 7) + 2;
|
|
77
|
+
const step = ver === 32 ? 26 : Math.ceil((ver * 4 + 4) / (n * 2 - 2)) * 2;
|
|
78
|
+
const out = [6];
|
|
79
|
+
for (let pos = ver * 4 + 10; out.length < n; pos -= step) out.splice(1, 0, pos);
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Encodes text as a QR code: a square of booleans (true = dark), without the quiet zone.
|
|
85
|
+
* Throws when the text does not fit version 40.
|
|
86
|
+
*/
|
|
87
|
+
export function qrMatrix(text: string, level: QrLevel = "M"): boolean[][] {
|
|
88
|
+
const bytes = Array.from(new TextEncoder().encode(text));
|
|
89
|
+
const lvl = LEVEL_INDEX[level];
|
|
90
|
+
let ver = 1;
|
|
91
|
+
for (; ; ver++) {
|
|
92
|
+
if (ver > 40) throw new Error("Text too long for a QR code");
|
|
93
|
+
const countBits = ver < 10 ? 8 : 16;
|
|
94
|
+
if (4 + countBits + bytes.length * 8 <= dataCodewords(ver, lvl) * 8) break;
|
|
95
|
+
}
|
|
96
|
+
const size = ver * 4 + 17;
|
|
97
|
+
|
|
98
|
+
// data bits: byte mode, count, bytes, terminator, padding
|
|
99
|
+
const bits: number[] = [];
|
|
100
|
+
const put = (v: number, n: number) => {
|
|
101
|
+
for (let i = n - 1; i >= 0; i--) bits.push((v >>> i) & 1);
|
|
102
|
+
};
|
|
103
|
+
put(0b0100, 4);
|
|
104
|
+
put(bytes.length, ver < 10 ? 8 : 16);
|
|
105
|
+
bytes.forEach((b) => put(b, 8));
|
|
106
|
+
const cap = dataCodewords(ver, lvl) * 8;
|
|
107
|
+
put(0, Math.min(4, cap - bits.length));
|
|
108
|
+
put(0, (8 - (bits.length % 8)) % 8);
|
|
109
|
+
for (let pad = 0xec; bits.length < cap; pad ^= 0xec ^ 0x11) put(pad, 8);
|
|
110
|
+
const data: number[] = [];
|
|
111
|
+
for (let i = 0; i < bits.length; i += 8) data.push(parseInt(bits.slice(i, i + 8).join(""), 2));
|
|
112
|
+
|
|
113
|
+
// blocks with error correction, interleaved
|
|
114
|
+
const nBlocks = BLOCKS[lvl]![ver]!,
|
|
115
|
+
eccLen = ECC_PER_BLOCK[lvl]![ver]!,
|
|
116
|
+
raw = Math.floor(rawModules(ver) / 8),
|
|
117
|
+
shortBlocks = nBlocks - (raw % nBlocks),
|
|
118
|
+
shortLen = Math.floor(raw / nBlocks);
|
|
119
|
+
const div = divisor(eccLen);
|
|
120
|
+
const blocks: number[][] = [];
|
|
121
|
+
for (let i = 0, k = 0; i < nBlocks; i++) {
|
|
122
|
+
const len = shortLen - eccLen + (i < shortBlocks ? 0 : 1);
|
|
123
|
+
const d = data.slice(k, k + len);
|
|
124
|
+
k += len;
|
|
125
|
+
const ecc = remainder(d, div);
|
|
126
|
+
if (i < shortBlocks) d.push(0);
|
|
127
|
+
blocks.push(d.concat(ecc));
|
|
128
|
+
}
|
|
129
|
+
const codewords: number[] = [];
|
|
130
|
+
for (let i = 0; i < blocks[0]!.length; i++)
|
|
131
|
+
blocks.forEach((b, j) => {
|
|
132
|
+
if (i !== shortLen - eccLen || j >= shortBlocks) codewords.push(b[i]!);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// function patterns
|
|
136
|
+
const m: boolean[][] = Array.from({ length: size }, () => new Array<boolean>(size).fill(false));
|
|
137
|
+
const fn: boolean[][] = Array.from({ length: size }, () => new Array<boolean>(size).fill(false));
|
|
138
|
+
const set = (x: number, y: number, dark: boolean) => {
|
|
139
|
+
m[y]![x] = dark;
|
|
140
|
+
fn[y]![x] = true;
|
|
141
|
+
};
|
|
142
|
+
for (let i = 0; i < size; i++) {
|
|
143
|
+
set(6, i, i % 2 === 0);
|
|
144
|
+
set(i, 6, i % 2 === 0);
|
|
145
|
+
}
|
|
146
|
+
const finder = (cx: number, cy: number) => {
|
|
147
|
+
for (let dy = -4; dy <= 4; dy++)
|
|
148
|
+
for (let dx = -4; dx <= 4; dx++) {
|
|
149
|
+
const d = Math.max(Math.abs(dx), Math.abs(dy)),
|
|
150
|
+
x = cx + dx,
|
|
151
|
+
y = cy + dy;
|
|
152
|
+
if (x >= 0 && x < size && y >= 0 && y < size) set(x, y, d !== 2 && d !== 4);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
finder(3, 3);
|
|
156
|
+
finder(size - 4, 3);
|
|
157
|
+
finder(3, size - 4);
|
|
158
|
+
const al = alignment(ver);
|
|
159
|
+
al.forEach((ay, i) =>
|
|
160
|
+
al.forEach((ax, j) => {
|
|
161
|
+
if (
|
|
162
|
+
(i === 0 && j === 0) ||
|
|
163
|
+
(i === 0 && j === al.length - 1) ||
|
|
164
|
+
(i === al.length - 1 && j === 0)
|
|
165
|
+
)
|
|
166
|
+
return;
|
|
167
|
+
for (let dy = -2; dy <= 2; dy++)
|
|
168
|
+
for (let dx = -2; dx <= 2; dx++)
|
|
169
|
+
set(ax + dx, ay + dy, Math.max(Math.abs(dx), Math.abs(dy)) !== 1);
|
|
170
|
+
}),
|
|
171
|
+
);
|
|
172
|
+
const format = (mask: number) => {
|
|
173
|
+
const d = (LEVEL_BITS[level] << 3) | mask;
|
|
174
|
+
let r = d;
|
|
175
|
+
for (let i = 0; i < 10; i++) r = (r << 1) ^ ((r >>> 9) * 0x537);
|
|
176
|
+
const b = ((d << 10) | r) ^ 0x5412;
|
|
177
|
+
const bit = (i: number) => ((b >>> i) & 1) !== 0;
|
|
178
|
+
for (let i = 0; i <= 5; i++) set(8, i, bit(i));
|
|
179
|
+
set(8, 7, bit(6));
|
|
180
|
+
set(8, 8, bit(7));
|
|
181
|
+
set(7, 8, bit(8));
|
|
182
|
+
for (let i = 9; i < 15; i++) set(14 - i, 8, bit(i));
|
|
183
|
+
for (let i = 0; i < 8; i++) set(size - 1 - i, 8, bit(i));
|
|
184
|
+
for (let i = 8; i < 15; i++) set(8, size - 15 + i, bit(i));
|
|
185
|
+
set(8, size - 8, true);
|
|
186
|
+
};
|
|
187
|
+
format(0); // reserve the format areas
|
|
188
|
+
if (ver >= 7) {
|
|
189
|
+
let r = ver;
|
|
190
|
+
for (let i = 0; i < 12; i++) r = (r << 1) ^ ((r >>> 11) * 0x1f25);
|
|
191
|
+
const b = (ver << 12) | r;
|
|
192
|
+
for (let i = 0; i < 18; i++) {
|
|
193
|
+
const dark = ((b >>> i) & 1) !== 0,
|
|
194
|
+
a = size - 11 + (i % 3),
|
|
195
|
+
c = Math.floor(i / 3);
|
|
196
|
+
set(a, c, dark);
|
|
197
|
+
set(c, a, dark);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// data in the zigzag
|
|
202
|
+
let i = 0;
|
|
203
|
+
for (let right = size - 1; right >= 1; right -= 2) {
|
|
204
|
+
if (right === 6) right = 5;
|
|
205
|
+
for (let vert = 0; vert < size; vert++)
|
|
206
|
+
for (let j = 0; j < 2; j++) {
|
|
207
|
+
const x = right - j,
|
|
208
|
+
up = ((right + 1) & 2) === 0,
|
|
209
|
+
y = up ? size - 1 - vert : vert;
|
|
210
|
+
if (!fn[y]![x] && i < codewords.length * 8) {
|
|
211
|
+
m[y]![x] = ((codewords[i >>> 3]! >>> (7 - (i & 7))) & 1) !== 0;
|
|
212
|
+
i++;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const masked = (mask: number) => {
|
|
218
|
+
const out = m.map((row) => row.slice());
|
|
219
|
+
for (let y = 0; y < size; y++)
|
|
220
|
+
for (let x = 0; x < size; x++) {
|
|
221
|
+
if (fn[y]![x]) continue;
|
|
222
|
+
const flip = [
|
|
223
|
+
(x + y) % 2 === 0,
|
|
224
|
+
y % 2 === 0,
|
|
225
|
+
x % 3 === 0,
|
|
226
|
+
(x + y) % 3 === 0,
|
|
227
|
+
(Math.floor(x / 3) + Math.floor(y / 2)) % 2 === 0,
|
|
228
|
+
((x * y) % 2) + ((x * y) % 3) === 0,
|
|
229
|
+
(((x * y) % 2) + ((x * y) % 3)) % 2 === 0,
|
|
230
|
+
(((x + y) % 2) + ((x * y) % 3)) % 2 === 0,
|
|
231
|
+
][mask];
|
|
232
|
+
if (flip) out[y]![x] = !out[y]![x];
|
|
233
|
+
}
|
|
234
|
+
return out;
|
|
235
|
+
};
|
|
236
|
+
const penalty = (g: boolean[][]) => {
|
|
237
|
+
let p = 0;
|
|
238
|
+
const lines = (get: (a: number, b: number) => boolean) => {
|
|
239
|
+
for (let a = 0; a < size; a++) {
|
|
240
|
+
let run = 1;
|
|
241
|
+
const seq: boolean[] = [];
|
|
242
|
+
for (let b = 0; b < size; b++) {
|
|
243
|
+
seq.push(get(a, b));
|
|
244
|
+
if (b > 0 && get(a, b) === get(a, b - 1)) {
|
|
245
|
+
run++;
|
|
246
|
+
if (run === 5) p += 3;
|
|
247
|
+
else if (run > 5) p++;
|
|
248
|
+
} else run = 1;
|
|
249
|
+
}
|
|
250
|
+
// finder-like patterns: 1:1:3:1:1 with four light modules on one side
|
|
251
|
+
const s = seq.map((v) => (v ? "1" : "0")).join("");
|
|
252
|
+
for (const pat of ["10111010000", "00001011101"]) {
|
|
253
|
+
let k = s.indexOf(pat);
|
|
254
|
+
while (k !== -1) {
|
|
255
|
+
p += 40;
|
|
256
|
+
k = s.indexOf(pat, k + 1);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
lines((a, b) => g[a]![b]!);
|
|
262
|
+
lines((a, b) => g[b]![a]!);
|
|
263
|
+
for (let y = 0; y < size - 1; y++)
|
|
264
|
+
for (let x = 0; x < size - 1; x++) {
|
|
265
|
+
const c = g[y]![x];
|
|
266
|
+
if (c === g[y]![x + 1] && c === g[y + 1]![x] && c === g[y + 1]![x + 1]) p += 3;
|
|
267
|
+
}
|
|
268
|
+
const dark = g.reduce((s, row) => s + row.filter(Boolean).length, 0);
|
|
269
|
+
const total = size * size;
|
|
270
|
+
p += Math.max(0, Math.ceil(Math.abs(dark * 20 - total * 10) / total) - 1) * 10;
|
|
271
|
+
return p;
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
let best: boolean[][] = m,
|
|
275
|
+
bestScore = Infinity;
|
|
276
|
+
for (let mask = 0; mask < 8; mask++) {
|
|
277
|
+
format(mask);
|
|
278
|
+
const g = masked(mask);
|
|
279
|
+
// the format bits were written into m; copy them into the masked grid
|
|
280
|
+
for (let y = 0; y < size; y++)
|
|
281
|
+
for (let x = 0; x < size; x++) if (fn[y]![x]) g[y]![x] = m[y]![x]!;
|
|
282
|
+
const score = penalty(g);
|
|
283
|
+
if (score < bestScore) {
|
|
284
|
+
bestScore = score;
|
|
285
|
+
best = g;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return best;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** SVG path data for a QR matrix: one 1×1 square per dark module, offset by the quiet zone. */
|
|
292
|
+
export function qrPath(matrix: boolean[][], quiet = 4): string {
|
|
293
|
+
let d = "";
|
|
294
|
+
matrix.forEach((row, y) =>
|
|
295
|
+
row.forEach((dark, x) => {
|
|
296
|
+
if (dark) d += `M${x + quiet} ${y + quiet}h1v1h-1z`;
|
|
297
|
+
}),
|
|
298
|
+
);
|
|
299
|
+
return d;
|
|
300
|
+
}
|
package/src/strings.ts
CHANGED
|
@@ -102,8 +102,22 @@ export interface UIStrings {
|
|
|
102
102
|
/** Accessible name of main navigation landmarks. */
|
|
103
103
|
mainNavigation: string;
|
|
104
104
|
sidebar: string;
|
|
105
|
+
/** Name of a `Sidebar as="aside"` and its button on phones, unless the app passes `label` */
|
|
106
|
+
filters: string;
|
|
105
107
|
expandSidebar: string;
|
|
106
108
|
collapseSidebar: string;
|
|
109
|
+
/** The menu button that opens the sidebar on phones. */
|
|
110
|
+
openNavigation: string;
|
|
111
|
+
closeNavigation: string;
|
|
112
|
+
/** The "…" button of a sidebar item. */
|
|
113
|
+
moreActionsFor: (label: string) => string;
|
|
114
|
+
/** Said after a link that opens in a new tab. */
|
|
115
|
+
opensInNewTab: string;
|
|
116
|
+
/** Said for the dot marker on a sidebar item. */
|
|
117
|
+
newActivity: string;
|
|
118
|
+
switchWorkspace: string;
|
|
119
|
+
/** The account menu (UserMenu). */
|
|
120
|
+
account: string;
|
|
107
121
|
/* Carousel */
|
|
108
122
|
/** aria-roledescription of a carousel slide. */
|
|
109
123
|
slide: string;
|
|
@@ -122,6 +136,9 @@ export interface UIStrings {
|
|
|
122
136
|
pickRange: string;
|
|
123
137
|
decrease: string;
|
|
124
138
|
increase: string;
|
|
139
|
+
/** TextField type="password": the reveal button */
|
|
140
|
+
showPassword: string;
|
|
141
|
+
hidePassword: string;
|
|
125
142
|
verificationCode: string;
|
|
126
143
|
digitN: (n: number) => string;
|
|
127
144
|
dropFiles: string;
|
|
@@ -178,6 +195,13 @@ export interface UIStrings {
|
|
|
178
195
|
/* Shell: SideRail, Dock */
|
|
179
196
|
tools: string;
|
|
180
197
|
quickActions: string;
|
|
198
|
+
/** SideRail toggle: show the names next to the icons */
|
|
199
|
+
expandRail: string;
|
|
200
|
+
/** SideRail toggle: back to icons only */
|
|
201
|
+
collapseRail: string;
|
|
202
|
+
/** FloatingLayout bottom sheet handle */
|
|
203
|
+
expandPanel: string;
|
|
204
|
+
collapsePanel: string;
|
|
181
205
|
/* Site: ChatLauncher, CookieConsent */
|
|
182
206
|
assistant: string;
|
|
183
207
|
openAssistant: string;
|
|
@@ -453,6 +477,8 @@ export interface UIStrings {
|
|
|
453
477
|
fileReady: string;
|
|
454
478
|
newExport: string;
|
|
455
479
|
twoFactorSteps: [string, string, string];
|
|
480
|
+
/** TwoFactorSetup: the checkbox under the code field */
|
|
481
|
+
trustDevice: string;
|
|
456
482
|
qrCode: string;
|
|
457
483
|
scanText: string;
|
|
458
484
|
next: string;
|
|
@@ -610,6 +636,7 @@ export const ADMIN_STRINGS: Pick<
|
|
|
610
636
|
| "newExport"
|
|
611
637
|
| "twoFactorSteps"
|
|
612
638
|
| "qrCode"
|
|
639
|
+
| "trustDevice"
|
|
613
640
|
| "scanText"
|
|
614
641
|
| "enterCode"
|
|
615
642
|
| "codeFailed"
|
|
@@ -621,7 +648,9 @@ export const ADMIN_STRINGS: Pick<
|
|
|
621
648
|
| "contrastAA"
|
|
622
649
|
| "contrastAALarge"
|
|
623
650
|
| "contrastFails"
|
|
651
|
+
| "switchWorkspace"
|
|
624
652
|
> = {
|
|
653
|
+
switchWorkspace: "Switch workspace",
|
|
625
654
|
minimum: "Minimum",
|
|
626
655
|
maximum: "Maximum",
|
|
627
656
|
min: "Min",
|
|
@@ -685,6 +714,7 @@ export const ADMIN_STRINGS: Pick<
|
|
|
685
714
|
newExport: "New export",
|
|
686
715
|
twoFactorSteps: ["Scan", "Confirm", "Save codes"],
|
|
687
716
|
qrCode: "QR code",
|
|
717
|
+
trustDevice: "Trust this device",
|
|
688
718
|
scanText:
|
|
689
719
|
"Scan the code with your authenticator app. If you can't scan it, enter the key by hand.",
|
|
690
720
|
enterCode: "Enter the 6-digit code from the app.",
|
|
@@ -1061,8 +1091,12 @@ export const FORMS_STRINGS: Pick<
|
|
|
1061
1091
|
| "dropHint"
|
|
1062
1092
|
| "uploaded"
|
|
1063
1093
|
| "cancelUpload"
|
|
1094
|
+
| "showPassword"
|
|
1095
|
+
| "hidePassword"
|
|
1064
1096
|
> = {
|
|
1065
1097
|
noMatches: "No matches",
|
|
1098
|
+
showPassword: "Show password",
|
|
1099
|
+
hidePassword: "Hide password",
|
|
1066
1100
|
createOption: (text) => `Create “${text}”`,
|
|
1067
1101
|
tagPlaceholder: "Type and press Enter",
|
|
1068
1102
|
previousMonth: "Previous month",
|
|
@@ -1126,16 +1160,30 @@ export const NAVIGATION_STRINGS: Pick<
|
|
|
1126
1160
|
| "previousPage"
|
|
1127
1161
|
| "nextPage"
|
|
1128
1162
|
| "sidebar"
|
|
1163
|
+
| "filters"
|
|
1129
1164
|
| "expandSidebar"
|
|
1130
1165
|
| "collapseSidebar"
|
|
1166
|
+
| "openNavigation"
|
|
1167
|
+
| "closeNavigation"
|
|
1168
|
+
| "moreActionsFor"
|
|
1169
|
+
| "opensInNewTab"
|
|
1170
|
+
| "newActivity"
|
|
1171
|
+
| "account"
|
|
1131
1172
|
> = {
|
|
1132
1173
|
breadcrumb: "Breadcrumb",
|
|
1133
1174
|
pagination: "Pagination",
|
|
1134
1175
|
previousPage: "Previous page",
|
|
1135
1176
|
nextPage: "Next page",
|
|
1136
1177
|
sidebar: "Sidebar",
|
|
1178
|
+
filters: "Filters",
|
|
1137
1179
|
expandSidebar: "Expand sidebar",
|
|
1138
1180
|
collapseSidebar: "Collapse sidebar",
|
|
1181
|
+
openNavigation: "Open navigation",
|
|
1182
|
+
closeNavigation: "Close navigation",
|
|
1183
|
+
moreActionsFor: (label) => `More actions for ${label}`,
|
|
1184
|
+
opensInNewTab: "(opens in a new tab)",
|
|
1185
|
+
newActivity: "New activity",
|
|
1186
|
+
account: "Account",
|
|
1139
1187
|
};
|
|
1140
1188
|
|
|
1141
1189
|
/** Strings of the components in `operations.tsx`. */
|
|
@@ -1325,9 +1373,16 @@ export const SELECT_MENU_STRINGS: Pick<UIStrings, "options"> = {
|
|
|
1325
1373
|
};
|
|
1326
1374
|
|
|
1327
1375
|
/** Strings of the components in `shell.tsx`. */
|
|
1328
|
-
export const SHELL_STRINGS: Pick<
|
|
1376
|
+
export const SHELL_STRINGS: Pick<
|
|
1377
|
+
UIStrings,
|
|
1378
|
+
"tools" | "quickActions" | "expandRail" | "collapseRail" | "expandPanel" | "collapsePanel"
|
|
1379
|
+
> = {
|
|
1329
1380
|
tools: "Tools",
|
|
1330
1381
|
quickActions: "Quick actions",
|
|
1382
|
+
expandRail: "Show names",
|
|
1383
|
+
collapseRail: "Icons only",
|
|
1384
|
+
expandPanel: "Expand panel",
|
|
1385
|
+
collapsePanel: "Collapse panel",
|
|
1331
1386
|
};
|
|
1332
1387
|
|
|
1333
1388
|
/** Strings of the components in `site.tsx`. */
|