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.
Files changed (132) hide show
  1. package/AGENTS.md +5 -5
  2. package/README.md +3 -3
  3. package/dist/tweaks/auto.js +1 -1
  4. package/dist/tweaks/auto.js.map +1 -1
  5. package/dist/tweaks/bezier-S2BOXQBM.js +2 -0
  6. package/dist/tweaks/bezier-S2BOXQBM.js.map +6 -0
  7. package/dist/tweaks/chunk-3MZAAMC2.js +2 -0
  8. package/dist/tweaks/chunk-3MZAAMC2.js.map +6 -0
  9. package/dist/tweaks/chunk-ETB35KFV.js +2 -0
  10. package/dist/tweaks/chunk-ETB35KFV.js.map +6 -0
  11. package/dist/tweaks/chunk-YB5GKWZI.js +2 -0
  12. package/dist/tweaks/chunk-YB5GKWZI.js.map +6 -0
  13. package/dist/tweaks/clip-A3VI53BK.js +2 -0
  14. package/dist/tweaks/clip-A3VI53BK.js.map +6 -0
  15. package/dist/tweaks/color-UGYMAF3W.js +2 -0
  16. package/dist/tweaks/core.js +1 -1
  17. package/dist/tweaks/core.js.map +3 -3
  18. package/dist/tweaks/fold-GY47HIQA.js +2 -0
  19. package/dist/tweaks/fold-GY47HIQA.js.map +6 -0
  20. package/dist/tweaks/gradient-BTX25WSH.js +2 -0
  21. package/dist/tweaks/gradient-BTX25WSH.js.map +6 -0
  22. package/dist/tweaks/{heavy-CLD7UAVI.js → heavy-NPFIGHRM.js} +2 -2
  23. package/dist/tweaks/image-HTQQ4WX6.js +4 -0
  24. package/dist/tweaks/image-HTQQ4WX6.js.map +6 -0
  25. package/dist/tweaks/{image-store-WRKY2NPU.js → image-store-QD5SMZXG.js} +1 -1
  26. package/dist/tweaks/image-store-QD5SMZXG.js.map +6 -0
  27. package/dist/tweaks/interval-BHPI4LRN.js +2 -0
  28. package/dist/tweaks/interval-BHPI4LRN.js.map +6 -0
  29. package/dist/tweaks/markup-QM53TQJZ.js +2 -0
  30. package/dist/tweaks/markup-QM53TQJZ.js.map +6 -0
  31. package/dist/tweaks/monitor-722WIYGW.js +3 -0
  32. package/dist/tweaks/monitor-722WIYGW.js.map +6 -0
  33. package/dist/tweaks/motion-HMCZK6HJ.js +2 -0
  34. package/dist/tweaks/motion-HMCZK6HJ.js.map +6 -0
  35. package/dist/tweaks/plot-D3NQ6XNN.js +3 -0
  36. package/dist/tweaks/plot-D3NQ6XNN.js.map +6 -0
  37. package/dist/tweaks/point-XDXKMDXH.js +2 -0
  38. package/dist/tweaks/point-XDXKMDXH.js.map +6 -0
  39. package/dist/tweaks/presets-EUWNSCUW.js +2 -0
  40. package/dist/tweaks/presets-EUWNSCUW.js.map +6 -0
  41. package/dist/tweaks/shadow-AM7VSRNS.js +2 -0
  42. package/dist/tweaks/shadow-AM7VSRNS.js.map +6 -0
  43. package/dist/tweaks/shadow-root-RYUV3AGS.js +3 -0
  44. package/dist/tweaks/shadow-root-RYUV3AGS.js.map +6 -0
  45. package/dist/tweaks/sides-JWIURDA4.js +2 -0
  46. package/dist/tweaks/sides-JWIURDA4.js.map +6 -0
  47. package/dist/tweaks/spring-BF5GBTPM.js +2 -0
  48. package/dist/tweaks/spring-BF5GBTPM.js.map +6 -0
  49. package/dist/tweaks/tabs-PRVUUZXZ.js +2 -0
  50. package/dist/tweaks/tabs-PRVUUZXZ.js.map +6 -0
  51. package/dist/tweaks.css +1 -1
  52. package/dist/tweaks.js +5 -4
  53. package/dist/tweaks.js.map +3 -3
  54. package/dist/types/tweaks/enhance.d.ts +3 -2
  55. package/dist/types/tweaks/types.d.ts +278 -72
  56. package/package.json +5 -2
  57. package/src/tweaks/auto.ts +9 -5
  58. package/src/tweaks/clip.ts +84 -22
  59. package/src/tweaks/controls/basic.ts +463 -139
  60. package/src/tweaks/controls/bezier.ts +152 -47
  61. package/src/tweaks/controls/color.ts +610 -161
  62. package/src/tweaks/controls/gradient.ts +256 -77
  63. package/src/tweaks/controls/image.ts +388 -132
  64. package/src/tweaks/controls/interval.ts +126 -41
  65. package/src/tweaks/controls/monitor.ts +142 -36
  66. package/src/tweaks/controls/motion.ts +231 -56
  67. package/src/tweaks/controls/plot.ts +321 -101
  68. package/src/tweaks/controls/point.ts +134 -45
  69. package/src/tweaks/controls/shadow.ts +103 -30
  70. package/src/tweaks/controls/sides.ts +150 -40
  71. package/src/tweaks/controls/spring.ts +220 -60
  72. package/src/tweaks/controls/tabs.ts +39 -18
  73. package/src/tweaks/core.ts +1 -1
  74. package/src/tweaks/easing.ts +45 -20
  75. package/src/tweaks/enhance.ts +21 -6
  76. package/src/tweaks/feedback.ts +133 -34
  77. package/src/tweaks/fold.ts +22 -10
  78. package/src/tweaks/heavy.ts +461 -137
  79. package/src/tweaks/icons.ts +12 -5
  80. package/src/tweaks/image-store.ts +131 -43
  81. package/src/tweaks/lazy.ts +36 -19
  82. package/src/tweaks/markup.ts +255 -92
  83. package/src/tweaks/panel.ts +1262 -438
  84. package/src/tweaks/presets.ts +85 -0
  85. package/src/tweaks/schema.ts +213 -51
  86. package/src/tweaks/shadow-root.ts +178 -0
  87. package/src/tweaks/shared.ts +802 -190
  88. package/src/tweaks/standalone.ts +120 -30
  89. package/src/tweaks/types.ts +644 -143
  90. package/src/tweaks/undo.ts +104 -0
  91. package/src/tweaks.css +556 -550
  92. package/src/wide-gamut.ts +473 -125
  93. package/dist/tweaks/bezier-JFEZMCLP.js +0 -2
  94. package/dist/tweaks/bezier-JFEZMCLP.js.map +0 -6
  95. package/dist/tweaks/chunk-6UO4DHBN.js +0 -2
  96. package/dist/tweaks/chunk-6UO4DHBN.js.map +0 -6
  97. package/dist/tweaks/chunk-DIQMLBAS.js +0 -2
  98. package/dist/tweaks/chunk-DIQMLBAS.js.map +0 -6
  99. package/dist/tweaks/chunk-XE6OUJBG.js +0 -2
  100. package/dist/tweaks/chunk-XE6OUJBG.js.map +0 -6
  101. package/dist/tweaks/clip-WW7JYO4X.js +0 -2
  102. package/dist/tweaks/clip-WW7JYO4X.js.map +0 -6
  103. package/dist/tweaks/color-YMMFURP6.js +0 -2
  104. package/dist/tweaks/fold-U6YRZLCJ.js +0 -2
  105. package/dist/tweaks/fold-U6YRZLCJ.js.map +0 -6
  106. package/dist/tweaks/gradient-JER7PW4D.js +0 -2
  107. package/dist/tweaks/gradient-JER7PW4D.js.map +0 -6
  108. package/dist/tweaks/image-H6QSLGO3.js +0 -4
  109. package/dist/tweaks/image-H6QSLGO3.js.map +0 -6
  110. package/dist/tweaks/image-store-WRKY2NPU.js.map +0 -6
  111. package/dist/tweaks/interval-TEUHQGZN.js +0 -2
  112. package/dist/tweaks/interval-TEUHQGZN.js.map +0 -6
  113. package/dist/tweaks/markup-NIBJD6E2.js +0 -2
  114. package/dist/tweaks/markup-NIBJD6E2.js.map +0 -6
  115. package/dist/tweaks/monitor-3BY7YCGX.js +0 -3
  116. package/dist/tweaks/monitor-3BY7YCGX.js.map +0 -6
  117. package/dist/tweaks/motion-FQPUBKKM.js +0 -2
  118. package/dist/tweaks/motion-FQPUBKKM.js.map +0 -6
  119. package/dist/tweaks/plot-2HBNBZSG.js +0 -3
  120. package/dist/tweaks/plot-2HBNBZSG.js.map +0 -6
  121. package/dist/tweaks/point-VV6XV3I6.js +0 -2
  122. package/dist/tweaks/point-VV6XV3I6.js.map +0 -6
  123. package/dist/tweaks/shadow-5E4E55I2.js +0 -2
  124. package/dist/tweaks/shadow-5E4E55I2.js.map +0 -6
  125. package/dist/tweaks/sides-P3STEVYY.js +0 -2
  126. package/dist/tweaks/sides-P3STEVYY.js.map +0 -6
  127. package/dist/tweaks/spring-HUVSXNVN.js +0 -2
  128. package/dist/tweaks/spring-HUVSXNVN.js.map +0 -6
  129. package/dist/tweaks/tabs-76FW7LQ7.js +0 -2
  130. package/dist/tweaks/tabs-76FW7LQ7.js.map +0 -6
  131. /package/dist/tweaks/{color-YMMFURP6.js.map → color-UGYMAF3W.js.map} +0 -0
  132. /package/dist/tweaks/{heavy-CLD7UAVI.js.map → heavy-NPFIGHRM.js.map} +0 -0
