@ojiepermana/angular-component 22.0.45 → 22.0.46

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.
@@ -83,7 +83,7 @@ class AlertDialogComponent {
83
83
  this.open.set(false);
84
84
  }
85
85
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: AlertDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
86
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: AlertDialogComponent, isStandalone: true, selector: "AlertDialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdropClick: { classPropertyName: "closeOnBackdropClick", publicName: "closeOnBackdropClick", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, closeButtonLabel: { classPropertyName: "closeButtonLabel", publicName: "closeButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, labelledBy: { classPropertyName: "labelledBy", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, describedBy: { classPropertyName: "describedBy", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, radius: { classPropertyName: "radius", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, density: { classPropertyName: "density", publicName: "density", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", openedChange: "openedChange" }, ngImport: i0, template: `
86
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: AlertDialogComponent, isStandalone: true, selector: "AlertDialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdropClick: { classPropertyName: "closeOnBackdropClick", publicName: "closeOnBackdropClick", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, closeButtonLabel: { classPropertyName: "closeButtonLabel", publicName: "closeButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, labelledBy: { classPropertyName: "labelledBy", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, describedBy: { classPropertyName: "describedBy", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, radius: { classPropertyName: "radius", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, density: { classPropertyName: "density", publicName: "density", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", openedChange: "openedChange" }, host: { properties: { "attr.aria-labelledby": "null", "attr.aria-describedby": "null" } }, ngImport: i0, template: `
87
87
  <Dialog
88
88
  [(open)]="open"
89
89
  [role]="role()"
@@ -106,6 +106,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
106
106
  type: Component,
107
107
  args: [{
108
108
  selector: 'AlertDialog',
109
+ // `<AlertDialog>` is a roleless host element; the consumer's
110
+ // aria-labelledby/aria-describedby are re-applied on the inner dialog surface,
111
+ // so strip them from the host (axe `aria-prohibited-attr`).
112
+ host: {
113
+ '[attr.aria-labelledby]': 'null',
114
+ '[attr.aria-describedby]': 'null',
115
+ },
109
116
  imports: [DialogComponent],
110
117
  template: `
111
118
  <Dialog
@@ -23,6 +23,9 @@ class ComboboxComponent {
23
23
  ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
24
24
  placeholder = input('Select…', /* @ts-ignore */
25
25
  ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
26
+ /** Accessible name for the combobox trigger (its text content is the value, not a name). */
27
+ ariaLabel = input(null, { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
28
+ ariaLabelledby = input(null, { ...(ngDevMode ? { debugName: "ariaLabelledby" } : /* istanbul ignore next */ {}), alias: 'aria-labelledby' });
26
29
  searchPlaceholder = input('Search…', /* @ts-ignore */
27
30
  ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
28
31
  emptyText = input('No results found.', /* @ts-ignore */
@@ -119,7 +122,7 @@ class ComboboxComponent {
119
122
  this.cvaDisabled.set(state);
120
123
  }
121
124
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: ComboboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
122
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: ComboboxComponent, isStandalone: true, selector: "Combobox", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", 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 }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", disabled: "disabledChange" }, host: { properties: { "class": "classes()" } }, providers: [
125
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: ComboboxComponent, isStandalone: true, selector: "Combobox", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", 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 }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", disabled: "disabledChange" }, host: { properties: { "class": "classes()" } }, providers: [
123
126
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ComboboxComponent), multi: true },
124
127
  ], viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true, isSignal: true }, { propertyName: "panel", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: `
125
128
  <button
@@ -128,6 +131,8 @@ class ComboboxComponent {
128
131
  [attr.id]="triggerId"
129
132
  role="combobox"
130
133
  aria-haspopup="listbox"
134
+ [attr.aria-label]="ariaLabelledby() ? null : (ariaLabel() ?? placeholder())"
135
+ [attr.aria-labelledby]="ariaLabelledby()"
131
136
  [attr.aria-expanded]="isOpen()"
132
137
  [attr.aria-controls]="isOpen() ? panelId : null"
133
138
  [class]="triggerClasses()"
@@ -189,7 +194,7 @@ class ComboboxComponent {
189
194
  </Command>
190
195
  </div>
191
196
  </ng-template>
192
- `, isInline: true, dependencies: [{ kind: "component", type: CommandComponent, selector: "Command", inputs: ["query", "class"], outputs: ["queryChange"] }, { kind: "component", type: CommandInputComponent, selector: "input[CommandInput]", inputs: ["placeholder", "class"] }, { kind: "component", type: CommandListComponent, selector: "CommandList", inputs: ["class"] }, { kind: "component", type: CommandEmptyComponent, selector: "CommandEmpty", inputs: ["class"] }, { kind: "component", type: CommandGroupComponent, selector: "CommandGroup", inputs: ["heading", "class"] }, { kind: "component", type: CommandItemComponent, selector: "CommandItem, button[CommandItem]", inputs: ["value", "disabled", "class"], outputs: ["selected"] }] });
197
+ `, isInline: true, dependencies: [{ kind: "component", type: CommandComponent, selector: "Command", inputs: ["query", "class"], outputs: ["queryChange"] }, { kind: "component", type: CommandInputComponent, selector: "input[CommandInput]", inputs: ["placeholder", "class"] }, { kind: "component", type: CommandListComponent, selector: "CommandList", inputs: ["class", "aria-label"] }, { kind: "component", type: CommandEmptyComponent, selector: "CommandEmpty", inputs: ["class"] }, { kind: "component", type: CommandGroupComponent, selector: "CommandGroup", inputs: ["heading", "class"] }, { kind: "component", type: CommandItemComponent, selector: "CommandItem, button[CommandItem]", inputs: ["value", "disabled", "class"], outputs: ["selected"] }] });
193
198
  }
194
199
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: ComboboxComponent, decorators: [{
195
200
  type: Component,
@@ -214,6 +219,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
214
219
  [attr.id]="triggerId"
215
220
  role="combobox"
216
221
  aria-haspopup="listbox"
222
+ [attr.aria-label]="ariaLabelledby() ? null : (ariaLabel() ?? placeholder())"
223
+ [attr.aria-labelledby]="ariaLabelledby()"
217
224
  [attr.aria-expanded]="isOpen()"
218
225
  [attr.aria-controls]="isOpen() ? panelId : null"
219
226
  [class]="triggerClasses()"
@@ -277,7 +284,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
277
284
  </ng-template>
278
285
  `,
279
286
  }]
280
- }], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], trigger: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }] } });
287
+ }], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaLabelledby: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], trigger: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }] } });
281
288
 
282
289
  /**
283
290
  * Generated bundle index. Do not edit.
@@ -1,9 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Directive, model, input, signal, computed, forwardRef, Component, inject, ElementRef, output, DestroyRef } from '@angular/core';
3
- import { cn, uniqueId } from '@ojiepermana/angular-component/utils';
3
+ import { uniqueId, cn } from '@ojiepermana/angular-component/utils';
4
4
 
5
5
  /** Base class exposed to children for context lookup. */
6
6
  class CommandContextBase {
7
+ /** Shared id linking the combobox input (aria-controls) to the listbox. */
8
+ listboxId = uniqueId('CommandList');
7
9
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CommandContextBase, deps: [], target: i0.ɵɵFactoryTarget.Directive });
8
10
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: CommandContextBase, isStandalone: true, ngImport: i0 });
9
11
  }
@@ -98,7 +100,7 @@ class CommandInputComponent {
98
100
  }
99
101
  }
100
102
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CommandInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
101
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: CommandInputComponent, isStandalone: true, selector: "input[CommandInput]", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "text", "role": "combobox", "aria-autocomplete": "list", "aria-expanded": "true", "autocomplete": "off" }, listeners: { "input": "onInput($any($event))", "keydown.arrowDown": "onArrow($any($event), 1)", "keydown.arrowUp": "onArrow($any($event), -1)", "keydown.enter": "onEnter($any($event))" }, properties: { "class": "classes()", "attr.aria-activedescendant": "ctx.activeDescendantId()", "value": "ctx.query()", "placeholder": "placeholder()" } }, ngImport: i0, template: ``, isInline: true });
103
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: CommandInputComponent, isStandalone: true, selector: "input[CommandInput]", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "text", "role": "combobox", "aria-autocomplete": "list", "aria-expanded": "true", "autocomplete": "off" }, listeners: { "input": "onInput($any($event))", "keydown.arrowDown": "onArrow($any($event), 1)", "keydown.arrowUp": "onArrow($any($event), -1)", "keydown.enter": "onEnter($any($event))" }, properties: { "class": "classes()", "attr.aria-controls": "ctx.listboxId", "attr.aria-activedescendant": "ctx.activeDescendantId()", "value": "ctx.query()", "placeholder": "placeholder()" } }, ngImport: i0, template: ``, isInline: true });
102
104
  }
103
105
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CommandInputComponent, decorators: [{
104
106
  type: Component,
@@ -110,6 +112,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
110
112
  role: 'combobox',
111
113
  'aria-autocomplete': 'list',
112
114
  'aria-expanded': 'true',
115
+ '[attr.aria-controls]': 'ctx.listboxId',
113
116
  '[attr.aria-activedescendant]': 'ctx.activeDescendantId()',
114
117
  autocomplete: 'off',
115
118
  '[value]': 'ctx.query()',
@@ -123,21 +126,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
123
126
  }]
124
127
  }], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
125
128
  class CommandListComponent {
129
+ ctx = inject(CommandContextBase);
126
130
  class = input('', /* @ts-ignore */
127
131
  ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
132
+ /** Accessible name for the listbox (required on role="listbox"). */
133
+ ariaLabel = input('Suggestions', { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
128
134
  classes = computed(() => cn('max-h-[300px] overflow-y-auto overflow-x-hidden p-1', this.class()), /* @ts-ignore */
129
135
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
130
136
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CommandListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
131
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: CommandListComponent, isStandalone: true, selector: "CommandList", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "listbox" }, properties: { "class": "classes()" } }, ngImport: i0, template: `<ng-content />`, isInline: true });
137
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: CommandListComponent, isStandalone: true, selector: "CommandList", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "listbox" }, properties: { "class": "classes()", "attr.id": "ctx.listboxId", "attr.aria-label": "ariaLabel()" } }, ngImport: i0, template: `<ng-content />`, isInline: true });
132
138
  }
133
139
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CommandListComponent, decorators: [{
134
140
  type: Component,
135
141
  args: [{
136
142
  selector: 'CommandList',
137
- host: { '[class]': 'classes()', role: 'listbox' },
143
+ host: {
144
+ '[class]': 'classes()',
145
+ role: 'listbox',
146
+ '[attr.id]': 'ctx.listboxId',
147
+ '[attr.aria-label]': 'ariaLabel()',
148
+ },
138
149
  template: `<ng-content />`,
139
150
  }]
140
- }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
151
+ }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }] } });
141
152
  class CommandEmptyComponent {
142
153
  ctx = inject(CommandComponent);
143
154
  class = input('', /* @ts-ignore */
@@ -192,13 +203,14 @@ class CommandSeparatorComponent {
192
203
  classes = computed(() => cn('-mx-1 h-px bg-border block', this.class()), /* @ts-ignore */
193
204
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
194
205
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CommandSeparatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
195
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: CommandSeparatorComponent, isStandalone: true, selector: "CommandSeparator", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "separator" }, properties: { "class": "classes()" } }, ngImport: i0, template: '', isInline: true });
206
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: CommandSeparatorComponent, isStandalone: true, selector: "CommandSeparator", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, properties: { "class": "classes()" } }, ngImport: i0, template: '', isInline: true });
196
207
  }
197
208
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: CommandSeparatorComponent, decorators: [{
198
209
  type: Component,
199
210
  args: [{
200
211
  selector: 'CommandSeparator',
201
- host: { '[class]': 'classes()', role: 'separator' },
212
+ // Decorative divider a separator is not an allowed child of role="listbox".
213
+ host: { '[class]': 'classes()', 'aria-hidden': 'true' },
202
214
  template: '',
203
215
  }]
204
216
  }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
@@ -9,16 +9,26 @@ import { NgControl } from '@angular/forms';
9
9
  */
10
10
  class FormFieldContext {
11
11
  controlId = uniqueId('FormField');
12
+ labelId = `${this.controlId}-label`;
12
13
  descriptionId = `${this.controlId}-description`;
13
14
  messageId = `${this.controlId}-message`;
14
15
  control = signal(null, /* @ts-ignore */
15
16
  ...(ngDevMode ? [{ debugName: "control" }] : /* istanbul ignore next */ []));
16
17
  manualInvalid = signal(false, /* @ts-ignore */
17
18
  ...(ngDevMode ? [{ debugName: "manualInvalid" }] : /* istanbul ignore next */ []));
19
+ hasLabel = signal(false, /* @ts-ignore */
20
+ ...(ngDevMode ? [{ debugName: "hasLabel" }] : /* istanbul ignore next */ []));
18
21
  hasDescription = signal(false, /* @ts-ignore */
19
22
  ...(ngDevMode ? [{ debugName: "hasDescription" }] : /* istanbul ignore next */ []));
20
23
  hasMessage = signal(false, /* @ts-ignore */
21
24
  ...(ngDevMode ? [{ debugName: "hasMessage" }] : /* istanbul ignore next */ []));
25
+ /**
26
+ * `aria-labelledby` for the control. `<FormLabel>` renders as a custom element,
27
+ * so the native `for`/`id` pairing does not associate it — point the control at
28
+ * the label's id explicitly so it has an accessible name (axe `select-name`/`label`).
29
+ */
30
+ labelledBy = computed(() => (this.hasLabel() ? this.labelId : null), /* @ts-ignore */
31
+ ...(ngDevMode ? [{ debugName: "labelledBy" }] : /* istanbul ignore next */ []));
22
32
  statusTick = signal(0, /* @ts-ignore */
23
33
  ...(ngDevMode ? [{ debugName: "statusTick" }] : /* istanbul ignore next */ []));
24
34
  invalid = computed(() => {
@@ -222,10 +232,14 @@ class FormLabelComponent {
222
232
  ctx = inject(FormFieldContext);
223
233
  class = input('', /* @ts-ignore */
224
234
  ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
235
+ constructor() {
236
+ // Let the control reference this label via aria-labelledby.
237
+ this.ctx.hasLabel.set(true);
238
+ }
225
239
  classes = computed(() => cn('text-sm font-medium leading-none', this.ctx.invalid() ? 'text-destructive' : 'text-foreground', 'peer-disabled:cursor-not-allowed peer-disabled:opacity-70', this.class()), /* @ts-ignore */
226
240
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
227
241
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: FormLabelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
228
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: FormLabelComponent, isStandalone: true, selector: "FormLabel, label[FormLabel]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.for": "ctx.controlId" } }, ngImport: i0, template: `<ng-content />`, isInline: true });
242
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: FormLabelComponent, isStandalone: true, selector: "FormLabel, label[FormLabel]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.id": "ctx.labelId", "attr.for": "ctx.controlId" } }, ngImport: i0, template: `<ng-content />`, isInline: true });
229
243
  }
230
244
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: FormLabelComponent, decorators: [{
231
245
  type: Component,
@@ -233,11 +247,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
233
247
  selector: 'FormLabel, label[FormLabel]',
234
248
  host: {
235
249
  '[class]': 'classes()',
250
+ '[attr.id]': 'ctx.labelId',
236
251
  '[attr.for]': 'ctx.controlId',
237
252
  },
238
253
  template: `<ng-content />`,
239
254
  }]
240
- }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
255
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
241
256
 
242
257
  class FormDescriptionComponent {
243
258
  ctx = inject(FormFieldContext, { optional: true });
@@ -334,7 +349,7 @@ class FormControlDirective {
334
349
  }
335
350
  }
336
351
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: FormControlDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
337
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: FormControlDirective, isStandalone: true, selector: "[FormControl]", host: { properties: { "attr.id": "ctx.controlId", "attr.aria-describedby": "ctx.describedBy()", "attr.aria-invalid": "ctx.invalid() ? \"true\" : null" } }, ngImport: i0 });
352
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: FormControlDirective, isStandalone: true, selector: "[FormControl]", host: { properties: { "attr.id": "ctx.controlId", "attr.aria-labelledby": "ctx.labelledBy()", "attr.aria-describedby": "ctx.describedBy()", "attr.aria-invalid": "ctx.invalid() ? \"true\" : null" } }, ngImport: i0 });
338
353
  }
339
354
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: FormControlDirective, decorators: [{
340
355
  type: Directive,
@@ -342,6 +357,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
342
357
  selector: '[FormControl]',
343
358
  host: {
344
359
  '[attr.id]': 'ctx.controlId',
360
+ '[attr.aria-labelledby]': 'ctx.labelledBy()',
345
361
  '[attr.aria-describedby]': 'ctx.describedBy()',
346
362
  '[attr.aria-invalid]': 'ctx.invalid() ? "true" : null',
347
363
  },
@@ -529,6 +529,8 @@ class PillboxComponent extends PillboxContext {
529
529
  <input
530
530
  #inlineSearch
531
531
  class="min-w-28 flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed"
532
+ [attr.aria-label]="ariaLabel() ?? placeholder()"
533
+ [attr.aria-labelledby]="ariaLabelledby()"
532
534
  [placeholder]="selectedItems().length === 0 ? placeholder() : ''"
533
535
  [value]="query()"
534
536
  [disabled]="disabledState() || null"
@@ -601,6 +603,7 @@ class PillboxComponent extends PillboxContext {
601
603
  <input
602
604
  #panelSearch
603
605
  class="h-9 min-w-0 flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
606
+ [attr.aria-label]="searchPlaceholder()"
604
607
  [placeholder]="searchPlaceholder()"
605
608
  [value]="query()"
606
609
  (input)="handleSearchInput($event)"
@@ -715,6 +718,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
715
718
  <input
716
719
  #inlineSearch
717
720
  class="min-w-28 flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed"
721
+ [attr.aria-label]="ariaLabel() ?? placeholder()"
722
+ [attr.aria-labelledby]="ariaLabelledby()"
718
723
  [placeholder]="selectedItems().length === 0 ? placeholder() : ''"
719
724
  [value]="query()"
720
725
  [disabled]="disabledState() || null"
@@ -787,6 +792,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
787
792
  <input
788
793
  #panelSearch
789
794
  class="h-9 min-w-0 flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
795
+ [attr.aria-label]="searchPlaceholder()"
790
796
  [placeholder]="searchPlaceholder()"
791
797
  [value]="query()"
792
798
  (input)="handleSearchInput($event)"
@@ -97,6 +97,9 @@ class RadioComponent {
97
97
  ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
98
98
  class = input('', /* @ts-ignore */
99
99
  ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
100
+ /** Accessible name for the radio input when no text is projected into `<Radio>`. */
101
+ ariaLabel = input(null, { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
102
+ ariaLabelledby = input(null, { ...(ngDevMode ? { debugName: "ariaLabelledby" } : /* istanbul ignore next */ {}), alias: 'aria-labelledby' });
100
103
  selected = computed(() => this.group.value() === this.value(), /* @ts-ignore */
101
104
  ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
102
105
  isDisabled = computed(() => this.disabled() || this.group.disabled(), /* @ts-ignore */
@@ -118,13 +121,15 @@ class RadioComponent {
118
121
  this.ref().nativeElement.focus();
119
122
  }
120
123
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: RadioComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
121
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: RadioComponent, isStandalone: true, selector: "Radio", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, viewQueries: [{ propertyName: "ref", first: true, predicate: ["ref"], descendants: true, isSignal: true }], ngImport: i0, template: `
124
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: RadioComponent, isStandalone: true, selector: "Radio", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, viewQueries: [{ propertyName: "ref", first: true, predicate: ["ref"], descendants: true, isSignal: true }], ngImport: i0, template: `
122
125
  <label [class]="labelClasses()">
123
126
  <input
124
127
  #ref
125
128
  type="radio"
126
129
  class="peer sr-only"
127
130
  [attr.name]="group.resolvedName()"
131
+ [attr.aria-label]="ariaLabel()"
132
+ [attr.aria-labelledby]="ariaLabelledby()"
128
133
  [value]="value()"
129
134
  [checked]="selected()"
130
135
  [disabled]="isDisabled()"
@@ -152,6 +157,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
152
157
  type="radio"
153
158
  class="peer sr-only"
154
159
  [attr.name]="group.resolvedName()"
160
+ [attr.aria-label]="ariaLabel()"
161
+ [attr.aria-labelledby]="ariaLabelledby()"
155
162
  [value]="value()"
156
163
  [checked]="selected()"
157
164
  [disabled]="isDisabled()"
@@ -167,7 +174,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
167
174
  </label>
168
175
  `,
169
176
  }]
170
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], ref: [{ type: i0.ViewChild, args: ['ref', { isSignal: true }] }] } });
177
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaLabelledby: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }], ref: [{ type: i0.ViewChild, args: ['ref', { isSignal: true }] }] } });
171
178
 
