tsgrid-ui 2.1.0 → 2.3.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/CHANGELOG.md CHANGED
@@ -2,6 +2,62 @@
2
2
 
3
3
  All notable changes to **TsGrid UI** will be documented in this file.
4
4
 
5
+ ## v2.3.0 — 2026-05-13
6
+
7
+ ### Refactor
8
+
9
+ Decomposed the **message cluster** (652 LOC) out of `TsUtils` into two new sibling modules — **no breaking changes**, public API byte-identical to v2.2.0. Class methods remain; bodies are now one-line delegators routing to plain functions in sibling modules.
10
+
11
+ - `src/tsutils-registry.ts` — `TsUi` widget registry + `checkName()` validation helper. Phase 0 Cycle-Break: severs the `tsbase ↔ tsutils` circular import that existed since v1.x. `tsbase.ts` now imports from `tsutils-registry.ts`, `tsutils-data.ts`, `tsutils-type-guards.ts`, and `query.js` directly — zero edges back into `tsutils.ts`.
12
+ - `src/tsutils-notify.ts` — `notify()` pure function + `NotifyDeps` DI interface. Imports only `query.js`; `this.tmp` state passed by reference via `deps.tmpSlot`.
13
+ - `src/tsutils-message.ts` — `normButtons()`, `_message()`, `_alert()`, `_confirm()`, `_prompt()` pure functions + `MessageDeps`, `NotifyDeps`, `ConfirmDeps`, `PromptDeps` DI interfaces + `TsMessageProm`, `TsMessageWhere`, `TsMessageOptions` type definitions. The only sub-module permitted to import `TsBase` from `tsbase.ts` (required for event-mixin instantiation; documented carve-out to INV-4).
14
+
15
+ `TsUtils` singleton shape and all ~788+ call sites: **UNCHANGED**. SEMVER MINOR. BC verdict: NONE.
16
+
17
+ ### Added
18
+
19
+ - New internal DI interfaces exported from `tsutils-message.ts`: `MessageDeps`, `ConfirmDeps`, `PromptDeps`.
20
+ - `TsMessageProm`, `TsMessageWhere`, `TsMessageOptions` types relocated from inline declarations in `tsutils.ts` to `tsutils-message.ts`; re-exported via `tsutils.ts` barrel — all existing import paths remain valid.
21
+
22
+ ### Fixed
23
+
24
+ - **`arguments.length == 1` overload trap** in `message()`, `confirm()`, and `prompt()`: the class delegator always passes 2 arguments to the extracted function, making `arguments.length` always `2` and silently breaking the single-arg `where-as-options` call form. Replaced with `options == null` (loose-equality covers both `undefined` and `null`). Behavior is a strict superset: additionally fixes `confirm(where, null)` and `prompt(where, null)` which previously assigned `null` to `msgOpts` and would crash on subsequent property access. Locked by parity tests (1-arg vs 2-arg-undefined produce identical DOM output for each method).
25
+
26
+ ### Tests
27
+
28
+ - Added 82 unit tests (115 → 197): 6 registry (Phase 0), 17 notify (Phase 1), 15 normButtons (Phase 2), 15 message scaffold (Phase 3a), 14 message body/animation/parity (Phase 3b), 15 alert/confirm/prompt/parity (Phase 4).
29
+
30
+ ### Bundle
31
+
32
+ Delta vs v2.2.0 baseline: `dist/tsgrid-ui.js` 946,684 B (+1,648 B, +0.17%), `dist/tsgrid-ui.es6.js` 944,836 B (+1,657 B, +0.18%). Within ±2% gate. PASSED.
33
+
34
+ ### BC
35
+
36
+ Net-additive. All `TsUtils` method signatures, arities, return types, and runtime behavior unchanged. Three type definitions relocated (re-exported at original paths). SEMVER MINOR. BC verdict: NONE.
37
+
38
+ ---
39
+
40
+ ## v2.2.0 — 2026-05-13
41
+
42
+ ### Added
43
+
44
+ - **`TsUtils.colorContrastValue(color1, color2): number`** — numeric companion to `colorContrast()` that returns the raw WCAG ratio as a `number` instead of a `.toFixed(2)` string. Consumers performing threshold checks no longer need to wrap the result in `Number(...)` or `parseFloat(...)`.
45
+
46
+ ### Refactor
47
+
48
+ - `colorContrast()` now delegates to `colorContrastValue().toFixed(2)`. Output is byte-identical to v2.1.0; no behavior change.
49
+ - `tstoolbar.ts` background-color contrast check upgraded to the numeric API (`TsUtils.colorContrastValue('#fff', color) < 2`), removing the `Number(...)` cast.
50
+
51
+ ### Tests
52
+
53
+ - Added 4 unit tests for `colorContrastValue` (111 → 115): typeof number, white/black ≥ 21 (max WCAG), identical = 1, parity with `colorContrast` string form via `.toFixed(2)`.
54
+
55
+ ### BC
56
+
57
+ Net-additive. `colorContrast` return type and value unchanged. SEMVER MINOR. BC verdict: NONE.
58
+
59
+ ---
60
+
5
61
  ## v2.1.0 — 2026-05-13
