semmet-angular 0.22.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 +6 -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
package/README.md
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
`semmet-angular` is a delivery-focused schematic collection for Angular teams that want to ship accessible UI faster: components with real ARIA behavior, a consistent visual identity, and generated test files from the first command.
|
|
6
6
|
|
|
7
|
+
Semmet Angular helps teams generate, test, verify, and package accessible Angular UI using the Angular CLI ecosystem.
|
|
8
|
+
|
|
9
|
+
**Gerar. Testar. Verificar. Empacotar.**
|
|
10
|
+
|
|
11
|
+
Read the broader product direction in [PRODUCT_VISION.md](./PRODUCT_VISION.md).
|
|
12
|
+
|
|
7
13
|
`ng generate semmet-angular:accordion my-faq` scaffolds a standalone, signals-based Angular component — `.ts`/`.html`/`.css` — plus `.spec.ts` and `.e2e-spec.ts` smoke tests. The generated component implements a W3C ARIA Authoring Practices Guide pattern for real: correct roles and `aria-*` wiring, the keyboard/focus behavior the pattern requires (arrow-key navigation, focus traps, focus restoration...), and a consistent visual identity out of the box.
|
|
8
14
|
|
|
9
15
|
## Usage
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "semmet-angular",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Accessible UI Delivery Kit for Angular: schematics that generate ARIA-conformant standalone components with styling, keyboard behavior, unit tests, and Playwright e2e smoke tests.",
|
|
5
5
|
"publisher": "danilodevsilva",
|
|
6
6
|
"license": "MIT",
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
+
import { <%= classify(name) %>, <%= classify(name) %>Item } from './<%= dasherize(name) %>';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
imports: [<%= classify(name) %>, <%= classify(name) %>Item],
|
|
7
|
+
template: `
|
|
8
|
+
<<%= selector %> [preserveContent]="preserveContent">
|
|
9
|
+
<ng-template <%= camelize(name) %>Item id="profile" title="Profile" [expanded]="true">
|
|
10
|
+
<p>Profile content</p>
|
|
11
|
+
</ng-template>
|
|
12
|
+
|
|
13
|
+
<ng-template <%= camelize(name) %>Item id="settings" title="Settings">
|
|
14
|
+
<p>Settings content</p>
|
|
15
|
+
</ng-template>
|
|
16
|
+
|
|
17
|
+
<ng-template <%= camelize(name) %>Item id="billing" title="Billing" disabled>
|
|
18
|
+
<p>Billing content</p>
|
|
19
|
+
</ng-template>
|
|
20
|
+
</<%= selector %>>
|
|
21
|
+
`,
|
|
22
|
+
})
|
|
23
|
+
class HostComponent {
|
|
24
|
+
preserveContent = true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
describe('<%= classify(name) %>', () => {
|
|
28
|
+
let fixture: ComponentFixture<HostComponent>;
|
|
29
|
+
|
|
30
|
+
beforeEach(async () => {
|
|
31
|
+
await TestBed.configureTestingModule({
|
|
32
|
+
imports: [HostComponent],
|
|
33
|
+
}).compileComponents();
|
|
34
|
+
|
|
35
|
+
fixture = TestBed.createComponent(HostComponent);
|
|
36
|
+
fixture.detectChanges();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
function buttons(): HTMLButtonElement[] {
|
|
40
|
+
return Array.from(fixture.nativeElement.querySelectorAll('button'));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function panels(): HTMLElement[] {
|
|
44
|
+
return Array.from(fixture.nativeElement.querySelectorAll('[role="region"]'));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
it('renders projected accordion items with ARIA relationships', () => {
|
|
48
|
+
const [profileButton, settingsButton] = buttons();
|
|
49
|
+
const [profilePanel, settingsPanel] = panels();
|
|
50
|
+
|
|
51
|
+
expect(profileButton.textContent?.trim()).toBe('Profile');
|
|
52
|
+
expect(profileButton.getAttribute('aria-expanded')).toBe('true');
|
|
53
|
+
expect(profileButton.getAttribute('aria-controls')).toBe(profilePanel.id);
|
|
54
|
+
expect(profilePanel.getAttribute('aria-labelledby')).toBe(profileButton.id);
|
|
55
|
+
expect(profilePanel.hidden).toBe(false);
|
|
56
|
+
|
|
57
|
+
expect(settingsButton.textContent?.trim()).toBe('Settings');
|
|
58
|
+
expect(settingsButton.getAttribute('aria-expanded')).toBe('false');
|
|
59
|
+
expect(settingsButton.getAttribute('aria-controls')).toBe(settingsPanel.id);
|
|
60
|
+
expect(settingsPanel.hidden).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('toggles an enabled item with click', () => {
|
|
64
|
+
const [, settingsButton] = buttons();
|
|
65
|
+
const [, settingsPanel] = panels();
|
|
66
|
+
|
|
67
|
+
settingsButton.click();
|
|
68
|
+
fixture.detectChanges();
|
|
69
|
+
|
|
70
|
+
expect(settingsButton.getAttribute('aria-expanded')).toBe('true');
|
|
71
|
+
expect(settingsPanel.hidden).toBe(false);
|
|
72
|
+
expect(settingsPanel.textContent).toContain('Settings content');
|
|
73
|
+
|
|
74
|
+
settingsButton.click();
|
|
75
|
+
fixture.detectChanges();
|
|
76
|
+
|
|
77
|
+
expect(settingsButton.getAttribute('aria-expanded')).toBe('false');
|
|
78
|
+
expect(settingsPanel.hidden).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('does not toggle disabled items', () => {
|
|
82
|
+
const disabledButton = buttons()[2];
|
|
83
|
+
const disabledPanel = panels()[2];
|
|
84
|
+
|
|
85
|
+
expect(disabledButton.disabled).toBe(true);
|
|
86
|
+
expect(disabledButton.getAttribute('aria-expanded')).toBe('false');
|
|
87
|
+
|
|
88
|
+
disabledButton.click();
|
|
89
|
+
fixture.detectChanges();
|
|
90
|
+
|
|
91
|
+
expect(disabledButton.getAttribute('aria-expanded')).toBe('false');
|
|
92
|
+
expect(disabledPanel.hidden).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('keeps closed content after first render when preserveContent is enabled', () => {
|
|
96
|
+
const [, settingsButton] = buttons();
|
|
97
|
+
const [, settingsPanel] = panels();
|
|
98
|
+
|
|
99
|
+
settingsButton.click();
|
|
100
|
+
fixture.detectChanges();
|
|
101
|
+
settingsButton.click();
|
|
102
|
+
fixture.detectChanges();
|
|
103
|
+
|
|
104
|
+
expect(settingsPanel.hidden).toBe(true);
|
|
105
|
+
expect(settingsPanel.textContent).toContain('Settings content');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('moves focus between headers with arrow, Home, and End keys', () => {
|
|
109
|
+
const [profileButton, settingsButton, billingButton] = buttons();
|
|
110
|
+
|
|
111
|
+
profileButton.focus();
|
|
112
|
+
profileButton.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
|
|
113
|
+
fixture.detectChanges();
|
|
114
|
+
expect(document.activeElement).toBe(settingsButton);
|
|
115
|
+
|
|
116
|
+
settingsButton.dispatchEvent(new KeyboardEvent('keydown', { key: 'End', bubbles: true }));
|
|
117
|
+
fixture.detectChanges();
|
|
118
|
+
expect(document.activeElement).toBe(billingButton);
|
|
119
|
+
|
|
120
|
+
billingButton.dispatchEvent(new KeyboardEvent('keydown', { key: 'Home', bubbles: true }));
|
|
121
|
+
fixture.detectChanges();
|
|
122
|
+
expect(document.activeElement).toBe(profileButton);
|
|
123
|
+
});
|
|
124
|
+
});
|
package/src/accordion/index.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.accordion = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.accordion = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.accordion = (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/accordion/index.ts
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
it('renders an assertive alert region', () => {
|
|
14
|
+
const alert = fixture.nativeElement.querySelector('[role="alert"]');
|
|
15
|
+
|
|
16
|
+
expect(alert).toBeTruthy();
|
|
17
|
+
expect(alert.textContent).toContain('Your changes have been saved.');
|
|
18
|
+
expect(fixture.nativeElement.querySelector('button').getAttribute('aria-label')).toBe('Dismiss');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('dismisses the alert', () => {
|
|
22
|
+
fixture.nativeElement.querySelector('button').click();
|
|
23
|
+
fixture.detectChanges();
|
|
24
|
+
|
|
25
|
+
expect(fixture.nativeElement.querySelector('[role="alert"]')).toBeNull();
|
|
26
|
+
});
|
|
27
|
+
});
|
package/src/alert/index.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.alert = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.alert = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.alert = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/src/alert/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/alert/index.ts
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
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 trigger(): HTMLButtonElement {
|
|
17
|
+
return fixture.nativeElement.querySelector('button');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function dialog(): HTMLElement | null {
|
|
21
|
+
return fixture.nativeElement.querySelector('[role="alertdialog"]');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
it('starts closed with a destructive-action trigger', () => {
|
|
25
|
+
expect(trigger().textContent?.trim()).toBe('Delete item');
|
|
26
|
+
expect(dialog()).toBeNull();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('opens an alertdialog with modal, title, and description semantics', () => {
|
|
30
|
+
trigger().click();
|
|
31
|
+
fixture.detectChanges();
|
|
32
|
+
|
|
33
|
+
const element = dialog();
|
|
34
|
+
const title = fixture.nativeElement.querySelector('h2');
|
|
35
|
+
const description = fixture.nativeElement.querySelector(`#${element?.getAttribute('aria-describedby')}`);
|
|
36
|
+
|
|
37
|
+
expect(element).toBeTruthy();
|
|
38
|
+
expect(element?.getAttribute('aria-modal')).toBe('true');
|
|
39
|
+
expect(element?.getAttribute('aria-labelledby')).toBe(title.id);
|
|
40
|
+
expect(description?.textContent).toContain('This action cannot be undone.');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('closes from Cancel and restores focus to the trigger', () => {
|
|
44
|
+
const button = trigger();
|
|
45
|
+
button.focus();
|
|
46
|
+
button.click();
|
|
47
|
+
fixture.detectChanges();
|
|
48
|
+
|
|
49
|
+
const cancelButton = Array.from(fixture.nativeElement.querySelectorAll('button'))[1] as HTMLButtonElement;
|
|
50
|
+
cancelButton.click();
|
|
51
|
+
fixture.detectChanges();
|
|
52
|
+
|
|
53
|
+
expect(dialog()).toBeNull();
|
|
54
|
+
expect(document.activeElement).toBe(button);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('closes with Escape', () => {
|
|
58
|
+
trigger().click();
|
|
59
|
+
fixture.detectChanges();
|
|
60
|
+
|
|
61
|
+
dialog()?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
62
|
+
fixture.detectChanges();
|
|
63
|
+
|
|
64
|
+
expect(dialog()).toBeNull();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.alertDialog = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.alertDialog = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.alertDialog = (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,69 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
+
import { <%= classify(name) %>, <%= classify(name) %>Label, <%= classify(name) %>Leading, <%= classify(name) %>Trailing } from './<%= dasherize(name) %>';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
imports: [<%= classify(name) %>, <%= classify(name) %>Label, <%= classify(name) %>Leading, <%= classify(name) %>Trailing],
|
|
7
|
+
template: `
|
|
8
|
+
<<%= selector %>
|
|
9
|
+
label="Save"
|
|
10
|
+
variant="danger"
|
|
11
|
+
size="lg"
|
|
12
|
+
[busy]="busy"
|
|
13
|
+
[disabled]="disabled"
|
|
14
|
+
[pressed]="pressed"
|
|
15
|
+
(buttonClick)="clicked = true"
|
|
16
|
+
>
|
|
17
|
+
<ng-template <%= camelize(name) %>Leading>Lead</ng-template>
|
|
18
|
+
<ng-template <%= camelize(name) %>Label>Projected label</ng-template>
|
|
19
|
+
<ng-template <%= camelize(name) %>Trailing>Trail</ng-template>
|
|
20
|
+
</<%= selector %>>
|
|
21
|
+
`,
|
|
22
|
+
})
|
|
23
|
+
class HostComponent {
|
|
24
|
+
busy = false;
|
|
25
|
+
disabled = false;
|
|
26
|
+
pressed: boolean | null = true;
|
|
27
|
+
clicked = false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe('<%= classify(name) %>', () => {
|
|
31
|
+
let fixture: ComponentFixture<HostComponent>;
|
|
32
|
+
|
|
33
|
+
beforeEach(async () => {
|
|
34
|
+
await TestBed.configureTestingModule({ imports: [HostComponent] }).compileComponents();
|
|
35
|
+
fixture = TestBed.createComponent(HostComponent);
|
|
36
|
+
fixture.detectChanges();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
function button(): HTMLButtonElement {
|
|
40
|
+
return fixture.nativeElement.querySelector('button');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
it('renders projected label, slots, classes, and pressed state', () => {
|
|
44
|
+
expect(button().textContent).toContain('Projected label');
|
|
45
|
+
expect(button().textContent).toContain('Lead');
|
|
46
|
+
expect(button().textContent).toContain('Trail');
|
|
47
|
+
expect(button().className).toContain('semmet-button--danger');
|
|
48
|
+
expect(button().className).toContain('semmet-button--lg');
|
|
49
|
+
expect(button().getAttribute('aria-pressed')).toBe('true');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('emits buttonClick when enabled', () => {
|
|
53
|
+
button().click();
|
|
54
|
+
fixture.detectChanges();
|
|
55
|
+
|
|
56
|
+
expect(fixture.componentInstance.clicked).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('blocks clicks when busy or disabled', () => {
|
|
60
|
+
fixture.componentInstance.busy = true;
|
|
61
|
+
fixture.componentInstance.clicked = false;
|
|
62
|
+
fixture.detectChanges();
|
|
63
|
+
|
|
64
|
+
button().click();
|
|
65
|
+
expect(fixture.componentInstance.clicked).toBe(false);
|
|
66
|
+
expect(button().disabled).toBe(true);
|
|
67
|
+
expect(button().getAttribute('aria-busy')).toBe('true');
|
|
68
|
+
});
|
|
69
|
+
});
|
package/src/button/index.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.button = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.button = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.button = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/src/button/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/button/index.ts
CHANGED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
+
import { <%= classify(name) %>, <%= classify(name) %>Item, <%= classify(name) %>ItemTemplate } from './<%= dasherize(name) %>';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
imports: [<%= classify(name) %>, <%= classify(name) %>ItemTemplate],
|
|
7
|
+
template: `
|
|
8
|
+
<<%= selector %>
|
|
9
|
+
label="View period"
|
|
10
|
+
selectionMode="multiple"
|
|
11
|
+
[items]="items"
|
|
12
|
+
[(selectedIds)]="selectedIds"
|
|
13
|
+
>
|
|
14
|
+
<ng-template <%= camelize(name) %>Item let-item let-pressed="pressed">
|
|
15
|
+
{{ item.label }} {{ pressed ? 'on' : 'off' }}
|
|
16
|
+
</ng-template>
|
|
17
|
+
</<%= selector %>>
|
|
18
|
+
`,
|
|
19
|
+
})
|
|
20
|
+
class HostComponent {
|
|
21
|
+
items: <%= classify(name) %>Item[] = [
|
|
22
|
+
{ id: 'day', label: 'Day', pressed: true },
|
|
23
|
+
{ id: 'week', label: 'Week' },
|
|
24
|
+
{ id: 'month', label: 'Month', disabled: true },
|
|
25
|
+
];
|
|
26
|
+
selectedIds = ['day'];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe('<%= classify(name) %>', () => {
|
|
30
|
+
let fixture: ComponentFixture<HostComponent>;
|
|
31
|
+
|
|
32
|
+
beforeEach(async () => {
|
|
33
|
+
await TestBed.configureTestingModule({ imports: [HostComponent] }).compileComponents();
|
|
34
|
+
fixture = TestBed.createComponent(HostComponent);
|
|
35
|
+
fixture.detectChanges();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
function group(): HTMLElement {
|
|
39
|
+
return fixture.nativeElement.querySelector('[role="group"]');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function buttons(): HTMLButtonElement[] {
|
|
43
|
+
return Array.from(fixture.nativeElement.querySelectorAll('button'));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
it('renders grouped buttons with labels and pressed state', () => {
|
|
47
|
+
const [day, week, month] = buttons();
|
|
48
|
+
|
|
49
|
+
expect(group().getAttribute('aria-label')).toBe('View period');
|
|
50
|
+
expect(day.getAttribute('aria-pressed')).toBe('true');
|
|
51
|
+
expect(day.textContent).toContain('Day on');
|
|
52
|
+
expect(week.getAttribute('aria-pressed')).toBe('false');
|
|
53
|
+
expect(month.disabled).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('updates selectedIds in multiple selection mode', () => {
|
|
57
|
+
buttons()[1].click();
|
|
58
|
+
fixture.detectChanges();
|
|
59
|
+
|
|
60
|
+
expect(fixture.componentInstance.selectedIds).toEqual(['day', 'week']);
|
|
61
|
+
expect(buttons()[1].getAttribute('aria-pressed')).toBe('true');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('ignores disabled items', () => {
|
|
65
|
+
buttons()[2].click();
|
|
66
|
+
fixture.detectChanges();
|
|
67
|
+
|
|
68
|
+
expect(fixture.componentInstance.selectedIds).toEqual(['day']);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.buttonGroup = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.buttonGroup = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.buttonGroup = (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,69 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
+
|
|
4
|
+
import { <%= classify(name) %>, <%= classify(name) %>Slide } from './<%= dasherize(name) %>';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
imports: [<%= classify(name) %>, <%= classify(name) %>Slide],
|
|
8
|
+
template: `
|
|
9
|
+
<<%= selector %>>
|
|
10
|
+
<ng-template <%= camelize(name) %>Slide id="intro" label="Introduction">
|
|
11
|
+
<h2>Intro slide</h2>
|
|
12
|
+
</ng-template>
|
|
13
|
+
<ng-template <%= camelize(name) %>Slide id="summary" label="Summary">
|
|
14
|
+
<h2>Summary slide</h2>
|
|
15
|
+
</ng-template>
|
|
16
|
+
</<%= selector %>>
|
|
17
|
+
`,
|
|
18
|
+
})
|
|
19
|
+
class HostComponent {}
|
|
20
|
+
|
|
21
|
+
describe('<%= classify(name) %>', () => {
|
|
22
|
+
let fixture: ComponentFixture<HostComponent>;
|
|
23
|
+
let host: HTMLElement;
|
|
24
|
+
|
|
25
|
+
beforeEach(async () => {
|
|
26
|
+
await TestBed.configureTestingModule({
|
|
27
|
+
imports: [HostComponent],
|
|
28
|
+
}).compileComponents();
|
|
29
|
+
|
|
30
|
+
fixture = TestBed.createComponent(HostComponent);
|
|
31
|
+
fixture.detectChanges();
|
|
32
|
+
host = fixture.nativeElement as HTMLElement;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('renders carousel and active slide semantics', () => {
|
|
36
|
+
const carousel = host.querySelector<HTMLElement>('[aria-roledescription="carousel"]');
|
|
37
|
+
const slides = Array.from(host.querySelectorAll<HTMLElement>('[aria-roledescription="slide"]'));
|
|
38
|
+
|
|
39
|
+
expect(carousel?.getAttribute('aria-label')).toBe('Featured items');
|
|
40
|
+
expect(slides).toHaveLength(2);
|
|
41
|
+
expect(slides[0].hidden).toBe(false);
|
|
42
|
+
expect(slides[0].getAttribute('aria-label')).toBe('1 of 2: Introduction');
|
|
43
|
+
expect(slides[1].hidden).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('moves between slides and wraps with previous/next buttons', () => {
|
|
47
|
+
const buttons = Array.from(host.querySelectorAll<HTMLButtonElement>('button'));
|
|
48
|
+
const getSlides = () => Array.from(host.querySelectorAll<HTMLElement>('[aria-roledescription="slide"]'));
|
|
49
|
+
|
|
50
|
+
buttons.find((button) => button.getAttribute('aria-label') === 'Next slide')?.click();
|
|
51
|
+
fixture.detectChanges();
|
|
52
|
+
|
|
53
|
+
expect(getSlides()[0].hidden).toBe(true);
|
|
54
|
+
expect(getSlides()[1].hidden).toBe(false);
|
|
55
|
+
expect(host.textContent).toContain('Summary slide');
|
|
56
|
+
|
|
57
|
+
buttons.find((button) => button.getAttribute('aria-label') === 'Next slide')?.click();
|
|
58
|
+
fixture.detectChanges();
|
|
59
|
+
|
|
60
|
+
expect(getSlides()[0].hidden).toBe(false);
|
|
61
|
+
expect(getSlides()[1].hidden).toBe(true);
|
|
62
|
+
|
|
63
|
+
buttons.find((button) => button.getAttribute('aria-label') === 'Previous slide')?.click();
|
|
64
|
+
fixture.detectChanges();
|
|
65
|
+
|
|
66
|
+
expect(getSlides()[0].hidden).toBe(true);
|
|
67
|
+
expect(getSlides()[1].hidden).toBe(false);
|
|
68
|
+
});
|
|
69
|
+
});
|
package/src/carousel/index.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.carousel = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.carousel = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.carousel = (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/carousel/index.ts
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
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 checkbox(): HTMLElement {
|
|
17
|
+
return fixture.nativeElement.querySelector('[role="checkbox"]');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
it('renders keyboard-focusable checkbox semantics', () => {
|
|
21
|
+
expect(checkbox().getAttribute('aria-checked')).toBe('false');
|
|
22
|
+
expect(checkbox().getAttribute('tabindex')).toBe('0');
|
|
23
|
+
expect(checkbox().textContent?.trim()).toBe('Subscribe to newsletter');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('toggles aria-checked when clicked', () => {
|
|
27
|
+
checkbox().click();
|
|
28
|
+
fixture.detectChanges();
|
|
29
|
+
expect(checkbox().getAttribute('aria-checked')).toBe('true');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('toggles with Space and Enter', () => {
|
|
33
|
+
checkbox().dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true }));
|
|
34
|
+
fixture.detectChanges();
|
|
35
|
+
expect(checkbox().getAttribute('aria-checked')).toBe('true');
|
|
36
|
+
|
|
37
|
+
checkbox().dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
|
|
38
|
+
fixture.detectChanges();
|
|
39
|
+
expect(checkbox().getAttribute('aria-checked')).toBe('false');
|
|
40
|
+
});
|
|
41
|
+
});
|
package/src/checkbox/index.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checkbox = void 0;
|
|
4
4
|
const generate_component_1 = require("../utils/generate-component");
|
|
5
|
-
exports.checkbox = (0, generate_component_1.createAriaComponentSchematic)();
|
|
5
|
+
exports.checkbox = (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/checkbox/index.ts
CHANGED