tsgrid-ui 2.2.0 → 2.4.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,92 @@
2
2
 
3
3
  All notable changes to **TsGrid UI** will be documented in this file.
4
4
 
5
+ ## v2.4.0 — 2026-05-13
6
+
7
+ ### Added
8
+
9
+ - **Minified bundles** — new `dist/tsgrid-ui.min.js` (CJS, IIFE-wrapped) and `dist/tsgrid-ui.es6.min.js` (ESM). ~46% smaller than non-min counterparts (~508 KB vs ~947 KB). Non-min bundles remain the default for debugging; minified are opt-in by direct path.
10
+ - **ESM sourcemap** — `dist/tsgrid-ui.es6.js.map` shipped alongside the ESM bundle for consumer debugging. CJS sourcemap intentionally omitted (incompatible with the legacy IIFE wrapper rewrite).
11
+ - **ESLint enforcement of INV-8** — new `no-restricted-syntax` rule scoped to `src/tsutils-*.ts` blocks `arguments.length` (codifies the delegator-trap discovered in v2.1 / fixed in v2.3 into the lint gate).
12
+
13
+ ### Refactor
14
+
15
+ Decomposed the **DOM cluster** (8 methods, ~397 LOC) out of `TsUtils` into a new leaf module `src/tsutils-dom.ts` — **no breaking changes**, public API preserved. Class methods remain; bodies are now one-line delegators routing to pure functions in the sibling module.
16
+
17
+ - `src/tsutils-dom.ts` — `transition`, `lock`, `unlock`, `getSize`, `getStrDimentions`, `getStrWidth`, `getStrHeight`, `bindEvents` extracted as stateless functions (~234 LOC). Zero `this.X` references in function bodies (INV-9); no import from `tsbase.ts` (INV-4 leaf rule).
18
+ - `TsLockOptions` interface moved to `tsutils-dom.ts` and re-exported via `tsutils.ts` barrel (TsCloneOptions / TsMessageOptions pattern). Public API unchanged.
19
+ - `lock()` internal `this.unlock(...)` call → direct module-level `unlock()` call (R-DOM-1 mitigation).
20
+ - `getStrDimentions()` internal `this.encodeTags(...)` → import `_encodeTags` from `tsutils-string.js` (R-DOM-2 mitigation).
21
+ - `src/tsutils.ts` shrinks from ~1,602 → ~1,470 LOC. **NET REPO DELTA: −18 LOC** (397 removed inline, 234 + 25 added in dom + delegators).
22
+
23
+ `TsUtils` singleton shape and all ~49+ call sites: **UNCHANGED**. SEMVER MINOR. BC verdict: NONE.
24
+
25
+ ### Improved (type)
26
+
27
+ - `TsUtils.getStrDimentions(str, styles): { width: number; height: number }`, `TsUtils.getStrWidth(str, styles): number`, `TsUtils.getStrHeight(str, styles): number` — return types narrowed from accidental `any` to explicit `number`. **Type improvement, runtime-equivalent**; no behavior change. Consumers using strict tsconfig settings will see the tighter types (all previously valid call sites remain valid — `any → number` is a strict refinement).
28
+
29
+ ### Internal
30
+
31
+ - `@internal` JSDoc + tsup `stripInternal: true` for private surface (`_msgDeps`/`_confirmDeps`/`_promptDeps`, plus `TsFormatterExtra`/`TsFormatter`/`TsTimeResult`). `dist/tsgrid-ui.d.ts` reduced ~1.07% (93,567 → 92,564 B). Larger reductions deferred to v2.5+ (root cause: `TsFormatter`/`TsTimeResult` referenced inline in public method signatures, so tsc re-emits them).
32
+ - `scripts/wrap-legacy.mjs` regex generalized to match esbuild's minified `module.exports=ui(_i);` form (anchors removed) — handles both `tsgrid-ui.js` and `tsgrid-ui.min.js` (R-WRAP-1 mitigation).
33
+
34
+ ### Tests
35
+
36
+ - Added 27 unit tests (197 → 224) covering DOM cluster (lock/unlock/getSize/getStrDimentions/getStrWidth/getStrHeight/bindEvents). `transition` covered by Playwright smoke only (jsdom cannot observe CSS animations).
37
+
38
+ ### Bundle
39
+
40
+ Non-min delta vs v2.3.0 baseline:
41
+ - `dist/tsgrid-ui.js`: 946,684 → 946,553 B (−0.014%)
42
+ - `dist/tsgrid-ui.es6.js`: 944,836 → 944,746 B (−0.010%)
43
+
44
+ New minified artifacts:
45
+ - `dist/tsgrid-ui.min.js`: ~509 KB (−46.3% vs non-min)
46
+ - `dist/tsgrid-ui.es6.min.js`: ~508 KB (−46.3%)
47
+
48
+ All within ±2% gate. PASSED.
49
+
50
+ ### BC
51
+
52
+ Net-additive (new artifacts + type narrowing). Public method signatures: byte-identical for transition/lock/unlock/getSize/bindEvents. `getStrWidth/Height/getStrDimentions` types narrowed `any → number` (strict superset; no runtime change). SEMVER MINOR. BC verdict: NONE.
53
+
54
+ ---
55
+
56
+ ## v2.3.0 — 2026-05-13
57
+
58
+ ### Refactor
59
+
60
+ 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.
61
+
62
+ - `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`.
63
+ - `src/tsutils-notify.ts` — `notify()` pure function + `NotifyDeps` DI interface. Imports only `query.js`; `this.tmp` state passed by reference via `deps.tmpSlot`.
64
+ - `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).
65
+
66
+ `TsUtils` singleton shape and all ~788+ call sites: **UNCHANGED**. SEMVER MINOR. BC verdict: NONE.
67
+
68
+ ### Added
69
+
70
+ - New internal DI interfaces exported from `tsutils-message.ts`: `MessageDeps`, `ConfirmDeps`, `PromptDeps`.
71
+ - `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.
72
+
73
+ ### Fixed
74
+
75
+ - **`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).
76
+
77
+ ### Tests
78
+
79
+ - 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).
80
+
81
+ ### Bundle
82
+
83
+ 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.
84
+
85
+ ### BC
86
+
87
+ 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.
88
+
89
+ ---
90
+
5
91
  ## v2.2.0 — 2026-05-13
6
92
 
7
93
  ### Added
@@ -1,4 +1,4 @@
1
- /* tsgrid-ui 1.0.x (nightly) (5/13/2026, 4:05:55 PM) (c) 2014 vitmalina@gmail.com, (c) 2026 DaverSoGT — MIT */
1
+ /* tsgrid-ui 1.0.x (nightly) (5/13/2026, 7:24:54 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
@@ -33,8 +182,6 @@ interface TsEventPayload<TDetail = unknown> {
33
182
  isCancelled: boolean;
34
183
  /** Reference to the widget that triggered this event. CIRCULAR — do not serialize. */
35
184
  owner: unknown;
36
- /** @internal — Promise resolved when listeners settle; do not depend on shape. */
37
- complete?: Promise<unknown>;
38
185
  }
39
186
  interface TsEventData {
40
187
  type?: string | null;
@@ -147,133 +294,103 @@ declare class TsBase {
147
294
  unmount(): void;
148
295
  }
149
296
 
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
297
  /**
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
298
+ * TsUtils message cluster (message/alert/confirm/prompt/normButtons + types)
299
+ * Phase 2-4 of v2.3 SDD (message-cluster-extraction).
235
300
  *
236
- * 4-space indent (project convention for sub-modules).
301
+ * IMPORTANT: This module imports TsBase from tsbase.ts — the only carve-out
302
+ * to INV-4. Rationale: message() does `new TsBase()` to mix events into msgBase.
303
+ * This exception is documented here and whitelisted in the INV-4 grep policy.
304
+ *
305
+ * Exports (Phase 2):
306
+ * normButtons — standalone pure helper; no DOM, no timers
307
+ *
308
+ * Exports (Phase 3a):
309
+ * TsMessageProm, TsMessageWhere, TsMessageOptions (types)
310
+ * MessageDeps (deps interface for _message — scaffold for Phase 3b)
311
+ * _message (stub — body lands in Phase 3b)
312
+ *
313
+ * Exports (Phase 3b+):
314
+ * _message (full body), _alert, _confirm, _prompt (Phase 4)
315
+ *
316
+ * Imports: TsBase from tsbase.ts (INV-4 carve-out, see above)
317
+ * TsUISettings type from tsutils.ts (type-only, no runtime dep)
318
+ * query from query.js (DOM helper)
237
319
  */
238
- /** RGB(A) color as returned by parseColor() */
239
- interface TsColorRgb {
240
- r: number;
241
- g: number;
242
- b: number;
243
- a: number;
320
+
321
+ /** Promise-chain handle returned by message() / confirm() / prompt() */
322
+ interface TsMessageProm {
323
+ self: TsBase;
324
+ action(callBack: (event: unknown) => void): TsMessageProm;
325
+ close(callBack: (event: unknown) => void): TsMessageProm;
326
+ open(callBack: (event: unknown) => void): TsMessageProm;
327
+ then(callBack: (event: unknown) => void): TsMessageProm;
328
+ change?: (callBack: (event: unknown) => void) => TsMessageProm;
329
+ [key: string]: unknown;
330
+ }
331
+ /** Where-descriptor for message() */
332
+ interface TsMessageWhere {
333
+ box: string | Element | null;
334
+ after?: string | Element | null;
335
+ owner?: {
336
+ name?: string;
337
+ lock?: (...args: unknown[]) => void;
338
+ unlock?: (...args: unknown[]) => void;
339
+ focus?: () => void;
340
+ };
341
+ param?: unknown;
342
+ }
343
+ /** Options for message() */
344
+ interface TsMessageOptions {
345
+ width?: number;
346
+ height?: number;
347
+ text?: string | null;
348
+ body?: string;
349
+ buttons?: string;
350
+ html?: string;
351
+ focus?: number | string | null;
352
+ hideOn?: string[];
353
+ actions?: Record<string, unknown>;
354
+ cancelAction?: string;
355
+ on?: unknown;
356
+ onOpen?: unknown;
357
+ onClose?: unknown;
358
+ onAction?: unknown;
359
+ originalWidth?: number;
360
+ originalHeight?: number;
361
+ msgIndex?: number;
362
+ tmp?: {
363
+ zIndex: string;
364
+ overflow: string;
365
+ };
366
+ input?: Element | null;
367
+ box?: Element | null;
368
+ trigger?: (event: string, data: Record<string, unknown>) => unknown;
369
+ close?: () => void;
370
+ setFocus?: (focus: number | string | null | undefined) => void;
371
+ action?: (action: string, event: unknown) => void;
372
+ [key: string]: unknown;
244
373
  }
245
374
 
246
375
  /**
247
- * TsUtils v2.1 — Data / Object helpers sub-module (Phase 3+4 of v2.1 SDD)
376
+ * TsUtils DOM sub-module Phase 5b of v2.4 SDD.
377
+ * DAG position: leaf module (no tsbase/tsutils imports).
248
378
  *
249
- * Contains: TsCloneOptions, clone, extend,
250
- * naturalCompare, normMenu, getNested, encodeParams,
251
- * prepareParams, parseRoute, debounce, wait
379
+ * Imports: ./tsutils-string.js (_encodeTags), ./tsutils-type-guards.js (_isInt),
380
+ * ./tsutils-data.js (_extend), ./query.js (query, Query), DOM globals only.
381
+ * 4-space indent convention.
252
382
  *
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
383
+ * INV-4: MUST NOT import from tsbase.ts or tsutils.ts.
384
+ * INV-8: No arguments.length usage.
385
+ * INV-9: No this.X in exported function bodies.
258
386
  */
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;
269
- }
270
- /** Options for TsUtils.normMenu() */
271
- interface TsNormMenuOptions {
272
- itemMap?: {
273
- id: string;
274
- text: string;
275
- };
276
- [key: string]: unknown;
387
+ /** Options for TsUtils.lock() — moved from tsutils.ts (Phase 5a of v2.4 SDD) */
388
+ interface TsLockOptions {
389
+ msg?: string | number;
390
+ spinner?: boolean;
391
+ opacity?: number;
392
+ bgColor?: string;
393
+ onClick?: () => void;
277
394
  }
278
395
 
279
396
  /**
@@ -310,7 +427,6 @@ interface TsNormMenuOptions {
310
427
  */
311
428
 
312
429
  declare const query: (selector: unknown, context?: unknown) => Query;
313
- declare const TsUi: Record<string, unknown>;
314
430
  /** Settings object merged from TsLocale + user locale overrides */
315
431
  interface TsUISettings {
316
432
  dataType: string;
@@ -336,29 +452,6 @@ interface TsUISettings {
336
452
  locale?: string;
337
453
  [key: string]: unknown;
338
454
  }
339
- /** Extra data passed to grid cell formatters */
340
- interface TsFormatterExtra {
341
- value: unknown;
342
- params?: unknown;
343
- record?: unknown;
344
- [key: string]: unknown;
345
- }
346
- /** Signature of a grid-cell formatter function */
347
- type TsFormatter = (record: TsFormatterExtra, extra?: TsFormatterExtra) => string;
348
- /** Options for TsUtils.lock() */
349
- interface TsLockOptions {
350
- msg?: string | number;
351
- spinner?: boolean;
352
- opacity?: number;
353
- bgColor?: string;
354
- onClick?: () => void;
355
- }
356
- /** Return value from TsUtils.isTime() when retTime === true */
357
- interface TsTimeResult {
358
- hours: number;
359
- minutes: number;
360
- seconds: number;
361
- }
362
455
 
363
456
  /** A normalized menu item */
364
457
  interface TsMenuItem {
@@ -370,59 +463,6 @@ interface TsMenuItem {
370
463
  attrs?: string;
371
464
  [key: string]: unknown;
372
465
  }
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
466
  declare class Utils {
427
467
  version: string;
428
468
  tmp: Record<string, unknown>;
@@ -554,11 +594,11 @@ declare class Utils {
554
594
  notify(text: string | Record<string, unknown>, options?: Record<string, unknown>): Promise<void>;
555
595
  getSize(el: unknown, type: string): number;
556
596
  getStrDimentions(str: string, styles?: string, raw?: boolean): {
557
- width: any;
558
- height: any;
597
+ width: number;
598
+ height: number;
559
599
  };
560
- getStrWidth(str: string, styles?: string, raw?: boolean): any;
561
- getStrHeight(str: string, styles?: string, raw?: boolean): any;
600
+ getStrWidth(str: string, styles?: string, raw?: boolean): number;
601
+ getStrHeight(str: string, styles?: string, raw?: boolean): number;
562
602
  execTemplate(str: any, replace_obj: any): any;
563
603
  marker(el: any, items: any, options?: any): unknown;
564
604
  lang(phrase: string, params?: Record<string, string | number> | boolean): string;
@@ -1446,17 +1486,6 @@ declare class TsLayout extends TsBase {
1446
1486
  *
1447
1487
  * @module types
1448
1488
  */
1449
- /**
1450
- * Creates a branded (nominal) type from a base type K and brand tag T.
1451
- *
1452
- * @example
1453
- * type UserId = Brand<number, 'UserId'>
1454
- *
1455
- * @internal
1456
- */
1457
- type Brand<K, T> = K & {
1458
- readonly __brand: T;
1459
- };
1460
1489
  /**
1461
1490
  * A record identifier value — the `recid` field used across TsGrid records.
1462
1491
  * Can be either a string or a number at runtime; branded to prevent mixing