@tx-angular-design-system/ui-kit 0.1.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.
@@ -0,0 +1,3697 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { WritableSignal, InjectionToken, Signal, TemplateRef } from '@angular/core';
3
+ import * as _tx_angular_design_system_ui_kit from '@tx-angular-design-system/ui-kit';
4
+ import { ControlValueAccessor } from '@angular/forms';
5
+ import { Combobox } from '@angular/aria/combobox';
6
+ import { CdkDragDrop } from '@angular/cdk/drag-drop';
7
+ import { DialogRef } from '@angular/cdk/dialog';
8
+ import { ComponentType } from '@angular/cdk/portal';
9
+
10
+ /**
11
+ * A process-unique DOM id.
12
+ *
13
+ * Used for label/control/description wiring. Ids only ever need to be unique
14
+ * within a document, and every id the kit generates carries the `tx-` prefix so
15
+ * it cannot collide with an application's own.
16
+ */
17
+ declare function txUniqueId(prefix: string): string;
18
+
19
+ /**
20
+ * One selectable option.
21
+ *
22
+ * Options are *data*, not configuration, so components take them through their
23
+ * own `options` input rather than as a field on a config object. That keeps the
24
+ * config interface to simple property-level variation, and lets an application
25
+ * pass an options array straight from a data source without wrapping it.
26
+ *
27
+ * Anything structural — a custom option template — is a `TemplateRef` input on
28
+ * the component, never a field here.
29
+ */
30
+ interface TxOption<T = string> {
31
+ /** The value carried into the component's `value` model. */
32
+ value: T;
33
+ /** Visible text. Also what typeahead matches against. */
34
+ label: string;
35
+ /** Optional second line, shown smaller and muted. */
36
+ description?: string;
37
+ /** Registered icon name shown before the label. */
38
+ icon?: string;
39
+ /** Short text rendered as a badge after the label, e.g. a count or status. */
40
+ badge?: string;
41
+ disabled?: boolean;
42
+ }
43
+ /**
44
+ * A group of options with a heading. Accepted anywhere a flat option list is,
45
+ * for components that support grouping.
46
+ */
47
+ interface TxOptionGroup<T = string> {
48
+ label: string;
49
+ options: TxOption<T>[];
50
+ }
51
+ /** Narrows a mixed list entry to a group. */
52
+ declare function isTxOptionGroup<T>(entry: TxOption<T> | TxOptionGroup<T>): entry is TxOptionGroup<T>;
53
+ /** Flattens a mixed option/group list into plain options, in display order. */
54
+ declare function flattenTxOptions<T>(entries: readonly (TxOption<T> | TxOptionGroup<T>)[]): TxOption<T>[];
55
+
56
+ /**
57
+ * Merges a caller's partial config over a component's defaults.
58
+ *
59
+ * Use this rather than `{ ...DEFAULTS, ...config }`. Object spread copies keys
60
+ * whose value is `undefined`, so a consumer binding an optional value:
61
+ *
62
+ * ```html
63
+ * <tx-button [config]="{ label: 'Save', variant: chosenVariant }" />
64
+ * ```
65
+ *
66
+ * would wipe the default whenever `chosenVariant` happens to be `undefined` —
67
+ * a bug that only shows up for some data. This treats an explicitly-undefined
68
+ * key as absent, which is what the call site reads as.
69
+ *
70
+ * `null`, `false`, `0` and `''` are all kept: those are deliberate values, and
71
+ * falling back from them is the `||` bug this exists to avoid.
72
+ */
73
+ declare function txMergeConfig<T extends object>(defaults: Partial<NoInfer<T>>, config: Partial<NoInfer<T>>): T;
74
+
75
+ /**
76
+ * Shared styling for the text-like control shell.
77
+ *
78
+ * Input, textarea, select, dropdown-tree, chips input and the datepicker
79
+ * trigger all present the same bordered surface with the same focus ring and
80
+ * the same error treatment. Building that string in one place is what stops
81
+ * them drifting apart, and keeps every value a token.
82
+ */
83
+ /** Size of a control. Matches the form field's size vocabulary. */
84
+ type TxControlSize = 'sm' | 'md' | 'lg';
85
+ interface TxControlShellOptions {
86
+ size: TxControlSize;
87
+ /** Renders the error border and keeps the focus ring in the danger colour. */
88
+ invalid: boolean;
89
+ /** Whether the control grows with its content (textarea, chips input). */
90
+ height?: 'fixed' | 'auto';
91
+ }
92
+ /**
93
+ * The bordered control surface: border, background, radius, focus ring,
94
+ * placeholder colour and disabled treatment.
95
+ *
96
+ * Disabled and invalid are styled from real DOM state — the `disabled`
97
+ * attribute and `aria-invalid` — rather than from classes toggled in
98
+ * TypeScript, so the visual state can never disagree with the accessible one.
99
+ */
100
+ declare function txControlShellClass(options: TxControlShellOptions): string;
101
+ /** Icon size that pairs with each control size. */
102
+ declare const CONTROL_ICON_SIZE: Record<TxControlSize, 'sm' | 'md'>;
103
+ /**
104
+ * The chevron. Rotates from `aria-expanded` on the trigger, which carries `group`.
105
+ *
106
+ * `flex` on the wrapper is load-bearing, not decoration. `tx-icon` is an
107
+ * inline-flex box, so inside a wrapper that establishes an inline formatting
108
+ * context it sits on the text baseline and the line box adds the strut's
109
+ * descender space *below* it — around 3px at the control's 14px/1.55 text,
110
+ * which pushes the glyph that far above the trigger's centre line and then
111
+ * visibly shifts it again when `rotate-180` flips it about the wrapper's own
112
+ * centre. Making the wrapper a flex container removes the line box entirely,
113
+ * so its height is the icon's height and `items-center` on the trigger centres
114
+ * the glyph exactly, open or closed.
115
+ */
116
+ declare const TX_TRIGGER_CHEVRON_CLASS: string;
117
+ /** The clear button, sitting immediately before the chevron. */
118
+ declare const TX_TRIGGER_CLEAR_CLASS: string;
119
+
120
+ /**
121
+ * Bridges a `model()` signal to `@angular/forms`.
122
+ *
123
+ * Kit controls expose their value as a `model()` so template-driven signal
124
+ * binding works, and implement `ControlValueAccessor` so reactive forms do too.
125
+ * This holds the small amount of state that both need to agree on, in one
126
+ * place that can be unit-tested without rendering a component.
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * export class TxInputComponent implements ControlValueAccessor {
131
+ * readonly value = model('');
132
+ * private readonly forms = new TxControlValueBridge<string>((v) => this.value.set(v));
133
+ *
134
+ * writeValue(value: string): void { this.forms.writeValue(value); }
135
+ * registerOnChange(fn: (value: string) => void): void { this.forms.registerOnChange(fn); }
136
+ * registerOnTouched(fn: () => void): void { this.forms.registerOnTouched(fn); }
137
+ * setDisabledState(isDisabled: boolean): void { this.forms.setDisabledState(isDisabled); }
138
+ * }
139
+ * ```
140
+ */
141
+ declare class TxControlValueBridge<T> {
142
+ private readonly applyValue;
143
+ private onChange;
144
+ private onTouched;
145
+ /**
146
+ * Disabled state pushed down by a `FormControl`.
147
+ *
148
+ * Kept separate from the config's own `disabled` so the two can be OR'd
149
+ * rather than fighting: a control disabled by its form stays disabled even if
150
+ * the config says otherwise, and vice versa.
151
+ */
152
+ readonly formDisabled: WritableSignal<boolean>;
153
+ constructor(applyValue: (value: T) => void);
154
+ /** Called by forms to push a value in. Does not echo back through onChange. */
155
+ writeValue(value: T): void;
156
+ registerOnChange(fn: (value: T) => void): void;
157
+ registerOnTouched(fn: () => void): void;
158
+ setDisabledState(isDisabled: boolean): void;
159
+ /** Called by the control when the user changes the value. */
160
+ emit(value: T): void;
161
+ /** Called by the control on blur. */
162
+ touch(): void;
163
+ }
164
+
165
+ /** Vertical rhythm/size of a form field and the control inside it. */
166
+ type TxFormFieldSize = 'sm' | 'md' | 'lg';
167
+ /** How the label sits relative to the control. */
168
+ type TxFormFieldLayout = 'stacked' | 'inline';
169
+ /**
170
+ * Simple property configuration for {@link TxFormFieldComponent}.
171
+ *
172
+ * Everything here is optional: a form field with no label is a legitimate way
173
+ * to get consistent hint/error placement around a control.
174
+ */
175
+ interface TxFormFieldConfig {
176
+ /** Visible label text. */
177
+ label?: string;
178
+ /**
179
+ * Keeps the label available to screen readers while hiding it visually —
180
+ * for a control whose purpose is already obvious from context, such as a
181
+ * search box with a magnifier icon.
182
+ */
183
+ labelVisibility?: 'visible' | 'screen-reader-only';
184
+ /** Helper text under the control. Hidden while an error is showing. */
185
+ hint?: string;
186
+ /**
187
+ * Error message. A non-empty value puts the field into its error state and
188
+ * marks the control `aria-invalid` — there is no separate `invalid` flag to
189
+ * keep in step with it.
190
+ */
191
+ error?: string;
192
+ /** Renders a required marker and sets `aria-required` on the control. */
193
+ required?: boolean;
194
+ /** Greys out the label/hint. The control still needs its own `disabled`. */
195
+ disabled?: boolean;
196
+ /** Defaults to `stacked`. */
197
+ layout?: TxFormFieldLayout;
198
+ /** Defaults to `md`. Controls inside inherit this unless they override it. */
199
+ size?: TxFormFieldSize;
200
+ }
201
+ declare const TX_FORM_FIELD_DEFAULTS: {
202
+ readonly labelVisibility: "visible";
203
+ readonly layout: "stacked";
204
+ readonly size: "md";
205
+ };
206
+ /**
207
+ * What a form field exposes to the control projected inside it.
208
+ *
209
+ * Controls inject this optionally: used bare, a control falls back to its own
210
+ * generated id and no described-by, so nothing depends on being wrapped.
211
+ */
212
+ interface TxFormFieldApi {
213
+ /** Id the label's `for` points at. The control must adopt it. */
214
+ readonly controlId: Signal<string>;
215
+ /** Space-joined ids of the hint and/or error, for `aria-describedby`. */
216
+ readonly describedBy: Signal<string | null>;
217
+ /** True while `error` is a non-empty string. */
218
+ readonly invalid: Signal<boolean>;
219
+ readonly required: Signal<boolean>;
220
+ readonly disabled: Signal<boolean>;
221
+ readonly size: Signal<TxFormFieldSize>;
222
+ }
223
+ declare const TX_FORM_FIELD: InjectionToken<TxFormFieldApi>;
224
+
225
+ /**
226
+ * What a control inherits from a surrounding {@link TxFormFieldComponent}.
227
+ * Every value falls back to a standalone default, so no kit control depends on
228
+ * being wrapped.
229
+ */
230
+ interface TxFormFieldBinding {
231
+ /** The control's `id`; the field's label points its `for` at this. */
232
+ readonly id: Signal<string>;
233
+ /** For `aria-describedby` — the hint's or error's id, whichever is showing. */
234
+ readonly describedBy: Signal<string | null>;
235
+ /** True when the field is showing an error. Drives `aria-invalid`. */
236
+ readonly invalid: Signal<boolean>;
237
+ /** Required marker set on the field. Drives `aria-required`. */
238
+ readonly required: Signal<boolean>;
239
+ /** The field's size, or `null` when there is no field to inherit from. */
240
+ readonly size: Signal<TxFormFieldSize | null>;
241
+ }
242
+ /**
243
+ * Connects a control to its surrounding form field.
244
+ *
245
+ * Must be called from an injection context (a field initialiser or the
246
+ * constructor).
247
+ */
248
+ declare function txBindFormField(idPrefix: string): TxFormFieldBinding;
249
+
250
+ /**
251
+ * Shared overlay vocabulary for every popup surface in the kit — select,
252
+ * multiselect, dropdown tree, chips input, autocomplete, menu, datepicker and
253
+ * tooltip all position through the same directive.
254
+ */
255
+ /**
256
+ * Preferred placement of the popup relative to its trigger. Each one carries
257
+ * its own fallback ladder, so a popup near a viewport edge flips rather than
258
+ * being clipped.
259
+ */
260
+ type TxOverlayPlacement = 'bottom-start' | 'bottom-end' | 'bottom-center' | 'top-start' | 'top-end' | 'top-center' | 'right-start' | 'left-start';
261
+ /**
262
+ * How the popup's width relates to its trigger.
263
+ *
264
+ * - `trigger` — exactly the trigger's width. Selects and dropdown trees.
265
+ * - `min-trigger` — at least the trigger's width, wider if content needs it.
266
+ * - `content` — sized purely by content. Menus, tooltips, datepickers.
267
+ */
268
+ type TxOverlayWidth = 'trigger' | 'min-trigger' | 'content';
269
+ /** Why the popup closed. Lets a trigger decide whether to restore focus. */
270
+ type TxOverlayCloseReason = 'escape' | 'outside-click' | 'detach';
271
+ /**
272
+ * Simple property configuration for a connected overlay.
273
+ *
274
+ * Structural content is NOT configured here — the popup body is a
275
+ * `TemplateRef` passed to the directive, never a field on this object.
276
+ */
277
+ interface TxOverlayConfig {
278
+ /** Preferred placement; falls back through a ladder if it does not fit. */
279
+ placement: TxOverlayPlacement;
280
+ /** How the popup's width relates to the trigger's. */
281
+ width: TxOverlayWidth;
282
+ /** Gap between trigger and popup, expressed as a spacing token step. */
283
+ gap: 'none' | 'sm' | 'md';
284
+ /** Close when a pointer event lands outside the popup and its trigger. */
285
+ closeOnOutsideClick: boolean;
286
+ /** Close when Escape is pressed while the popup has focus or activedescendant. */
287
+ closeOnEscape: boolean;
288
+ /** Reposition the popup as ancestors scroll, instead of leaving it behind. */
289
+ repositionOnScroll: boolean;
290
+ }
291
+ declare const TX_OVERLAY_DEFAULTS: TxOverlayConfig;
292
+
293
+ /**
294
+ * Positions a popup template against a trigger element using the CDK overlay.
295
+ *
296
+ * ## Why the portal is attached eagerly
297
+ *
298
+ * `@angular/aria`'s `ComboboxPopup` registers itself with its `Combobox` in
299
+ * `ngOnInit`, and that registration is what gives the trigger its
300
+ * `aria-controls`, its `aria-expanded` wiring and — most importantly — its
301
+ * forwarding of arrow keys into the popup widget. If the popup template were
302
+ * only instantiated on first open, the very first ArrowDown on a closed
303
+ * trigger would have nothing to forward to.
304
+ *
305
+ * So the `TemplatePortal` is attached as soon as the directive initialises,
306
+ * and stays attached for the directive's lifetime. Aria's own `DeferredContent`
307
+ * still creates and destroys the popup *body* in step with `expanded`, so the
308
+ * pane is genuinely empty (and zero-sized) while closed. `open` therefore
309
+ * drives positioning and the scroll strategy, not attachment.
310
+ *
311
+ * The alternative — letting Aria render the popup inline and moving the live
312
+ * node into an overlay with `DomPortal` — was rejected because detaching has
313
+ * to be sequenced against Aria destroying that same view, and we do not
314
+ * control that ordering.
315
+ *
316
+ * @example
317
+ * ```html
318
+ * <div ngCombobox #cb="ngCombobox" [(expanded)]="expanded"
319
+ * [txConnectedOverlay]="popup" [txOverlayOpen]="expanded()">
320
+ * {{ label() }}
321
+ * </div>
322
+ *
323
+ * <ng-template #popup>
324
+ * <ng-template ngComboboxPopup [combobox]="cb">
325
+ * <div ngComboboxWidget ngListbox>…</div>
326
+ * </ng-template>
327
+ * </ng-template>
328
+ * ```
329
+ */
330
+ declare class TxConnectedOverlayDirective {
331
+ private readonly host;
332
+ private readonly viewContainerRef;
333
+ private readonly injector;
334
+ /** The popup body. Structural, so it is a template — never a config field. */
335
+ readonly template: _angular_core.InputSignal<TemplateRef<unknown>>;
336
+ /** Whether the popup is currently shown. */
337
+ readonly open: _angular_core.InputSignal<boolean>;
338
+ /** Trigger to position against. Defaults to the element the directive is on. */
339
+ readonly origin: _angular_core.InputSignal<HTMLElement | undefined>;
340
+ /** Simple property configuration; merged over {@link TX_OVERLAY_DEFAULTS}. */
341
+ readonly config: _angular_core.InputSignal<Partial<TxOverlayConfig>>;
342
+ /** Emitted when the popup asks to close. The trigger owns the open state. */
343
+ readonly closed: _angular_core.OutputEmitterRef<TxOverlayCloseReason>;
344
+ protected readonly resolved: _angular_core.Signal<TxOverlayConfig>;
345
+ private overlayRef;
346
+ private get originElement();
347
+ constructor();
348
+ /** Recomputes position and size. Call after the popup's content changes. */
349
+ reposition(): void;
350
+ private ensureOverlay;
351
+ private applyOpenState;
352
+ private applyWidth;
353
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxConnectedOverlayDirective, never>;
354
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TxConnectedOverlayDirective, "[txConnectedOverlay]", ["txConnectedOverlay"], { "template": { "alias": "txConnectedOverlay"; "required": true; "isSignal": true; }; "open": { "alias": "txOverlayOpen"; "required": false; "isSignal": true; }; "origin": { "alias": "txOverlayOrigin"; "required": false; "isSignal": true; }; "config": { "alias": "txOverlayConfig"; "required": false; "isSignal": true; }; }, { "closed": "closed"; }, never, never, true, never>;
355
+ }
356
+
357
+ /**
358
+ * A registered icon.
359
+ *
360
+ * Only the *inner* markup is stored — the `<svg>` wrapper, its viewBox and its
361
+ * paint attributes are rendered by `TxIconComponent`, so a registered icon can
362
+ * never override the element's sizing or accessibility attributes.
363
+ */
364
+ interface TxIconDefinition {
365
+ /**
366
+ * Inner SVG markup: `<path>`, `<circle>`, `<rect>`, `<g>` and friends.
367
+ * Must NOT include an `<svg>` wrapper.
368
+ */
369
+ body: string;
370
+ /** Defaults to the kit's 24x24 grid. */
371
+ viewBox?: string;
372
+ /**
373
+ * `stroke` (default) matches the kit's line-drawn icon language;
374
+ * `fill` suits solid glyphs and brand marks.
375
+ */
376
+ paint?: 'stroke' | 'fill';
377
+ }
378
+ /** Icon size, aligned to the control heights so icons sit on the text baseline. */
379
+ type TxIconSize = 'sm' | 'md' | 'lg' | 'inherit';
380
+ /**
381
+ * Simple property configuration for {@link TxIconComponent}.
382
+ *
383
+ * `name` is genuinely required — an icon with no name has nothing to draw.
384
+ */
385
+ interface TxIconConfig {
386
+ /** Registered icon name. Unknown names render nothing and warn in dev mode. */
387
+ name: string;
388
+ /** Defaults to `md`. `inherit` scales with the surrounding font size. */
389
+ size?: TxIconSize;
390
+ /**
391
+ * Accessible label. Omit for decorative icons (the default), which are
392
+ * marked `aria-hidden` so screen readers skip them.
393
+ */
394
+ label?: string;
395
+ }
396
+ declare const TX_ICON_DEFAULTS: {
397
+ readonly size: "md";
398
+ };
399
+
400
+ /**
401
+ * The icon set every consumer gets for free.
402
+ *
403
+ * Drawn on a 24x24 grid in one line-drawn language (round caps and joins,
404
+ * `currentColor` stroke) so a mixed row of icons reads as one family. Names are
405
+ * descriptive of the glyph, never of a use case — `clipboard-check`, not
406
+ * `reports` — so no application's vocabulary leaks into the library.
407
+ *
408
+ * Register your own with `TxIconRegistry.register()`; a custom icon of the same
409
+ * name replaces the default.
410
+ */
411
+ declare const TX_DEFAULT_ICONS: Readonly<Record<string, TxIconDefinition>>;
412
+
413
+ /**
414
+ * Holds the kit's icons and any the application registers.
415
+ *
416
+ * Icon bodies are parsed once into real SVG nodes and cached. Nothing goes
417
+ * through `innerHTML` or `bypassSecurityTrust*`: the parsed tree is walked and
418
+ * every element outside {@link ALLOWED_ELEMENTS}, every `on*` handler and every
419
+ * scripting URL is stripped before the fragment is ever attached. Registering
420
+ * an icon is therefore safe even for markup you did not author, though the
421
+ * intended use is still SVG you control.
422
+ */
423
+ declare class TxIconRegistry {
424
+ private readonly definitions;
425
+ private readonly parsed;
426
+ /** Bumped on every mutation so rendered icons re-resolve their name. */
427
+ readonly revision: _angular_core.WritableSignal<number>;
428
+ /** Registers (or replaces) a single icon. */
429
+ register(name: string, definition: TxIconDefinition | string): void;
430
+ /**
431
+ * Registers (or replaces) many icons at once.
432
+ *
433
+ * @example
434
+ * ```ts
435
+ * inject(TxIconRegistry).registerAll({
436
+ * 'company-logo': { body: '<path d="…"/>', paint: 'fill' },
437
+ * });
438
+ * ```
439
+ */
440
+ registerAll(icons: Record<string, TxIconDefinition | string>): void;
441
+ /** Whether an icon is registered under this name. */
442
+ has(name: string): boolean;
443
+ /** Every registered name, sorted. Useful for building an icon browser. */
444
+ names(): string[];
445
+ /** The raw definition, for reading `viewBox` and `paint`. */
446
+ definition(name: string): TxIconDefinition | undefined;
447
+ /**
448
+ * A fresh clone of the icon's sanitised nodes, ready to append.
449
+ * Returns `null` for an unknown name.
450
+ */
451
+ resolve(name: string): DocumentFragment | null;
452
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxIconRegistry, never>;
453
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<TxIconRegistry>;
454
+ }
455
+
456
+ /**
457
+ * Renders a registered icon.
458
+ *
459
+ * Decorative by default (`aria-hidden`); give the config a `label` to expose it
460
+ * as an image to assistive technology. Colour comes from `currentColor`, so an
461
+ * icon inherits whatever text colour its context sets — no icon ever needs a
462
+ * colour of its own.
463
+ *
464
+ * @example
465
+ * ```html
466
+ * <tx-icon [config]="{ name: 'chevron-down' }" />
467
+ * <tx-icon [config]="{ name: 'trash', size: 'sm', label: 'Delete row' }" />
468
+ * ```
469
+ *
470
+ * Config is a signal input, so update it by replacing the object:
471
+ * `this.iconConfig = { ...this.iconConfig, name: 'check' }`.
472
+ */
473
+ declare class TxIconComponent {
474
+ private readonly registry;
475
+ private readonly svg;
476
+ readonly config: _angular_core.InputSignal<TxIconConfig>;
477
+ protected readonly label: _angular_core.Signal<string | null>;
478
+ protected readonly viewBox: _angular_core.Signal<string>;
479
+ protected readonly svgClass: _angular_core.Signal<string>;
480
+ constructor();
481
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxIconComponent, never>;
482
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxIconComponent, "tx-icon", never, { "config": { "alias": "config"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
483
+ }
484
+
485
+ /**
486
+ * Label / hint / error / required-marker chrome around a form control.
487
+ *
488
+ * Wraps any control — the kit's or your own — and wires up the accessible
489
+ * relationships: the label's `for`, `aria-describedby` for the hint and error,
490
+ * and `aria-invalid` / `aria-required` on the control. Kit controls pick these
491
+ * up by injecting {@link TX_FORM_FIELD}; a plain `<input>` can use the exported
492
+ * `controlId` from the template reference instead.
493
+ *
494
+ * @example
495
+ * ```html
496
+ * <tx-form-field [config]="{ label: 'Part number', required: true, hint: 'As printed on the label' }">
497
+ * <tx-input [config]="{ placeholder: 'e.g. 44-2201' }" [(value)]="partNumber" />
498
+ * </tx-form-field>
499
+ * ```
500
+ *
501
+ * Config is a signal input, so update it by replacing the object rather than
502
+ * mutating it: `this.fieldConfig = { ...this.fieldConfig, error: 'Required' }`.
503
+ */
504
+ declare class TxFormFieldComponent implements TxFormFieldApi {
505
+ readonly config: _angular_core.InputSignal<Partial<TxFormFieldConfig>>;
506
+ private readonly resolved;
507
+ protected readonly hintId: string;
508
+ protected readonly errorId: string;
509
+ /** Stable for the component's lifetime; the label's `for` and the control's `id`. */
510
+ readonly controlId: _angular_core.Signal<string>;
511
+ private readonly generatedId;
512
+ protected readonly label: _angular_core.Signal<string | null>;
513
+ protected readonly hint: _angular_core.Signal<string | null>;
514
+ protected readonly error: _angular_core.Signal<string | null>;
515
+ readonly invalid: _angular_core.Signal<boolean>;
516
+ readonly required: _angular_core.Signal<boolean>;
517
+ readonly disabled: _angular_core.Signal<boolean>;
518
+ readonly size: _angular_core.Signal<_tx_angular_design_system_ui_kit.TxFormFieldSize>;
519
+ readonly describedBy: _angular_core.Signal<string | null>;
520
+ protected readonly wrapperClass: _angular_core.Signal<"flex flex-col gap-tx-1 sm:flex-row sm:items-baseline sm:gap-tx-3" | "flex flex-col gap-tx-1-5">;
521
+ protected readonly labelClass: _angular_core.Signal<string>;
522
+ protected readonly hintClass: _angular_core.Signal<string>;
523
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxFormFieldComponent, never>;
524
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxFormFieldComponent, "tx-form-field", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
525
+ }
526
+
527
+ /**
528
+ * Visual weight of a button.
529
+ *
530
+ * `primary` is the emphasis action (outlined in the brand colour, filling on
531
+ * hover); `accent` is the solid dark button used for a page's single dominant
532
+ * action; `secondary` is the neutral outlined default; `ghost` is the quiet
533
+ * action that only gains a border on hover; `danger` is destructive.
534
+ */
535
+ type TxButtonVariant = 'primary' | 'accent' | 'secondary' | 'ghost' | 'danger';
536
+ type TxButtonSize = 'sm' | 'md' | 'lg';
537
+ /** Where an icon sits relative to the label. */
538
+ type TxButtonIconPosition = 'leading' | 'trailing';
539
+ /**
540
+ * Whether the label is rendered or used only as the accessible name.
541
+ * `icon-only` requires `icon` to be set.
542
+ */
543
+ type TxButtonDisplay = 'label' | 'icon-only';
544
+ /**
545
+ * Simple property configuration for {@link TxButtonComponent}.
546
+ *
547
+ * `label` is genuinely required, including for `icon-only` buttons where it
548
+ * becomes the accessible name — an unlabelled icon button is unusable with a
549
+ * screen reader, so there is no way to omit it.
550
+ */
551
+ interface TxButtonConfig {
552
+ label: string;
553
+ /** Defaults to `secondary`. */
554
+ variant?: TxButtonVariant;
555
+ /** Defaults to `md`. */
556
+ size?: TxButtonSize;
557
+ /** Registered icon name. */
558
+ icon?: string;
559
+ /** Defaults to `leading`. Ignored when `display` is `icon-only`. */
560
+ iconPosition?: TxButtonIconPosition;
561
+ /** Defaults to `label`. */
562
+ display?: TxButtonDisplay;
563
+ /** Native button type. Defaults to `button` so it never submits by accident. */
564
+ type?: 'button' | 'submit' | 'reset';
565
+ /** Defaults to `auto`. `full` stretches to the container. */
566
+ width?: 'auto' | 'full';
567
+ disabled?: boolean;
568
+ /** Swaps the icon for a spinner, marks `aria-busy` and blocks activation. */
569
+ loading?: boolean;
570
+ }
571
+ declare const TX_BUTTON_DEFAULTS: {
572
+ readonly variant: "secondary";
573
+ readonly size: "md";
574
+ readonly iconPosition: "leading";
575
+ readonly display: "label";
576
+ readonly type: "button";
577
+ readonly width: "auto";
578
+ };
579
+
580
+ /**
581
+ * A button.
582
+ *
583
+ * Renders a native `<button>`, so keyboard activation, form participation and
584
+ * the disabled semantics are the platform's rather than ours.
585
+ *
586
+ * @example
587
+ * ```html
588
+ * <tx-button [config]="saveConfig" (clicked)="save()" />
589
+ * ```
590
+ * ```ts
591
+ * saveConfig: TxButtonConfig = { label: 'Save', variant: 'primary', icon: 'check' };
592
+ * ```
593
+ *
594
+ * Config is a signal input, so updates happen by passing a new object
595
+ * reference, never by mutating in place:
596
+ * ```ts
597
+ * this.saveConfig = { ...this.saveConfig, loading: true };
598
+ * ```
599
+ */
600
+ declare class TxButtonComponent {
601
+ readonly config: _angular_core.InputSignal<TxButtonConfig>;
602
+ /** Native click. Behaviour never lives in the config object. */
603
+ readonly clicked: _angular_core.OutputEmitterRef<MouseEvent>;
604
+ private readonly resolved;
605
+ protected readonly label: _angular_core.Signal<string>;
606
+ protected readonly icon: _angular_core.Signal<string | null>;
607
+ protected readonly iconPosition: _angular_core.Signal<_tx_angular_design_system_ui_kit.TxButtonIconPosition | undefined>;
608
+ protected readonly type: _angular_core.Signal<"button" | "submit" | "reset" | undefined>;
609
+ protected readonly loading: _angular_core.Signal<boolean>;
610
+ protected readonly iconOnly: _angular_core.Signal<boolean>;
611
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
612
+ protected readonly iconSize: _angular_core.Signal<"sm" | "md" | "lg">;
613
+ protected readonly hostClass: _angular_core.Signal<"block w-full" | "inline-block">;
614
+ protected readonly buttonClass: _angular_core.Signal<string>;
615
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxButtonComponent, never>;
616
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxButtonComponent, "tx-button", never, { "config": { "alias": "config"; "required": true; "isSignal": true; }; }, { "clicked": "clicked"; }, never, never, true, never>;
617
+ }
618
+
619
+ /** Text-like input types. Checkbox/radio/date have their own components. */
620
+ type TxInputType = 'text' | 'email' | 'password' | 'search' | 'tel' | 'url' | 'number';
621
+ /**
622
+ * Simple property configuration for {@link TxInputComponent}.
623
+ *
624
+ * Everything is optional: `<tx-input />` with no config is a valid text box.
625
+ */
626
+ interface TxInputConfig {
627
+ /** Defaults to `text`. */
628
+ type?: TxInputType;
629
+ placeholder?: string;
630
+ /** Defaults to the surrounding form field's size, else `md`. */
631
+ size?: TxControlSize;
632
+ disabled?: boolean;
633
+ readonly?: boolean;
634
+ /**
635
+ * Marks the input required. A surrounding form field's `required` also
636
+ * applies, so this only needs setting on a bare input.
637
+ */
638
+ required?: boolean;
639
+ /**
640
+ * Forces the error appearance on a bare input. Inside a form field the
641
+ * field's `error` message already drives this, and the two are OR'd.
642
+ */
643
+ invalid?: boolean;
644
+ /** Registered icon name shown inside the leading edge. */
645
+ iconStart?: string;
646
+ /** Registered icon name shown inside the trailing edge. */
647
+ iconEnd?: string;
648
+ /** Shows a clear button once the input has a value. */
649
+ clearable?: boolean;
650
+ /** Native `name`, for uncontrolled form submission. */
651
+ name?: string;
652
+ /** Native `autocomplete` token. */
653
+ autocomplete?: string;
654
+ maxLength?: number;
655
+ /** Native `min`/`max`/`step`, meaningful for `type: 'number'`. */
656
+ min?: number;
657
+ max?: number;
658
+ step?: number;
659
+ /** Accessible name for a bare input with no surrounding form field. */
660
+ ariaLabel?: string;
661
+ }
662
+ declare const TX_INPUT_DEFAULTS: {
663
+ readonly type: "text";
664
+ };
665
+
666
+ /**
667
+ * A single-line text input.
668
+ *
669
+ * Renders a native `<input>`. Works three ways: with `[(value)]`, with
670
+ * `[formControl]` / `formControlName`, or uncontrolled with a `name`.
671
+ *
672
+ * @example
673
+ * ```html
674
+ * <tx-form-field [config]="{ label: 'Part number', required: true }">
675
+ * <tx-input [config]="{ placeholder: 'e.g. 44-2201', iconStart: 'search', clearable: true }"
676
+ * [(value)]="partNumber" />
677
+ * </tx-form-field>
678
+ * ```
679
+ *
680
+ * Config is a signal input — replace the object to change it:
681
+ * `this.inputConfig = { ...this.inputConfig, disabled: true }`.
682
+ */
683
+ declare class TxInputComponent implements ControlValueAccessor {
684
+ readonly config: _angular_core.InputSignal<Partial<TxInputConfig>>;
685
+ /** Two-way bindable value. Also driven by `formControl` via CVA. */
686
+ readonly value: _angular_core.ModelSignal<string>;
687
+ /** Fires on the native `change` event, i.e. on commit rather than per key. */
688
+ readonly changed: _angular_core.OutputEmitterRef<string>;
689
+ /** Fires when the clear button empties the input. */
690
+ readonly cleared: _angular_core.OutputEmitterRef<void>;
691
+ private readonly field;
692
+ private readonly formField;
693
+ private readonly forms;
694
+ protected readonly fieldId: _angular_core.Signal<string>;
695
+ protected readonly describedBy: _angular_core.Signal<string | null>;
696
+ private readonly resolved;
697
+ protected readonly type: _angular_core.Signal<_tx_angular_design_system_ui_kit.TxInputType | undefined>;
698
+ protected readonly placeholder: _angular_core.Signal<string | null>;
699
+ protected readonly iconStart: _angular_core.Signal<string | null>;
700
+ protected readonly iconEnd: _angular_core.Signal<string | null>;
701
+ protected readonly isReadonly: _angular_core.Signal<boolean>;
702
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
703
+ protected readonly isInvalid: _angular_core.Signal<boolean>;
704
+ protected readonly isRequired: _angular_core.Signal<boolean>;
705
+ protected readonly size: _angular_core.Signal<"sm" | "md" | "lg">;
706
+ protected readonly iconSize: _angular_core.Signal<"sm" | "md">;
707
+ protected readonly showClear: _angular_core.Signal<boolean>;
708
+ protected readonly inputClass: _angular_core.Signal<string>;
709
+ /** Moves focus into the input. */
710
+ focus(): void;
711
+ protected onInput(event: Event): void;
712
+ protected onBlur(): void;
713
+ protected clear(): void;
714
+ writeValue(value: string): void;
715
+ registerOnChange(fn: (value: string) => void): void;
716
+ registerOnTouched(fn: () => void): void;
717
+ setDisabledState(isDisabled: boolean): void;
718
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxInputComponent, never>;
719
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxInputComponent, "tx-input", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; "cleared": "cleared"; }, never, never, true, never>;
720
+ }
721
+
722
+ /** How the textarea handles growth. */
723
+ type TxTextareaResize = 'vertical' | 'none' | 'auto';
724
+ /** Simple property configuration for {@link TxTextareaComponent}. */
725
+ interface TxTextareaConfig {
726
+ placeholder?: string;
727
+ /** Defaults to the surrounding form field's size, else `md`. */
728
+ size?: TxControlSize;
729
+ /** Visible rows before scrolling. Defaults to 3. */
730
+ rows?: number;
731
+ /**
732
+ * `vertical` (default) lets the user drag to resize; `none` locks the height;
733
+ * `auto` grows the textarea to fit its content and hides the drag handle.
734
+ */
735
+ resize?: TxTextareaResize;
736
+ disabled?: boolean;
737
+ readonly?: boolean;
738
+ required?: boolean;
739
+ invalid?: boolean;
740
+ maxLength?: number;
741
+ /** Shows a live "n / max" counter. Requires `maxLength`. */
742
+ showCount?: boolean;
743
+ name?: string;
744
+ ariaLabel?: string;
745
+ }
746
+ declare const TX_TEXTAREA_DEFAULTS: {
747
+ readonly rows: 3;
748
+ readonly resize: "vertical";
749
+ };
750
+ /**
751
+ * A multi-line text input.
752
+ *
753
+ * @example
754
+ * ```html
755
+ * <tx-form-field [config]="{ label: 'Failure description', required: true }">
756
+ * <tx-textarea [config]="{ rows: 5, maxLength: 500, showCount: true }"
757
+ * [(value)]="description" />
758
+ * </tx-form-field>
759
+ * ```
760
+ *
761
+ * Config is a signal input — replace the object rather than mutating it.
762
+ */
763
+ declare class TxTextareaComponent implements ControlValueAccessor {
764
+ readonly config: _angular_core.InputSignal<Partial<TxTextareaConfig>>;
765
+ readonly value: _angular_core.ModelSignal<string>;
766
+ readonly changed: _angular_core.OutputEmitterRef<string>;
767
+ private readonly field;
768
+ private readonly formField;
769
+ private readonly forms;
770
+ protected readonly fieldId: _angular_core.Signal<string>;
771
+ protected readonly describedBy: _angular_core.Signal<string | null>;
772
+ private readonly resolved;
773
+ protected readonly rows: _angular_core.Signal<number | undefined>;
774
+ protected readonly placeholder: _angular_core.Signal<string | null>;
775
+ protected readonly isReadonly: _angular_core.Signal<boolean>;
776
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
777
+ protected readonly isInvalid: _angular_core.Signal<boolean>;
778
+ protected readonly isRequired: _angular_core.Signal<boolean>;
779
+ protected readonly size: _angular_core.Signal<"sm" | "md" | "lg">;
780
+ protected readonly showCount: _angular_core.Signal<boolean>;
781
+ protected readonly overLimit: _angular_core.Signal<boolean>;
782
+ protected readonly textareaClass: _angular_core.Signal<string>;
783
+ constructor();
784
+ /** Moves focus into the textarea. */
785
+ focus(): void;
786
+ protected onInput(event: Event): void;
787
+ protected onBlur(): void;
788
+ writeValue(value: string): void;
789
+ registerOnChange(fn: (value: string) => void): void;
790
+ registerOnTouched(fn: () => void): void;
791
+ setDisabledState(isDisabled: boolean): void;
792
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxTextareaComponent, never>;
793
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxTextareaComponent, "tx-textarea", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; }, never, never, true, never>;
794
+ }
795
+
796
+ /** Simple property configuration for {@link TxCheckboxComponent}. */
797
+ interface TxCheckboxConfig {
798
+ /**
799
+ * Inline label beside the box. Omit when a surrounding form field already
800
+ * labels the control.
801
+ */
802
+ label?: string;
803
+ /** Second line under the label, for the "what does this actually do" text. */
804
+ description?: string;
805
+ /** Defaults to the surrounding form field's size, else `md`. */
806
+ size?: TxControlSize;
807
+ /** Defaults to `after`. */
808
+ labelPosition?: 'after' | 'before';
809
+ /**
810
+ * Renders the mixed state. Indeterminate is a presentation of a tri-state
811
+ * parent, so it is separate from `value` rather than a third value.
812
+ */
813
+ indeterminate?: boolean;
814
+ disabled?: boolean;
815
+ required?: boolean;
816
+ invalid?: boolean;
817
+ name?: string;
818
+ ariaLabel?: string;
819
+ }
820
+ /**
821
+ * A checkbox.
822
+ *
823
+ * A native `input[type=checkbox]` tinted with `accent-color` from the theme, so
824
+ * the platform provides the checked, indeterminate, focus and disabled visuals
825
+ * rather than a re-implementation of them.
826
+ *
827
+ * @example
828
+ * ```html
829
+ * <tx-checkbox [config]="{ label: 'Include retired parts' }" [(checked)]="includeRetired" />
830
+ * ```
831
+ *
832
+ * Config is a signal input — replace the object rather than mutating it.
833
+ */
834
+ declare class TxCheckboxComponent implements ControlValueAccessor {
835
+ readonly config: _angular_core.InputSignal<Partial<TxCheckboxConfig>>;
836
+ readonly checked: _angular_core.ModelSignal<boolean>;
837
+ readonly changed: _angular_core.OutputEmitterRef<boolean>;
838
+ private readonly box;
839
+ private readonly formField;
840
+ private readonly forms;
841
+ protected readonly fieldId: _angular_core.Signal<string>;
842
+ protected readonly describedBy: _angular_core.Signal<string | null>;
843
+ private readonly resolved;
844
+ protected readonly label: _angular_core.Signal<string | null>;
845
+ protected readonly description: _angular_core.Signal<string | null>;
846
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
847
+ protected readonly isInvalid: _angular_core.Signal<boolean>;
848
+ protected readonly isRequired: _angular_core.Signal<boolean>;
849
+ protected readonly size: _angular_core.Signal<"sm" | "md" | "lg">;
850
+ protected readonly labelClass: _angular_core.Signal<string>;
851
+ protected readonly boxClass: _angular_core.Signal<string>;
852
+ protected readonly textClass: _angular_core.Signal<string>;
853
+ constructor();
854
+ /** Moves focus onto the checkbox. */
855
+ focus(): void;
856
+ protected onChange(event: Event): void;
857
+ protected onBlur(): void;
858
+ writeValue(value: boolean): void;
859
+ registerOnChange(fn: (value: boolean) => void): void;
860
+ registerOnTouched(fn: () => void): void;
861
+ setDisabledState(isDisabled: boolean): void;
862
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxCheckboxComponent, never>;
863
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxCheckboxComponent, "tx-checkbox", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "checked": { "alias": "checked"; "required": false; "isSignal": true; }; }, { "checked": "checkedChange"; "changed": "changed"; }, never, never, true, never>;
864
+ }
865
+
866
+ /**
867
+ * How each option is presented.
868
+ *
869
+ * `plain` is a bare radio and label; `card` is a bordered tile that tints when
870
+ * selected, which reads far better when options carry descriptions.
871
+ */
872
+ type TxRadioAppearance = 'plain' | 'card';
873
+ /** Simple property configuration for {@link TxRadioGroupComponent}. */
874
+ interface TxRadioGroupConfig {
875
+ /** Defaults to `vertical`. */
876
+ orientation?: 'vertical' | 'horizontal';
877
+ /** Defaults to `plain`. */
878
+ appearance?: TxRadioAppearance;
879
+ /** Defaults to the surrounding form field's size, else `md`. */
880
+ size?: TxControlSize;
881
+ /** Disables every option at once. Individual options can also be disabled. */
882
+ disabled?: boolean;
883
+ required?: boolean;
884
+ invalid?: boolean;
885
+ /** Shared `name` for the radios. Generated when omitted. */
886
+ name?: string;
887
+ /** Accessible name when there is no surrounding form field. */
888
+ ariaLabel?: string;
889
+ }
890
+ declare const TX_RADIO_GROUP_DEFAULTS: {
891
+ readonly orientation: "vertical";
892
+ readonly appearance: "plain";
893
+ };
894
+ /**
895
+ * A group of mutually exclusive options, built from native radio inputs so
896
+ * arrow-key navigation and the roving tab stop come from the platform.
897
+ *
898
+ * Options are passed as data through `options`, not as a config field.
899
+ *
900
+ * @example
901
+ * ```html
902
+ * <tx-form-field [config]="{ label: 'Origin', required: true }">
903
+ * <tx-radio-group
904
+ * [options]="[{ value: 'field', label: 'Field' }, { value: 'qc', label: 'QC' }]"
905
+ * [config]="{ orientation: 'horizontal' }"
906
+ * [(value)]="origin" />
907
+ * </tx-form-field>
908
+ * ```
909
+ *
910
+ * Config is a signal input — replace the object rather than mutating it.
911
+ */
912
+ declare class TxRadioGroupComponent<T = string> implements ControlValueAccessor {
913
+ readonly config: _angular_core.InputSignal<Partial<TxRadioGroupConfig>>;
914
+ /** The selectable options. Data, so it is its own input. */
915
+ readonly options: _angular_core.InputSignal<readonly TxOption<T>[]>;
916
+ /** Currently selected value, or `null` when nothing is selected. */
917
+ readonly value: _angular_core.ModelSignal<T | null>;
918
+ readonly changed: _angular_core.OutputEmitterRef<T>;
919
+ private readonly formField;
920
+ private readonly forms;
921
+ private readonly fallbackName;
922
+ protected readonly describedBy: _angular_core.Signal<string | null>;
923
+ protected readonly String: StringConstructor;
924
+ private readonly resolved;
925
+ protected readonly orientation: _angular_core.Signal<"vertical" | "horizontal" | undefined>;
926
+ protected readonly groupName: _angular_core.Signal<string>;
927
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
928
+ protected readonly isInvalid: _angular_core.Signal<boolean>;
929
+ protected readonly isRequired: _angular_core.Signal<boolean>;
930
+ protected readonly size: _angular_core.Signal<"sm" | "md" | "lg">;
931
+ protected readonly groupClass: _angular_core.Signal<string>;
932
+ protected readonly boxClass: _angular_core.Signal<string>;
933
+ protected isOptionDisabled(option: TxOption<T>): boolean;
934
+ protected optionClass(option: TxOption<T>): string;
935
+ protected labelClass(option: TxOption<T>): string;
936
+ protected select(option: TxOption<T>): void;
937
+ protected onBlur(): void;
938
+ writeValue(value: T | null): void;
939
+ registerOnChange(fn: (value: T | null) => void): void;
940
+ registerOnTouched(fn: () => void): void;
941
+ setDisabledState(isDisabled: boolean): void;
942
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxRadioGroupComponent<any>, never>;
943
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxRadioGroupComponent<any>, "tx-radio-group", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; }, never, never, true, never>;
944
+ }
945
+
946
+ /** Simple property configuration for {@link TxSwitchComponent}. */
947
+ interface TxSwitchConfig {
948
+ /** Inline label beside the switch. */
949
+ label?: string;
950
+ /** Second line under the label. */
951
+ description?: string;
952
+ /** Defaults to the surrounding form field's size, else `md`. */
953
+ size?: TxControlSize;
954
+ /** Defaults to `after`. */
955
+ labelPosition?: 'after' | 'before';
956
+ disabled?: boolean;
957
+ required?: boolean;
958
+ name?: string;
959
+ ariaLabel?: string;
960
+ }
961
+ /**
962
+ * An on/off switch.
963
+ *
964
+ * A native `input[type=checkbox]` carrying `role="switch"`, as the brief
965
+ * requires — the platform provides keyboard activation, the checked state and
966
+ * the form value, and only the track/thumb appearance is ours. The visual state
967
+ * is driven entirely by the `checked:` variant reading the element's real
968
+ * state, never by classes toggled from TypeScript.
969
+ *
970
+ * @example
971
+ * ```html
972
+ * <tx-switch [config]="{ label: 'Notify on new failures' }" [(checked)]="notify" />
973
+ * ```
974
+ *
975
+ * Config is a signal input — replace the object rather than mutating it.
976
+ */
977
+ declare class TxSwitchComponent implements ControlValueAccessor {
978
+ readonly config: _angular_core.InputSignal<Partial<TxSwitchConfig>>;
979
+ readonly checked: _angular_core.ModelSignal<boolean>;
980
+ readonly changed: _angular_core.OutputEmitterRef<boolean>;
981
+ private readonly control;
982
+ private readonly formField;
983
+ private readonly forms;
984
+ protected readonly fieldId: _angular_core.Signal<string>;
985
+ protected readonly describedBy: _angular_core.Signal<string | null>;
986
+ private readonly resolved;
987
+ protected readonly label: _angular_core.Signal<string | null>;
988
+ protected readonly description: _angular_core.Signal<string | null>;
989
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
990
+ protected readonly isRequired: _angular_core.Signal<boolean>;
991
+ protected readonly size: _angular_core.Signal<"sm" | "md" | "lg">;
992
+ protected readonly labelClass: _angular_core.Signal<string>;
993
+ protected readonly wrapperClass: _angular_core.Signal<string>;
994
+ protected readonly trackClass: _angular_core.Signal<string>;
995
+ protected readonly thumbClass: _angular_core.Signal<string>;
996
+ protected readonly textClass: _angular_core.Signal<string>;
997
+ /** Moves focus onto the switch. */
998
+ focus(): void;
999
+ protected onChange(event: Event): void;
1000
+ protected onBlur(): void;
1001
+ writeValue(value: boolean): void;
1002
+ registerOnChange(fn: (value: boolean) => void): void;
1003
+ registerOnTouched(fn: () => void): void;
1004
+ setDisabledState(isDisabled: boolean): void;
1005
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxSwitchComponent, never>;
1006
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxSwitchComponent, "tx-switch", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "checked": { "alias": "checked"; "required": false; "isSignal": true; }; }, { "checked": "checkedChange"; "changed": "changed"; }, never, never, true, never>;
1007
+ }
1008
+
1009
+ /**
1010
+ * Shared appearance for every popup surface — select, multiselect, dropdown
1011
+ * tree, chips input, autocomplete, menu and the datepicker.
1012
+ *
1013
+ * Interaction state is styled from the attributes `@angular/aria` already
1014
+ * emits, never from booleans mirrored into TypeScript:
1015
+ *
1016
+ * `aria-selected` / `aria-disabled` / `aria-expanded` — Tailwind's built-in
1017
+ * aria variants match `="true"` exactly, so a `false` attribute (which
1018
+ * Angular still renders) does not match.
1019
+ *
1020
+ * `data-active` — the roving "active descendant" marker. This one must be
1021
+ * written as `data-[active=true]:`, because Aria binds a boolean and Angular
1022
+ * renders `data-active="false"` rather than removing the attribute, which
1023
+ * would make a bare `data-active:` match at all times.
1024
+ */
1025
+ /** Popup height, chosen per component through its config. */
1026
+ type TxPopupHeight = 'sm' | 'md' | 'lg';
1027
+ declare const TX_POPUP_MAX_HEIGHT: Record<TxPopupHeight, string>;
1028
+ /**
1029
+ * The popup card itself. `min-h-0` matters: the CDK pane sets a max-height when
1030
+ * the popup would otherwise leave the viewport, and without it the panel would
1031
+ * refuse to shrink and the list would overflow the screen instead of scrolling.
1032
+ */
1033
+ declare const TX_POPUP_PANEL_CLASS: string;
1034
+ /** The scrollable list inside the popup. */
1035
+ declare const TX_POPUP_LIST_CLASS: string;
1036
+ /** One option row. */
1037
+ declare const TX_POPUP_OPTION_CLASS: string;
1038
+ /** Group heading inside a popup list. */
1039
+ declare const TX_POPUP_GROUP_CLASS: string;
1040
+ /** "No results" / "No options" row. */
1041
+ declare const TX_POPUP_EMPTY_CLASS = "px-tx-3 py-tx-5 text-center text-tx-base text-tx-text-muted";
1042
+
1043
+ /**
1044
+ * Simple property configuration for {@link TxSelectComponent} and
1045
+ * {@link TxMultiselectComponent}.
1046
+ *
1047
+ * Options are data and come through the component's own `options` input; a
1048
+ * custom option renderer is structural and comes through `optionTemplate`.
1049
+ * Neither belongs here.
1050
+ */
1051
+ interface TxSelectConfig {
1052
+ /** Shown in the trigger when nothing is selected. */
1053
+ placeholder?: string;
1054
+ /** Defaults to the surrounding form field's size, else `md`. */
1055
+ size?: TxControlSize;
1056
+ /** Defaults to `md`. */
1057
+ popupHeight?: TxPopupHeight;
1058
+ /** Shows a clear button in the trigger once something is selected. */
1059
+ clearable?: boolean;
1060
+ disabled?: boolean;
1061
+ required?: boolean;
1062
+ invalid?: boolean;
1063
+ /** Message shown in the popup when `options` is empty. */
1064
+ emptyText?: string;
1065
+ /** Accessible name when there is no surrounding form field. */
1066
+ ariaLabel?: string;
1067
+ name?: string;
1068
+ }
1069
+ declare const TX_SELECT_DEFAULTS: {
1070
+ readonly placeholder: "Select…";
1071
+ readonly popupHeight: "md";
1072
+ readonly emptyText: "No options";
1073
+ };
1074
+ /**
1075
+ * How a multiselect summarises its selection in the closed trigger.
1076
+ *
1077
+ * A union rather than a pair of booleans, so the states stay mutually
1078
+ * exclusive as more are added.
1079
+ */
1080
+ type TxMultiselectSummary = 'chips' | 'comma' | 'count';
1081
+ /** Simple property configuration for {@link TxMultiselectComponent}. */
1082
+ interface TxMultiselectConfig extends TxSelectConfig {
1083
+ /** Defaults to `chips`. */
1084
+ summary?: TxMultiselectSummary;
1085
+ /**
1086
+ * Above this many selections a `chips` trigger collapses to a count, so a
1087
+ * long selection cannot push the trigger to an unusable height. Defaults to 3.
1088
+ */
1089
+ maxVisibleChips?: number;
1090
+ }
1091
+ declare const TX_MULTISELECT_DEFAULTS: {
1092
+ readonly placeholder: "Select…";
1093
+ readonly summary: "chips";
1094
+ readonly maxVisibleChips: 3;
1095
+ readonly popupHeight: "md";
1096
+ readonly emptyText: "No options";
1097
+ };
1098
+
1099
+ /**
1100
+ * A single-select dropdown.
1101
+ *
1102
+ * Behaviour is `@angular/aria`'s: `ngCombobox` on the trigger provides
1103
+ * `role="combobox"`, `aria-expanded`, `aria-controls`, `aria-activedescendant`
1104
+ * and key forwarding into the popup; `ngListbox`/`ngOption` provide roving
1105
+ * activation, typeahead and selection. Positioning is
1106
+ * {@link TxConnectedOverlayDirective}, which hosts the Aria popup template in a
1107
+ * CDK overlay so it escapes `overflow` clipping and flips near a viewport edge.
1108
+ *
1109
+ * Every visual state is styled from the attributes Aria emits —
1110
+ * `aria-selected`, `aria-disabled`, `aria-expanded`, `data-active` — so nothing
1111
+ * is mirrored into a boolean and toggled from TypeScript.
1112
+ *
1113
+ * The trigger is deliberately assembled so a search box can be added inside it
1114
+ * later without changing this public API: typed-text filtering is out of scope
1115
+ * for v1.
1116
+ *
1117
+ * @example
1118
+ * ```html
1119
+ * <tx-form-field [config]="{ label: 'Disposition', required: true }">
1120
+ * <tx-select [options]="dispositions" [config]="{ clearable: true }" [(value)]="disposition" />
1121
+ * </tx-form-field>
1122
+ * ```
1123
+ *
1124
+ * Config is a signal input — replace the object rather than mutating it:
1125
+ * `this.selectConfig = { ...this.selectConfig, disabled: true }`.
1126
+ */
1127
+ declare class TxSelectComponent<T = string> implements ControlValueAccessor {
1128
+ readonly config: _angular_core.InputSignal<Partial<TxSelectConfig>>;
1129
+ /** The selectable options. Data, so it is its own input. */
1130
+ readonly options: _angular_core.InputSignal<readonly TxOption<T>[]>;
1131
+ /**
1132
+ * Custom option renderer. Structural, so it is a `TemplateRef` input rather
1133
+ * than a config field. Context: `$implicit` is the option, `selected` is a
1134
+ * boolean.
1135
+ */
1136
+ readonly optionTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
1137
+ /** Selected value, or `null`. */
1138
+ readonly value: _angular_core.ModelSignal<T | null>;
1139
+ readonly changed: _angular_core.OutputEmitterRef<T | null>;
1140
+ readonly openedChange: _angular_core.OutputEmitterRef<boolean>;
1141
+ protected readonly expanded: _angular_core.WritableSignal<boolean>;
1142
+ private readonly trigger;
1143
+ private readonly formField;
1144
+ private readonly forms;
1145
+ protected readonly fieldId: _angular_core.Signal<string>;
1146
+ protected readonly describedBy: _angular_core.Signal<string | null>;
1147
+ protected readonly optionClass: string;
1148
+ protected readonly emptyClass = "px-tx-3 py-tx-5 text-center text-tx-base text-tx-text-muted";
1149
+ protected readonly listClass: string;
1150
+ protected readonly overlayConfig: Partial<TxOverlayConfig>;
1151
+ private readonly resolved;
1152
+ protected readonly emptyText: _angular_core.Signal<string | undefined>;
1153
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
1154
+ protected readonly isInvalid: _angular_core.Signal<boolean>;
1155
+ protected readonly isRequired: _angular_core.Signal<boolean>;
1156
+ protected readonly size: _angular_core.Signal<"sm" | "md" | "lg">;
1157
+ protected readonly iconSize: _angular_core.Signal<"sm" | "md">;
1158
+ private readonly selectedOption;
1159
+ protected readonly triggerLabel: _angular_core.Signal<string>;
1160
+ protected readonly showClear: _angular_core.Signal<boolean>;
1161
+ /** Aria's listbox always models its value as an array, even single-select. */
1162
+ protected readonly listboxValue: _angular_core.Signal<T[]>;
1163
+ protected readonly triggerClass: _angular_core.Signal<string>;
1164
+ protected readonly chevronClass: string;
1165
+ protected readonly clearClass: string;
1166
+ protected readonly valueClass: _angular_core.Signal<string>;
1167
+ protected readonly panelClass: _angular_core.Signal<string>;
1168
+ protected onListboxValue(next: T[]): void;
1169
+ protected onOverlayClosed(reason: TxOverlayCloseReason): void;
1170
+ private close;
1171
+ protected clear(event: MouseEvent): void;
1172
+ /** Moves focus onto the trigger. */
1173
+ focus(): void;
1174
+ writeValue(value: T | null): void;
1175
+ registerOnChange(fn: (value: T | null) => void): void;
1176
+ registerOnTouched(fn: () => void): void;
1177
+ setDisabledState(isDisabled: boolean): void;
1178
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxSelectComponent<any>, never>;
1179
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxSelectComponent<any>, "tx-select", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": true; "isSignal": true; }; "optionTemplate": { "alias": "optionTemplate"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; "openedChange": "openedChange"; }, never, never, true, never>;
1180
+ }
1181
+
1182
+ /**
1183
+ * A multi-select dropdown.
1184
+ *
1185
+ * Same Aria machinery as {@link TxSelectComponent}, with `multi` on the listbox
1186
+ * and a popup that stays open across selections. The closed trigger summarises
1187
+ * the selection as chips, a comma-joined list or a count, chosen through the
1188
+ * config's `summary` union rather than a set of booleans.
1189
+ *
1190
+ * @example
1191
+ * ```html
1192
+ * <tx-form-field [config]="{ label: 'Symptoms' }">
1193
+ * <tx-multiselect [options]="symptoms" [config]="{ summary: 'chips' }" [(value)]="selected" />
1194
+ * </tx-form-field>
1195
+ * ```
1196
+ *
1197
+ * Config is a signal input — replace the object rather than mutating it.
1198
+ */
1199
+ declare class TxMultiselectComponent<T = string> implements ControlValueAccessor {
1200
+ readonly config: _angular_core.InputSignal<Partial<TxMultiselectConfig>>;
1201
+ /** The selectable options. Data, so it is its own input. */
1202
+ readonly options: _angular_core.InputSignal<readonly TxOption<T>[]>;
1203
+ /** Custom option renderer. Structural, so a template rather than config. */
1204
+ readonly optionTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
1205
+ /** Selected values. */
1206
+ readonly value: _angular_core.ModelSignal<T[]>;
1207
+ readonly changed: _angular_core.OutputEmitterRef<T[]>;
1208
+ readonly openedChange: _angular_core.OutputEmitterRef<boolean>;
1209
+ protected readonly expanded: _angular_core.WritableSignal<boolean>;
1210
+ private readonly trigger;
1211
+ private readonly formField;
1212
+ private readonly forms;
1213
+ protected readonly fieldId: _angular_core.Signal<string>;
1214
+ protected readonly describedBy: _angular_core.Signal<string | null>;
1215
+ protected readonly optionClass: string;
1216
+ protected readonly emptyClass = "px-tx-3 py-tx-5 text-center text-tx-base text-tx-text-muted";
1217
+ protected readonly listClass: string;
1218
+ protected readonly overlayConfig: Partial<TxOverlayConfig>;
1219
+ private readonly resolved;
1220
+ protected readonly placeholder: _angular_core.Signal<string | undefined>;
1221
+ protected readonly summary: _angular_core.Signal<_tx_angular_design_system_ui_kit.TxMultiselectSummary | undefined>;
1222
+ protected readonly emptyText: _angular_core.Signal<string | undefined>;
1223
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
1224
+ protected readonly isInvalid: _angular_core.Signal<boolean>;
1225
+ protected readonly isRequired: _angular_core.Signal<boolean>;
1226
+ protected readonly size: _angular_core.Signal<"sm" | "md" | "lg">;
1227
+ protected readonly iconSize: _angular_core.Signal<"sm" | "md">;
1228
+ private readonly selectedLabels;
1229
+ protected readonly chips: _angular_core.Signal<{
1230
+ visible: string[];
1231
+ overflow: number;
1232
+ }>;
1233
+ protected readonly summaryText: _angular_core.Signal<string>;
1234
+ protected readonly showClear: _angular_core.Signal<boolean>;
1235
+ protected readonly triggerClass: _angular_core.Signal<string>;
1236
+ protected readonly chevronClass: string;
1237
+ protected readonly clearClass: string;
1238
+ protected readonly panelClass: _angular_core.Signal<string>;
1239
+ protected onListboxValue(next: T[]): void;
1240
+ protected onOverlayClosed(reason: TxOverlayCloseReason): void;
1241
+ protected clear(event: MouseEvent): void;
1242
+ /** Moves focus onto the trigger. */
1243
+ focus(): void;
1244
+ writeValue(value: T[]): void;
1245
+ registerOnChange(fn: (value: T[]) => void): void;
1246
+ registerOnTouched(fn: () => void): void;
1247
+ setDisabledState(isDisabled: boolean): void;
1248
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxMultiselectComponent<any>, never>;
1249
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxMultiselectComponent<any>, "tx-multiselect", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": true; "isSignal": true; }; "optionTemplate": { "alias": "optionTemplate"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; "openedChange": "openedChange"; }, never, never, true, never>;
1250
+ }
1251
+
1252
+ /**
1253
+ * Builds the text a closed multi-select trigger shows.
1254
+ *
1255
+ * Shared by the multiselect and the dropdown tree so the two never drift into
1256
+ * summarising the same selection differently.
1257
+ */
1258
+ declare function txSelectionSummary(labels: readonly string[], mode: 'comma' | 'count', noun?: string): string;
1259
+ /**
1260
+ * Splits labels into the chips to render and the number hidden behind a
1261
+ * "+n" pill, so a long selection cannot grow the trigger without bound.
1262
+ */
1263
+ declare function txVisibleChips(labels: readonly string[], maxVisible: number): {
1264
+ visible: string[];
1265
+ overflow: number;
1266
+ };
1267
+
1268
+ /**
1269
+ * One node in a {@link TxTreeComponent}.
1270
+ *
1271
+ * Nodes are data. Anything structural about how a node is drawn — a leading
1272
+ * control, a badge, trailing actions — is a `TemplateRef` slot on the component,
1273
+ * never a field here.
1274
+ */
1275
+ interface TxTreeNode<T = string> {
1276
+ /** Unique across the whole tree. Carried in the selection value. */
1277
+ id: T;
1278
+ label: string;
1279
+ children?: readonly TxTreeNode<T>[];
1280
+ /** Registered icon name shown before the label. */
1281
+ icon?: string;
1282
+ /** Short text rendered in the default badge slot. */
1283
+ badge?: string;
1284
+ disabled?: boolean;
1285
+ /** Defaults to true. Set false for a node that is a container only. */
1286
+ selectable?: boolean;
1287
+ /** Application payload. Passed back in slot contexts and in outputs. */
1288
+ data?: unknown;
1289
+ }
1290
+ /**
1291
+ * How many nodes may be selected.
1292
+ *
1293
+ * A union rather than a `multi` boolean, so `none` is a first-class state
1294
+ * instead of an absence that has to be inferred.
1295
+ */
1296
+ type TxTreeSelection = 'none' | 'single' | 'multiple';
1297
+ /**
1298
+ * Whether the built-in checkbox indicator fills the leading slot, and for which
1299
+ * nodes. Ignored when a `leadingTemplate` is supplied.
1300
+ */
1301
+ type TxTreeCheckboxes = 'none' | 'all' | 'leaf';
1302
+ /** Whether branches can be collapsed. */
1303
+ type TxTreeExpansion = 'collapsible' | 'static';
1304
+ /** Whether connector lines are drawn between parents and children. */
1305
+ type TxTreeGuides = 'lines' | 'none';
1306
+ /** Simple property configuration for {@link TxTreeComponent}. */
1307
+ interface TxTreeConfig {
1308
+ /** Defaults to `single`. */
1309
+ selection?: TxTreeSelection;
1310
+ /** Defaults to `none`. Pairs naturally with `selection: 'multiple'`. */
1311
+ checkboxes?: TxTreeCheckboxes;
1312
+ /** Defaults to `collapsible`. */
1313
+ expansion?: TxTreeExpansion;
1314
+ /** Defaults to `lines`, matching the reference tree of parts. */
1315
+ guides?: TxTreeGuides;
1316
+ /** Defaults to `md`. */
1317
+ size?: 'sm' | 'md';
1318
+ disabled?: boolean;
1319
+ /** Message shown when `nodes` is empty. */
1320
+ emptyText?: string;
1321
+ /** Accessible name for the tree. */
1322
+ ariaLabel?: string;
1323
+ }
1324
+ declare const TX_TREE_DEFAULTS: {
1325
+ readonly selection: "single";
1326
+ readonly checkboxes: "none";
1327
+ readonly expansion: "collapsible";
1328
+ readonly guides: "lines";
1329
+ readonly size: "md";
1330
+ readonly emptyText: "No items";
1331
+ };
1332
+ /**
1333
+ * Context handed to every tree slot template.
1334
+ *
1335
+ * `$implicit` is the node, so `let-node` works without naming the key.
1336
+ */
1337
+ interface TxTreeSlotContext<T = string> {
1338
+ $implicit: TxTreeNode<T>;
1339
+ node: TxTreeNode<T>;
1340
+ /** 1-based depth, matching `aria-level`. */
1341
+ level: number;
1342
+ selected: boolean;
1343
+ expanded: boolean;
1344
+ hasChildren: boolean;
1345
+ }
1346
+ /** Flattens a node tree into visible rows, honouring collapsed branches. */
1347
+ declare function flattenTxTree<T>(nodes: readonly TxTreeNode<T>[], isExpanded: (node: TxTreeNode<T>) => boolean, level?: number): {
1348
+ node: TxTreeNode<T>;
1349
+ level: number;
1350
+ }[];
1351
+ /** Every node id in the tree, depth-first. */
1352
+ declare function txTreeNodeIds<T>(nodes: readonly TxTreeNode<T>[]): T[];
1353
+ /** Ids of every node that has children, depth-first. */
1354
+ declare function txTreeBranchIds<T>(nodes: readonly TxTreeNode<T>[]): T[];
1355
+ /** Finds a node by id, searching depth-first. */
1356
+ declare function findTxTreeNode<T>(nodes: readonly TxTreeNode<T>[], id: T): TxTreeNode<T> | null;
1357
+
1358
+ /** Simple property configuration for {@link TxDropdownTreeComponent}. */
1359
+ interface TxDropdownTreeConfig {
1360
+ /** Shown in the trigger when nothing is selected. */
1361
+ placeholder?: string;
1362
+ /**
1363
+ * Defaults to `single`: the popup closes on selection. `multiple` keeps the
1364
+ * popup open and turns on the tree's leading checkbox indicator.
1365
+ */
1366
+ selection?: 'single' | 'multiple';
1367
+ /** How a multiple selection is summarised in the closed trigger. Defaults to `chips`. */
1368
+ summary?: TxMultiselectSummary;
1369
+ /** Chips shown before collapsing to a "+n" pill. Defaults to 3. */
1370
+ maxVisibleChips?: number;
1371
+ /** Defaults to the surrounding form field's size, else `md`. */
1372
+ size?: TxControlSize;
1373
+ /** Defaults to `md`. */
1374
+ popupHeight?: TxPopupHeight;
1375
+ /** Forwarded to the tree. Defaults to `all` when selection is `multiple`. */
1376
+ checkboxes?: TxTreeCheckboxes;
1377
+ /** Forwarded to the tree. Defaults to `collapsible`. */
1378
+ expansion?: TxTreeExpansion;
1379
+ /** Forwarded to the tree. Defaults to `lines`. */
1380
+ guides?: TxTreeGuides;
1381
+ clearable?: boolean;
1382
+ disabled?: boolean;
1383
+ required?: boolean;
1384
+ invalid?: boolean;
1385
+ emptyText?: string;
1386
+ ariaLabel?: string;
1387
+ name?: string;
1388
+ }
1389
+ declare const TX_DROPDOWN_TREE_DEFAULTS: {
1390
+ readonly placeholder: "Select…";
1391
+ readonly selection: "single";
1392
+ readonly summary: "chips";
1393
+ readonly maxVisibleChips: 3;
1394
+ readonly popupHeight: "md";
1395
+ readonly expansion: "collapsible";
1396
+ readonly guides: "lines";
1397
+ readonly emptyText: "No items";
1398
+ };
1399
+ /**
1400
+ * A select-style trigger whose popup contains a tree.
1401
+ *
1402
+ * Assembled from the pieces that already exist rather than reimplemented: the
1403
+ * combobox trigger and {@link TxConnectedOverlayDirective} from the select, and
1404
+ * {@link TxTreeComponent} for everything inside the popup. No node-rendering
1405
+ * logic is duplicated — the tree's `comboboxHost` input is the extension point
1406
+ * that lets it act as the combobox's popup widget, so `aria-controls` points at
1407
+ * the real `role="tree"` element and its collapsible behaviour, badge slot and
1408
+ * leading-checkbox slot all work exactly as they do standalone.
1409
+ *
1410
+ * Single-select closes the popup on selection and shows the node's label.
1411
+ * Multi-select keeps the popup open, turns on the tree's checkbox indicator and
1412
+ * summarises the selection in the trigger.
1413
+ *
1414
+ * Typed-text filtering inside the trigger is out of scope for v1. The trigger is
1415
+ * laid out so a search box can be added inside the popup later without changing
1416
+ * this public API.
1417
+ *
1418
+ * @example
1419
+ * ```html
1420
+ * <tx-form-field [config]="{ label: 'Failed part' }">
1421
+ * <tx-dropdown-tree
1422
+ * [nodes]="assemblyTree"
1423
+ * [config]="{ selection: 'multiple', summary: 'chips', clearable: true }"
1424
+ * [(selectedIds)]="failedParts" />
1425
+ * </tx-form-field>
1426
+ * ```
1427
+ *
1428
+ * Config is a signal input — replace the object rather than mutating it.
1429
+ */
1430
+ declare class TxDropdownTreeComponent<T = string> implements ControlValueAccessor {
1431
+ readonly config: _angular_core.InputSignal<Partial<TxDropdownTreeConfig>>;
1432
+ /** The node hierarchy. Data, so it is its own input. */
1433
+ readonly nodes: _angular_core.InputSignal<readonly TxTreeNode<T>[]>;
1434
+ /** Selected node ids. Always an array, including in single-select. */
1435
+ readonly selectedIds: _angular_core.ModelSignal<T[]>;
1436
+ /** Expanded branch ids, forwarded to the tree. */
1437
+ readonly expandedIds: _angular_core.ModelSignal<T[]>;
1438
+ readonly leadingTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
1439
+ readonly badgeTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
1440
+ readonly actionsTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
1441
+ readonly changed: _angular_core.OutputEmitterRef<T[]>;
1442
+ readonly openedChange: _angular_core.OutputEmitterRef<boolean>;
1443
+ protected readonly expanded: _angular_core.WritableSignal<boolean>;
1444
+ private readonly trigger;
1445
+ private readonly formField;
1446
+ private readonly forms;
1447
+ protected readonly fieldId: _angular_core.Signal<string>;
1448
+ protected readonly describedBy: _angular_core.Signal<string | null>;
1449
+ protected readonly overlayConfig: Partial<TxOverlayConfig>;
1450
+ private readonly resolved;
1451
+ protected readonly placeholder: _angular_core.Signal<string | undefined>;
1452
+ protected readonly summary: _angular_core.Signal<TxMultiselectSummary | undefined>;
1453
+ protected readonly isMultiple: _angular_core.Signal<boolean>;
1454
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
1455
+ protected readonly isInvalid: _angular_core.Signal<boolean>;
1456
+ protected readonly isRequired: _angular_core.Signal<boolean>;
1457
+ protected readonly size: _angular_core.Signal<"sm" | "md" | "lg">;
1458
+ protected readonly iconSize: _angular_core.Signal<"sm" | "md">;
1459
+ /** Everything the tree needs, derived from this component's own config. */
1460
+ protected readonly treeConfig: _angular_core.Signal<{
1461
+ selection: "single" | "multiple";
1462
+ checkboxes: TxTreeCheckboxes;
1463
+ expansion: TxTreeExpansion | undefined;
1464
+ guides: TxTreeGuides | undefined;
1465
+ emptyText: string | undefined;
1466
+ size: "sm" | "md";
1467
+ disabled: boolean;
1468
+ }>;
1469
+ private readonly selectedLabels;
1470
+ protected readonly chips: _angular_core.Signal<{
1471
+ visible: string[];
1472
+ overflow: number;
1473
+ }>;
1474
+ protected readonly triggerText: _angular_core.Signal<string>;
1475
+ protected readonly showClear: _angular_core.Signal<boolean>;
1476
+ protected readonly triggerClass: _angular_core.Signal<string>;
1477
+ protected readonly chevronClass: string;
1478
+ protected readonly clearClass: string;
1479
+ protected readonly panelClass: _angular_core.Signal<string>;
1480
+ protected onTreeSelection(next: T[]): void;
1481
+ protected onOverlayClosed(reason: TxOverlayCloseReason): void;
1482
+ private close;
1483
+ protected clear(event: MouseEvent): void;
1484
+ /** Moves focus onto the trigger. */
1485
+ focus(): void;
1486
+ writeValue(value: T[]): void;
1487
+ registerOnChange(fn: (value: T[]) => void): void;
1488
+ registerOnTouched(fn: () => void): void;
1489
+ setDisabledState(isDisabled: boolean): void;
1490
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxDropdownTreeComponent<any>, never>;
1491
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxDropdownTreeComponent<any>, "tx-dropdown-tree", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "nodes": { "alias": "nodes"; "required": true; "isSignal": true; }; "selectedIds": { "alias": "selectedIds"; "required": false; "isSignal": true; }; "expandedIds": { "alias": "expandedIds"; "required": false; "isSignal": true; }; "leadingTemplate": { "alias": "leadingTemplate"; "required": false; "isSignal": true; }; "badgeTemplate": { "alias": "badgeTemplate"; "required": false; "isSignal": true; }; "actionsTemplate": { "alias": "actionsTemplate"; "required": false; "isSignal": true; }; }, { "selectedIds": "selectedIdsChange"; "expandedIds": "expandedIdsChange"; "changed": "changed"; "openedChange": "openedChange"; }, never, never, true, never>;
1492
+ }
1493
+
1494
+ /**
1495
+ * Where new chip values may come from.
1496
+ *
1497
+ * A union rather than `allowFreeText` + `allowSuggestions` booleans, so the
1498
+ * three states stay mutually exclusive as they are added to.
1499
+ */
1500
+ type TxChipsSource = 'free-text' | 'suggestions' | 'both';
1501
+ /** Simple property configuration for {@link TxChipsInputComponent}. */
1502
+ interface TxChipsInputConfig {
1503
+ placeholder?: string;
1504
+ /** Defaults to the surrounding form field's size, else `md`. */
1505
+ size?: TxControlSize;
1506
+ /** Defaults to `both`. */
1507
+ source?: TxChipsSource;
1508
+ /** Defaults to `md`. */
1509
+ popupHeight?: TxPopupHeight;
1510
+ /** Refuses a value already present. Defaults to true. */
1511
+ unique?: boolean;
1512
+ /** Maximum number of chips. Further input is refused once reached. */
1513
+ max?: number;
1514
+ /** Keys that commit the typed text. Defaults to Enter and comma. */
1515
+ commitKeys?: readonly string[];
1516
+ disabled?: boolean;
1517
+ required?: boolean;
1518
+ invalid?: boolean;
1519
+ /** Message shown in the popup when nothing matches. */
1520
+ emptyText?: string;
1521
+ ariaLabel?: string;
1522
+ }
1523
+ declare const TX_CHIPS_INPUT_DEFAULTS: {
1524
+ readonly placeholder: "Add…";
1525
+ readonly source: "both";
1526
+ readonly popupHeight: "md";
1527
+ readonly unique: true;
1528
+ readonly commitKeys: readonly ["Enter", ","];
1529
+ readonly emptyText: "No matches";
1530
+ };
1531
+ /**
1532
+ * A text field that turns entries into removable chips, with an optional
1533
+ * suggestion popup.
1534
+ *
1535
+ * The popup is `@angular/aria`'s combobox and listbox — the same primitives and
1536
+ * the same overlay as the select — driven by an editable `<input>` rather than a
1537
+ * static trigger, which is exactly the autocomplete shape Aria's combobox is
1538
+ * built for. Suggestions filter as you type.
1539
+ *
1540
+ * Backspace on an empty field removes the last chip, matching every chips input
1541
+ * people already know.
1542
+ *
1543
+ * @example
1544
+ * ```html
1545
+ * <tx-form-field [config]="{ label: 'Symptoms' }">
1546
+ * <tx-chips-input
1547
+ * [suggestions]="symptomOptions"
1548
+ * [config]="{ placeholder: 'Add a symptom…', max: 8 }"
1549
+ * [(value)]="symptoms" />
1550
+ * </tx-form-field>
1551
+ * ```
1552
+ *
1553
+ * Config is a signal input — replace the object rather than mutating it.
1554
+ */
1555
+ declare class TxChipsInputComponent implements ControlValueAccessor {
1556
+ readonly config: _angular_core.InputSignal<Partial<TxChipsInputConfig>>;
1557
+ /** Optional suggestions. Data, so it is its own input. */
1558
+ readonly suggestions: _angular_core.InputSignal<readonly TxOption<string>[]>;
1559
+ /** The committed chip values. */
1560
+ readonly value: _angular_core.ModelSignal<string[]>;
1561
+ readonly changed: _angular_core.OutputEmitterRef<string[]>;
1562
+ /** Emitted when a value is refused — duplicate, or over `max`. */
1563
+ readonly rejected: _angular_core.OutputEmitterRef<{
1564
+ value: string;
1565
+ reason: "duplicate" | "max";
1566
+ }>;
1567
+ protected readonly expanded: _angular_core.WritableSignal<boolean>;
1568
+ protected readonly query: _angular_core.WritableSignal<string>;
1569
+ private readonly shell;
1570
+ private readonly field;
1571
+ private readonly formField;
1572
+ private readonly forms;
1573
+ protected readonly fieldId: _angular_core.Signal<string>;
1574
+ protected readonly describedBy: _angular_core.Signal<string | null>;
1575
+ protected readonly optionClass: string;
1576
+ protected readonly emptyClass = "px-tx-3 py-tx-5 text-center text-tx-base text-tx-text-muted";
1577
+ protected readonly listClass: string;
1578
+ protected readonly overlayConfig: Partial<TxOverlayConfig>;
1579
+ private readonly resolved;
1580
+ protected readonly placeholder: _angular_core.Signal<string | undefined>;
1581
+ protected readonly emptyText: _angular_core.Signal<string | undefined>;
1582
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
1583
+ protected readonly isInvalid: _angular_core.Signal<boolean>;
1584
+ protected readonly isRequired: _angular_core.Signal<boolean>;
1585
+ protected readonly size: _angular_core.Signal<"sm" | "md" | "lg">;
1586
+ protected readonly atMax: _angular_core.Signal<boolean>;
1587
+ /** Suggestions matching the query and not already chosen. */
1588
+ protected readonly filtered: _angular_core.Signal<TxOption<string>[]>;
1589
+ protected readonly shellClass: _angular_core.Signal<string>;
1590
+ protected readonly panelClass: _angular_core.Signal<string>;
1591
+ /** The suggestion's label if the chip came from one, else the raw value. */
1592
+ protected labelFor(value: string): string;
1593
+ /** Moves focus into the text field. */
1594
+ focus(): void;
1595
+ protected onKeydown(event: KeyboardEvent): void;
1596
+ protected onSuggestionPicked(picked: string[]): void;
1597
+ /** Adds a value as a chip, applying the uniqueness and max rules. */
1598
+ add(raw: string): void;
1599
+ protected remove(chip: string, event: MouseEvent): void;
1600
+ protected onOverlayClosed(reason: TxOverlayCloseReason): void;
1601
+ protected onBlur(): void;
1602
+ private commitValue;
1603
+ writeValue(value: string[]): void;
1604
+ registerOnChange(fn: (value: string[]) => void): void;
1605
+ registerOnTouched(fn: () => void): void;
1606
+ setDisabledState(isDisabled: boolean): void;
1607
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxChipsInputComponent, never>;
1608
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxChipsInputComponent, "tx-chips-input", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "suggestions": { "alias": "suggestions"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; "rejected": "rejected"; }, never, never, true, never>;
1609
+ }
1610
+
1611
+ /**
1612
+ * Pure date helpers for {@link TxDatepickerComponent}.
1613
+ *
1614
+ * Everything here is local-time and constructed with `new Date(y, m, d)` rather
1615
+ * than by parsing strings, so a date never shifts a day across a timezone
1616
+ * boundary. Kept separate from the component because parsing and grid building
1617
+ * are exactly the sort of logic that is easy to get subtly wrong, and are the
1618
+ * part worth unit-testing.
1619
+ */
1620
+ /** Supported input/display formats. */
1621
+ type TxDateFormat = 'iso' | 'dmy' | 'mdy';
1622
+ /** 0 = Sunday … 6 = Saturday. */
1623
+ type TxWeekday = 0 | 1 | 2 | 3 | 4 | 5 | 6;
1624
+ /** Midnight local time on the same calendar day. */
1625
+ declare function txStartOfDay(date: Date): Date;
1626
+ /** Whether two dates fall on the same calendar day. */
1627
+ declare function txIsSameDay(a: Date | null, b: Date | null): boolean;
1628
+ /** Whether two dates fall in the same calendar month. */
1629
+ declare function txIsSameMonth(a: Date, b: Date): boolean;
1630
+ /** The first day of `date`'s month. */
1631
+ declare function txStartOfMonth(date: Date): Date;
1632
+ /**
1633
+ * Adds whole months, clamping the day so that adding a month to 31 January
1634
+ * gives 28/29 February rather than rolling into March.
1635
+ */
1636
+ declare function txAddMonths(date: Date, months: number): Date;
1637
+ /** Adds whole days. */
1638
+ declare function txAddDays(date: Date, days: number): Date;
1639
+ /** Number of days in a given month. `month` is 0-based. */
1640
+ declare function txDaysInMonth(year: number, month: number): number;
1641
+ /** Restricts a date to the inclusive `[min, max]` range. */
1642
+ declare function txClampDate(date: Date, min?: Date | null, max?: Date | null): Date;
1643
+ /** Whether a date falls inside the inclusive `[min, max]` range. */
1644
+ declare function txIsWithin(date: Date, min?: Date | null, max?: Date | null): boolean;
1645
+ /**
1646
+ * Formats a date for display and for the text input.
1647
+ *
1648
+ * Always zero-padded and always four-digit years, so the output round-trips
1649
+ * back through {@link txParseDate} unchanged.
1650
+ */
1651
+ declare function txFormatDate(date: Date | null, format: TxDateFormat): string;
1652
+ /** The placeholder that matches a format, e.g. `dd/mm/yyyy`. */
1653
+ declare function txFormatPlaceholder(format: TxDateFormat): string;
1654
+ /**
1655
+ * Parses user-typed text.
1656
+ *
1657
+ * Accepts `-`, `/` and `.` as separators regardless of format, and one- or
1658
+ * two-digit day/month parts, because people type `1/2/2026` far more often than
1659
+ * `01/02/2026`. Returns `null` for anything that is not a real calendar date —
1660
+ * notably 31 February, which a naive `new Date` would silently roll into March.
1661
+ */
1662
+ declare function txParseDate(text: string, format: TxDateFormat): Date | null;
1663
+ /** One cell of the month grid. */
1664
+ interface TxCalendarDay {
1665
+ date: Date;
1666
+ /** False for the leading/trailing days borrowed from adjacent months. */
1667
+ inMonth: boolean;
1668
+ }
1669
+ /**
1670
+ * Builds a six-week grid covering `month`, padded with adjacent months' days.
1671
+ *
1672
+ * Always six rows, so the popup does not change height as the user pages
1673
+ * through months.
1674
+ */
1675
+ declare function txBuildMonthGrid(year: number, month: number, firstDayOfWeek?: TxWeekday): TxCalendarDay[][];
1676
+ /** Weekday initials starting from `firstDayOfWeek`, in the given locale. */
1677
+ declare function txWeekdayLabels(firstDayOfWeek?: TxWeekday, locale?: string): string[];
1678
+ /** Month and year heading, e.g. `February 2026`. */
1679
+ declare function txMonthLabel(date: Date, locale?: string): string;
1680
+ /** Full date for an accessible label, e.g. `Monday, 2 February 2026`. */
1681
+ declare function txFullDateLabel(date: Date, locale?: string): string;
1682
+
1683
+ /**
1684
+ * How a date may be entered.
1685
+ *
1686
+ * A union rather than a `readonly` boolean, so a third mode can be added
1687
+ * without the two existing ones becoming ambiguous.
1688
+ */
1689
+ type TxDatepickerEntry = 'typed' | 'picker-only';
1690
+ /** Simple property configuration for {@link TxDatepickerComponent}. */
1691
+ interface TxDatepickerConfig {
1692
+ /** Defaults to the placeholder implied by `format`, e.g. `dd/mm/yyyy`. */
1693
+ placeholder?: string;
1694
+ /** Defaults to the surrounding form field's size, else `md`. */
1695
+ size?: TxControlSize;
1696
+ /** Display and parse format. Defaults to `iso`. */
1697
+ format?: TxDateFormat;
1698
+ /** Earliest selectable date, inclusive. */
1699
+ min?: Date | null;
1700
+ /** Latest selectable date, inclusive. */
1701
+ max?: Date | null;
1702
+ /** 0 = Sunday … 6 = Saturday. Defaults to Monday. */
1703
+ firstDayOfWeek?: TxWeekday;
1704
+ /** BCP 47 tag for month and weekday names. Defaults to the browser's. */
1705
+ locale?: string;
1706
+ /** Defaults to `typed`. */
1707
+ entry?: TxDatepickerEntry;
1708
+ /** Shows a "Today" shortcut in the calendar footer. Defaults to true. */
1709
+ showToday?: boolean;
1710
+ clearable?: boolean;
1711
+ disabled?: boolean;
1712
+ required?: boolean;
1713
+ invalid?: boolean;
1714
+ ariaLabel?: string;
1715
+ name?: string;
1716
+ }
1717
+ declare const TX_DATEPICKER_DEFAULTS: {
1718
+ readonly format: "iso";
1719
+ readonly firstDayOfWeek: 1;
1720
+ readonly entry: "typed";
1721
+ readonly showToday: true;
1722
+ };
1723
+ /**
1724
+ * A date field with a calendar popup.
1725
+ *
1726
+ * `@angular/aria` has no datepicker, so the popup is a CDK overlay positioned by
1727
+ * {@link TxConnectedOverlayDirective} — the same one the select uses, which is
1728
+ * what keeps a datepicker inside a scrolling panel from being clipped. The
1729
+ * calendar is a `role="grid"` with a roving tab stop, matching the ARIA date
1730
+ * picker dialog pattern.
1731
+ *
1732
+ * Parsing and formatting live in `date-utils`, away from the component, because
1733
+ * they are the part that is easy to get subtly wrong — and they are unit-tested
1734
+ * there rather than through the DOM.
1735
+ *
1736
+ * @example
1737
+ * ```html
1738
+ * <tx-form-field [config]="{ label: 'Failure date', required: true }">
1739
+ * <tx-datepicker [config]="{ format: 'dmy', max: today, clearable: true }" [(value)]="failedOn" />
1740
+ * </tx-form-field>
1741
+ * ```
1742
+ *
1743
+ * Config is a signal input — replace the object rather than mutating it.
1744
+ */
1745
+ declare class TxDatepickerComponent implements ControlValueAccessor {
1746
+ readonly config: _angular_core.InputSignal<Partial<TxDatepickerConfig>>;
1747
+ /** The selected date, or `null`. */
1748
+ readonly value: _angular_core.ModelSignal<Date | null>;
1749
+ readonly changed: _angular_core.OutputEmitterRef<Date | null>;
1750
+ readonly openedChange: _angular_core.OutputEmitterRef<boolean>;
1751
+ protected readonly expanded: _angular_core.WritableSignal<boolean>;
1752
+ protected readonly text: _angular_core.WritableSignal<string>;
1753
+ /** The day the roving tab stop is on. Drives arrow-key navigation. */
1754
+ protected readonly focusedDate: _angular_core.WritableSignal<Date>;
1755
+ /** First of the visible month. */
1756
+ protected readonly viewMonth: _angular_core.WritableSignal<Date>;
1757
+ protected readonly todayDate: Date;
1758
+ protected readonly gridLabelId: string;
1759
+ protected readonly panelClass: string;
1760
+ protected readonly txIsSameDay: typeof txIsSameDay;
1761
+ protected readonly navClass: string;
1762
+ protected readonly footerClass: string;
1763
+ protected readonly overlayConfig: Partial<TxOverlayConfig>;
1764
+ private readonly field;
1765
+ private readonly trigger;
1766
+ private readonly formField;
1767
+ private readonly forms;
1768
+ protected readonly fieldId: _angular_core.Signal<string>;
1769
+ protected readonly describedBy: _angular_core.Signal<string | null>;
1770
+ private readonly resolved;
1771
+ protected readonly format: _angular_core.Signal<TxDateFormat>;
1772
+ protected readonly showToday: _angular_core.Signal<boolean>;
1773
+ protected readonly isPickerOnly: _angular_core.Signal<boolean>;
1774
+ protected readonly placeholder: _angular_core.Signal<string>;
1775
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
1776
+ protected readonly isInvalid: _angular_core.Signal<boolean>;
1777
+ protected readonly isRequired: _angular_core.Signal<boolean>;
1778
+ protected readonly size: _angular_core.Signal<"sm" | "md" | "lg">;
1779
+ protected readonly iconSize: _angular_core.Signal<"sm" | "md">;
1780
+ protected readonly showClear: _angular_core.Signal<boolean>;
1781
+ protected readonly shellClass: _angular_core.Signal<string>;
1782
+ protected readonly weekdays: _angular_core.Signal<string[]>;
1783
+ protected readonly monthLabel: _angular_core.Signal<string>;
1784
+ protected readonly weeks: _angular_core.Signal<_tx_angular_design_system_ui_kit.TxCalendarDay[][]>;
1785
+ protected readonly canGoPrevious: _angular_core.Signal<boolean>;
1786
+ protected readonly canGoNext: _angular_core.Signal<boolean>;
1787
+ constructor();
1788
+ protected selectable(date: Date): boolean;
1789
+ protected isToday(date: Date): boolean;
1790
+ protected isFocused(date: Date): boolean;
1791
+ protected fullLabel(date: Date): string;
1792
+ protected dayClass(date: Date, inMonth: boolean): string;
1793
+ /** Opens the calendar. */
1794
+ open(): void;
1795
+ /** Closes the calendar. */
1796
+ close(restoreFocus?: boolean): void;
1797
+ protected toggle(): void;
1798
+ protected onOverlayClosed(reason: TxOverlayCloseReason): void;
1799
+ protected onInput(event: Event): void;
1800
+ protected onBlur(): void;
1801
+ protected onFieldKeydown(event: KeyboardEvent): void;
1802
+ protected onCalendarKeydown(event: KeyboardEvent): void;
1803
+ protected shiftMonth(delta: number): void;
1804
+ protected pick(date: Date): void;
1805
+ protected clear(): void;
1806
+ /** Moves focus onto the text field. */
1807
+ focus(): void;
1808
+ private commit;
1809
+ /**
1810
+ * Moves DOM focus onto the day carrying the roving tab stop, once the grid
1811
+ * has rendered the new month.
1812
+ */
1813
+ private focusActiveDay;
1814
+ writeValue(value: Date | string | null): void;
1815
+ registerOnChange(fn: (value: Date | null) => void): void;
1816
+ registerOnTouched(fn: () => void): void;
1817
+ setDisabledState(isDisabled: boolean): void;
1818
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxDatepickerComponent, never>;
1819
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxDatepickerComponent, "tx-datepicker", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; "openedChange": "openedChange"; }, never, never, true, never>;
1820
+ }
1821
+
1822
+ /**
1823
+ * A hierarchical tree of nodes.
1824
+ *
1825
+ * Behaviour is `@angular/aria`'s `ngTree` / `ngTreeItem` / `ngTreeItemGroup`:
1826
+ * roving focus, typeahead, arrow-key expansion, deferred rendering of collapsed
1827
+ * branches, and the full `treeitem` ARIA contract. Every visual state is read
1828
+ * off the attributes Aria emits — `aria-selected`, `aria-expanded`,
1829
+ * `aria-disabled`, `data-active` — so nothing is mirrored into a boolean and
1830
+ * toggled from TypeScript.
1831
+ *
1832
+ * ## Slots
1833
+ *
1834
+ * Structural customisation goes through `TemplateRef` inputs, not config:
1835
+ * `leadingTemplate` (before the label), `badgeTemplate` (after the label) and
1836
+ * `actionsTemplate` (trailing). Each receives a {@link TxTreeSlotContext}. The
1837
+ * `checkboxes` config fills the leading slot with a built-in indicator when no
1838
+ * `leadingTemplate` is given, so the common case needs no template at all.
1839
+ *
1840
+ * ## Reuse by the dropdown tree
1841
+ *
1842
+ * `comboboxHost` is the extension point that lets {@link TxDropdownTreeComponent}
1843
+ * compose this component into a combobox popup rather than re-implementing node
1844
+ * rendering. Setting it applies `ngComboboxWidget` to the `role="tree"` element
1845
+ * so the combobox's `aria-controls` points at the tree itself. Only the two
1846
+ * `<ul>` declarations differ between the modes; every node is rendered by the
1847
+ * one recursive template below.
1848
+ *
1849
+ * @example
1850
+ * ```html
1851
+ * <tx-tree
1852
+ * [nodes]="parts"
1853
+ * [config]="{ selection: 'multiple', checkboxes: 'all' }"
1854
+ * [(selectedIds)]="selected"
1855
+ * [actionsTemplate]="rowActions" />
1856
+ *
1857
+ * <ng-template #rowActions let-node>
1858
+ * <tx-button [config]="{ label: 'Rename ' + node.label, icon: 'edit',
1859
+ * display: 'icon-only', variant: 'ghost', size: 'sm' }" />
1860
+ * </ng-template>
1861
+ * ```
1862
+ *
1863
+ * Config is a signal input — replace the object rather than mutating it.
1864
+ */
1865
+ declare class TxTreeComponent<T = string> {
1866
+ readonly config: _angular_core.InputSignal<Partial<TxTreeConfig>>;
1867
+ /** The node hierarchy. Data, so it is its own input. */
1868
+ readonly nodes: _angular_core.InputSignal<readonly TxTreeNode<T>[]>;
1869
+ /** Selected node ids. Always an array, including in single-select. */
1870
+ readonly selectedIds: _angular_core.ModelSignal<T[]>;
1871
+ /** Expanded branch ids. Two-way, so a page can expand or collapse all. */
1872
+ readonly expandedIds: _angular_core.ModelSignal<T[]>;
1873
+ /** Before the label. Replaces the built-in checkbox indicator. */
1874
+ readonly leadingTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
1875
+ /** After the label. Replaces the node's `badge` text. */
1876
+ readonly badgeTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
1877
+ /** Trailing row actions. Revealed on hover, focus-within or selection. */
1878
+ readonly actionsTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
1879
+ /**
1880
+ * Extension point for {@link TxDropdownTreeComponent}: the combobox this tree
1881
+ * is the popup widget for. Leave unset for a standalone tree.
1882
+ */
1883
+ readonly comboboxHost: _angular_core.InputSignal<Combobox | null>;
1884
+ readonly selectionChange: _angular_core.OutputEmitterRef<T[]>;
1885
+ readonly expansionChange: _angular_core.OutputEmitterRef<T[]>;
1886
+ private readonly resolved;
1887
+ private readonly expandedSet;
1888
+ protected readonly emptyText: _angular_core.Signal<string | undefined>;
1889
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
1890
+ protected readonly selectionEnabled: _angular_core.Signal<boolean>;
1891
+ protected readonly isMulti: _angular_core.Signal<boolean>;
1892
+ protected readonly collapsible: _angular_core.Signal<boolean>;
1893
+ protected readonly treeClass: _angular_core.Signal<string>;
1894
+ protected readonly rowClass: _angular_core.Signal<string>;
1895
+ /** Expands every branch. */
1896
+ expandAll(): void;
1897
+ /** Collapses every branch. */
1898
+ collapseAll(): void;
1899
+ protected isExpanded(id: T): boolean;
1900
+ protected setExpanded(id: T, expanded: boolean): void;
1901
+ protected toggle(id: T, event: MouseEvent): void;
1902
+ protected showCheckbox(node: TxTreeNode<T>): boolean;
1903
+ protected slotContext(node: TxTreeNode<T>, level: number): {
1904
+ $implicit: TxTreeNode<T>;
1905
+ node: TxTreeNode<T>;
1906
+ level: number;
1907
+ selected: boolean;
1908
+ expanded: boolean;
1909
+ hasChildren: boolean;
1910
+ };
1911
+ protected onValue(next: T[]): void;
1912
+ private setExpansion;
1913
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxTreeComponent<any>, never>;
1914
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxTreeComponent<any>, "tx-tree", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "nodes": { "alias": "nodes"; "required": true; "isSignal": true; }; "selectedIds": { "alias": "selectedIds"; "required": false; "isSignal": true; }; "expandedIds": { "alias": "expandedIds"; "required": false; "isSignal": true; }; "leadingTemplate": { "alias": "leadingTemplate"; "required": false; "isSignal": true; }; "badgeTemplate": { "alias": "badgeTemplate"; "required": false; "isSignal": true; }; "actionsTemplate": { "alias": "actionsTemplate"; "required": false; "isSignal": true; }; "comboboxHost": { "alias": "comboboxHost"; "required": false; "isSignal": true; }; }, { "selectedIds": "selectedIdsChange"; "expandedIds": "expandedIdsChange"; "selectionChange": "selectionChange"; "expansionChange": "expansionChange"; }, never, never, true, never>;
1915
+ }
1916
+
1917
+ /** Sort direction. `null` means unsorted. */
1918
+ type TxSortDirection = 'asc' | 'desc';
1919
+ /** Which column is sorted, and which way. */
1920
+ interface TxTableSort {
1921
+ column: string;
1922
+ direction: TxSortDirection;
1923
+ }
1924
+ /** Horizontal alignment of a column's cells. */
1925
+ type TxColumnAlign = 'start' | 'center' | 'end';
1926
+ /**
1927
+ * How a column's text is rendered.
1928
+ *
1929
+ * `mono` is the reference design's treatment for part numbers, serials and
1930
+ * identifiers; `numeric` right-aligns and uses tabular figures so columns of
1931
+ * numbers line up.
1932
+ */
1933
+ type TxColumnVariant = 'text' | 'mono' | 'numeric';
1934
+ /**
1935
+ * The breakpoint at or above which a column appears.
1936
+ *
1937
+ * This is the documented column-priority approach to narrow screens: rather
1938
+ * than letting a wide table overflow, low-priority columns drop out and the
1939
+ * rest stay readable. Pair it with the table's `responsive` config.
1940
+ */
1941
+ type TxColumnPriority = 'always' | 'sm' | 'md' | 'lg' | 'xl';
1942
+ /**
1943
+ * One column.
1944
+ *
1945
+ * Columns are *data*, so they come through the table's own `columns` input
1946
+ * rather than as a field on the config object. `value` and `compare` are
1947
+ * projections of a row, not behaviour — event handlers stay as `output()`s on
1948
+ * the component. Anything structural (a custom cell) is a projected
1949
+ * `ng-template[txTableCell]`, never a field here.
1950
+ */
1951
+ interface TxTableColumn<T = Record<string, unknown>> {
1952
+ /**
1953
+ * Unique key. Doubles as the property name read from each row unless `value`
1954
+ * is supplied, and as the name a `txTableCell` template matches on.
1955
+ */
1956
+ key: string;
1957
+ /** Column heading. */
1958
+ header: string;
1959
+ /** Derives the display value. Defaults to `row[key]`. */
1960
+ value?: (row: T) => string | number | boolean | null | undefined;
1961
+ /** Whether this column can be sorted. Defaults to false. */
1962
+ sortable?: boolean;
1963
+ /**
1964
+ * Custom comparator, for when the display value does not sort correctly —
1965
+ * a formatted date, or a status that has a rank rather than an alphabet.
1966
+ */
1967
+ compare?: (a: T, b: T) => number;
1968
+ /** Defaults to `start`, or `end` when the variant is `numeric`. */
1969
+ align?: TxColumnAlign;
1970
+ /** Defaults to `text`. */
1971
+ variant?: TxColumnVariant;
1972
+ /** Defaults to `always`. */
1973
+ priority?: TxColumnPriority;
1974
+ /** Stops the cell wrapping. Useful for timestamps and identifiers. */
1975
+ noWrap?: boolean;
1976
+ /** Accessible description of the column, announced with the header. */
1977
+ headerLabel?: string;
1978
+ }
1979
+ /** Row selection mode. */
1980
+ type TxTableSelection = 'none' | 'single' | 'multiple';
1981
+ /** Simple property configuration for {@link TxTableComponent}. */
1982
+ interface TxTableConfig {
1983
+ /** Defaults to `none`. */
1984
+ selection?: TxTableSelection;
1985
+ /** Defaults to `comfortable`. */
1986
+ density?: 'comfortable' | 'compact';
1987
+ /**
1988
+ * `client` sorts the rows given to the table; `server` only reports the
1989
+ * requested sort through the `sortChange` output and leaves `rows` alone.
1990
+ * Defaults to `client`.
1991
+ */
1992
+ sort?: 'none' | 'client' | 'server';
1993
+ /** Same split as `sort`. Defaults to `none`. */
1994
+ pagination?: 'none' | 'client' | 'server';
1995
+ /** Page sizes offered in the footer. */
1996
+ pageSizeOptions?: readonly number[];
1997
+ /**
1998
+ * How the table copes with a narrow viewport.
1999
+ *
2000
+ * `scroll` puts the table in a horizontal scroller; `sticky-first` also pins
2001
+ * the first column so the row stays identifiable while scrolling; `priority`
2002
+ * drops low-priority columns instead of scrolling at all.
2003
+ * Defaults to `sticky-first`.
2004
+ */
2005
+ responsive?: 'scroll' | 'sticky-first' | 'priority';
2006
+ /** Highlights the row under the pointer. Defaults to true. */
2007
+ hoverable?: boolean;
2008
+ /** Replaces the body with a loading state. */
2009
+ loading?: boolean;
2010
+ /** Rows rendered as skeletons while loading. Defaults to 5. */
2011
+ loadingRows?: number;
2012
+ /** Shown when there are no rows and the table is not loading. */
2013
+ emptyText?: string;
2014
+ /** Registered icon name shown above `emptyText`. */
2015
+ emptyIcon?: string;
2016
+ /** Adds a trailing action column fed by the `txTableActions` template. */
2017
+ actionColumn?: 'none' | 'end';
2018
+ /** Heading for the action column. Defaults to a visually hidden "Actions". */
2019
+ actionColumnHeader?: string;
2020
+ /** Noun used by the footer's range summary, e.g. "84 reports". */
2021
+ itemLabel?: string;
2022
+ /** Accessible name for the table. */
2023
+ ariaLabel?: string;
2024
+ /** Visible caption above the table. */
2025
+ caption?: string;
2026
+ }
2027
+ declare const TX_TABLE_DEFAULTS: {
2028
+ readonly selection: "none";
2029
+ readonly density: "comfortable";
2030
+ readonly sort: "client";
2031
+ readonly pagination: "none";
2032
+ readonly responsive: "sticky-first";
2033
+ readonly hoverable: true;
2034
+ readonly loadingRows: 5;
2035
+ readonly emptyText: "Nothing to show";
2036
+ readonly emptyIcon: "inbox";
2037
+ readonly actionColumn: "none";
2038
+ readonly actionColumnHeader: "Actions";
2039
+ readonly itemLabel: "rows";
2040
+ };
2041
+
2042
+ /**
2043
+ * Pure sorting helpers.
2044
+ *
2045
+ * Comparators are the classic source of quiet bugs — nulls sorting to the top,
2046
+ * numbers compared as strings so `10` lands before `9`, a sort that is not
2047
+ * stable so equal rows shuffle on every re-sort. Kept out of the component and
2048
+ * unit-tested directly.
2049
+ */
2050
+ /** Reads a column's display value from a row. */
2051
+ declare function txColumnValue<T>(column: TxTableColumn<T>, row: T): string | number | boolean | null | undefined;
2052
+ /**
2053
+ * Compares two cell values.
2054
+ *
2055
+ * Nulls and empty strings always sort last regardless of direction, because a
2056
+ * missing value is not "smaller" — burying blanks at the bottom is what people
2057
+ * actually expect. Numbers compare numerically, strings with `localeCompare`
2058
+ * so accents and case behave, and numeric strings are compared as numbers so
2059
+ * `10` does not sort before `9`.
2060
+ */
2061
+ declare function txCompareValues(a: unknown, b: unknown): number;
2062
+ /**
2063
+ * Returns a sorted copy of `rows`.
2064
+ *
2065
+ * Never mutates the input — the caller owns that array — and the sort is stable
2066
+ * (`Array.prototype.sort` has been required to be stable since ES2019), so rows
2067
+ * that compare equal keep the order they were given in. "Empty last" is applied
2068
+ * before the direction flip, so blanks stay at the bottom either way.
2069
+ */
2070
+ declare function txSortRows<T>(rows: readonly T[], column: TxTableColumn<T> | undefined, direction: TxSortDirection): T[];
2071
+ /**
2072
+ * The sort state after clicking a column header.
2073
+ *
2074
+ * Cycles ascending → descending → unsorted, so a user can always get back to
2075
+ * the original order without reloading.
2076
+ */
2077
+ declare function txNextSort(current: {
2078
+ column: string;
2079
+ direction: TxSortDirection;
2080
+ } | null, column: string): {
2081
+ column: string;
2082
+ direction: TxSortDirection;
2083
+ } | null;
2084
+ /** The `aria-sort` value for a header cell. */
2085
+ declare function txAriaSort(current: {
2086
+ column: string;
2087
+ direction: TxSortDirection;
2088
+ } | null, column: string, sortable: boolean): 'ascending' | 'descending' | 'none' | null;
2089
+
2090
+ /**
2091
+ * Marks an `ng-template` as the renderer for one column's cells.
2092
+ *
2093
+ * Structural customisation by projection rather than by config: a table can
2094
+ * have any number of custom cells, and each one is a template with the row in
2095
+ * scope, so a cell can contain badges, links, nested controls — anything.
2096
+ *
2097
+ * @example
2098
+ * ```html
2099
+ * <tx-table [columns]="columns" [rows]="reports">
2100
+ * <ng-template txTableCell="status" let-row>
2101
+ * <tx-badge [config]="{ label: row.status, variant: toneFor(row.status) }" />
2102
+ * </ng-template>
2103
+ * </tx-table>
2104
+ * ```
2105
+ *
2106
+ * Context: `$implicit` and `row` are the row; `column` is the column; `value`
2107
+ * is what the table would otherwise have rendered.
2108
+ */
2109
+ declare class TxTableCellDirective {
2110
+ /** The `key` of the column this template renders. */
2111
+ readonly column: _angular_core.InputSignal<string>;
2112
+ readonly template: TemplateRef<unknown>;
2113
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxTableCellDirective, never>;
2114
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TxTableCellDirective, "ng-template[txTableCell]", never, { "column": { "alias": "txTableCell"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
2115
+ }
2116
+ /**
2117
+ * Marks an `ng-template` as the content of the table's action column.
2118
+ *
2119
+ * Turned on with the table's `actionColumn: 'end'` config. Actions are quiet
2120
+ * until the row is hovered, focused within or selected, and always visible on
2121
+ * touch-sized screens where there is no hover at all.
2122
+ *
2123
+ * @example
2124
+ * ```html
2125
+ * <ng-template txTableActions let-row>
2126
+ * <tx-button [config]="{ label: 'Edit ' + row.id, icon: 'edit',
2127
+ * display: 'icon-only', variant: 'ghost', size: 'sm' }"
2128
+ * (clicked)="edit(row)" />
2129
+ * </ng-template>
2130
+ * ```
2131
+ */
2132
+ declare class TxTableActionsDirective {
2133
+ readonly template: TemplateRef<unknown>;
2134
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxTableActionsDirective, never>;
2135
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TxTableActionsDirective, "ng-template[txTableActions]", never, {}, {}, never, never, true, never>;
2136
+ }
2137
+
2138
+ /**
2139
+ * A data table.
2140
+ *
2141
+ * Built on `@angular/cdk/table` in its native-`<table>` form, so the markup is a
2142
+ * real table with real `th`/`td` semantics rather than a grid of divs.
2143
+ *
2144
+ * ## What is config and what is a slot
2145
+ *
2146
+ * Sorting, pagination, density, selection mode, loading and the empty state are
2147
+ * simple property variation and live in {@link TxTableConfig}. Columns are data
2148
+ * and come through `columns`. Anything structural is projected: a custom cell is
2149
+ * an `ng-template[txTableCell="key"]`, and the action column's content is an
2150
+ * `ng-template[txTableActions]`.
2151
+ *
2152
+ * ## Narrow screens
2153
+ *
2154
+ * `responsive` picks the strategy rather than leaving it to chance:
2155
+ * `sticky-first` (default) scrolls horizontally with the first column pinned so
2156
+ * the row stays identifiable; `scroll` scrolls plainly; `priority` drops columns
2157
+ * by their `priority` instead of scrolling at all.
2158
+ *
2159
+ * @example
2160
+ * ```html
2161
+ * <tx-table
2162
+ * [columns]="columns"
2163
+ * [rows]="reports()"
2164
+ * [config]="{ sort: 'client', pagination: 'client', actionColumn: 'end' }"
2165
+ * [(sort)]="sort"
2166
+ * [(selectedRows)]="selected">
2167
+ * <ng-template txTableCell="status" let-row>
2168
+ * <tx-badge [config]="{ label: row.status }" />
2169
+ * </ng-template>
2170
+ * <ng-template txTableActions let-row>
2171
+ * <tx-button [config]="{ label: 'Edit', icon: 'edit', display: 'icon-only' }" />
2172
+ * </ng-template>
2173
+ * </tx-table>
2174
+ * ```
2175
+ *
2176
+ * Config is a signal input — replace the object rather than mutating it.
2177
+ */
2178
+ declare class TxTableComponent<T = Record<string, unknown>> {
2179
+ readonly config: _angular_core.InputSignal<Partial<TxTableConfig>>;
2180
+ /** Column descriptors. Data, so they are their own input. */
2181
+ readonly columns: _angular_core.InputSignal<readonly TxTableColumn<T>[]>;
2182
+ /** The rows to show. */
2183
+ readonly rows: _angular_core.InputSignal<readonly T[]>;
2184
+ /**
2185
+ * Identity for selection and tracking. Defaults to the row object itself,
2186
+ * which is right when rows are stable references; supply one when rows are
2187
+ * re-created on every fetch.
2188
+ */
2189
+ readonly trackBy: _angular_core.InputSignal<(row: T) => unknown>;
2190
+ /**
2191
+ * Total row count for server-side pagination. Ignored when paginating on the
2192
+ * client, where the row count is simply `rows().length`.
2193
+ */
2194
+ readonly total: _angular_core.InputSignal<number | null>;
2195
+ readonly sort: _angular_core.ModelSignal<TxTableSort | null>;
2196
+ readonly pageIndex: _angular_core.ModelSignal<number>;
2197
+ readonly pageSize: _angular_core.ModelSignal<number>;
2198
+ readonly selectedRows: _angular_core.ModelSignal<T[]>;
2199
+ readonly pageChange: _angular_core.OutputEmitterRef<{
2200
+ pageIndex: number;
2201
+ pageSize: number;
2202
+ }>;
2203
+ readonly selectionChange: _angular_core.OutputEmitterRef<T[]>;
2204
+ /** A row was clicked or activated with Enter/Space. */
2205
+ readonly rowActivate: _angular_core.OutputEmitterRef<T>;
2206
+ private readonly cellTemplates;
2207
+ protected readonly actionsTemplate: _angular_core.Signal<TxTableActionsDirective | undefined>;
2208
+ protected readonly selectColumn = "__tx_select";
2209
+ protected readonly actionColumn = "__tx_actions";
2210
+ private readonly resolved;
2211
+ protected readonly caption: _angular_core.Signal<string | null>;
2212
+ protected readonly emptyText: _angular_core.Signal<string | undefined>;
2213
+ protected readonly emptyIcon: _angular_core.Signal<string | null>;
2214
+ protected readonly itemLabel: _angular_core.Signal<string | undefined>;
2215
+ protected readonly isLoading: _angular_core.Signal<boolean>;
2216
+ protected readonly selectionMode: _angular_core.Signal<_tx_angular_design_system_ui_kit.TxTableSelection>;
2217
+ protected readonly sortEnabled: _angular_core.Signal<boolean>;
2218
+ protected readonly paginationEnabled: _angular_core.Signal<boolean>;
2219
+ protected readonly hasActionColumn: _angular_core.Signal<boolean>;
2220
+ protected readonly actionHeader: _angular_core.Signal<string | undefined>;
2221
+ protected readonly stickyFirst: _angular_core.Signal<boolean>;
2222
+ protected readonly loadingRows: _angular_core.Signal<unknown[]>;
2223
+ /** Rows after client-side sorting. Server modes leave the input untouched. */
2224
+ private readonly sortedRows;
2225
+ /** Total for the pagination footer. */
2226
+ protected readonly totalRows: _angular_core.Signal<number>;
2227
+ /** Rows actually rendered. Empty while loading, so the no-data row shows. */
2228
+ protected readonly visibleRows: _angular_core.Signal<readonly T[]>;
2229
+ protected readonly displayedColumns: _angular_core.Signal<string[]>;
2230
+ constructor();
2231
+ protected alignOf(column: TxTableColumn<T>): 'start' | 'center' | 'end';
2232
+ protected isStickyColumn(column: TxTableColumn<T>): boolean;
2233
+ protected display(column: TxTableColumn<T>, row: T): string;
2234
+ protected cellTemplateFor(key: string): _angular_core.TemplateRef<unknown> | null;
2235
+ protected ariaSort(column: TxTableColumn<T>): "none" | "ascending" | "descending" | null;
2236
+ protected sortIcon(column: TxTableColumn<T>): string;
2237
+ protected sortLabel(column: TxTableColumn<T>): string;
2238
+ protected readonly headerRowClass = "border-b-2 border-tx-accent";
2239
+ protected readonly sortButtonClass: string;
2240
+ protected scrollerClass(): string;
2241
+ protected tableClass(): string;
2242
+ protected headerCellClass(align: 'start' | 'center' | 'end', sticky: boolean, priority?: TxColumnPriority): string;
2243
+ protected bodyCellClass(align: 'start' | 'center' | 'end', variant: 'text' | 'mono' | 'numeric', sticky: boolean, priority?: TxColumnPriority, noWrap?: boolean): string;
2244
+ protected rowClass(): string;
2245
+ protected toggleSort(column: TxTableColumn<T>): void;
2246
+ protected isSelected(row: T): boolean;
2247
+ protected allSelected(): boolean;
2248
+ protected someSelected(): boolean;
2249
+ protected toggleRow(row: T): void;
2250
+ protected toggleAll(): void;
2251
+ protected onRowActivate(row: T): void;
2252
+ protected onRowKeydown(row: T, event: KeyboardEvent): void;
2253
+ private commitSelection;
2254
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxTableComponent<any>, never>;
2255
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxTableComponent<any>, "tx-table", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "rows": { "alias": "rows"; "required": true; "isSignal": true; }; "trackBy": { "alias": "trackBy"; "required": false; "isSignal": true; }; "total": { "alias": "total"; "required": false; "isSignal": true; }; "sort": { "alias": "sort"; "required": false; "isSignal": true; }; "pageIndex": { "alias": "pageIndex"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "selectedRows": { "alias": "selectedRows"; "required": false; "isSignal": true; }; }, { "sort": "sortChange"; "pageIndex": "pageIndexChange"; "pageSize": "pageSizeChange"; "selectedRows": "selectedRowsChange"; "pageChange": "pageChange"; "selectionChange": "selectionChange"; "rowActivate": "rowActivate"; }, ["cellTemplates", "actionsTemplate"], never, true, never>;
2256
+ }
2257
+
2258
+ /**
2259
+ * One reorderable item.
2260
+ *
2261
+ * Items are data. Anything structural — per-item actions, a custom body — is a
2262
+ * `TemplateRef` slot on the component, never a field here.
2263
+ */
2264
+ interface TxReorderItem<T = unknown> {
2265
+ /** Unique within the list. */
2266
+ id: string;
2267
+ label: string;
2268
+ /** Optional second line. */
2269
+ description?: string;
2270
+ /** Registered icon name shown before the label. */
2271
+ icon?: string;
2272
+ /** Excluded from dragging and from the move buttons. */
2273
+ disabled?: boolean;
2274
+ /** Application payload, passed back in slot contexts and outputs. */
2275
+ data?: T;
2276
+ }
2277
+ /**
2278
+ * What the user grabs to drag.
2279
+ *
2280
+ * A union rather than a `dragAnywhere` boolean, so a third mode stays possible.
2281
+ */
2282
+ type TxReorderHandle = 'handle' | 'row';
2283
+ /** Simple property configuration for {@link TxReorderListComponent}. */
2284
+ interface TxReorderListConfig {
2285
+ /** Defaults to `handle`. */
2286
+ handle?: TxReorderHandle;
2287
+ /** Defaults to `md`. */
2288
+ size?: 'sm' | 'md';
2289
+ /** Shows the 1-based position before each item. */
2290
+ showIndex?: boolean;
2291
+ disabled?: boolean;
2292
+ emptyText?: string;
2293
+ ariaLabel?: string;
2294
+ }
2295
+ declare const TX_REORDER_LIST_DEFAULTS: {
2296
+ readonly handle: "handle";
2297
+ readonly size: "md";
2298
+ readonly emptyText: "Nothing to reorder";
2299
+ readonly ariaLabel: "Reorderable list";
2300
+ };
2301
+ /**
2302
+ * A list whose items can be reordered.
2303
+ *
2304
+ * Dragging is `@angular/cdk/drag-drop`. Dragging alone is not accessible, so
2305
+ * every row also carries move-up and move-down buttons: they are the keyboard
2306
+ * path, they are reachable by Tab, and they appear on focus as well as on hover.
2307
+ * Each move is announced through the CDK's `LiveAnnouncer`, so a screen-reader
2308
+ * user hears where the item landed rather than being left to guess.
2309
+ *
2310
+ * @example
2311
+ * ```html
2312
+ * <tx-reorder-list [(items)]="steps" [config]="{ showIndex: true }"
2313
+ * [actionsTemplate]="rowActions" />
2314
+ *
2315
+ * <ng-template #rowActions let-item>
2316
+ * <tx-button [config]="{ label: 'Remove ' + item.label, icon: 'trash',
2317
+ * display: 'icon-only', variant: 'danger', size: 'sm' }" />
2318
+ * </ng-template>
2319
+ * ```
2320
+ *
2321
+ * Config is a signal input — replace the object rather than mutating it.
2322
+ */
2323
+ declare class TxReorderListComponent<T = unknown> {
2324
+ private readonly announcer;
2325
+ readonly config: _angular_core.InputSignal<Partial<TxReorderListConfig>>;
2326
+ /** The ordered items. Two-way, so the new order flows straight back out. */
2327
+ readonly items: _angular_core.ModelSignal<TxReorderItem<T>[]>;
2328
+ /** Replaces the default label/description body. */
2329
+ readonly itemTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
2330
+ /** Per-item action buttons, rendered after the move buttons. */
2331
+ readonly actionsTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
2332
+ /** Emitted with the new order whenever an item moves. */
2333
+ readonly reordered: _angular_core.OutputEmitterRef<{
2334
+ item: TxReorderItem<T>;
2335
+ from: number;
2336
+ to: number;
2337
+ items: TxReorderItem<T>[];
2338
+ }>;
2339
+ private readonly resolved;
2340
+ protected readonly emptyText: _angular_core.Signal<string | undefined>;
2341
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
2342
+ protected readonly showIndex: _angular_core.Signal<boolean>;
2343
+ protected readonly grabWholeRow: _angular_core.Signal<boolean>;
2344
+ protected readonly moveButtonClass: string;
2345
+ protected rowClass(): string;
2346
+ protected handleClass(): string;
2347
+ protected moveGroupClass(): string;
2348
+ protected slotContext(item: TxReorderItem<T>, index: number): {
2349
+ $implicit: TxReorderItem<T>;
2350
+ item: TxReorderItem<T>;
2351
+ index: number;
2352
+ first: boolean;
2353
+ last: boolean;
2354
+ };
2355
+ protected onDrop(event: CdkDragDrop<unknown>): void;
2356
+ /** Moves an item, clamped to the list's bounds. Also the keyboard path. */
2357
+ move(from: number, to: number): void;
2358
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxReorderListComponent<any>, never>;
2359
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxReorderListComponent<any>, "tx-reorder-list", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": true; "isSignal": true; }; "itemTemplate": { "alias": "itemTemplate"; "required": false; "isSignal": true; }; "actionsTemplate": { "alias": "actionsTemplate"; "required": false; "isSignal": true; }; }, { "items": "itemsChange"; "reordered": "reordered"; }, never, never, true, never>;
2360
+ }
2361
+
2362
+ /** Diameter of the spinner, aligned to the icon sizes. */
2363
+ type TxSpinnerSize = 'sm' | 'md' | 'lg';
2364
+ /**
2365
+ * Colour of the spinner. `current` inherits the surrounding text colour, which
2366
+ * is what lets the same component sit inside a button of any variant.
2367
+ */
2368
+ type TxSpinnerTone = 'current' | 'primary' | 'muted' | 'inverse';
2369
+ /** Simple property configuration for {@link TxSpinnerComponent}. */
2370
+ interface TxSpinnerConfig {
2371
+ /** Defaults to `md`. */
2372
+ size?: TxSpinnerSize;
2373
+ /** Defaults to `current`. */
2374
+ tone?: TxSpinnerTone;
2375
+ /**
2376
+ * Accessible label announced to screen readers. Defaults to `Loading`.
2377
+ * Set `labelVisibility: 'visible'` to also show it beside the spinner.
2378
+ */
2379
+ label?: string;
2380
+ /** Defaults to `screen-reader-only`. */
2381
+ labelVisibility?: 'visible' | 'screen-reader-only';
2382
+ }
2383
+ declare const TX_SPINNER_DEFAULTS: {
2384
+ readonly size: "md";
2385
+ readonly tone: "current";
2386
+ readonly label: "Loading";
2387
+ readonly labelVisibility: "screen-reader-only";
2388
+ };
2389
+ /**
2390
+ * An indeterminate loading indicator.
2391
+ *
2392
+ * @example
2393
+ * ```html
2394
+ * <tx-spinner [config]="{ size: 'lg', tone: 'primary', label: 'Loading reports' }" />
2395
+ * ```
2396
+ *
2397
+ * Config is a signal input — update it by replacing the object:
2398
+ * `this.spinnerConfig = { ...this.spinnerConfig, size: 'sm' }`.
2399
+ */
2400
+ declare class TxSpinnerComponent {
2401
+ readonly config: _angular_core.InputSignal<Partial<TxSpinnerConfig>>;
2402
+ private readonly resolved;
2403
+ protected readonly label: _angular_core.Signal<string | undefined>;
2404
+ protected readonly svgClass: _angular_core.Signal<string>;
2405
+ protected readonly labelClass: _angular_core.Signal<"sr-only" | "text-tx-base text-tx-text-muted">;
2406
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxSpinnerComponent, never>;
2407
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxSpinnerComponent, "tx-spinner", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2408
+ }
2409
+
2410
+ /** Shape of the placeholder. */
2411
+ type TxSkeletonShape = 'text' | 'heading' | 'block' | 'circle' | 'pill';
2412
+ /** Simple property configuration for {@link TxSkeletonComponent}. */
2413
+ interface TxSkeletonConfig {
2414
+ /** Defaults to `text`. */
2415
+ shape?: TxSkeletonShape;
2416
+ /**
2417
+ * Number of lines. Only meaningful for `text`; the last line is rendered
2418
+ * short so a block of them reads as a paragraph rather than a grid.
2419
+ * Defaults to 1.
2420
+ */
2421
+ lines?: number;
2422
+ /** CSS width, e.g. `60%`. Defaults to full width (or a square for `circle`). */
2423
+ width?: string;
2424
+ /** CSS height. Defaults to a sensible height for the shape. */
2425
+ height?: string;
2426
+ /** Set false for a static placeholder. Defaults to true. */
2427
+ animated?: boolean;
2428
+ /**
2429
+ * Announced to screen readers while content loads. Defaults to `Loading`;
2430
+ * set to an empty string when a nearby live region already says so.
2431
+ */
2432
+ label?: string;
2433
+ }
2434
+ declare const TX_SKELETON_DEFAULTS: {
2435
+ readonly shape: "text";
2436
+ readonly lines: 1;
2437
+ readonly animated: true;
2438
+ readonly label: "Loading";
2439
+ };
2440
+ /**
2441
+ * A placeholder shown in the shape of the content that is loading.
2442
+ *
2443
+ * Used on its own, and by {@link TxTableComponent} for its loading rows.
2444
+ *
2445
+ * @example
2446
+ * ```html
2447
+ * <tx-skeleton [config]="{ shape: 'text', lines: 3 }" />
2448
+ * <tx-skeleton [config]="{ shape: 'circle' }" />
2449
+ * ```
2450
+ *
2451
+ * Config is a signal input — replace the object rather than mutating it.
2452
+ */
2453
+ declare class TxSkeletonComponent {
2454
+ readonly config: _angular_core.InputSignal<Partial<TxSkeletonConfig>>;
2455
+ private readonly resolved;
2456
+ protected readonly label: _angular_core.Signal<string | undefined>;
2457
+ protected readonly height: _angular_core.Signal<string | null>;
2458
+ protected readonly lines: _angular_core.Signal<unknown[]>;
2459
+ protected lineClass(index: number): string;
2460
+ protected widthFor(index: number): string | null;
2461
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxSkeletonComponent, never>;
2462
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxSkeletonComponent, "tx-skeleton", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2463
+ }
2464
+
2465
+ /** Severity of the message. Drives colour, default icon and the ARIA role. */
2466
+ type TxAlertVariant = 'info' | 'success' | 'warning' | 'danger';
2467
+ /**
2468
+ * How prominent the alert is.
2469
+ *
2470
+ * `subtle` is a tinted panel; `solid` fills with the variant colour for
2471
+ * something that must not be missed; `bare` drops the surface and keeps only
2472
+ * the icon and text, for use inside an already-bordered container.
2473
+ */
2474
+ type TxAlertAppearance = 'subtle' | 'solid' | 'bare';
2475
+ /** Simple property configuration for {@link TxAlertComponent}. */
2476
+ interface TxAlertConfig {
2477
+ /** Genuinely required: an alert with no severity has no meaning. */
2478
+ variant: TxAlertVariant;
2479
+ /** Bold first line. Omit for a single-line alert. */
2480
+ title?: string;
2481
+ /** Body text. Omit and project content instead for anything richer. */
2482
+ message?: string;
2483
+ /** Defaults to `subtle`. */
2484
+ appearance?: TxAlertAppearance;
2485
+ /** Registered icon name. Defaults to the variant's icon; `null` hides it. */
2486
+ icon?: string | null;
2487
+ /** Shows a close button and enables the `dismissed` output. */
2488
+ dismissible?: boolean;
2489
+ /**
2490
+ * `polite` (default) waits for a pause; `assertive` interrupts; `none`
2491
+ * renders no live region, for an alert present on first paint that would
2492
+ * otherwise be announced twice.
2493
+ */
2494
+ announce?: 'polite' | 'assertive' | 'none';
2495
+ }
2496
+ declare const TX_ALERT_DEFAULTS: {
2497
+ readonly appearance: "subtle";
2498
+ readonly announce: "polite";
2499
+ };
2500
+ /**
2501
+ * An inline message about the state of the page or a region of it.
2502
+ *
2503
+ * Use `message` for plain text, or project content for anything richer — a
2504
+ * link, a list, a button. Both can be used together.
2505
+ *
2506
+ * `danger` and `warning` render as `role="alert"` so they interrupt; the others
2507
+ * are `role="status"`. Set `announce: 'none'` for an alert that is present on
2508
+ * first paint, which a live region would otherwise announce twice.
2509
+ *
2510
+ * @example
2511
+ * ```html
2512
+ * <tx-alert [config]="{ variant: 'warning', title: 'Unsaved changes',
2513
+ * message: 'Leaving now discards them.', dismissible: true }"
2514
+ * (dismissed)="hide()" />
2515
+ * ```
2516
+ *
2517
+ * Config is a signal input — replace the object rather than mutating it.
2518
+ */
2519
+ declare class TxAlertComponent {
2520
+ readonly config: _angular_core.InputSignal<TxAlertConfig>;
2521
+ /** Emitted when the close button is used. The parent owns visibility. */
2522
+ readonly dismissed: _angular_core.OutputEmitterRef<void>;
2523
+ private readonly resolved;
2524
+ protected readonly title: _angular_core.Signal<string | null>;
2525
+ protected readonly message: _angular_core.Signal<string | null>;
2526
+ protected readonly iconName: _angular_core.Signal<string | null>;
2527
+ protected readonly role: _angular_core.Signal<"status" | "alert" | null>;
2528
+ protected readonly ariaLive: _angular_core.Signal<"polite" | "assertive" | null | undefined>;
2529
+ private readonly isSolid;
2530
+ protected readonly rootClass: _angular_core.Signal<string>;
2531
+ protected readonly iconClass: _angular_core.Signal<string>;
2532
+ protected readonly messageClass: _angular_core.Signal<string>;
2533
+ protected readonly closeClass: _angular_core.Signal<string>;
2534
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxAlertComponent, never>;
2535
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxAlertComponent, "tx-alert", never, { "config": { "alias": "config"; "required": true; "isSignal": true; }; }, { "dismissed": "dismissed"; }, never, ["*"], true, never>;
2536
+ }
2537
+
2538
+ /** Simple property configuration for {@link TxTooltipDirective}. */
2539
+ interface TxTooltipConfig {
2540
+ /** The text. Genuinely required — a tooltip with no text does nothing. */
2541
+ text: string;
2542
+ /** Defaults to `top-center`. Falls back through a ladder if it does not fit. */
2543
+ placement?: TxOverlayPlacement;
2544
+ /** Milliseconds before showing on hover. Defaults to 300. */
2545
+ showDelay?: number;
2546
+ /** Milliseconds before hiding. Defaults to 100. */
2547
+ hideDelay?: number;
2548
+ disabled?: boolean;
2549
+ }
2550
+ declare const TX_TOOLTIP_DEFAULTS: {
2551
+ readonly placement: "top-center";
2552
+ readonly showDelay: 300;
2553
+ readonly hideDelay: 100;
2554
+ };
2555
+ /** The floating bubble. Rendered into the overlay by the directive. */
2556
+ declare class TxTooltipPanelComponent {
2557
+ readonly text: _angular_core.WritableSignal<string>;
2558
+ id: string;
2559
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxTooltipPanelComponent, never>;
2560
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxTooltipPanelComponent, "tx-tooltip-panel", never, {}, {}, never, never, true, never>;
2561
+ }
2562
+ /**
2563
+ * A text tooltip on hover and on keyboard focus.
2564
+ *
2565
+ * Aria has no tooltip, so this is a CDK overlay. It attaches on demand rather
2566
+ * than eagerly — unlike the dropdown overlays, nothing needs to register with
2567
+ * it before first use.
2568
+ *
2569
+ * Shows on `focus-visible` as well as hover, so a tooltip is never information
2570
+ * available only to a mouse, and hides on Escape. The host gets
2571
+ * `aria-describedby` while the tooltip is up, which is how the text reaches a
2572
+ * screen reader — note that a tooltip *describes* a control, so the control
2573
+ * still needs its own accessible name.
2574
+ *
2575
+ * @example
2576
+ * ```html
2577
+ * <tx-button [config]="{ label: 'Export', icon: 'download', display: 'icon-only' }"
2578
+ * [txTooltip]="{ text: 'Export as CSV' }" />
2579
+ * ```
2580
+ *
2581
+ * Config is a signal input — replace the object rather than mutating it.
2582
+ */
2583
+ declare class TxTooltipDirective {
2584
+ private readonly host;
2585
+ private readonly injector;
2586
+ readonly config: _angular_core.InputSignal<TxTooltipConfig>;
2587
+ protected readonly panelId: string;
2588
+ protected readonly visible: _angular_core.WritableSignal<boolean>;
2589
+ private overlayRef;
2590
+ private panel;
2591
+ private timer;
2592
+ private readonly resolved;
2593
+ constructor();
2594
+ /** Shows the tooltip after the configured delay. */
2595
+ show(): void;
2596
+ /** Hides the tooltip after the configured delay. */
2597
+ hide(): void;
2598
+ /**
2599
+ * Only a keyboard focus should show a tooltip. A click focuses the element
2600
+ * too, and a bubble appearing under the pointer you just clicked with is
2601
+ * noise rather than help.
2602
+ */
2603
+ protected onFocus(event: FocusEvent): void;
2604
+ private attach;
2605
+ private detach;
2606
+ private clearTimer;
2607
+ private dispose;
2608
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxTooltipDirective, never>;
2609
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TxTooltipDirective, "[txTooltip]", ["txTooltip"], { "config": { "alias": "txTooltip"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
2610
+ }
2611
+
2612
+ /** Severity of a toast. Drives colour, default icon and announcement urgency. */
2613
+ type TxToastVariant = 'info' | 'success' | 'warning' | 'danger';
2614
+ /** Where the stack sits. Set once through {@link TxToastService.configure}. */
2615
+ type TxToastPosition = 'top-start' | 'top-center' | 'top-end' | 'bottom-start' | 'bottom-center' | 'bottom-end';
2616
+ /**
2617
+ * Simple property configuration for a toast.
2618
+ *
2619
+ * Deliberately no `onAction` callback: behaviour never lives in a config
2620
+ * object. `show()` returns a {@link TxToastRef} whose `action` promise resolves
2621
+ * when the action button is used.
2622
+ */
2623
+ interface TxToastConfig {
2624
+ /** Genuinely required: a toast with no message says nothing. */
2625
+ message: string;
2626
+ /** Defaults to `info`. */
2627
+ variant?: TxToastVariant;
2628
+ /** Bold first line above the message. */
2629
+ title?: string;
2630
+ /** Registered icon name. Defaults to the variant's icon; `null` hides it. */
2631
+ icon?: string | null;
2632
+ /**
2633
+ * Milliseconds before auto-dismissal. `0` keeps it until dismissed, which is
2634
+ * what `danger` defaults to — an error that vanishes is an error missed.
2635
+ */
2636
+ duration?: number;
2637
+ /** Shows a close button. Defaults to true. */
2638
+ dismissible?: boolean;
2639
+ /** Label for an action button, e.g. "Undo". */
2640
+ actionLabel?: string;
2641
+ }
2642
+ /** Why a toast closed. */
2643
+ type TxToastCloseReason = 'timeout' | 'dismissed' | 'action' | 'cleared';
2644
+ /** Handle to a live toast. */
2645
+ interface TxToastRef {
2646
+ readonly id: string;
2647
+ /** Resolves when the toast closes, with the reason. */
2648
+ readonly closed: Promise<TxToastCloseReason>;
2649
+ /** Resolves only if the action button is used. Never rejects. */
2650
+ readonly action: Promise<void>;
2651
+ /** Closes the toast early. */
2652
+ dismiss(): void;
2653
+ }
2654
+ interface ToastEntry {
2655
+ id: string;
2656
+ config: Required<Pick<TxToastConfig, 'message'>> & TxToastConfig;
2657
+ variant: TxToastVariant;
2658
+ timer: ReturnType<typeof setTimeout> | null;
2659
+ close: (reason: TxToastCloseReason) => void;
2660
+ fireAction: () => void;
2661
+ }
2662
+ /** Service-level settings, applied to every toast. */
2663
+ interface TxToastServiceConfig {
2664
+ /** Defaults to `bottom-center`, matching the reference design. */
2665
+ position?: TxToastPosition;
2666
+ /** Most toasts on screen at once. Oldest are dropped first. Defaults to 4. */
2667
+ max?: number;
2668
+ /** Default duration in ms for non-danger toasts. Defaults to 5000. */
2669
+ duration?: number;
2670
+ }
2671
+ /**
2672
+ * The stack. One instance, attached to a global CDK overlay on first use.
2673
+ */
2674
+ declare class TxToastStackComponent {
2675
+ readonly entries: _angular_core.WritableSignal<ToastEntry[]>;
2676
+ readonly position: _angular_core.WritableSignal<TxToastPosition>;
2677
+ protected readonly stackClass: _angular_core.Signal<string>;
2678
+ protected iconFor(entry: ToastEntry): string | null;
2679
+ protected toastClass(variant: TxToastVariant): string;
2680
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxToastStackComponent, never>;
2681
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxToastStackComponent, "tx-toast-stack", never, {}, {}, never, never, true, never>;
2682
+ }
2683
+ /**
2684
+ * Shows transient notifications.
2685
+ *
2686
+ * Aria has no toaster, so this is a CDK global overlay plus the CDK's
2687
+ * `LiveAnnouncer`. The announcement matters: a toast that only appears visually
2688
+ * is invisible to a screen-reader user, and `danger` toasts are announced
2689
+ * assertively while the rest are polite.
2690
+ *
2691
+ * Behaviour never lives in the config object — `show()` returns a
2692
+ * {@link TxToastRef} whose `action` and `closed` promises are how a caller
2693
+ * responds.
2694
+ *
2695
+ * @example
2696
+ * ```ts
2697
+ * const toast = inject(TxToastService);
2698
+ *
2699
+ * toast.success('Report saved');
2700
+ *
2701
+ * const ref = toast.show({ message: 'Report deleted', actionLabel: 'Undo' });
2702
+ * ref.action.then(() => this.restore());
2703
+ * ```
2704
+ */
2705
+ declare class TxToastService {
2706
+ private readonly injector;
2707
+ private readonly announcer;
2708
+ private overlayRef;
2709
+ private stack;
2710
+ private settings;
2711
+ /** Sets stack position, capacity and default duration for the whole app. */
2712
+ configure(config: TxToastServiceConfig): void;
2713
+ /** Shows a toast. */
2714
+ show(config: TxToastConfig): TxToastRef;
2715
+ /** Shorthand for an informational toast. */
2716
+ info(message: string, config?: Omit<TxToastConfig, 'message' | 'variant'>): TxToastRef;
2717
+ /** Shorthand for a success toast. */
2718
+ success(message: string, config?: Omit<TxToastConfig, 'message' | 'variant'>): TxToastRef;
2719
+ /** Shorthand for a warning toast. */
2720
+ warning(message: string, config?: Omit<TxToastConfig, 'message' | 'variant'>): TxToastRef;
2721
+ /** Shorthand for an error toast. Stays until dismissed by default. */
2722
+ danger(message: string, config?: Omit<TxToastConfig, 'message' | 'variant'>): TxToastRef;
2723
+ /** Removes every toast on screen. */
2724
+ clear(): void;
2725
+ private remove;
2726
+ private ensureStack;
2727
+ private applyPosition;
2728
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxToastService, never>;
2729
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<TxToastService>;
2730
+ }
2731
+
2732
+ /** Width of the dialog. */
2733
+ type TxDialogSize = 'sm' | 'md' | 'lg' | 'full';
2734
+ /** Tone of the header icon, for a dialog that carries consequence. */
2735
+ type TxDialogTone = 'default' | 'info' | 'warning' | 'danger';
2736
+ /** Simple property configuration for {@link TxDialogComponent}. */
2737
+ interface TxDialogConfig {
2738
+ /** Genuinely required: it names the dialog for assistive technology. */
2739
+ title: string;
2740
+ /** Secondary line under the title. */
2741
+ description?: string;
2742
+ /** Defaults to `md`. */
2743
+ size?: TxDialogSize;
2744
+ /** Defaults to `default`. */
2745
+ tone?: TxDialogTone;
2746
+ /** Registered icon name shown beside the title. */
2747
+ icon?: string;
2748
+ /** Shows the header close button. Defaults to true. */
2749
+ dismissible?: boolean;
2750
+ }
2751
+ declare const TX_DIALOG_DEFAULTS: {
2752
+ readonly size: "md";
2753
+ readonly tone: "default";
2754
+ readonly dismissible: true;
2755
+ };
2756
+ /**
2757
+ * The chrome of a dialog: header, scrolling body and footer.
2758
+ *
2759
+ * Put this inside the component you open with {@link TxDialogService}; it does
2760
+ * not open anything itself. The body is projected, and the footer is a named
2761
+ * slot, so a dialog can hold anything without this component knowing about it.
2762
+ *
2763
+ * @example
2764
+ * ```html
2765
+ * <tx-dialog [config]="{ title: 'Edit report', description: 'R-1042' }"
2766
+ * (dismissed)="ref.close()">
2767
+ * <tx-form-field [config]="{ label: 'Summary' }">…</tx-form-field>
2768
+ *
2769
+ * <ng-container txDialogFooter>
2770
+ * <tx-button [config]="{ label: 'Cancel', variant: 'secondary' }" (clicked)="ref.close()" />
2771
+ * <tx-button [config]="{ label: 'Save', variant: 'primary' }" (clicked)="save()" />
2772
+ * </ng-container>
2773
+ * </tx-dialog>
2774
+ * ```
2775
+ *
2776
+ * Config is a signal input — replace the object rather than mutating it.
2777
+ */
2778
+ declare class TxDialogComponent {
2779
+ readonly config: _angular_core.InputSignal<TxDialogConfig>;
2780
+ /** The header close button was used. The opener owns closing. */
2781
+ readonly dismissed: _angular_core.OutputEmitterRef<void>;
2782
+ private readonly resolved;
2783
+ protected readonly isDismissible: _angular_core.Signal<boolean>;
2784
+ protected readonly rootClass: _angular_core.Signal<string>;
2785
+ protected readonly iconClass: _angular_core.Signal<string>;
2786
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxDialogComponent, never>;
2787
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxDialogComponent, "tx-dialog", never, { "config": { "alias": "config"; "required": true; "isSignal": true; }; }, { "dismissed": "dismissed"; }, never, ["*", "[txDialogFooter]"], true, never>;
2788
+ }
2789
+
2790
+ /** Options for opening any dialog. */
2791
+ interface TxDialogOpenConfig<D = unknown> {
2792
+ /** Data injected into the dialog component via `DIALOG_DATA`. */
2793
+ data?: D;
2794
+ /** Defaults to `md`. Only used for the backdrop/panel sizing hints. */
2795
+ size?: TxDialogSize;
2796
+ /** Clicking the backdrop or pressing Escape closes. Defaults to true. */
2797
+ dismissible?: boolean;
2798
+ /** Extra classes for the overlay pane. */
2799
+ panelClass?: string | string[];
2800
+ /** Accessible name, when the dialog does not render a TxDialogComponent. */
2801
+ ariaLabel?: string;
2802
+ }
2803
+ /** Simple property configuration for a confirmation dialog. */
2804
+ interface TxConfirmDialogConfig {
2805
+ /** Genuinely required: it names the dialog. */
2806
+ title: string;
2807
+ /** The question or consequence. */
2808
+ message: string;
2809
+ /** Defaults to `Confirm`. */
2810
+ confirmLabel?: string;
2811
+ /** Defaults to `Cancel`. */
2812
+ cancelLabel?: string;
2813
+ /**
2814
+ * Visual weight of the confirm button. Defaults to `primary`, or `danger`
2815
+ * when `tone` is `danger` — so a destructive confirmation looks destructive
2816
+ * without the caller having to say it twice.
2817
+ */
2818
+ confirmVariant?: TxButtonVariant;
2819
+ /** Defaults to `warning`. */
2820
+ tone?: TxDialogTone;
2821
+ /** Registered icon name. Defaults to the tone's icon. */
2822
+ icon?: string;
2823
+ /** Defaults to `sm`. */
2824
+ size?: TxDialogSize;
2825
+ }
2826
+ /** The built-in confirmation dialog body. */
2827
+ declare class TxConfirmDialogComponent {
2828
+ private readonly ref;
2829
+ readonly config: _angular_core.WritableSignal<TxConfirmDialogConfig>;
2830
+ protected readonly dialogConfig: _angular_core.Signal<TxDialogConfig>;
2831
+ protected readonly confirmVariant: _angular_core.Signal<TxButtonVariant>;
2832
+ protected close(result: boolean): void;
2833
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxConfirmDialogComponent, never>;
2834
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxConfirmDialogComponent, "tx-confirm-dialog", never, {}, {}, never, never, true, never>;
2835
+ }
2836
+ /**
2837
+ * Opens dialogs.
2838
+ *
2839
+ * Wraps `@angular/cdk/dialog`, which provides the overlay, the focus trap,
2840
+ * focus restoration on close, and the `Escape` handling. This adds the kit's
2841
+ * sizing, the scrim token, and a ready-made confirmation.
2842
+ *
2843
+ * @example
2844
+ * ```ts
2845
+ * const dialogs = inject(TxDialogService);
2846
+ *
2847
+ * // A custom dialog component
2848
+ * const ref = dialogs.open(EditReportDialog, { data: { id: 'R-1042' }, size: 'lg' });
2849
+ * ref.closed.subscribe((result) => …);
2850
+ *
2851
+ * // The built-in confirmation
2852
+ * if (await dialogs.confirm({
2853
+ * title: 'Delete report?',
2854
+ * message: 'This cannot be undone.',
2855
+ * tone: 'danger',
2856
+ * confirmLabel: 'Delete',
2857
+ * })) {
2858
+ * this.remove();
2859
+ * }
2860
+ * ```
2861
+ */
2862
+ declare class TxDialogService {
2863
+ private readonly dialog;
2864
+ /** Opens a component as a dialog. */
2865
+ open<T, D = unknown, R = unknown>(component: ComponentType<T>, config?: TxDialogOpenConfig<D>): DialogRef<R, T>;
2866
+ /**
2867
+ * Opens a confirmation and resolves to the user's answer.
2868
+ *
2869
+ * Resolves `false` when dismissed by Escape or the backdrop, so a caller can
2870
+ * treat "closed without answering" and "declined" the same way.
2871
+ */
2872
+ confirm(config: TxConfirmDialogConfig): Promise<boolean>;
2873
+ /** Closes every open dialog. */
2874
+ closeAll(): void;
2875
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxDialogService, never>;
2876
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<TxDialogService>;
2877
+ }
2878
+
2879
+ /**
2880
+ * Pure pagination arithmetic.
2881
+ *
2882
+ * Off-by-one errors here are invisible until someone lands on an empty last
2883
+ * page, so this is kept out of the component and unit-tested directly.
2884
+ *
2885
+ * Page indexes are zero-based throughout; only the rendered label is 1-based.
2886
+ */
2887
+ /** Number of pages needed to hold `total` rows. Always at least 1. */
2888
+ declare function txPageCount(total: number, pageSize: number): number;
2889
+ /**
2890
+ * Restricts a page index to one that exists.
2891
+ *
2892
+ * Called after the row count changes — deleting the last row of the last page
2893
+ * would otherwise leave the user stranded on a page past the end.
2894
+ */
2895
+ declare function txClampPageIndex(index: number, total: number, pageSize: number): number;
2896
+ /** The slice of rows on a given page. */
2897
+ declare function txPaginate<T>(rows: readonly T[], pageIndex: number, pageSize: number): T[];
2898
+ /** Inclusive 1-based row range on a page, for a "n–m of t" label. */
2899
+ interface TxPageRange {
2900
+ /** 1-based index of the first row, or 0 when there are none. */
2901
+ from: number;
2902
+ /** 1-based index of the last row, or 0 when there are none. */
2903
+ to: number;
2904
+ total: number;
2905
+ }
2906
+ declare function txPageRange(pageIndex: number, pageSize: number, total: number): TxPageRange;
2907
+ /**
2908
+ * The page buttons to render: page indexes plus `'gap'` markers.
2909
+ *
2910
+ * Always shows the first and last page, and a window of `siblings` either side
2911
+ * of the current one, so the control's width stays stable no matter how many
2912
+ * pages there are.
2913
+ */
2914
+ declare function txPageItems(pageIndex: number, pageCount: number, siblings?: number): (number | 'gap')[];
2915
+
2916
+ /**
2917
+ * How much of the control is shown.
2918
+ *
2919
+ * A union rather than a set of `showX` booleans, so the variants stay mutually
2920
+ * exclusive as more are added.
2921
+ */
2922
+ type TxPaginationAppearance = 'full' | 'compact' | 'simple';
2923
+ /** Simple property configuration for {@link TxPaginationComponent}. */
2924
+ interface TxPaginationConfig {
2925
+ /**
2926
+ * `full` shows numbered pages, a range summary and a page-size selector;
2927
+ * `compact` drops the numbers; `simple` is just previous/next.
2928
+ * Defaults to `full`.
2929
+ */
2930
+ appearance?: TxPaginationAppearance;
2931
+ /** Page sizes offered in the selector. Omit to hide the selector. */
2932
+ pageSizeOptions?: readonly number[];
2933
+ /** Pages shown either side of the current one. Defaults to 1. */
2934
+ siblings?: number;
2935
+ /** Noun used in the range summary, e.g. "12–20 of 84 reports". */
2936
+ itemLabel?: string;
2937
+ disabled?: boolean;
2938
+ ariaLabel?: string;
2939
+ }
2940
+ declare const TX_PAGINATION_DEFAULTS: {
2941
+ readonly appearance: "full";
2942
+ readonly siblings: 1;
2943
+ readonly itemLabel: "items";
2944
+ readonly ariaLabel: "Pagination";
2945
+ };
2946
+ /**
2947
+ * A standalone pagination control.
2948
+ *
2949
+ * Used on its own, and by {@link TxTableComponent} for its footer — the table
2950
+ * does not reimplement any of this.
2951
+ *
2952
+ * All arithmetic lives in `pagination-utils` and is unit-tested there: page
2953
+ * clamping in particular matters, because deleting the last row of the last
2954
+ * page would otherwise strand the user on a page that no longer exists.
2955
+ *
2956
+ * @example
2957
+ * ```html
2958
+ * <tx-pagination
2959
+ * [total]="reports().length"
2960
+ * [(pageIndex)]="pageIndex"
2961
+ * [(pageSize)]="pageSize"
2962
+ * [config]="{ pageSizeOptions: [10, 25, 50], itemLabel: 'reports' }" />
2963
+ * ```
2964
+ *
2965
+ * Config is a signal input — replace the object rather than mutating it.
2966
+ */
2967
+ declare class TxPaginationComponent {
2968
+ readonly config: _angular_core.InputSignal<Partial<TxPaginationConfig>>;
2969
+ /** Total number of rows across all pages. */
2970
+ readonly total: _angular_core.InputSignal<number>;
2971
+ /** Zero-based current page. */
2972
+ readonly pageIndex: _angular_core.ModelSignal<number>;
2973
+ readonly pageSize: _angular_core.ModelSignal<number>;
2974
+ /** Emitted whenever the page or the page size changes. */
2975
+ readonly pageChange: _angular_core.OutputEmitterRef<{
2976
+ pageIndex: number;
2977
+ pageSize: number;
2978
+ }>;
2979
+ private readonly resolved;
2980
+ protected readonly appearance: _angular_core.Signal<TxPaginationAppearance | undefined>;
2981
+ protected readonly itemLabel: _angular_core.Signal<string | undefined>;
2982
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
2983
+ protected readonly pageSizeOptions: _angular_core.Signal<readonly number[]>;
2984
+ protected readonly pageCount: _angular_core.Signal<number>;
2985
+ protected readonly range: _angular_core.Signal<_tx_angular_design_system_ui_kit.TxPageRange>;
2986
+ protected readonly items: _angular_core.Signal<(number | "gap")[]>;
2987
+ protected readonly navClass: string;
2988
+ protected readonly pageClass: string;
2989
+ protected readonly selectClass: string;
2990
+ /** Moves to a page, clamped to one that exists. */
2991
+ goTo(index: number): void;
2992
+ protected onPageSize(event: Event): void;
2993
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxPaginationComponent, never>;
2994
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxPaginationComponent, "tx-pagination", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "total": { "alias": "total"; "required": true; "isSignal": true; }; "pageIndex": { "alias": "pageIndex"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; }, { "pageIndex": "pageIndexChange"; "pageSize": "pageSizeChange"; "pageChange": "pageChange"; }, never, never, true, never>;
2995
+ }
2996
+
2997
+ /** Semantic colour of a badge. */
2998
+ type TxBadgeVariant = 'neutral' | 'primary' | 'accent' | 'info' | 'success' | 'warning' | 'danger';
2999
+ /** How the badge is filled. */
3000
+ type TxBadgeAppearance = 'subtle' | 'solid' | 'outline';
3001
+ /** Simple property configuration for {@link TxBadgeComponent}. */
3002
+ interface TxBadgeConfig {
3003
+ /** Genuinely required: a badge with no text is decoration, not information. */
3004
+ label: string;
3005
+ /** Defaults to `neutral`. */
3006
+ variant?: TxBadgeVariant;
3007
+ /** Defaults to `subtle`. */
3008
+ appearance?: TxBadgeAppearance;
3009
+ /** Defaults to `md`. */
3010
+ size?: 'sm' | 'md';
3011
+ /** Registered icon name shown before the label. */
3012
+ icon?: string;
3013
+ /** Small filled circle before the label, for a status pip. */
3014
+ dot?: boolean;
3015
+ /** Strikes the label through, for a retired or superseded item. */
3016
+ struck?: boolean;
3017
+ /** Shows a remove button and enables the `removed` output. */
3018
+ removable?: boolean;
3019
+ }
3020
+ declare const TX_BADGE_DEFAULTS: {
3021
+ readonly variant: "neutral";
3022
+ readonly appearance: "subtle";
3023
+ readonly size: "md";
3024
+ };
3025
+ /**
3026
+ * A small status pill or tag.
3027
+ *
3028
+ * Rendered in the mono face at the smallest type step, matching the reference
3029
+ * design's treatment for statuses, counts and part classifications.
3030
+ *
3031
+ * @example
3032
+ * ```html
3033
+ * <tx-badge [config]="{ label: 'critical', variant: 'danger' }" />
3034
+ * <tx-badge [config]="{ label: 'Gearbox', removable: true }" (removed)="drop()" />
3035
+ * ```
3036
+ *
3037
+ * Config is a signal input — replace the object rather than mutating it.
3038
+ */
3039
+ declare class TxBadgeComponent {
3040
+ readonly config: _angular_core.InputSignal<TxBadgeConfig>;
3041
+ /** Emitted by the remove button. The parent owns the list. */
3042
+ readonly removed: _angular_core.OutputEmitterRef<void>;
3043
+ private readonly resolved;
3044
+ private readonly variant;
3045
+ protected readonly rootClass: _angular_core.Signal<string>;
3046
+ protected readonly labelClass: _angular_core.Signal<string>;
3047
+ protected readonly dotClass: _angular_core.Signal<string>;
3048
+ protected readonly removeClass: _angular_core.Signal<string>;
3049
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxBadgeComponent, never>;
3050
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxBadgeComponent, "tx-badge", never, { "config": { "alias": "config"; "required": true; "isSignal": true; }; }, { "removed": "removed"; }, never, never, true, never>;
3051
+ }
3052
+
3053
+ /**
3054
+ * Visual treatment of the rule.
3055
+ *
3056
+ * `groove` is the reference design's one ornament — a diagonal tread band. It
3057
+ * is the brand's signature, so it ships as a divider variant rather than being
3058
+ * re-cut by hand wherever it is wanted.
3059
+ */
3060
+ type TxDividerVariant = 'line' | 'subtle' | 'groove';
3061
+ /** Simple property configuration for {@link TxDividerComponent}. */
3062
+ interface TxDividerConfig {
3063
+ /** Defaults to `horizontal`. */
3064
+ orientation?: 'horizontal' | 'vertical';
3065
+ /** Defaults to `line`. */
3066
+ variant?: TxDividerVariant;
3067
+ /** Text set into the rule. Horizontal only; ignored by `groove`. */
3068
+ label?: string;
3069
+ /** Where the label sits. Defaults to `center`. */
3070
+ labelPosition?: 'start' | 'center' | 'end';
3071
+ /** Vertical margin around the rule. Defaults to `md`. */
3072
+ spacing?: 'none' | 'sm' | 'md' | 'lg';
3073
+ }
3074
+ declare const TX_DIVIDER_DEFAULTS: {
3075
+ readonly orientation: "horizontal";
3076
+ readonly variant: "line";
3077
+ readonly labelPosition: "center";
3078
+ readonly spacing: "md";
3079
+ };
3080
+ /**
3081
+ * A rule between sections.
3082
+ *
3083
+ * `separator` role only when it carries no label; a labelled divider is a
3084
+ * heading in disguise and is announced as its text instead.
3085
+ *
3086
+ * @example
3087
+ * ```html
3088
+ * <tx-divider />
3089
+ * <tx-divider [config]="{ label: 'Failed parts' }" />
3090
+ * <tx-divider [config]="{ variant: 'groove', spacing: 'none' }" />
3091
+ * <tx-divider [config]="{ orientation: 'vertical', spacing: 'sm' }" />
3092
+ * ```
3093
+ *
3094
+ * Config is a signal input — replace the object rather than mutating it.
3095
+ */
3096
+ declare class TxDividerComponent {
3097
+ readonly config: _angular_core.InputSignal<Partial<TxDividerConfig>>;
3098
+ private readonly resolved;
3099
+ protected readonly label: _angular_core.Signal<string | null>;
3100
+ protected readonly orientation: _angular_core.Signal<"vertical" | "horizontal" | undefined>;
3101
+ protected readonly variant: _angular_core.Signal<TxDividerVariant | undefined>;
3102
+ protected readonly labelPosition: _angular_core.Signal<"start" | "end" | "center" | undefined>;
3103
+ /**
3104
+ * The tread band: diagonal brand-coloured strokes over a tinted ground.
3105
+ * Built from gradients rather than an image so it re-themes with the tokens.
3106
+ */
3107
+ protected readonly grooveClass = "tx-groove";
3108
+ protected readonly hostClass: _angular_core.Signal<string>;
3109
+ protected readonly ruleClass: _angular_core.Signal<string>;
3110
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxDividerComponent, never>;
3111
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxDividerComponent, "tx-divider", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
3112
+ }
3113
+
3114
+ /** Surface treatment of the card. */
3115
+ type TxCardAppearance = 'panel' | 'plain' | 'sunken';
3116
+ /** Simple property configuration for {@link TxCardComponent}. */
3117
+ interface TxCardConfig {
3118
+ /** Heading. Rendered in the reference design's uppercase panel-header style. */
3119
+ title?: string;
3120
+ /** Secondary line under the title. */
3121
+ description?: string;
3122
+ /** Registered icon name shown before the title. */
3123
+ icon?: string;
3124
+ /** Defaults to `panel`. */
3125
+ appearance?: TxCardAppearance;
3126
+ /** Body padding. Defaults to `md`. `none` suits a table or list body. */
3127
+ padding?: 'none' | 'sm' | 'md' | 'lg';
3128
+ /** Adds a chevron that collapses the body. */
3129
+ collapsible?: boolean;
3130
+ /** Short muted text beside the title, e.g. the current selection. */
3131
+ summary?: string;
3132
+ /**
3133
+ * Leading accent bar in a semantic colour, matching the reference design's
3134
+ * failed-part card.
3135
+ */
3136
+ accent?: 'none' | 'primary' | 'danger' | 'warning' | 'info';
3137
+ }
3138
+ declare const TX_CARD_DEFAULTS: {
3139
+ readonly appearance: "panel";
3140
+ readonly padding: "md";
3141
+ readonly accent: "none";
3142
+ };
3143
+ /**
3144
+ * A bordered panel with an optional header, and slots for header actions and a
3145
+ * footer.
3146
+ *
3147
+ * The header's action slot is a projected `[txCardActions]`, not a config
3148
+ * field, so a panel header can carry arbitrary buttons — which is exactly the
3149
+ * case config could never cover.
3150
+ *
3151
+ * @example
3152
+ * ```html
3153
+ * <tx-card [config]="{ title: 'Failed parts', collapsible: true }">
3154
+ * <ng-container txCardActions>
3155
+ * <tx-button [config]="{ label: 'Add', icon: 'plus', size: 'sm' }" />
3156
+ * </ng-container>
3157
+ *
3158
+ * <p>Body</p>
3159
+ *
3160
+ * <ng-container txCardFooter>
3161
+ * <tx-button [config]="{ label: 'Save', variant: 'primary' }" />
3162
+ * </ng-container>
3163
+ * </tx-card>
3164
+ * ```
3165
+ *
3166
+ * Config is a signal input — replace the object rather than mutating it.
3167
+ */
3168
+ declare class TxCardComponent {
3169
+ readonly config: _angular_core.InputSignal<Partial<TxCardConfig>>;
3170
+ /** Whether the body is shown. Two-way, so a page can collapse every card. */
3171
+ readonly expanded: _angular_core.ModelSignal<boolean>;
3172
+ readonly toggled: _angular_core.OutputEmitterRef<boolean>;
3173
+ private readonly resolved;
3174
+ protected readonly hasHeader: _angular_core.Signal<boolean>;
3175
+ protected readonly rootClass: _angular_core.Signal<string>;
3176
+ protected readonly headerClass: _angular_core.Signal<string>;
3177
+ protected readonly bodyClass: _angular_core.Signal<string>;
3178
+ protected toggle(): void;
3179
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxCardComponent, never>;
3180
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxCardComponent, "tx-card", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "expanded": { "alias": "expanded"; "required": false; "isSignal": true; }; }, { "expanded": "expandedChange"; "toggled": "toggled"; }, never, ["[txCardActions]", "*", "[txCardFooter]"], true, never>;
3181
+ }
3182
+
3183
+ /** Simple property configuration for {@link TxEmptyStateComponent}. */
3184
+ interface TxEmptyStateConfig {
3185
+ /** Genuinely required: an empty state with no message explains nothing. */
3186
+ title: string;
3187
+ /** What to do about it. */
3188
+ description?: string;
3189
+ /** Registered icon name. Defaults to `inbox`; `null` hides it. */
3190
+ icon?: string | null;
3191
+ /** Defaults to `md`. `sm` suits an empty panel body or popup. */
3192
+ size?: 'sm' | 'md' | 'lg';
3193
+ /** Defaults to `dashed`. */
3194
+ appearance?: 'dashed' | 'plain';
3195
+ }
3196
+ declare const TX_EMPTY_STATE_DEFAULTS: {
3197
+ readonly icon: "inbox";
3198
+ readonly size: "md";
3199
+ readonly appearance: "dashed";
3200
+ };
3201
+ /**
3202
+ * The "there is nothing here" panel.
3203
+ *
3204
+ * Actions are projected rather than configured, so an empty state can offer
3205
+ * whatever the situation calls for — a button, a link, a short form.
3206
+ *
3207
+ * @example
3208
+ * ```html
3209
+ * <tx-empty-state [config]="{ title: 'No reports yet',
3210
+ * description: 'Create one to get started.' }">
3211
+ * <tx-button [config]="{ label: 'New report', variant: 'primary', icon: 'plus' }" />
3212
+ * </tx-empty-state>
3213
+ * ```
3214
+ *
3215
+ * Config is a signal input — replace the object rather than mutating it.
3216
+ */
3217
+ declare class TxEmptyStateComponent {
3218
+ readonly config: _angular_core.InputSignal<TxEmptyStateConfig>;
3219
+ private readonly resolved;
3220
+ protected readonly iconName: _angular_core.Signal<string | null>;
3221
+ protected readonly rootClass: _angular_core.Signal<string>;
3222
+ protected readonly titleClass: _angular_core.Signal<string>;
3223
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxEmptyStateComponent, never>;
3224
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxEmptyStateComponent, "tx-empty-state", never, { "config": { "alias": "config"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
3225
+ }
3226
+
3227
+ /**
3228
+ * One step in the trail.
3229
+ *
3230
+ * Items are data. A crumb navigates by `routerLink` or `href`, or by nothing at
3231
+ * all — in which case the component emits `selected` and the application
3232
+ * decides. No callback ever lives on the item.
3233
+ */
3234
+ interface TxBreadcrumbItem {
3235
+ label: string;
3236
+ /** Angular router target. Takes precedence over `href`. */
3237
+ routerLink?: string | readonly unknown[];
3238
+ /** Plain link target, for anything outside the router. */
3239
+ href?: string;
3240
+ /** Registered icon name shown before the label. */
3241
+ icon?: string;
3242
+ }
3243
+ /** Simple property configuration for {@link TxBreadcrumbComponent}. */
3244
+ interface TxBreadcrumbConfig {
3245
+ /** Registered icon name used between crumbs. Defaults to `chevron-right`. */
3246
+ separator?: string;
3247
+ /**
3248
+ * Above this many crumbs the middle ones collapse behind an ellipsis, so a
3249
+ * deep trail cannot wrap onto three lines. `0` disables collapsing.
3250
+ * Defaults to 4.
3251
+ */
3252
+ maxVisible?: number;
3253
+ /** Defaults to `md`. */
3254
+ size?: 'sm' | 'md';
3255
+ /** Accessible name. Defaults to `Breadcrumb`. */
3256
+ ariaLabel?: string;
3257
+ }
3258
+ declare const TX_BREADCRUMB_DEFAULTS: {
3259
+ readonly separator: "chevron-right";
3260
+ readonly maxVisible: 4;
3261
+ readonly size: "md";
3262
+ readonly ariaLabel: "Breadcrumb";
3263
+ };
3264
+ /**
3265
+ * A crumb, or the ellipsis standing in for the ones that were collapsed.
3266
+ *
3267
+ * A nullable `item` rather than a discriminated union: Angular's template type
3268
+ * checker narrows cleanly through `@if (crumb.item; as item)`, whereas a `kind`
3269
+ * discriminant does not survive an `@else if` chain.
3270
+ */
3271
+ interface Crumb {
3272
+ /** `null` for the ellipsis placeholder. */
3273
+ item: TxBreadcrumbItem | null;
3274
+ }
3275
+ /**
3276
+ * A trail of ancestor links.
3277
+ *
3278
+ * The last crumb is the current page: it is never a link, and carries
3279
+ * `aria-current="page"`.
3280
+ *
3281
+ * @example
3282
+ * ```html
3283
+ * <tx-breadcrumb
3284
+ * [items]="[{ label: 'Reports', routerLink: '/reports' }, { label: 'R-1042' }]" />
3285
+ * ```
3286
+ *
3287
+ * Config is a signal input — replace the object rather than mutating it.
3288
+ */
3289
+ declare class TxBreadcrumbComponent {
3290
+ readonly config: _angular_core.InputSignal<Partial<TxBreadcrumbConfig>>;
3291
+ /** The trail, root first. Data, so it is its own input. */
3292
+ readonly items: _angular_core.InputSignal<readonly TxBreadcrumbItem[]>;
3293
+ /** Emitted when a crumb with no link target is activated. */
3294
+ readonly selected: _angular_core.OutputEmitterRef<TxBreadcrumbItem>;
3295
+ private readonly resolved;
3296
+ protected readonly separator: _angular_core.Signal<string>;
3297
+ protected readonly hiddenCount: _angular_core.Signal<number>;
3298
+ /** First crumb, an ellipsis, then the tail — so the trail never wraps. */
3299
+ protected readonly crumbs: _angular_core.Signal<Crumb[]>;
3300
+ protected readonly listClass: _angular_core.Signal<string>;
3301
+ protected readonly linkClass: _angular_core.Signal<string>;
3302
+ protected readonly currentClass: _angular_core.Signal<string>;
3303
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxBreadcrumbComponent, never>;
3304
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxBreadcrumbComponent, "tx-breadcrumb", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": true; "isSignal": true; }; }, { "selected": "selected"; }, never, never, true, never>;
3305
+ }
3306
+
3307
+ /**
3308
+ * One tab.
3309
+ *
3310
+ * Tabs are data; each panel's *content* is a projected
3311
+ * `ng-template[txTabPanel="value"]`, because content is structural and could
3312
+ * never be a config field.
3313
+ */
3314
+ interface TxTab {
3315
+ /** Unique value. Also what a `txTabPanel` template matches on. */
3316
+ value: string;
3317
+ label: string;
3318
+ /** Registered icon name shown before the label. */
3319
+ icon?: string;
3320
+ /** Short count or status after the label. */
3321
+ badge?: string;
3322
+ disabled?: boolean;
3323
+ }
3324
+ /** Visual treatment of the tab strip. */
3325
+ type TxTabsAppearance = 'underline' | 'pills' | 'enclosed';
3326
+ /** Simple property configuration for {@link TxTabsComponent}. */
3327
+ interface TxTabsConfig {
3328
+ /** Defaults to `underline`. */
3329
+ appearance?: TxTabsAppearance;
3330
+ /** Defaults to `horizontal`. */
3331
+ orientation?: 'horizontal' | 'vertical';
3332
+ /** Defaults to `md`. */
3333
+ size?: 'sm' | 'md';
3334
+ /**
3335
+ * `follow` selects a tab as soon as it is focused, which is the usual
3336
+ * behaviour for cheap panels; `explicit` waits for Enter or Space, which is
3337
+ * right when switching tabs costs a fetch. Defaults to `follow`.
3338
+ */
3339
+ activation?: 'follow' | 'explicit';
3340
+ /** Stretches tabs to fill the strip. Defaults to false. */
3341
+ stretch?: boolean;
3342
+ disabled?: boolean;
3343
+ ariaLabel?: string;
3344
+ }
3345
+ declare const TX_TABS_DEFAULTS: {
3346
+ readonly appearance: "underline";
3347
+ readonly orientation: "horizontal";
3348
+ readonly size: "md";
3349
+ readonly activation: "follow";
3350
+ };
3351
+ /**
3352
+ * Marks an `ng-template` as one tab's panel content.
3353
+ *
3354
+ * @example
3355
+ * ```html
3356
+ * <ng-template txTabPanel="details">…</ng-template>
3357
+ * ```
3358
+ */
3359
+ declare class TxTabPanelDirective {
3360
+ /** The `value` of the tab this template belongs to. */
3361
+ readonly tab: _angular_core.InputSignal<string>;
3362
+ readonly template: TemplateRef<unknown>;
3363
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxTabPanelDirective, never>;
3364
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TxTabPanelDirective, "ng-template[txTabPanel]", never, { "tab": { "alias": "txTabPanel"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
3365
+ }
3366
+ /**
3367
+ * Tabs.
3368
+ *
3369
+ * Behaviour is `@angular/aria`'s `ngTabs` / `ngTabList` / `ngTab` /
3370
+ * `ngTabPanel`: the roving tab stop, arrow-key navigation, Home/End, and the
3371
+ * `aria-controls` / `aria-labelledby` pairing between each tab and its panel.
3372
+ * Every visual state is read off `aria-selected` and `aria-disabled` rather
3373
+ * than mirrored into TypeScript.
3374
+ *
3375
+ * Panel content is deferred by Aria, so a panel is only created once its tab is
3376
+ * first selected.
3377
+ *
3378
+ * @example
3379
+ * ```html
3380
+ * <tx-tabs [tabs]="tabs" [(selected)]="current">
3381
+ * <ng-template txTabPanel="details">…</ng-template>
3382
+ * <ng-template txTabPanel="history">…</ng-template>
3383
+ * </tx-tabs>
3384
+ * ```
3385
+ *
3386
+ * Config is a signal input — replace the object rather than mutating it.
3387
+ */
3388
+ declare class TxTabsComponent {
3389
+ readonly config: _angular_core.InputSignal<Partial<TxTabsConfig>>;
3390
+ /** The tabs. Data, so they are their own input. */
3391
+ readonly tabs: _angular_core.InputSignal<readonly TxTab[]>;
3392
+ /** The selected tab's `value`. */
3393
+ readonly selected: _angular_core.ModelSignal<string | undefined>;
3394
+ readonly selectedChanged: _angular_core.OutputEmitterRef<string | undefined>;
3395
+ private readonly panels;
3396
+ private readonly resolved;
3397
+ protected readonly orientation: _angular_core.Signal<"vertical" | "horizontal">;
3398
+ protected readonly activation: _angular_core.Signal<"follow" | "explicit">;
3399
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
3400
+ protected panelFor(value: string): TemplateRef<unknown> | null;
3401
+ protected readonly rootClass: _angular_core.Signal<string>;
3402
+ protected readonly listClass: _angular_core.Signal<string>;
3403
+ protected readonly triggerClass: _angular_core.Signal<string>;
3404
+ protected readonly panelsClass: _angular_core.Signal<string>;
3405
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxTabsComponent, never>;
3406
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxTabsComponent, "tx-tabs", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "tabs": { "alias": "tabs"; "required": true; "isSignal": true; }; "selected": { "alias": "selected"; "required": false; "isSignal": true; }; }, { "selected": "selectedChange"; "selectedChanged": "selectedChanged"; }, ["panels"], never, true, never>;
3407
+ }
3408
+
3409
+ /**
3410
+ * One accordion section.
3411
+ *
3412
+ * Sections are data. Both the body and any header buttons are projected
3413
+ * templates, because a header that "must accept arbitrary buttons" is exactly
3414
+ * what a config field can never express.
3415
+ */
3416
+ interface TxAccordionItem {
3417
+ /** Unique value. Also what the content and header-action templates match on. */
3418
+ value: string;
3419
+ label: string;
3420
+ /** Secondary line under the label. */
3421
+ description?: string;
3422
+ /** Registered icon name shown before the label. */
3423
+ icon?: string;
3424
+ /** Short count or status shown after the label. */
3425
+ badge?: string;
3426
+ disabled?: boolean;
3427
+ }
3428
+ /** Visual treatment. */
3429
+ type TxAccordionAppearance = 'separated' | 'contained' | 'flush';
3430
+ /** Simple property configuration for {@link TxAccordionComponent}. */
3431
+ interface TxAccordionConfig {
3432
+ /** Defaults to `separated`. */
3433
+ appearance?: TxAccordionAppearance;
3434
+ /** Defaults to `md`. */
3435
+ size?: 'sm' | 'md';
3436
+ /** More than one section open at a time. Defaults to true. */
3437
+ multiple?: boolean;
3438
+ /** Which side the chevron sits on. Defaults to `start`. */
3439
+ chevronPosition?: 'start' | 'end';
3440
+ disabled?: boolean;
3441
+ }
3442
+ declare const TX_ACCORDION_DEFAULTS: {
3443
+ readonly appearance: "separated";
3444
+ readonly size: "md";
3445
+ readonly multiple: true;
3446
+ readonly chevronPosition: "start";
3447
+ };
3448
+ /** Marks an `ng-template` as one section's body. */
3449
+ declare class TxAccordionContentDirective {
3450
+ /** The `value` of the section this template belongs to. */
3451
+ readonly item: _angular_core.InputSignal<string>;
3452
+ readonly template: TemplateRef<unknown>;
3453
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxAccordionContentDirective, never>;
3454
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TxAccordionContentDirective, "ng-template[txAccordionContent]", never, { "item": { "alias": "txAccordionContent"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
3455
+ }
3456
+ /**
3457
+ * Marks an `ng-template` as buttons for one section's header.
3458
+ *
3459
+ * Rendered outside the trigger button, because a button inside a button is
3460
+ * invalid and unreachable — which is why this is a slot rather than a config
3461
+ * field.
3462
+ */
3463
+ declare class TxAccordionHeaderActionsDirective {
3464
+ /** The `value` of the section these actions belong to. */
3465
+ readonly item: _angular_core.InputSignal<string>;
3466
+ readonly template: TemplateRef<unknown>;
3467
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxAccordionHeaderActionsDirective, never>;
3468
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TxAccordionHeaderActionsDirective, "ng-template[txAccordionHeaderActions]", never, { "item": { "alias": "txAccordionHeaderActions"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
3469
+ }
3470
+ /**
3471
+ * A stack of collapsible sections.
3472
+ *
3473
+ * Behaviour is `@angular/aria`'s `ngAccordionGroup` / `ngAccordionPanel` /
3474
+ * `ngAccordionTrigger` / `ngAccordionContent`: arrow-key navigation between
3475
+ * headers, Home/End, the `aria-expanded` / `aria-controls` pairing, and
3476
+ * deferred rendering so a collapsed body is never created.
3477
+ *
3478
+ * Header actions are projected and rendered *beside* the trigger, never inside
3479
+ * it: nesting a button in a button is invalid HTML and the inner one cannot be
3480
+ * reached by keyboard.
3481
+ *
3482
+ * @example
3483
+ * ```html
3484
+ * <tx-accordion [items]="sections" [(expanded)]="open">
3485
+ * <ng-template txAccordionContent="symptoms">…</ng-template>
3486
+ * <ng-template txAccordionHeaderActions="symptoms">
3487
+ * <tx-button [config]="{ label: 'Add symptom', icon: 'plus', size: 'sm' }" />
3488
+ * </ng-template>
3489
+ * </tx-accordion>
3490
+ * ```
3491
+ *
3492
+ * Config is a signal input — replace the object rather than mutating it.
3493
+ */
3494
+ declare class TxAccordionComponent {
3495
+ readonly config: _angular_core.InputSignal<Partial<TxAccordionConfig>>;
3496
+ /** The sections. Data, so they are their own input. */
3497
+ readonly items: _angular_core.InputSignal<readonly TxAccordionItem[]>;
3498
+ /** Values of the open sections. */
3499
+ readonly expanded: _angular_core.ModelSignal<string[]>;
3500
+ readonly expandedChanged: _angular_core.OutputEmitterRef<string[]>;
3501
+ private readonly contents;
3502
+ private readonly headerActions;
3503
+ private readonly resolved;
3504
+ private readonly expandedSet;
3505
+ protected readonly isMultiple: _angular_core.Signal<boolean>;
3506
+ protected readonly isDisabled: _angular_core.Signal<boolean>;
3507
+ protected readonly chevronStart: _angular_core.Signal<boolean>;
3508
+ protected readonly chevronClass: string;
3509
+ protected contentFor(value: string): TemplateRef<unknown> | null;
3510
+ protected headerActionsFor(value: string): TemplateRef<unknown> | null;
3511
+ protected isExpanded(value: string): boolean;
3512
+ protected setExpanded(value: string, expanded: boolean): void;
3513
+ protected readonly rootClass: _angular_core.Signal<string>;
3514
+ protected readonly sectionClass: _angular_core.Signal<string>;
3515
+ protected readonly headerClass: _angular_core.Signal<string>;
3516
+ protected readonly triggerClass: _angular_core.Signal<string>;
3517
+ protected readonly bodyClass: _angular_core.Signal<string>;
3518
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxAccordionComponent, never>;
3519
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxAccordionComponent, "tx-accordion", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": true; "isSignal": true; }; "expanded": { "alias": "expanded"; "required": false; "isSignal": true; }; }, { "expanded": "expandedChange"; "expandedChanged": "expandedChanged"; }, ["contents", "headerActions"], never, true, never>;
3520
+ }
3521
+
3522
+ /** Simple property configuration for {@link TxHeaderComponent}. */
3523
+ interface TxHeaderConfig {
3524
+ /**
3525
+ * Wordmark text. Rendered in the display face, uppercase and letter-spaced,
3526
+ * matching the reference design's lockup.
3527
+ */
3528
+ wordmark?: string;
3529
+ /**
3530
+ * A slice of the wordmark to accent in the brand colour, e.g. the `X` in
3531
+ * `TRAXTION`. Matched case-sensitively, first occurrence only.
3532
+ */
3533
+ wordmarkAccent?: string;
3534
+ /** Application name, shown after a divider. */
3535
+ appName?: string;
3536
+ /** Registered icon name shown before the wordmark. */
3537
+ icon?: string;
3538
+ /** Shows the menu button below `lg`, for toggling a sidebar. Defaults to true. */
3539
+ menuButton?: boolean;
3540
+ /** Reflected on the menu button as `aria-expanded`. */
3541
+ menuOpen?: boolean;
3542
+ /** Id of the element the menu button controls. */
3543
+ menuControls?: string;
3544
+ /** Sticks the header to the top of the viewport. Defaults to true. */
3545
+ sticky?: boolean;
3546
+ /** Adds the brand's tread band under the header. Defaults to false. */
3547
+ groove?: boolean;
3548
+ }
3549
+ declare const TX_HEADER_DEFAULTS: {
3550
+ readonly menuButton: true;
3551
+ readonly sticky: true;
3552
+ };
3553
+ /**
3554
+ * The application header bar.
3555
+ *
3556
+ * The wordmark and app name are simple properties; everything else — search,
3557
+ * user chip, actions — is projected, because a header's contents are exactly
3558
+ * the sort of thing a config object could never anticipate.
3559
+ *
3560
+ * Slots: `[txHeaderStart]` after the wordmark, default content in the middle,
3561
+ * `[txHeaderEnd]` pinned to the trailing edge.
3562
+ *
3563
+ * @example
3564
+ * ```html
3565
+ * <tx-header
3566
+ * [config]="{ wordmark: 'TRAXTION', wordmarkAccent: 'X', appName: 'UI Kit',
3567
+ * menuOpen: navOpen(), menuControls: 'app-nav' }"
3568
+ * (menuToggled)="navOpen.set(!navOpen())">
3569
+ * <div txHeaderEnd>
3570
+ * <tx-button [config]="{ label: 'Sign out', variant: 'ghost', size: 'sm' }" />
3571
+ * </div>
3572
+ * </tx-header>
3573
+ * ```
3574
+ *
3575
+ * Config is a signal input — replace the object rather than mutating it.
3576
+ */
3577
+ declare class TxHeaderComponent {
3578
+ readonly config: _angular_core.InputSignal<Partial<TxHeaderConfig>>;
3579
+ /** Emitted with the requested state. The app owns whether the nav is open. */
3580
+ readonly menuToggled: _angular_core.OutputEmitterRef<boolean>;
3581
+ private readonly resolved;
3582
+ protected readonly showMenuButton: _angular_core.Signal<boolean>;
3583
+ /** Splits the wordmark so one slice can carry the brand colour. */
3584
+ protected readonly wordmarkParts: _angular_core.Signal<{
3585
+ before: string;
3586
+ accent: string;
3587
+ after: string;
3588
+ } | null>;
3589
+ protected readonly grooveClass = "tx-groove";
3590
+ protected readonly hostClass: _angular_core.Signal<string>;
3591
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxHeaderComponent, never>;
3592
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxHeaderComponent, "tx-header", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; }, { "menuToggled": "menuToggled"; }, never, ["[txHeaderStart]", "*", "[txHeaderEnd]"], true, never>;
3593
+ }
3594
+
3595
+ /**
3596
+ * One navigation entry.
3597
+ *
3598
+ * Items are data, and nest through `children`. A link navigates by
3599
+ * `routerLink` or `href`; an item with neither emits `selected` and the
3600
+ * application decides. No callback ever lives on the item.
3601
+ */
3602
+ interface TxNavItem {
3603
+ /** Unique within the sidebar. Used for expansion state. */
3604
+ id: string;
3605
+ label: string;
3606
+ /** Registered icon name. */
3607
+ icon?: string;
3608
+ /** Short count or status after the label. */
3609
+ badge?: string;
3610
+ /** Angular router target. Takes precedence over `href`. */
3611
+ routerLink?: string | readonly unknown[];
3612
+ /** Plain link target. */
3613
+ href?: string;
3614
+ /** Nested entries. A parent with children is a disclosure, not a link. */
3615
+ children?: readonly TxNavItem[];
3616
+ disabled?: boolean;
3617
+ }
3618
+ /** A titled block of entries. */
3619
+ interface TxNavGroup {
3620
+ /** Optional heading. Omit for an untitled block. */
3621
+ label?: string;
3622
+ items: readonly TxNavItem[];
3623
+ }
3624
+ /** Simple property configuration for {@link TxSidebarComponent}. */
3625
+ interface TxSidebarConfig {
3626
+ /**
3627
+ * Below this breakpoint the sidebar becomes an overlay drawer; at and above
3628
+ * it, a static column. Defaults to `lg`.
3629
+ */
3630
+ breakpoint?: 'sm' | 'md' | 'lg' | 'xl';
3631
+ /** Collapses the static sidebar to an icon rail. Defaults to false. */
3632
+ railed?: boolean;
3633
+ /** Defaults to `md`. */
3634
+ size?: 'sm' | 'md';
3635
+ /** Accessible name. Defaults to `Main`. */
3636
+ ariaLabel?: string;
3637
+ }
3638
+ declare const TX_SIDEBAR_DEFAULTS: {
3639
+ readonly breakpoint: "lg";
3640
+ readonly size: "md";
3641
+ readonly ariaLabel: "Main";
3642
+ };
3643
+ /**
3644
+ * The application's navigation sidebar.
3645
+ *
3646
+ * A static column from its breakpoint up, and an overlay drawer below it, with
3647
+ * a scrim that closes on click. Nested entries are disclosures that carry
3648
+ * `aria-expanded`; the active route is marked with `aria-current="page"` by
3649
+ * `RouterLinkActive`, and every selected/active style is read off that
3650
+ * attribute rather than from a mirrored boolean.
3651
+ *
3652
+ * Header and footer are projected slots, so a product can put a logo, a search
3653
+ * box or a user chip in without this component knowing about any of them.
3654
+ *
3655
+ * @example
3656
+ * ```html
3657
+ * <tx-sidebar
3658
+ * id="app-nav"
3659
+ * [groups]="navGroups"
3660
+ * [(open)]="navOpen"
3661
+ * [config]="{ breakpoint: 'lg' }">
3662
+ * <div txSidebarFooter>
3663
+ * <tx-button [config]="{ label: 'Sign out', variant: 'ghost', width: 'full' }" />
3664
+ * </div>
3665
+ * </tx-sidebar>
3666
+ * ```
3667
+ *
3668
+ * Config is a signal input — replace the object rather than mutating it.
3669
+ */
3670
+ declare class TxSidebarComponent {
3671
+ readonly config: _angular_core.InputSignal<Partial<TxSidebarConfig>>;
3672
+ /** The navigation tree, in groups. Data, so it is its own input. */
3673
+ readonly groups: _angular_core.InputSignal<readonly TxNavGroup[]>;
3674
+ /** Whether the drawer is open. Only meaningful below the breakpoint. */
3675
+ readonly open: _angular_core.ModelSignal<boolean>;
3676
+ /** Ids of the expanded parent entries. */
3677
+ readonly expandedIds: _angular_core.ModelSignal<string[]>;
3678
+ /** Emitted for an entry that has no link target. */
3679
+ readonly selected: _angular_core.OutputEmitterRef<TxNavItem>;
3680
+ private readonly resolved;
3681
+ private readonly breakpoint;
3682
+ private readonly expandedSet;
3683
+ protected readonly isRailed: _angular_core.Signal<boolean>;
3684
+ protected readonly navClass: _angular_core.Signal<string>;
3685
+ protected readonly scrimClass: _angular_core.Signal<string>;
3686
+ protected itemClass(depth: number): string;
3687
+ protected isExpanded(id: string): boolean;
3688
+ protected toggle(id: string): void;
3689
+ protected setOpen(open: boolean): void;
3690
+ /** Navigating from the drawer should close it; on desktop it is a no-op. */
3691
+ protected onNavigate(): void;
3692
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TxSidebarComponent, never>;
3693
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TxSidebarComponent, "tx-sidebar", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "groups": { "alias": "groups"; "required": true; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; "expandedIds": { "alias": "expandedIds"; "required": false; "isSignal": true; }; }, { "open": "openChange"; "expandedIds": "expandedIdsChange"; "selected": "selected"; }, never, ["[txSidebarHeader]", "[txSidebarFooter]"], true, never>;
3694
+ }
3695
+
3696
+ export { CONTROL_ICON_SIZE, TX_ACCORDION_DEFAULTS, TX_ALERT_DEFAULTS, TX_BADGE_DEFAULTS, TX_BREADCRUMB_DEFAULTS, TX_BUTTON_DEFAULTS, TX_CARD_DEFAULTS, TX_CHIPS_INPUT_DEFAULTS, TX_DATEPICKER_DEFAULTS, TX_DEFAULT_ICONS, TX_DIALOG_DEFAULTS, TX_DIVIDER_DEFAULTS, TX_DROPDOWN_TREE_DEFAULTS, TX_EMPTY_STATE_DEFAULTS, TX_FORM_FIELD, TX_FORM_FIELD_DEFAULTS, TX_HEADER_DEFAULTS, TX_ICON_DEFAULTS, TX_INPUT_DEFAULTS, TX_MULTISELECT_DEFAULTS, TX_OVERLAY_DEFAULTS, TX_PAGINATION_DEFAULTS, TX_POPUP_EMPTY_CLASS, TX_POPUP_GROUP_CLASS, TX_POPUP_LIST_CLASS, TX_POPUP_MAX_HEIGHT, TX_POPUP_OPTION_CLASS, TX_POPUP_PANEL_CLASS, TX_RADIO_GROUP_DEFAULTS, TX_REORDER_LIST_DEFAULTS, TX_SELECT_DEFAULTS, TX_SIDEBAR_DEFAULTS, TX_SKELETON_DEFAULTS, TX_SPINNER_DEFAULTS, TX_TABLE_DEFAULTS, TX_TABS_DEFAULTS, TX_TEXTAREA_DEFAULTS, TX_TOOLTIP_DEFAULTS, TX_TREE_DEFAULTS, TX_TRIGGER_CHEVRON_CLASS, TX_TRIGGER_CLEAR_CLASS, TxAccordionComponent, TxAccordionContentDirective, TxAccordionHeaderActionsDirective, TxAlertComponent, TxBadgeComponent, TxBreadcrumbComponent, TxButtonComponent, TxCardComponent, TxCheckboxComponent, TxChipsInputComponent, TxConfirmDialogComponent, TxConnectedOverlayDirective, TxControlValueBridge, TxDatepickerComponent, TxDialogComponent, TxDialogService, TxDividerComponent, TxDropdownTreeComponent, TxEmptyStateComponent, TxFormFieldComponent, TxHeaderComponent, TxIconComponent, TxIconRegistry, TxInputComponent, TxMultiselectComponent, TxPaginationComponent, TxRadioGroupComponent, TxReorderListComponent, TxSelectComponent, TxSidebarComponent, TxSkeletonComponent, TxSpinnerComponent, TxSwitchComponent, TxTabPanelDirective, TxTableActionsDirective, TxTableCellDirective, TxTableComponent, TxTabsComponent, TxTextareaComponent, TxToastService, TxToastStackComponent, TxTooltipDirective, TxTooltipPanelComponent, TxTreeComponent, findTxTreeNode, flattenTxOptions, flattenTxTree, isTxOptionGroup, txAddDays, txAddMonths, txAriaSort, txBindFormField, txBuildMonthGrid, txClampDate, txClampPageIndex, txColumnValue, txCompareValues, txControlShellClass, txDaysInMonth, txFormatDate, txFormatPlaceholder, txFullDateLabel, txIsSameDay, txIsSameMonth, txIsWithin, txMergeConfig, txMonthLabel, txNextSort, txPageCount, txPageItems, txPageRange, txPaginate, txParseDate, txSelectionSummary, txSortRows, txStartOfDay, txStartOfMonth, txTreeBranchIds, txTreeNodeIds, txUniqueId, txVisibleChips, txWeekdayLabels };
3697
+ export type { TxAccordionAppearance, TxAccordionConfig, TxAccordionItem, TxAlertAppearance, TxAlertConfig, TxAlertVariant, TxBadgeAppearance, TxBadgeConfig, TxBadgeVariant, TxBreadcrumbConfig, TxBreadcrumbItem, TxButtonConfig, TxButtonDisplay, TxButtonIconPosition, TxButtonSize, TxButtonVariant, TxCalendarDay, TxCardAppearance, TxCardConfig, TxCheckboxConfig, TxChipsInputConfig, TxChipsSource, TxColumnAlign, TxColumnPriority, TxColumnVariant, TxConfirmDialogConfig, TxControlShellOptions, TxControlSize, TxDateFormat, TxDatepickerConfig, TxDatepickerEntry, TxDialogConfig, TxDialogOpenConfig, TxDialogSize, TxDialogTone, TxDividerConfig, TxDividerVariant, TxDropdownTreeConfig, TxEmptyStateConfig, TxFormFieldApi, TxFormFieldBinding, TxFormFieldConfig, TxFormFieldLayout, TxFormFieldSize, TxHeaderConfig, TxIconConfig, TxIconDefinition, TxIconSize, TxInputConfig, TxInputType, TxMultiselectConfig, TxMultiselectSummary, TxNavGroup, TxNavItem, TxOption, TxOptionGroup, TxOverlayCloseReason, TxOverlayConfig, TxOverlayPlacement, TxOverlayWidth, TxPageRange, TxPaginationAppearance, TxPaginationConfig, TxPopupHeight, TxRadioAppearance, TxRadioGroupConfig, TxReorderHandle, TxReorderItem, TxReorderListConfig, TxSelectConfig, TxSidebarConfig, TxSkeletonConfig, TxSkeletonShape, TxSortDirection, TxSpinnerConfig, TxSpinnerSize, TxSpinnerTone, TxSwitchConfig, TxTab, TxTableColumn, TxTableConfig, TxTableSelection, TxTableSort, TxTabsAppearance, TxTabsConfig, TxTextareaConfig, TxTextareaResize, TxToastCloseReason, TxToastConfig, TxToastPosition, TxToastRef, TxToastServiceConfig, TxToastVariant, TxTooltipConfig, TxTreeCheckboxes, TxTreeConfig, TxTreeExpansion, TxTreeGuides, TxTreeNode, TxTreeSelection, TxTreeSlotContext, TxWeekday };