@egose/shadcn-theme-ng-tw 0.6.0 → 0.6.2
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 +11 -1
- package/data-table/fesm2022/data-table.mjs +76 -26
- package/data-table/types/data-table.d.ts +25 -6
- 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
|
@@ -87,6 +87,18 @@ class EgFormSearchableMultiselect {
|
|
|
87
87
|
// Multiselect-specific
|
|
88
88
|
options = input([], /* @ts-ignore */
|
|
89
89
|
...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ [])); // [{ label, value }]
|
|
90
|
+
/** Visible native search label; local label filtering preserves every selected form value. */
|
|
91
|
+
searchLabel = input('Search options', /* @ts-ignore */
|
|
92
|
+
...(ngDevMode ? [{ debugName: "searchLabel" }] : /* istanbul ignore next */ []));
|
|
93
|
+
/** Search hint forwarded independently of the empty-selection placeholder. */
|
|
94
|
+
searchPlaceholder = input('Type to filter…', /* @ts-ignore */
|
|
95
|
+
...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
|
|
96
|
+
/** Polite live-region copy for an empty filtered option list. */
|
|
97
|
+
emptyMessage = input('No matching options', /* @ts-ignore */
|
|
98
|
+
...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
|
|
99
|
+
/** Pure accessible chip-remove name formatter; receives the resolved label or raw unresolved ID. */
|
|
100
|
+
removeLabel = input((option) => `Remove ${option.label}`, /* @ts-ignore */
|
|
101
|
+
...(ngDevMode ? [{ debugName: "removeLabel" }] : /* istanbul ignore next */ []));
|
|
90
102
|
// Styling classes
|
|
91
103
|
userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
|
|
92
104
|
labelClass = input('', /* @ts-ignore */
|
|
@@ -109,7 +121,7 @@ class EgFormSearchableMultiselect {
|
|
|
109
121
|
$hintClass = computed(() => hlm('tw:mt-0', this._shared.hintClass, this._config.hintClass, this.hintClass()), /* @ts-ignore */
|
|
110
122
|
...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
|
|
111
123
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormSearchableMultiselect, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
112
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormSearchableMultiselect, isStandalone: true, selector: "eg-form-searchable-multiselect", 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 }, 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 }, 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: `
|
|
124
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormSearchableMultiselect, isStandalone: true, selector: "eg-form-searchable-multiselect", 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 }, 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 }, searchLabel: { classPropertyName: "searchLabel", publicName: "searchLabel", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", 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 }, 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: `
|
|
113
125
|
@let lbl = label();
|
|
114
126
|
@let cnm = controlName();
|
|
115
127
|
@let hnt = hint();
|
|
@@ -129,6 +141,10 @@ class EgFormSearchableMultiselect {
|
|
|
129
141
|
[id]="effectiveId()"
|
|
130
142
|
[options]="options()"
|
|
131
143
|
[placeholder]="placeholder()"
|
|
144
|
+
[searchLabel]="searchLabel()"
|
|
145
|
+
[searchPlaceholder]="searchPlaceholder()"
|
|
146
|
+
[emptyMessage]="emptyMessage()"
|
|
147
|
+
[removeLabel]="removeLabel()"
|
|
132
148
|
[formControlName]="cnm"
|
|
133
149
|
[required]="rqrd"
|
|
134
150
|
[wrapperDisabled]="disabled()"
|
|
@@ -148,7 +164,7 @@ class EgFormSearchableMultiselect {
|
|
|
148
164
|
</hlm-hint>
|
|
149
165
|
}
|
|
150
166
|
</eg-form-field>
|
|
151
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: EgFormField, selector: "eg-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: "component", type: EgSearchableMultiselect, selector: "eg-searchable-multiselect", inputs: ["options", "placeholder", "id", "disabled", "wrapperDisabled", "ariaLabel", "ariaDescribedby", "class", "value"], outputs: ["valueChange"] }] });
|
|
167
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: EgFormField, selector: "eg-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: "component", type: EgSearchableMultiselect, selector: "eg-searchable-multiselect", inputs: ["options", "placeholder", "searchLabel", "searchPlaceholder", "emptyMessage", "removeLabel", "id", "disabled", "wrapperDisabled", "ariaLabel", "ariaDescribedby", "class", "value"], outputs: ["valueChange"] }] });
|
|
152
168
|
}
|
|
153
169
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormSearchableMultiselect, decorators: [{
|
|
154
170
|
type: Component,
|
|
@@ -180,6 +196,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
180
196
|
[id]="effectiveId()"
|
|
181
197
|
[options]="options()"
|
|
182
198
|
[placeholder]="placeholder()"
|
|
199
|
+
[searchLabel]="searchLabel()"
|
|
200
|
+
[searchPlaceholder]="searchPlaceholder()"
|
|
201
|
+
[emptyMessage]="emptyMessage()"
|
|
202
|
+
[removeLabel]="removeLabel()"
|
|
183
203
|
[formControlName]="cnm"
|
|
184
204
|
[required]="rqrd"
|
|
185
205
|
[wrapperDisabled]="disabled()"
|
|
@@ -201,7 +221,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
201
221
|
</eg-form-field>
|
|
202
222
|
`,
|
|
203
223
|
}]
|
|
204
|
-
}], 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 }] }], 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 }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
|
|
224
|
+
}], 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 }] }], 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 }] }], searchLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchLabel", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], removeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeLabel", 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 }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
|
|
205
225
|
|
|
206
226
|
/*
|
|
207
227
|
* Public API Surface of form-searchable-multiselect
|
|
@@ -42,6 +42,14 @@ declare class EgFormSearchableMultiselect {
|
|
|
42
42
|
protected showError(): boolean;
|
|
43
43
|
describedBy(): string | null;
|
|
44
44
|
options: _angular_core.InputSignal<SelectOption[]>;
|
|
45
|
+
/** Visible native search label; local label filtering preserves every selected form value. */
|
|
46
|
+
searchLabel: _angular_core.InputSignal<string>;
|
|
47
|
+
/** Search hint forwarded independently of the empty-selection placeholder. */
|
|
48
|
+
searchPlaceholder: _angular_core.InputSignal<string>;
|
|
49
|
+
/** Polite live-region copy for an empty filtered option list. */
|
|
50
|
+
emptyMessage: _angular_core.InputSignal<string>;
|
|
51
|
+
/** Pure accessible chip-remove name formatter; receives the resolved label or raw unresolved ID. */
|
|
52
|
+
removeLabel: _angular_core.InputSignal<(option: SelectOption) => string>;
|
|
45
53
|
userClass: _angular_core.InputSignal<ClassValue>;
|
|
46
54
|
labelClass: _angular_core.InputSignal<string>;
|
|
47
55
|
controlClass: _angular_core.InputSignal<string>;
|
|
@@ -53,7 +61,7 @@ declare class EgFormSearchableMultiselect {
|
|
|
53
61
|
$errorClass: _angular_core.Signal<string>;
|
|
54
62
|
$hintClass: _angular_core.Signal<string>;
|
|
55
63
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<EgFormSearchableMultiselect, never>;
|
|
56
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormSearchableMultiselect, "eg-form-searchable-multiselect", 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; }; "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; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
64
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormSearchableMultiselect, "eg-form-searchable-multiselect", 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; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "searchLabel": { "alias": "searchLabel"; "required": false; "isSignal": true; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "removeLabel": { "alias": "removeLabel"; "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; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
interface EgFormSearchableMultiselectConfig {
|
package/form-slider/README.md
CHANGED
|
@@ -158,7 +158,9 @@ export class PriceComponent {
|
|
|
158
158
|
## Accessibility notes
|
|
159
159
|
|
|
160
160
|
- The label is linked via `aria-labelledby` (sliders have no `for`-compatible control); always pass a `label`.
|
|
161
|
-
-
|
|
161
|
+
- Each focusable thumb carries `aria-labelledby`, form-control `aria-invalid`, and `aria-describedby` for the displayed error (invalid + touched/dirty/submitted), otherwise the hint. Correction/reset restores the hint, including range sliders.
|
|
162
|
+
- Optional `[aria-describedby]` (`string | null`, default `null`) adds consumer-owned IDs before the current message ID, normalized and deduplicated. Keep external elements mounted and reserve `<effectiveId>-error` / `-hint` for the wrapper. Bind the input rather than `[attr.aria-describedby]` on the wrapper host.
|
|
163
|
+
- The `required` asterisk remains visual; configure validators independently. The slider role does not support `aria-required`. `HlmError` is not a live region; automated DOM/focus coverage does not establish screen-reader announcement behavior.
|
|
162
164
|
|
|
163
165
|
## Theming / CSS variables
|
|
164
166
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, input, numberAttribute, computed, Component } from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, ChangeDetectorRef, DestroyRef, input, numberAttribute, 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 { HlmSlider } from '@egose/shadcn-theme-ng-tw/slider';
|
|
8
8
|
import { hlm } from '@egose/shadcn-theme-ng-tw/utils';
|
|
9
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
9
10
|
|
|
10
11
|
const EgFormSliderConfigToken = new InjectionToken('EgFormSliderConfig');
|
|
11
12
|
function provideEgFormSliderConfig(config) {
|
|
@@ -21,6 +22,14 @@ class EgFormSlider {
|
|
|
21
22
|
generatedId = inject(HlmFormIdGenerator).generate('eg-form-slider');
|
|
22
23
|
_config = injectEgFormSliderConfig();
|
|
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 EgFormSlider {
|
|
|
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 on every thumb. */
|
|
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
|
disabled = input(false, /* @ts-ignore */
|
|
@@ -89,8 +100,10 @@ class EgFormSlider {
|
|
|
89
100
|
effectiveDisabled() {
|
|
90
101
|
return this.disabled() || !!this.formGroupDirective.form.get(this.controlName())?.disabled;
|
|
91
102
|
}
|
|
92
|
-
|
|
93
|
-
|
|
103
|
+
describedBy() {
|
|
104
|
+
const ids = [this.ariaDescribedBy(), this.showError() ? this.errorId() : this.hint() ? this.hintId() : null];
|
|
105
|
+
return [...new Set(ids.filter(Boolean).join(' ').split(/\s+/).filter(Boolean))].join(' ') || null;
|
|
106
|
+
}
|
|
94
107
|
// Styling
|
|
95
108
|
userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
|
|
96
109
|
labelClass = input('', /* @ts-ignore */
|
|
@@ -113,7 +126,7 @@ class EgFormSlider {
|
|
|
113
126
|
$hintClass = computed(() => hlm('tw:mt-0', this._shared.hintClass, this._config.hintClass, this.hintClass()), /* @ts-ignore */
|
|
114
127
|
...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
|
|
115
128
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormSlider, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
116
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormSlider, isStandalone: true, selector: "eg-form-slider", 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", 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 }, sliderClass: { classPropertyName: "sliderClass", publicName: "sliderClass", 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: `
|
|
129
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormSlider, isStandalone: true, selector: "eg-form-slider", 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", 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 }, sliderClass: { classPropertyName: "sliderClass", publicName: "sliderClass", 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: `
|
|
117
130
|
@let lbl = label();
|
|
118
131
|
@let cnm = controlName();
|
|
119
132
|
@let hnt = hint();
|
|
@@ -137,6 +150,7 @@ class EgFormSlider {
|
|
|
137
150
|
[step]="step()"
|
|
138
151
|
[disabled]="effectiveDisabled()"
|
|
139
152
|
[aria-labelledby]="lbl ? labelId() : null"
|
|
153
|
+
[aria-describedby]="describedBy()"
|
|
140
154
|
[class]="$sliderClass()"
|
|
141
155
|
/>
|
|
142
156
|
|
|
@@ -152,7 +166,7 @@ class EgFormSlider {
|
|
|
152
166
|
</hlm-hint>
|
|
153
167
|
}
|
|
154
168
|
</hlm-form-field>
|
|
155
|
-
`, 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: "component", type: HlmSlider, selector: "hlm-slider, brn-slider [hlm]" }] });
|
|
169
|
+
`, 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: "component", type: HlmSlider, selector: "hlm-slider, brn-slider [hlm]", inputs: ["aria-describedby"] }] });
|
|
156
170
|
}
|
|
157
171
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormSlider, decorators: [{
|
|
158
172
|
type: Component,
|
|
@@ -188,6 +202,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
188
202
|
[step]="step()"
|
|
189
203
|
[disabled]="effectiveDisabled()"
|
|
190
204
|
[aria-labelledby]="lbl ? labelId() : null"
|
|
205
|
+
[aria-describedby]="describedBy()"
|
|
191
206
|
[class]="$sliderClass()"
|
|
192
207
|
/>
|
|
193
208
|
|
|
@@ -205,7 +220,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
205
220
|
</hlm-form-field>
|
|
206
221
|
`,
|
|
207
222
|
}]
|
|
208
|
-
}], 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], sliderClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "sliderClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
|
|
223
|
+
}], 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], sliderClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "sliderClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
|
|
209
224
|
|
|
210
225
|
/*
|
|
211
226
|
* Public API Surface of form-slider
|
|
@@ -1,14 +1,17 @@
|
|
|
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
|
import { NumberInput } from '@angular/cdk/coercion';
|
|
5
5
|
|
|
6
|
-
declare class EgFormSlider {
|
|
6
|
+
declare class EgFormSlider implements OnInit {
|
|
7
7
|
private readonly formGroupDirective;
|
|
8
8
|
private readonly _errorMessages;
|
|
9
9
|
private readonly generatedId;
|
|
10
10
|
private readonly _config;
|
|
11
11
|
private readonly _shared;
|
|
12
|
+
private readonly _cdr;
|
|
13
|
+
private readonly _destroyRef;
|
|
14
|
+
ngOnInit(): void;
|
|
12
15
|
label: _angular_core.InputSignal<string | undefined>;
|
|
13
16
|
controlId: _angular_core.InputSignal<string | undefined>;
|
|
14
17
|
controlName: _angular_core.InputSignal<string>;
|
|
@@ -20,6 +23,8 @@ declare class EgFormSlider {
|
|
|
20
23
|
*/
|
|
21
24
|
autoError: _angular_core.InputSignal<boolean>;
|
|
22
25
|
hint: _angular_core.InputSignal<string | undefined>;
|
|
26
|
+
/** Consumer-owned description IDs, merged with the current error and hint IDs on every thumb. */
|
|
27
|
+
ariaDescribedBy: _angular_core.InputSignal<string | null>;
|
|
23
28
|
id: _angular_core.InputSignal<string | undefined>;
|
|
24
29
|
disabled: _angular_core.InputSignal<boolean>;
|
|
25
30
|
required: _angular_core.InputSignal<boolean>;
|
|
@@ -49,6 +54,7 @@ declare class EgFormSlider {
|
|
|
49
54
|
* wrapper-toggle + `control.disable()` cannot clobber CVA state.
|
|
50
55
|
*/
|
|
51
56
|
effectiveDisabled(): boolean;
|
|
57
|
+
protected describedBy(): string | null;
|
|
52
58
|
userClass: _angular_core.InputSignal<ClassValue>;
|
|
53
59
|
labelClass: _angular_core.InputSignal<string>;
|
|
54
60
|
sliderClass: _angular_core.InputSignal<string>;
|
|
@@ -60,7 +66,7 @@ declare class EgFormSlider {
|
|
|
60
66
|
$errorClass: _angular_core.Signal<string>;
|
|
61
67
|
$hintClass: _angular_core.Signal<string>;
|
|
62
68
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<EgFormSlider, never>;
|
|
63
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormSlider, "eg-form-slider", 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; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "labelClass": { "alias": "labelClass"; "required": false; "isSignal": true; }; "sliderClass": { "alias": "sliderClass"; "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<EgFormSlider, "eg-form-slider", 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; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "labelClass": { "alias": "labelClass"; "required": false; "isSignal": true; }; "sliderClass": { "alias": "sliderClass"; "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 EgFormSliderConfig {
|
package/form-toggle/README.md
CHANGED
|
@@ -77,23 +77,24 @@ Selector (from source): `eg-form-toggle` (standalone component, host `tw:w-full`
|
|
|
77
77
|
|
|
78
78
|
Bind `formControlName` on the element; there is no `controlName` input.
|
|
79
79
|
|
|
80
|
-
| Input
|
|
81
|
-
|
|
|
82
|
-
| `label`
|
|
83
|
-
| `error`
|
|
84
|
-
| `autoError`
|
|
85
|
-
| `hint`
|
|
86
|
-
| `
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
| `
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
| `
|
|
80
|
+
| Input | Type | Default | Description |
|
|
81
|
+
| ------------------ | --------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
82
|
+
| `label` | `string \| undefined` | — | Label text beside the toggle (hidden when omitted). |
|
|
83
|
+
| `error` | `string \| undefined` | — | Error text shown when invalid. |
|
|
84
|
+
| `autoError` | `boolean` | `true` | Auto-resolve the message from the control's `ValidationErrors` when `error` is unset. Explicit `error` always wins; `error=""` counts as unset. Global wording via `provideEgFormErrorMessages`. |
|
|
85
|
+
| `hint` | `string \| undefined` | — | Hint text shown otherwise. |
|
|
86
|
+
| `aria-describedby` | `string \| null` | `null` | Consumer-owned description IDs merged with the displayed error or hint on the native button. |
|
|
87
|
+
| `controlId` | `string \| undefined` | — | Explicit id (first priority for `effectiveId`). |
|
|
88
|
+
| `id` | `string \| undefined` | — | Fallback id (second priority). |
|
|
89
|
+
| `disabled` | `boolean` | `false` | Locks interaction (form control stays enabled). |
|
|
90
|
+
| `required` | `boolean` | `false` | Shows a red `*` next to the label. |
|
|
91
|
+
| `variant` | `'default' \| 'outline'` | `'default'` | Toggle variant forwarded to `hlmToggle`. |
|
|
92
|
+
| `size` | `'default' \| 'sm' \| 'lg'` | `'default'` | Toggle size forwarded to `hlmToggle`. |
|
|
93
|
+
| `class` | `ClassValue` | `''` | Extra host classes (base `tw:w-full`). |
|
|
94
|
+
| `toggleClass` | `string` | `''` | Extra toggle-button classes. |
|
|
95
|
+
| `labelClass` | `string` | `''` | Extra label classes. |
|
|
96
|
+
| `errorClass` | `string` | `''` | Extra error classes (base `tw:mt-0`). |
|
|
97
|
+
| `hintClass` | `string` | `''` | Extra hint classes (base `tw:mt-0`). |
|
|
97
98
|
|
|
98
99
|
| Member | Description |
|
|
99
100
|
| -------------------- | ------------------------------------------------------------------------------ |
|
|
@@ -163,7 +164,10 @@ export class ConsentToggleComponent {
|
|
|
163
164
|
## Accessibility notes
|
|
164
165
|
|
|
165
166
|
- Label `for` ↔ button `id` wiring is automatic via `effectiveId` — always pass a `label`.
|
|
166
|
-
- The
|
|
167
|
+
- The actual toggle button exposes `aria-pressed` and references the **currently displayed error or hint** with `aria-describedby`. Touch/dirty-only changes and submission update the description; correction/reset restore the hint when present. Removing a hint removes its reference.
|
|
168
|
+
- Pass consumer-owned IDs with `[aria-describedby]="'notification-help notification-policy'"`. They precede the active wrapper message ID; whitespace is normalized and duplicate IDs are removed. Keep those external elements mounted. `${effectiveId}-error` and `${effectiveId}-hint` are reserved for wrapper messages; do not supply them as consumer IDs.
|
|
169
|
+
- The button exposes `aria-invalid="true"` while its validation error is displayed and removes the attribute when feedback clears. The native label association and pressed state remain independent of validation.
|
|
170
|
+
- The required `*` is visual; configure `Validators.requiredTrue` independently. Toggle buttons do not support `aria-required`.
|
|
167
171
|
|
|
168
172
|
## Theming / CSS variables
|
|
169
173
|
|
|
@@ -53,6 +53,8 @@ class EgFormToggle {
|
|
|
53
53
|
...(ngDevMode ? [{ debugName: "autoError" }] : /* istanbul ignore next */ []));
|
|
54
54
|
hint = input(undefined, /* @ts-ignore */
|
|
55
55
|
...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
|
|
56
|
+
/** Consumer-owned description IDs, merged with the displayed error or hint on the button. */
|
|
57
|
+
ariaDescribedBy = input(null, { ...(ngDevMode ? { debugName: "ariaDescribedBy" } : /* istanbul ignore next */ {}), alias: 'aria-describedby' });
|
|
56
58
|
id = input(undefined, /* @ts-ignore */
|
|
57
59
|
...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
58
60
|
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
@@ -78,12 +80,14 @@ class EgFormToggle {
|
|
|
78
80
|
...(ngDevMode ? [{ debugName: "_status" }] : /* istanbul ignore next */ []));
|
|
79
81
|
_submitted = signal(false, /* @ts-ignore */
|
|
80
82
|
...(ngDevMode ? [{ debugName: "_submitted" }] : /* istanbul ignore next */ []));
|
|
83
|
+
_interacted = signal(false, /* @ts-ignore */
|
|
84
|
+
...(ngDevMode ? [{ debugName: "_interacted" }] : /* istanbul ignore next */ []));
|
|
81
85
|
/**
|
|
82
86
|
* Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
|
|
83
87
|
* auto-resolved from the control's `ValidationErrors`. Plain method (not a
|
|
84
88
|
* computed): `ValidationErrors` is not a signal, so the control must be read
|
|
85
89
|
* fresh on every change-detection pass (`showError()` re-evaluates with it
|
|
86
|
-
* via the `_status`/`_submitted` signals).
|
|
90
|
+
* via the `_status`/`_submitted`/`_interacted` signals).
|
|
87
91
|
*/
|
|
88
92
|
resolvedError() {
|
|
89
93
|
const explicit = this.error();
|
|
@@ -96,20 +100,26 @@ class EgFormToggle {
|
|
|
96
100
|
showError = computed(() => {
|
|
97
101
|
this._status();
|
|
98
102
|
this._submitted();
|
|
103
|
+
this._interacted();
|
|
99
104
|
const control = this._controlDir?.control;
|
|
100
|
-
return
|
|
101
|
-
!!control?.errors &&
|
|
102
|
-
(control.touched || control.dirty || !!this._formGroupDirective?.submitted));
|
|
105
|
+
return !!this.resolvedError() && !!control?.errors && (this._interacted() || this._submitted());
|
|
103
106
|
}, /* @ts-ignore */
|
|
104
107
|
...(ngDevMode ? [{ debugName: "showError" }] : /* istanbul ignore next */ []));
|
|
105
108
|
showHint = computed(() => !this.showError() && !!this.hint(), /* @ts-ignore */
|
|
106
109
|
...(ngDevMode ? [{ debugName: "showHint" }] : /* istanbul ignore next */ []));
|
|
110
|
+
describedBy() {
|
|
111
|
+
const ids = [this.ariaDescribedBy(), this.showError() ? this.errorId() : this.showHint() ? this.hintId() : null];
|
|
112
|
+
return [...new Set(ids.filter(Boolean).join(' ').split(/\s+/).filter(Boolean))].join(' ') || null;
|
|
113
|
+
}
|
|
107
114
|
_onChange;
|
|
108
115
|
_onTouched;
|
|
109
116
|
ngDoCheck() {
|
|
110
117
|
const submitted = !!this._formGroupDirective?.submitted;
|
|
111
118
|
if (this._submitted() !== submitted)
|
|
112
119
|
this._submitted.set(submitted);
|
|
120
|
+
// Keep silent interaction updates (emitEvent: false) visible on the next check too.
|
|
121
|
+
const control = this._controlDir?.control;
|
|
122
|
+
this._interacted.set(!!control && (control.touched || control.dirty));
|
|
113
123
|
}
|
|
114
124
|
ngAfterViewInit() {
|
|
115
125
|
// Resolved here (not earlier): this component IS the value accessor for
|
|
@@ -119,8 +129,11 @@ class EgFormToggle {
|
|
|
119
129
|
this._controlDir = this._injector.get(FormControlName, null, { self: true, optional: true }) ?? null;
|
|
120
130
|
const control = this._controlDir?.control;
|
|
121
131
|
this._status.set(control?.status ?? null);
|
|
122
|
-
|
|
123
|
-
|
|
132
|
+
this._interacted.set(!!control && (control.touched || control.dirty));
|
|
133
|
+
// Touch/dirty/reset events must invalidate feedback even when status stays INVALID.
|
|
134
|
+
control?.events.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => {
|
|
135
|
+
this._status.set(control.status);
|
|
136
|
+
this._interacted.set(control.touched || control.dirty);
|
|
124
137
|
});
|
|
125
138
|
}
|
|
126
139
|
_handleStateChange(state) {
|
|
@@ -167,7 +180,7 @@ class EgFormToggle {
|
|
|
167
180
|
$hintClass = computed(() => hlm('tw:mt-0', this._shared.hintClass, this._config.hintClass, this.hintClass()), /* @ts-ignore */
|
|
168
181
|
...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
|
|
169
182
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormToggle, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
170
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormToggle, isStandalone: true, selector: "eg-form-toggle", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, toggleClass: { classPropertyName: "toggleClass", publicName: "toggleClass", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", 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: [EG_FORM_TOGGLE_VALUE_ACCESSOR, provideIcons({ lucideCheck })], ngImport: i0, template: `
|
|
183
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormToggle, isStandalone: true, selector: "eg-form-toggle", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, toggleClass: { classPropertyName: "toggleClass", publicName: "toggleClass", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", 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: [EG_FORM_TOGGLE_VALUE_ACCESSOR, provideIcons({ lucideCheck })], ngImport: i0, template: `
|
|
171
184
|
@let lbl = label();
|
|
172
185
|
@let rqrd = required();
|
|
173
186
|
|
|
@@ -177,6 +190,8 @@ class EgFormToggle {
|
|
|
177
190
|
hlmToggle
|
|
178
191
|
type="button"
|
|
179
192
|
[id]="effectiveId()"
|
|
193
|
+
[attr.aria-describedby]="describedBy()"
|
|
194
|
+
[attr.aria-invalid]="showError() ? 'true' : null"
|
|
180
195
|
[state]="_state() ? 'on' : 'off'"
|
|
181
196
|
(stateChange)="_handleStateChange($event)"
|
|
182
197
|
[disabled]="_disabled()"
|
|
@@ -231,6 +246,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
231
246
|
hlmToggle
|
|
232
247
|
type="button"
|
|
233
248
|
[id]="effectiveId()"
|
|
249
|
+
[attr.aria-describedby]="describedBy()"
|
|
250
|
+
[attr.aria-invalid]="showError() ? 'true' : null"
|
|
234
251
|
[state]="_state() ? 'on' : 'off'"
|
|
235
252
|
(stateChange)="_handleStateChange($event)"
|
|
236
253
|
[disabled]="_disabled()"
|
|
@@ -264,7 +281,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
264
281
|
</div>
|
|
265
282
|
`,
|
|
266
283
|
}]
|
|
267
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], controlId: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlId", 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], toggleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleClass", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
|
|
284
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], controlId: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlId", 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], toggleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleClass", required: false }] }], labelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelClass", required: false }] }], errorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorClass", required: false }] }], hintClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintClass", required: false }] }] } });
|
|
268
285
|
|
|
269
286
|
/*
|
|
270
287
|
* Public API Surface of form-toggle
|
|
@@ -36,6 +36,8 @@ declare class EgFormToggle implements ControlValueAccessor, AfterViewInit, DoChe
|
|
|
36
36
|
*/
|
|
37
37
|
autoError: _angular_core.InputSignal<boolean>;
|
|
38
38
|
hint: _angular_core.InputSignal<string | undefined>;
|
|
39
|
+
/** Consumer-owned description IDs, merged with the displayed error or hint on the button. */
|
|
40
|
+
ariaDescribedBy: _angular_core.InputSignal<string | null>;
|
|
39
41
|
id: _angular_core.InputSignal<string | undefined>;
|
|
40
42
|
disabled: _angular_core.InputSignalWithTransform<boolean, BooleanInput>;
|
|
41
43
|
required: _angular_core.InputSignal<boolean>;
|
|
@@ -49,16 +51,18 @@ declare class EgFormToggle implements ControlValueAccessor, AfterViewInit, DoChe
|
|
|
49
51
|
protected readonly _disabled: _angular_core.Signal<boolean>;
|
|
50
52
|
private readonly _status;
|
|
51
53
|
private readonly _submitted;
|
|
54
|
+
private readonly _interacted;
|
|
52
55
|
/**
|
|
53
56
|
* Displayed message: explicit `error()` wins; otherwise (when `autoError()`)
|
|
54
57
|
* auto-resolved from the control's `ValidationErrors`. Plain method (not a
|
|
55
58
|
* computed): `ValidationErrors` is not a signal, so the control must be read
|
|
56
59
|
* fresh on every change-detection pass (`showError()` re-evaluates with it
|
|
57
|
-
* via the `_status`/`_submitted` signals).
|
|
60
|
+
* via the `_status`/`_submitted`/`_interacted` signals).
|
|
58
61
|
*/
|
|
59
62
|
protected resolvedError(): string | undefined;
|
|
60
63
|
protected readonly showError: _angular_core.Signal<boolean>;
|
|
61
64
|
protected readonly showHint: _angular_core.Signal<boolean>;
|
|
65
|
+
protected describedBy(): string | null;
|
|
62
66
|
protected _onChange?: ChangeFn<boolean>;
|
|
63
67
|
protected _onTouched?: TouchFn;
|
|
64
68
|
ngDoCheck(): void;
|
|
@@ -80,7 +84,7 @@ declare class EgFormToggle implements ControlValueAccessor, AfterViewInit, DoChe
|
|
|
80
84
|
$errorClass: _angular_core.Signal<string>;
|
|
81
85
|
$hintClass: _angular_core.Signal<string>;
|
|
82
86
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<EgFormToggle, never>;
|
|
83
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormToggle, "eg-form-toggle", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "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; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "toggleClass": { "alias": "toggleClass"; "required": false; "isSignal": true; }; "labelClass": { "alias": "labelClass"; "required": false; "isSignal": true; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
87
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgFormToggle, "eg-form-toggle", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "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; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "toggleClass": { "alias": "toggleClass"; "required": false; "isSignal": true; }; "labelClass": { "alias": "labelClass"; "required": false; "isSignal": true; }; "errorClass": { "alias": "errorClass"; "required": false; "isSignal": true; }; "hintClass": { "alias": "hintClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
84
88
|
}
|
|
85
89
|
|
|
86
90
|
interface EgFormToggleConfig {
|