@cdevhub/ngx-tw 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +264 -49
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs +11 -7
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-alert.mjs +43 -29
- package/fesm2022/cdevhub-ngx-tw-alert.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-aspect-ratio.mjs +103 -0
- package/fesm2022/cdevhub-ngx-tw-aspect-ratio.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs +56 -31
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-badge.mjs +61 -35
- package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +154 -93
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-button.mjs +24 -15
- package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +3 -3
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs +408 -215
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-card.mjs +33 -24
- package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs +144 -79
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +99 -47
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs +34 -20
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +46 -29
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs +195 -110
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +140 -73
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-core.mjs +16 -11
- package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +393 -149
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +305 -150
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs +56 -43
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +51 -33
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-file-upload.mjs +905 -0
- package/fesm2022/cdevhub-ngx-tw-file-upload.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +49 -26
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs +133 -74
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs +2 -2
- package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-icon.mjs +28 -17
- package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-input.mjs +37 -21
- package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-item.mjs +33 -24
- package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-menu.mjs +63 -48
- package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-number-input.mjs +622 -0
- package/fesm2022/cdevhub-ngx-tw-number-input.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs +137 -71
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-popover.mjs +101 -46
- package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +57 -30
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-radio.mjs +108 -57
- package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +46 -26
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-select.mjs +217 -122
- package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-separator.mjs +21 -12
- package/fesm2022/cdevhub-ngx-tw-separator.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs +58 -44
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-skeleton.mjs +25 -14
- package/fesm2022/cdevhub-ngx-tw-skeleton.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-slider.mjs +155 -79
- package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-sort.mjs +44 -25
- package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-spinner.mjs +29 -16
- package/fesm2022/cdevhub-ngx-tw-spinner.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-split.mjs +72 -42
- package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-stat.mjs +107 -64
- package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs +113 -47
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-switch.mjs +61 -32
- package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +88 -42
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-table.mjs +266 -118
- package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs +101 -51
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tags-input.mjs +798 -0
- package/fesm2022/cdevhub-ngx-tw-tags-input.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs +11 -7
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-theme.mjs +22 -14
- package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +243 -95
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs +149 -82
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-toast.mjs +89 -55
- package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +50 -28
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-transfer.mjs +1129 -0
- package/fesm2022/cdevhub-ngx-tw-transfer.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-tree.mjs +554 -0
- package/fesm2022/cdevhub-ngx-tw-tree.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw.mjs +7 -0
- package/fesm2022/cdevhub-ngx-tw.mjs.map +1 -1
- package/index.json +1 -0
- package/package.json +45 -20
- package/theme/index.css +10 -2
- package/types/cdevhub-ngx-tw-aspect-ratio.d.ts +40 -0
- package/types/cdevhub-ngx-tw-calendar.d.ts +39 -8
- package/types/cdevhub-ngx-tw-command-palette.d.ts +7 -0
- package/types/cdevhub-ngx-tw-date-picker.d.ts +36 -10
- package/types/cdevhub-ngx-tw-file-upload.d.ts +250 -0
- package/types/cdevhub-ngx-tw-form-field.d.ts +22 -3
- package/types/cdevhub-ngx-tw-icon-lucide.d.ts +21 -3
- package/types/cdevhub-ngx-tw-number-input.d.ts +130 -0
- package/types/cdevhub-ngx-tw-popover.d.ts +8 -0
- package/types/cdevhub-ngx-tw-stepper.d.ts +30 -2
- package/types/cdevhub-ngx-tw-tab-nav.d.ts +8 -0
- package/types/cdevhub-ngx-tw-table.d.ts +30 -1
- package/types/cdevhub-ngx-tw-tabs.d.ts +8 -0
- package/types/cdevhub-ngx-tw-tags-input.d.ts +217 -0
- package/types/cdevhub-ngx-tw-time-picker.d.ts +31 -6
- package/types/cdevhub-ngx-tw-transfer.d.ts +330 -0
- package/types/cdevhub-ngx-tw-tree.d.ts +189 -0
- package/types/cdevhub-ngx-tw.d.ts +7 -0
|
@@ -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
|
-
|
|
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
|
|
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 };
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { TemplateRef, TrackByFunction } from '@angular/core';
|
|
3
|
+
import { TwSize } from '@cdevhub/ngx-tw/core';
|
|
4
|
+
|
|
5
|
+
/** Tri-state selection status of a tree node. */
|
|
6
|
+
type TwTreeSelectionState = 'checked' | 'unchecked' | 'indeterminate';
|
|
7
|
+
/** Configuration for node selection behavior. Pass any subset; unset keys fall back to the defaults. */
|
|
8
|
+
interface TwTreeSelectionConfig {
|
|
9
|
+
/** Selection mode. `'single'` is scalar (one node, no cascade/indeterminate); `'multiple'` supports cascade + tri-state. `'none'` disables selection. Defaults to `'none'`. */
|
|
10
|
+
mode: 'none' | 'single' | 'multiple';
|
|
11
|
+
/** In `'multiple'` mode, selecting a branch selects all its leaf descendants and a branch renders `'indeterminate'` when only some are selected. Ignored in `'single'`/`'none'`. Defaults to `true`. */
|
|
12
|
+
cascade?: boolean;
|
|
13
|
+
/** Pre-selected node keys (matched via `trackBy`). In cascade mode these are leaf-node keys. Defaults to `[]`. */
|
|
14
|
+
initialKeys?: readonly unknown[];
|
|
15
|
+
}
|
|
16
|
+
/** Display configuration for the tree. Pass any subset; unset keys fall back to the defaults. */
|
|
17
|
+
interface TwTreeDisplayConfig {
|
|
18
|
+
/** Row vertical density. Defaults to `'md'`. */
|
|
19
|
+
size?: TwSize;
|
|
20
|
+
/** Indentation per level, in pixels. Defaults to `16`. */
|
|
21
|
+
indent?: number;
|
|
22
|
+
/** Render connecting guide lines down the indent gutter. Defaults to `false`. */
|
|
23
|
+
showLines?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/** Context surfaced to a `*twTreeNode` template. Generic over the node type `T`. */
|
|
26
|
+
interface TwTreeNodeContext<T> {
|
|
27
|
+
/** The node data (implicit `let-node`). */
|
|
28
|
+
$implicit: T;
|
|
29
|
+
/** The node data, aliased for readability. */
|
|
30
|
+
node: T;
|
|
31
|
+
/** Zero-based depth of the node. */
|
|
32
|
+
level: number;
|
|
33
|
+
/** Whether the node is currently expanded. Always `false` for leaf nodes. */
|
|
34
|
+
expanded: boolean;
|
|
35
|
+
/** Whether the node has children (is a branch, not a leaf). */
|
|
36
|
+
hasChildren: boolean;
|
|
37
|
+
/** Tri-state selection status of this node. `'unchecked'` when selection is disabled. */
|
|
38
|
+
selectionState: TwTreeSelectionState;
|
|
39
|
+
/** Toggles this node's expand/collapse state. No-op on leaf nodes. */
|
|
40
|
+
toggle: () => void;
|
|
41
|
+
/** Expands this node. No-op on leaf nodes or when already expanded. */
|
|
42
|
+
expand: () => void;
|
|
43
|
+
/** Collapses this node. No-op when already collapsed. */
|
|
44
|
+
collapse: () => void;
|
|
45
|
+
/** Toggles this node's selection (cascades in `'multiple'` mode with `cascade` on). No-op when selection is disabled. */
|
|
46
|
+
toggleSelection: () => void;
|
|
47
|
+
}
|
|
48
|
+
/** Structural directive (`*twTreeNode="let node"`) declaring the per-node template. Typed as `TwTreeNodeContext<T>`. */
|
|
49
|
+
declare class TreeNodeDefDirective<T = unknown> {
|
|
50
|
+
/** @internal Consumer-projected per-node template. */
|
|
51
|
+
readonly template: TemplateRef<any>;
|
|
52
|
+
/** @internal */
|
|
53
|
+
static ngTemplateContextGuard<T>(_dir: TreeNodeDefDirective<T>, _ctx: unknown): _ctx is TwTreeNodeContext<T>;
|
|
54
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<TreeNodeDefDirective<any>, never>;
|
|
55
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TreeNodeDefDirective<any>, "[twTreeNode]", never, {}, {}, never, never, true, never>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A hierarchical, keyboard-navigable tree-view wrapping `@angular/cdk/tree`
|
|
59
|
+
* (children-accessor model). Consumers supply the per-node template via the
|
|
60
|
+
* `*twTreeNode` structural directive and receive a typed context exposing the
|
|
61
|
+
* node, its depth/expansion/children flags, its selection state, and action
|
|
62
|
+
* functions (`toggle`, `expand`, `collapse`, `toggleSelection`).
|
|
63
|
+
*
|
|
64
|
+
* Selection is optional and managed internally (`'none' | 'single' | 'multiple'`).
|
|
65
|
+
* In `'multiple'` mode with `cascade`, selecting a branch selects all its leaf
|
|
66
|
+
* descendants and the branch reports `'indeterminate'` when partially selected.
|
|
67
|
+
* This is NOT a form control — selection is exposed via the `selectionChange`
|
|
68
|
+
* output and the public `toggleSelection` / `selectionState` methods.
|
|
69
|
+
*/
|
|
70
|
+
declare class TreeComponent<T = unknown> {
|
|
71
|
+
/** Root nodes of the tree. Each node's children are resolved via `childrenAccessor`. Defaults to `[]`. */
|
|
72
|
+
readonly data: _angular_core.InputSignal<readonly T[]>;
|
|
73
|
+
/** Resolves a node's direct children; return an empty array for leaf nodes. Required. */
|
|
74
|
+
readonly childrenAccessor: _angular_core.InputSignal<(node: T) => readonly T[]>;
|
|
75
|
+
/** Identifies a node across data changes and keys both expansion and selection state. When unset, node identity is used. */
|
|
76
|
+
readonly trackBy: _angular_core.InputSignal<((node: T) => unknown) | undefined>;
|
|
77
|
+
/** Node-selection behavior — `mode`, `cascade`, `initialKeys`. Accepts a partial; unset keys fall back to the defaults. Defaults to selection disabled. */
|
|
78
|
+
readonly selection: _angular_core.InputSignal<Partial<TwTreeSelectionConfig>>;
|
|
79
|
+
/** Display configuration — `size`, `indent`, `showLines`. Accepts a partial; unset keys fall back to the defaults. */
|
|
80
|
+
readonly display: _angular_core.InputSignal<Partial<TwTreeDisplayConfig>>;
|
|
81
|
+
/** Two-way bound list of expansion key values (resolved via `trackBy`) for currently-expanded nodes. Set a new array on every change; do not mutate in place. Changes when a node is expanded or collapsed. Defaults to `[]` (all collapsed). */
|
|
82
|
+
readonly expandedKeys: _angular_core.ModelSignal<readonly unknown[]>;
|
|
83
|
+
/** Fires after the selection changes by user interaction. Payload is every node whose `selectionState` is `'checked'` (selected leaves plus fully-checked branches in cascade mode). */
|
|
84
|
+
readonly selectionChange: _angular_core.OutputEmitterRef<readonly T[]>;
|
|
85
|
+
/** Fires after a node is expanded or collapsed by user interaction. Payload identifies the node and its new expansion state. */
|
|
86
|
+
readonly expandedChange: _angular_core.OutputEmitterRef<{
|
|
87
|
+
node: T;
|
|
88
|
+
expanded: boolean;
|
|
89
|
+
}>;
|
|
90
|
+
/** @internal Consumer-projected per-node template (`*twTreeNode`). */
|
|
91
|
+
readonly nodeTemplate: _angular_core.Signal<TreeNodeDefDirective<any> | undefined>;
|
|
92
|
+
/** @internal The CDK tree inside our view. */
|
|
93
|
+
private readonly cdkTree;
|
|
94
|
+
/** @internal Selected node keys. In cascade mode this holds leaf keys only; branch state is derived. */
|
|
95
|
+
private readonly selectedKeys;
|
|
96
|
+
/** @internal One-shot guard so `initialKeys` seeds selection exactly once. */
|
|
97
|
+
private seeded;
|
|
98
|
+
/** @internal Resolved selection configuration. */
|
|
99
|
+
private readonly resolvedSelection;
|
|
100
|
+
/** @internal Resolved display configuration. */
|
|
101
|
+
private readonly resolvedDisplay;
|
|
102
|
+
/** @internal Indentation width in px per level. */
|
|
103
|
+
readonly indentWidth: _angular_core.Signal<number>;
|
|
104
|
+
/** @internal Snapshot of the root nodes as a mutable array (CDK's `dataSource` rejects `readonly T[]`). */
|
|
105
|
+
readonly dataArray: _angular_core.Signal<T[]>;
|
|
106
|
+
private readonly variants;
|
|
107
|
+
readonly rootClasses: _angular_core.Signal<string>;
|
|
108
|
+
readonly spacerClasses: _angular_core.Signal<string>;
|
|
109
|
+
readonly contentClasses: _angular_core.Signal<string>;
|
|
110
|
+
constructor();
|
|
111
|
+
/** @internal Resolves a node's identity key via `trackBy`, falling back to the node itself. */
|
|
112
|
+
private keyOf;
|
|
113
|
+
/** @internal Direct children of a node (always a fresh mutable array). */
|
|
114
|
+
private childrenOf;
|
|
115
|
+
/** Whether the node has at least one child (is a branch). */
|
|
116
|
+
hasChildren(node: T): boolean;
|
|
117
|
+
/** @internal Depth-first list of every node in the tree (under collapsed parents too). */
|
|
118
|
+
private flattenAll;
|
|
119
|
+
/** @internal All leaf descendants of a node (the node itself if it is a leaf). */
|
|
120
|
+
private leavesOf;
|
|
121
|
+
/** @internal Array of length `level` used to render per-level indent spacers. */
|
|
122
|
+
indentMarkers(level: number): readonly number[];
|
|
123
|
+
/** @internal Per-node row classes (incorporates the selected state). */
|
|
124
|
+
nodeClasses(node: T): string;
|
|
125
|
+
/** @internal Builds the typed context handed to the consumer's `*twTreeNode` template. */
|
|
126
|
+
buildContext(node: T, level: number): TwTreeNodeContext<T>;
|
|
127
|
+
/**
|
|
128
|
+
* @internal `aria-selected` for `'single'` mode (boolean selection), or `null`
|
|
129
|
+
* otherwise. Multiple mode uses `aria-checked` instead so the tri-state
|
|
130
|
+
* `'mixed'` value is exposed to assistive tech on the focusable treeitem.
|
|
131
|
+
*/
|
|
132
|
+
ariaSelected(node: T): 'true' | 'false' | null;
|
|
133
|
+
/**
|
|
134
|
+
* @internal Tri-state `aria-checked` for `'multiple'` mode (`'mixed'` for a
|
|
135
|
+
* partially-selected branch), or `null` otherwise. APG exposes checkbox-tree
|
|
136
|
+
* selection on the treeitem via `aria-checked`; `aria-selected` cannot carry
|
|
137
|
+
* the indeterminate state.
|
|
138
|
+
*/
|
|
139
|
+
ariaChecked(node: T): 'true' | 'false' | 'mixed' | null;
|
|
140
|
+
/** @internal Adapts the consumer's `readonly`-returning accessor to CDK's mutable-array contract. */
|
|
141
|
+
readonly cdkChildrenAccessor: (node: T) => T[];
|
|
142
|
+
/** @internal CDK row-tracking function keyed via `trackBy`. */
|
|
143
|
+
readonly cdkTrackBy: TrackByFunction<T>;
|
|
144
|
+
/** @internal Keys CDK's expansion model via `trackBy`. */
|
|
145
|
+
readonly cdkExpansionKey: (node: T) => unknown;
|
|
146
|
+
/** Whether the node is currently expanded. */
|
|
147
|
+
isExpanded(node: T): boolean;
|
|
148
|
+
/** Expands the node if collapsed. Emits `expandedChange` and updates `expandedKeys` via the CDK callback. */
|
|
149
|
+
expand(node: T): void;
|
|
150
|
+
/** Collapses the node if expanded. Emits `expandedChange` and updates `expandedKeys` via the CDK callback. */
|
|
151
|
+
collapse(node: T): void;
|
|
152
|
+
/** Toggles the node's expand/collapse state. No-op on leaf nodes. */
|
|
153
|
+
toggle(node: T): void;
|
|
154
|
+
/**
|
|
155
|
+
* @internal Bridges CDK's per-node `(expandedChange)` to the `expandedKeys`
|
|
156
|
+
* model. Compare-before-write: only mutates the model and emits when the
|
|
157
|
+
* key's membership actually changes, so the model→CDK effect cannot loop.
|
|
158
|
+
*/
|
|
159
|
+
onCdkExpandedChange(node: T, expanded: boolean): void;
|
|
160
|
+
/**
|
|
161
|
+
* Returns the tri-state selection status of a node. `'unchecked'` when
|
|
162
|
+
* selection is disabled.
|
|
163
|
+
*
|
|
164
|
+
* For cascade branches this walks the node's leaf descendants on each call and
|
|
165
|
+
* is invoked a few times per node per change-detection pass (row class, ARIA,
|
|
166
|
+
* context). This assumes small-to-medium trees; the component has no
|
|
167
|
+
* virtualization and is not tuned for very large data sets.
|
|
168
|
+
*/
|
|
169
|
+
selectionState(node: T): TwTreeSelectionState;
|
|
170
|
+
/** Toggles selection for a node (cascades to leaf descendants in `'multiple'` mode with `cascade` on). No-op when `selection.mode === 'none'`. */
|
|
171
|
+
toggleSelection(node: T): void;
|
|
172
|
+
/** @internal Every node currently reporting `selectionState() === 'checked'`. */
|
|
173
|
+
private selectedNodes;
|
|
174
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<TreeComponent<any>, never>;
|
|
175
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<TreeComponent<any>, "tw-tree", ["twTree"], { "data": { "alias": "data"; "required": false; "isSignal": true; }; "childrenAccessor": { "alias": "childrenAccessor"; "required": true; "isSignal": true; }; "trackBy": { "alias": "trackBy"; "required": false; "isSignal": true; }; "selection": { "alias": "selection"; "required": false; "isSignal": true; }; "display": { "alias": "display"; "required": false; "isSignal": true; }; "expandedKeys": { "alias": "expandedKeys"; "required": false; "isSignal": true; }; }, { "expandedKeys": "expandedKeysChange"; "selectionChange": "selectionChange"; "expandedChange": "expandedChange"; }, ["nodeTemplate"], never, true, never>;
|
|
176
|
+
}
|
|
177
|
+
/** Attribute directive (`[twTreeNodeToggle]="node"`) that toggles the given node's expansion on click. */
|
|
178
|
+
declare class TreeNodeToggleDirective<T = unknown> {
|
|
179
|
+
private readonly tree;
|
|
180
|
+
/** The node whose expansion this control toggles. */
|
|
181
|
+
readonly node: _angular_core.InputSignal<T>;
|
|
182
|
+
/** @internal Toggles the node and stops the click from bubbling to row activation. */
|
|
183
|
+
onClick(event: Event): void;
|
|
184
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<TreeNodeToggleDirective<any>, never>;
|
|
185
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TreeNodeToggleDirective<any>, "[twTreeNodeToggle]", never, { "node": { "alias": "twTreeNodeToggle"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export { TreeComponent, TreeNodeDefDirective, TreeNodeToggleDirective };
|
|
189
|
+
export type { TwTreeDisplayConfig, TwTreeNodeContext, TwTreeSelectionConfig, TwTreeSelectionState };
|
|
@@ -19,6 +19,7 @@ export * from '@cdevhub/ngx-tw/popover';
|
|
|
19
19
|
export * from '@cdevhub/ngx-tw/dialog';
|
|
20
20
|
export * from '@cdevhub/ngx-tw/command-palette';
|
|
21
21
|
export * from '@cdevhub/ngx-tw/toast';
|
|
22
|
+
export * from '@cdevhub/ngx-tw/transfer';
|
|
22
23
|
export * from '@cdevhub/ngx-tw/form-field';
|
|
23
24
|
export * from '@cdevhub/ngx-tw/switch';
|
|
24
25
|
export * from '@cdevhub/ngx-tw/checkbox';
|
|
@@ -26,6 +27,9 @@ export * from '@cdevhub/ngx-tw/radio';
|
|
|
26
27
|
export * from '@cdevhub/ngx-tw/select';
|
|
27
28
|
export * from '@cdevhub/ngx-tw/input';
|
|
28
29
|
export * from '@cdevhub/ngx-tw/textarea';
|
|
30
|
+
export * from '@cdevhub/ngx-tw/file-upload';
|
|
31
|
+
export * from '@cdevhub/ngx-tw/number-input';
|
|
32
|
+
export * from '@cdevhub/ngx-tw/tags-input';
|
|
29
33
|
export * from '@cdevhub/ngx-tw/spinner';
|
|
30
34
|
export * from '@cdevhub/ngx-tw/progress-bar';
|
|
31
35
|
export * from '@cdevhub/ngx-tw/skeleton';
|
|
@@ -47,3 +51,6 @@ export * from '@cdevhub/ngx-tw/stat';
|
|
|
47
51
|
export * from '@cdevhub/ngx-tw/combobox';
|
|
48
52
|
export * from '@cdevhub/ngx-tw/empty-state';
|
|
49
53
|
export * from '@cdevhub/ngx-tw/sheet';
|
|
54
|
+
export * from '@cdevhub/ngx-tw/aspect-ratio';
|
|
55
|
+
export * from '@cdevhub/ngx-tw/tree';
|
|
56
|
+
export * from '@cdevhub/ngx-tw/theme';
|