@@ -1,2 +1,3 @@
1
- /** Bind every unbound [data-tw] host under `root` (the document by default). */
2
- export declare function enhance(root?: Document | Element): Promise<void>;
1
+ import type { EnhanceOptions } from "./types.js";
2
+ /** Bind every unbound [data-twk] host under `root` (the document by default). */
3
+ export declare function enhance(root?: Document | Element, opts?: EnhanceOptions): Promise<void>;
@@ -1,4 +1,5 @@
1
- /** An option for a select / radio grid: a bare string or number, or `{ value, label }`; the param is the value as written. */
1
+ /** An option for a select / radio grid: a bare string or number, or `{ value, label }`; the param is the value as
2
+ * written. */
2
3
  export type Option = string | number | {
3
4
  value: string | number;
4
5
  label?: string;
@@ -264,26 +265,30 @@ export type SchemaObject = {
264
265
  type: "image";
265
266
  value?: string;
266
267
  /** Supplied images to pick from, as URLs or `{ value, label }`. The control becomes a row naming the chosen
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. */
268
+ * image that opens a pane of tiles with the upload below them, and the param is the chosen URL or the upload's
269
+ * data URL. */
268
270
  options?: ReadonlyArray<string | {
269
271
  value: string;
270
272
  label?: string;
271
273
  }>;
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). */
274
+ /** Tiles per row in the gallery, 1 to 6 (by default one per option for two or three, 2 for one or four, then
275
+ * 3). */
273
276
  cols?: number;
274
277
  /** The largest upload taken, in bytes (10 MB unless set); a bigger file is refused with a note. */
275
278
  maxSize?: number;
276
279
  /** An upload longer than this on its long side, in px, is drawn down to it before it becomes the param, and one
277
- * heavier than 1.5 MB is redrawn at its size, so a phone photo can't fill storage (2560 unless set; `false` takes
278
- * uploads as they are). A JPEG comes out as a JPEG at
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
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. */
280
+ * heavier than 1.5 MB is redrawn at its size, so a phone photo can't fill storage (2560 unless set; `false`
281
+ * takes uploads as they are). A JPEG comes out as a JPEG at
282
+ * `quality`; anything else as a PNG when that is 1.5 MB or less (a screenshot, not a photo), else as a JPEG, or
283
+ * a WebP when it has transparency. A GIF, an SVG, an animated WebP or APNG, a light picture within `fit`, or one
284
+ * the redraw wouldn't make smaller is kept as it is. */
281
285
  fit?: number | false;
