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
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* Undo / redo (opts.undo) — a debounced history of snapshots, scoped to a hovered or focused panel so it doesn't hijack
|
|
2
|
+
* the page's own undo. Its own module, so the history can be tested without a panel (test/undo.test.mjs). */
|
|
3
|
+
import { hasOwn, valueChanged, activeIn } from "./shared.js";
|
|
4
|
+
import type { Snapshot } from "./panel.js";
|
|
5
|
+
|
|
6
|
+
/** A panel's history: `snapshot` reads its values, `applySnapshot` writes them back, `watch` subscribes to every change
|
|
7
|
+
* (the silent ones too), and ⌘Z belongs to `panel` while it's hovered or focused, outside an editable field.
|
|
8
|
+
* Positional, as a context object's keys would survive minification in the core. */
|
|
9
|
+
export const createUndo = (
|
|
10
|
+
panel: HTMLElement,
|
|
11
|
+
snapshot: () => Snapshot,
|
|
12
|
+
applySnapshot: (snap: Snapshot) => void,
|
|
13
|
+
atPath: (obj: Snapshot | null, path: string[]) => unknown,
|
|
14
|
+
inEditable: (t: Element | null) => boolean,
|
|
15
|
+
watch: (fn: () => void) => void,
|
|
16
|
+
) => {
|
|
17
|
+
// Bounded: each step is a deep clone of every value.
|
|
18
|
+
const HIST_MAX = 200;
|
|
19
|
+
let history: Snapshot[] = [],
|
|
20
|
+
histIdx = 0,
|
|
21
|
+
applyingHistory = false,
|
|
22
|
+
histTimer = 0;
|
|
23
|
+
// Walk a new step beside the one before it: a string that didn't change takes the earlier step's copy, so an image's
|
|
24
|
+
// data URL is held once across history, not once a step. Strings only, never objects, so no step can edit another.
|
|
25
|
+
// True when nothing changed, which spares serializing both steps to compare them.
|
|
26
|
+
// (Snapshots are JSON: own keys, no undefined. A key b lacks reads undefined or an inherited function, and never
|
|
27
|
+
// matches.)
|
|
28
|
+
const share = (a: any, b: any): boolean => {
|
|
29
|
+
if (a === b) return true;
|
|
30
|
+
if (!a || !b || typeof a != "object" || typeof b != "object" || Array.isArray(a) != Array.isArray(b)) return false;
|
|
31
|
+
let same = Object.keys(a).length == Object.keys(b).length;
|
|
32
|
+
for (const k in a)
|
|
33
|
+
if (a[k] === b[k]) a[k] = b[k];
|
|
34
|
+
else if (!share(a[k], b[k])) same = false;
|
|
35
|
+
return same;
|
|
36
|
+
};
|
|
37
|
+
const commit = () => {
|
|
38
|
+
histTimer = 0;
|
|
39
|
+
const snap = snapshot();
|
|
40
|
+
if (share(snap, history[histIdx])) return; // unchanged
|
|
41
|
+
history = history.slice(0, histIdx + 1);
|
|
42
|
+
history.push(snap); // a new edit drops the redo branch
|
|
43
|
+
if (history.length > HIST_MAX) history = history.slice(history.length - HIST_MAX); // oldest steps age out
|
|
44
|
+
histIdx = history.length - 1;
|
|
45
|
+
};
|
|
46
|
+
const record = () => {
|
|
47
|
+
if (applyingHistory) return;
|
|
48
|
+
clearTimeout(histTimer);
|
|
49
|
+
histTimer = setTimeout(commit, 350);
|
|
50
|
+
};
|
|
51
|
+
// so ⌘Z right after a change still undoes that change
|
|
52
|
+
const flush = () => {
|
|
53
|
+
if (histTimer) {
|
|
54
|
+
clearTimeout(histTimer);
|
|
55
|
+
commit();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
watch(record);
|
|
59
|
+
const restore = (idx: number) => {
|
|
60
|
+
applyingHistory = true;
|
|
61
|
+
applySnapshot(history[idx]);
|
|
62
|
+
applyingHistory = false;
|
|
63
|
+
histIdx = idx;
|
|
64
|
+
};
|
|
65
|
+
const undo = () => {
|
|
66
|
+
flush();
|
|
67
|
+
if (histIdx > 0) restore(histIdx - 1);
|
|
68
|
+
};
|
|
69
|
+
const redo = () => {
|
|
70
|
+
flush();
|
|
71
|
+
if (histIdx < history.length - 1) restore(histIdx + 1);
|
|
72
|
+
};
|
|
73
|
+
const focused = () => panel.matches(":hover") || panel.contains(activeIn(panel));
|
|
74
|
+
const onKey = (e: KeyboardEvent) => {
|
|
75
|
+
// the path: a shadow host retargets e.target
|
|
76
|
+
if (!focused() || !(e.metaKey || e.ctrlKey) || inEditable(e.composedPath()[0] as Element)) return;
|
|
77
|
+
const k = e.key.toLowerCase();
|
|
78
|
+
if (k === "z") {
|
|
79
|
+
e.preventDefault();
|
|
80
|
+
e.shiftKey ? redo() : undo();
|
|
81
|
+
} else if (k === "y") {
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
redo();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
// patch: a late restore (an image the store just answered for) goes into every step that still held what its row
|
|
87
|
+
// held, so it isn't a step of its own, and ⌘Z neither takes it back out nor folds a pending edit into the base.
|
|
88
|
+
const patch = (path: string[], held: unknown, v: unknown) => {
|
|
89
|
+
const k = path[path.length - 1],
|
|
90
|
+
h = JSON.parse(JSON.stringify(held ?? null)),
|
|
91
|
+
nv = JSON.parse(JSON.stringify(v ?? null));
|
|
92
|
+
for (const step of history) {
|
|
93
|
+
const o: any = atPath(step, path.slice(0, -1));
|
|
94
|
+
if (o && typeof o === "object" && hasOwn(o, k) && !valueChanged(o[k], h)) o[k] = nv;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
// the base step: the panel as built and restored
|
|
98
|
+
const arm = () => {
|
|
99
|
+
history = [snapshot()];
|
|
100
|
+
histIdx = 0;
|
|
101
|
+
};
|
|
102
|
+
return { undo, redo, onKey, flush, arm, patch };
|
|
103
|
+
};
|
|
104
|
+
export type Undo = ReturnType<typeof createUndo>;
|