Skip to content

Commit 5ca5f5a

Browse files
authored
Merge pull request #401 from cal-smith/dialog
fix(dialog): add afterDialogViewInit and improve A11Y
2 parents e439c0e + a720346 commit 5ca5f5a

File tree

9 files changed

+91
-82
lines changed

9 files changed

+91
-82
lines changed
Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,38 @@
11
$feature-flags: (
22
components-x: true,
3-
ui-shell: true,
4-
css--body: false, // we're providing our own body styles
5-
css--reset: false // prevent thousands of resets being included...
3+
ui-shell: true
64
);
75

6+
$css--body: false; // we're providing our own body styles
7+
$css--reset: false; // prevent thousands of resets being included...
8+
89
.experimental {
910
@import '~carbon-components/scss/globals/scss/styles';
11+
@import '~carbon-components/scss/globals/scss/css--typography';
1012

1113
// carbon body reset and styles
12-
// @include reset;
14+
@include typography;
1315
@include font-family;
16+
// reset
1417
color: $text-01;
1518
background-color: $ui-02;
1619
line-height: 1;
20+
box-sizing: border-box;
21+
margin: 0;
22+
padding: 0;
23+
border: 0;
24+
font-size: 100%;
25+
vertical-align: baseline;
1726

18-
@include typography;
27+
& > *,
28+
& > *:before,
29+
& > *:after {
30+
box-sizing: inherit;
31+
}
1932

20-
// padding/margin body reset
21-
padding: 0;
22-
margin: 0;
33+
ul {
34+
list-style: none;
35+
margin: 0;
36+
padding: 0;
37+
}
2338
}

.storybook/preview.scss

Lines changed: 21 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,37 @@
11
$feature-flags: (
22
components-x: false,
3-
ui-shell: true,
4-
css--body: false, // we're providing our own body styles
5-
css--reset: false // prevent thousands of resets being included...
3+
ui-shell: true
64
);
75