172
179
  /**
173
180
  * Generated bundle index. Do not edit.
@@ -167,7 +167,7 @@ class SheetComponent {
167
167
  return this.host.nativeElement.localName === 'drawer';
168
168
  }
169
169
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: SheetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
170
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: SheetComponent, isStandalone: true, selector: "Sheet, Drawer", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdropClick: { classPropertyName: "closeOnBackdropClick", publicName: "closeOnBackdropClick", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, closeButtonLabel: { classPropertyName: "closeButtonLabel", publicName: "closeButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, labelledBy: { classPropertyName: "labelledBy", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, describedBy: { classPropertyName: "describedBy", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, radius: { classPropertyName: "radius", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, density: { classPropertyName: "density", publicName: "density", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", openedChange: "openedChange" }, viewQueries: [{ propertyName: "tpl", first: true, predicate: ["tpl"], descendants: true, isSignal: true }], ngImport: i0, template: `
170
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: SheetComponent, isStandalone: true, selector: "Sheet, Drawer", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdropClick: { classPropertyName: "closeOnBackdropClick", publicName: "closeOnBackdropClick", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, closeButtonLabel: { classPropertyName: "closeButtonLabel", publicName: "closeButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, labelledBy: { classPropertyName: "labelledBy", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, describedBy: { classPropertyName: "describedBy", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, radius: { classPropertyName: "radius", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, density: { classPropertyName: "density", publicName: "density", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", openedChange: "openedChange" }, host: { properties: { "attr.aria-labelledby": "null", "attr.aria-describedby": "null" } }, viewQueries: [{ propertyName: "tpl", first: true, predicate: ["tpl"], descendants: true, isSignal: true }], ngImport: i0, template: `
171
171
  <ng-template #tpl>
172
172
  <div
173
173
  class="sheet-surface fixed z-50 bg-background shadow-lg transition ease-in-out"
@@ -201,7 +201,10 @@ class SheetComponent {
201
201
  }
202
202
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: SheetComponent, decorators: [{
203
203
  type: Component,
204
- args: [{ selector: 'Sheet, Drawer', imports: [ButtonComponent], template: `
204
+ args: [{ selector: 'Sheet, Drawer', host: {
205
+ '[attr.aria-labelledby]': 'null',
206
+ '[attr.aria-describedby]': 'null',
207
+ }, imports: [ButtonComponent], template: `
205
208
  <ng-template #tpl>
206
209
  <div
207
210
  class="sheet-surface fixed z-50 bg-background shadow-lg transition ease-in-out"
@@ -134,6 +134,7 @@ class TimelineIndicatorComponent {
134
134
  ...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
135
135
  color = input(null, /* @ts-ignore */
