semmet-angular 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/package.json +1 -1
- package/src/accordion/files/__name@dasherize__/__name@dasherize__.spec.ts.template +124 -0
- package/src/accordion/index.js +1 -1
- package/src/accordion/index.js.map +1 -1
- package/src/accordion/index.ts +1 -1
- package/src/alert/files/__name@dasherize__/__name@dasherize__.spec.ts.template +27 -0
- package/src/alert/index.js +1 -1
- package/src/alert/index.js.map +1 -1
- package/src/alert/index.ts +1 -1
- package/src/alert-dialog/files/__name@dasherize__/__name@dasherize__.spec.ts.template +66 -0
- package/src/alert-dialog/index.js +1 -1
- package/src/alert-dialog/index.js.map +1 -1
- package/src/alert-dialog/index.ts +1 -1
- package/src/button/files/__name@dasherize__/__name@dasherize__.spec.ts.template +69 -0
- package/src/button/index.js +1 -1
- package/src/button/index.js.map +1 -1
- package/src/button/index.ts +1 -1
- package/src/button-group/files/__name@dasherize__/__name@dasherize__.spec.ts.template +70 -0
- package/src/button-group/index.js +1 -1
- package/src/button-group/index.js.map +1 -1
- package/src/button-group/index.ts +1 -1
- package/src/carousel/files/__name@dasherize__/__name@dasherize__.spec.ts.template +69 -0
- package/src/carousel/index.js +1 -1
- package/src/carousel/index.js.map +1 -1
- package/src/carousel/index.ts +1 -1
- package/src/checkbox/files/__name@dasherize__/__name@dasherize__.spec.ts.template +41 -0
- package/src/checkbox/index.js +1 -1
- package/src/checkbox/index.js.map +1 -1
- package/src/checkbox/index.ts +1 -1
- package/src/close-button/files/__name@dasherize__/__name@dasherize__.spec.ts.template +64 -0
- package/src/close-button/index.js +1 -1
- package/src/close-button/index.js.map +1 -1
- package/src/close-button/index.ts +1 -1
- package/src/combobox/files/__name@dasherize__/__name@dasherize__.spec.ts.template +79 -0
- package/src/combobox/index.js +1 -1
- package/src/combobox/index.js.map +1 -1
- package/src/combobox/index.ts +1 -1
- package/src/dialog/files/__name@dasherize__/__name@dasherize__.spec.ts.template +68 -0
- package/src/dialog/index.js +1 -1
- package/src/dialog/index.js.map +1 -1
- package/src/dialog/index.ts +1 -1
- package/src/disclosure/files/__name@dasherize__/__name@dasherize__.spec.ts.template +67 -0
- package/src/disclosure/index.js +1 -1
- package/src/disclosure/index.js.map +1 -1
- package/src/disclosure/index.ts +1 -1
- package/src/input/files/__name@dasherize__/__name@dasherize__.spec.ts.template +56 -0
- package/src/input/index.js +1 -1
- package/src/input/index.js.map +1 -1
- package/src/input/index.ts +1 -1
- package/src/list-group/files/__name@dasherize__/__name@dasherize__.spec.ts.template +66 -0
- package/src/list-group/index.js +1 -1
- package/src/list-group/index.js.map +1 -1
- package/src/list-group/index.ts +1 -1
- package/src/listbox/files/__name@dasherize__/__name@dasherize__.spec.ts.template +50 -0
- package/src/listbox/index.js +1 -1
- package/src/listbox/index.js.map +1 -1
- package/src/listbox/index.ts +1 -1
- package/src/menu-button/files/__name@dasherize__/__name@dasherize__.spec.ts.template +64 -0
- package/src/menu-button/index.js +1 -1
- package/src/menu-button/index.js.map +1 -1
- package/src/menu-button/index.ts +1 -1
- package/src/navbar/files/__name@dasherize__/__name@dasherize__.spec.ts.template +74 -0
- package/src/navbar/index.js +1 -1
- package/src/navbar/index.js.map +1 -1
- package/src/navbar/index.ts +1 -1
- package/src/navigation-menu/files/__name@dasherize__/__name@dasherize__.spec.ts.template +51 -0
- package/src/navigation-menu/index.js +1 -1
- package/src/navigation-menu/index.js.map +1 -1
- package/src/navigation-menu/index.ts +1 -1
- package/src/offcanvas/files/__name@dasherize__/__name@dasherize__.spec.ts.template +70 -0
- package/src/offcanvas/index.js +1 -1
- package/src/offcanvas/index.js.map +1 -1
- package/src/offcanvas/index.ts +1 -1
- package/src/pagination/files/__name@dasherize__/__name@dasherize__.spec.ts.template +41 -0
- package/src/pagination/index.js +1 -1
- package/src/pagination/index.js.map +1 -1
- package/src/pagination/index.ts +1 -1
- package/src/popover/files/__name@dasherize__/__name@dasherize__.spec.ts.template +69 -0
- package/src/popover/index.js +1 -1
- package/src/popover/index.js.map +1 -1
- package/src/popover/index.ts +1 -1
- package/src/radio-group/files/__name@dasherize__/__name@dasherize__.spec.ts.template +47 -0
- package/src/radio-group/index.js +1 -1
- package/src/radio-group/index.js.map +1 -1
- package/src/radio-group/index.ts +1 -1
- package/src/select/files/__name@dasherize__/__name@dasherize__.spec.ts.template +54 -0
- package/src/select/index.js +1 -1
- package/src/select/index.js.map +1 -1
- package/src/select/index.ts +1 -1
- package/src/slider/files/__name@dasherize__/__name@dasherize__.spec.ts.template +61 -0
- package/src/slider/index.js +1 -1
- package/src/slider/index.js.map +1 -1
- package/src/slider/index.ts +1 -1
- package/src/spinbutton/files/__name@dasherize__/__name@dasherize__.spec.ts.template +74 -0
- package/src/spinbutton/index.js +1 -1
- package/src/spinbutton/index.js.map +1 -1
- package/src/spinbutton/index.ts +1 -1
- package/src/switch/files/__name@dasherize__/__name@dasherize__.spec.ts.template +35 -0
- package/src/switch/index.js +1 -1
- package/src/switch/index.js.map +1 -1
- package/src/switch/index.ts +1 -1
- package/src/tabs/files/__name@dasherize__/__name@dasherize__.spec.ts.template +113 -0
- package/src/tabs/index.js +1 -1
- package/src/tabs/index.js.map +1 -1
- package/src/tabs/index.ts +1 -1
- package/src/textarea/files/__name@dasherize__/__name@dasherize__.spec.ts.template +59 -0
- package/src/textarea/index.js +1 -1
- package/src/textarea/index.js.map +1 -1
- package/src/textarea/index.ts +1 -1
- package/src/toast/files/__name@dasherize__/__name@dasherize__.spec.ts.template +48 -0
- package/src/toast/index.js +1 -1
- package/src/toast/index.js.map +1 -1
- package/src/toast/index.ts +1 -1
- package/src/toolbar/files/__name@dasherize__/__name@dasherize__.spec.ts.template +45 -0
- package/src/toolbar/index.js +1 -1
- package/src/toolbar/index.js.map +1 -1
- package/src/toolbar/index.ts +1 -1
- package/src/tooltip/files/__name@dasherize__/__name@dasherize__.spec.ts.template +56 -0
- package/src/tooltip/index.js +1 -1
- package/src/tooltip/index.js.map +1 -1
- package/src/tooltip/index.ts +1 -1
- package/src/tree-view/files/__name@dasherize__/__name@dasherize__.spec.ts.template +84 -0
- package/src/tree-view/index.js +1 -1
- package/src/tree-view/index.js.map +1 -1
- package/src/tree-view/index.ts +1 -1
- package/src/utils/component-test-files/__name@dasherize__/__name@dasherize__.spec.ts.template +15 -1
- package/src/utils/generate-component.d.ts +6 -1
- package/src/utils/generate-component.js +21 -6
- package/src/utils/generate-component.js.map +1 -1
- package/src/utils/generate-component.ts +28 -7
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
+
|
|
4
|
+
import { <%= classify(name) %> } from './<%= dasherize(name) %>';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
imports: [<%= classify(name) %>],
|
|
8
|
+
template: `
|
|
9
|
+
<<%= selector %>
|
|
10
|
+
label="Close dialog"
|
|
11
|
+
variant="inverse"
|
|
12
|
+
size="lg"
|
|
13
|
+
[disabled]="disabled"
|
|
14
|
+
(buttonClick)="clickCount = clickCount + 1"
|
|
15
|
+
/>
|
|
16
|
+
`,
|
|
17
|
+
})
|
|
18
|
+
class HostComponent {
|
|
19
|
+
disabled = false;
|
|
20
|
+
clickCount = 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('<%= classify(name) %>', () => {
|
|
24
|
+
let fixture: ComponentFixture<HostComponent>;
|
|
25
|
+
let host: HTMLElement;
|
|
26
|
+
|
|
27
|
+
beforeEach(async () => {
|
|
28
|
+
await TestBed.configureTestingModule({
|
|
29
|
+
imports: [HostComponent],
|
|
30
|
+
}).compileComponents();
|
|
31
|
+
|
|
32
|
+
fixture = TestBed.createComponent(HostComponent);
|
|
33
|
+
fixture.detectChanges();
|
|
34
|
+
host = fixture.nativeElement as HTMLElement;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('renders a native close button with accessible name and visual variants', () => {
|
|
38
|
+
const button = host.querySelector<HTMLButtonElement>('button');
|
|
39
|
+
const icon = host.querySelector<HTMLElement>('.semmet-close-button__icon');
|
|
40
|
+
|
|
41
|
+
expect(button?.type).toBe('button');
|
|
42
|
+
expect(button?.getAttribute('aria-label')).toBe('Close dialog');
|
|
43
|
+
expect(button?.classList.contains('semmet-close-button--inverse')).toBe(true);
|
|
44
|
+
expect(button?.classList.contains('semmet-close-button--lg')).toBe(true);
|
|
45
|
+
expect(icon?.getAttribute('aria-hidden')).toBe('true');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('emits buttonClick only when enabled', () => {
|
|
49
|
+
const component = fixture.componentInstance;
|
|
50
|
+
const button = host.querySelector<HTMLButtonElement>('button');
|
|
51
|
+
|
|
52
|
+
button?.click();
|
|
53
|
+
fixture.detectChanges();
|
|
54
|
+
expect(component.clickCount).toBe(1);
|
|
55
|
+
|
|
56
|
+
component.disabled = true;
|
|
57
|
+
fixture.detectChanges();
|
|
58
|
+
|
|
59
|
+
button?.click();
|
|
60
|
+
fixture.detectChanges();
|
|
61
|
+
expect(component.clickCount).toBe(1);
|
|
62
|
+
expect(button?.disabled).toBe(true);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.closeButton = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.closeButton = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.closeButton = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,WAAW,GAAG,IAAA,iDAA4B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,WAAW,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
+
import { By } from '@angular/platform-browser';
|
|
4
|
+
|
|
5
|
+
import { <%= classify(name) %> } from './<%= dasherize(name) %>';
|
|
6
|
+
|
|
7
|
+
@Component({
|
|
8
|
+
imports: [<%= classify(name) %>],
|
|
9
|
+
template: `<<%= selector %> />`,
|
|
10
|
+
})
|
|
11
|
+
class HostComponent {}
|
|
12
|
+
|
|
13
|
+
describe('<%= classify(name) %>', () => {
|
|
14
|
+
let fixture: ComponentFixture<HostComponent>;
|
|
15
|
+
let host: HTMLElement;
|
|
16
|
+
|
|
17
|
+
beforeEach(async () => {
|
|
18
|
+
await TestBed.configureTestingModule({
|
|
19
|
+
imports: [HostComponent],
|
|
20
|
+
}).compileComponents();
|
|
21
|
+
|
|
22
|
+
fixture = TestBed.createComponent(HostComponent);
|
|
23
|
+
fixture.detectChanges();
|
|
24
|
+
host = fixture.nativeElement as HTMLElement;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('renders the combobox with label and collapsed popup wiring', () => {
|
|
28
|
+
const input = host.querySelector<HTMLInputElement>('[role="combobox"]');
|
|
29
|
+
const listbox = host.querySelector<HTMLElement>('[role="listbox"]');
|
|
30
|
+
|
|
31
|
+
expect(input).toBeTruthy();
|
|
32
|
+
expect(input?.getAttribute('aria-autocomplete')).toBe('list');
|
|
33
|
+
expect(input?.getAttribute('aria-expanded')).toBe('false');
|
|
34
|
+
expect(input?.getAttribute('aria-controls')).toBe(listbox?.id);
|
|
35
|
+
expect(input?.getAttribute('aria-labelledby')).toBeTruthy();
|
|
36
|
+
expect(listbox?.hidden).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('filters options from user input and opens the listbox', () => {
|
|
40
|
+
const inputDebug = fixture.debugElement.query(By.css('[role="combobox"]'));
|
|
41
|
+
const input = inputDebug.nativeElement as HTMLInputElement;
|
|
42
|
+
|
|
43
|
+
input.value = 'ba';
|
|
44
|
+
inputDebug.triggerEventHandler('input', { target: input });
|
|
45
|
+
fixture.detectChanges();
|
|
46
|
+
|
|
47
|
+
const options = Array.from(host.querySelectorAll<HTMLElement>('[role="option"]'));
|
|
48
|
+
const listbox = host.querySelector<HTMLElement>('[role="listbox"]');
|
|
49
|
+
|
|
50
|
+
expect(input.value).toBe('ba');
|
|
51
|
+
expect(listbox?.hidden).toBe(false);
|
|
52
|
+
expect(options.map((option) => option.textContent?.trim())).toEqual(['Banana']);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('moves active option with the keyboard and selects it with Enter', () => {
|
|
56
|
+
const inputDebug = fixture.debugElement.query(By.css('[role="combobox"]'));
|
|
57
|
+
const input = inputDebug.nativeElement as HTMLInputElement;
|
|
58
|
+
|
|
59
|
+
inputDebug.triggerEventHandler('keydown', new KeyboardEvent('keydown', { key: 'ArrowDown' }));
|
|
60
|
+
fixture.detectChanges();
|
|
61
|
+
|
|
62
|
+
let activeOption = host.querySelector<HTMLElement>('[role="option"][aria-selected="true"]');
|
|
63
|
+
expect(input.getAttribute('aria-activedescendant')).toBe(activeOption?.id);
|
|
64
|
+
expect(activeOption?.textContent?.trim()).toBe('Apple');
|
|
65
|
+
|
|
66
|
+
inputDebug.triggerEventHandler('keydown', new KeyboardEvent('keydown', { key: 'ArrowDown' }));
|
|
67
|
+
fixture.detectChanges();
|
|
68
|
+
|
|
69
|
+
activeOption = host.querySelector<HTMLElement>('[role="option"][aria-selected="true"]');
|
|
70
|
+
expect(activeOption?.textContent?.trim()).toBe('Banana');
|
|
71
|
+
|
|
72
|
+
inputDebug.triggerEventHandler('keydown', new KeyboardEvent('keydown', { key: 'Enter' }));
|
|
73
|
+
fixture.detectChanges();
|
|
74
|
+
|
|
75
|
+
const listbox = host.querySelector<HTMLElement>('[role="listbox"]');
|
|
76
|
+
expect(input.value).toBe('Banana');
|
|
77
|
+
expect(listbox?.hidden).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
});
|
package/src/combobox/index.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.combobox = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.combobox = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.combobox = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,QAAQ,GAAG,IAAA,iDAA4B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,QAAQ,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
|
package/src/combobox/index.ts
CHANGED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
import { <%= classify(name) %> } from './<%= dasherize(name) %>';
|
|
3
|
+
|
|
4
|
+
describe('<%= classify(name) %>', () => {
|
|
5
|
+
let fixture: ComponentFixture<<%= classify(name) %>>;
|
|
6
|
+
|
|
7
|
+
beforeEach(async () => {
|
|
8
|
+
await TestBed.configureTestingModule({
|
|
9
|
+
imports: [<%= classify(name) %>],
|
|
10
|
+
}).compileComponents();
|
|
11
|
+
|
|
12
|
+
fixture = TestBed.createComponent(<%= classify(name) %>);
|
|
13
|
+
fixture.detectChanges();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
function openButton(): HTMLButtonElement {
|
|
17
|
+
return fixture.nativeElement.querySelector('button');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function dialog(): HTMLElement | null {
|
|
21
|
+
return fixture.nativeElement.querySelector('[role="dialog"]');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
it('starts closed with an opening trigger', () => {
|
|
25
|
+
expect(openButton().textContent?.trim()).toBe('Open dialog');
|
|
26
|
+
expect(dialog()).toBeNull();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('opens a modal dialog with labelled title', () => {
|
|
30
|
+
openButton().click();
|
|
31
|
+
fixture.detectChanges();
|
|
32
|
+
|
|
33
|
+
const element = dialog();
|
|
34
|
+
const title = fixture.nativeElement.querySelector('h2');
|
|
35
|
+
|
|
36
|
+
expect(element).toBeTruthy();
|
|
37
|
+
expect(element?.getAttribute('aria-modal')).toBe('true');
|
|
38
|
+
expect(element?.getAttribute('aria-labelledby')).toBe(title.id);
|
|
39
|
+
expect(element?.getAttribute('tabindex')).toBe('-1');
|
|
40
|
+
expect(title.textContent?.trim()).toBe('Dialog title');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('closes with the close button and restores focus to the trigger', () => {
|
|
44
|
+
const trigger = openButton();
|
|
45
|
+
trigger.focus();
|
|
46
|
+
trigger.click();
|
|
47
|
+
fixture.detectChanges();
|
|
48
|
+
|
|
49
|
+
const closeButton = Array.from(fixture.nativeElement.querySelectorAll('button')).at(-1) as HTMLButtonElement;
|
|
50
|
+
closeButton.click();
|
|
51
|
+
fixture.detectChanges();
|
|
52
|
+
|
|
53
|
+
expect(dialog()).toBeNull();
|
|
54
|
+
expect(document.activeElement).toBe(trigger);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('closes with Escape from inside the dialog', () => {
|
|
58
|
+
const trigger = openButton();
|
|
59
|
+
trigger.click();
|
|
60
|
+
fixture.detectChanges();
|
|
61
|
+
|
|
62
|
+
dialog()?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
63
|
+
fixture.detectChanges();
|
|
64
|
+
|
|
65
|
+
expect(dialog()).toBeNull();
|
|
66
|
+
expect(document.activeElement).toBe(trigger);
|
|
67
|
+
});
|
|
68
|
+
});
|
package/src/dialog/index.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.dialog = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.dialog = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.dialog = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/src/dialog/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,MAAM,GAAG,IAAA,iDAA4B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,MAAM,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
|
package/src/dialog/index.ts
CHANGED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
+
import { <%= classify(name) %>, <%= classify(name) %>Content } from './<%= dasherize(name) %>';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
imports: [<%= classify(name) %>, <%= classify(name) %>Content],
|
|
7
|
+
template: `
|
|
8
|
+
<<%= selector %> label="Show profile details" [(expanded)]="expanded" [preserveContent]="preserveContent">
|
|
9
|
+
<ng-template <%= camelize(name) %>Content>
|
|
10
|
+
<p>Profile details</p>
|
|
11
|
+
</ng-template>
|
|
12
|
+
</<%= selector %>>
|
|
13
|
+
`,
|
|
14
|
+
})
|
|
15
|
+
class HostComponent {
|
|
16
|
+
expanded = false;
|
|
17
|
+
preserveContent = true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('<%= classify(name) %>', () => {
|
|
21
|
+
let fixture: ComponentFixture<HostComponent>;
|
|
22
|
+
|
|
23
|
+
beforeEach(async () => {
|
|
24
|
+
await TestBed.configureTestingModule({
|
|
25
|
+
imports: [HostComponent],
|
|
26
|
+
}).compileComponents();
|
|
27
|
+
|
|
28
|
+
fixture = TestBed.createComponent(HostComponent);
|
|
29
|
+
fixture.detectChanges();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
function button(): HTMLButtonElement {
|
|
33
|
+
return fixture.nativeElement.querySelector('button');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function panel(): HTMLElement {
|
|
37
|
+
return fixture.nativeElement.querySelector('div');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
it('renders button and panel with ARIA relationships', () => {
|
|
41
|
+
expect(button().textContent?.trim()).toBe('Show profile details');
|
|
42
|
+
expect(button().getAttribute('aria-expanded')).toBe('false');
|
|
43
|
+
expect(button().getAttribute('aria-controls')).toBe(panel().id);
|
|
44
|
+
expect(panel().getAttribute('aria-labelledby')).toBe(button().id);
|
|
45
|
+
expect(panel().hidden).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('toggles expanded state from the trigger button', () => {
|
|
49
|
+
button().click();
|
|
50
|
+
fixture.detectChanges();
|
|
51
|
+
|
|
52
|
+
expect(fixture.componentInstance.expanded).toBe(true);
|
|
53
|
+
expect(button().getAttribute('aria-expanded')).toBe('true');
|
|
54
|
+
expect(panel().hidden).toBe(false);
|
|
55
|
+
expect(panel().textContent).toContain('Profile details');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('preserves content after first render when preserveContent is enabled', () => {
|
|
59
|
+
button().click();
|
|
60
|
+
fixture.detectChanges();
|
|
61
|
+
button().click();
|
|
62
|
+
fixture.detectChanges();
|
|
63
|
+
|
|
64
|
+
expect(panel().hidden).toBe(true);
|
|
65
|
+
expect(panel().textContent).toContain('Profile details');
|
|
66
|
+
});
|
|
67
|
+
});
|
package/src/disclosure/index.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.disclosure = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.disclosure = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.disclosure = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,UAAU,GAAG,IAAA,iDAA4B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,UAAU,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
|
package/src/disclosure/index.ts
CHANGED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
+
import { <%= classify(name) %> } from './<%= dasherize(name) %>';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
imports: [<%= classify(name) %>],
|
|
7
|
+
template: `
|
|
8
|
+
<<%= selector %>
|
|
9
|
+
label="Work email"
|
|
10
|
+
hint="Use your company address."
|
|
11
|
+
error="Email is required."
|
|
12
|
+
[required]="true"
|
|
13
|
+
[(value)]="email"
|
|
14
|
+
/>
|
|
15
|
+
`,
|
|
16
|
+
})
|
|
17
|
+
class HostComponent {
|
|
18
|
+
email = '';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('<%= classify(name) %>', () => {
|
|
22
|
+
let fixture: ComponentFixture<HostComponent>;
|
|
23
|
+
|
|
24
|
+
beforeEach(async () => {
|
|
25
|
+
await TestBed.configureTestingModule({ imports: [HostComponent] }).compileComponents();
|
|
26
|
+
fixture = TestBed.createComponent(HostComponent);
|
|
27
|
+
fixture.detectChanges();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
function input(): HTMLInputElement {
|
|
31
|
+
return fixture.nativeElement.querySelector('input');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
it('wires label, required state, hint, and error message', () => {
|
|
35
|
+
const label = fixture.nativeElement.querySelector('label');
|
|
36
|
+
const hint = fixture.nativeElement.querySelector('.semmet-field__hint');
|
|
37
|
+
const error = fixture.nativeElement.querySelector('.semmet-field__error');
|
|
38
|
+
|
|
39
|
+
expect(label.textContent).toContain('Work email');
|
|
40
|
+
expect(label.getAttribute('for')).toBe(input().id);
|
|
41
|
+
expect(input().required).toBe(true);
|
|
42
|
+
expect(input().getAttribute('aria-required')).toBe('true');
|
|
43
|
+
expect(input().getAttribute('aria-invalid')).toBe('true');
|
|
44
|
+
expect(input().getAttribute('aria-describedby')).toContain(hint.id);
|
|
45
|
+
expect(input().getAttribute('aria-describedby')).toContain(error.id);
|
|
46
|
+
expect(error.getAttribute('role')).toBe('alert');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('updates the bound value on input', () => {
|
|
50
|
+
input().value = 'team@example.com';
|
|
51
|
+
input().dispatchEvent(new Event('input', { bubbles: true }));
|
|
52
|
+
fixture.detectChanges();
|
|
53
|
+
|
|
54
|
+
expect(fixture.componentInstance.email).toBe('team@example.com');
|
|
55
|
+
});
|
|
56
|
+
});
|
package/src/input/index.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.input = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.input = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.input = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/src/input/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,KAAK,GAAG,IAAA,iDAA4B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,KAAK,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
|
package/src/input/index.ts
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
+
|
|
4
|
+
import { <%= classify(name) %> } from './<%= dasherize(name) %>';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
imports: [<%= classify(name) %>],
|
|
8
|
+
template: `
|
|
9
|
+
<<%= selector %>
|
|
10
|
+
label="Account sections"
|
|
11
|
+
[items]="items"
|
|
12
|
+
/>
|
|
13
|
+
`,
|
|
14
|
+
})
|
|
15
|
+
class HostComponent {
|
|
16
|
+
readonly items = [
|
|
17
|
+
{ id: 'profile', title: 'Profile', description: 'Public identity', active: true },
|
|
18
|
+
{ id: 'security', title: 'Security', description: 'Password settings', badge: '2' },
|
|
19
|
+
{ id: 'billing', title: 'Billing', description: 'Invoices', disabled: true },
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('<%= classify(name) %>', () => {
|
|
24
|
+
let fixture: ComponentFixture<HostComponent>;
|
|
25
|
+
let host: HTMLElement;
|
|
26
|
+
|
|
27
|
+
beforeEach(async () => {
|
|
28
|
+
await TestBed.configureTestingModule({
|
|
29
|
+
imports: [HostComponent],
|
|
30
|
+
}).compileComponents();
|
|
31
|
+
|
|
32
|
+
fixture = TestBed.createComponent(HostComponent);
|
|
33
|
+
fixture.detectChanges();
|
|
34
|
+
host = fixture.nativeElement as HTMLElement;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('renders a labeled semantic list with active and disabled states', () => {
|
|
38
|
+
const list = host.querySelector<HTMLUListElement>('ul');
|
|
39
|
+
const buttons = Array.from(host.querySelectorAll<HTMLButtonElement>('button'));
|
|
40
|
+
|
|
41
|
+
expect(list?.getAttribute('aria-label')).toBe('Account sections');
|
|
42
|
+
expect(buttons.map((button) => button.textContent?.replace(/\s+/g, ' ').trim())).toEqual([
|
|
43
|
+
'Profile Public identity',
|
|
44
|
+
'Security Password settings 2',
|
|
45
|
+
'Billing Invoices',
|
|
46
|
+
]);
|
|
47
|
+
expect(buttons[0].getAttribute('aria-current')).toBe('true');
|
|
48
|
+
expect(buttons[2].disabled).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('updates selected item when an enabled item is activated', () => {
|
|
52
|
+
const buttons = Array.from(host.querySelectorAll<HTMLButtonElement>('button'));
|
|
53
|
+
|
|
54
|
+
buttons[1].click();
|
|
55
|
+
fixture.detectChanges();
|
|
56
|
+
|
|
57
|
+
expect(buttons[0].getAttribute('aria-current')).toBeNull();
|
|
58
|
+
expect(buttons[1].getAttribute('aria-current')).toBe('true');
|
|
59
|
+
|
|
60
|
+
buttons[2].click();
|
|
61
|
+
fixture.detectChanges();
|
|
62
|
+
|
|
63
|
+
expect(buttons[1].getAttribute('aria-current')).toBe('true');
|
|
64
|
+
expect(buttons[2].getAttribute('aria-current')).toBeNull();
|
|
65
|
+
});
|
|
66
|
+
});
|
package/src/list-group/index.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.listGroup = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.listGroup = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.listGroup = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,SAAS,GAAG,IAAA,iDAA4B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,SAAS,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
|
package/src/list-group/index.ts
CHANGED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
import { <%= classify(name) %> } from './<%= dasherize(name) %>';
|
|
3
|
+
|
|
4
|
+
describe('<%= classify(name) %>', () => {
|
|
5
|
+
let fixture: ComponentFixture<<%= classify(name) %>>;
|
|
6
|
+
|
|
7
|
+
beforeEach(async () => {
|
|
8
|
+
await TestBed.configureTestingModule({ imports: [<%= classify(name) %>] }).compileComponents();
|
|
9
|
+
fixture = TestBed.createComponent(<%= classify(name) %>);
|
|
10
|
+
fixture.detectChanges();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
function listbox(): HTMLElement {
|
|
14
|
+
return fixture.nativeElement.querySelector('[role="listbox"]');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function options(): HTMLElement[] {
|
|
18
|
+
return Array.from(fixture.nativeElement.querySelectorAll('[role="option"]'));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
it('renders listbox semantics with active descendant', () => {
|
|
22
|
+
const [first, second] = options();
|
|
23
|
+
|
|
24
|
+
expect(listbox().getAttribute('aria-labelledby')).toBeTruthy();
|
|
25
|
+
expect(listbox().getAttribute('aria-activedescendant')).toBe(first.id);
|
|
26
|
+
expect(first.getAttribute('aria-selected')).toBe('true');
|
|
27
|
+
expect(second.getAttribute('aria-selected')).toBe('false');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('selects an option on click', () => {
|
|
31
|
+
const [, second] = options();
|
|
32
|
+
second.click();
|
|
33
|
+
fixture.detectChanges();
|
|
34
|
+
|
|
35
|
+
expect(listbox().getAttribute('aria-activedescendant')).toBe(second.id);
|
|
36
|
+
expect(second.getAttribute('aria-selected')).toBe('true');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('moves active option with keyboard', () => {
|
|
40
|
+
listbox().dispatchEvent(new KeyboardEvent('keydown', { key: 'End', bubbles: true }));
|
|
41
|
+
fixture.detectChanges();
|
|
42
|
+
|
|
43
|
+
expect(listbox().getAttribute('aria-activedescendant')).toBe(options()[1].id);
|
|
44
|
+
|
|
45
|
+
listbox().dispatchEvent(new KeyboardEvent('keydown', { key: 'Home', bubbles: true }));
|
|
46
|
+
fixture.detectChanges();
|
|
47
|
+
|
|
48
|
+
expect(listbox().getAttribute('aria-activedescendant')).toBe(options()[0].id);
|
|
49
|
+
});
|
|
50
|
+
});
|
package/src/listbox/index.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.listbox = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.listbox = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.listbox = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/src/listbox/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,OAAO,GAAG,IAAA,iDAA4B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,OAAO,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
|
package/src/listbox/index.ts
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
import { <%= classify(name) %> } from './<%= dasherize(name) %>';
|
|
3
|
+
|
|
4
|
+
describe('<%= classify(name) %>', () => {
|
|
5
|
+
let fixture: ComponentFixture<<%= classify(name) %>>;
|
|
6
|
+
|
|
7
|
+
beforeEach(async () => {
|
|
8
|
+
await TestBed.configureTestingModule({ imports: [<%= classify(name) %>] }).compileComponents();
|
|
9
|
+
fixture = TestBed.createComponent(<%= classify(name) %>);
|
|
10
|
+
fixture.detectChanges();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
function trigger(): HTMLButtonElement {
|
|
14
|
+
return fixture.nativeElement.querySelector('button');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function menu(): HTMLElement {
|
|
18
|
+
return fixture.nativeElement.querySelector('[role="menu"]');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function menuItems(): HTMLElement[] {
|
|
22
|
+
return Array.from(fixture.nativeElement.querySelectorAll('[role="menuitem"]'));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
it('starts closed with menu button semantics', () => {
|
|
26
|
+
expect(trigger().getAttribute('aria-haspopup')).toBe('true');
|
|
27
|
+
expect(trigger().getAttribute('aria-expanded')).toBe('false');
|
|
28
|
+
expect(trigger().getAttribute('aria-controls')).toBe(menu().id);
|
|
29
|
+
expect(menu().hidden).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('opens from click and wires menu labelling', () => {
|
|
33
|
+
trigger().click();
|
|
34
|
+
fixture.detectChanges();
|
|
35
|
+
|
|
36
|
+
expect(trigger().getAttribute('aria-expanded')).toBe('true');
|
|
37
|
+
expect(menu().hidden).toBe(false);
|
|
38
|
+
expect(menu().getAttribute('aria-labelledby')).toBe(trigger().id);
|
|
39
|
+
expect(menuItems()[0].textContent?.trim()).toBe('First option');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('opens with keyboard and closes with Escape', () => {
|
|
43
|
+
trigger().dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
|
|
44
|
+
fixture.detectChanges();
|
|
45
|
+
expect(menu().hidden).toBe(false);
|
|
46
|
+
|
|
47
|
+
menuItems()[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
48
|
+
fixture.detectChanges();
|
|
49
|
+
|
|
50
|
+
expect(menu().hidden).toBe(true);
|
|
51
|
+
expect(document.activeElement).toBe(trigger());
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('moves focus between menu items', () => {
|
|
55
|
+
trigger().click();
|
|
56
|
+
fixture.detectChanges();
|
|
57
|
+
|
|
58
|
+
menuItems()[0].focus();
|
|
59
|
+
menuItems()[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
|
|
60
|
+
fixture.detectChanges();
|
|
61
|
+
|
|
62
|
+
expect(document.activeElement).toBe(menuItems()[1]);
|
|
63
|
+
});
|
|
64
|
+
});
|