282
286
  /** The JPEG or WebP quality of a shrunk upload, 0 to 1 (0.85 unless set). */
283
287
  quality?: number;
284
288
  /** `false` leaves the upload button out of a gallery: the options are the whole choice. */
285
289
  upload?: boolean;
286
- /** `false` leaves Clear out of a gallery, and Delete no longer empties it: for a choice that must keep a value. */
290
+ /** `false` leaves Clear out of a gallery, and Delete no longer empties it: for a choice that must keep a
291
+ * value. */
287
292
  clear?: boolean;
288
293
  } | {
289
294
  type: "button";
@@ -359,7 +364,7 @@ type Dashed<S extends string, Acc extends string = "", Run = false> = S extends
359
364
  type TrimDash<S extends string> = S extends `-${infer R}` ? TrimDash<R> : S extends `${infer R}-` ? TrimDash<R> : S;
360
365
  /** A tab title's key under `params`: lower-case, each run of other characters a `-`, trimmed
361
366
  * (`"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;
367
+ 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
368
  type TabClash<P> = true extends {
364
369
  [T in keyof P & string]: TabKey<T> extends {
365
370
  [U in Exclude<keyof P & string, T>]: TabKey<U>;
@@ -367,11 +372,11 @@ type TabClash<P> = true extends {
367
372
  }[keyof P & string] ? true : false;
368
373
  type Valueless = "button" | "buttongroup" | "separator" | "fpsgraph" | "monitor";
369
374
  type Hinge = {
370
- list: "options";
371
- radiogrid: "options";
372
- segmented: "options";
375
+ list: "options" | "value";
376
+ radiogrid: "options" | "value";
377
+ segmented: "options" | "value";
373
378
  point: "components" | "value";
374
- tabs: "pages";
379
+ tabs: "pages" | "value";
375
380
  };
376
381
  type TypedValue<V> = V extends {
377
382
  readonly type: "slider" | "number";
@@ -379,9 +384,9 @@ type TypedValue<V> = V extends {
379
384
  readonly type: "checkbox";
380
385
  } ? boolean : V extends {
381
386
  readonly type: "list" | "radiogrid" | "segmented";
382
- } ? (V extends {
387
+ } ? V extends {
383
388
  readonly options: readonly unknown[];
384
- } ? ChoiceValue<V> : never) : V extends {
389
+ } ? ChoiceValue<V> : never : V extends {
385
390
  readonly type: "color" | "text" | "image" | "plot";
386
391
  } ? string : V extends {
387
392
  readonly type: "interval";
@@ -399,7 +404,7 @@ type TypedValue<V> = V extends {
399
404
  readonly type: "gradient";
400
405
  } ? GradientValue : V extends {
401
406
  readonly type: "point";
402
- } ? (V extends {
407
+ } ? V extends {
403
408
  readonly components: readonly [];
404
409
  } ? never : V extends {
405
410
  readonly components: readonly (infer C)[];
@@ -409,19 +414,19 @@ type TypedValue<V> = V extends {
409
414
  } ? Key : never]: number;
410
415
  } : V extends {
411
416
  readonly value: infer P extends object;
412
- } ? (keyof P extends never ? never : {
417
+ } ? keyof P extends never ? never : {
413
418
  -readonly [K in keyof P & string]: number;
414
- }) : never) : V extends {
419
+ } : never : V extends {
415
420
  readonly type: "tabs";
416
- } ? (V extends {
421
+ } ? V extends {
417
422
  readonly pages: infer P extends object;
418
- } ? (keyof P extends never ? never : TabClash<P> extends true ? Record<string, Params> : {
423
+ } ? keyof P extends never ? never : TabClash<P> extends true ? Record<string, Params> : {
419
424
  [T in keyof P & string as TabKey<T>]: ParamsOf<P[T]>;
420
- }) : never) : unknown;
425
+ } : never : unknown;
421
426
  /** The value a schema entry puts on `params`. */
422
427
  export type ValueOf<V> = V extends {
423
428
  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>;
429
+ } ? 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> : T extends string ? [Extract<"value" | "options" | "action", keyof V>] extends [never] ? ShorthandValue<V> : never : ShorthandValue<V> : ShorthandValue<V>;
425
430
  type VerboseValue<V, T> = T extends Valueless ? never : TypedValue<V>;
426
431
  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
432
  readonly action: (...a: any[]) => any;
@@ -429,24 +434,24 @@ type ShorthandValue<V> = V extends readonly [readonly [number, number], ...unkno
429
434
  readonly options: readonly unknown[];
430
435
  } ? ChoiceValue<V> : V extends object ? Entries<V, true> : unknown;
431
436
  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;
437
+ type FolderChrome<V, K> = K extends "disabled" | "hint" ? true : K extends "render" ? V extends (...a: any[]) => any ? true : false : false;
433
438
  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]>;