136
136
  ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
137
+ ariaLabel = input(null, { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
137
138
  class = input('', /* @ts-ignore */
138
139
  ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
139
140
  resolvedStatus = computed(() => this.status() ?? this.item?.status() ?? 'incomplete', /* @ts-ignore */
@@ -151,7 +152,7 @@ class TimelineIndicatorComponent {
151
152
  }, /* @ts-ignore */
152
153
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
153
154
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TimelineIndicatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
154
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: TimelineIndicatorComponent, isStandalone: true, selector: "TimelineIndicator", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.data-slot": "\"timeline-indicator\"", "attr.data-variant": "variant()", "attr.data-status": "resolvedStatus()", "attr.data-color": "color() ?? null" } }, ngImport: i0, template: `<ng-content />`, isInline: true });
155
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: TimelineIndicatorComponent, isStandalone: true, selector: "TimelineIndicator", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.role": "ariaLabel() ? \"img\" : null", "attr.aria-label": "ariaLabel()", "attr.data-slot": "\"timeline-indicator\"", "attr.data-variant": "variant()", "attr.data-status": "resolvedStatus()", "attr.data-color": "color() ?? null" } }, ngImport: i0, template: `<ng-content />`, isInline: true });
155
156
  }
156
157
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TimelineIndicatorComponent, decorators: [{
157
158
  type: Component,
@@ -159,6 +160,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
159
160
  selector: 'TimelineIndicator',
160
161
  host: {
161
162
  '[class]': 'classes()',
163
+ // A labeled indicator is a status graphic (role="img" so aria-label is valid);
164
+ // without a label it stays a decorative marker.
165
+ '[attr.role]': 'ariaLabel() ? "img" : null',
166
+ '[attr.aria-label]': 'ariaLabel()',
162
167
  '[attr.data-slot]': '"timeline-indicator"',
163
168
  '[attr.data-variant]': 'variant()',
164
169
  '[attr.data-status]': 'resolvedStatus()',
@@ -166,7 +171,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
166
171
  },
167
172
  template: `<ng-content />`,
168
173
  }]
