@egose/shadcn-theme-ng-tw 0.6.0 → 0.6.1
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 +119 -1
- package/autocomplete/fesm2022/autocomplete.mjs +14 -4
- package/autocomplete/types/autocomplete.d.ts +4 -1
- package/checkbox/README.md +6 -2
- package/checkbox/fesm2022/checkbox.mjs +15 -9
- package/checkbox/types/checkbox.d.ts +6 -4
- package/combobox/fesm2022/combobox.mjs +22 -6
- package/combobox/types/combobox.d.ts +8 -2
- package/data-table/README.md +10 -0
- package/data-table/fesm2022/data-table.mjs +48 -12
- package/data-table/types/data-table.d.ts +16 -4
- package/date-picker/README.md +41 -9
- package/date-picker/fesm2022/date-picker.mjs +265 -59
- package/date-picker/types/date-picker.d.ts +58 -27
- package/form-autocomplete/README.md +4 -2
- package/form-autocomplete/fesm2022/form-autocomplete.mjs +33 -8
- package/form-autocomplete/types/form-autocomplete.d.ts +9 -3
- package/form-combobox/README.md +4 -2
- package/form-combobox/fesm2022/form-combobox.mjs +65 -14
- package/form-combobox/types/form-combobox.d.ts +10 -3
- package/form-input-otp/README.md +7 -5
- package/form-input-otp/fesm2022/form-input-otp.mjs +28 -14
- package/form-input-otp/types/form-input-otp.d.ts +9 -3
- package/form-searchable-multiselect/README.md +15 -1
- package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs +23 -3
- package/form-searchable-multiselect/types/form-searchable-multiselect.d.ts +9 -1
- package/form-slider/README.md +3 -1
- package/form-slider/fesm2022/form-slider.mjs +21 -6
- package/form-slider/types/form-slider.d.ts +9 -3
- package/form-toggle/README.md +22 -18
- package/form-toggle/fesm2022/form-toggle.mjs +25 -8
- package/form-toggle/types/form-toggle.d.ts +6 -2
- package/input-otp/README.md +33 -9
- package/input-otp/fesm2022/input-otp.mjs +127 -11
- package/input-otp/types/input-otp.d.ts +24 -4
- package/package.json +1 -1
- package/pagination/README.md +21 -12
- package/pagination/fesm2022/pagination.mjs +83 -75
- package/pagination/types/pagination.d.ts +21 -8
- package/phone-input/README.md +16 -0
- package/phone-input/fesm2022/phone-input.mjs +41 -3
- package/phone-input/types/phone-input.d.ts +5 -2
- package/searchable-multiselect/README.md +62 -40
- package/searchable-multiselect/fesm2022/searchable-multiselect.mjs +97 -36
- package/searchable-multiselect/types/searchable-multiselect.d.ts +23 -6
- package/slider/fesm2022/slider.mjs +15 -5
- package/slider/types/slider.d.ts +6 -2
- package/stepper/README.md +39 -19
- package/stepper/fesm2022/stepper.mjs +71 -17
- package/stepper/types/stepper.d.ts +12 -1
|
@@ -11,7 +11,23 @@ import * as _spartan_ng_brain_popover from '@spartan-ng/brain/popover';
|
|
|
11
11
|
import { BrnPopover } from '@spartan-ng/brain/popover';
|
|
12
12
|
import * as i1$1 from '@spartan-ng/brain/field';
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
/** Internal input lifecycle shared by the single, range and multi pickers. */
|
|
15
|
+
declare abstract class HlmConstrainedDateInput<V> extends BrnDateInput<V> {
|
|
16
|
+
private readonly _commitState;
|
|
17
|
+
protected abstract readonly: () => boolean;
|
|
18
|
+
protected readonly _inputValue: _angular_core.WritableSignal<string>;
|
|
19
|
+
/** Rejected text stays invalid until a successful commit, clear, or external value write. */
|
|
20
|
+
readonly inputInvalid: _angular_core.WritableSignal<boolean>;
|
|
21
|
+
protected _commitDate(): void;
|
|
22
|
+
protected _handleBlur(): void;
|
|
23
|
+
protected _handleEnter(event: Event): void;
|
|
24
|
+
protected _handleFocus(): void;
|
|
25
|
+
protected _clear(): void;
|
|
26
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<HlmConstrainedDateInput<any>, never>;
|
|
27
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<HlmConstrainedDateInput<any>, never, never, {}, {}, never, never, true, never>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare class HlmDateMultiInput<T> extends HlmConstrainedDateInput<T[]> implements BrnDatePickerTriggerBase {
|
|
15
31
|
private readonly _config;
|
|
16
32
|
/** Native `name` attribute forwarded to the inner `<input>`. */
|
|
17
33
|
readonly name: _angular_core.InputSignal<string | undefined>;
|
|
@@ -26,9 +42,9 @@ declare class HlmDateMultiInput<T> extends BrnDateInput<T[]> implements BrnDateP
|
|
|
26
42
|
protected readonly $inputClass: _angular_core.Signal<string>;
|
|
27
43
|
constructor();
|
|
28
44
|
/**
|
|
29
|
-
* Parses input text into dates. Return `null` for invalid input
|
|
30
|
-
*
|
|
31
|
-
*
|
|
45
|
+
* Parses input text into dates. Return `null` for invalid input. Rejected
|
|
46
|
+
* text stays editable and aria-invalid; the committed value is preserved.
|
|
47
|
+
* Empty text explicitly clears on blur/Enter.
|
|
32
48
|
*
|
|
33
49
|
* Defaults to `parseDate` from `HlmDatePickerMultiConfig`.
|
|
34
50
|
*/
|
|
@@ -53,6 +69,10 @@ declare const HLM_DATE_PICKER_VALUE_ACCESSOR: {
|
|
|
53
69
|
};
|
|
54
70
|
declare class HlmDatePicker<T> implements BrnDatePickerBase<T>, ControlValueAccessor {
|
|
55
71
|
private readonly _config;
|
|
72
|
+
private readonly _dateAdapter;
|
|
73
|
+
private readonly _commitState;
|
|
74
|
+
private readonly _calendar;
|
|
75
|
+
private _restoringCalendar;
|
|
56
76
|
readonly popover: _angular_core.Signal<BrnPopover>;
|
|
57
77
|
private readonly _trigger;
|
|
58
78
|
/** Show dropdowns to navigate between months or years. */
|
|
@@ -91,13 +111,12 @@ declare class HlmDatePicker<T> implements BrnDatePickerBase<T>, ControlValueAcce
|
|
|
91
111
|
protected _onStateChange(state: BrnOverlayState): void;
|
|
92
112
|
protected _handleChange(value: T | undefined): void;
|
|
93
113
|
/**
|
|
94
|
-
* Commit a
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* is parsing user-entered values while typing.
|
|
114
|
+
* Commit a user value (null clears). Returns false without changing/emitting
|
|
115
|
+
* the model when disabled or when the raw/transformed date is invalid or
|
|
116
|
+
* outside the adapter's inclusive whole-day min/max bounds.
|
|
98
117
|
*/
|
|
99
|
-
updateDate(value: T | null):
|
|
100
|
-
/**
|
|
118
|
+
updateDate(value: T | null): boolean;
|
|
119
|
+
/** Programmatic CVA write: transforms without enforcing user constraints or emitting. Clears rejected text. */
|
|
101
120
|
writeValue(value: T | null): void;
|
|
102
121
|
registerOnChange(fn: ChangeFn<T | null>): void;
|
|
103
122
|
registerOnTouched(fn: TouchFn): void;
|
|
@@ -120,7 +139,7 @@ declare class HlmDatePickerAnchor {
|
|
|
120
139
|
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<HlmDatePickerAnchor, "[hlmDatePickerAnchor]", never, { "hlmDatePickerAnchorForInput": { "alias": "hlmDatePickerAnchorFor"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
121
140
|
}
|
|
122
141
|
|
|
123
|
-
declare class HlmDatePickerInput<T> extends
|
|
142
|
+
declare class HlmDatePickerInput<T> extends HlmConstrainedDateInput<T> implements BrnDatePickerTriggerBase {
|
|
124
143
|
private readonly _config;
|
|
125
144
|
readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
|
|
126
145
|
readonly ariaDescribedby: _angular_core.InputSignal<string | null>;
|
|
@@ -136,8 +155,8 @@ declare class HlmDatePickerInput<T> extends BrnDateInput<T> implements BrnDatePi
|
|
|
136
155
|
constructor();
|
|
137
156
|
/**
|
|
138
157
|
* Parses input text into a date value. Return `null` for invalid
|
|
139
|
-
* input
|
|
140
|
-
*
|
|
158
|
+
* input. Rejected text stays editable and aria-invalid; the committed value
|
|
159
|
+
* is preserved. Empty text explicitly clears on blur/Enter.
|
|
141
160
|
*
|
|
142
161
|
* Defaults to `parseDate` from `HlmDatePickerConfig`.
|
|
143
162
|
*/
|
|
@@ -162,6 +181,10 @@ declare const HLM_DATE_PICKER_MUTLI_VALUE_ACCESSOR: {
|
|
|
162
181
|
};
|
|
163
182
|
declare class HlmDatePickerMulti<T> implements BrnDatePickerBase<T[]>, ControlValueAccessor {
|
|
164
183
|
private readonly _config;
|
|
184
|
+
private readonly _dateAdapter;
|
|
185
|
+
private readonly _commitState;
|
|
186
|
+
private readonly _calendar;
|
|
187
|
+
private _restoringCalendar;
|
|
165
188
|
readonly popover: _angular_core.Signal<BrnPopover>;
|
|
166
189
|
private readonly _trigger;
|
|
167
190
|
/** Show dropdowns to navigate between months or years. */
|
|
@@ -170,7 +193,7 @@ declare class HlmDatePickerMulti<T> implements BrnDatePickerBase<T[]>, ControlVa
|
|
|
170
193
|
readonly min: _angular_core.InputSignal<T | undefined>;
|
|
171
194
|
/** The maximum date that can be selected. */
|
|
172
195
|
readonly max: _angular_core.InputSignal<T | undefined>;
|
|
173
|
-
/**
|
|
196
|
+
/** Deselection floor; selection can grow from empty below this count. Explicit clear is allowed. */
|
|
174
197
|
readonly minSelection: _angular_core.InputSignalWithTransform<number | undefined, NumberInput>;
|
|
175
198
|
/** The maximum selectable dates. */
|
|
176
199
|
readonly maxSelection: _angular_core.InputSignalWithTransform<number | undefined, NumberInput>;
|
|
@@ -201,13 +224,15 @@ declare class HlmDatePickerMulti<T> implements BrnDatePickerBase<T[]>, ControlVa
|
|
|
201
224
|
protected _onStateChange(state: BrnOverlayState): void;
|
|
202
225
|
protected _handleChange(value: T[] | undefined): void;
|
|
203
226
|
/**
|
|
204
|
-
* Commit dates
|
|
205
|
-
*
|
|
206
|
-
*
|
|
227
|
+
* Commit user dates, validating raw and transformed dates/counts. Returns
|
|
228
|
+
* false without changing/emitting on rejection. Min selection prevents
|
|
229
|
+
* reductions below the floor, but permits growth from empty. Null explicitly
|
|
230
|
+
* clears (emits []), bypassing the selection floor and transform.
|
|
207
231
|
*/
|
|
208
|
-
updateDate(value: T[] | null):
|
|
232
|
+
updateDate(value: T[] | null): boolean;
|
|
233
|
+
private _isSelectionAllowed;
|
|
209
234
|
touched(): void;
|
|
210
|
-
/**
|
|
235
|
+
/** Programmatic CVA write: transforms without enforcing user constraints or emitting. Clears rejected text. */
|
|
211
236
|
writeValue(value: T[] | null): void;
|
|
212
237
|
registerOnChange(fn: ChangeFn<T[]>): void;
|
|
213
238
|
registerOnTouched(fn: TouchFn): void;
|
|
@@ -246,7 +271,7 @@ declare class HlmDatePickerTrigger implements BrnDatePickerTriggerBase {
|
|
|
246
271
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<HlmDatePickerTrigger, "hlm-date-picker-trigger", never, { "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "buttonId": { "alias": "buttonId"; "required": false; "isSignal": true; }; "forceInvalid": { "alias": "forceInvalid"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "showTrigger": { "alias": "showTrigger"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
247
272
|
}
|
|
248
273
|
|
|
249
|
-
declare class HlmDateRangeInput<T> extends
|
|
274
|
+
declare class HlmDateRangeInput<T> extends HlmConstrainedDateInput<[T, T]> implements BrnDatePickerTriggerBase {
|
|
250
275
|
private readonly _config;
|
|
251
276
|
/** Native `name` attribute forwarded to the inner `<input>`. */
|
|
252
277
|
readonly name: _angular_core.InputSignal<string | undefined>;
|
|
@@ -262,8 +287,8 @@ declare class HlmDateRangeInput<T> extends BrnDateInput<[T, T]> implements BrnDa
|
|
|
262
287
|
constructor();
|
|
263
288
|
/**
|
|
264
289
|
* Parses input text into a date range. Return `null` for invalid
|
|
265
|
-
* input
|
|
266
|
-
*
|
|
290
|
+
* input. Rejected text stays editable and aria-invalid; the committed value
|
|
291
|
+
* is preserved. Empty text explicitly clears on blur/Enter.
|
|
267
292
|
*
|
|
268
293
|
* Defaults to `parseDate` from `HlmDateRangePickerConfig`.
|
|
269
294
|
*/
|
|
@@ -288,6 +313,10 @@ declare const HLM_DATE_RANGE_PICKER_VALUE_ACCESSOR: {
|
|
|
288
313
|
};
|
|
289
314
|
declare class HlmDateRangePicker<T> implements BrnDatePickerBase<[T, T]>, ControlValueAccessor {
|
|
290
315
|
private readonly _config;
|
|
316
|
+
private readonly _dateAdapter;
|
|
317
|
+
private readonly _commitState;
|
|
318
|
+
private readonly _calendar;
|
|
319
|
+
private _restoringCalendar;
|
|
291
320
|
readonly popover: _angular_core.Signal<BrnPopover>;
|
|
292
321
|
private readonly _trigger;
|
|
293
322
|
/** Show dropdowns to navigate between months or years. */
|
|
@@ -325,14 +354,16 @@ declare class HlmDateRangePicker<T> implements BrnDatePickerBase<[T, T]>, Contro
|
|
|
325
354
|
protected _onStateChange(state: BrnOverlayState): void;
|
|
326
355
|
protected _handleStartDayChange(value: T | undefined): void;
|
|
327
356
|
protected _handleEndDateChange(value: T | undefined): void;
|
|
357
|
+
private _restoreCalendar;
|
|
328
358
|
/**
|
|
329
|
-
* Commit a range
|
|
330
|
-
*
|
|
331
|
-
*
|
|
359
|
+
* Commit a user range (null clears). Both raw/transformed endpoints must
|
|
360
|
+
* satisfy adapter whole-day bounds; the transformed range must be ordered.
|
|
361
|
+
* Returns false without changing/emitting the model on rejection or disabled.
|
|
332
362
|
*/
|
|
333
|
-
updateDate(value: [T, T] | null):
|
|
363
|
+
updateDate(value: [T, T] | null): boolean;
|
|
364
|
+
private _isRangeAllowed;
|
|
334
365
|
touched(): void;
|
|
335
|
-
/**
|
|
366
|
+
/** Programmatic CVA write: transforms without enforcing user constraints or emitting. Clears rejected text. */
|
|
336
367
|
writeValue(value: [T, T] | null): void;
|
|
337
368
|
registerOnChange(fn: ChangeFn<[T, T] | null>): void;
|
|
338
369
|
registerOnTouched(fn: TouchFn): void;
|
|
@@ -151,8 +151,10 @@ export class CityComponent {
|
|
|
151
151
|
## Accessibility notes
|
|
152
152
|
|
|
153
153
|
- Label `for` ↔ input `inputId` wiring is automatic via `effectiveId` — always pass a `label`.
|
|
154
|
-
- The
|
|
155
|
-
-
|
|
154
|
+
- The native input's `aria-describedby` references the displayed error when invalid and touched/dirty/submitted, otherwise the hint. Correction/reset restores the hint; absent messages leave no wrapper-owned reference.
|
|
155
|
+
- Optional `[aria-describedby]` (`string | null`, default `null`) adds consumer-owned IDs before the current message ID, with whitespace normalization and deduplication. Keep those external elements mounted; reserve `<effectiveId>-error` and `<effectiveId>-hint` for the wrapper. Use the input binding, not `[attr.aria-describedby]` on the wrapper host.
|
|
156
|
+
- `required` supplies the visual `*` and native `aria-required`; configure `Validators.required` independently. Native invalid state continues to follow the form control.
|
|
157
|
+
- Verification covers rendered DOM relationships and focus, not screen-reader announcement behavior. `HlmError` itself is not a live region.
|
|
156
158
|
|
|
157
159
|
## Theming / CSS variables
|
|
158
160
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, input, computed, Component } from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, ChangeDetectorRef, DestroyRef, input, computed, Component } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/forms';
|
|
4
4
|
import { FormGroupDirective, ReactiveFormsModule, ControlContainer } from '@angular/forms';
|
|
5
5
|
import { injectEgFormErrorMessages, HlmFormIdGenerator, injectEgFormSharedConfig, resolveEgFormError, HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng-tw/form-field';
|
|
6
6
|
import { HlmLabel } from '@egose/shadcn-theme-ng-tw/label';
|
|
7
7
|
import { HlmAutocomplete, HlmAutocompleteContent, HlmAutocompleteEmpty, HlmAutocompleteGroup, HlmAutocompleteInput, HlmAutocompleteItem, HlmAutocompleteList, HlmAutocompleteLabel } from '@egose/shadcn-theme-ng-tw/autocomplete';
|
|
8
8
|
import { hlm } from '@egose/shadcn-theme-ng-tw/utils';
|
|
9
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
9
10
|
|
|
10
11
|
const EgFormAutocompleteConfigToken = new InjectionToken('EgFormAutocompleteConfig');
|
|
11
12
|
function provideEgFormAutocompleteConfig(config) {
|
|
@@ -21,6 +22,14 @@ class EgFormAutocomplete {
|
|
|
21
22
|
generatedId = inject(HlmFormIdGenerator).generate('eg-form-autocomplete');
|
|
22
23
|
_config = injectEgFormAutocompleteConfig();
|
|
23
24
|
_shared = injectEgFormSharedConfig();
|
|
25
|
+
_cdr = inject(ChangeDetectorRef);
|
|
26
|
+
_destroyRef = inject(DestroyRef);
|
|
27
|
+
ngOnInit() {
|
|
28
|
+
// Submit/reset may change message visibility without changing the field's value or validity.
|
|
29
|
+
this.formGroupDirective.form.events
|
|
30
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
31
|
+
.subscribe(() => this._cdr.markForCheck());
|
|
32
|
+
}
|
|
24
33
|
label = input(undefined, /* @ts-ignore */
|
|
25
34
|
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
26
35
|
controlId = input(undefined, /* @ts-ignore */
|
|
@@ -38,6 +47,8 @@ class EgFormAutocomplete {
|
|
|
38
47
|
...(ngDevMode ? [{ debugName: "autoError" }] : /* istanbul ignore next */ []));
|
|
39
48
|
hint = input(undefined, /* @ts-ignore */
|
|
40
49
|
...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
|
|
50
|
+
/** Consumer-owned description IDs, merged with the current error and hint IDs. */
|
|
51
|
+
ariaDescribedBy = input(null, { ...(ngDevMode ? { debugName: "ariaDescribedBy" } : /* istanbul ignore next */ {}), alias: 'aria-describedby' });
|
|
41
52
|
id = input(undefined, /* @ts-ignore */
|
|
42
53
|
...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
43
54
|
placeholder = input('Type to search…', /* @ts-ignore */
|
|
@@ -90,6 +101,10 @@ class EgFormAutocomplete {
|
|
|
90
101
|
effectiveDisabled() {
|
|
91
102
|
return this.disabled() || !!this.formGroupDirective.form.get(this.controlName())?.disabled;
|
|
92
103
|
}
|
|
104
|
+
describedBy() {
|
|
105
|
+
const ids = [this.ariaDescribedBy(), this.showError() ? this.errorId() : this.hint() ? this.hintId() : null];
|
|
106
|
+
return [...new Set(ids.filter(Boolean).join(' ').split(/\s+/).filter(Boolean))].join(' ') || null;
|
|
107
|
+
}
|
|
93
108
|
// Styling
|
|
94
109
|
userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
|
|
95
110
|
labelClass = input('', /* @ts-ignore */
|
|
@@ -103,8 +118,6 @@ class EgFormAutocomplete {
|
|
|
103
118
|
hintClass = input('', /* @ts-ignore */
|
|
104
119
|
...(ngDevMode ? [{ debugName: "hintClass" }] : /* istanbul ignore next */ []));
|
|
105
120
|
// Computed classes (library base < global config < per-instance).
|
|
106
|
-
// NOTE: the autocomplete input exposes no aria-describedby, so error/hint
|
|
107
|
-
// ids render without an input-level describedby link.
|
|
108
121
|
$userClass = computed(() => hlm('tw:w-full', this.userClass()), /* @ts-ignore */
|
|
109
122
|
...(ngDevMode ? [{ debugName: "$userClass" }] : /* istanbul ignore next */ []));
|
|
110
123
|
$labelClass = computed(() => hlm('tw:mb-1', this._shared.labelClass, this._config.labelClass, this.labelClass()), /* @ts-ignore */
|
|
@@ -118,7 +131,7 @@ class EgFormAutocomplete {
|
|
|
118
131
|
$hintClass = computed(() => hlm('tw:mt-0', this._shared.hintClass, this._config.hintClass, this.hintClass()), /* @ts-ignore */
|
|
119
132
|
...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
|
|
120
133
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormAutocomplete, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
121
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormAutocomplete, isStandalone: true, selector: "eg-form-autocomplete", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, autoError: { classPropertyName: "autoError", publicName: "autoError", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, controlClass: { classPropertyName: "controlClass", publicName: "controlClass", isSignal: true, isRequired: false, transformFunction: null }, inputClass: { classPropertyName: "inputClass", publicName: "inputClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "$userClass()" } }, providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }], ngImport: i0, template: `
|
|
134
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormAutocomplete, isStandalone: true, selector: "eg-form-autocomplete", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, autoError: { classPropertyName: "autoError", publicName: "autoError", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, controlClass: { classPropertyName: "controlClass", publicName: "controlClass", isSignal: true, isRequired: false, transformFunction: null }, inputClass: { classPropertyName: "inputClass", publicName: "inputClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "$userClass()" } }, providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }], ngImport: i0, template: `
|
|
122
135
|
@let lbl = label();
|
|
123
136
|
@let cnm = controlName();
|
|
124
137
|
@let hnt = hint();
|
|
@@ -135,7 +148,13 @@ class EgFormAutocomplete {
|
|
|
135
148
|
}
|
|
136
149
|
|
|
137
150
|
<div hlmAutocomplete [formControlName]="cnm" [disabled]="effectiveDisabled()" [class]="$controlClass()">
|
|
138
|
-
<hlm-autocomplete-input
|
|
151
|
+
<hlm-autocomplete-input
|
|
152
|
+
[inputId]="effectiveId()"
|
|
153
|
+
[placeholder]="placeholder()"
|
|
154
|
+
[aria-describedby]="describedBy()"
|
|
155
|
+
[required]="rqrd"
|
|
156
|
+
[class]="$inputClass()"
|
|
157
|
+
/>
|
|
139
158
|
<hlm-autocomplete-content>
|
|
140
159
|
<div hlmAutocompleteList>
|
|
141
160
|
<div hlmAutocompleteGroup>
|
|
@@ -160,7 +179,7 @@ class EgFormAutocomplete {
|
|
|
160
179
|
</hlm-hint>
|
|
161
180
|
}
|
|
162
181
|
</hlm-form-field>
|
|
163
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: HlmFormField, selector: "hlm-form-field", inputs: ["class"] }, { kind: "directive", type: HlmError, selector: "hlm-error", inputs: ["class"] }, { kind: "directive", type: HlmHint, selector: "hlm-hint", inputs: ["class"] }, { kind: "directive", type: HlmLabel, selector: "[hlmLabel]", inputs: ["class"] }, { kind: "directive", type: HlmAutocomplete, selector: "[hlmAutocomplete],hlm-autocomplete" }, { kind: "directive", type: HlmAutocompleteContent, selector: "[hlmAutocompleteContent],hlm-autocomplete-content" }, { kind: "directive", type: HlmAutocompleteEmpty, selector: "[hlmAutocompleteEmpty],hlm-autocomplete-empty" }, { kind: "directive", type: HlmAutocompleteGroup, selector: "[hlmAutocompleteGroup]" }, { kind: "component", type: HlmAutocompleteInput, selector: "hlm-autocomplete-input", inputs: ["inputId", "placeholder", "showSearch", "showClear", "forceInvalid", "aria-invalid"] }, { kind: "component", type: HlmAutocompleteItem, selector: "hlm-autocomplete-item" }, { kind: "directive", type: HlmAutocompleteList, selector: "[hlmAutocompleteList]" }] });
|
|
182
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: HlmFormField, selector: "hlm-form-field", inputs: ["class"] }, { kind: "directive", type: HlmError, selector: "hlm-error", inputs: ["class"] }, { kind: "directive", type: HlmHint, selector: "hlm-hint", inputs: ["class"] }, { kind: "directive", type: HlmLabel, selector: "[hlmLabel]", inputs: ["class"] }, { kind: "directive", type: HlmAutocomplete, selector: "[hlmAutocomplete],hlm-autocomplete" }, { kind: "directive", type: HlmAutocompleteContent, selector: "[hlmAutocompleteContent],hlm-autocomplete-content" }, { kind: "directive", type: HlmAutocompleteEmpty, selector: "[hlmAutocompleteEmpty],hlm-autocomplete-empty" }, { kind: "directive", type: HlmAutocompleteGroup, selector: "[hlmAutocompleteGroup]" }, { kind: "component", type: HlmAutocompleteInput, selector: "hlm-autocomplete-input", inputs: ["inputId", "placeholder", "aria-describedby", "required", "showSearch", "showClear", "forceInvalid", "aria-invalid"] }, { kind: "component", type: HlmAutocompleteItem, selector: "hlm-autocomplete-item" }, { kind: "directive", type: HlmAutocompleteList, selector: "[hlmAutocompleteList]" }] });
|
|
164
183
|
}
|
|
165
184
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormAutocomplete, decorators: [{
|
|
166
185
|
type: Component,
|
|
@@ -203,7 +222,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
203
222
|
}
|
|
204
223
|
|
|
205
224
|
<div hlmAutocomplete [formControlName]="cnm" [disabled]="effectiveDisabled()" [class]="$controlClass()">
|
|
206
|
-
<hlm-autocomplete-input
|
|
225
|
+
<hlm-autocomplete-input
|
|
226
|
+
[inputId]="effectiveId()"
|
|
227
|
+
[placeholder]="placeholder()"
|
|
228
|
+
[aria-describedby]="describedBy()"
|
|
229
|
+
[required]="rqrd"
|
|
230
|
+
[class]="$inputClass()"
|
|
231
|
+
/>
|
|
207
232
|
<hlm-autocomplete-content>
|
|
208
233
|
<div hlmAutocompleteList>
|
|
209
234
|
<div hlmAutocompleteGroup>
|
|
@@ -230,7 +255,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
230
255
|
</hlm-form-field>
|
|
231
256
|
`,
|
|
232
257
|
}]
|
|
233
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], controlId: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlId", required: false }] }], controlName: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlName", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], autoError: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoError", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], controlClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlClass", required: false }] }], inputClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
|
|
258
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], controlId: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlId", required: false }] }], controlName: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlName", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], autoError: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoError", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-describedby", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], controlClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlClass", required: false }] }], inputClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
|
|
234
259
|
|
|
235
260
|
/*
|
|
236
261
|
* Public API Surface of form-autocomplete
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
-
import { ValueProvider } from '@angular/core';
|
|
2
|
+
import { OnInit, ValueProvider } from '@angular/core';
|
|
3
3
|
import { ClassValue } from 'clsx';
|
|
4
4
|
|
|
5
|
-
declare class EgFormAutocomplete {
|
|
5
|
+
declare class EgFormAutocomplete implements OnInit {
|
|
6
6
|
private readonly formGroupDirective;
|
|
7
7
|
private readonly _errorMessages;
|
|
8
8
|
private readonly generatedId;
|
|
9
9
|
private readonly _config;
|
|
10
10
|
private readonly _shared;
|
|
11
|
+
private readonly _cdr;
|
|
12
|
+
private readonly _destroyRef;
|
|
13
|
+
ngOnInit(): void;
|
|
11
14
|
label: _angular_core.InputSignal<string | undefined>;
|
|
12
15
|
controlId: _angular_core.InputSignal<string | undefined>;
|
|
13
16
|
controlName: _angular_core.InputSignal<string>;
|
|
@@ -19,6 +22,8 @@ declare class EgFormAutocomplete {
|
|
|
19
22
|
*/
|
|
20
23
|
autoError: _angular_core.InputSignal<boolean>;
|
|
21
24
|
hint: _angular_core.InputSignal<string | undefined>;
|
|
25
|
+
/** Consumer-owned description IDs, merged with the current error and hint IDs. */
|
|
26
|
+
ariaDescribedBy: _angular_core.InputSignal<string | null>;
|
|
22
27
|
id: _angular_core.InputSignal<string | undefined>;
|
|
23
28
|
placeholder: _angular_core.InputSignal<string>;
|
|
24
29
|
emptyText: _angular_core.InputSignal<string>;
|
|
@@ -47,6 +52,7 @@ declare class EgFormAutocomplete {
|
|
|
47
52
|
* wrapper-toggle + `control.disable()` cannot clobber CVA state.
|
|
48
53
|
*/
|
|
49
54
|
effectiveDisabled(): boolean;
|
|
55
|
+
protected describedBy(): string | null;
|
|
50
56
|
userClass: _angular_core.InputSignal<ClassValue>;
|
|
51
57
|
labelClass: _angular_core.InputSignal<string>;
|
|
52
58
|
controlClass: _angular_core.InputSignal<string>;
|
|
@@ -60,7 +66,7 @@ declare class EgFormAutocomplete {
|
|
|
60
66
|
$errorClass: _angular_core.Signal<string>;
|
|
61
67
|
$hintClass: _angular_core.Signal<string>;
|
|
62
68
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<EgFormAutocomplete, never>;
|
|
63
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormAutocomplete, "eg-form-autocomplete", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; "controlName": { "alias": "controlName"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "autoError": { "alias": "autoError"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "emptyText": { "alias": "emptyText"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "labelClass": { "alias": "labelClass"; "required": false; "isSignal": true; }; "controlClass": { "alias": "controlClass"; "required": false; "isSignal": true; }; "inputClass": { "alias": "inputClass"; "required": false; "isSignal": true; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
69
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormAutocomplete, "eg-form-autocomplete", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; "controlName": { "alias": "controlName"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "autoError": { "alias": "autoError"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "ariaDescribedBy": { "alias": "aria-describedby"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "emptyText": { "alias": "emptyText"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "labelClass": { "alias": "labelClass"; "required": false; "isSignal": true; }; "controlClass": { "alias": "controlClass"; "required": false; "isSignal": true; }; "inputClass": { "alias": "inputClass"; "required": false; "isSignal": true; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
interface EgFormAutocompleteConfig {
|
package/form-combobox/README.md
CHANGED
|
@@ -176,8 +176,10 @@ export class FruitSingleComponent {
|
|
|
176
176
|
## Accessibility notes
|
|
177
177
|
|
|
178
178
|
- Label `for` ↔ chip-search-input `id` wiring is automatic via `effectiveId` — always pass a `label`.
|
|
179
|
-
-
|
|
180
|
-
-
|
|
179
|
+
- Multiple mode connects the native chip input to the displayed error (invalid + touched/dirty/submitted), otherwise the hint. Single mode connects both the native trigger button and portaled search input. Correction/reset restores hint descriptions and obsolete message IDs disappear.
|
|
180
|
+
- Optional `[aria-describedby]` (`string | null`, default `null`) adds consumer-owned IDs before the current message ID, with whitespace normalization and deduplication. Keep external elements mounted and reserve `<effectiveId>-error` / `-hint` for the wrapper. Use the input binding rather than `[attr.aria-describedby]` on the wrapper host.
|
|
181
|
+
- Single mode uses `<effectiveId>` for the labeled trigger and `<effectiveId>-search` for its search input, labeled by `<effectiveId>-label`; this avoids duplicate IDs while open. The search filters options, so required/invalid state belongs to the selected-value trigger. Multiple mode exposes that state on its chip input.
|
|
182
|
+
- `required` supplies the visual `*` and `aria-required` on the selected-value control; configure `Validators.required` independently. `HlmError` is not a live region; rendered DOM/focus tests do not establish screen-reader announcement behavior.
|
|
181
183
|
|
|
182
184
|
## Theming / CSS variables
|
|
183
185
|
|