6
62
 
7
63
  ### Refactor
@@ -1,4 +1,4 @@
1
- /* tsgrid-ui 1.0.x (nightly) (5/13/2026, 3:29:07 PM) (c) 2014 vitmalina@gmail.com, (c) 2026 DaverSoGT — MIT */
1
+ /* tsgrid-ui 1.0.x (nightly) (5/13/2026, 5:32:29 PM) (c) 2014 vitmalina@gmail.com, (c) 2026 DaverSoGT — MIT */
2
2
  /**
3
3
  * TODO:
4
4
  * - remove default styling, only keep tsg-* styles
@@ -9,7 +9,7 @@
9
9
  */
10
10
  @font-face {
11
11
  font-family: "tsgrid-font";
12
- src: url("data:application/x-font-woff;charset=utf-8;base64,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") format("woff");
12
+ src: url("data:application/x-font-woff;charset=utf-8;base64,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") format("woff");
13
13
  font-weight: normal;
14
14
  font-style: normal;
15
15
  }
@@ -1,3 +1,152 @@
1
+ type QuerySelector = string | Node | Window | Query | Array<Node | Element> | Iterable<Node | Element> | null | undefined;
2
+ type QueryContext = Document | Element | ShadowRoot | DocumentFragment;
3
+ interface EventRecord {
4
+ event: string;
5
+ scope: string | undefined;
6
+ callback: EventListener;
7
+ options: AddEventListenerOptions | boolean | undefined;
8
+ }
9
+ interface MQueryData {
10
+ events?: EventRecord[];
11
+ prevDisplay?: string;
12
+ [key: string]: unknown;
13
+ }
14
+ declare global {
15
+ interface Node {
16
+ _mQuery?: MQueryData;
17
+ }
18
+ }
19
+ declare class Query {
20
+ static version: number;
21
+ context: QueryContext;
22
+ nodes: Node[];
23
+ length: number;
24
+ [index: number]: Node;
25
+ constructor(selector: QuerySelector, context?: QueryContext);
26
+ static _fragment(html: string): DocumentFragment;
27
+ static _scriptConvert(node: Node): Node;
28
+ static _fixProp(name: string): string;
29
+ _insert(method: string, html: string | Query | Node): Query;
30
+ _save(node: Node, name: string, value: unknown): void;
31
+ get(index?: number): Node | Node[] | null;
32
+ eq(index: number): Query;
33
+ then(fun: (q: Query) => Query | null | undefined): Query;
34
+ find(selector: string): Query;
35
+ filter(selector: string | Node | ((node: Node) => boolean)): Query;
36
+ next(): Query;
37
+ prev(): Query;
38
+ shadow(selector?: string): Query;
39
+ closest(selector: string): Query;
40
+ host(all?: boolean): Query;
41
+ parent(selector?: string): Query;
42
+ parents(selector?: string, firstOnly?: boolean): Query;
43
+ add(more: Query | Node | Node[]): Query;
44
+ each(func: (node: Node, ind: number, col: Query) => void): Query;
45
+ append(html: string | Query | Node): Query;
46
+ prepend(html: string | Query | Node): Query;
47
+ after(html: string | Query | Node): Query;
48
+ before(html: string | Query | Node): Query;
49
+ replace(html: string | Query | Node): Query;
50
+ remove(): Query;
51
+ css(key?: string | Record<string, string | number>, value?: string | number): string | Record<string, string> | undefined | Query;
52
+ addClass(classes: string): Query;
53
+ removeClass(classes: string | string[] | null): Query;
54
+ toggleClass(classes: string | string[] | null, force?: boolean): Query;
55
+ hasClass(classes: string | string[] | null): boolean | string[];
56
+ on(events: string, options: AddEventListenerOptions | EventListener | {
57
+ delegate?: string;
58
+ } | undefined, callback?: EventListener): Query;
59
+ on(events: string, callback: EventListener): Query;
60
+ off(events?: string, options?: AddEventListenerOptions | EventListener, callback?: EventListener): Query;
61
+ trigger(name: string | Event | CustomEvent, options?: EventInit): Query;
62
+ attr(name: string): string | undefined;
63
+ attr(name: string | Record<string, string>, value?: string): Query;
64
+ removeAttr(...attrs: string[]): Query;
65
+ prop(name: string): unknown;
66
+ prop(name: string | Record<string, unknown>, value?: unknown): Query;
67
+ removeProp(...props: string[]): Query;
68
+ data(key?: string | Record<string, unknown>, value?: unknown): unknown | Query;
69
+ removeData(key: string | string[]): Query;
70
+ show(): Query;
71
+ hide(): Query;
72
+ toggle(force?: boolean): Query;
73
+ empty(): Query;
74
+ html(html?: string | HTMLElement): string | Query | undefined;
75
+ text(text?: string): unknown | Query;
76
+ val(value?: string): unknown | Query;
77
+ change(): Query;
78
+ click(): Query;
79
+ }
80
+
81
+ /**
82
+ * Part of TsUi 2.0 library — color cluster sub-module
83
+ * - Extracted from src/tsutils.ts by v2.1 SDD refactor (Phase 2)
84
+ * - No dependencies on TsBase, TsUtils, or any other sub-module (L1 DAG leaf)
85
+ * - All exports are plain functions — no default export
86
+ *
87
+ * 4-space indent (project convention for sub-modules).
88
+ */
89
+ /** RGB(A) color as returned by parseColor() */
90
+ interface TsColorRgb {
91
+ r: number;
92
+ g: number;
93
+ b: number;
94
+ a: number;
95
+ }
96
+
97
+ /**
98
+ * TsUtils v2.1 — Data / Object helpers sub-module (Phase 3+4 of v2.1 SDD)
99
+ *
100
+ * Contains: TsCloneOptions, clone, extend,
101
+ * naturalCompare, normMenu, getNested, encodeParams,
102
+ * prepareParams, parseRoute, debounce, wait
103
+ *
104
+ * Rules:
105
+ * - No default export
106
+ * - No import from tsbase.ts (INV-4)
107
+ * - No this.-dispatch inside function bodies (INV-8)
108
+ * - 4-space indent
109
+ */
110
+ /** Options for TsUtils.clone() */
111
+ interface TsCloneOptions {
112
+ functions?: boolean;
113
+ elements?: boolean;
114
+ events?: boolean;
115
+ exclude?: string[] | ((key: string, ctx: {
116
+ obj: unknown;
117
+ parent: string;
118
+ }) => boolean);
119
+ parent?: string;
120
+ }
121
+ /** Options for TsUtils.normMenu() */
122
+ interface TsNormMenuOptions {
123
+ itemMap?: {
124
+ id: string;
125
+ text: string;
126
+ };
127
+ [key: string]: unknown;
128
+ }
129
+
130
+ /**
131
+ * TsUi registry + checkName — Phase 0 of v2.3 SDD.
132
+ * DEPENDENCY-FREE: zero imports from tsutils/tsbase family.
133
+ *
134
+ * Hosts the mutable widget registry object (TsUi) and the name-validation
135
+ * helper (checkName) that were previously coupled to tsbase.ts via tsutils.ts,
136
+ * creating a tsbase ↔ tsutils import cycle. Moving them here breaks that cycle:
137
+ *
138
+ * tsbase.ts → tsutils-registry.ts → tsutils-type-guards.ts → (leaf)
139
+ *
140
+ * tsutils.ts re-exports TsUi from this module (does NOT re-declare it) to
141
+ * preserve the single-object identity required by INV-12 (referential equality
142
+ * across all import paths).
143
+ *
144
+ * Imports: only isAlphaNumeric from ./tsutils-type-guards.js
145
+ * Exports: TsUi, checkName
146
+ */
147
+ /** Widget registry — widgets register here when constructed with a `name`. */
148
+ declare const TsUi: Record<string, unknown>;
149
+
1
150
  /**
2
151
  * Part of TsUi 2.0 library
3
152
  * - Dependencies: TsUtils
@@ -147,132 +296,81 @@ declare class TsBase {
147
296
  unmount(): void;
148
297
  }
149
298
 
150
- type QuerySelector = string | Node | Window | Query | Array<Node | Element> | Iterable<Node | Element> | null | undefined;
151
- type QueryContext = Document | Element | ShadowRoot | DocumentFragment;
152
- interface EventRecord {
153
- event: string;
154
- scope: string | undefined;
155
- callback: EventListener;
156
- options: AddEventListenerOptions | boolean | undefined;
157
- }
158
- interface MQueryData {
159
- events?: EventRecord[];
160
- prevDisplay?: string;
161
- [key: string]: unknown;
162
- }
163
- declare global {
164
- interface Node {
165
- _mQuery?: MQueryData;
166
- }
167
- }
168
- declare class Query {
169
- static version: number;
170
- context: QueryContext;
171
- nodes: Node[];
172
- length: number;
173
- [index: number]: Node;
174
- constructor(selector: QuerySelector, context?: QueryContext);
175
- static _fragment(html: string): DocumentFragment;
176
- static _scriptConvert(node: Node): Node;
177
- static _fixProp(name: string): string;
178
- _insert(method: string, html: string | Query | Node): Query;
179
- _save(node: Node, name: string, value: unknown): void;
180
- get(index?: number): Node | Node[] | null;
181
- eq(index: number): Query;
182
- then(fun: (q: Query) => Query | null | undefined): Query;
183
- find(selector: string): Query;
184
- filter(selector: string | Node | ((node: Node) => boolean)): Query;
185
- next(): Query;
186
- prev(): Query;
187
- shadow(selector?: string): Query;
188
- closest(selector: string): Query;
189
- host(all?: boolean): Query;
190
- parent(selector?: string): Query;
191
- parents(selector?: string, firstOnly?: boolean): Query;
192
- add(more: Query | Node | Node[]): Query;
193
- each(func: (node: Node, ind: number, col: Query) => void): Query;
194
- append(html: string | Query | Node): Query;
195
- prepend(html: string | Query | Node): Query;
196
- after(html: string | Query | Node): Query;
197
- before(html: string | Query | Node): Query;
198
- replace(html: string | Query | Node): Query;
199
- remove(): Query;
200
- css(key?: string | Record<string, string | number>, value?: string | number): string | Record<string, string> | undefined | Query;
201
- addClass(classes: string): Query;
202
- removeClass(classes: string | string[] | null): Query;
203
- toggleClass(classes: string | string[] | null, force?: boolean): Query;
204
- hasClass(classes: string | string[] | null): boolean | string[];
205
- on(events: string, options: AddEventListenerOptions | EventListener | {
206
- delegate?: string;
207
- } | undefined, callback?: EventListener): Query;
208
- on(events: string, callback: EventListener): Query;
209
- off(events?: string, options?: AddEventListenerOptions | EventListener, callback?: EventListener): Query;
210
- trigger(name: string | Event | CustomEvent, options?: EventInit): Query;
211
- attr(name: string): string | undefined;
212
- attr(name: string | Record<string, string>, value?: string): Query;
213
- removeAttr(...attrs: string[]): Query;
214
- prop(name: string): unknown;
215
- prop(name: string | Record<string, unknown>, value?: unknown): Query;
216
- removeProp(...props: string[]): Query;
217
- data(key?: string | Record<string, unknown>, value?: unknown): unknown | Query;
218
- removeData(key: string | string[]): Query;
219
- show(): Query;
220
- hide(): Query;
221
- toggle(force?: boolean): Query;
222
- empty(): Query;
223
- html(html?: string | HTMLElement): string | Query | undefined;
224
- text(text?: string): unknown | Query;
225
- val(value?: string): unknown | Query;
226
- change(): Query;
227
- click(): Query;
228
- }
229
-
230
299
  /**
231
- * Part of TsUi 2.0 library — color cluster sub-module
232
- * - Extracted from src/tsutils.ts by v2.1 SDD refactor (Phase 2)
233
- * - No dependencies on TsBase, TsUtils, or any other sub-module (L1 DAG leaf)
234
- * - All exports are plain functions — no default export
300
+ * TsUtils message cluster (message/alert/confirm/prompt/normButtons + types)
301
+ * Phase 2-4 of v2.3 SDD (message-cluster-extraction).
235
302
  *
236
- * 4-space indent (project convention for sub-modules).
237
- */
238
- /** RGB(A) color as returned by parseColor() */
239
- interface TsColorRgb {
240
- r: number;
241
- g: number;
242
- b: number;
243
- a: number;
244
- }
245
-
246
- /**
247
- * TsUtils v2.1 — Data / Object helpers sub-module (Phase 3+4 of v2.1 SDD)
303
+ * IMPORTANT: This module imports TsBase from tsbase.ts — the only carve-out
304
+ * to INV-4. Rationale: message() does `new TsBase()` to mix events into msgBase.
305
+ * This exception is documented here and whitelisted in the INV-4 grep policy.
248
306
  *
249
- * Contains: TsCloneOptions, clone, extend,
250
- * naturalCompare, normMenu, getNested, encodeParams,
251
- * prepareParams, parseRoute, debounce, wait
307
+ * Exports (Phase 2):
308
+ * normButtons standalone pure helper; no DOM, no timers
252
309
  *
253
- * Rules:
254
- * - No default export
255
- * - No import from tsbase.ts (INV-4)
256
- * - No this.-dispatch inside function bodies (INV-8)
257
- * - 4-space indent
310
+ * Exports (Phase 3a):
311
+ * TsMessageProm, TsMessageWhere, TsMessageOptions (types)
312
+ * MessageDeps (deps interface for _message — scaffold for Phase 3b)
313
+ * _message (stub body lands in Phase 3b)
314
+ *
315
+ * Exports (Phase 3b+):
316
+ * _message (full body), _alert, _confirm, _prompt (Phase 4)
317
+ *
318
+ * Imports: TsBase from tsbase.ts (INV-4 carve-out, see above)
319
+ * TsUISettings type from tsutils.ts (type-only, no runtime dep)
320
+ * query from query.js (DOM helper)
258
321
  */
