tweakit 0.5.2 → 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/AGENTS.md +31 -29
- 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-JFEZMCLP.js +2 -0
- package/dist/tweaks/bezier-JFEZMCLP.js.map +6 -0
- package/dist/tweaks/chunk-6UO4DHBN.js +2 -0
- package/dist/tweaks/chunk-6UO4DHBN.js.map +6 -0
- package/dist/tweaks/chunk-DIQMLBAS.js +2 -0
- package/dist/tweaks/chunk-DIQMLBAS.js.map +6 -0
- package/dist/tweaks/chunk-XE6OUJBG.js +2 -0
- package/dist/tweaks/chunk-XE6OUJBG.js.map +6 -0
- package/dist/tweaks/clip-WW7JYO4X.js +2 -0
- package/dist/tweaks/clip-WW7JYO4X.js.map +6 -0
- package/dist/tweaks/color-YMMFURP6.js +2 -0
- package/dist/tweaks/color-YMMFURP6.js.map +6 -0
- package/dist/tweaks/core.js +2 -1
- package/dist/tweaks/core.js.map +6 -0
- package/dist/tweaks/{fold-UGN7TXGX.js → fold-U6YRZLCJ.js} +2 -1
- package/dist/tweaks/fold-U6YRZLCJ.js.map +6 -0
- package/dist/tweaks/gradient-JER7PW4D.js +2 -0
- package/dist/tweaks/gradient-JER7PW4D.js.map +6 -0
- package/dist/tweaks/heavy-CLD7UAVI.js +2 -0
- package/dist/tweaks/heavy-CLD7UAVI.js.map +6 -0
- package/dist/tweaks/image-H6QSLGO3.js +4 -0
- package/dist/tweaks/image-H6QSLGO3.js.map +6 -0
- package/dist/tweaks/image-store-WRKY2NPU.js +2 -0
- package/dist/tweaks/image-store-WRKY2NPU.js.map +6 -0
- package/dist/tweaks/interval-TEUHQGZN.js +2 -0
- package/dist/tweaks/interval-TEUHQGZN.js.map +6 -0
- package/dist/tweaks/markup-NIBJD6E2.js +2 -0
- package/dist/tweaks/markup-NIBJD6E2.js.map +6 -0
- package/dist/tweaks/monitor-3BY7YCGX.js +3 -0
- package/dist/tweaks/monitor-3BY7YCGX.js.map +6 -0
- package/dist/tweaks/motion-FQPUBKKM.js +2 -0
- package/dist/tweaks/motion-FQPUBKKM.js.map +6 -0
- package/dist/tweaks/plot-2HBNBZSG.js +3 -0
- package/dist/tweaks/plot-2HBNBZSG.js.map +6 -0
- package/dist/tweaks/point-VV6XV3I6.js +2 -0
- package/dist/tweaks/point-VV6XV3I6.js.map +6 -0
- package/dist/tweaks/shadow-5E4E55I2.js +2 -0
- package/dist/tweaks/shadow-5E4E55I2.js.map +6 -0
- package/dist/tweaks/sides-P3STEVYY.js +2 -0
- package/dist/tweaks/sides-P3STEVYY.js.map +6 -0
- package/dist/tweaks/spring-HUVSXNVN.js +2 -0
- package/dist/tweaks/spring-HUVSXNVN.js.map +6 -0
- package/dist/tweaks/tabs-76FW7LQ7.js +2 -0
- package/dist/tweaks/tabs-76FW7LQ7.js.map +6 -0
- package/dist/tweaks.css +1 -1
- package/dist/tweaks.js +6 -3
- package/dist/tweaks.js.map +6 -0
- package/dist/types/tweaks/easing.d.ts +8 -11
- 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 +278 -101
- package/package.json +27 -5
- package/src/tweaks/auto.ts +12 -0
- package/src/tweaks/clip.ts +94 -0
- package/src/tweaks/controls/basic.ts +403 -0
- package/src/tweaks/controls/bezier.ts +99 -0
- package/src/tweaks/controls/color.ts +412 -0
- package/src/tweaks/controls/gradient.ts +240 -0
- package/src/tweaks/controls/image.ts +299 -0
- package/src/tweaks/controls/interval.ts +104 -0
- package/src/tweaks/controls/monitor.ts +105 -0
- package/src/tweaks/controls/motion.ts +141 -0
- package/src/tweaks/controls/plot.ts +220 -0
- package/src/tweaks/controls/point.ts +119 -0
- package/src/tweaks/controls/shadow.ts +83 -0
- package/src/tweaks/controls/sides.ts +86 -0
- package/src/tweaks/controls/spring.ts +148 -0
- package/src/tweaks/controls/tabs.ts +47 -0
- package/src/tweaks/core.ts +9 -0
- package/src/tweaks/easing.ts +93 -0
- package/src/tweaks/enhance.ts +20 -0
- package/src/tweaks/feedback.ts +119 -0
- package/src/tweaks/fold.ts +21 -0
- package/src/tweaks/heavy.ts +302 -0
- package/src/tweaks/icons.ts +19 -0
- package/src/tweaks/image-store.ts +101 -0
- package/src/tweaks/lazy.ts +46 -0
- package/src/tweaks/markup.ts +154 -0
- package/src/tweaks/panel.ts +869 -0
- package/src/tweaks/schema.ts +189 -0
- package/src/tweaks/shared.ts +525 -0
- package/src/tweaks/single.ts +22 -0
- package/src/tweaks/standalone.ts +89 -0
- package/src/tweaks/types.ts +526 -0
- package/src/tweaks.css +959 -0
- package/src/wide-gamut.ts +310 -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/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
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/** An option for a select / radio grid: a bare string, or `{ value, label }
|
|
2
|
-
export type Option = string | {
|
|
3
|
-
value: string;
|
|
1
|
+
/** An option for a select / radio grid: a bare string or number, or `{ value, label }`; the param is the value as written. */
|
|
2
|
+
export type Option = string | number | {
|
|
3
|
+
value: string | number;
|
|
4
4
|
label?: string;
|
|
5
5
|
color?: string;
|
|
6
6
|
};
|
|
7
|
-
/** A
|
|
7
|
+
/** A color stop in a gradient. */
|
|
8
8
|
export type GradientStop = {
|
|
9
9
|
color: string;
|
|
10
10
|
pos: number;
|
|
@@ -15,10 +15,11 @@ export type GradientStop = {
|
|
|
15
15
|
export type GradientInterpolation = "srgb" | "hsl" | "hwb" | "oklch" | "oklab" | "lch" | "lab" | "display-p3" | "rec2020";
|
|
16
16
|
/** What a sides control accepts: one number for all four; `[vertical, horizontal]`,
|
|
17
17
|
* `[top, horizontal, bottom]` or `[top, right, bottom, left]` (CSS order); a CSS shorthand
|
|
18
|
-
* string like `"
|
|
18
|
+
* string like `"1rem 2rem"` (its unit becomes the control's when `unit` isn't given; mixed
|
|
19
|
+
* units warn and read as px); or any subset of
|
|
19
20
|
* the four as an object. With `corners: true` the four are the corners from top-left round,
|
|
20
21
|
* the same CSS order, under the same keys, and they floor at 0 unless `min` says otherwise. */
|
|
21
|
-
export type SidesInput = number | number[] | string | {
|
|
22
|
+
export type SidesInput = number | readonly number[] | string | {
|
|
22
23
|
top?: number;
|
|
23
24
|
right?: number;
|
|
24
25
|
bottom?: number;
|
|
@@ -33,9 +34,9 @@ export interface SidesValue {
|
|
|
33
34
|
left: number;
|
|
34
35
|
css: string;
|
|
35
36
|
}
|
|
36
|
-
/** What a shadow control accepts — any subset of its fields (px, `color` any
|
|
37
|
+
/** What a shadow control accepts — any subset of its fields (px, `color` any color the kit
|
|
37
38
|
* parses); or, as `value`, a `box-shadow` string: optional `inset`, two to four px lengths,
|
|
38
|
-
* one
|
|
39
|
+
* one color, one layer. */
|
|
39
40
|
export interface ShadowInput {
|
|
40
41
|
inset?: boolean;
|
|
41
42
|
x?: number;
|
|
@@ -45,7 +46,7 @@ export interface ShadowInput {
|
|
|
45
46
|
color?: string;
|
|
46
47
|
}
|
|
47
48
|
/** A shadow control's value — the fields, plus the `box-shadow` CSS they resolve to (`css`),
|
|
48
|
-
* built from the numbers and the picker's own
|
|
49
|
+
* built from the numbers and the picker's own color notation, so `el.style.boxShadow = css`. */
|
|
49
50
|
export interface ShadowValue {
|
|
50
51
|
inset: boolean;
|
|
51
52
|
x: number;
|
|
@@ -60,7 +61,7 @@ export interface ShadowValue {
|
|
|
60
61
|
* the easing's, in ms. Spring keys select the spring mode unless `mode` says otherwise. */
|
|
61
62
|
export interface MotionInput {
|
|
62
63
|
mode?: "easing" | "spring";
|
|
63
|
-
curve?: [number, number, number, number] | string;
|
|
64
|
+
curve?: readonly [number, number, number, number] | string;
|
|
64
65
|
duration?: number;
|
|
65
66
|
stiffness?: number;
|
|
66
67
|
damping?: number;
|
|
@@ -87,7 +88,7 @@ export type MotionValue = {
|
|
|
87
88
|
duration: number;
|
|
88
89
|
easing: string;
|
|
89
90
|
};
|
|
90
|
-
/** How a gradient blends between
|
|
91
|
+
/** How a gradient blends between neighboring stops: `"linear"` (CSS's own straight blend,
|
|
91
92
|
* the default) or a CSS easing — `ease`, `ease-in`, `ease-out`, `ease-in-out`, or any
|
|
92
93
|
* `cubic-bezier(x1, y1, x2, y2)`. No browser eases a gradient natively, so `gradientCss()`
|
|
93
94
|
* samples the curve into stops; template through it rather than by hand. */
|
|
@@ -109,7 +110,7 @@ export interface ControlOptions {
|
|
|
109
110
|
label?: string;
|
|
110
111
|
/** Show/hide this control based on other values. */
|
|
111
112
|
render?: (get: Get) => boolean;
|
|
112
|
-
/**
|
|
113
|
+
/** Gray-out + lock this control (static, or derived from other values). */
|
|
113
114
|
disabled?: boolean | ((get: Get) => boolean);
|
|
114
115
|
/** A tooltip revealed by an ⓘ marker beside the label. */
|
|
115
116
|
hint?: string;
|
|
@@ -147,12 +148,12 @@ export type SchemaObject = {
|
|
|
147
148
|
value?: boolean;
|
|
148
149
|
} | {
|
|
149
150
|
type: "list";
|
|
150
|
-
options: Option[];
|
|
151
|
-
value?: string;
|
|
151
|
+
options: readonly Option[];
|
|
152
|
+
value?: string | number;
|
|
152
153
|
} | {
|
|
153
154
|
type: "radiogrid" | "segmented";
|
|
154
|
-
options: Option[];
|
|
155
|
-
value?: string;
|
|
155
|
+
options: readonly Option[];
|
|
156
|
+
value?: string | number;
|
|
156
157
|
cols?: number;
|
|
157
158
|
} | {
|
|
158
159
|
type: "color";
|
|
@@ -164,7 +165,7 @@ export type SchemaObject = {
|
|
|
164
165
|
placeholder?: string;
|
|
165
166
|
} | {
|
|
166
167
|
type: "interval";
|
|
167
|
-
value?: [number, number];
|
|
168
|
+
value?: readonly [number, number];
|
|
168
169
|
min?: number;
|
|
169
170
|
max?: number;
|
|
170
171
|
step?: number;
|
|
@@ -186,7 +187,7 @@ export type SchemaObject = {
|
|
|
186
187
|
};
|
|
187
188
|
} | {
|
|
188
189
|
type: "cubicbezier";
|
|
189
|
-
value?: [number, number, number, number];
|
|
190
|
+
value?: readonly [number, number, number, number];
|
|
190
191
|
} | ({
|
|
191
192
|
type: "shadow";
|
|
192
193
|
value?: ShadowInput | string;
|
|
@@ -207,7 +208,7 @@ export type SchemaObject = {
|
|
|
207
208
|
value?: MotionInput;
|
|
208
209
|
} & MotionInput) | {
|
|
209
210
|
type: "point";
|
|
210
|
-
components:
|
|
211
|
+
components: ReadonlyArray<{
|
|
211
212
|
key: string;
|
|
212
213
|
label?: string;
|
|
213
214
|
value?: number;
|
|
@@ -215,12 +216,25 @@ export type SchemaObject = {
|
|
|
215
216
|
max?: number;
|
|
216
217
|
step?: number;
|
|
217
218
|
}>;
|
|
219
|
+
value?: {
|
|
220
|
+
readonly [key: string]: number;
|
|
221
|
+
};
|
|
222
|
+
pad?: boolean;
|
|
223
|
+
invertY?: boolean;
|
|
224
|
+
} | {
|
|
225
|
+
type: "point";
|
|
226
|
+
value: {
|
|
227
|
+
readonly [key: string]: number;
|
|
228
|
+
};
|
|
229
|
+
components?: undefined;
|
|
218
230
|
pad?: boolean;
|
|
219
231
|
invertY?: boolean;
|
|
220
232
|
} | {
|
|
221
233
|
type: "gradient";
|
|
222
|
-
value?: GradientValue |
|
|
223
|
-
stops?:
|
|
234
|
+
value?: GradientValue | ReadonlyArray<GradientStop | readonly [string, number]>;
|
|
235
|
+
stops?: ReadonlyArray<GradientStop | readonly [string, number]>;
|
|
236
|
+
interpolation?: GradientInterpolation;
|
|
237
|
+
easing?: GradientEasing;
|
|
224
238
|
} | {
|
|
225
239
|
type: "plot";
|
|
226
240
|
expr?: string;
|
|
@@ -251,7 +265,10 @@ export type SchemaObject = {
|
|
|
251
265
|
value?: string;
|
|
252
266
|
/** Supplied images to pick from, as URLs or `{ value, label }`. The control becomes a row naming the chosen
|
|
253
267
|
* image that opens a pane of tiles with the upload below them, and the param is the chosen URL or the upload's data URL. */
|
|
254
|
-
options?:
|
|
268
|
+
options?: ReadonlyArray<string | {
|
|
269
|
+
value: string;
|
|
270
|
+
label?: string;
|
|
271
|
+
}>;
|
|
255
272
|
/** Tiles per row in the gallery, 1 to 6 (by default one per option for two or three, 2 for one or four, then 3). */
|
|
256
273
|
cols?: number;
|
|
257
274
|
/** The largest upload taken, in bytes (10 MB unless set); a bigger file is refused with a note. */
|
|
@@ -260,7 +277,7 @@ export type SchemaObject = {
|
|
|
260
277
|
* heavier than 1.5 MB is redrawn at its size, so a phone photo can't fill storage (2560 unless set; `false` takes
|
|
261
278
|
* uploads as they are). A JPEG comes out as a JPEG at
|
|
262
279
|
* `quality`; anything else as a PNG when that is 1.5 MB or less (a screenshot, not a photo), else as a JPEG, or a WebP
|
|
263
|
-
* when it has transparency. A GIF, an SVG, a light picture within `fit
|
|
280
|
+
* when it has transparency. A GIF, an SVG, an animated WebP or APNG, a light picture within `fit`, or one the redraw wouldn't make smaller is kept as it is. */
|
|
264
281
|
fit?: number | false;
|
|
265
282
|
/** The JPEG or WebP quality of a shrunk upload, 0 to 1 (0.85 unless set). */
|
|
266
283
|
quality?: number;
|
|
@@ -274,7 +291,7 @@ export type SchemaObject = {
|
|
|
274
291
|
label?: string;
|
|
275
292
|
} | {
|
|
276
293
|
type: "buttongroup";
|
|
277
|
-
buttons: Record<string, () => void> |
|
|
294
|
+
buttons: Record<string, () => void> | ReadonlyArray<{
|
|
278
295
|
label: string;
|
|
279
296
|
action: () => void;
|
|
280
297
|
}>;
|
|
@@ -282,63 +299,214 @@ export type SchemaObject = {
|
|
|
282
299
|
type: "separator";
|
|
283
300
|
} | {
|
|
284
301
|
type: "tabs";
|
|
285
|
-
pages:
|
|
302
|
+
pages: {
|
|
303
|
+
readonly [title: string]: Schema;
|
|
304
|
+
};
|
|
286
305
|
};
|
|
287
306
|
/** A schema value — a shorthand, a verbose `{ type }` object, or a nested folder. */
|
|
288
|
-
export type SchemaValue =
|
|
289
|
-
|
|
307
|
+
export type SchemaValue = SchemaValueOf<SchemaNest>;
|
|
308
|
+
type SchemaValueOf<F> = number | boolean | string | readonly [number] | readonly [number, number] | readonly [number, number, number] | readonly [number, number, number, number] | readonly [readonly [number, number], number, number] | readonly [readonly [number, number], number, number, number] | readonly number[] | readonly (number | readonly number[])[] | readonly Option[] | {
|
|
309
|
+
options: readonly Option[];
|
|
310
|
+
value?: string | number;
|
|
311
|
+
} | {
|
|
312
|
+
action: () => void;
|
|
313
|
+
label?: string;
|
|
314
|
+
} | (SchemaObject & ControlOptions) | F | SchemaFolder;
|
|
315
|
+
/** The object you hand to `tweaks(name, schema, opts?)`. No value is a function, so a verbose
|
|
316
|
+
* form's callbacks (`format`, `fn`) take their parameter types from that form alone. */
|
|
290
317
|
export interface Schema {
|
|
291
|
-
[key: string]: SchemaValue;
|
|
318
|
+
readonly [key: string]: SchemaValue;
|
|
319
|
+
}
|
|
320
|
+
type SchemaNest = Schema & {
|
|
321
|
+
readonly type?: SchemaObject["type"] | Exclude<SchemaValue, string>;
|
|
322
|
+
};
|
|
323
|
+
/** What tweaks() and mountControl() infer from: `Schema` with a folder's `type` left open, since a schema held in a
|
|
324
|
+
* variable widens a verbose form's `type` to `string`; their own check then rules on the names it can still see. */
|
|
325
|
+
export interface HeldSchema {
|
|
326
|
+
readonly [key: string]: HeldValue;
|
|
327
|
+
}
|
|
328
|
+
/** A single value as mountControl() infers it; see `HeldSchema`. */
|
|
329
|
+
export type HeldValue = SchemaValueOf<HeldSchema>;
|
|
330
|
+
/** A nested folder that carries its own `render` / `disabled` predicate or `hint`: chrome, not
|
|
331
|
+
* children. Its index admits the predicate, so it gives up a child named `type`: that sets it
|
|
332
|
+
* apart from a verbose form, whose callbacks would otherwise be typed against the predicate too. */
|
|
333
|
+
export interface SchemaFolder {
|
|
334
|
+
readonly type?: undefined;
|
|
335
|
+
readonly render?: (get: Get) => boolean;
|
|
336
|
+
readonly disabled?: boolean | ((get: Get) => boolean);
|
|
337
|
+
readonly hint?: string;
|
|
338
|
+
readonly [key: string]: SchemaValue | ((get: Get) => boolean) | undefined;
|
|
339
|
+
}
|
|
340
|
+
/** A spring control's value: the physics, plus the time pair and mode when tuned by feel. */
|
|
341
|
+
export interface SpringValue {
|
|
342
|
+
stiffness: number;
|
|
343
|
+
damping: number;
|
|
344
|
+
mass: number;
|
|
345
|
+
visualDuration?: number;
|
|
346
|
+
bounce?: number;
|
|
347
|
+
mode?: "time" | "physics";
|
|
292
348
|
}
|
|
349
|
+
type OptionValue<O> = O extends string | number ? O : O extends {
|
|
350
|
+
readonly value: infer V extends string | number;
|
|
351
|
+
} ? V : never;
|
|
352
|
+
type ChoiceValue<V> = (V extends {
|
|
353
|
+
readonly options: readonly (infer O)[];
|
|
354
|
+
} ? OptionValue<O> : never) | (V extends {
|
|
355
|
+
readonly value: infer D extends string | number;
|
|
356
|
+
} ? D : never);
|
|
357
|
+
type Alnum = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
|
|
358
|
+
type Dashed<S extends string, Acc extends string = "", Run = false> = S extends `${infer C}${infer R}` ? C extends Alnum ? Dashed<R, `${Acc}${C}`, false> : Run extends true ? Dashed<R, Acc, true> : Dashed<R, `${Acc}-`, true> : Acc;
|
|
359
|
+
type TrimDash<S extends string> = S extends `-${infer R}` ? TrimDash<R> : S extends `${infer R}-` ? TrimDash<R> : S;
|
|
360
|
+
/** A tab title's key under `params`: lower-case, each run of other characters a `-`, trimmed
|
|
361
|
+
* (`"Layout & Grid"` → `"layout-grid"`). Two titles that slug alike are told apart at runtime only. */
|
|
362
|
+
export type TabKey<T extends string> = string extends T ? string : TrimDash<Dashed<Lowercase<T>>> extends infer K extends string ? (K extends "" ? "tab" : K) : never;
|
|
363
|
+
type TabClash<P> = true extends {
|
|
364
|
+
[T in keyof P & string]: TabKey<T> extends {
|
|
365
|
+
[U in Exclude<keyof P & string, T>]: TabKey<U>;
|
|
366
|
+
}[Exclude<keyof P & string, T>] ? true : false;
|
|
367
|
+
}[keyof P & string] ? true : false;
|
|
368
|
+
type Valueless = "button" | "buttongroup" | "separator" | "fpsgraph" | "monitor";
|
|
369
|
+
type Hinge = {
|
|
370
|
+
list: "options";
|
|
371
|
+
radiogrid: "options";
|
|
372
|
+
segmented: "options";
|
|
373
|
+
point: "components" | "value";
|
|
374
|
+
tabs: "pages";
|
|
375
|
+
};
|
|
376
|
+
type TypedValue<V> = V extends {
|
|
377
|
+
readonly type: "slider" | "number";
|
|
378
|
+
} ? number : V extends {
|
|
379
|
+
readonly type: "checkbox";
|
|
380
|
+
} ? boolean : V extends {
|
|
381
|
+
readonly type: "list" | "radiogrid" | "segmented";
|
|
382
|
+
} ? (V extends {
|
|
383
|
+
readonly options: readonly unknown[];
|
|
384
|
+
} ? ChoiceValue<V> : never) : V extends {
|
|
385
|
+
readonly type: "color" | "text" | "image" | "plot";
|
|
386
|
+
} ? string : V extends {
|
|
387
|
+
readonly type: "interval";
|
|
388
|
+
} ? [number, number] : V extends {
|
|
389
|
+
readonly type: "cubicbezier";
|
|
390
|
+
} ? [number, number, number, number] : V extends {
|
|
391
|
+
readonly type: "spring";
|
|
392
|
+
} ? SpringValue : V extends {
|
|
393
|
+
readonly type: "motion";
|
|
394
|
+
} ? MotionValue : V extends {
|
|
395
|
+
readonly type: "shadow";
|
|
396
|
+
} ? ShadowValue : V extends {
|
|
397
|
+
readonly type: "sides";
|
|
398
|
+
} ? SidesValue : V extends {
|
|
399
|
+
readonly type: "gradient";
|
|
400
|
+
} ? GradientValue : V extends {
|
|
401
|
+
readonly type: "point";
|
|
402
|
+
} ? (V extends {
|
|
403
|
+
readonly components: readonly [];
|
|
404
|
+
} ? never : V extends {
|
|
405
|
+
readonly components: readonly (infer C)[];
|
|
406
|
+
} ? {
|
|
407
|
+
[K in C extends {
|
|
408
|
+
readonly key: infer Key extends string;
|
|
409
|
+
} ? Key : never]: number;
|
|
410
|
+
} : V extends {
|
|
411
|
+
readonly value: infer P extends object;
|
|
412
|
+
} ? (keyof P extends never ? never : {
|
|
413
|
+
-readonly [K in keyof P & string]: number;
|
|
414
|
+
}) : never) : V extends {
|
|
415
|
+
readonly type: "tabs";
|
|
416
|
+
} ? (V extends {
|
|
417
|
+
readonly pages: infer P extends object;
|
|
418
|
+
} ? (keyof P extends never ? never : TabClash<P> extends true ? Record<string, Params> : {
|
|
419
|
+
[T in keyof P & string as TabKey<T>]: ParamsOf<P[T]>;
|
|
420
|
+
}) : never) : unknown;
|
|
421
|
+
/** The value a schema entry puts on `params`. */
|
|
422
|
+
export type ValueOf<V> = V extends {
|
|
423
|
+
readonly type: infer T;
|
|
424
|
+
} ? (string extends T ? any : T extends SchemaObject["type"] ? (T extends keyof Hinge ? ([Extract<Hinge[T], keyof V>] extends [never] ? ShorthandValue<V> : VerboseValue<V, T>) : VerboseValue<V, T>) : ShorthandValue<V>) : ShorthandValue<V>;
|
|
425
|
+
type VerboseValue<V, T> = T extends Valueless ? never : TypedValue<V>;
|
|
426
|
+
type ShorthandValue<V> = V extends readonly [readonly [number, number], ...unknown[]] ? [number, number] : V extends readonly [number] | readonly [number, number] | readonly [number, number, number] | readonly [number, number, number, number] ? number : V extends readonly [number, ...number[]] ? V[number] : V extends readonly [] ? undefined : V extends readonly number[] ? number : V extends readonly (number | readonly number[])[] ? [number, number] : V extends number ? number : V extends boolean ? boolean : V extends string ? string : V extends readonly (infer O)[] ? OptionValue<O> : V extends {
|
|
427
|
+
readonly action: (...a: any[]) => any;
|
|
428
|
+
} ? never : V extends {
|
|
429
|
+
readonly options: readonly unknown[];
|
|
430
|
+
} ? ChoiceValue<V> : V extends object ? Entries<V, true> : unknown;
|
|
431
|
+
type Reserved = "__proto__" | "constructor" | "prototype";
|
|
432
|
+
type FolderChrome<V, K> = K extends "disabled" | "hint" ? true : K extends "render" ? (V extends (...a: any[]) => any ? true : false) : false;
|
|
433
|
+
type Entries<S, Nested extends boolean> = string extends keyof S ? Params : {
|
|
434
|
+
-readonly [K in keyof S & string as K extends Reserved ? never : ValueOf<S[K]> extends never ? never : Nested extends true ? (FolderChrome<S[K], K> extends true ? never : K) : K]: ValueOf<S[K]>;
|
|
435
|
+
};
|
|
436
|
+
/** The live values a schema builds, nested like the schema; a plain `Schema` gives the loose `Params`. */
|
|
437
|
+
export type ParamsOf<S> = Entries<S, false>;
|
|
438
|
+
type CheckValue<V> = V extends {
|
|
439
|
+
readonly type: infer T;
|
|
440
|
+
} ? (string extends T ? V : T extends SchemaObject["type"] ? (V extends {
|
|
441
|
+
readonly type: "tabs";
|
|
442
|
+
readonly pages: infer P;
|
|
443
|
+
} ? {
|
|
444
|
+
readonly pages: {
|
|
445
|
+
[K in keyof P]: KnownTypes<P[K]>;
|
|
446
|
+
};
|
|
447
|
+
} : T extends keyof Hinge ? ([Extract<Hinge[T], keyof V>] extends [never] ? unknown : FitsForm<V, T>) : FitsForm<V, T>) : {
|
|
448
|
+
readonly type: NotAControlType;
|
|
449
|
+
}) : V extends readonly unknown[] | ((...a: any[]) => any) ? unknown : V extends object ? KnownTypes<V> : unknown;
|
|
450
|
+
type FormOf<O, T> = O extends {
|
|
451
|
+
readonly type: infer N;
|
|
452
|
+
} ? (T extends N ? O & ControlOptions : never) : never;
|
|
453
|
+
type FitsForm<V, T> = V extends FormOf<SchemaObject, T> ? unknown : FormOf<SchemaObject, T>;
|
|
454
|
+
type NotAControlType = {
|
|
455
|
+
readonly "names no control: see the type list in AGENTS.md": true;
|
|
456
|
+
};
|
|
457
|
+
/** A schema whose every `type` names a control (`tweaks()` checks it; `{ type: "slidr" }` is an error). */
|
|
458
|
+
export type KnownTypes<S> = {
|
|
459
|
+
[K in keyof S]: CheckValue<S[K]>;
|
|
460
|
+
};
|
|
461
|
+
/** One schema value whose `type` names a control (`mountControl()` checks it). */
|
|
462
|
+
export type KnownType<V> = CheckValue<V>;
|
|
293
463
|
/** A theme — token overrides applied over the default monochrome look. Every key is
|
|
294
464
|
* optional, so a partial theme only moves what it names; unset tokens keep their default.
|
|
295
|
-
*
|
|
465
|
+
* Keys are the `--tw-*` custom properties themselves. Apply at build via
|
|
296
466
|
* `tweaks(name, schema, { theme })`, or live via `panel.setTheme(theme)`. The kit's whole
|
|
297
467
|
* appearance runs on these custom properties — this is the public theming surface. */
|
|
298
468
|
export interface Theme {
|
|
299
469
|
/** Brand accent — slider fills, focus rings, active highlights (default: neutral, no accent). */
|
|
300
|
-
accent?: string;
|
|
301
|
-
/** Text drawn on the accent (active segment / radio label)
|
|
302
|
-
|
|
470
|
+
"--tw-accent"?: string;
|
|
471
|
+
/** Text drawn on the accent (active segment / radio label); the primary text tone unless set, so set it with a light accent. */
|
|
472
|
+
"--tw-on-accent"?: string;
|
|
303
473
|
/** Panel background, reused for recessed wells. */
|
|
304
|
-
base?: string;
|
|
474
|
+
"--tw-base"?: string;
|
|
305
475
|
/** Popover / dropdown background. */
|
|
306
|
-
|
|
476
|
+
"--tw-dropdown-bg"?: string;
|
|
307
477
|
/** Control surface and its hover / active steps. */
|
|
308
|
-
surface?: string;
|
|
309
|
-
|
|
310
|
-
|
|
478
|
+
"--tw-surface"?: string;
|
|
479
|
+
"--tw-surface-hover"?: string;
|
|
480
|
+
"--tw-surface-active"?: string;
|
|
311
481
|
/** Hairline border and its hover step. */
|
|
312
|
-
border?: string;
|
|
313
|
-
|
|
482
|
+
"--tw-border"?: string;
|
|
483
|
+
"--tw-border-hover"?: string;
|
|
314
484
|
/** Text-selection highlight wash. */
|
|
315
|
-
selection?: string;
|
|
485
|
+
"--tw-selection"?: string;
|
|
316
486
|
/** Text tones — panel title, section heading, primary value text, control label, and the muted / faint / focus tones. */
|
|
317
|
-
|
|
318
|
-
section?: string;
|
|
319
|
-
text?: string;
|
|
320
|
-
label?: string;
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
focus?: string;
|
|
324
|
-
/** Copy-confirmation accent. */
|
|
325
|
-
success?: string;
|
|
326
|
-
|
|
327
|
-
danger?: string;
|
|
487
|
+
"--tw-text-root"?: string;
|
|
488
|
+
"--tw-text-section"?: string;
|
|
489
|
+
"--tw-text-primary"?: string;
|
|
490
|
+
"--tw-text-label"?: string;
|
|
491
|
+
"--tw-text-secondary"?: string;
|
|
492
|
+
"--tw-text-tertiary"?: string;
|
|
493
|
+
"--tw-text-focus"?: string;
|
|
494
|
+
/** Copy-confirmation accent, and the invalid-state accent (the plot's bad-expression cue). */
|
|
495
|
+
"--tw-success"?: string;
|
|
496
|
+
"--tw-danger"?: string;
|
|
328
497
|
/** Popover shadow, the panel's container elevation, and its lifted (floating / dragging) variant. */
|
|
329
|
-
shadow?: string;
|
|
330
|
-
|
|
331
|
-
|
|
498
|
+
"--tw-shadow-dropdown"?: string;
|
|
499
|
+
"--tw-shadow-panel"?: string;
|
|
500
|
+
"--tw-shadow-panel-lifted"?: string;
|
|
332
501
|
/** Font stack, and the monospace stack (the plot's expression field). */
|
|
333
|
-
font?: string;
|
|
334
|
-
|
|
335
|
-
/** Control corner radius
|
|
336
|
-
radius?:
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
[token: string]: string | number | undefined;
|
|
502
|
+
"--tw-font-sans"?: string;
|
|
503
|
+
"--tw-font-mono"?: string;
|
|
504
|
+
/** Control corner radius, row height and the panel's width (256px by default), as CSS lengths. */
|
|
505
|
+
"--tw-radius"?: string;
|
|
506
|
+
"--tw-row-height"?: string;
|
|
507
|
+
"--tw-width"?: string;
|
|
508
|
+
/** Any other token. */
|
|
509
|
+
[token: `--${string}`]: string | undefined;
|
|
342
510
|
}
|
|
343
511
|
/** Options for a programmatic write — `set()`, `setMany()`, `fromJSON()`. */
|
|
344
512
|
export interface SetOptions {
|
|
@@ -347,29 +515,25 @@ export interface SetOptions {
|
|
|
347
515
|
* controls, persistence and undo still follow it: it's an undo step like any other. */
|
|
348
516
|
silent?: boolean;
|
|
349
517
|
}
|
|
350
|
-
/**
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
/** Where a floating panel starts: `x` / `y` are its insets in px (16 by default) from the two
|
|
354
|
-
* edges of `corner` (top-left by default), and it keeps that corner as the window resizes.
|
|
355
|
-
* The far edge keeps a gap of `y` when the height caps; CSS `--tw-float-gap` overrides it. */
|
|
518
|
+
/** Where a floating panel starts: `x` / `y` are its insets in px (16 by default) from the
|
|
519
|
+
* viewport's top-left. The far edge keeps a gap of `y` when the height caps; CSS
|
|
520
|
+
* `--tw-float-gap` overrides it. */
|
|
356
521
|
export interface FloatingPlacement {
|
|
357
522
|
x?: number;
|
|
358
523
|
y?: number;
|
|
359
|
-
corner?: FloatingCorner;
|
|
360
524
|
}
|
|
525
|
+
/** Panel options (third arg to `tweaks()`). */
|
|
361
526
|
export interface TweaksOptions {
|
|
362
|
-
/** Theme overrides
|
|
527
|
+
/** Theme overrides as `--tw-*` tokens; `null` / omitted = default monochrome. */
|
|
363
528
|
theme?: Theme | null;
|
|
364
|
-
/** Persist values to localStorage + enable presets — a key, or `true` to key by name.
|
|
529
|
+
/** Persist values to localStorage + enable presets — a key, or `true` to key by name. Uploaded images go to
|
|
530
|
+
* IndexedDB under the same key, and come back by `ready`. */
|
|
365
531
|
persist?: string | boolean;
|
|
366
532
|
/** With `persist`, `false` keeps saving values but leaves the Presets menu out of the
|
|
367
533
|
* toolbar (the presets API still works). On by default. */
|
|
368
534
|
presets?: boolean;
|
|
369
|
-
/** Add a filter/search field to the toolbar. */
|
|
370
|
-
filter?: boolean;
|
|
371
535
|
/** Start the panel already floated (fixed-positioned): `true` → 16px from the top-left, or a
|
|
372
|
-
* placement `{ x, y
|
|
536
|
+
* placement `{ x, y }`. Its height caps at the window and it scrolls, header and all. */
|
|
373
537
|
floating?: boolean | FloatingPlacement;
|
|
374
538
|
/** Drag the header to reposition the panel — on by default. An inline panel lifts into a
|
|
375
539
|
* floating layer on first drag; set `false` to pin it in place. */
|
|
@@ -380,15 +544,18 @@ export interface TweaksOptions {
|
|
|
380
544
|
undo?: boolean;
|
|
381
545
|
/** Custom reset handler (e.g. restore real app defaults + rebuild). */
|
|
382
546
|
onReset?: () => void;
|
|
383
|
-
/** Fired when a drag/scrub on any control begins. */
|
|
384
|
-
onEditStart?: () => void;
|
|
385
|
-
/** Fired when a drag/scrub ends. */
|
|
386
|
-
onEditEnd?: () => void;
|
|
387
547
|
}
|
|
388
|
-
/** The live values bag — `params[key]` for each control
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
548
|
+
/** The live values bag, loosely typed — `params[key]` for each control. A schema literal passed
|
|
549
|
+
* to `tweaks()` gets its exact shape instead (`ParamsOf`). */
|
|
550
|
+
export type Params = Record<string, any>;
|
|
551
|
+
/** The keys `set()` and `setMany()` take: a typed panel's controls by dotted path (`size`, `card.size`), so a typo is a
|
|
552
|
+
* compile error; any string for a panel built from a plain `Schema`. An object-valued control's own fields read as
|
|
553
|
+
* paths too (`drop.blur`): the types can't tell its value from a folder, so they allow what the runtime refuses. Past ten
|
|
554
|
+
* folders deep the rest of a path is any string, since spelling every one out overran tsc's depth limit. */
|
|
555
|
+
export type PanelPath<P> = PathsOf<P, []>;
|
|
556
|
+
type PathsOf<P, D extends unknown[]> = string extends keyof P ? string : D["length"] extends 10 ? string : {
|
|
557
|
+
[K in keyof P & string]: K | (P[K] extends readonly unknown[] ? never : P[K] extends object ? `${K}.${PathsOf<P[K], [...D, 0]>}` : never);
|
|
558
|
+
}[keyof P & string];
|
|
392
559
|
/** The whole-panel state `toJSON()` returns / `fromJSON()` accepts: every control value
|
|
393
560
|
* (nested to mirror folders/tabs) plus UI state — which folders are collapsed and which
|
|
394
561
|
* tab is active. JSON-safe; persist it however you like. Both `values` and `ui` are
|
|
@@ -410,25 +577,31 @@ export interface PanelState {
|
|
|
410
577
|
tabs?: Record<string, string | null>;
|
|
411
578
|
};
|
|
412
579
|
}
|
|
413
|
-
/** The panel object `tweaks()` returns.
|
|
414
|
-
|
|
580
|
+
/** The panel object `tweaks()` returns; `P` is its values' shape. A bare `Panel` takes any panel, typed or not (its
|
|
581
|
+
* default is `any`, not `Params`: `set()`'s typed paths would make a typed panel unassignable to `Panel<Params>`). */
|
|
582
|
+
export interface Panel<P = any> {
|
|
415
583
|
/** The panel root element — append it to the DOM. */
|
|
416
584
|
el: HTMLElement;
|
|
417
585
|
/** Live values, updated in place as controls change. */
|
|
418
|
-
params:
|
|
419
|
-
/** Resolves once any lazily-loaded controls have hydrated
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
586
|
+
params: P;
|
|
587
|
+
/** Resolves once any lazily-loaded controls have hydrated and, for a panel that persists an image control, its
|
|
588
|
+
* stored images have loaded (resolves immediately when there's neither). */
|
|
589
|
+
ready: Promise<Panel<P>>;
|
|
590
|
+
/** Subscribe to changes; `last` is the changed control's dotted path (`size`, `card.size`), as `set()` and `changes()`
|
|
591
|
+
* name it, or undefined when many changed at once (a restore, `reset()`, `fromJSON`, `setMany`). */
|
|
592
|
+
on(fn: (params: P, last?: string) => void): () => void;
|
|
423
593
|
/** Set a control's value programmatically. Nested controls take a dotted path
|
|
424
|
-
* ("folder.child", "tabs.page.child"); a bare key also reaches a nested control
|
|
425
|
-
* when it's unambiguous
|
|
426
|
-
|
|
594
|
+
* ("folder.child", "tabs.page.child"); at runtime a bare key also reaches a nested control
|
|
595
|
+
* when it's unambiguous, though a typed panel's types take the full path. A key matching
|
|
596
|
+
* no control, or a folder or tab, is refused with a console warning. */
|
|
597
|
+
set(key: PanelPath<P>, value: unknown, options?: SetOptions): void;
|
|
427
598
|
/** Set several controls at once — a flat map of keys (dotted for nested controls), e.g.
|
|
428
599
|
* `setMany({ "shadow.radius": 28, blur: 48 })`. Resolves each key like `set()`, then fires
|
|
429
600
|
* listeners + persists ONCE for the whole batch, where N separate `set()` calls would fire
|
|
430
601
|
* N times. Unknown / ambiguous / reserved keys warn and are skipped. */
|
|
431
|
-
setMany(values:
|
|
602
|
+
setMany(values: {
|
|
603
|
+
readonly [K in PanelPath<P>]?: unknown;
|
|
604
|
+
}, options?: SetOptions): void;
|
|
432
605
|
/** Reset every control to its default (or run `opts.onReset`). */
|
|
433
606
|
reset(): void;
|
|
434
607
|
/** Serialize the whole panel — every control value plus UI state (collapsed folders,
|
|
@@ -479,6 +652,9 @@ export interface Control {
|
|
|
479
652
|
/** Show a short message on the control for a moment. Only the image control supplies it; the panel calls it when
|
|
480
653
|
* storage refuses the control's value. */
|
|
481
654
|
note?(message: string): void;
|
|
655
|
+
/** The hard range set() fits a number into, as the control resolved it (derived bounds too); a point's per component.
|
|
656
|
+
* Only the numeric controls supply it; the panel's clamp notice reads it. */
|
|
657
|
+
range?: [number, number] | Record<string, [number, number]>;
|
|
482
658
|
}
|
|
483
659
|
/** Options for `mountControl(host, value, opts?)` — one control, no panel. */
|
|
484
660
|
export interface MountOptions {
|
|
@@ -507,16 +683,16 @@ export interface MountedControl {
|
|
|
507
683
|
/** Resolves with this handle once the control has built — immediately on the single-file build. */
|
|
508
684
|
ready: Promise<MountedControl>;
|
|
509
685
|
}
|
|
510
|
-
/** The notations the
|
|
511
|
-
* the mode: `hex` gives `#
|
|
686
|
+
/** The notations the color picker edits in (its mode dropdown). The emitted value follows
|
|
687
|
+
* the mode: `hex` gives `#RRGGBB`, the wide-gamut modes give a CSS color like `oklch(…)`. */
|
|
512
688
|
export type ColorMode = "hex" | "srgb" | "css" | "hsl" | "hwb" | "oklch" | "oklab" | "lch" | "lab" | "p3" | "rec2020";
|
|
513
689
|
/** Options for `createColorPicker(opts?)` — the picker body alone, no trigger row. */
|
|
514
690
|
export interface ColorPickerOptions {
|
|
515
|
-
/** The
|
|
691
|
+
/** The color it opens on — any CSS color string (default `#7c5cff`). */
|
|
516
692
|
value?: string;
|
|
517
693
|
/** The notation it opens in (default `oklch`). */
|
|
518
694
|
mode?: ColorMode;
|
|
519
|
-
/** Fired with the new
|
|
695
|
+
/** Fired with the new color string whenever it changes — by hand or through `set()`. */
|
|
520
696
|
onChange?: (value: string) => void;
|
|
521
697
|
}
|
|
522
698
|
/** The handle `createColorPicker()` returns. Bring your own trigger: append `el` to a popover
|
|
@@ -524,11 +700,11 @@ export interface ColorPickerOptions {
|
|
|
524
700
|
export interface ColorPicker {
|
|
525
701
|
/** The picker's root (`.tw-color-picker`), stable from creation; it carries the kit's tokens,
|
|
526
702
|
* so the picker renders anywhere. On the code-split build the editor fills it in once the
|
|
527
|
-
*
|
|
703
|
+
* color chunk has loaded. */
|
|
528
704
|
el: HTMLElement;
|
|
529
|
-
/** Apply a
|
|
705
|
+
/** Apply a color — the picker updates AND `onChange` fires (when the color actually changed). */
|
|
530
706
|
set(value: string): void;
|
|
531
|
-
/** The current
|
|
707
|
+
/** The current color, serialized in the picker's mode. */
|
|
532
708
|
get(): string;
|
|
533
709
|
/** The current notation. */
|
|
534
710
|
mode(): ColorMode;
|
|
@@ -554,3 +730,4 @@ declare global {
|
|
|
554
730
|
"tw:change": CustomEvent<TwChangeDetail>;
|
|
555
731
|
}
|
|
556
732
|
}
|
|
733
|
+
export {};
|