Skip to content

Commit

Permalink
feat(tag): add nxTagIntl provider for i18n (#1246)
Browse files Browse the repository at this point in the history
  • Loading branch information
vt-allianz authored and GitHub Enterprise committed Aug 1, 2024
1 parent 56b12bd commit a4b9ffd
Show file tree
Hide file tree
Showing 11 changed files with 119 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Component, OnInit } from '@angular/core';

import { NxProgressbarComponent } from '@aposin/ng-aquila/progressbar';

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import { TaglistA11yExampleComponent } from './taglist-a11y/taglist-a11y-example
import { TaglistBasicExampleComponent } from './taglist-basic/taglist-basic-example';
import { TaglistDeleteExampleComponent } from './taglist-delete/taglist-delete-example';
import { TaglistFormatterExampleComponent } from './taglist-formatter/taglist-formatter-example';
import { TaglistIntlExampleComponent } from './taglist-intl/taglist-intl-example';
import { TaglistKeywordExampleComponent } from './taglist-keyword/taglist-keyword-example';
import { TaglistObjectsExampleComponent } from './taglist-objects/taglist-objects-example';
import { TaglistOutputExampleComponent } from './taglist-output/taglist-output-example';
import { TaglistReactiveExampleComponent } from './taglist-reactive/taglist-reactive-example';
import { TaglistTemplatedrivenExampleComponent } from './taglist-templatedriven/taglist-templatedriven-example';

const EXAMPLES = [
TaglistIntlExampleComponent,
TaglistExampleComponent,
TaglistA11yExampleComponent,
TaglistBasicExampleComponent,
Expand All @@ -34,6 +36,7 @@ const EXAMPLES = [
export class TaglistExamplesModule {
static components() {
return {
'taglist-intl': TaglistIntlExampleComponent,
taglist: TaglistExampleComponent,
'taglist-a11y': TaglistA11yExampleComponent,
'taglist-basic': TaglistBasicExampleComponent,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<nx-taglist [tags]="tags" [allowTagDeletion]="true"> </nx-taglist>
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ChangeDetectionStrategy, Component, Injectable } from '@angular/core';
import { NxTagIntl, NxTaglistComponent } from '@aposin/ng-aquila/taglist';

@Injectable()
class MyIntl extends NxTagIntl {
deleteAriaLabel = 'Tag löschen';
}

/**
* @title Tag Internationalization Example
*/
@Component({
selector: 'taglist-intl-example',
standalone: true,
imports: [NxTaglistComponent],
templateUrl: './taglist-intl-example.html',
styleUrl: './taglist-intl-example.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: NxTagIntl,
useClass: MyIntl,
},
],
})
export class TaglistIntlExampleComponent {
tags = ['Apples', 'Oranges', 'Bananas', 'Strawberries', 'Melons', 'Lemons'];
}
1 change: 1 addition & 0 deletions projects/ng-aquila/src/taglist/public-api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './tag.component';
export * from './tag-intl';
export * from './taglist.component';
export * from './taglist.module';
16 changes: 16 additions & 0 deletions projects/ng-aquila/src/taglist/tag-intl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({
providedIn: 'root',
})
export class NxTagIntl {
/**
* Stream that emits whenever the labels here are changed. Use this to notify
* components if the labels have changed after initialization.
*/
readonly changes = new Subject<void>();

/** The aria label for the delete button */
deleteAriaLabel = 'Delete tag';
}
2 changes: 1 addition & 1 deletion projects/ng-aquila/src/taglist/tag.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
(keydown.enter)="$event.stopPropagation()"
nxButton="tertiary small"
type="button"
aria-label="delete tag"
[attr.aria-label]="deleteAriaLabel || intl.deleteAriaLabel"
class="nx-tag__close"
(click)="removeHandler($event)"
>
Expand Down
47 changes: 43 additions & 4 deletions projects/ng-aquila/src/taglist/tag.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ENTER } from '@angular/cdk/keycodes';
import { Component, Directive, Type, ViewChild } from '@angular/core';
import { Component, Directive, Injectable, Type, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { dispatchKeyboardEvent } from '../cdk-test-utils';
import { NxTagComponent } from './tag.component';
import { NxTagIntl } from './tag-intl';
import { NxTaglistModule } from './taglist.module';

@Directive({ standalone: true })
Expand All @@ -28,7 +29,7 @@ describe('NxTagComponent', () => {

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [NxTaglistModule, BasicTag, RemovableTag],
imports: [NxTaglistModule, BasicTag, RemovableTag, IntlTag],
}).compileComponents();
}));

