Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 0bc4794

Browse files
authored
Merge pull request #7492 from plotly/david-enhancement-modebar-emilykl
feat: Improve keyboard navigation of modebar (by @davidangarita1)
2 parents 2cac1b1 + 4698ac6 commit 0bc4794

File tree

5 files changed

+44
-19
lines changed

5 files changed

+44
-19
lines changed

‎build/plotcss.js‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@ var rules = {
3434
"X .ease-bg": "-webkit-transition:background-color .3s ease 0s;-moz-transition:background-color .3s ease 0s;-ms-transition:background-color .3s ease 0s;-o-transition:background-color .3s ease 0s;transition:background-color .3s ease 0s;",
3535
"X .modebar--hover>:not(.watermark)": "opacity:0;-webkit-transition:opacity .3s ease 0s;-moz-transition:opacity .3s ease 0s;-ms-transition:opacity .3s ease 0s;-o-transition:opacity .3s ease 0s;transition:opacity .3s ease 0s;",
3636
"X:hover .modebar--hover .modebar-group": "opacity:1;",
37+
"X:focus-within .modebar--hover .modebar-group": "opacity:1;",
3738
"X .modebar-group": "float:left;display:inline-block;box-sizing:border-box;padding-left:8px;position:relative;vertical-align:middle;white-space:nowrap;",
38-
"X .modebar-btn": "position:relative;font-size:16px;padding:3px 4px;height:22px;cursor:pointer;line-height:normal;box-sizing:border-box;",
39-
"X .modebar-btn svg": "position:relative;top:2px;",
39+
"X .modebar-group a": "display:grid;place-content:center;",
40+
"X .modebar-btn": "position:relative;font-size:16px;padding:3px 4px;height:22px;cursor:pointer;line-height:normal;box-sizing:border-box;border:none;background:rgba(0,0,0,0);",
41+
"X .modebar-btn svg": "position:relative;",
42+
"X .modebar-btn:focus-visible": "outline:1px solid #000;outline-offset:1px;border-radius:3px;",
4043
"X .modebar.vertical": "display:flex;flex-direction:column;flex-wrap:wrap;align-content:flex-end;max-height:100%;",
4144
"X .modebar.vertical svg": "top:-1px;",
4245
"X .modebar.vertical .modebar-group": "display:block;float:none;padding-left:0px;padding-bottom:8px;",

‎draftlogs/7492_add.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Make modebar keyboard-accessible via tabbing [[#7492](https://github.com/plotly/plotly.js/pull/7492)], with thanks to @davidangarita1 for the contribution!

‎src/components/modebar/modebar.js‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ proto.update = function(graphInfo, buttons) {
4343
var modeBarId = 'modebar-' + fullLayout._uid;
4444

4545
this.element.setAttribute('id', modeBarId);
46-
this._uid=modeBarId;
46+
this.element.setAttribute('role','toolbar');
4747

48-
this.element.className = 'modebar';
48+
this._uid = modeBarId;
49+
this.element.className = 'modebar modebar--custom';
4950
if(context.displayModeBar === 'hover') this.element.className += ' modebar--hover ease-bg';
5051

5152
if(fullLayout.modebar.orientation === 'v') {
@@ -145,8 +146,9 @@ proto.createGroup = function() {
145146
*/
146147
proto.createButton = function(config) {
147148
var _this = this;
148-
var button = document.createElement('a');
149+
var button = document.createElement('button');
149150

151+
button.setAttribute('type', 'button');
150152
button.setAttribute('rel', 'tooltip');
151153
button.className = 'modebar-btn';
152154

@@ -155,7 +157,10 @@ proto.createButton = function(config) {
155157
// for localization: allow title to be a callable that takes gd as arg
156158
else if(typeof title === 'function') title = title(this.graphInfo);
157159

158-
if(title || title === 0) button.setAttribute('data-title', title);
160+
if(title || title === 0) {
161+
button.setAttribute('data-title', title)
162+
button.setAttribute("aria-label", title)
163+
};
159164

160165
if(config.attr !== undefined) button.setAttribute('data-attr', config.attr);
161166

‎src/css/_modebar.scss‎

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
@include vendor('transition', background-color 0.3s ease 0s);
99
}
1010

11-
.modebar--hover> :not(.watermark) {
11+
.modebar--hover> :not(.watermark) {
1212
opacity: 0;
1313
@include vendor('transition', opacity 0.3s ease 0s);
1414
}
@@ -17,6 +17,10 @@
1717
opacity: 1;
1818
}
1919

20+
&:focus-within .modebar--hover .modebar-group {
21+
opacity: 1;
22+
}
23+
2024
.modebar-group {
2125
float: left;
2226
display: inline-block;
@@ -25,6 +29,11 @@
2529
position: relative;
2630
vertical-align: middle;
2731
white-space: nowrap;
32+
33+
a {
34+
display: grid;
35+
place-content: center;
36+
}
2837
}
2938

3039
.modebar-btn {
@@ -36,15 +45,20 @@
3645
cursor: pointer;
3746
line-height: normal;
3847
box-sizing: border-box;
48+
border: none;
49+
background: transparent;
3950

4051
svg {
4152
position: relative;
42-
top: 2px;
4353
}
4454

45-
&.modebar-btn--logo {
46-
55+
&:focus-visible {
56+
outline: 1px solid black;
57+
outline-offset: 1px;
58+
border-radius: 3px;
4759
}
60+
61+
&.modebar-btn--logo {}
4862
}
4963

5064
.modebar.vertical {
@@ -53,9 +67,11 @@
5367
flex-wrap: wrap;
5468
align-content: flex-end;
5569
max-height: 100%;
70+
5671
svg {
57-
top: -1px;
72+
top: -1px;
5873
}
74+
5975
.modebar-group {
6076
display: block;
6177
float: none;
@@ -67,4 +83,4 @@
6783
text-align: center;
6884
}
6985
}
70-
}
86+
}

‎test/jasmine/tests/modebar_test.js‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ describe('ModeBar', function() {
6969
}
7070

7171
function countButtons(modeBar) {
72-
return d3Select(modeBar.element).selectAll('a.modebar-btn').size();
72+
return d3Select(modeBar.element).selectAll('button.modebar-btn, a.modebar-btn').size();
7373
}
7474

7575
function countLogo(modeBar) {
7676
return d3Select(modeBar.element).selectAll('a.plotlyjsicon').size();
7777
}
7878

7979
function checkBtnAttr(modeBar, index, attr) {
80-
var buttons = d3Select(modeBar.element).selectAll('a.modebar-btn');
80+
var buttons = d3Select(modeBar.element).selectAll('button.modebar-btn, a.modebar-btn');
8181
return d3Select(buttons[0][index]).attr(attr);
8282
}
8383

@@ -1676,7 +1676,7 @@ describe('ModeBar', function() {
16761676
it('add predefined shape drawing and hover buttons via layout.modebar.add', function(done) {
16771677
function countButtons() {
16781678
var modeBarEl = gd._fullLayout._modeBar.element;
1679-
return d3Select(modeBarEl).selectAll('a.modebar-btn').size();
1679+
return d3Select(modeBarEl).selectAll('button.modebar-btn, a.modebar-btn').size();
16801680
}
16811681

16821682
var initial = 10;
@@ -1761,7 +1761,7 @@ describe('ModeBar', function() {
17611761
it('remove buttons using exact (camel case) and short (lower case) names via layout.modebar.remove and template', function(done) {
17621762
function countButtons() {
17631763
var modeBarEl = gd._fullLayout._modeBar.element;
1764-
return d3Select(modeBarEl).selectAll('a.modebar-btn').size();
1764+
return d3Select(modeBarEl).selectAll('button.modebar-btn, a.modebar-btn').size();
17651765
}
17661766

17671767
var initial = 10;
@@ -1842,7 +1842,7 @@ describe('ModeBar', function() {
18421842
it('add buttons using template', function(done) {
18431843
function countButtons() {
18441844
var modeBarEl = gd._fullLayout._modeBar.element;
1845-
return d3Select(modeBarEl).selectAll('a.modebar-btn').size();
1845+
return d3Select(modeBarEl).selectAll('button.modebar-btn, a.modebar-btn').size();
18461846
}
18471847

18481848
var initial = 10;
@@ -1865,7 +1865,7 @@ describe('ModeBar', function() {
18651865
it('add ' + t + ' button if removed by layout and added by config', function(done) {
18661866
function countButtons() {
18671867
var modeBarEl = gd._fullLayout._modeBar.element;
1868-
return d3Select(modeBarEl).selectAll('a.modebar-btn').size();
1868+
return d3Select(modeBarEl).selectAll('button.modebar-btn, a.modebar-btn').size();
18691869
}
18701870

18711871
var initial = 10;
@@ -1886,7 +1886,7 @@ describe('ModeBar', function() {
18861886
it('remove button if added by layout and removed by config', function(done) {
18871887
function countButtons() {
18881888
var modeBarEl = gd._fullLayout._modeBar.element;
1889-
return d3Select(modeBarEl).selectAll('a.modebar-btn').size();
1889+
return d3Select(modeBarEl).selectAll('button.modebar-btn, a.modebar-btn').size();
18901890
}
18911891

18921892
var initial = 10;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /