@cdevhub/ngx-tw 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +264 -49
  2. package/fesm2022/cdevhub-ngx-tw-accordion.mjs +11 -7
  3. package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -1
  4. package/fesm2022/cdevhub-ngx-tw-alert.mjs +43 -29
  5. package/fesm2022/cdevhub-ngx-tw-alert.mjs.map +1 -1
  6. package/fesm2022/cdevhub-ngx-tw-aspect-ratio.mjs +103 -0
  7. package/fesm2022/cdevhub-ngx-tw-aspect-ratio.mjs.map +1 -0
  8. package/fesm2022/cdevhub-ngx-tw-avatar.mjs +56 -31
  9. package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -1
  10. package/fesm2022/cdevhub-ngx-tw-badge.mjs +61 -35
  11. package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -1
  12. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +154 -93
  13. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -1
  14. package/fesm2022/cdevhub-ngx-tw-button.mjs +24 -15
  15. package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -1
  16. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +3 -3
  17. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -1
  18. package/fesm2022/cdevhub-ngx-tw-calendar.mjs +408 -215
  19. package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -1
  20. package/fesm2022/cdevhub-ngx-tw-card.mjs +33 -24
  21. package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -1
  22. package/fesm2022/cdevhub-ngx-tw-carousel.mjs +144 -79
  23. package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -1
  24. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +99 -47
  25. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -1
  26. package/fesm2022/cdevhub-ngx-tw-code-block.mjs +34 -20
  27. package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -1
  28. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +46 -29
  29. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -1
  30. package/fesm2022/cdevhub-ngx-tw-combobox.mjs +195 -110
  31. package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -1
  32. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +140 -73
  33. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -1
  34. package/fesm2022/cdevhub-ngx-tw-core.mjs +16 -11
  35. package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -1
  36. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +393 -149
  37. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -1
  38. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +305 -150
  39. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -1
  40. package/fesm2022/cdevhub-ngx-tw-dialog.mjs +56 -43
  41. package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -1
  42. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +51 -33
  43. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -1
  44. package/fesm2022/cdevhub-ngx-tw-file-upload.mjs +905 -0
  45. package/fesm2022/cdevhub-ngx-tw-file-upload.mjs.map +1 -0
  46. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +49 -26
  47. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -1
  48. package/fesm2022/cdevhub-ngx-tw-form-field.mjs +133 -74
  49. package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -1
  50. package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs +2 -2
  51. package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs.map +1 -1
  52. package/fesm2022/cdevhub-ngx-tw-icon.mjs +28 -17
  53. package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -1
  54. package/fesm2022/cdevhub-ngx-tw-input.mjs +37 -21
  55. package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -1
  56. package/fesm2022/cdevhub-ngx-tw-item.mjs +33 -24
  57. package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -1
  58. package/fesm2022/cdevhub-ngx-tw-menu.mjs +63 -48
  59. package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -1
  60. package/fesm2022/cdevhub-ngx-tw-number-input.mjs +622 -0
  61. package/fesm2022/cdevhub-ngx-tw-number-input.mjs.map +1 -0
  62. package/fesm2022/cdevhub-ngx-tw-paginator.mjs +137 -71
  63. package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -1
  64. package/fesm2022/cdevhub-ngx-tw-popover.mjs +101 -46
  65. package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -1
  66. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +57 -30
  67. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -1
  68. package/fesm2022/cdevhub-ngx-tw-radio.mjs +108 -57
  69. package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -1
  70. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +46 -26
  71. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -1
  72. package/fesm2022/cdevhub-ngx-tw-select.mjs +217 -122
  73. package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -1
  74. package/fesm2022/cdevhub-ngx-tw-separator.mjs +21 -12
  75. package/fesm2022/cdevhub-ngx-tw-separator.mjs.map +1 -1
  76. package/fesm2022/cdevhub-ngx-tw-sheet.mjs +58 -44
  77. package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -1
  78. package/fesm2022/cdevhub-ngx-tw-skeleton.mjs +25 -14
  79. package/fesm2022/cdevhub-ngx-tw-skeleton.mjs.map +1 -1
  80. package/fesm2022/cdevhub-ngx-tw-slider.mjs +155 -79
  81. package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -1
  82. package/fesm2022/cdevhub-ngx-tw-sort.mjs +44 -25
  83. package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -1
  84. package/fesm2022/cdevhub-ngx-tw-spinner.mjs +29 -16
  85. package/fesm2022/cdevhub-ngx-tw-spinner.mjs.map +1 -1
  86. package/fesm2022/cdevhub-ngx-tw-split.mjs +72 -42
  87. package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -1
  88. package/fesm2022/cdevhub-ngx-tw-stat.mjs +107 -64
  89. package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -1
  90. package/fesm2022/cdevhub-ngx-tw-stepper.mjs +113 -47
  91. package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -1
  92. package/fesm2022/cdevhub-ngx-tw-switch.mjs +61 -32
  93. package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -1
  94. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +88 -42
  95. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -1
  96. package/fesm2022/cdevhub-ngx-tw-table.mjs +266 -118
  97. package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -1
  98. package/fesm2022/cdevhub-ngx-tw-tabs.mjs +101 -51
  99. package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -1
  100. package/fesm2022/cdevhub-ngx-tw-tags-input.mjs +798 -0
  101. package/fesm2022/cdevhub-ngx-tw-tags-input.mjs.map +1 -0
  102. package/fesm2022/cdevhub-ngx-tw-textarea.mjs +11 -7
  103. package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -1
  104. package/fesm2022/cdevhub-ngx-tw-theme.mjs +22 -14
  105. package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -1
  106. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +243 -95
  107. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -1
  108. package/fesm2022/cdevhub-ngx-tw-timeline.mjs +149 -82
  109. package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -1
  110. package/fesm2022/cdevhub-ngx-tw-toast.mjs +89 -55
  111. package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -1
  112. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +50 -28
  113. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -1
  114. package/fesm2022/cdevhub-ngx-tw-transfer.mjs +1129 -0
  115. package/fesm2022/cdevhub-ngx-tw-transfer.mjs.map +1 -0
  116. package/fesm2022/cdevhub-ngx-tw-tree.mjs +554 -0
  117. package/fesm2022/cdevhub-ngx-tw-tree.mjs.map +1 -0
  118. package/fesm2022/cdevhub-ngx-tw.mjs +7 -0
  119. package/fesm2022/cdevhub-ngx-tw.mjs.map +1 -1
  120. package/package.json +45 -20
  121. package/theme/index.css +10 -2
  122. package/types/cdevhub-ngx-tw-aspect-ratio.d.ts +40 -0
  123. package/types/cdevhub-ngx-tw-calendar.d.ts +39 -8
  124. package/types/cdevhub-ngx-tw-command-palette.d.ts +7 -0
  125. package/types/cdevhub-ngx-tw-date-picker.d.ts +36 -10
  126. package/types/cdevhub-ngx-tw-file-upload.d.ts +250 -0
  127. package/types/cdevhub-ngx-tw-form-field.d.ts +22 -3
  128. package/types/cdevhub-ngx-tw-icon-lucide.d.ts +21 -3
  129. package/types/cdevhub-ngx-tw-number-input.d.ts +130 -0
  130. package/types/cdevhub-ngx-tw-popover.d.ts +8 -0
  131. package/types/cdevhub-ngx-tw-stepper.d.ts +30 -2
  132. package/types/cdevhub-ngx-tw-tab-nav.d.ts +8 -0
  133. package/types/cdevhub-ngx-tw-table.d.ts +30 -1
  134. package/types/cdevhub-ngx-tw-tabs.d.ts +8 -0
  135. package/types/cdevhub-ngx-tw-tags-input.d.ts +217 -0
  136. package/types/cdevhub-ngx-tw-time-picker.d.ts +31 -6
  137. package/types/cdevhub-ngx-tw-transfer.d.ts +330 -0
  138. package/types/cdevhub-ngx-tw-tree.d.ts +189 -0
  139. package/types/cdevhub-ngx-tw.d.ts +7 -0
