Merge pull request #4897 from Gazook89/Accessible-Dropdowns

More Accessible Dropdowns
This commit is contained in:
Víctor Losada Hernández
2026-08-16 10:44:51 +02:00
committed by GitHub
4 changed files with 48 additions and 69 deletions
+6 -4
View File
@@ -92,12 +92,13 @@ const Dropdown = ({ groupName, className = null, icon, children, color = null, c
};
return (
<div className={['menu-wrapper', className].join(' ')} role='none' >
<li className='menu-wrapper' role='none'>
<button
id={`${menuId}-trigger`}
className={['menu-item', color].join(' ')}
popoverTarget={menuId}
aria-haspopup='menu'
aria-label={groupName}
role='menuitem'
disabled={!React.Children.count(children)}
ref={triggerRef}
@@ -105,18 +106,19 @@ const Dropdown = ({ groupName, className = null, icon, children, color = null, c
{trigger(groupName, icon)}
</button>
<MenuDepthContext.Provider value={depth + 1}>
<div
<ul
ref={menuRef}
id={menuId}
className='menu-list'
popover='auto'
role='menu'
aria-label={`${groupName} Submenu`}
onClick={handleMenuActionClick}
>
{children}
</div>
</ul>
</MenuDepthContext.Provider>
</div>
</li>
);
};
+19 -10
View File
@@ -1,24 +1,33 @@
.menu-wrapper {
position: relative;
&:is(.menu-bar > .menu-section > .menu-wrapper){
display: inline-block;
}
@property --menuColor {
syntax: '<color>';
inherits: true;
initial-value: #DDD;
}
@property --activeTriggerColor {
syntax: '<color>';
inherits: true;
initial-value: #DDD;
}
:root{
--activeTriggerColor : var(--activeTriggerColor);
}
.menu-list {
contain : content;
position : fixed;
z-index : 1000;
top : anchor(bottom);
left : anchor(left);
position-try: flip-inline flip-block;
color: inherit; // [popover] gets a `canvastext` color value from useragent.
> .menu-wrapper {
position:relative;
> .menu-list {
background: var(--menuColor);
li > .menu-list {
margin: 0 0px;
top : anchor(top);
left : anchor(right);
position-try: flip-inline;
}
}
}
.menu-wrapper:has(:popover-open) > button { // if menu is open...
background-color: var(--activeTriggerColor, hsl(from var(--menuColor) h s calc(l * .85))); // tint menu triggers based on menu color
}
@@ -188,7 +188,7 @@ const Snippetbar = createReactClass({
const snippets = this.state.snippets.filter((snippetGroup)=>snippetGroup.view === this.props.view);
if(snippets.length === 0) return null;
return <div className='snippets'>
return <ul className='snippets' role='menubar' aria-label='Snippets Menubar'>
{_.map(snippets, (snippetGroup)=>{
return <SnippetGroup
brew={this.props.brew}
@@ -201,7 +201,7 @@ const Snippetbar = createReactClass({
/>;
})
}
</div>;
</ul>;
},
replaceContent : function(item){
@@ -327,12 +327,14 @@ const SnippetGroup = createReactClass({
return _.map(snippets, (snippet)=>{
if(!snippet.subsnippets){
return (
<button className='menu-item' key={snippet.name} onClick={(e)=>this.handleSnippetClick(e, snippet)} role='menuitem'>
<i className={snippet.icon} />
<span className={`name${snippet.disabled ? ' disabled' : ''}`} title={snippet.name}>{snippet.name}</span>
{snippet.experimental && <span className='beta'>beta</span>}
{snippet.disabled && <span className='beta' title='temporarily disabled due to large slowdown; under re-design'>disabled</span>}
</button>
<li key={snippet.name} role='none'>
<button className='menu-item' onClick={(e)=>this.handleSnippetClick(e, snippet)} role='menuitem' aria-label={snippet.name} disabled={snippet.disabled}>
<i className={snippet.icon} />
<span className={`name${snippet.disabled ? ' disabled' : ''}`} title={snippet.name}>{snippet.name}</span>
{snippet.experimental && <span className='status'>beta</span>}
{snippet.disabled && <span className='status' title='temporarily disabled due to large slowdown; under re-design'>disabled</span>}
</button>
</li>
);
} else if(snippet.subsnippets){
return (
@@ -3,6 +3,8 @@
@import (less) '@themes/fonts/5e/fonts.less';
.snippetBar {
--activeTriggerColor: inherit;
--menuColor : #DDDDDD;
@menuHeight : 25px;
position : relative;
display : flex;
@@ -16,12 +18,6 @@
text-transform: uppercase;
font-weight: 800;
.snippets {
display : flex;
justify-content : flex-start;
min-width : 499.35px; //must be controlled every time an item is added, must be hardcoded for the wrapping as it is applied
}
.editors {
display : flex;
justify-content : flex-end;
@@ -118,23 +114,7 @@
}
}
}
.snippetBarButton {
display : inline-block;
height : @menuHeight;
padding : 0px 5px;
font-size : 0.625em;
font-weight : 800;
line-height : @menuHeight;
text-transform : uppercase;
text-wrap : nowrap;
cursor : pointer;
&:hover, &.selected { background-color : #999999; }
i {
margin-right : 3px;
font-size : 1.4em;
vertical-align : middle;
}
}
.toggleMeta {
position : absolute;
top : 0px;
@@ -143,20 +123,15 @@
.tooltipLeft('Edit Brew Properties');
}
.menu-wrapper {
.menu-item:is(.snippets > .menu-wrapper > .menu-item):first-child {
.caret {
display: none;
}
}
.menu-list {
padding : 0px;
background-color : #DDDDDD;
}
.snippets {
display : flex;
justify-content : flex-start;
min-width : 565.95px; //must be controlled every time an item is added, must be hardcoded for the wrapping as it is applied
}
// removed caret for top level items, by request (makes buttons too wide).
.menu-wrapper .menu-item:is(.snippets > .menu-wrapper > .menu-item):first-child .caret { display: none; }
.menu-item {
position : relative;
display : flex;
@@ -166,9 +141,8 @@
padding : 5px;
cursor : pointer;
width: 100%;
.animate(background-color);
&:is(.menu-list .menu-item) [class*="name"] {
padding-inline: 8px;
padding-inline: 8px; // additional space between icon and name (helpful in Fonts menu especially).
}
.menu-name {
flex: 1;
@@ -214,8 +188,7 @@
}
}
.name { margin-right : auto; }
.disabled { text-decoration : line-through; }
.beta {
.status {
align-self : center;
padding : 4px 6px;
margin-left : 5px;
@@ -234,15 +207,8 @@
&:hover { background-color: unset; }
}
}
.disabledSnippets {
color: grey;
cursor: not-allowed;
&:hover { background-color: #DDDDDD;}
}
}
@container editor (width < 750px) {
@container editor (width < 816px) {
.snippetBar {
.editors {
flex : 1;