439
+ -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
440
  };
436
441
  /** The live values a schema builds, nested like the schema; a plain `Schema` gives the loose `Params`. */
437
442
  export type ParamsOf<S> = Entries<S, false>;
438
443
  type CheckValue<V> = V extends {
439
444
  readonly type: infer T;
440
- } ? (string extends T ? V : T extends SchemaObject["type"] ? (V extends {
445
+ } ? string extends T ? V : T extends SchemaObject["type"] ? V extends {
441
446
  readonly type: "tabs";
442
447
  readonly pages: infer P;
443
448
  } ? {
444
449
  readonly pages: {
445
450
  [K in keyof P]: KnownTypes<P[K]>;
446
451
  };
447
- } : T extends keyof Hinge ? ([Extract<Hinge[T], keyof V>] extends [never] ? unknown : FitsForm<V, T>) : FitsForm<V, T>) : {
452
+ } : T extends keyof Hinge ? [Extract<Hinge[T], keyof V>] extends [never] ? unknown : FitsForm<V, T> : FitsForm<V, T> : {
448
453
  readonly type: NotAControlType;
449
- }) : V extends readonly unknown[] | ((...a: any[]) => any) ? unknown : V extends object ? KnownTypes<V> : unknown;
454
+ } : V extends readonly unknown[] | ((...a: any[]) => any) ? unknown : V extends object ? KnownTypes<V> : unknown;
450
455
  type FormOf<O, T> = O extends {
451
456
  readonly type: infer N;
452
457
  } ? (T extends N ? O & ControlOptions : never) : never;