@@ -0,0 +1,217 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { OnInit, Signal } from '@angular/core';
3
+ import { ControlValueAccessor } from '@angular/forms';
4
+ import { TwColor, TwSize, ErrorStateMatcher } from '@cdevhub/ngx-tw/core';
5
+ import { FormFieldControl } from '@cdevhub/ngx-tw/form-field';
6
+
7
+ /**
8
+ * Maps the committed input text to a tag value. The default returns the trimmed
9
+ * string, so the value type defaults to `string`. Override to build object tags
10
+ * (e.g. `(text) => ({ id: crypto.randomUUID(), name: text })`).
11
+ */
12
+ type TwTagFactory<T> = (text: string) => T;
13
+ /**
14
+ * Maps a tag value to its visible chip label and the remove-button accessible
15
+ * name. Defaults to `String(tag)`.
16
+ */
17
+ type TwTagLabelFn<T> = (tag: T) => string;
18
+ /**
19
+ * Equality comparator used to dedupe tags when `allowDuplicates` is `false` and
20
+ * to resolve a tag passed to `removeTag`. Defaults to `Object.is`.
21
+ */
22
+ type TwTagCompareFn<T> = (a: T, b: T) => boolean;
23
+ /** Payload of the `tagAdded` output. */
24
+ interface TwTagAddedEvent<T> {
25
+ /** The tag that was committed. */
26
+ tag: T;
27
+ /** The full tag array after the addition. A fresh array reference. */
28
+ value: T[];
29
+ }
30
+ /** Payload of the `tagRemoved` output. */
31
+ interface TwTagRemovedEvent<T> {
32
+ /** The tag that was removed. */
33
+ tag: T;
34
+ /** The full tag array after the removal. A fresh array reference. */
35
+ value: T[];
36
+ /** The index the removed tag occupied before removal. */
37
+ index: number;
38
+ }
39
+
40
+ /**
41
+ * Free-text multi-value input. The user types a token and commits it via Enter,
42
+ * a separator key, paste, or blur; committed tokens render as dismissible chips
43
+ * (composing `[twBadge]`) inline with the text input. The value is exposed as a
44
+ * real `T[]` (default `string[]`) through `ControlValueAccessor`, so it works
45
+ * with template-driven, reactive, and signal forms and integrates with
46
+ * `<tw-form-field>` for label / hint / error chrome.
47
+ *
48
+ * The control is a single tab stop with a roving-tabindex chip strip
49
+ * (Material `MatChipGrid` interaction model): Arrow keys traverse chips and the
50
+ * input, Delete / a two-step Backspace remove chips, and `LiveAnnouncer` voices
51
+ * add / remove. Autocomplete suggestions are out of scope (use `tw-combobox`).
52
+ */
53
+ declare class TagsInputComponent<T = string> extends FormFieldControl<T[]> implements ControlValueAccessor, OnInit {
54
+ /** Semantic color for the container focus-within ring and the chip accent. Defaults to `'primary'`. */
55
+ readonly color: _angular_core.InputSignal<TwColor>;
56
+ /** Controls overall density: container padding, chip size, and text scale. Defaults to `'md'`. */
57
+ readonly size: _angular_core.InputSignal<TwSize>;
58
+ /** When true, blocks typing, committing, and chip removal, and applies muted styling. Reactive forms also propagate disabled via `setDisabledState`. Defaults to `false`. */
59
+ readonly disabledInput: _angular_core.InputSignal<boolean>;
60
+ /** Marks the control as required. Mirrored to the input's `aria-required`. Also inferred from `Validators.required` on a bound control. Defaults to `false`. */
61
+ readonly requiredInput: _angular_core.InputSignal<boolean>;
62
+ /** Placeholder shown in the text input only while there are no chips and the input is empty. */
63
+ readonly placeholder: _angular_core.InputSignal<string | undefined>;
64
+ /** Keys that commit the in-progress text as a tag. Each entry is a `KeyboardEvent.key` value (`'Enter'`) or a single separator character (`','`). Single-character separators also split pasted text. Defaults to `['Enter', ',']`. */
65
+ readonly separatorKeys: _angular_core.InputSignal<readonly string[]>;
66
+ /** When true, blurring the control while the input holds non-empty text commits it as a tag. Defaults to `false`. */
67
+ readonly addOnBlur: _angular_core.InputSignal<boolean>;
68
+ /** Maximum number of tags. Once reached, further commits are blocked and announced. Does not truncate an oversized `writeValue`. Defaults to `undefined` (no limit). */
69
+ readonly maxTags: _angular_core.InputSignal<number | undefined>;
70
+ /** When false (default), a committed tag equal (per `compareWith`) to an existing tag is dropped silently. When true, duplicates are kept. Defaults to `false`. */
71
+ readonly allowDuplicates: _angular_core.InputSignal<boolean>;
72
+ /** Maps committed text to a tag value. Default is identity — the trimmed string. Override to build object tags. */
73
+ readonly createTag: _angular_core.InputSignal<TwTagFactory<T>>;
74
+ /** Maps a tag value to its visible chip label and the remove-button accessible name. Defaults to `String(tag)`. */
75
+ readonly tagLabel: _angular_core.InputSignal<TwTagLabelFn<T>>;
76
+ /** Equality comparator used for dedup when `allowDuplicates` is false. Defaults to `Object.is` (reference / value identity). String tags dedupe case-sensitively by default; pass `(a, b) => a.toLowerCase() === b.toLowerCase()` for case-insensitive dedup. */
77
+ readonly compareWith: _angular_core.InputSignal<TwTagCompareFn<T>>;
78
+ /** Applied to the text input for labeling and identification only; does not submit the tag array via native (non-Angular) form posting. */
79
+ readonly name: _angular_core.InputSignal<string | undefined>;
80
+ /** Id on the host element. Auto-generated as `tw-tags-input-N` when not provided. Used by the form-field's `<label for>` association. */
81
+ readonly idInput: _angular_core.InputSignal<string | undefined>;
82
+ /** Accessible name applied to the control when no visible label is wired. Mirrored to `aria-label`. */
83
+ readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
84
+ /** ID of an external element that labels the control. Mirrored to `aria-labelledby`. */
85
+ readonly ariaLabelledby: _angular_core.InputSignal<string | undefined>;
86
+ /** ID of an external element that describes the control. Form-field merges its hint / error ids alongside. */
87
+ readonly ariaDescribedby: _angular_core.InputSignal<string | undefined>;
88
+ /** Per-instance override of the {@link ErrorStateMatcher}. When omitted, uses the `TW_ERROR_STATE_MATCHER` token's value. */
89
+ readonly errorStateMatcher: _angular_core.InputSignal<ErrorStateMatcher | undefined>;
90
+ /** Fires when the tag array changes through user interaction (add, remove, clear). Emits a fresh array reference. Does not fire on `writeValue`. */
91
+ readonly valueChange: _angular_core.OutputEmitterRef<T[]>;
92
+ /** Fires when a tag is committed via Enter, a separator key, paste, or `addTag()`. Does not fire for dropped duplicates, blocked-by-max commits, empty commits, or `writeValue`. */
93
+ readonly tagAdded: _angular_core.OutputEmitterRef<TwTagAddedEvent<T>>;
94
+ /** Fires when a tag is removed via the remove button, Backspace / Delete, or `removeTag()`. Does not fire on `writeValue` or `clear()`. */
95
+ readonly tagRemoved: _angular_core.OutputEmitterRef<TwTagRemovedEvent<T>>;
96
+ private readonly focusMonitor;
97
+ private readonly liveAnnouncer;
98
+ private readonly elementRef;
99
+ private readonly destroyRef;
100
+ private readonly ngControl;
101
+ private readonly parentForm;
102
+ private readonly parentFormGroup;
103
+ private readonly defaultMatcher;
104
+ private readonly formField;
105
+ private readonly textInputRef;
106
+ private readonly removeButtons;
107
+ private onChange;
108
+ private onTouched;
109
+ private readonly tags;
110
+ /** The current in-progress (uncommitted) text in the input. Empty when nothing is typed. */
111
+ readonly inputText: _angular_core.WritableSignal<string>;
112
+ /** @internal Roving-tabindex position. `null` = the text input is the active element; a number = that chip's remove button. */
113
+ protected readonly activeChipIndex: _angular_core.WritableSignal<number | null>;
114
+ private readonly cvaDisabled;
115
+ private readonly _focused;
116
+ private readonly _ngControlRev;
117
+ private readonly _formSubmitRev;
118
+ private readonly describedByIdsSignal;
119
+ private readonly labelledByIdsSignal;
120
+ /** Nonce bumped only on explicit focus intent — keeps the focus effect from stealing focus on unrelated renders. */
121
+ private readonly focusNonce;
122
+ private lastMaxAnnounce;
123
+ private readonly uid;
124
+ /** @internal Fallback id used when the consumer does not set `[id]`. */
125
+ readonly hostId: string;
126
+ /** @internal */
127
+ readonly id: Signal<string>;
128
+ /** The current tag array (empty array when there are no tags). Read from a template ref (`#t="twTagsInput"`) for non-form usage. Doubles as the `FormFieldControl` contract member. */
129
+ readonly value: Signal<T[]>;
130
+ /** @internal */
131
+ readonly focused: Signal<boolean>;
132
+ /** @internal Empty when there are no chips AND the input text is blank — drives the form-field floating label. */
133
+ readonly empty: Signal<boolean>;
134
+ /** @internal */
135
+ readonly disabled: Signal<boolean>;
136
+ /** @internal */
137
+ readonly required: Signal<boolean>;
138
+ /** @internal */
139
+ readonly errorState: Signal<boolean>;
140
+ /** @internal Active validation errors map from the bound control, for `[twError match="…"]` filtering. */
141
+ readonly errors: Signal<Record<string, unknown> | null>;
142
+ /** @internal */
143
+ readonly controlType = "tags-input";
144
+ /** @internal */
145
+ readonly userAriaDescribedBy: Signal<string | undefined>;
146
+ /** @internal */
147
+ readonly userAriaLabelledby: Signal<string | undefined>;
148
+ /** @internal Merged `aria-describedby` (form-field hint/error ids + consumer-supplied). */
149
+ readonly resolvedDescribedBy: Signal<string>;
150
+ /** @internal Merged `aria-labelledby` (form-field label id + consumer-supplied). */
151
+ readonly resolvedLabelledBy: Signal<string>;
152
+ private readonly variantResult;
153
+ /** @internal */
154
+ readonly rootClasses: Signal<string>;
155
+ /** @internal */
156
+ readonly chipClasses: Signal<string>;
157
+ /** @internal */
158
+ readonly chipLabelClasses: Signal<string>;
159
+ /** @internal */
160
+ readonly removeButtonClasses: Signal<string>;
161
+ /** @internal */
162
+ readonly removeIconClasses: Signal<string>;
163
+ /** @internal */
164
+ readonly inputClasses: Signal<string>;
165
+ /** @internal Pre-resolved chip view models so the template never calls accessor functions inline. */
166
+ readonly chipViews: Signal<{
167
+ tag: T;
168
+ label: string;
169
+ removeLabel: string;
170
+ index: number;
171
+ }[]>;
172
+ constructor();
173
+ /** Commits `text` as a tag (trim → `createTag` → dedup unless `allowDuplicates` → `maxTags` check). Returns true if a tag was added, false if dropped (empty / duplicate / max). Emits `tagAdded` + `valueChange` on success. No-op when disabled. */
174
+ addTag(text: string): boolean;
175
+ /** Removes a tag by value (first match via `compareWith`) or by index when a number is passed. Emits `tagRemoved` + `valueChange` and restores focus. No-op when disabled or when no match. Note: when the tag type is `number`, the argument is treated as an index. */
176
+ removeTag(tag: T | number): void;
177
+ /** Removes all tags and clears the in-progress input text. Emits `valueChange` with `[]`. Does NOT emit `tagRemoved` per tag (bulk reset). No-op when already empty or disabled. */
178
+ clear(): void;
179
+ /** Moves focus to the text input. */
180
+ focus(): void;
181
+ private tryAdd;
182
+ private commitInput;
183
+ private removeAt;
184
+ /** @internal */
185
+ onInput(event: Event): void;
186
+ /** @internal */
187
+ onInputKeydown(event: KeyboardEvent): void;
188
+ /** @internal */
189
+ onChipKeydown(event: KeyboardEvent, index: number): void;
190
+ /** @internal */
191
+ onRemoveClick(index: number): void;
192
+ /** @internal */
193
+ onPaste(event: ClipboardEvent): void;
194
+ writeValue(value: T[] | null | undefined): void;
195
+ registerOnChange(fn: (value: T[]) => void): void;
196
+ registerOnTouched(fn: () => void): void;
197
+ setDisabledState(isDisabled: boolean): void;
198
+ /** @internal */
199
+ setDescribedByIds(ids: string[]): void;
200
+ /** @internal */
201
+ setLabelledByIds(ids: string[]): void;
202
+ /** @internal Clicking the form-field surface (outside the control) focuses the text input. Clicks inside the control are left alone so chip removal keeps its own focus restoration. */
203
+ onContainerClick(event: MouseEvent): void;
204
+ ngOnInit(): void;
205
+ private focusChip;
206
+ private focusInput;
207
+ private requestFocus;
208
+ private setInputText;
209
+ private announceMax;
210
+ private splitOnSeparators;
211
+ private hasAccessibleNameHint;
212
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TagsInputComponent<any>, never>;
213
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TagsInputComponent<any>, "tw-tags-input", ["twTagsInput"], { "color": { "alias": "color"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "disabledInput": { "alias": "disabled"; "required": false; "isSignal": true; }; "requiredInput": { "alias": "required"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "separatorKeys": { "alias": "separatorKeys"; "required": false; "isSignal": true; }; "addOnBlur": { "alias": "addOnBlur"; "required": false; "isSignal": true; }; "maxTags": { "alias": "maxTags"; "required": false; "isSignal": true; }; "allowDuplicates": { "alias": "allowDuplicates"; "required": false; "isSignal": true; }; "createTag": { "alias": "createTag"; "required": false; "isSignal": true; }; "tagLabel": { "alias": "tagLabel"; "required": false; "isSignal": true; }; "compareWith": { "alias": "compareWith"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "idInput": { "alias": "id"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; "isSignal": true; }; "ariaDescribedby": { "alias": "aria-describedby"; "required": false; "isSignal": true; }; "errorStateMatcher": { "alias": "errorStateMatcher"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; "tagAdded": "tagAdded"; "tagRemoved": "tagRemoved"; }, never, never, true, never>;
214
+ }
215
+
216
+ export { TagsInputComponent };
217
+ export type { TwTagAddedEvent, TwTagCompareFn, TwTagFactory, TwTagLabelFn, TwTagRemovedEvent };
@@ -1,6 +1,6 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { Provider, OnInit, Signal } from '@angular/core';
3
- import { ControlValueAccessor } from '@angular/forms';
3
+ import { ControlValueAccessor, Validator, AbstractControl, ValidationErrors } from '@angular/forms';
4
4
  import { TwSize, TwColor, TimePickerFormat, ErrorStateMatcher, TimePickerMeridiem } from '@cdevhub/ngx-tw/core';
5
5
  export { TimePickerFormat, TimePickerMeridiem } from '@cdevhub/ngx-tw/core';
6
6
  import { FormFieldControl } from '@cdevhub/ngx-tw/form-field';
@@ -97,7 +97,24 @@ interface TimePickerInputEvent<D> {
97
97
  * `DateAdapter<D>`, so the component works with the default native adapter
98
98
  * (`provideNativeDateAdapter()`) or any custom adapter a consumer ships.
99
99
  */
100
- declare class TimePickerComponent<D = Date> extends FormFieldControl<D> implements ControlValueAccessor, OnInit {
100
+ /**
101
+ * Validation errors a `tw-time-picker` can place on its bound control.
102
+ *
103
+ * Mirrors the shape of `CalendarValidationErrors` so the two pickers report
104
+ * constraint violations the same way: a code keyed by what was violated, with
105
+ * the offending value and the bound it broke.
106
+ */
107
+ type TimePickerValidationErrors = Partial<{
108
+ timePickerMin: {
109
+ min: unknown;
110
+ actual: unknown;
111
+ };
112
+ timePickerMax: {
113
+ max: unknown;
114
+ actual: unknown;
115
+ };
116
+ }>;
117
+ declare class TimePickerComponent<D = Date> extends FormFieldControl<D> implements ControlValueAccessor, Validator, OnInit {
101
118
  /** Id on the time-picker's host element. Auto-generated when not provided. Used by the form-field's `<label for>` attribute. */
102
119
  readonly idInput: _angular_core.InputSignal<string | undefined>;
103
120
  /** When true, the whole component is disabled and every field sets `aria-disabled="true"`. Defaults to `false`. */
@@ -122,9 +139,9 @@ declare class TimePickerComponent<D = Date> extends FormFieldControl<D> implemen
122
139
  readonly minuteStep: _angular_core.InputSignal<number>;
123
140
  /** Amount to add/subtract when stepping seconds. Defaults to `1`. */
124
141
  readonly secondStep: _angular_core.InputSignal<number>;
125
- /** Earliest accepted time-of-day. Values earlier than this set `errorState`. Defaults to `null`. Note: when `showSeconds` is `false`, the seconds component of any value still participates in the range comparison — supply `minTime` with zeroed seconds to match the 2-field display. */
142
+ /** Earliest accepted time-of-day. Values earlier than this set `errorState` and mark the bound control invalid with `timePickerMin`. Defaults to `null`. Note: when `showSeconds` is `false`, the seconds component of any value still participates in the range comparison — supply `minTime` with zeroed seconds to match the 2-field display. */
126
143
  readonly minTime: _angular_core.InputSignal<D | null>;
127
- /** Latest accepted time-of-day. Values later than this set `errorState`. Defaults to `null`. Note: when `showSeconds` is `false`, the seconds component of any value still participates in the range comparison — supply `maxTime` with zeroed seconds to match the 2-field display. */
144
+ /** Latest accepted time-of-day. Values later than this set `errorState` and mark the bound control invalid with `timePickerMax`. Defaults to `null`. Note: when `showSeconds` is `false`, the seconds component of any value still participates in the range comparison — supply `maxTime` with zeroed seconds to match the 2-field display. */
128
145
  readonly maxTime: _angular_core.InputSignal<D | null>;
129
146
  /** Date portion used when the user types a time while `value` is `null`. Defaults to today. */
130
147
  readonly referenceDate: _angular_core.InputSignal<D | null>;
@@ -155,8 +172,9 @@ declare class TimePickerComponent<D = Date> extends FormFieldControl<D> implemen
155
172
  private readonly liveAnnouncer;
156
173
  private readonly elementRef;
157
174
  private readonly destroyRef;
175
+ private readonly injector;
158
176
  private readonly formField;
159
- private readonly ngControl;
177
+ private ngControl;
160
178
  private readonly parentForm;
161
179
  private readonly parentFormGroup;
162
180
  private readonly defaultMatcher;
@@ -287,6 +305,13 @@ declare class TimePickerComponent<D = Date> extends FormFieldControl<D> implemen
287
305
  private stepFor;
288
306
  private fieldMinFor;
289
307
  private fieldMaxFor;
308
+ private validatorOnChange;
309
+ /** @internal */
310
+ validate(control: AbstractControl): ValidationErrors | null;
311
+ /** @internal */
312
+ registerOnValidatorChange(fn: () => void): void;
313
+ /** Time-of-day in seconds, ignoring the date part — the same basis `isInRange` uses. */
314
+ private secondsOf;
290
315
  writeValue(value: unknown): void;
291
316
  registerOnChange(fn: (value: D | null) => void): void;
292
317
  registerOnTouched(fn: () => void): void;
@@ -300,4 +325,4 @@ declare class TimePickerComponent<D = Date> extends FormFieldControl<D> implemen
300
325
  }
301
326
 
302
327
  export { TimePickerComponent, TimePickerIntl, provideTimePickerIntl };
303
- export type { TimePickerChangeEvent, TimePickerChangeSource, TimePickerField, TimePickerInputEvent, TimePickerVariant };
328
+ export type { TimePickerChangeEvent, TimePickerChangeSource, TimePickerField, TimePickerInputEvent, TimePickerValidationErrors, TimePickerVariant };
@@ -0,0 +1,330 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { OnInit, Signal, TemplateRef } from '@angular/core';
3
+ import { ControlValueAccessor } from '@angular/forms';
4
+ import { ListboxValueChangeEvent } from '@angular/cdk/listbox';
5
+ import { TwSize, ErrorStateMatcher } from '@cdevhub/ngx-tw/core';
6
+ import { FormFieldControl } from '@cdevhub/ngx-tw/form-field';
7
+
8
+ /** Which panel of the transfer an item / event belongs to. */
9
+ type TwTransferSide = 'source' | 'target';
10
+ /** i18n strings for the transfer. Pass any subset; unset keys fall back to the English defaults. */
11
+ interface TwTransferLabels {
12
+ /** Source (left) panel title. Defaults to `'Source'`. */
13
+ sourceTitle?: string;
14
+ /** Target (right) panel title. Defaults to `'Target'`. */
15
+ targetTitle?: string;
16
+ /** Placeholder + accessible name for the per-panel search inputs. Defaults to `'Search'`. */
17
+ searchPlaceholder?: string;
18
+ /** Text shown in a panel body when it has no visible items. Defaults to `'No items'`. */
19
+ emptyText?: string;
20
+ /** Accessible name for the header select-all checkbox. Defaults to `'Select all'`. */
21
+ selectAllLabel?: string;
22
+ /** Accessible name for the → (move-to-target) button. Defaults to `'Move selected to target'`. */
23
+ moveToTargetLabel?: string;
24
+ /** Accessible name for the ← (move-to-source) button. Defaults to `'Move selected to source'`. */
25
+ moveToSourceLabel?: string;
26
+ /** Count template rendered in each panel header. Variables: `{total}`, `{selected}`. Defaults to `'{total} items'`. */
27
+ countFormat?: string;
28
+ /** LiveAnnouncer template announced after a move. Variables: `{count}`, `{target}`. Defaults to `'{count} items moved to {target}'`. */
29
+ moveAnnouncement?: string;
30
+ }
31
+ /** Visual configuration for the transfer. Pass any subset; unset keys fall back to the defaults. */
32
+ interface TwTransferDisplayConfig {
33
+ /** Row / control density across the design-system ramps. Defaults to `'md'`. */
34
+ size?: TwSize;
35
+ /** Scroll-viewport height of each list, in px (a number) or `'auto'` (flow with content). Defaults to `240`. */
36
+ listHeight?: number | 'auto';
37
+ /** When true, each panel gets a labelled search input above its list. Defaults to `false`. */
38
+ showSearch?: boolean;
39
+ /** When true, each panel header shows a tri-state select-all checkbox. Defaults to `true`. */
40
+ showSelectAll?: boolean;
41
+ }
42
+ /** Behavioural configuration for the transfer. Generic over item type `T`. Pass any subset; unset keys fall back to the defaults. */
43
+ interface TwTransferBehaviorConfig<T = unknown> {
44
+ /** When true, items only flow source → target; the ← button is not rendered. Defaults to `false`. */
45
+ oneWay?: boolean;
46
+ /** Custom search predicate. Defaults to a case-insensitive substring match of the query against `labelFn(item)`. */
47
+ filterFn?: (item: T, query: string) => boolean;
48
+ /** Per-item disable predicate. A disabled item renders as a disabled option and is excluded from select-all and all moves. Defaults to `() => false`. */
49
+ disabledItem?: (item: T) => boolean;
50
+ }
51
+ /** Context surfaced to a `*twTransferItem` template. Generic over the item type `T`. */
52
+ interface TwTransferItemContext<T> {
53
+ /** The item data (implicit `let-item`). */
54
+ $implicit: T;
55
+ /** Resolved `labelFn(item)`. */
56
+ label: string;
57
+ /** Ephemeral pending-move checked state of this row's option. */
58
+ checked: boolean;
59
+ /** Whether the item is disabled (via `behavior.disabledItem`). */
60
+ disabled: boolean;
61
+ /** Which panel this row renders in. */
62
+ side: TwTransferSide;
63
+ }
64
+ /** Payload emitted by `moved`. Generic over the key type `K`. */
65
+ interface TwTransferMovedEvent<K> {
66
+ /** The keys that moved in this interaction. */
67
+ keys: readonly K[];
68
+ /** The direction of the move. */
69
+ direction: 'toTarget' | 'toSource';
70
+ }
71
+ /** Structural directive (`*twTransferItem="let item"`) declaring the per-item template. Typed as `TwTransferItemContext<T>`. */
72
+ declare class TransferItemDefDirective<T = unknown> {
73
+ /** @internal Consumer-projected per-item template. */
74
+ readonly template: TemplateRef<any>;
75
+ /** @internal */
76
+ static ngTemplateContextGuard<T>(_dir: TransferItemDefDirective<T>, _ctx: unknown): _ctx is TwTransferItemContext<T>;
77
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TransferItemDefDirective<any>, never>;
78
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TransferItemDefDirective<any>, "[twTransferItem]", never, {}, {}, never, never, true, never>;
79
+ }
80
+ interface RowBase<T, K> {
81
+ readonly item: T;
82
+ readonly key: K;
83
+ readonly label: string;
84
+ readonly disabled: boolean;
85
+ }
86
+ interface RowView<T, K> extends RowBase<T, K> {
87
+ readonly checked: boolean;
88
+ readonly optionClass: string;
89
+ readonly checkClass: string;
90
+ readonly context: TwTransferItemContext<T>;
91
+ }
92
+ interface PanelView<T, K> {
93
+ readonly side: TwTransferSide;
94
+ readonly title: string;
95
+ readonly titleId: string;
96
+ readonly countText: string;
97
+ readonly emptyText: string;
98
+ readonly searchPlaceholder: string;
99
+ readonly selectAllLabel: string;
100
+ readonly query: string;
101
+ readonly rows: readonly RowView<T, K>[];
102
+ readonly checkedValue: readonly K[];
103
+ readonly selectAllChecked: boolean;
104
+ readonly selectAllIndeterminate: boolean;
105
+ }
106
+ /**
107
+ * A dual-listbox shuttle: two panels (source / target) with a column of move
108
+ * buttons between them. The user ticks items in a panel and shuttles them across;
109
+ * an optional per-panel search and a tri-state header select-all accelerate bulk
110
+ * moves. The component's value is the set of keys on the target side, exposed
111
+ * through `ControlValueAccessor` + `FormFieldControl` so it works with reactive,
112
+ * template-driven, and signal forms and integrates with `<tw-form-field>`.
113
+ *
114
+ * Each panel composes `@angular/cdk/listbox` (`CdkListbox` / `CdkOption`) for
115
+ * focus-managed, accessible, keyboard-navigable selection. Consumers supply
116
+ * `keyFn` (required) and `labelFn` (defaulted to `String(item)`), and may project
117
+ * a `*twTransferItem` template for rich row content.
118
+ */
119
+ declare class TransferComponent<T = unknown, K = unknown> extends FormFieldControl<readonly K[]> implements ControlValueAccessor, OnInit {
120
+ /** All items across both panels. The source/target split derives from the value, not the reverse. Defaults to `[]`. */
121
+ readonly data: _angular_core.InputSignal<readonly T[]>;
122
+ /** Resolves a stable key for an item — drives membership (the value), checked state, tracking, the cdkOption value, and compareWith. Required. */
123
+ readonly keyFn: _angular_core.InputSignal<(item: T) => K>;
124
+ /** Resolves an item's display label — used for the default row render, search filtering, and listbox typeahead. Defaults to `(item) => String(item)`. */
125
+ readonly labelFn: _angular_core.InputSignal<(item: T) => string>;
126
+ /** Per-panel text + ARIA labels. Partial; unset keys fall back to the English defaults. */
127
+ readonly labels: _angular_core.InputSignal<Partial<TwTransferLabels>>;
128
+ /** Visual configuration — size, list viewport height, search / select-all visibility. Partial; unset keys fall back to the defaults. */
129
+ readonly display: _angular_core.InputSignal<Partial<TwTransferDisplayConfig>>;
130
+ /** Behavioural configuration — oneWay, custom filterFn, per-item disabledItem predicate. Partial; unset keys fall back to the defaults. */
131
+ readonly behavior: _angular_core.InputSignal<Partial<TwTransferBehaviorConfig<T>>>;
132
+ /** Disables the entire control — panels non-interactive, search + buttons disabled, muted styling. Also driven by Forms `setDisabledState`. Defaults to `false`. */
133
+ readonly disabledInput: _angular_core.InputSignal<boolean>;
134
+ /** Marks the control as required. Mirrored to `aria-required` chrome via the form-field; also inferred from `Validators.required` on a bound control. Defaults to `false`. */
135
+ readonly requiredInput: _angular_core.InputSignal<boolean>;
136
+ /** Reserved for control identification (e.g. analytics, future native-submission parity). The transfer has no single native value element, so it is not currently reflected to the DOM. Defaults to `undefined`. */
137
+ readonly name: _angular_core.InputSignal<string | undefined>;
138
+ /** Id on the host element. Auto-generated as `tw-transfer-N` when unset. Used by the form-field's `<label for>` association. */
139
+ readonly idInput: _angular_core.InputSignal<string | undefined>;
140
+ /** Accessible name applied to the control when no visible label is wired. Mirrored to `aria-label`. Defaults to `undefined`. */
141
+ readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
142
+ /** ID of an external element that labels the control. Mirrored to `aria-labelledby`. Defaults to `undefined`. */
143
+ readonly ariaLabelledby: _angular_core.InputSignal<string | undefined>;
144
+ /** ID of an external element that describes the control. The form-field merges its hint / error ids alongside. Defaults to `undefined`. */
145
+ readonly ariaDescribedby: _angular_core.InputSignal<string | undefined>;
146
+ /** Per-instance override of the {@link ErrorStateMatcher}. When omitted, uses the `TW_ERROR_STATE_MATCHER` token's value. Defaults to `undefined`. */
147
+ readonly errorStateMatcher: _angular_core.InputSignal<ErrorStateMatcher | undefined>;
148
+ /** Fires when items move between panels by user interaction. Payload is the new full target-keys array. Does not fire on `writeValue`. */
149
+ readonly valueChange: _angular_core.OutputEmitterRef<readonly K[]>;
150
+ /** Fires after each directional move, identifying the moved keys and their direction. Does not fire on `writeValue`. */
151
+ readonly moved: _angular_core.OutputEmitterRef<TwTransferMovedEvent<K>>;
152
+ /** @internal Consumer-projected per-item template (`*twTransferItem`). */
153
+ readonly itemTemplate: Signal<TransferItemDefDirective<any> | undefined>;
154
+ private readonly elementRef;
155
+ private readonly injector;
156
+ private readonly destroyRef;
157
+ private readonly focusMonitor;
158
+ private readonly liveAnnouncer;
159
+ private readonly ngControl;
160
+ private readonly parentForm;
161
+ private readonly parentFormGroup;
162
+ private readonly defaultMatcher;
163
+ private readonly platform;
164
+ private readonly uid;
165
+ /** @internal Fallback id used when the consumer does not set `[id]`. */
166
+ readonly hostId: string;
167
+ private readonly sourceTitleId;
168
+ private readonly targetTitleId;
169
+ /** @internal The value: keys currently on the target side. Source of truth for membership. */
170
+ private readonly targetKeys;
171
+ /** @internal Per-panel search queries. */
172
+ private readonly sourceQuery;
173
+ private readonly targetQuery;
174
+ private readonly cvaDisabled;
175
+ private readonly _focused;
176
+ private readonly _ngControlRev;
177
+ private readonly _formSubmitRev;
178
+ private readonly describedByIdsSignal;
179
+ private readonly labelledByIdsSignal;
180
+ private onChange;
181
+ private onTouched;
182
+ /** @internal Stable comparator for `[cdkListboxCompareWith]`. Keys are identity-comparable. */
183
+ readonly compareKeys: (a: K, b: K) => boolean;
184
+ /** @internal */
185
+ readonly resolvedLabels: Signal<Required<TwTransferLabels>>;
186
+ private readonly resolvedDisplay;
187
+ private readonly resolvedBehavior;
188
+ /** @internal */
189
+ readonly resolvedSize: Signal<TwSize>;
190
+ /** @internal Checkbox tops out at `lg` density; map xl → lg. */
191
+ readonly checkboxSize: Signal<TwSize>;
192
+ /** @internal */
193
+ readonly showSearch: Signal<boolean>;
194
+ /** @internal */
195
+ readonly showSelectAll: Signal<boolean>;
196
+ /** @internal */
197
+ readonly oneWay: Signal<boolean>;
198
+ /** @internal Fixed list height in px, or `null` when `'auto'`. */
199
+ readonly listHeightPx: Signal<number | null>;
200
+ /** @internal Map from key to item across all data — for orphan-aware target rendering and disabled lookups. */
201
+ private readonly itemByKey;
202
+ private readonly targetKeySet;
203
+ /** @internal Items on the source side (in `data` order). */
204
+ private readonly sourceItems;
205
+ /** @internal Items on the target side (in `targetKeys` order; orphan keys with no item are skipped). */
206
+ private readonly targetItems;
207
+ private readonly sourceRowsBase;
208
+ private readonly sourceRenderedKeys;
209
+ /**
210
+ * @internal Ephemeral pending-move checked keys for the source panel — the
211
+ * controlled `[cdkListboxValue]`. A `linkedSignal` over the rendered-key set so
212
+ * it auto-prunes keys whose option a filter / move removed (kept ⊆ rendered → no
213
+ * CdkListbox `_invalid`; dropped keys do not re-surface). Cleared after moves.
214
+ */
215
+ readonly sourceChecked: _angular_core.WritableSignal<readonly K[]>;
216
+ private readonly sourceCheckedSet;
217
+ private readonly sourceRows;
218
+ private readonly targetRowsBase;
219
+ private readonly targetRenderedKeys;
220
+ /** @internal Ephemeral pending-move checked keys for the target panel — see {@link sourceChecked}. */
221
+ readonly targetChecked: _angular_core.WritableSignal<readonly K[]>;
222
+ private readonly targetCheckedSet;
223
+ private readonly targetRows;
224
+ /** @internal Checked, enabled, visible source keys — what the → button moves. */
225
+ readonly sourceMovableKeys: Signal<readonly K[]>;
226
+ /** @internal Checked, enabled, visible target keys — what the ← button moves. */
227
+ readonly targetMovableKeys: Signal<readonly K[]>;
228
+ private readonly sourceSelectAllKeys;
229
+ private readonly targetSelectAllKeys;
230
+ /** @internal */
231
+ readonly sourcePanel: Signal<PanelView<T, K>>;
232
+ /** @internal */
233
+ readonly targetPanel: Signal<PanelView<T, K>>;
234
+ private readonly variants;
235
+ /** @internal */
236
+ readonly rootClasses: Signal<string>;
237
+ /** @internal */
238
+ readonly panelClasses: Signal<string>;
239
+ /** @internal */
240
+ readonly panelHeaderClasses: Signal<string>;
241
+ /** @internal */
242
+ readonly panelTitleClasses: Signal<string>;
243
+ /** @internal */
244
+ readonly panelCountClasses: Signal<string>;
245
+ /** @internal */
246
+ readonly searchClasses: Signal<string>;
247
+ /** @internal */
248
+ readonly listClasses: Signal<string>;
249
+ /** @internal */
250
+ readonly optionLabelClasses: Signal<string>;
251
+ /** @internal */
252
+ readonly controlsClasses: Signal<string>;
253
+ /** @internal */
254
+ readonly moveButtonClasses: Signal<string>;
255
+ /** @internal */
256
+ readonly moveIconClasses: Signal<string>;
257
+ /** @internal */
258
+ readonly emptyClasses: Signal<string>;
259
+ constructor();
260
+ /** Moves the given items (by key) to the target side; ignores keys already there or whose item is disabled. Clears the source panel's pending checks, emits `valueChange` + `moved`, calls the CVA onChange, and announces the move. No-op when the control is disabled. */
261
+ moveToTarget(keys: readonly K[]): void;
262
+ /** Moves the given items (by key) to the source side; ignores keys not on target or whose item is disabled. Clears the target panel's pending checks. No-op when the control is disabled or `behavior.oneWay` is on. Same emissions as {@link moveToTarget}. */
263
+ moveToSource(keys: readonly K[]): void;
264
+ /** @internal */
265
+ onCheckedChange(side: TwTransferSide, event: ListboxValueChangeEvent<K>): void;
266
+ /** @internal Select-all toggles the visible, enabled keys for the panel (replace semantics). */
267
+ onSelectAll(side: TwTransferSide, checked: boolean): void;
268
+ /** @internal */
269
+ onSearch(side: TwTransferSide, event: Event): void;
270
+ /** @internal */
271
+ onMoveToTarget(): void;
272
+ /** @internal */
273
+ onMoveToSource(): void;
274
+ /**
275
+ * @internal Focuses the destination panel's listbox after the move re-renders.
276
+ * Deferred to the next render (the destination listbox may have just mounted
277
+ * from empty) and matched by its title id rather than DOM order (the *other*
278
+ * panel may have emptied, removing its listbox).
279
+ */
280
+ private focusDestination;
281
+ private applyValue;
282
+ private filterItems;
283
+ private toRowsBase;
284
+ private toRows;
285
+ private buildPanel;
286
+ private selectAllState;
287
+ private hasAccessibleNameHint;
288
+ /** @internal */
289
+ readonly id: Signal<string>;
290
+ /** The current target-keys array. Doubles as the `FormFieldControl` value member. */
291
+ readonly value: Signal<readonly K[]>;
292
+ /** @internal */
293
+ readonly focused: Signal<boolean>;
294
+ /** @internal Empty when nothing is on the target side — drives the form-field floating label. */
295
+ readonly empty: Signal<boolean>;
296
+ /** @internal */
297
+ readonly disabled: Signal<boolean>;
298
+ /** @internal */
299
+ readonly required: Signal<boolean>;
300
+ /** @internal */
301
+ readonly errorState: Signal<boolean>;
302
+ /** @internal Active validation errors from the bound control, for `[twError match="…"]` filtering. */
303
+ readonly errors: Signal<Record<string, unknown> | null>;
304
+ /** @internal */
305
+ readonly controlType = "transfer";
306
+ /** @internal */
307
+ readonly userAriaDescribedBy: Signal<string | undefined>;
308
+ /** @internal */
309
+ readonly userAriaLabelledby: Signal<string | undefined>;
310
+ /** @internal Merged `aria-describedby` (form-field hint/error ids + consumer-supplied). */
311
+ readonly resolvedDescribedBy: Signal<string>;
312
+ /** @internal Merged `aria-labelledby` (form-field label id + consumer-supplied). */
313
+ readonly resolvedLabelledBy: Signal<string>;
314
+ writeValue(value: readonly K[] | null | undefined): void;
315
+ registerOnChange(fn: (value: readonly K[]) => void): void;
316
+ registerOnTouched(fn: () => void): void;
317
+ setDisabledState(isDisabled: boolean): void;
318
+ /** @internal */
319
+ setDescribedByIds(ids: string[]): void;
320
+ /** @internal */
321
+ setLabelledByIds(ids: string[]): void;
322
+ /** @internal Clicking the form-field surface focuses the first listbox. */
323
+ onContainerClick(event: MouseEvent): void;
324
+ ngOnInit(): void;
325
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TransferComponent<any, any>, never>;
326
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TransferComponent<any, any>, "tw-transfer", ["twTransfer"], { "data": { "alias": "data"; "required": false; "isSignal": true; }; "keyFn": { "alias": "keyFn"; "required": true; "isSignal": true; }; "labelFn": { "alias": "labelFn"; "required": false; "isSignal": true; }; "labels": { "alias": "labels"; "required": false; "isSignal": true; }; "display": { "alias": "display"; "required": false; "isSignal": true; }; "behavior": { "alias": "behavior"; "required": false; "isSignal": true; }; "disabledInput": { "alias": "disabled"; "required": false; "isSignal": true; }; "requiredInput": { "alias": "required"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "idInput": { "alias": "id"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; "isSignal": true; }; "ariaDescribedby": { "alias": "aria-describedby"; "required": false; "isSignal": true; }; "errorStateMatcher": { "alias": "errorStateMatcher"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; "moved": "moved"; }, ["itemTemplate"], never, true, never>;
327
+ }
328
+
329
+ export { TransferComponent, TransferItemDefDirective };
330
+ export type { TwTransferBehaviorConfig, TwTransferDisplayConfig, TwTransferItemContext, TwTransferLabels, TwTransferMovedEvent, TwTransferSide };