tweakit 0.5.2 → 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 +32 -30
- package/README.md +55 -29
- package/THIRD-PARTY-NOTICES.md +0 -1
- package/dist/tweaks/auto.js +2 -0
- package/dist/tweaks/auto.js.map +6 -0
- 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/color-UGYMAF3W.js.map +6 -0
- package/dist/tweaks/core.js +2 -1
- package/dist/tweaks/core.js.map +6 -0
- 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-NPFIGHRM.js +2 -0
- package/dist/tweaks/heavy-NPFIGHRM.js.map +6 -0
- package/dist/tweaks/image-HTQQ4WX6.js +4 -0
- package/dist/tweaks/image-HTQQ4WX6.js.map +6 -0
- package/dist/tweaks/image-store-QD5SMZXG.js +2 -0
- 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 +7 -3
- package/dist/tweaks.js.map +6 -0
- package/dist/types/tweaks/easing.d.ts +8 -11
- package/dist/types/tweaks/enhance.d.ts +3 -2
- package/dist/types/tweaks/panel.d.ts +6 -4
- package/dist/types/tweaks/schema.d.ts +4 -8
- package/dist/types/tweaks/standalone.d.ts +3 -3
- package/dist/types/tweaks/types.d.ts +499 -116
- package/package.json +30 -5
- package/src/tweaks/auto.ts +16 -0
- package/src/tweaks/clip.ts +156 -0
- package/src/tweaks/controls/basic.ts +727 -0
- package/src/tweaks/controls/bezier.ts +204 -0
- package/src/tweaks/controls/color.ts +861 -0
- package/src/tweaks/controls/gradient.ts +419 -0
- package/src/tweaks/controls/image.ts +555 -0
- package/src/tweaks/controls/interval.ts +189 -0
- package/src/tweaks/controls/monitor.ts +211 -0
- package/src/tweaks/controls/motion.ts +316 -0
- package/src/tweaks/controls/plot.ts +440 -0
- package/src/tweaks/controls/point.ts +208 -0
- package/src/tweaks/controls/shadow.ts +156 -0
- package/src/tweaks/controls/sides.ts +196 -0
- package/src/tweaks/controls/spring.ts +308 -0
- package/src/tweaks/controls/tabs.ts +68 -0
- package/src/tweaks/core.ts +9 -0
- package/src/tweaks/easing.ts +118 -0
- package/src/tweaks/enhance.ts +35 -0
- package/src/tweaks/feedback.ts +218 -0
- package/src/tweaks/fold.ts +33 -0
- package/src/tweaks/heavy.ts +626 -0
- package/src/tweaks/icons.ts +26 -0
- package/src/tweaks/image-store.ts +189 -0
- package/src/tweaks/lazy.ts +63 -0
- package/src/tweaks/markup.ts +317 -0
- package/src/tweaks/panel.ts +1693 -0
- package/src/tweaks/presets.ts +85 -0
- package/src/tweaks/schema.ts +351 -0
- package/src/tweaks/shadow-root.ts +178 -0
- package/src/tweaks/shared.ts +1137 -0
- package/src/tweaks/single.ts +22 -0
- package/src/tweaks/standalone.ts +179 -0
- package/src/tweaks/types.ts +1027 -0
- package/src/tweaks/undo.ts +104 -0
- package/src/tweaks.css +965 -0
- package/src/wide-gamut.ts +658 -0
- package/dist/tweaks/bezier-2RABC6LD.js +0 -1
- package/dist/tweaks/chunk-4ATI34PB.js +0 -1
- package/dist/tweaks/chunk-7OSCMZ2J.js +0 -1
- package/dist/tweaks/chunk-W3JNIJ2F.js +0 -1
- package/dist/tweaks/clip-ECGCECEC.js +0 -1
- package/dist/tweaks/colour-2RE3FQ5E.js +0 -1
- package/dist/tweaks/fold-UGN7TXGX.js +0 -1
- package/dist/tweaks/gradient-DB6XTDHO.js +0 -1
- package/dist/tweaks/heavy-PKOMHB3C.js +0 -1
- package/dist/tweaks/image-7MCLBOZ3.js +0 -1
- package/dist/tweaks/interval-L2E4L3AZ.js +0 -1
- package/dist/tweaks/markup-ZJJ6CCWM.js +0 -1
- package/dist/tweaks/monitor-IEK742PG.js +0 -2
- package/dist/tweaks/motion-N5UNVR55.js +0 -1
- package/dist/tweaks/plot-VVTOY3RA.js +0 -2
- package/dist/tweaks/point-YMMHSLO7.js +0 -1
- package/dist/tweaks/shadow-IKYOV3VN.js +0 -1
- package/dist/tweaks/sides-FH227Z54.js +0 -1
- package/dist/tweaks/spring-3PKAFIH7.js +0 -1
- package/dist/tweaks/tabs-BKK5NIIY.js +0 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* Single-file build entry. Statically imports every control so each self-registers
|
|
2
|
+
* into the shared registry on load; with the esbuild define TW_SPLIT=false, core's
|
|
3
|
+
* dynamic-import map is empty, so esbuild inlines the whole kit into one self-contained,
|
|
4
|
+
* synchronous file — a drop-in that needs no bundler. The code-split build uses core.ts
|
|
5
|
+
* directly (TW_SPLIT=true) and loads these controls on demand instead. */
|
|
6
|
+
import "./markup.js"; // registers enhance()'s work, so enhance() stays synchronous here
|
|
7
|
+
import "./heavy.js"; // registers the Number control
|
|
8
|
+
import "./controls/color.js";
|
|
9
|
+
import "./controls/gradient.js";
|
|
10
|
+
import "./controls/shadow.js";
|
|
11
|
+
import "./controls/sides.js";
|
|
12
|
+
import "./controls/interval.js";
|
|
13
|
+
import "./controls/tabs.js";
|
|
14
|
+
import "./controls/image.js";
|
|
15
|
+
import "./controls/monitor.js";
|
|
16
|
+
import "./controls/spring.js";
|
|
17
|
+
import "./controls/bezier.js";
|
|
18
|
+
import "./controls/motion.js";
|
|
19
|
+
import "./controls/point.js";
|
|
20
|
+
import "./controls/plot.js";
|
|
21
|
+
|
|
22
|
+
export * from "./core.js";
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/* Standalone controls — the kit's controls without the panel: mountControl() builds one control
|
|
2
|
+
* into a host of your own, createColorPicker() hands out the color editor surface alone. */
|
|
3
|
+
import { el, getControl, onReady, setDisabled, valueChanged, isolate, using } from "./shared.js";
|
|
4
|
+
import { metaFor, VALUELESS } from "./schema.js";
|
|
5
|
+
import { ensureForMetas } from "./lazy.js";
|
|
6
|
+
import { createControl } from "./controls/basic.js";
|
|
7
|
+
import { addHintMarker } from "./feedback.js";
|
|
8
|
+
import type {
|
|
9
|
+
SchemaValue,
|
|
10
|
+
HeldValue,
|
|
11
|
+
KnownType,
|
|
12
|
+
MountOptions,
|
|
13
|
+
MountedControl,
|
|
14
|
+
ColorPickerOptions,
|
|
15
|
+
ColorPicker,
|
|
16
|
+
ColorMode,
|
|
17
|
+
Control,
|
|
18
|
+
Get,
|
|
19
|
+
} from "./types.js";
|
|
20
|
+
import type { Meta } from "./schema.js";
|
|
21
|
+
import type { PickerBody, PickerOptions } from "./controls/color.js";
|
|
22
|
+
|
|
23
|
+
// Outside a .twk-panel the cascade delivers none of the kit's tokens, so the wrapper carries .twk-portal.
|
|
24
|
+
const scope = (cls: string) => el("div", `${cls} twk-standalone twk-portal`);
|
|
25
|
+
// Run `build` once the lazy module has landed (synchronously when none is missing); the handled fork keeps a failed
|
|
26
|
+
// chunk out of the unhandled-rejection channel.
|
|
27
|
+
const whenLoaded = <H>(metas: Array<Pick<Meta, "type">>, build: () => void, handle: H): Promise<H> => {
|
|
28
|
+
const pend = ensureForMetas(metas);
|
|
29
|
+
if (!pend) {
|
|
30
|
+
build();
|
|
31
|
+
return Promise.resolve(handle);
|
|
32
|
+
}
|
|
33
|
+
const ready = pend.then(build).then(() => handle);
|
|
34
|
+
ready.catch(() => {});
|
|
35
|
+
return ready;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** One control from a schema value, into `host`; a folder or tabs set is tweaks()'s to build. */
|
|
39
|
+
export function mountControl<const V extends HeldValue>(
|
|
40
|
+
host: Element,
|
|
41
|
+
value: V & KnownType<V>,
|
|
42
|
+
opts?: MountOptions,
|
|
43
|
+
): MountedControl;
|
|
44
|
+
export function mountControl(host: Element, value: SchemaValue, opts: MountOptions = {}): MountedControl {
|
|
45
|
+
const key = opts.key ?? "value";
|
|
46
|
+
const meta = metaFor(key, value);
|
|
47
|
+
if (!meta || meta.type === "folder" || meta.type === "tabs")
|
|
48
|
+
throw new TypeError(`[tweaks] mountControl: "${key}" is not a single-control schema value`);
|
|
49
|
+
if (opts.label != null) meta.label = String(opts.label); // the option wins over the derived label; "" = no label
|
|
50
|
+
const valued = !VALUELESS.has(meta.type); // display/action controls carry no value: set/get are inert
|
|
51
|
+
const root = scope("twk-control"); // the control fills it in on ready
|
|
52
|
+
const iso = isolate(root, opts.shadow);
|
|
53
|
+
host.append(iso.box);
|
|
54
|
+
let ctrl: Control | null = null,
|
|
55
|
+
destroyed = false,
|
|
56
|
+
last: unknown = meta.value,
|
|
57
|
+
parked: unknown,
|
|
58
|
+
queued = false;
|
|
59
|
+
// Gated the way the panel gates notify(): a same-value set() stays silent instead of echoing.
|
|
60
|
+
const emit = (v: unknown) => {
|
|
61
|
+
if (!valueChanged(last, v)) return;
|
|
62
|
+
last = v;
|
|
63
|
+
opts.onChange && opts.onChange(v, key);
|
|
64
|
+
};
|
|
65
|
+
const build = () => {
|
|
66
|
+
if (destroyed) return; // destroy() before the chunk landed — nothing to mount
|
|
67
|
+
ctrl = using(opts.strings, () => createControl(meta, valued ? emit : () => {}));
|
|
68
|
+
if (!ctrl) return; // a failed chunk degrades to an empty wrapper
|
|
69
|
+
if (meta.hint) addHintMarker(ctrl.el, meta.hint);
|
|
70
|
+
// Resolved once at mount: with no siblings for a predicate to read, `get` answers undefined.
|
|
71
|
+
const none: Get = () => undefined;
|
|
72
|
+
try {
|
|
73
|
+
if (meta.render && !meta.render(none)) ctrl.el.classList.add("twk-cond-hidden");
|
|
74
|
+
} catch {}
|
|
75
|
+
// each predicate fails on its own
|
|
76
|
+
try {
|
|
77
|
+
const d = typeof meta.disabled === "function" ? meta.disabled(none) : meta.disabled;
|
|
78
|
+
if (d) setDisabled(ctrl.el, true);
|
|
79
|
+
} catch {}
|
|
80
|
+
root.append(ctrl.el);
|
|
81
|
+
if (!valued) return;
|
|
82
|
+
last = ctrl.get(); // the form the control opened on
|
|
83
|
+
// a set() from the lazy window applies and announces now
|
|
84
|
+
if (queued) {
|
|
85
|
+
ctrl.set(parked);
|
|
86
|
+
emit(ctrl.get());
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const handle: MountedControl = {
|
|
90
|
+
el: iso.box,
|
|
91
|
+
set: (v) => {
|
|
92
|
+
if (destroyed || !valued) return;
|
|
93
|
+
if (ctrl) {
|
|
94
|
+
ctrl.set(v);
|
|
95
|
+
emit(ctrl.get());
|
|
96
|
+
} else {
|
|
97
|
+
parked = v;
|
|
98
|
+
queued = true;
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
get: () => (!valued ? undefined : ctrl ? ctrl.get() : queued ? parked : meta.value),
|
|
102
|
+
// onLive listeners release on their next event by this mark
|
|
103
|
+
destroy: () => {
|
|
104
|
+
destroyed = true;
|
|
105
|
+
if (ctrl && typeof ctrl.destroy === "function") ctrl.destroy();
|
|
106
|
+
root.dataset.twkDestroyed = "";
|
|
107
|
+
root.remove();
|
|
108
|
+
iso.end();
|
|
109
|
+
},
|
|
110
|
+
ready: null,
|
|
111
|
+
};
|
|
112
|
+
handle.ready = whenLoaded([meta], build, handle);
|
|
113
|
+
// the handled fork whenLoaded keeps
|
|
114
|
+
if (iso.dressed) (handle.ready = Promise.all([handle.ready, iso.dressed]).then(() => handle)).catch(() => {});
|
|
115
|
+
return handle;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** The color editor surface alone, for a host page that brings its own swatch. */
|
|
119
|
+
export function createColorPicker(opts: ColorPickerOptions = {}): ColorPicker {
|
|
120
|
+
const root = scope("twk-color-picker"),
|
|
121
|
+
iso = isolate(root, opts.shadow);
|
|
122
|
+
let body: PickerBody | null = null,
|
|
123
|
+
destroyed = false,
|
|
124
|
+
last = opts.value,
|
|
125
|
+
parked: string,
|
|
126
|
+
queued = false,
|
|
127
|
+
parkedMode: ColorMode = null;
|
|
128
|
+
const emit = (v: string) => {
|
|
129
|
+
if (!valueChanged(last, v)) return;
|
|
130
|
+
last = v;
|
|
131
|
+
opts.onChange && opts.onChange(v);
|
|
132
|
+
};
|
|
133
|
+
const build = () => {
|
|
134
|
+
if (destroyed) return;
|
|
135
|
+
// registered by the color module beside its control
|
|
136
|
+
const make = getControl<PickerBody, PickerOptions>("colorpicker");
|
|
137
|
+
if (!make) return;
|
|
138
|
+
body = using(opts.strings, () => make({ value: opts.value, mode: opts.mode }, emit));
|
|
139
|
+
last = body.get();
|
|
140
|
+
root.append(body.el);
|
|
141
|
+
if (parkedMode) body.setMode(parkedMode);
|
|
142
|
+
if (queued) {
|
|
143
|
+
body.set(parked);
|
|
144
|
+
emit(body.get());
|
|
145
|
+
}
|
|
146
|
+
onReady(body.reflow); // next frame: the thumbs need a real box
|
|
147
|
+
};
|
|
148
|
+
const picker: ColorPicker = {
|
|
149
|
+
el: iso.box,
|
|
150
|
+
set: (v) => {
|
|
151
|
+
if (destroyed) return;
|
|
152
|
+
if (body) {
|
|
153
|
+
body.set(v);
|
|
154
|
+
emit(body.get());
|
|
155
|
+
} else {
|
|
156
|
+
parked = v;
|
|
157
|
+
queued = true;
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
get: () => (body ? body.get() : queued ? parked : opts.value),
|
|
161
|
+
mode: () => (body ? body.mode() : parkedMode || opts.mode || "oklch"),
|
|
162
|
+
setMode: (m) => {
|
|
163
|
+
if (body) body.setMode(m);
|
|
164
|
+
else parkedMode = m;
|
|
165
|
+
},
|
|
166
|
+
reflow: () => {
|
|
167
|
+
if (body) body.reflow();
|
|
168
|
+
},
|
|
169
|
+
destroy: () => {
|
|
170
|
+
destroyed = true;
|
|
171
|
+
root.remove();
|
|
172
|
+
iso.end();
|
|
173
|
+
},
|
|
174
|
+
ready: null,
|
|
175
|
+
};
|
|
176
|
+
picker.ready = whenLoaded([{ type: "color" }], build, picker);
|
|
177
|
+
if (iso.dressed) (picker.ready = Promise.all([picker.ready, iso.dressed]).then(() => picker)).catch(() => {});
|
|
178
|
+
return picker;
|
|
179
|
+
}
|