6+
$css--body: false; // we're providing our own body styles
7+
$css--reset: false; // prevent thousands of resets being included...
8+
89
.carbon {
910
@import '~carbon-components/scss/globals/scss/styles';
11+
@import '~carbon-components/scss/globals/scss/css--typography';
1012

1113
// carbon body reset and styles
12-
// @include reset;
14+
@include typography;
1315
@include font-family;
16+
//reset
1417
color: $text-01;
1518
background-color: $ui-02;
16-
line-height: 1;
17-
18-
@include typography;
19-
20-
// padding/margin body reset
21-
padding: 0;
19+
box-sizing: border-box;
2220
margin: 0;
23-
24-
// for some reason this isn't included when tabs are built. So lets just manually include it here.
25-
.bx--tabs__nav-item + .bx--tabs__nav-item {
26-
margin-left: 3rem;
27-
}
28-
29-
// for some reason this isn't included when progress indicator is built. So lets just manually include it here.
30-
.bx--progress-step:first-child .bx--progress-line {
31-
display: none;
32-
}
33-
34-
// for some reason all this isn't included when structured list is built. So lets just manually include it here.
35-
.bx--structured-list--selection .bx--structured-list-row:hover:not(.bx--structured-list-row--header-row) {
36-
background-color: $hover-row;
37-
cursor: pointer;
38-
}
39-
40-
.bx--structured-list-row:focus:not(.bx--structured-list-row--header-row) {
41-
@include focus-outline('border');
42-
}
43-
44-
.bx--structured-list-svg {
45-
display: inline-block;
46-
fill: transparent;
47-
vertical-align: middle;
48-
transition: $transition--base $carbon--standard-easing;
49-
}
50-
51-
.bx--structured-list-row:hover .bx--structured-list-svg {
52-
fill: $hover-row;
21+
padding: 0;
22+
border: 0;
23+
font-size: 100%;
24+
vertical-align: baseline;
25+
26+
& > *,
27+
& > *:before,
28+
& > *:after {
29+
box-sizing: inherit;
5330
}
5431

55-
.bx--structured-list-input:checked + .bx--structured-list-row .bx--structured-list-svg,
56-
.bx--structured-list-input:checked + .bx--structured-list-td .bx--structured-list-svg {
57-
fill: $brand-02;
32+
ul {
33+
list-style: none;
34+
margin: 0;
35+
padding: 0;
5836
}
5937
}

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
"@types/node": "8.5.2",
9999
"angular2-template-loader": "0.6.2",
100100
"babel-loader": "8.0.4",
101-
"carbon-components": "9.68.16",
101+
"carbon-components": "9.70.3",
102102
"codelyzer": "4.5.0",
103103
"commitizen": "2.10.1",
104104
"core-js": "2.5.5",

src/dialog/dialog.component.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,15 +196,24 @@ export class Dialog implements OnInit, AfterViewInit, OnDestroy {
196196
};
197197

198198
// settimeout to let the DOM settle before attempting to place the dialog
199-
setTimeout(placeDialogInContainer);
199+
// and before notifying components that the DOM is ready
200+
setTimeout(() => {
201+
placeDialogInContainer();
202+
this.afterDialogViewInit();
203+
});
200204
}
201205

202206
/**
203207
* Empty method to be overridden by consuming classes to run any additional initialization code.
204-
* @memberof Dialog
205208
*/
206209
onDialogInit() {}
207210

211+
/**
212+
* Empty method to be overridden by consuming classes to run any additional initialization code after the view is available.
213+
* NOTE: this does _not_ guarantee the dialog will be positioned, simply that it will exist in the DOM
214+
*/
215+
afterDialogViewInit() {}
216+
208217
/**
209218
* Uses the position service to position the `Dialog` in screen space
210219
*/

src/dialog/dialog.directive.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { DialogConfig } from "./dialog-config.interface";
1919
/**
2020
* A generic directive that can be inherited from to create dialogs (for example, a tooltip or popover)
2121
*
22-
* This class contains the relevant intilization code, specific templates, options, and additional inputs
22+
* This class contains the relevant initialization code, specific templates, options, and additional inputs
2323
* should be specified in the derived class.
2424
*
2525
* NOTE: All child classes should add `DialogService` as a provider, otherwise they will lose context that
@@ -33,6 +33,7 @@ import { DialogConfig } from "./dialog-config.interface";
3333
]
3434
})
3535
export class DialogDirective implements OnInit, OnDestroy, OnChanges {
36+
static dialogCounter = 0;
3637
/**
3738
* Title for the dialog
3839
* @type {string}
@@ -64,7 +65,7 @@ export class DialogDirective implements OnInit, OnDestroy, OnChanges {
6465
@Input() gap = 0;
6566
/**
6667
* Deprecated. Defaults to true. Use appendInline to keep dialogs within page flow
67-
* Value `true` sets Dialog be appened to the body (to break out of containers)
68+
* Value `true` appends Dialog to the body (to break out of containers)
6869
*/
6970
@Input() set appendToBody(v: boolean) {
7071
console.log("`appendToBody` has been deprecated. Dialogs now append to the body by default.");
@@ -91,6 +92,10 @@ export class DialogDirective implements OnInit, OnDestroy, OnChanges {
9192

9293
@HostBinding("attr.role") role = "button";
9394
@HostBinding("attr.aria-expanded") expanded = false;
95+
@HostBinding("attr.aria-haspopup") hasPopup = true;
96+
@HostBinding("attr.aria-owns") get ariaOwns(): string {
97+
return this.expanded ? this.dialogConfig.compID : null;
98+
}
9499

95100
/**
96101
* Creates an instance of DialogDirective.
@@ -170,6 +175,9 @@ export class DialogDirective implements OnInit, OnDestroy, OnChanges {
170175
}
171176
});
172177

178+
DialogDirective.dialogCounter++;
179+
this.dialogConfig.compID = "dialog-" + DialogDirective.dialogCounter;
180+
173181
// run any code a child class may need
174182
this.onDialogInit();
175183
}

src/dialog/overflow-menu/overflow-menu-pane.component.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -106,21 +106,16 @@ export class OverflowMenuPane extends Dialog implements AfterViewInit {
106106
}
107107
}
108108

109-
ngAfterViewInit() {
110-
// wait for the menu to exist in the DOM before setting focus
111-
// TODO: work on a more elegant solution (afterDialogInit hook maybe?)
112-
setTimeout(() => {
113-
const focusElementList = this.listItems();
114-
focusElementList.forEach(button => {
115-
// Allows user to set tabindex to 0.
116-
if (button.getAttribute("tabindex") === null) {
117-
button.tabIndex = -1;
118-
}
119-
});
120-
focusElementList[0].tabIndex = 0;
121-
focusElementList[0].focus();
109+
afterDialogViewInit() {
110+
const focusElementList = this.listItems();
111+
focusElementList.forEach(button => {
112+
// Allows user to set tabindex to 0.
113+
if (button.getAttribute("tabindex") === null) {
114+
button.tabIndex = -1;
115+
}
122116
});
123-
super.ngAfterViewInit();
117+
focusElementList[0].tabIndex = 0;
118+
focusElementList[0].focus();
124119
}
125120

126121
protected listItems() {

src/dialog/tooltip/tooltip.component.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@ import { Dialog } from "./../dialog.component";
1616
template: `
1717
<div
1818
#dialog
19-
[tabindex]="tabIndex"
2019
[id]="dialogConfig.compID"
21-
role="tooltip"
20+
[attr.role]="role"
2221
class="bx--tooltip bx--tooltip--shown">
2322
<span class="bx--tooltip__caret" aria-hidden="true"></span>
2423
<ng-template
@@ -39,14 +38,23 @@ export class Tooltip extends Dialog {
3938
* Value is set to `true` if the `Tooltip` is to display a `TemplateRef` instead of a string.
4039
*/
4140
public hasContentTemplate = false;
42-
43-
@Input() tabIndex;
41+
/**
42+
* Sets the role of the tooltip. If there's no focusable content we leave it as a `tooltip`,
43+
* if there _is_ focusable content we switch to the interactive `dialog` role.
44+
*/
45+
public role = "tooltip";
4446
/**
4547
* Check whether there is a template for the `Tooltip` content.
4648
*/
4749
onDialogInit() {
4850
this.hasContentTemplate = this.dialogConfig.content instanceof TemplateRef;
51+
}
4952

50-
this.tabIndex = getFocusElementList(this.dialog.nativeElement).length > 0 ? 0 : -1;
53+
afterDialogViewInit() {
54+
const focusableElements = getFocusElementList(this.dialog.nativeElement);
55+
if (focusableElements.length > 0) {
56+
this.role = "dialog";
57+
focusableElements[0].focus();
58+
}
5159
}
5260
}

src/dialog/tooltip/tooltip.directive.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ import { DialogService } from "./../dialog.service";
3939
]
4040
})
4141
export class TooltipDirective extends DialogDirective {
42-
static tooltipCounter = 0;
43-
4442
/**
4543
* The string or template content to be exposed by the tooltip.
4644
*/
@@ -74,8 +72,6 @@ export class TooltipDirective extends DialogDirective {
7472
* Extends the `Dialog` component's data structure with tooltip properties.
7573
*/
7674
onDialogInit() {
77-
TooltipDirective.tooltipCounter++;
78-
this.dialogConfig.compID = "tooltip-" + TooltipDirective.tooltipCounter;
7975
this.dialogConfig.content = this.ibmTooltip;
8076
this.dialogConfig.type = this.tooltipType;
8177
}

0 commit comments

Comments
 (0)