169
- }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
174
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
170
175
  class TimelineContentComponent {
171
176
  item = inject(TimelineItemComponent, { optional: true });
172
177
  class = input('', /* @ts-ignore */
@@ -176,7 +176,7 @@ class ToggleGroupComponent extends ToggleGroupContextBase {
176
176
  this.registrationVersion.update((version) => version + 1);
177
177
  }
178
178
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: ToggleGroupComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
179
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: ToggleGroupComponent, isStandalone: true, selector: "ToggleGroup", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, values: { classPropertyName: "values", publicName: "values", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", 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 }, spacing: { classPropertyName: "spacing", publicName: "spacing", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", values: "valuesChange" }, host: { properties: { "class": "classes()", "attr.role": "\"group\"", "attr.dir": "dir() ?? null", "attr.aria-orientation": "orientation()", "attr.data-disabled": "disabled() ? \"\" : null", "attr.data-orientation": "orientation()", "attr.data-slot": "\"toggle-group\"", "attr.data-type": "type()" } }, providers: [
179
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: ToggleGroupComponent, isStandalone: true, selector: "ToggleGroup", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, values: { classPropertyName: "values", publicName: "values", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", 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 }, spacing: { classPropertyName: "spacing", publicName: "spacing", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", values: "valuesChange" }, host: { properties: { "class": "classes()", "attr.role": "\"group\"", "attr.dir": "dir() ?? null", "attr.data-disabled": "disabled() ? \"\" : null", "attr.data-orientation": "orientation()", "attr.data-slot": "\"toggle-group\"", "attr.data-type": "type()" } }, providers: [
180
180
  { provide: ToggleGroupContextBase, useExisting: forwardRef(() => ToggleGroupComponent) },
181
181
  ], usesInheritance: true, ngImport: i0, template: `<ng-content />`, isInline: true });
182
182
  }