Expand Down Expand Up @@ -136,6 +137,24 @@ describe('NxTagComponent', () => {
createTestComponent(BasicTag);
await expectAsync(fixture.nativeElement).toBeAccessible();
});

it('should set aria-label of delete button', () => {
createTestComponent(RemovableTag);
spyOn(tagInstance.removed, 'emit');
const deleteButton = fixture.nativeElement.querySelector('.nx-tag__close');
expect(deleteButton.getAttribute('aria-label')).toBe('Delete tag');

(testInstance as RemovableTag).deleteAriaLabel = 'hello';

fixture.detectChanges();
expect(deleteButton.getAttribute('aria-label')).toBe('hello');
});

it('should override the default intl', () => {
createTestComponent(IntlTag);
const deleteButton = fixture.nativeElement.querySelector('.nx-tag__close');
expect(deleteButton.getAttribute('aria-label')).toBe('Custom delete aria-label');
});
});
});

Expand All @@ -146,9 +165,29 @@ describe('NxTagComponent', () => {
})
class BasicTag extends TagTest {}

@Injectable()
class MyIntl extends NxTagIntl {
deleteAriaLabel = 'Custom delete aria-label';
}

@Component({
template: `<nx-tag value="bar" removable="true"></nx-tag>`,
template: `<nx-tag value="foo" removable="true"></nx-tag>`,
standalone: true,
imports: [NxTaglistModule],
providers: [
{
provide: NxTagIntl,
useClass: MyIntl,
},
],
})
class RemovableTag extends TagTest {}
class IntlTag extends TagTest {}

@Component({
template: `<nx-tag value="bar" removable="true" [deleteAriaLabel]="deleteAriaLabel"></nx-tag>`,
standalone: true,
imports: [NxTaglistModule],
})
class RemovableTag extends TagTest {
deleteAriaLabel = '';
}
24 changes: 22 additions & 2 deletions projects/ng-aquila/src/taglist/tag.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import { FocusMonitor } from '@angular/cdk/a11y';
import { BooleanInput, coerceBooleanProperty, coerceNumberProperty, NumberInput } from '@angular/cdk/coercion';
import { ENTER } from '@angular/cdk/keycodes';
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, OnDestroy, Output } from '@angular/core';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
inject,
Input,
OnDestroy,
Output,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NxButtonModule } from '@aposin/ng-aquila/button';
import { NxIconModule } from '@aposin/ng-aquila/icon';

import { NxTagIntl } from './tag-intl';

@Component({
selector: 'nx-tag',
templateUrl: 'tag.component.html',
Expand Down Expand Up @@ -65,11 +79,17 @@ export class NxTagComponent implements OnDestroy, AfterViewInit {
/** An event is dispatched each time when the tag is removed. */
@Output() readonly removed = new EventEmitter<any>();

@Input() deleteAriaLabel = '';

intl = inject(NxTagIntl);

constructor(
private readonly _cdr: ChangeDetectorRef,
private readonly _elementRef: ElementRef,
private readonly _focusMonitor: FocusMonitor,
) {}
) {
this.intl.changes.pipe(takeUntilDestroyed()).subscribe(() => this._cdr.markForCheck());
}

ngAfterViewInit(): void {
this._focusMonitor.monitor(this._elementRef);
Expand Down
4 changes: 4 additions & 0 deletions projects/ng-aquila/src/taglist/taglist.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ In oder to improve accessibility, please consider **linking a label** to the tag

<!-- example(taglist-a11y) -->

### Internationalization
The provider `NxTagIntl` contains various strings to provide labels for display and screen readers. You have to provide a proper translation for each of your locales.
<!-- example(taglist-intl) -->

#### Keybord navigation

If `allowTagDeletion` is set to `true`, you can remove selected tags using BACKSPACE. If your tags trigger actions on click, these actions will be also triggered on ENTER click.

0 comments on commit a4b9ffd

Please sign in to comment.