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
|
@@ -1,99 +1,204 @@
|
|
|
1
1
|
// ── Cubic bezier — interactive easing-curve editor. Lazy.
|
|
2
|
-
import { el, btn, txt, clamp, onReady, onLive, registerControl } from "../shared.js";
|
|
2
|
+
import { el, btn, txt, clamp, onReady, onLive, registerControl, words } from "../shared.js";
|
|
3
3
|
import { dragGesture, numField, svgEl, arrowStep } from "../heavy.js";
|
|
4
|
+
import { parseEasing } from "../easing.js";
|
|
4
5
|
import type { OnChange, Built } from "../shared.js";
|
|
5
6
|
import type { Meta } from "../schema.js";
|
|
6
7
|
import type { Control } from "../types.js";
|
|
7
8
|
|
|
8
9
|
function createBezier(meta: Meta, onChange: OnChange): Control {
|
|
10
|
+
const tr = words();
|
|
9
11
|
const DEF = [0.25, 0.1, 0.25, 1];
|
|
10
|
-
// x must stay 0–1 for a valid cubic-bezier(); y may be anything in CSS, and −1–2 holds the overshoot curves people
|
|
11
|
-
// for (easeOutBack's 1.56, easeInOutBack's −0.6 and 1.6), which a −0.25–1.25 clamp flattened without a word.
|
|
12
|
-
const YMIN = -1,
|
|
12
|
+
// x must stay 0–1 for a valid cubic-bezier(); y may be anything in CSS, and −1–2 holds the overshoot curves people
|
|
13
|
+
// reach for (easeOutBack's 1.56, easeInOutBack's −0.6 and 1.6), which a −0.25–1.25 clamp flattened without a word.
|
|
14
|
+
const YMIN = -1,
|
|
15
|
+
YMAX = 2,
|
|
16
|
+
PAD = 8;
|
|
13
17
|
// Fit on build as well as in set(), so an authored [1.5, 0, -0.2, 1] can't reach get() as an invalid cubic-bezier().
|
|
14
18
|
const fit = (m: number[]) => m.map((n, i) => clamp(n, i % 2 ? YMIN : 0, i % 2 ? YMAX : 1));
|
|
15
|
-
// The drawn y range: −0.25–1.25, grown to fit the handles. A drag holds it still, so the curve doesn't slide under
|
|
16
|
-
// pointer, and the graph fits again when the drag ends.
|
|
17
|
-
let view = [-0.25, 1.25],
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
// The drawn y range: −0.25–1.25, grown to fit the handles. A drag holds it still, so the curve doesn't slide under
|
|
20
|
+
// the pointer, and the graph fits again when the drag ends.
|
|
21
|
+
let view = [-0.25, 1.25],
|
|
22
|
+
held = false;
|
|
23
|
+
const fitView = () => {
|
|
24
|
+
if (!held) view = [Math.min(-0.25, v[1] - 0.1, v[3] - 0.1), Math.max(1.25, v[1] + 0.1, v[3] + 0.1)];
|
|
25
|
+
};
|
|
26
|
+
// Four numbers, or what CSS writes: a keyword (`ease-in-out`) or `cubic-bezier(…)`. Anything else opens on `ease`.
|
|
27
|
+
// parseEasing reads linear as null
|
|
28
|
+
const read = (x: unknown) =>
|
|
29
|
+
Array.isArray(x) && x.length === 4 ? x.map(Number) : x === "linear" ? [0, 0, 1, 1] : parseEasing(x)?.slice();
|
|
30
|
+
let v: number[] = read(meta.value) || DEF.slice();
|
|
20
31
|
if (v.some((n) => !Number.isFinite(n))) v = DEF.slice(); // a non-finite init would show NaN and a blank curve
|
|
21
32
|
v = fit(v);
|
|
22
33
|
const def = v.slice(); // fitted default; Home on a handle returns to it
|
|
23
34
|
|
|
24
|
-
const root = el("div", "
|
|
25
|
-
if (meta.label) root.append(txt("div", "
|
|
26
|
-
const graph = el("div", "
|
|
27
|
-
const svg = svgEl("svg", "
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
35
|
+
const root = el("div", "twk-bezier");
|
|
36
|
+
if (meta.label) root.append(txt("div", "twk-bezier-label", meta.label)); // a caption; an explicit "" skips it
|
|
37
|
+
const graph = el("div", "twk-bezier-graph");
|
|
38
|
+
const svg = svgEl("svg", "twk-bezier-svg");
|
|
39
|
+
svg.setAttribute("preserveAspectRatio", "none");
|
|
40
|
+
const unitBot = svgEl("line", "twk-bezier-guide"),
|
|
41
|
+
unitTop = svgEl("line", "twk-bezier-guide");
|
|
42
|
+
const diag = svgEl("line", "twk-bezier-diag"),
|
|
43
|
+
line1 = svgEl("line", "twk-bezier-ctl"),
|
|
44
|
+
line2 = svgEl("line", "twk-bezier-ctl");
|
|
45
|
+
const curve = svgEl("path", "twk-bezier-curve");
|
|
31
46
|
svg.append(unitBot, unitTop, diag, line1, line2, curve);
|
|
32
|
-
const h1 = btn("
|
|
33
|
-
|
|
47
|
+
const h1 = btn("twk-bezier-handle");
|
|
48
|
+
h1.setAttribute("aria-label", tr("controlPoint", "Control point {n}", { n: 1 }));
|
|
49
|
+
const h2 = btn("twk-bezier-handle");
|
|
50
|
+
h2.setAttribute("aria-label", tr("controlPoint", "Control point {n}", { n: 2 }));
|
|
34
51
|
graph.append(svg, h1, h2);
|
|
35
|
-
const fields = el("div", "
|
|
52
|
+
const fields = el("div", "twk-fields twk-bezier-fields");
|
|
36
53
|
root.append(graph, fields);
|
|
37
54
|
|
|
38
|
-
let W = 0,
|
|
55
|
+
let W = 0,
|
|
56
|
+
H = 0;
|
|
39
57
|
const xPx = (x: number) => PAD + x * (W - 2 * PAD);
|
|
40
|
-
const yPx = (y: number) =>
|
|
41
|
-
const setLine = (ln: Built<SVGLineElement>, ax: number, ay: number, bx: number, by: number) => {
|
|
58
|
+
const yPx = (y: number) => H - PAD - ((y - view[0]) / (view[1] - view[0])) * (H - 2 * PAD);
|
|
59
|
+
const setLine = (ln: Built<SVGLineElement>, ax: number, ay: number, bx: number, by: number) => {
|
|
60
|
+
ln.setAttribute("x1", ax);
|
|
61
|
+
ln.setAttribute("y1", ay);
|
|
62
|
+
ln.setAttribute("x2", bx);
|
|
63
|
+
ln.setAttribute("y2", by);
|
|
64
|
+
};
|
|
42
65
|
// The curve and handles only; the fields update separately, so a field edit doesn't re-set itself.
|
|
43
66
|
const drawGraph = () => {
|
|
44
|
-
// No ARIA role fits a 2D point, so the labels carry the coordinates; set before the size guard for hidden tab
|
|
45
|
-
|
|
67
|
+
// No ARIA role fits a 2D point, so the labels carry the coordinates; set before the size guard for hidden tab
|
|
68
|
+
// pages.
|
|
69
|
+
h1.setAttribute("aria-label", tr("controlPointAt", "Control point {n}, x {x}, y {y}", { n: 1, x: v[0], y: v[1] }));
|
|
70
|
+
h2.setAttribute("aria-label", tr("controlPointAt", "Control point {n}, x {x}, y {y}", { n: 2, x: v[2], y: v[3] }));
|
|
46
71
|
// Layout px, not getBoundingClientRect: under an ancestor CSS scale the rect sat the handles off the curve.
|
|
47
|
-
W = graph.offsetWidth;
|
|
72
|
+
W = graph.offsetWidth;
|
|
73
|
+
H = graph.offsetHeight;
|
|
74
|
+
if (W < 2) return;
|
|
48
75
|
fitView();
|
|
49
76
|
svg.setAttribute("viewBox", `0 0 ${W} ${H}`);
|
|
50
77
|
const [x1, y1, x2, y2] = v;
|
|
51
|
-
const ax = xPx(0),
|
|
52
|
-
|
|
53
|
-
|
|
78
|
+
const ax = xPx(0),
|
|
79
|
+
ay = yPx(0),
|
|
80
|
+
bx = xPx(1),
|
|
81
|
+
by = yPx(1),
|
|
82
|
+
p1x = xPx(x1),
|
|
83
|
+
p1y = yPx(y1),
|
|
84
|
+
p2x = xPx(x2),
|
|
85
|
+
p2y = yPx(y2);
|
|
86
|
+
setLine(unitBot, PAD, ay, W - PAD, ay);
|
|
87
|
+
setLine(unitTop, PAD, by, W - PAD, by);
|
|
88
|
+
setLine(diag, ax, ay, bx, by);
|
|
89
|
+
setLine(line1, ax, ay, p1x, p1y);
|
|
90
|
+
setLine(line2, bx, by, p2x, p2y);
|
|
54
91
|
curve.setAttribute("d", `M${ax},${ay} C${p1x},${p1y} ${p2x},${p2y} ${bx},${by}`);
|
|
55
|
-
h1.style.left = p1x + "px";
|
|
92
|
+
h1.style.left = p1x + "px";
|
|
93
|
+
h1.style.top = p1y + "px";
|
|
94
|
+
h2.style.left = p2x + "px";
|
|
95
|
+
h2.style.top = p2y + "px";
|
|
56
96
|
};
|
|
57
97
|
|
|
58
|
-
const SPECS = [
|
|
98
|
+
const SPECS = [
|
|
99
|
+
{ label: "X1", i: 0, lo: 0, hi: 1 },
|
|
100
|
+
{ label: "Y1", i: 1, lo: YMIN, hi: YMAX },
|
|
101
|
+
{ label: "X2", i: 2, lo: 0, hi: 1 },
|
|
102
|
+
{ label: "Y2", i: 3, lo: YMIN, hi: YMAX },
|
|
103
|
+
];
|
|
59
104
|
const flds = SPECS.map((sp) => {
|
|
60
|
-
const fld = numField({ label: sp.label, value: v[sp.i], step: 0.01, min: sp.lo, max: sp.hi }, (val) => {
|
|
61
|
-
|
|
105
|
+
const fld = numField({ label: sp.label, value: v[sp.i], step: 0.01, min: sp.lo, max: sp.hi }, (val) => {
|
|
106
|
+
v[sp.i] = val;
|
|
107
|
+
drawGraph();
|
|
108
|
+
onChange(v.slice());
|
|
109
|
+
});
|
|
110
|
+
fields.append(fld.el);
|
|
111
|
+
return fld;
|
|
62
112
|
});
|
|
63
113
|
const syncFields = () => flds.forEach((fld, k) => fld.set(v[SPECS[k].i]));
|
|
64
114
|
|
|
65
115
|
const drag = (handle: HTMLButtonElement, idx: number) => {
|
|
66
|
-
let rect: DOMRect | null = null,
|
|
116
|
+
let rect: DOMRect | null = null,
|
|
117
|
+
gw = 0,
|
|
118
|
+
gh = 0,
|
|
119
|
+
scale = 1;
|
|
67
120
|
dragGesture(handle, {
|
|
68
|
-
// Divide out any ancestor CSS transform (rect is visual px, offsetWidth layout px); preventDefault killed
|
|
69
|
-
|
|
121
|
+
// Divide out any ancestor CSS transform (rect is visual px, offsetWidth layout px); preventDefault killed
|
|
122
|
+
// click-to-focus.
|
|
123
|
+
onDown: (e) => {
|
|
124
|
+
e.preventDefault();
|
|
125
|
+
rect = graph.getBoundingClientRect();
|
|
126
|
+
gw = graph.offsetWidth || rect.width;
|
|
127
|
+
gh = graph.offsetHeight || rect.height;
|
|
128
|
+
scale = rect.width / gw;
|
|
129
|
+
handle.classList.add("is-dragging");
|
|
130
|
+
handle.focus({ focusVisible: false });
|
|
131
|
+
held = true;
|
|
132
|
+
},
|
|
70
133
|
onMove: (e) => {
|
|
71
|
-
const gx = (e.clientX - rect.left) / scale,
|
|
134
|
+
const gx = (e.clientX - rect.left) / scale,
|
|
135
|
+
gy = (e.clientY - rect.top) / scale;
|
|
72
136
|
const x = clamp((gx - PAD) / (gw - 2 * PAD), 0, 1);
|
|
73
|
-
const y = clamp(view[0] + ((gh - PAD
|
|
74
|
-
v[idx * 2] = +x.toFixed(2);
|
|
137
|
+
const y = clamp(view[0] + ((gh - PAD - gy) / (gh - 2 * PAD)) * (view[1] - view[0]), YMIN, YMAX);
|
|
138
|
+
v[idx * 2] = +x.toFixed(2);
|
|
139
|
+
v[idx * 2 + 1] = +y.toFixed(2);
|
|
140
|
+
drawGraph();
|
|
141
|
+
syncFields();
|
|
142
|
+
onChange(v.slice());
|
|
143
|
+
},
|
|
144
|
+
onEnd: () => {
|
|
145
|
+
rect = null;
|
|
146
|
+
handle.classList.remove("is-dragging");
|
|
147
|
+
held = false;
|
|
148
|
+
drawGraph();
|
|
75
149
|
},
|
|
76
|
-
onEnd: () => { rect = null; handle.classList.remove("is-dragging"); held = false; drawGraph(); },
|
|
77
150
|
});
|
|
78
|
-
// Keyboard: arrows nudge by 0.01 (⇧ = 0.1) on the drag's clamps and grid, Home restores the default, Escape drops
|
|
151
|
+
// Keyboard: arrows nudge by 0.01 (⇧ = 0.1) on the drag's clamps and grid, Home restores the default, Escape drops
|
|
152
|
+
// focus.
|
|
79
153
|
handle.addEventListener("keydown", (e) => {
|
|
80
154
|
if (e.key === "Escape") return handle.blur();
|
|
81
|
-
if (e.key === "Home") {
|
|
155
|
+
if (e.key === "Home") {
|
|
156
|
+
e.preventDefault();
|
|
157
|
+
v = def.slice();
|
|
158
|
+
drawGraph();
|
|
159
|
+
syncFields();
|
|
160
|
+
onChange(v.slice());
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
82
163
|
const [dx, dy] = arrowStep(e);
|
|
83
164
|
if (!dx && !dy) return;
|
|
84
165
|
e.preventDefault();
|
|
85
|
-
const k = e.shiftKey ? 0.1 : 0.01,
|
|
166
|
+
const k = e.shiftKey ? 0.1 : 0.01,
|
|
167
|
+
i = idx * 2;
|
|
86
168
|
if (dx) v[i] = +clamp(v[i] + dx * k, 0, 1).toFixed(2);
|
|
87
169
|
if (dy) v[i + 1] = +clamp(v[i + 1] + dy * k, YMIN, YMAX).toFixed(2);
|
|
88
|
-
drawGraph();
|
|
170
|
+
drawGraph();
|
|
171
|
+
syncFields();
|
|
172
|
+
onChange(v.slice());
|
|
89
173
|
});
|
|
90
174
|
};
|
|
91
|
-
drag(h1, 0);
|
|
175
|
+
drag(h1, 0);
|
|
176
|
+
drag(h2, 1);
|
|
92
177
|
|
|
93
178
|
onReady(drawGraph);
|
|
94
|
-
|
|
95
|
-
|
|
179
|
+
// twk-reflow: a tab page revealing this re-measures it
|
|
180
|
+
onLive(
|
|
181
|
+
root,
|
|
182
|
+
[
|
|
183
|
+
[window, "resize"],
|
|
184
|
+
[window, "twk-reflow"],
|
|
185
|
+
],
|
|
186
|
+
drawGraph,
|
|
187
|
+
);
|
|
188
|
+
// the build's clamp, so get() agrees with the handles
|
|
189
|
+
return {
|
|
190
|
+
el: root,
|
|
191
|
+
set: (nv: unknown) => {
|
|
192
|
+
const m = read(nv);
|
|
193
|
+
if (m) {
|
|
194
|
+
if (m.some((n) => !Number.isFinite(n))) return;
|
|
195
|
+
v = fit(m);
|
|
196
|
+
drawGraph();
|
|
197
|
+
syncFields();
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
get: () => v.slice(),
|
|
201
|
+
};
|
|
96
202
|
}
|
|
97
203
|
|
|
98
204
|
registerControl("cubicbezier", createBezier);
|
|
99
|
-
|