@texuli/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/README.md +30 -6
- package/dist/editor/document.js +8 -1
- package/dist/editor/extensions.d.ts +64 -0
- package/dist/editor/extensions.js +116 -0
- package/dist/editor/inline.d.ts +5 -3
- package/dist/editor/inline.js +24 -12
- package/dist/editor/load.d.ts +10 -0
- package/dist/editor/load.js +16 -0
- package/dist/editor/markdown.d.ts +10 -1
- package/dist/editor/markdown.js +340 -100
- package/dist/editor/model.d.ts +3 -1
- package/dist/editor/model.js +3 -1
- package/dist/editor/transforms.d.ts +1 -1
- package/dist/editor/tree.d.ts +11 -1
- package/dist/editor/tree.js +11 -2
- package/dist/editor/types.d.ts +10 -0
- package/dist/editor/types.js +1 -0
- package/dist/focus-scope/focus-scope.d.ts +7 -0
- package/dist/focus-scope/focus-scope.js +24 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/inert/inert.d.ts +11 -0
- package/dist/inert/inert.js +13 -4
- package/dist/markup/index.d.ts +5 -0
- package/dist/markup/index.js +5 -0
- package/dist/markup/markup.d.ts +72 -0
- package/dist/markup/markup.js +233 -0
- package/dist/motion/animate.d.ts +109 -0
- package/dist/motion/animate.js +225 -0
- package/dist/motion/flip.d.ts +58 -0
- package/dist/motion/flip.js +167 -0
- package/dist/motion/index.d.ts +15 -0
- package/dist/motion/index.js +15 -0
- package/dist/motion/preferences.d.ts +68 -0
- package/dist/motion/preferences.js +111 -0
- package/dist/motion/presence.d.ts +61 -0
- package/dist/motion/presence.js +231 -0
- package/dist/motion/sequence.d.ts +70 -0
- package/dist/motion/sequence.js +159 -0
- package/dist/motion/shared.d.ts +45 -0
- package/dist/motion/shared.js +144 -0
- package/dist/motion/spring.d.ts +109 -0
- package/dist/motion/spring.js +166 -0
- package/dist/overlay/core.js +16 -3
- package/dist/url-policy/filter-image-srcset.d.ts +11 -0
- package/dist/url-policy/filter-image-srcset.js +60 -0
- package/dist/url-policy/index.d.ts +1 -0
- package/dist/url-policy/index.js +1 -0
- package/dist/zip/index.d.ts +5 -0
- package/dist/zip/index.js +5 -0
- package/dist/zip/zip.d.ts +35 -0
- package/dist/zip/zip.js +190 -0
- package/package.json +6 -2
package/dist/zip/zip.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
const MAX_ENTRIES = 0xffff;
|
|
2
|
+
const MAX_SIZE = 0xffffffff;
|
|
3
|
+
const DOS_TIME = 0;
|
|
4
|
+
const DOS_DATE = (0 << 9) | (1 << 5) | 1;
|
|
5
|
+
const UTF8_FLAG = 0x0800;
|
|
6
|
+
const STORED = 0;
|
|
7
|
+
const DEFLATED = 8;
|
|
8
|
+
let crcTable;
|
|
9
|
+
function table() {
|
|
10
|
+
if (crcTable)
|
|
11
|
+
return crcTable;
|
|
12
|
+
crcTable = new Uint32Array(256);
|
|
13
|
+
for (let n = 0; n < 256; n += 1) {
|
|
14
|
+
let c = n;
|
|
15
|
+
for (let k = 0; k < 8; k += 1)
|
|
16
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
17
|
+
crcTable[n] = c >>> 0;
|
|
18
|
+
}
|
|
19
|
+
return crcTable;
|
|
20
|
+
}
|
|
21
|
+
/** CRC-32 (IEEE 802.3), as ZIP and PNG use. */
|
|
22
|
+
export function crc32(data) {
|
|
23
|
+
const lookup = table();
|
|
24
|
+
let crc = 0xffffffff;
|
|
25
|
+
for (let index = 0; index < data.length; index += 1) {
|
|
26
|
+
crc = lookup[(crc ^ data[index]) & 0xff] ^ (crc >>> 8);
|
|
27
|
+
}
|
|
28
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
29
|
+
}
|
|
30
|
+
/** Refuse empty, absolute, backslashed, dot-segment and control-character paths (no traversal on extract). */
|
|
31
|
+
export function assertZipPath(path) {
|
|
32
|
+
if (typeof path !== 'string' ||
|
|
33
|
+
path.length === 0 ||
|
|
34
|
+
path.startsWith('/') ||
|
|
35
|
+
path.includes('\\') ||
|
|
36
|
+
path.split('/').some((segment) => segment === '' || segment === '.' || segment === '..') ||
|
|
37
|
+
[...path].some((character) => (character.codePointAt(0) ?? 0) < 0x20)) {
|
|
38
|
+
throw new TypeError(`Unsafe ZIP entry path: ${JSON.stringify(path)}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function prepare(entries) {
|
|
42
|
+
if (entries.length > MAX_ENTRIES)
|
|
43
|
+
throw new RangeError('Too many ZIP entries.');
|
|
44
|
+
const encoder = new TextEncoder();
|
|
45
|
+
const seen = new Set();
|
|
46
|
+
const raw = [];
|
|
47
|
+
const prepared = entries.map((entry) => {
|
|
48
|
+
assertZipPath(entry.path);
|
|
49
|
+
if (seen.has(entry.path))
|
|
50
|
+
throw new TypeError(`Duplicate ZIP entry: ${entry.path}`);
|
|
51
|
+
seen.add(entry.path);
|
|
52
|
+
const name = encoder.encode(entry.path);
|
|
53
|
+
const data = typeof entry.data === 'string' ? encoder.encode(entry.data) : entry.data;
|
|
54
|
+
if (data.length > MAX_SIZE)
|
|
55
|
+
throw new RangeError(`ZIP entry is too large: ${entry.path}`);
|
|
56
|
+
raw.push(data);
|
|
57
|
+
return { name, data, size: data.length, crc: crc32(data), method: STORED };
|
|
58
|
+
});
|
|
59
|
+
return { prepared, raw };
|
|
60
|
+
}
|
|
61
|
+
function assemble(prepared) {
|
|
62
|
+
const localSize = prepared.reduce((sum, entry) => sum + 30 + entry.name.length + entry.data.length, 0);
|
|
63
|
+
const centralSize = prepared.reduce((sum, entry) => sum + 46 + entry.name.length, 0);
|
|
64
|
+
if (localSize + centralSize > MAX_SIZE)
|
|
65
|
+
throw new RangeError('ZIP archive is too large.');
|
|
66
|
+
const bytes = new Uint8Array(localSize + centralSize + 22);
|
|
67
|
+
const view = new DataView(bytes.buffer);
|
|
68
|
+
let offset = 0;
|
|
69
|
+
const offsets = [];
|
|
70
|
+
for (const entry of prepared) {
|
|
71
|
+
offsets.push(offset);
|
|
72
|
+
view.setUint32(offset, 0x04034b50, true);
|
|
73
|
+
view.setUint16(offset + 4, 20, true);
|
|
74
|
+
view.setUint16(offset + 6, UTF8_FLAG, true);
|
|
75
|
+
view.setUint16(offset + 8, entry.method, true);
|
|
76
|
+
view.setUint16(offset + 10, DOS_TIME, true);
|
|
77
|
+
view.setUint16(offset + 12, DOS_DATE, true);
|
|
78
|
+
view.setUint32(offset + 14, entry.crc, true);
|
|
79
|
+
view.setUint32(offset + 18, entry.data.length, true);
|
|
80
|
+
view.setUint32(offset + 22, entry.size, true);
|
|
81
|
+
view.setUint16(offset + 26, entry.name.length, true);
|
|
82
|
+
view.setUint16(offset + 28, 0, true);
|
|
83
|
+
bytes.set(entry.name, offset + 30);
|
|
84
|
+
bytes.set(entry.data, offset + 30 + entry.name.length);
|
|
85
|
+
offset += 30 + entry.name.length + entry.data.length;
|
|
86
|
+
}
|
|
87
|
+
const centralStart = offset;
|
|
88
|
+
prepared.forEach((entry, index) => {
|
|
89
|
+
view.setUint32(offset, 0x02014b50, true);
|
|
90
|
+
view.setUint16(offset + 4, 20, true);
|
|
91
|
+
view.setUint16(offset + 6, 20, true);
|
|
92
|
+
view.setUint16(offset + 8, UTF8_FLAG, true);
|
|
93
|
+
view.setUint16(offset + 10, entry.method, true);
|
|
94
|
+
view.setUint16(offset + 12, DOS_TIME, true);
|
|
95
|
+
view.setUint16(offset + 14, DOS_DATE, true);
|
|
96
|
+
view.setUint32(offset + 16, entry.crc, true);
|
|
97
|
+
view.setUint32(offset + 20, entry.data.length, true);
|
|
98
|
+
view.setUint32(offset + 24, entry.size, true);
|
|
99
|
+
view.setUint16(offset + 28, entry.name.length, true);
|
|
100
|
+
view.setUint16(offset + 30, 0, true);
|
|
101
|
+
view.setUint16(offset + 32, 0, true);
|
|
102
|
+
view.setUint16(offset + 34, 0, true);
|
|
103
|
+
view.setUint16(offset + 36, 0, true);
|
|
104
|
+
view.setUint32(offset + 38, 0, true);
|
|
105
|
+
view.setUint32(offset + 42, offsets[index], true);
|
|
106
|
+
bytes.set(entry.name, offset + 46);
|
|
107
|
+
offset += 46 + entry.name.length;
|
|
108
|
+
});
|
|
109
|
+
view.setUint32(offset, 0x06054b50, true);
|
|
110
|
+
view.setUint16(offset + 4, 0, true);
|
|
111
|
+
view.setUint16(offset + 6, 0, true);
|
|
112
|
+
view.setUint16(offset + 8, prepared.length, true);
|
|
113
|
+
view.setUint16(offset + 10, prepared.length, true);
|
|
114
|
+
view.setUint32(offset + 12, offset - centralStart, true);
|
|
115
|
+
view.setUint32(offset + 16, centralStart, true);
|
|
116
|
+
view.setUint16(offset + 20, 0, true);
|
|
117
|
+
return bytes;
|
|
118
|
+
}
|
|
119
|
+
/** A stored (uncompressed) ZIP, synchronously. */
|
|
120
|
+
export function writeZip(entries) {
|
|
121
|
+
return assemble(prepare(entries).prepared);
|
|
122
|
+
}
|
|
123
|
+
/** True when the platform has `CompressionStream` with raw deflate. */
|
|
124
|
+
export function canCompress(format = 'deflate-raw') {
|
|
125
|
+
const Ctor = globalThis.CompressionStream;
|
|
126
|
+
if (typeof Ctor !== 'function')
|
|
127
|
+
return false;
|
|
128
|
+
try {
|
|
129
|
+
new Ctor(format);
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Compress bytes with the platform `CompressionStream` (`deflate` is the
|
|
138
|
+
* zlib wrapper PDF's FlateDecode reads; `deflate-raw` is what ZIP stores),
|
|
139
|
+
* or `null` when the platform has no such stream.
|
|
140
|
+
*/
|
|
141
|
+
export async function compressBytes(data, format) {
|
|
142
|
+
const Ctor = globalThis.CompressionStream;
|
|
143
|
+
if (typeof Ctor !== 'function')
|
|
144
|
+
return null;
|
|
145
|
+
let stream;
|
|
146
|
+
try {
|
|
147
|
+
stream = new Ctor(format);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
const writer = stream.writable.getWriter();
|
|
153
|
+
// Write and close without awaiting: the readable side drains the stream.
|
|
154
|
+
writer.write(data).catch(() => { });
|
|
155
|
+
writer.close().catch(() => { });
|
|
156
|
+
const reader = stream.readable.getReader();
|
|
157
|
+
const chunks = [];
|
|
158
|
+
let total = 0;
|
|
159
|
+
for (;;) {
|
|
160
|
+
const { done, value } = await reader.read();
|
|
161
|
+
if (done)
|
|
162
|
+
break;
|
|
163
|
+
chunks.push(value);
|
|
164
|
+
total += value.length;
|
|
165
|
+
}
|
|
166
|
+
const out = new Uint8Array(total);
|
|
167
|
+
let offset = 0;
|
|
168
|
+
for (const chunk of chunks) {
|
|
169
|
+
out.set(chunk, offset);
|
|
170
|
+
offset += chunk.length;
|
|
171
|
+
}
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
/** A ZIP whose entries are deflated where the platform can and where it makes them smaller. */
|
|
175
|
+
export async function writeZipAsync(entries, options = {}) {
|
|
176
|
+
const { prepared, raw } = prepare(entries);
|
|
177
|
+
if (options.compress !== false && canCompress('deflate-raw')) {
|
|
178
|
+
for (let index = 0; index < prepared.length; index += 1) {
|
|
179
|
+
if (entries[index]?.compress === false)
|
|
180
|
+
continue;
|
|
181
|
+
const entry = prepared[index];
|
|
182
|
+
const packed = await compressBytes(raw[index], 'deflate-raw');
|
|
183
|
+
if (packed && packed.length < entry.data.length) {
|
|
184
|
+
entry.data = packed;
|
|
185
|
+
entry.method = DEFLATED;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return assemble(prepared);
|
|
190
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@texuli/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Texels: framework-free behavior and policy that every Texuli component is built from.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"svelte",
|
|
@@ -41,6 +41,9 @@
|
|
|
41
41
|
"./keyboard": "./dist/keyboard/index.js",
|
|
42
42
|
"./layer-stack": "./dist/layer-stack/index.js",
|
|
43
43
|
"./lazy": "./dist/lazy/index.js",
|
|
44
|
+
"./markup": "./dist/markup/index.js",
|
|
45
|
+
"./motion": "./dist/motion/index.js",
|
|
46
|
+
"./motion/spring": "./dist/motion/spring.js",
|
|
44
47
|
"./overlay": "./dist/overlay/index.js",
|
|
45
48
|
"./overlay-core": "./dist/overlay/core-entry.js",
|
|
46
49
|
"./portal": "./dist/portal/index.js",
|
|
@@ -50,7 +53,8 @@
|
|
|
50
53
|
"./roving": "./dist/roving/index.js",
|
|
51
54
|
"./scroll-lock": "./dist/scroll-lock/scroll-lock.js",
|
|
52
55
|
"./tabbable": "./dist/tabbable/index.js",
|
|
53
|
-
"./url-policy": "./dist/url-policy/index.js"
|
|
56
|
+
"./url-policy": "./dist/url-policy/index.js",
|
|
57
|
+
"./zip": "./dist/zip/index.js"
|
|
54
58
|
},
|
|
55
59
|
"files": [
|
|
56
60
|
"dist"
|