@@ -191,7 +191,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
191
191
  '[class]': 'classes()',
192
192
  '[attr.role]': '"group"',
193
193
  '[attr.dir]': 'dir() ?? null',
194
- '[attr.aria-orientation]': 'orientation()',
194
+ // aria-orientation is not allowed on role="group" (axe aria-allowed-attr);
195
+ // data-orientation below drives the visual layout instead.
195
196
  '[attr.data-disabled]': 'disabled() ? "" : null',
196
197
  '[attr.data-orientation]': 'orientation()',
197
198
  '[attr.data-slot]': '"toggle-group"',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ojiepermana/angular-component",
3
- "version": "22.0.45",
3
+ "version": "22.0.46",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/edsis/angular.git"
@@ -18,6 +18,9 @@ declare class ComboboxComponent<T = unknown> implements ControlValueAccessor {
18
18
  readonly options: _angular_core.InputSignal<readonly ComboboxOption<T>[]>;
19
19
  readonly value: _angular_core.ModelSignal<T | null>;
20
20
  readonly placeholder: _angular_core.InputSignal<string>;
21
+ /** Accessible name for the combobox trigger (its text content is the value, not a name). */
22
+ readonly ariaLabel: _angular_core.InputSignal<string | null>;
23
+ readonly ariaLabelledby: _angular_core.InputSignal<string | null>;
21
24
  readonly searchPlaceholder: _angular_core.InputSignal<string>;
22
25
  readonly emptyText: _angular_core.InputSignal<string>;
23
26
  readonly disabled: _angular_core.ModelSignal<boolean>;
@@ -46,7 +49,7 @@ declare class ComboboxComponent<T = unknown> implements ControlValueAccessor {
46
49
  registerOnTouched(fn: () => void): void;
47
50
  setDisabledState(state: boolean): void;
48
51
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ComboboxComponent<any>, never>;
49
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ComboboxComponent<any>, "Combobox", never, { "options": { "alias": "options"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; "isSignal": true; }; "emptyText": { "alias": "emptyText"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "class": { "alias": "class"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; }, never, never, true, never>;
52
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ComboboxComponent<any>, "Combobox", never, { "options": { "alias": "options"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; "isSignal": true; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; "isSignal": true; }; "emptyText": { "alias": "emptyText"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "class": { "alias": "class"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "disabled": "disabledChange"; }, never, never, true, never>;
50
53
  }
51
54
 
52
55
  export { ComboboxComponent };
@@ -3,6 +3,8 @@ import { model } from '@angular/core';
3
3
 
4
4
  /** Base class exposed to children for context lookup. */
5
5
  declare abstract class CommandContextBase {
6
+ /** Shared id linking the combobox input (aria-controls) to the listbox. */
7
+ readonly listboxId: string;
6
8
  abstract query: ReturnType<typeof model<string>>;
7
9
  abstract matches(text: string): boolean;
8
10
  abstract registerItem(item: CommandItemComponent): void;
@@ -48,10 +50,13 @@ declare class CommandInputComponent {
48
50
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<CommandInputComponent, "input[CommandInput]", never, { "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "class": { "alias": "class"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
49
51
  }
50
52
  declare class CommandListComponent {
53
+ protected readonly ctx: CommandContextBase;
51
54
  readonly class: _angular_core.InputSignal<string>;
55
+ /** Accessible name for the listbox (required on role="listbox"). */
56
+ readonly ariaLabel: _angular_core.InputSignal<string>;
52
57
  protected readonly classes: _angular_core.Signal<string>;
53
58
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<CommandListComponent, never>;
54
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<CommandListComponent, "CommandList", never, { "class": { "alias": "class"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
59
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<CommandListComponent, "CommandList", never, { "class": { "alias": "class"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
55
60
  }
56
61
  declare class CommandEmptyComponent {
57
62
  protected readonly ctx: CommandComponent;
@@ -80,7 +85,7 @@ declare class CommandItemComponent {
80
85
  readonly value: _angular_core.InputSignal<string>;
81
86
  readonly disabled: _angular_core.InputSignal<boolean>;
82
87
  readonly class: _angular_core.InputSignal<string>;
83
- readonly selected: _angular_core.OutputEmitterRef<MouseEvent | KeyboardEvent>;
88
+ readonly selected: _angular_core.OutputEmitterRef<KeyboardEvent | MouseEvent>;
84
89
  readonly active: _angular_core.WritableSignal<boolean>;
85
90
  readonly visible: _angular_core.Signal<boolean>;
86
91
  protected readonly classes: _angular_core.Signal<string>;
@@ -8,12 +8,20 @@ import { AbstractControl } from '@angular/forms';
8
8
  */
9
9
  declare class FormFieldContext {
10
10
  readonly controlId: string;
11
+ readonly labelId: string;
11
12
  readonly descriptionId: string;
12
13
  readonly messageId: string;
13
14
  readonly control: _angular_core.WritableSignal<AbstractControl<any, any, any> | null>;
14
15
  readonly manualInvalid: _angular_core.WritableSignal<boolean>;
16
+ readonly hasLabel: _angular_core.WritableSignal<boolean>;
15
17
  readonly hasDescription: _angular_core.WritableSignal<boolean>;
16
18
  readonly hasMessage: _angular_core.WritableSignal<boolean>;
19
+ /**
20
+ * `aria-labelledby` for the control. `<FormLabel>` renders as a custom element,
21
+ * so the native `for`/`id` pairing does not associate it — point the control at
22
+ * the label's id explicitly so it has an accessible name (axe `select-name`/`label`).
23
+ */
24
+ readonly labelledBy: _angular_core.Signal<string | null>;
17
25
  private readonly statusTick;
18
26
  readonly invalid: _angular_core.Signal<boolean>;
19
27
  readonly firstError: _angular_core.Signal<string | null>;
@@ -84,6 +92,7 @@ declare class FormTitleComponent {
84
92
  declare class FormLabelComponent {
85
93
  protected readonly ctx: FormFieldContext;
86
94
  readonly class: _angular_core.InputSignal<string>;
95
+ constructor();
87
96
  protected readonly classes: _angular_core.Signal<string>;
88
97
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<FormLabelComponent, never>;
89
98
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<FormLabelComponent, "FormLabel, label[FormLabel]", never, { "class": { "alias": "class"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
@@ -41,6 +41,9 @@ declare class RadioComponent {
41
41
  readonly value: _angular_core.InputSignal<string>;
42
42
  readonly disabled: _angular_core.InputSignal<boolean>;
43
43
  readonly class: _angular_core.InputSignal<string>;
44
+ /** Accessible name for the radio input when no text is projected into `<Radio>`. */
45
+ readonly ariaLabel: _angular_core.InputSignal<string | null>;
46
+ readonly ariaLabelledby: _angular_core.InputSignal<string | null>;
44
47
  protected readonly selected: _angular_core.Signal<boolean>;
45
48
  protected readonly isDisabled: _angular_core.Signal<boolean>;
46
49
  protected readonly hostClasses: _angular_core.Signal<string>;
@@ -51,7 +54,7 @@ declare class RadioComponent {
51
54
  protected handleBlur(): void;
52
55
  focus(): void;
53
56
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<RadioComponent, never>;
54
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<RadioComponent, "Radio", never, { "value": { "alias": "value"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "class": { "alias": "class"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
57
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<RadioComponent, "Radio", never, { "value": { "alias": "value"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "class": { "alias": "class"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
55
58
  }
56
59
 
57
60
  export { RadioComponent, RadioGroupComponent };
@@ -32,11 +32,12 @@ declare class TimelineIndicatorComponent {
32
32
  readonly variant: _angular_core.InputSignal<TimelineIndicatorVariant>;
33
33
  readonly status: _angular_core.InputSignal<TimelineStatus | null>;
34
34
  readonly color: _angular_core.InputSignal<TimelineIndicatorColor | null>;
35
+ readonly ariaLabel: _angular_core.InputSignal<string | null>;
35
36
  readonly class: _angular_core.InputSignal<string>;
36
37
  protected readonly resolvedStatus: _angular_core.Signal<TimelineStatus>;
37
38
  protected readonly classes: _angular_core.Signal<string>;
38
39
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TimelineIndicatorComponent, never>;
39
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<TimelineIndicatorComponent, "TimelineIndicator", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "status": { "alias": "status"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "class": { "alias": "class"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
40
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TimelineIndicatorComponent, "TimelineIndicator", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "status": { "alias": "status"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "class": { "alias": "class"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
40
41
  }
41
42
  declare class TimelineContentComponent {
42
43
  private readonly item;