259
- /** Options for TsUtils.clone() */
260
- interface TsCloneOptions {
261
- functions?: boolean;
262
- elements?: boolean;
263
- events?: boolean;
264
- exclude?: string[] | ((key: string, ctx: {
265
- obj: unknown;
266
- parent: string;
267
- }) => boolean);
268
- parent?: string;
322
+
323
+ /** Promise-chain handle returned by message() / confirm() / prompt() */
324
+ interface TsMessageProm {
325
+ self: TsBase;
326
+ action(callBack: (event: unknown) => void): TsMessageProm;
327
+ close(callBack: (event: unknown) => void): TsMessageProm;
328
+ open(callBack: (event: unknown) => void): TsMessageProm;
329
+ then(callBack: (event: unknown) => void): TsMessageProm;
330
+ change?: (callBack: (event: unknown) => void) => TsMessageProm;
331
+ [key: string]: unknown;
269
332
  }
270
- /** Options for TsUtils.normMenu() */
271
- interface TsNormMenuOptions {
272
- itemMap?: {
273
- id: string;
274
- text: string;
333
+ /** Where-descriptor for message() */
334
+ interface TsMessageWhere {
335
+ box: string | Element | null;
336
+ after?: string | Element | null;
337
+ owner?: {
338
+ name?: string;
339
+ lock?: (...args: unknown[]) => void;
340
+ unlock?: (...args: unknown[]) => void;
341
+ focus?: () => void;
275
342
  };
343
+ param?: unknown;
344
+ }
345
+ /** Options for message() */
346
+ interface TsMessageOptions {
347
+ width?: number;
348
+ height?: number;
349
+ text?: string | null;
350
+ body?: string;
351
+ buttons?: string;
352
+ html?: string;
353
+ focus?: number | string | null;
354
+ hideOn?: string[];
355
+ actions?: Record<string, unknown>;
356
+ cancelAction?: string;
357
+ on?: unknown;
358
+ onOpen?: unknown;
359
+ onClose?: unknown;
360
+ onAction?: unknown;
361
+ originalWidth?: number;
362
+ originalHeight?: number;
363
+ msgIndex?: number;
364
+ tmp?: {
365
+ zIndex: string;
366
+ overflow: string;
367
+ };
368
+ input?: Element | null;
369
+ box?: Element | null;
370
+ trigger?: (event: string, data: Record<string, unknown>) => unknown;
371
+ close?: () => void;
372
+ setFocus?: (focus: number | string | null | undefined) => void;
373
+ action?: (action: string, event: unknown) => void;
276
374
  [key: string]: unknown;
277
375
  }
278
376
 
@@ -310,7 +408,6 @@ interface TsNormMenuOptions {
310
408
  */
311
409
 
312
410
  declare const query: (selector: unknown, context?: unknown) => Query;
313
- declare const TsUi: Record<string, unknown>;
314
411
  /** Settings object merged from TsLocale + user locale overrides */
315
412
  interface TsUISettings {
316
413
  dataType: string;
@@ -370,59 +467,6 @@ interface TsMenuItem {
370
467
  attrs?: string;
371
468
  [key: string]: unknown;
372
469
  }
373
- /** Promise-chain handle returned by TsUtils.message() / .confirm() / .prompt() */
374
- interface TsMessageProm {
375
- self: TsBase;
376
- action(callBack: (event: unknown) => void): TsMessageProm;
377
- close(callBack: (event: unknown) => void): TsMessageProm;
378
- open(callBack: (event: unknown) => void): TsMessageProm;
379
- then(callBack: (event: unknown) => void): TsMessageProm;
380
- change?: (callBack: (event: unknown) => void) => TsMessageProm;
381
- [key: string]: unknown;
382
- }
383
- /** Where-descriptor for TsUtils.message() */
384
- interface TsMessageWhere {
385
- box: string | Element | null;
386
- after?: string | Element | null;
387
- owner?: {
388
- name?: string;
389
- lock?: (...args: unknown[]) => void;
390
- unlock?: (...args: unknown[]) => void;
391
- focus?: () => void;
392
- };
393
- param?: unknown;
394
- }
395
- /** Options for TsUtils.message() */
396
- interface TsMessageOptions {
397
- width?: number;
398
- height?: number;
399
- text?: string | null;
400
- body?: string;
401
- buttons?: string;
402
- html?: string;
403
- focus?: number | string | null;
404
- hideOn?: string[];
405
- actions?: Record<string, unknown>;
406
- cancelAction?: string;
407
- on?: unknown;
408
- onOpen?: unknown;
409
- onClose?: unknown;
410
- onAction?: unknown;
411
- originalWidth?: number;
412
- originalHeight?: number;
413
- msgIndex?: number;
414
- tmp?: {
415
- zIndex: string;
416
- overflow: string;
417
- };
418
- input?: Element | null;
419
- box?: Element | null;
420
- trigger?: (event: string, data: Record<string, unknown>) => unknown;
421
- close?: () => void;
422
- setFocus?: (focus: number | string | null | undefined) => void;
423
- action?: (action: string, event: unknown) => void;
424
- [key: string]: unknown;
425
- }
426
470
  declare class Utils {
427
471
  version: string;
428
472
  tmp: Record<string, unknown>;
@@ -468,6 +512,25 @@ declare class Utils {
468
512
  transition(div_old: HTMLElement, div_new: HTMLElement, type: string, callBack?: () => void): Promise<void>;
469
513
  lock(box: unknown, options?: TsLockOptions | string, ...rest: unknown[]): void;
470
514
  unlock(box: unknown, speed?: number): void;
515
+ /**
516
+ * Constructs the MessageDeps object for the _message() delegator.
517
+ * Called once per message() invocation — captures `this` at call time.
518
+ * Per design §C.5 / §C.2.
519
+ */
520
+ private _msgDeps;
521
+ /**
522
+ * Constructs the ConfirmDeps object for the _confirm() delegator.
523
+ * Per design §C.3.
524
+ * normButtons closure: uses inline lambda that binds this.lang and this.settings
525
+ * at call time — preserving the call-time timing semantics (design §C.3 caveat).
526
+ */
527
+ private _confirmDeps;
528
+ /**
529
+ * Constructs the PromptDeps object for the _prompt() delegator.
530
+ * Per design §C.3.
531
+ * lang is bound at call time so deps.lang('Ok') uses current locale.
532
+ */
533
+ private _promptDeps;
471
534
  /**
472
535
  * Opens a context message, similar in parameters as TsPopup.open()
473
536
  *
@@ -587,6 +650,7 @@ declare class Utils {
587
650
  setCursorPosition(input: HTMLElement | null, pos: number, posEnd?: number): void;
588
651
  parseColor(str: string | null | undefined): TsColorRgb | null;
589
652
  colorContrast(color1: string, color2: string): string;
653
+ colorContrastValue(color1: string, color2: string): number;
590
654
  hsv2rgb(h: any, s?: any, v?: any, a?: any): {
591
655
  r: number;
592
656
  g: number;