@@ -462,51 +467,53 @@ export type KnownTypes<S> = {
462
467
  export type KnownType<V> = CheckValue<V>;
463
468
  /** A theme — token overrides applied over the default monochrome look. Every key is
464
469
  * optional, so a partial theme only moves what it names; unset tokens keep their default.
465
- * Keys are the `--tw-*` custom properties themselves. Apply at build via
470
+ * Keys are the `--twk-*` custom properties themselves. Apply at build via
466
471
  * `tweaks(name, schema, { theme })`, or live via `panel.setTheme(theme)`. The kit's whole
467
472
  * appearance runs on these custom properties — this is the public theming surface. */
468
473
  export interface Theme {
469
474
  /** Brand accent — slider fills, focus rings, active highlights (default: neutral, no accent). */
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;
475
+ "--twk-accent"?: string;
476
+ /** Text drawn on the accent (active segment / radio label); the primary text tone unless set, so set it with a light
477
+ * accent. */
478
+ "--twk-on-accent"?: string;
473
479
  /** Panel background, reused for recessed wells. */
474
- "--tw-base"?: string;
480
+ "--twk-base"?: string;
475
481
  /** Popover / dropdown background. */
476
- "--tw-dropdown-bg"?: string;
482
+ "--twk-dropdown-bg"?: string;
477
483
  /** Control surface and its hover / active steps. */
478
- "--tw-surface"?: string;
479
- "--tw-surface-hover"?: string;
480
- "--tw-surface-active"?: string;
484
+ "--twk-surface"?: string;
485
+ "--twk-surface-hover"?: string;
486
+ "--twk-surface-active"?: string;
481
487
  /** Hairline border and its hover step. */
482
- "--tw-border"?: string;
483
- "--tw-border-hover"?: string;
488
+ "--twk-border"?: string;
489
+ "--twk-border-hover"?: string;
484
490
  /** Text-selection highlight wash. */
485
- "--tw-selection"?: string;
486
- /** Text tones — panel title, section heading, primary value text, control label, and the muted / faint / focus tones. */
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;
491
+ "--twk-selection"?: string;
492
+ /** Text tones — panel title, section heading, primary value text, control label, and the muted / faint / focus
493
+ * tones. */
494
+ "--twk-text-root"?: string;
495
+ "--twk-text-section"?: string;
496
+ "--twk-text-primary"?: string;
497
+ "--twk-text-label"?: string;
498
+ "--twk-text-secondary"?: string;
499
+ "--twk-text-tertiary"?: string;
500
+ "--twk-text-focus"?: string;
494
501
  /** Copy-confirmation accent, and the invalid-state accent (the plot's bad-expression cue). */
495
- "--tw-success"?: string;
496
- "--tw-danger"?: string;
502
+ "--twk-success"?: string;
503
+ "--twk-danger"?: string;
497
504
  /** Popover shadow, the panel's container elevation, and its lifted (floating / dragging) variant. */
498
- "--tw-shadow-dropdown"?: string;
499
- "--tw-shadow-panel"?: string;
500
- "--tw-shadow-panel-lifted"?: string;
505
+ "--twk-shadow-dropdown"?: string;
506
+ "--twk-shadow-panel"?: string;
507
+ "--twk-shadow-panel-lifted"?: string;
501
508
  /** Font stack, and the monospace stack (the plot's expression field). */
502
- "--tw-font-sans"?: string;
503
- "--tw-font-mono"?: string;
509
+ "--twk-font-sans"?: string;
510
+ "--twk-font-mono"?: string;
504
511
  /** 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;
512
+ "--twk-radius"?: string;
513
+ "--twk-row-height"?: string;
514
+ "--twk-width"?: string;
508
515
  /** Any other token. */
509
- [token: `--${string}`]: string | undefined;
516
+ [token: `--twk-${string}`]: string | undefined;
510
517
  }
511
518
  /** Options for a programmatic write — `set()`, `setMany()`, `fromJSON()`. */
512
519
  export interface SetOptions {
@@ -517,14 +524,183 @@ export interface SetOptions {
517
524
  }
518
525
  /** Where a floating panel starts: `x` / `y` are its insets in px (16 by default) from the
519
526
  * viewport's top-left. The far edge keeps a gap of `y` when the height caps; CSS
520
- * `--tw-float-gap` overrides it. */
527
+ * `--twk-float-gap` overrides it. */
521
528
  export interface FloatingPlacement {
522
529
  x?: number;
523
530
  y?: number;
524
531
  }
532
+ /** The words a panel shows and says, by key, for the `strings` option (each line notes the English default). A key
533
+ * with a `{placeholder}` takes a string that uses it, or a function given the values, for a language whose plurals
534
+ * need more than one form. Units (px, ms, %), axis letters and color notations stay as they are. */
535
+ export type Word<V = never> = [V] extends [never] ? string : string | ((v: V) => string);
536
+ export interface Strings {
537
+ /** "Tweaks" — the panel's landmark name when its own is blank */ panel?: string;
538
+ /** "Presets" — the toolbar button */ presets?: string;
539
+ /** "Copy values (⇧: changed only)" — the toolbar button */ copy?: string;
540
+ /** "Reset" — the toolbar button */ reset?: string;
541
+ /** "Double-click or hold to reset" — a row label's tooltip */ resetHint?: string;
542
+ /** "Values copied" */ copied?: string;
543
+ /** "{n} changed values copied" — 1 changed value copied for one */ copiedChanged?: Word<{
544
+ n: number;
545
+ }>;
546
+ /** "Nothing has changed" */ nothingChanged?: string;
547
+ /** "Copy failed" */ copyFailed?: string;
548
+ /** "{label} copied" — ⌘C on a row */ rowCopied?: Word<{
549
+ label: string;
550
+ }>;
551
+ /** "Not saved" — a value storage refused */ notSaved?: string;
552
+ /** "{n} values pasted" — 1 value pasted for one */ pasted?: Word<{
553
+ n: number;
554
+ }>;
555
+ /** "Nothing to paste" */ nothingToPaste?: string;
556
+ /** "Couldn't read the clipboard" */ clipboardUnread?: string;
557
+ /** "Preset name…" — the field's placeholder */ presetName?: string;
558
+ /** "New preset name" — the field's label */ newPreset?: string;
559
+ /** "Save" */ save?: string;
560
+ /** "No presets yet" */ noPresets?: string;
561
+ /** "Loaded preset {name}" */ presetLoaded?: Word<{
562
+ name: string;
563
+ }>;
564
+ /** "Saved preset {name}" */ presetSaved?: Word<{
565
+ name: string;
566
+ }>;
567
+ /** "Preset {name} not saved: storage is full" */ presetFull?: Word<{
568
+ name: string;
569
+ }>;
570
+ /** "Delete preset {name}" — a row's delete button */ presetDelete?: Word<{
571
+ name: string;
572
+ }>;
573
+ /** "Off" — a checkbox */ off?: string;
574
+ /** "On" — a checkbox */ on?: string;
575
+ /** "Button" — a group button with no label */ button?: string;
576
+ /** "Tab" — a tab page whose title is blank */ tab?: string;
577
+ /** "Folder" — a markup folder with no data-label */ folder?: string;
578
+ /** "Drag to adjust" — a number field's grip */ dragToAdjust?: string;
579
+ /** "{label} minimum" */ intervalMin?: Word<{
580
+ label: string;
581
+ }>;
582
+ /** "{label} maximum" */ intervalMax?: Word<{
583
+ label: string;
584
+ }>;
585
+ /** "Monitor" — a monitor with no label */ monitor?: string;
586
+ /** "FPS" — an fpsgraph with no label */ fps?: string;
587
+ /** "Plot" — a plot with no label */ plot?: string;
588
+ /** "{label} — expression in x" — a plot's field */ expression?: Word<{
589
+ label: string;
590
+ }>;
591
+ /** "Point" — a point with no label */ point?: string;
592
+ /** "{label} pad: {x} and {y}" */ pointPad?: Word<{
593
+ label: string;
594
+ x: string | number;
595
+ y: string | number;
596
+ }>;
597
+ /** "Control point {n}" — a cubic bézier handle */ controlPoint?: Word<{
598
+ n: number;
599
+ }>;
600
+ /** "Control point {n}, x {x}, y {y}" */ controlPointAt?: Word<{
601
+ n: number;
602
+ x: string | number;
603
+ y: string | number;
604
+ }>;
605
+ /** "Color" — a color row with no label, and the shadow's color row */ color?: string;
606
+ /** "Color plane: chroma across, lightness up" */ colorPlane?: string;
607
+ /** "Color mode" */ colorMode?: string;
608
+ /** "Hex color" */ hex?: string;
609
+ /** "Hue" */ hue?: string;
610
+ /** "Alpha" */ alpha?: string;
611
+ /** "lightness {l}%, chroma {c}" — the color plane's description, said after a run of keys */ colorReadout?: Word<{
612
+ l: number;
613
+ c: number;
614
+ }>;
615
+ /** "wide" — the gamut badge past P3 (sRGB and P3 are names) */ wide?: string;
616
+ /** "Gradient" — a gradient with no label */ gradient?: string;
617
+ /** "{n} stops" — 1 stop for one */ stops?: Word<{
618
+ n: number;
619
+ }>;
620
+ /** "Add a stop after the selected one" — the add button's tooltip */ addStop?: string;
621
+ /** "Add a color stop after the selected one" — the add button's label */ addStopAria?: string;
622
+ /** "Color stop at {pos}%" */ stopAt?: Word<{
623
+ pos: number;
624
+ }>;
625
+ /** "Color stop at {pos}%, selected" */ stopAtSelected?: Word<{
626
+ pos: number;
627
+ }>;
628
+ /** "Easing between stops" — the easing menu's label */ stopEasing?: string;
629
+ /** "How the ramp blends between stops" — its tooltip */ stopEasingHint?: string;
630
+ /** "Linear" */ easeLinear?: string;
631
+ /** "Ease" */ ease?: string;
632
+ /** "Ease in" */ easeIn?: string;
633
+ /** "Ease out" */ easeOut?: string;
634
+ /** "Ease in-out" */ easeInOut?: string;
635
+ /** "Custom" — an easing the menu doesn't list */ custom?: string;
636
+ /** "Upload image" — the gallery's upload button */ upload?: string;
637
+ /** "{label}: upload an image" */ uploadImage?: Word<{
638
+ label: string;
639
+ }>;
640
+ /** "{label}: choose an image" */ chooseImage?: Word<{
641
+ label: string;
642
+ }>;
643
+ /** "Clear" */ clear?: string;
644
+ /** "{label}: clear the image" */ clearImage?: Word<{
645
+ label: string;
646
+ }>;
647
+ /** "Replace" */ replace?: string;
648
+ /** "Drop or choose" */ dropOrChoose?: string;
649
+ /** "None" — no image chosen */ none?: string;
650
+ /** "Image {n}" — a gallery option with no label */ imageN?: Word<{
651
+ n: number;
652
+ }>;
653
+ /** "Uploaded image" */ uploadedImage?: string;
654
+ /** "Custom image" — a value off the gallery's list */ customImage?: string;
655
+ /** "Not an image" */ notAnImage?: string;
656
+ /** "Couldn't read the file" */ unreadable?: string;
657
+ /** "{size}, max {max}" — a file over maxSize */ tooLarge?: Word<{
658
+ size: string;
659
+ max: string;
660
+ }>;
661
+ /** "Motion" — a motion row with no label */ motion?: string;
662
+ /** "Motion type" */ motionType?: string;
663
+ /** "Type" — the motion pane's row label beside that switch */ type?: string;
664
+ /** "Easing" */ easing?: string;
665
+ /** "Spring" */ spring?: string;
666
+ /** "Duration" */ duration?: string;
667
+ /** "Replay the motion" */ replay?: string;
668
+ /** "Easing · {ms} ms" */ easingSummary?: Word<{
669
+ ms: number;
670
+ }>;
671
+ /** "Spring · {ms} ms" */ springSummary?: Word<{
672
+ ms: number;
673
+ }>;
674
+ /** "Spring mode" */ springMode?: string;
675
+ /** "Mode" */ mode?: string;
676
+ /** "Time" */ time?: string;
677
+ /** "Physics" */ physics?: string;
678
+ /** "Stiffness" */ stiffness?: string;
679
+ /** "Damping" */ damping?: string;
680
+ /** "Mass" */ mass?: string;
681
+ /** "Bounce" */ bounce?: string;
682
+ /** "Shadow" — a shadow with no label */ shadow?: string;
683
+ /** "Shadow position" */ shadowPosition?: string;
684
+ /** "in" — an inset shadow's summary, before its numbers */ inset?: string;
685
+ /** "Position" */ position?: string;
686
+ /** "Outer" */ outer?: string;
687
+ /** "Inner" */ inner?: string;
688
+ /** "Blur" */ blur?: string;
689
+ /** "Spread" */ spread?: string;
690
+ /** "Top" */ top?: string;
691
+ /** "Right" */ right?: string;
692
+ /** "Bottom" */ bottom?: string;
693
+ /** "Left" */ left?: string;
694
+ /** "Top-left" */ topLeft?: string;
695
+ /** "Top-right" */ topRight?: string;
696
+ /** "Bottom-right" */ bottomRight?: string;
697
+ /** "Bottom-left" */ bottomLeft?: string;
698
+ /** "Independent sides" */ splitSides?: string;
699
+ /** "Independent corners" */ splitCorners?: string;
700
+ }
525
701
  /** Panel options (third arg to `tweaks()`). */
526
702
  export interface TweaksOptions {
527
- /** Theme overrides as `--tw-*` tokens; `null` / omitted = default monochrome. */
703
+ /** Theme overrides as `--twk-*` tokens; `null` / omitted = default monochrome. */
528
704
  theme?: Theme | null;
529
705
  /** Persist values to localStorage + enable presets — a key, or `true` to key by name. Uploaded images go to
530
706
  * IndexedDB under the same key, and come back by `ready`. */
@@ -544,14 +720,28 @@ export interface TweaksOptions {
544
720
  undo?: boolean;
545
721
  /** Custom reset handler (e.g. restore real app defaults + rebuild). */
546
722
  onReset?: () => void;
723
+ /** Mount the panel in a shadow root, so page CSS can't restyle it (`#app button { … }`, a `.prose` wrapper). `el` is
724
+ * then its host, a `<twk-host>`: theme it with `--twk-*` on the host itself (`.twk-host { … }`), or with `theme`.
725
+ * The styles come from the page's `tweakit/css` when that's loaded, else from `href` (by default `tweaks.css` beside
726
+ * the module). */
727
+ shadow?: boolean | {
728
+ href?: string;
729
+ };
730
+ /** The words the panel and its controls show and say, over the English defaults: translate them, or rename the chrome
731
+ * (`{ presets: "Looks" }`). A key left out keeps its default. */
732
+ strings?: Strings;
733
+ }
734
+ /** Options for `enhance()`: the words its markup controls show and say. */
735
+ export interface EnhanceOptions {
736
+ strings?: Strings;
547
737
  }
548
738
  /** The live values bag, loosely typed — `params[key]` for each control. A schema literal passed
549
739
  * to `tweaks()` gets its exact shape instead (`ParamsOf`). */
550
740
  export type Params = Record<string, any>;
551
741
  /** The keys `set()` and `setMany()` take: a typed panel's controls by dotted path (`size`, `card.size`), so a typo is a
552
742
  * 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. */
743
+ * paths too (`drop.blur`): the types can't tell its value from a folder, so they allow what the runtime refuses. Past
744
+ * ten folders deep the rest of a path is any string, since spelling every one out overran tsc's depth limit. */
555
745
  export type PanelPath<P> = PathsOf<P, []>;
556
746
  type PathsOf<P, D extends unknown[]> = string extends keyof P ? string : D["length"] extends 10 ? string : {
557
747
  [K in keyof P & string]: K | (P[K] extends readonly unknown[] ? never : P[K] extends object ? `${K}.${PathsOf<P[K], [...D, 0]>}` : never);
@@ -580,14 +770,15 @@ export interface PanelState {
580
770
  /** The panel object `tweaks()` returns; `P` is its values' shape. A bare `Panel` takes any panel, typed or not (its
581
771
  * default is `any`, not `Params`: `set()`'s typed paths would make a typed panel unassignable to `Panel<Params>`). */
582
772
  export interface Panel<P = any> {
583
- /** The panel root element — append it to the DOM. */
773
+ /** The panel root element — append it to the DOM. With `shadow`, the host the panel lives in. */
584
774
  el: HTMLElement;
585
775
  /** Live values, updated in place as controls change. */
586
776
  params: P;
587
777
  /** Resolves once any lazily-loaded controls have hydrated and, for a panel that persists an image control, its
588
778
  * stored images have loaded (resolves immediately when there's neither). */
589
779
  ready: Promise<Panel<P>>;
590
- /** Subscribe to changes; `last` is the changed control's dotted path (`size`, `card.size`), as `set()` and `changes()`
780
+ /** Subscribe to changes; `last` is the changed control's dotted path (`size`, `card.size`), as `set()` and
781
+ * `changes()`
591
782
  * name it, or undefined when many changed at once (a restore, `reset()`, `fromJSON`, `setMany`). */
592
783
  on(fn: (params: P, last?: string) => void): () => void;
593
784
  /** Set a control's value programmatically. Nested controls take a dotted path
@@ -627,7 +818,8 @@ export interface Panel<P = any> {
627
818
  * with stays its storage key (`persist: true`), so saved values and presets keep their
628
819
  * home across a rename. */
629
820
  setName(name: string): void;
630
- /** Save the current values as a named preset (needs `opts.persist`). False when there is nowhere to save it, or storage refused it. */
821
+ /** Save the current values as a named preset (needs `opts.persist`). False when there is nowhere to save it, or
822
+ * storage refused it. */
631
823
  savePreset(name: string): boolean;
632
824
  /** Load a named preset. */
633
825
  loadPreset(name: string): boolean;
@@ -638,7 +830,8 @@ export interface Panel<P = any> {
638
830
  /** Undo / redo (need `opts.undo`). */
639
831
  undo(): void;
640
832
  redo(): void;
641
- /** Tear the panel down — remove it from the DOM, release every global listener, close any open popover; the API goes inert. */
833
+ /** Tear the panel down — remove it from the DOM, release every global listener, close any open popover; the API goes
834
+ * inert. */
642
835
  destroy(): void;
643
836
  }
644
837
  /** A built control's handle (internal-ish, but used across modules). */
@@ -665,12 +858,19 @@ export interface MountOptions {
665
858
  label?: string;
666
859
  /** Fired with the new value whenever the control changes — by hand or through `set()`. */
667
860
  onChange?: (value: unknown, key: string) => void;
861
+ /** Mount it in a shadow root, as `tweaks()`'s `shadow` does a panel; `el` is then the host. */
862
+ shadow?: boolean | {
863
+ href?: string;
864
+ };
865
+ /** Its words, as `tweaks()`'s `strings`. */
866
+ strings?: Strings;
668
867
  }
669
868
  /** The handle `mountControl()` returns. */
670
869
  export interface MountedControl {
671
- /** The wrapper (`.tw-control`) the control lives in, already appended to the host and
870
+ /** The wrapper (`.twk-control`) the control lives in, already appended to the host and
672
871
  * stable from creation — it carries the kit's tokens, so the control renders outside a
673
- * panel. On the code-split build a lazily-loaded control fills it in once `ready` resolves. */
872
+ * panel. On the code-split build a lazily-loaded control fills it in once `ready` resolves. With `shadow`, the host
873
+ * the wrapper lives in. */
674
874
  el: HTMLElement;
675
875
  /** Apply a value — the control updates AND `onChange` fires (when the value actually
676
876
  * changed). Before `ready`, the value is queued and applied once the control builds. */
@@ -694,13 +894,19 @@ export interface ColorPickerOptions {
694
894
  mode?: ColorMode;
695
895
  /** Fired with the new color string whenever it changes — by hand or through `set()`. */
696
896
  onChange?: (value: string) => void;
897
+ /** Build it in a shadow root, as `tweaks()`'s `shadow` does a panel; `el` is then the host. */
898
+ shadow?: boolean | {
899
+ href?: string;
900
+ };
901
+ /** Its words, as `tweaks()`'s `strings`. */
902
+ strings?: Strings;
697
903
  }
698
904
  /** The handle `createColorPicker()` returns. Bring your own trigger: append `el` to a popover
699
905
  * or a panel of your own; the kit owns the editor surface and the gamut math. */
700
906
  export interface ColorPicker {
701
- /** The picker's root (`.tw-color-picker`), stable from creation; it carries the kit's tokens,
907
+ /** The picker's root (`.twk-color-picker`), stable from creation; it carries the kit's tokens,
702
908
  * so the picker renders anywhere. On the code-split build the editor fills it in once the
703
- * color chunk has loaded. */
909
+ * color chunk has loaded. With `shadow`, the host the root lives in. */
704
910
  el: HTMLElement;
705
911
  /** Apply a color — the picker updates AND `onChange` fires (when the color actually changed). */
706
912
  set(value: string): void;
@@ -718,7 +924,7 @@ export interface ColorPicker {
718
924
  /** Resolves with this handle once the editor has built — immediately on the single-file build. */
719
925
  ready: Promise<ColorPicker>;
720
926
  }
721
- /** `detail` of the `tw:change` event a `[data-tw]` host dispatches (bubbling) whenever its
927
+ /** `detail` of the `twk:change` event a `[data-twk]` host dispatches (bubbling) whenever its
722
928
  * control changes — `key` is the host's `data-key` (or its label), `value` the new value,
723
929
  * also written to the host's `data-value`. */
724
930
  export interface TwChangeDetail {
@@ -727,7 +933,7 @@ export interface TwChangeDetail {
727
933
  }
728
934
  declare global {
729
935
  interface HTMLElementEventMap {
730
- "tw:change": CustomEvent<TwChangeDetail>;
936
+ "twk:change": CustomEvent<TwChangeDetail>;
731
937
  }
732
938
  }
733
939
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tweakit",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "main": "./dist/tweaks/core.js",
6
6
  "types": "./dist/types/tweaks/core.d.ts",
@@ -32,7 +32,9 @@
32
32
  "prepublishOnly": "npm test",
33
33
  "prepack": "node build.mjs",
34
34
  "serve": "node build.mjs && python3 -m http.server 4330 --directory dist",
35
- "test:browser": "node build.mjs && node --test \"test/browser/*.test.mjs\""
35
+ "test:browser": "node build.mjs && node --test \"test/browser/*.test.mjs\"",
36
+ "format": "prettier --write .",
37
+ "format:check": "prettier --check ."
36
38
  },
37
39
  "exports": {
38
40
  ".": {
@@ -83,6 +85,7 @@
83
85
  "fake-indexeddb": "^6.2.6",
84
86
  "jsdom": "^30.1.2",
85
87
  "playwright": "^1.64.1",
88
+ "prettier": "3.9.10",
86
89
  "typescript": "^7.0.2"
87
90
  }
88
91
  }
@@ -1,12 +1,16 @@
1
- /* tweakit/auto: the code-split API, plus enhance(document) once the page has parsed. The bare import binds nothing, so a
2
- * page of [data-tw] markup with no script of its own imports this entry instead. Built on its own, unbundled, so it stays a
3
- * few lines over ./core.js rather than reshaping the split build's chunks. */
1
+ /* tweakit/auto: the code-split API, plus enhance(document) once the page has parsed. The bare import binds nothing, so
2
+ * a
3
+ * page of [data-twk] markup with no script of its own imports this entry instead. Built on its own, unbundled, so it
4
+ * stays a few lines over ./core.js rather than reshaping the split build's chunks. */
4
5
  import { enhance } from "./core.js";
5
6
  export * from "./core.js";
6
7
 
7
- // A page with nothing to bind doesn't fetch the markup chunk: no [data-tw] host, and no static showcase panel (enhance() wraps one).
8
+ // A page with nothing to bind doesn't fetch the markup chunk: no [data-twk] host, and no static showcase panel
9
+ // (enhance() wraps one).
8
10
  if (typeof document !== "undefined") {
9
- const run = () => { if (document.querySelector('[data-tw], .tw-panel[data-mode="inline"] > .tw-controls')) enhance(document); };
11
+ const run = () => {
12
+ if (document.querySelector('[data-twk], .twk-panel[data-mode="inline"] > .twk-controls')) enhance(document);
13
+ };
10
14
  if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", run);
11
15
  else run();
12
16
  }