tweakit 0.6.0 → 0.7.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/AGENTS.md +5 -5
- package/README.md +3 -3
- package/dist/tweaks/auto.js +1 -1
- package/dist/tweaks/auto.js.map +1 -1
- package/dist/tweaks/bezier-S2BOXQBM.js +2 -0
- package/dist/tweaks/bezier-S2BOXQBM.js.map +6 -0
- package/dist/tweaks/chunk-3MZAAMC2.js +2 -0
- package/dist/tweaks/chunk-3MZAAMC2.js.map +6 -0
- package/dist/tweaks/chunk-ETB35KFV.js +2 -0
- package/dist/tweaks/chunk-ETB35KFV.js.map +6 -0
- package/dist/tweaks/chunk-YB5GKWZI.js +2 -0
- package/dist/tweaks/chunk-YB5GKWZI.js.map +6 -0
- package/dist/tweaks/clip-A3VI53BK.js +2 -0
- package/dist/tweaks/clip-A3VI53BK.js.map +6 -0
- package/dist/tweaks/color-UGYMAF3W.js +2 -0
- package/dist/tweaks/core.js +1 -1
- package/dist/tweaks/core.js.map +3 -3
- package/dist/tweaks/fold-GY47HIQA.js +2 -0
- package/dist/tweaks/fold-GY47HIQA.js.map +6 -0
- package/dist/tweaks/gradient-BTX25WSH.js +2 -0
- package/dist/tweaks/gradient-BTX25WSH.js.map +6 -0
- package/dist/tweaks/{heavy-CLD7UAVI.js → heavy-NPFIGHRM.js} +2 -2
- package/dist/tweaks/image-HTQQ4WX6.js +4 -0
- package/dist/tweaks/image-HTQQ4WX6.js.map +6 -0
- package/dist/tweaks/{image-store-WRKY2NPU.js → image-store-QD5SMZXG.js} +1 -1
- package/dist/tweaks/image-store-QD5SMZXG.js.map +6 -0
- package/dist/tweaks/interval-BHPI4LRN.js +2 -0
- package/dist/tweaks/interval-BHPI4LRN.js.map +6 -0
- package/dist/tweaks/markup-QM53TQJZ.js +2 -0
- package/dist/tweaks/markup-QM53TQJZ.js.map +6 -0
- package/dist/tweaks/monitor-722WIYGW.js +3 -0
- package/dist/tweaks/monitor-722WIYGW.js.map +6 -0
- package/dist/tweaks/motion-HMCZK6HJ.js +2 -0
- package/dist/tweaks/motion-HMCZK6HJ.js.map +6 -0
- package/dist/tweaks/plot-D3NQ6XNN.js +3 -0
- package/dist/tweaks/plot-D3NQ6XNN.js.map +6 -0
- package/dist/tweaks/point-XDXKMDXH.js +2 -0
- package/dist/tweaks/point-XDXKMDXH.js.map +6 -0
- package/dist/tweaks/presets-EUWNSCUW.js +2 -0
- package/dist/tweaks/presets-EUWNSCUW.js.map +6 -0
- package/dist/tweaks/shadow-AM7VSRNS.js +2 -0
- package/dist/tweaks/shadow-AM7VSRNS.js.map +6 -0
- package/dist/tweaks/shadow-root-RYUV3AGS.js +3 -0
- package/dist/tweaks/shadow-root-RYUV3AGS.js.map +6 -0
- package/dist/tweaks/sides-JWIURDA4.js +2 -0
- package/dist/tweaks/sides-JWIURDA4.js.map +6 -0
- package/dist/tweaks/spring-BF5GBTPM.js +2 -0
- package/dist/tweaks/spring-BF5GBTPM.js.map +6 -0
- package/dist/tweaks/tabs-PRVUUZXZ.js +2 -0
- package/dist/tweaks/tabs-PRVUUZXZ.js.map +6 -0
- package/dist/tweaks.css +1 -1
- package/dist/tweaks.js +5 -4
- package/dist/tweaks.js.map +3 -3
- package/dist/types/tweaks/enhance.d.ts +3 -2
- package/dist/types/tweaks/types.d.ts +278 -72
- package/package.json +5 -2
- package/src/tweaks/auto.ts +9 -5
- package/src/tweaks/clip.ts +84 -22
- package/src/tweaks/controls/basic.ts +463 -139
- package/src/tweaks/controls/bezier.ts +152 -47
- package/src/tweaks/controls/color.ts +610 -161
- package/src/tweaks/controls/gradient.ts +256 -77
- package/src/tweaks/controls/image.ts +388 -132
- package/src/tweaks/controls/interval.ts +126 -41
- package/src/tweaks/controls/monitor.ts +142 -36
- package/src/tweaks/controls/motion.ts +231 -56
- package/src/tweaks/controls/plot.ts +321 -101
- package/src/tweaks/controls/point.ts +134 -45
- package/src/tweaks/controls/shadow.ts +103 -30
- package/src/tweaks/controls/sides.ts +150 -40
- package/src/tweaks/controls/spring.ts +220 -60
- package/src/tweaks/controls/tabs.ts +39 -18
- package/src/tweaks/core.ts +1 -1
- package/src/tweaks/easing.ts +45 -20
- package/src/tweaks/enhance.ts +21 -6
- package/src/tweaks/feedback.ts +133 -34
- package/src/tweaks/fold.ts +22 -10
- package/src/tweaks/heavy.ts +461 -137
- package/src/tweaks/icons.ts +12 -5
- package/src/tweaks/image-store.ts +131 -43
- package/src/tweaks/lazy.ts +36 -19
- package/src/tweaks/markup.ts +255 -92
- package/src/tweaks/panel.ts +1262 -438
- package/src/tweaks/presets.ts +85 -0
- package/src/tweaks/schema.ts +213 -51
- package/src/tweaks/shadow-root.ts +178 -0
- package/src/tweaks/shared.ts +802 -190
- package/src/tweaks/standalone.ts +120 -30
- package/src/tweaks/types.ts +644 -143
- package/src/tweaks/undo.ts +104 -0
- package/src/tweaks.css +556 -550
- package/src/wide-gamut.ts +473 -125
- package/dist/tweaks/bezier-JFEZMCLP.js +0 -2
- package/dist/tweaks/bezier-JFEZMCLP.js.map +0 -6
- package/dist/tweaks/chunk-6UO4DHBN.js +0 -2
- package/dist/tweaks/chunk-6UO4DHBN.js.map +0 -6
- package/dist/tweaks/chunk-DIQMLBAS.js +0 -2
- package/dist/tweaks/chunk-DIQMLBAS.js.map +0 -6
- package/dist/tweaks/chunk-XE6OUJBG.js +0 -2
- package/dist/tweaks/chunk-XE6OUJBG.js.map +0 -6
- package/dist/tweaks/clip-WW7JYO4X.js +0 -2
- package/dist/tweaks/clip-WW7JYO4X.js.map +0 -6
- package/dist/tweaks/color-YMMFURP6.js +0 -2
- package/dist/tweaks/fold-U6YRZLCJ.js +0 -2
- package/dist/tweaks/fold-U6YRZLCJ.js.map +0 -6
- package/dist/tweaks/gradient-JER7PW4D.js +0 -2
- package/dist/tweaks/gradient-JER7PW4D.js.map +0 -6
- package/dist/tweaks/image-H6QSLGO3.js +0 -4
- package/dist/tweaks/image-H6QSLGO3.js.map +0 -6
- package/dist/tweaks/image-store-WRKY2NPU.js.map +0 -6
- package/dist/tweaks/interval-TEUHQGZN.js +0 -2
- package/dist/tweaks/interval-TEUHQGZN.js.map +0 -6
- package/dist/tweaks/markup-NIBJD6E2.js +0 -2
- package/dist/tweaks/markup-NIBJD6E2.js.map +0 -6
- package/dist/tweaks/monitor-3BY7YCGX.js +0 -3
- package/dist/tweaks/monitor-3BY7YCGX.js.map +0 -6
- package/dist/tweaks/motion-FQPUBKKM.js +0 -2
- package/dist/tweaks/motion-FQPUBKKM.js.map +0 -6
- package/dist/tweaks/plot-2HBNBZSG.js +0 -3
- package/dist/tweaks/plot-2HBNBZSG.js.map +0 -6
- package/dist/tweaks/point-VV6XV3I6.js +0 -2
- package/dist/tweaks/point-VV6XV3I6.js.map +0 -6
- package/dist/tweaks/shadow-5E4E55I2.js +0 -2
- package/dist/tweaks/shadow-5E4E55I2.js.map +0 -6
- package/dist/tweaks/sides-P3STEVYY.js +0 -2
- package/dist/tweaks/sides-P3STEVYY.js.map +0 -6
- package/dist/tweaks/spring-HUVSXNVN.js +0 -2
- package/dist/tweaks/spring-HUVSXNVN.js.map +0 -6
- package/dist/tweaks/tabs-76FW7LQ7.js +0 -2
- package/dist/tweaks/tabs-76FW7LQ7.js.map +0 -6
- /package/dist/tweaks/{color-YMMFURP6.js.map → color-UGYMAF3W.js.map} +0 -0
- /package/dist/tweaks/{heavy-CLD7UAVI.js.map → heavy-NPFIGHRM.js.map} +0 -0
package/src/tweaks/icons.ts
CHANGED
|
@@ -6,14 +6,21 @@
|
|
|
6
6
|
// bright hotspot: each icon is one path. Copy and presets keep separate parts so the hover can
|
|
7
7
|
// move them (tweaks.css), drawn to abut rather than overlap.
|
|
8
8
|
import { icon } from "./shared.js";
|
|
9
|
-
const ICON_COPY = icon(
|
|
10
|
-
|
|
9
|
+
const ICON_COPY = icon(
|
|
10
|
+
'<path class="twk-copy-back" d="m5.5 16.5-.7-.2q-1.5-.6-2.1-2.1-.2-.7-.2-2.7v-2c0-3.3 0-5 1-6s2.7-1 6-1h2c1.4 0 2 0 2.7.2q1.6.5 2.1 2.1l.2.7"/><path class="twk-copy-front" d="M7.5 14.5c0-3.3 0-5 1-6s2.7-1 6-1 5 0 6 1 1 2.7 1 6 0 5-1 6-2.7 1-6 1-5 0-6-1-1-2.7-1-6"/>',
|
|
11
|
+
"twk-toolbar-btn__copy",
|
|
12
|
+
);
|
|
13
|
+
const ICON_CHECK = icon('<path d="m5 14 3.5 3.5L19 6.5"/>', "twk-toolbar-btn__check", 2.4);
|
|
11
14
|
// Reset is Hugeicons' undo, a near-full circle, so the spin on click reads as a turn about the center.
|
|
12
15
|
const ICON_RESET = icon('<path d="M3 12a9 9 0 1 0 9-9 9 9 0 0 0-7.6 4.2M3.3 3l.2 2q0 2.2.6 2.7t2.7.2l2-.2"/>');
|
|
13
16
|
const chevronIcon = (cls: string) => icon('<path d="M18 9s-4.4 6-6 6-6-6-6-6"/>', cls, 2.5);
|
|
14
|
-
const ICON_CHEVRON = chevronIcon("
|
|
15
|
-
const ICON_PRESETS = icon(
|
|
17
|
+
const ICON_CHEVRON = chevronIcon("twk-chevron");
|
|
18
|
+
const ICON_PRESETS = icon(
|
|
19
|
+
'<path d="M20.2 13.5q1.8.8 1.8 1.5 0 .8-2.7 2l-5 2.2Q13 20 12 20q-.7 0-2.4-.8l-4.9-2.3Q2 16 2 15t1.8-1.5"/><path class="twk-layer-top" d="M9.6 4.8Q11.3 4 12 4t2.4.8l4.9 2.3Q22 8 22 9c0 .7-.9 1.1-2.7 2l-5 2.2Q13 14 12 14q-.7 0-2.4-.8l-4.9-2.3Q2 10 2 9c0-.7.9-1.1 2.7-2z"/>',
|
|
20
|
+
);
|
|
16
21
|
const ICON_X = icon('<path d="M18 6 6 18m12 0L6 6"/>', "", 2.2);
|
|
17
|
-
const ICON_INFO = icon(
|
|
22
|
+
const ICON_INFO = icon(
|
|
23
|
+
'<circle cx="12" cy="12" r="10"/><path d="M12 16v-4m-.25-3.75a.25.25 0 0 0 .5 0 .25.25 0 0 0-.5 0"/>',
|
|
24
|
+
);
|
|
18
25
|
|
|
19
26
|
export { ICON_COPY, ICON_CHECK, ICON_RESET, ICON_CHEVRON, ICON_PRESETS, ICON_X, ICON_INFO, chevronIcon };
|
|
@@ -6,34 +6,75 @@
|
|
|
6
6
|
const REF = "tw-image:";
|
|
7
7
|
type Store = IDBObjectStore;
|
|
8
8
|
let db: Promise<IDBDatabase | null> | null = null;
|
|
9
|
-
// An open that never settles (another tab's pending delete or upgrade) reads as unavailable after 3s rather than
|
|
10
|
-
// panel.ready forever. The connection closes for another tab's upgrade or delete, and one the browser drops is
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
9
|
+
// An open that never settles (another tab's pending delete or upgrade) reads as unavailable after 3s rather than
|
|
10
|
+
// holding panel.ready forever. The connection closes for another tab's upgrade or delete, and one the browser drops is
|
|
11
|
+
// reopened.
|
|
12
|
+
const open = () =>
|
|
13
|
+
(db ||= new Promise<IDBDatabase | null>((done) => {
|
|
14
|
+
let late = false;
|
|
15
|
+
const t = setTimeout(() => {
|
|
16
|
+
late = true;
|
|
17
|
+
db = null;
|
|
18
|
+
done(null);
|
|
19
|
+
}, 3000);
|
|
20
|
+
// no indexedDB at all
|
|
21
|
+
try {
|
|
22
|
+
const r = indexedDB.open("tweakit", 1);
|
|
23
|
+
r.onupgradeneeded = () => r.result.createObjectStore("images");
|
|
24
|
+
r.onsuccess = () => {
|
|
25
|
+
const d = r.result;
|
|
26
|
+
clearTimeout(t);
|
|
27
|
+
if (late) {
|
|
28
|
+
d.close();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
d.onversionchange = () => {
|
|
32
|
+
d.close();
|
|
33
|
+
db = null;
|
|
34
|
+
};
|
|
35
|
+
d.onclose = () => {
|
|
36
|
+
db = null;
|
|
37
|
+
};
|
|
38
|
+
done(d);
|
|
39
|
+
};
|
|
40
|
+
r.onerror = () => {
|
|
41
|
+
clearTimeout(t);
|
|
42
|
+
db = null;
|
|
43
|
+
done(null);
|
|
44
|
+
};
|
|
45
|
+
} catch {
|
|
46
|
+
clearTimeout(t);
|
|
47
|
+
done(null);
|
|
48
|
+
}
|
|
49
|
+
}));
|
|
26
50
|
// One transaction; resolves with what `fn` returns once it commits, null if it fails.
|
|
27
|
-
const run = <T>(mode: IDBTransactionMode, fn: (s: Store) => T) =>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
51
|
+
const run = <T>(mode: IDBTransactionMode, fn: (s: Store) => T) =>
|
|
52
|
+
open().then(
|
|
53
|
+
(d) =>
|
|
54
|
+
d &&
|
|
55
|
+
new Promise<T | null>((done) => {
|
|
56
|
+
try {
|
|
57
|
+
const t = d.transaction("images", mode),
|
|
58
|
+
out = fn(t.objectStore("images"));
|
|
59
|
+
t.oncomplete = () => done(out);
|
|
60
|
+
t.onerror = t.onabort = () => done(null);
|
|
61
|
+
} catch {
|
|
62
|
+
done(null);
|
|
63
|
+
}
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
// an array sorts after every string, so [key, []] caps the range
|
|
67
|
+
const range = (key: string) => IDBKeyRange.bound([key], [key, []]);
|
|
32
68
|
|
|
33
69
|
// cyrb53: a 53-bit string hash, plenty to tell one panel's few images apart.
|
|
34
70
|
const hash = (s: string) => {
|
|
35
|
-
let h1 = 0xdeadbeef,
|
|
36
|
-
|
|
71
|
+
let h1 = 0xdeadbeef,
|
|
72
|
+
h2 = 0x41c6ce57;
|
|
73
|
+
for (let i = 0; i < s.length; i++) {
|
|
74
|
+
const c = s.charCodeAt(i);
|
|
75
|
+
h1 = Math.imul(h1 ^ c, 2654435761);
|
|
76
|
+
h2 = Math.imul(h2 ^ c, 1597334677);
|
|
77
|
+
}
|
|
37
78
|
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
|
38
79
|
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
|
39
80
|
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36) + s.length.toString(36);
|
|
@@ -42,22 +83,42 @@ const hash = (s: string) => {
|
|
|
42
83
|
const refFor = (dataUrl: string) => REF + hash(dataUrl);
|
|
43
84
|
|
|
44
85
|
/** Every image stored under `key`, ref → data URL; null when IndexedDB can't be used. */
|
|
45
|
-
const load = (key: string) =>
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
86
|
+
const load = (key: string) =>
|
|
87
|
+
run("readonly", (s) => {
|
|
88
|
+
const out = new Map<string, string>();
|
|
89
|
+
s.openCursor(range(key)).onsuccess = function () {
|
|
90
|
+
const c = this.result;
|
|
91
|
+
if (!c) return;
|
|
92
|
+
if (typeof c.value === "string") out.set(REF + (c.key as string[])[1], c.value);
|
|
93
|
+
c.continue();
|
|
94
|
+
};
|
|
95
|
+
return out;
|
|
96
|
+
});
|
|
50
97
|
/** One image by its ref (a preset another tab saved after this panel loaded); null when it isn't there. */
|
|
51
|
-
const get = (key: string, ref: string) =>
|
|
52
|
-
|
|
98
|
+
const get = (key: string, ref: string) =>
|
|
99
|
+
run("readonly", (s) => {
|
|
100
|
+
const r = s.get([key, ref.slice(REF.length)]);
|
|
101
|
+
return r;
|
|
102
|
+
}).then((r) => (r && typeof r.result === "string" ? r.result : null));
|
|
103
|
+
const put = (key: string, ref: string, dataUrl: string) =>
|
|
104
|
+
run("readwrite", (s) => {
|
|
105
|
+
s.put(dataUrl, [key, ref.slice(REF.length)]);
|
|
106
|
+
return true;
|
|
107
|
+
});
|
|
53
108
|
/** Delete the images under `key` that `refs` name. */
|
|
54
|
-
const prune = (key: string, refs: string[]) =>
|
|
109
|
+
const prune = (key: string, refs: string[]) =>
|
|
110
|
+
run("readwrite", (s) => {
|
|
111
|
+
for (const r of refs) s.delete([key, r.slice(REF.length)]);
|
|
112
|
+
return true;
|
|
113
|
+
});
|
|
55
114
|
|
|
56
|
-
/** Each ref a stored snapshot or preset names, read from its JSON whatever the schema: a renamed field's preset still
|
|
115
|
+
/** Each ref a stored snapshot or preset names, read from its JSON whatever the schema: a renamed field's preset still
|
|
116
|
+
* counts. */
|
|
57
117
|
const refsIn = (v: unknown) => new Set<string>(JSON.stringify(v ?? null).match(/tw-image:[0-9a-z]+/g) || []);
|
|
58
118
|
/** Delete the records under `key` this panel knows (`known`) that nothing in `named` names any more. */
|
|
59
119
|
const pruneUnnamed = (key: string, known: Map<string, string>, named: unknown[]) => {
|
|
60
|
-
const keep = refsIn(named),
|
|
120
|
+
const keep = refsIn(named),
|
|
121
|
+
gone = [...known.keys()].filter((r) => !keep.has(r));
|
|
61
122
|
for (const r of gone) known.delete(r);
|
|
62
123
|
if (gone.length) prune(key, gone);
|
|
63
124
|
};
|
|
@@ -67,13 +128,29 @@ const swapRef = (presets: unknown, ref: string, withText: string) => {
|
|
|
67
128
|
return text.includes(ref) ? JSON.parse(text.split(ref).join(JSON.stringify(withText).slice(1, -1))) : null;
|
|
68
129
|
};
|
|
69
130
|
|
|
70
|
-
/** The store bound to one panel: `known` holds the records it has loaded or written (ref → data URL), `refused` runs
|
|
71
|
-
*
|
|
72
|
-
|
|
73
|
-
|
|
131
|
+
/** The store bound to one panel: `known` holds the records it has loaded or written (ref → data URL), `refused` runs
|
|
132
|
+
* when
|
|
133
|
+
* a write fails with its ref (the panel saves again, that image inline), and the presets pair reads and writes its
|
|
134
|
+
* presets. */
|
|
135
|
+
const bind = (
|
|
136
|
+
key: string,
|
|
137
|
+
known: Map<string, string>,
|
|
138
|
+
refused: (ref: string) => void,
|
|
139
|
+
readPresets: () => unknown,
|
|
140
|
+
writePresets: (v: unknown) => boolean,
|
|
141
|
+
) => {
|
|
142
|
+
const failed = new Set<string>(),
|
|
143
|
+
hashed = new WeakMap<object, [string, string]>();
|
|
74
144
|
// Each row's last data URL and its ref, so a save that didn't touch the image doesn't hash megabytes again.
|
|
75
|
-
const refOf = (row: object, v: string) => {
|
|
76
|
-
|
|
145
|
+
const refOf = (row: object, v: string) => {
|
|
146
|
+
const c = hashed.get(row);
|
|
147
|
+
if (c?.[0] === v) return c[1];
|
|
148
|
+
const r = refFor(v);
|
|
149
|
+
hashed.set(row, [v, r]);
|
|
150
|
+
return r;
|
|
151
|
+
};
|
|
152
|
+
// A record the store refused: a preset that names it takes the data URL inline, or an empty image if storage can't
|
|
153
|
+
// fit it.
|
|
77
154
|
const inlinePresets = (ref: string, v: string) => {
|
|
78
155
|
const inlined = swapRef(readPresets(), ref, v);
|
|
79
156
|
if (!inlined || writePresets(inlined)) return;
|
|
@@ -81,20 +158,31 @@ const bind = (key: string, known: Map<string, string>, refused: (ref: string) =>
|
|
|
81
158
|
console.warn("[tweaks] persist: an image a preset holds didn't fit in storage — the preset keeps the rest");
|
|
82
159
|
};
|
|
83
160
|
return {
|
|
84
|
-
/** The ref `row`'s image saves as, or null to save it inline (the store refused it). Written once, and again
|
|
161
|
+
/** The ref `row`'s image saves as, or null to save it inline (the store refused it). Written once, and again
|
|
162
|
+
* whenever
|
|
85
163
|
* `stored` (what storage holds now) no longer names it: a tab that replaced it may have pruned the record. */
|
|
86
164
|
save(row: object, v: string, stored: unknown) {
|
|
87
165
|
const ref = refOf(row, v);
|
|
88
166
|
if (failed.has(ref)) return null;
|
|
89
167
|
if (!known.has(ref) || !refsIn(stored).has(ref)) {
|
|
90
168
|
known.set(ref, v);
|
|
91
|
-
put(key, ref, v).then((ok) => {
|
|
169
|
+
put(key, ref, v).then((ok) => {
|
|
170
|
+
if (ok) return;
|
|
171
|
+
known.delete(ref);
|
|
172
|
+
failed.add(ref);
|
|
173
|
+
refused(ref);
|
|
174
|
+
inlinePresets(ref, v);
|
|
175
|
+
});
|
|
92
176
|
}
|
|
93
177
|
return ref;
|
|
94
178
|
},
|
|
95
179
|
prune: (named: unknown[]) => pruneUnnamed(key, known, named),
|
|
96
180
|
/** A ref this panel hasn't seen (a preset another tab saved), read from the store. */
|
|
97
|
-
fetch: (ref: string) =>
|
|
181
|
+
fetch: (ref: string) =>
|
|
182
|
+
get(key, ref).then((url) => {
|
|
183
|
+
if (url) known.set(ref, url);
|
|
184
|
+
return url;
|
|
185
|
+
}),
|
|
98
186
|
};
|
|
99
187
|
};
|
|
100
188
|
|
package/src/tweaks/lazy.ts
CHANGED
|
@@ -10,26 +10,43 @@ type MetaNode = Pick<Meta, "type" | "children" | "pages">;
|
|
|
10
10
|
// TW_SPLIT is an esbuild `define`: `false` for the single-file bundle, where single.ts imports
|
|
11
11
|
// every control statically, so this map is empty and esbuild drops the import()s.
|
|
12
12
|
declare const TW_SPLIT: boolean;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
13
|
+
// null-prototype: "constructor" isn't a chunk
|
|
14
|
+
const LAZY_IMPORT: Record<string, () => Promise<unknown>> = Object.assign(
|
|
15
|
+
Object.create(null),
|
|
16
|
+
TW_SPLIT
|
|
17
|
+
? {
|
|
18
|
+
number: () => import("./heavy.js"), // heavy.js registers the Number control itself
|
|
19
|
+
interval: () => import("./controls/interval.js"),
|
|
20
|
+
color: () => import("./controls/color.js"),
|
|
21
|
+
gradient: () => import("./controls/gradient.js"),
|
|
22
|
+
shadow: () => import("./controls/shadow.js"),
|
|
23
|
+
sides: () => import("./controls/sides.js"),
|
|
24
|
+
tabs: () => import("./controls/tabs.js"),
|
|
25
|
+
image: () => import("./controls/image.js"),
|
|
26
|
+
fpsgraph: () => import("./controls/monitor.js"),
|
|
27
|
+
monitor: () => import("./controls/monitor.js"),
|
|
28
|
+
spring: () => import("./controls/spring.js"),
|
|
29
|
+
cubicbezier: () => import("./controls/bezier.js"),
|
|
30
|
+
// motion registers last, so a failed editor chunk leaves it unregistered for the next panel to retry.
|
|
31
|
+
motion: () =>
|
|
32
|
+
Promise.all([import("./controls/bezier.js"), import("./controls/spring.js")]).then(
|
|
33
|
+
() => import("./controls/motion.js"),
|
|
34
|
+
),
|
|
35
|
+
point: () => import("./controls/point.js"),
|
|
36
|
+
plot: () => import("./controls/plot.js"),
|
|
37
|
+
}
|
|
38
|
+
: {},
|
|
39
|
+
);
|
|
31
40
|
const loading: Record<string, Promise<unknown>> = {};
|
|
32
|
-
|
|
41
|
+
// a rejection isn't cached, so a later panel retries
|
|
42
|
+
const ensure = (type: string) =>
|
|
43
|
+
getControl(type) || !LAZY_IMPORT[type]
|
|
44
|
+
? null
|
|
45
|
+
: (loading[type] ||= LAZY_IMPORT[type]().catch((e) => {
|
|
46
|
+
delete loading[type];
|
|
47
|
+
console.error(`[tweaks] control chunk "${type}" failed to load:`, e);
|
|
48
|
+
throw e;
|
|
49
|
+
}));
|
|
33
50
|
const scanTypes = (metas: MetaNode[], set = new Set<string>()) => {
|
|
34
51
|
for (const m of metas) {
|
|
35
52
|
set.add(m.type);
|