@instructure/ui-menu 10.10.1-snapshot-9 → 10.10.1-snapshot-14

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/CHANGELOG.md CHANGED
@@ -3,12 +3,13 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ## [10.10.1-snapshot-9](https://github.com/instructure/instructure-ui/compare/v10.10.0...v10.10.1-snapshot-9) (2025-02-03)
6
+ ## [10.10.1-snapshot-14](https://github.com/instructure/instructure-ui/compare/v10.10.0...v10.10.1-snapshot-14) (2025-02-03)
7
7
 
8
8
 
9
9
  ### Bug Fixes
10
10
 
11
11
  * **ui-menu:** make Menu.Item apply target prop ([6c85b31](https://github.com/instructure/instructure-ui/commit/6c85b312212edf9f08317d0d6aeb7c28fe1eb3b3))
12
+ * **ui-menu:** screenreaders should read the correct number of menu items ([0670648](https://github.com/instructure/instructure-ui/commit/06706488cd4b550594f7a5b2b52ea674c79b0530))
12
13
 
13
14
 
14
15
 
@@ -141,8 +141,6 @@ let MenuItem = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle, g
141
141
  return 'menuitemcheckbox';
142
142
  case 'radio':
143
143
  return 'menuitemradio';
144
- case 'flyout':
145
- return 'button';
146
144
  default:
147
145
  return 'menuitem';
148
146
  }
@@ -1,4 +1,4 @@
1
- var _MenuItemGroup, _MenuItemGroup2, _MenuItemGroup3, _MenuItemGroup4, _MenuItemGroup5, _MenuItemGroup6, _MenuItem, _MenuItem2, _MenuItemSeparator, _MenuItem3, _MenuItem4, _MenuItemSeparator2, _MenuItem5, _MenuItem6, _MenuItem7, _MenuItem8, _MenuItemSeparator3, _MenuItem9, _MenuItem10, _MenuItemSeparator4;
1
+ var _MenuItemGroup, _MenuItemGroup2, _MenuItemGroup3, _MenuItemGroup4, _MenuItem, _MenuItem2, _MenuItemSeparator, _MenuItem3, _MenuItem4, _MenuItemSeparator2, _MenuItem5, _MenuItem6, _MenuItem7, _MenuItem8, _MenuItemSeparator3, _MenuItem9, _MenuItem10, _MenuItemSeparator4;
2
2
  /*
3
3
  * The MIT License (MIT)
4
4
  *
@@ -36,40 +36,21 @@ describe('<MenuItemGroup />', () => {
36
36
  label: "Menu Label"
37
37
  }, /*#__PURE__*/React.createElement(MenuItem, null, "Item Text 1"), /*#__PURE__*/React.createElement(MenuItem, null, "Item Text 2"), /*#__PURE__*/React.createElement(MenuItemSeparator, null)))),
38
38
  container = _render.container;
39
- const group = container.querySelector("[id*='MenuItemGroup_']");
40
- const groupMenu = screen.getByRole('menu');
39
+ const group = container.querySelector("[class*='menuItemGroup']");
41
40
  expect(group).toBeInTheDocument();
42
41
  expect(group).toHaveTextContent('Menu Label');
43
- expect(groupMenu).toBeInTheDocument();
44
- expect(groupMenu).toHaveTextContent('Item Text 1');
45
- expect(groupMenu).toHaveTextContent('Item Text 2');
46
- });
47
- it('should set the role to "menu"', () => {
48
- const _render2 = render(_MenuItemGroup2 || (_MenuItemGroup2 = /*#__PURE__*/React.createElement(MenuItemGroup, {
49
- label: "Select one"
50
- }, /*#__PURE__*/React.createElement(MenuItem, null, "Foo"), /*#__PURE__*/React.createElement(MenuItem, null, "Bar"), /*#__PURE__*/React.createElement(MenuItemSeparator, null)))),
51
- container = _render2.container;
52
- const menuItemGroup = container.querySelector("[class*='menuItemGroup__items']");
53
- expect(menuItemGroup).toHaveAttribute('role', 'menu');
54
- });
55
- it('should set the list item role to "none"', () => {
56
- render(_MenuItemGroup3 || (_MenuItemGroup3 = /*#__PURE__*/React.createElement(MenuItemGroup, {
57
- label: "Select one"
58
- }, /*#__PURE__*/React.createElement(MenuItem, null, "Food"), /*#__PURE__*/React.createElement(MenuItem, null, "Bar"))));
59
- const menu = screen.getByRole('menu');
60
- const menuListItem = menu.firstChild;
61
- expect(menuListItem.tagName).toBe('LI');
62
- expect(menuListItem).toHaveAttribute('role', 'none');
42
+ expect(group).toHaveTextContent('Item Text 1');
43
+ expect(group).toHaveTextContent('Item Text 2');
63
44
  });
64
45
  it('should default to children with type "radio"', () => {
65
- render(_MenuItemGroup4 || (_MenuItemGroup4 = /*#__PURE__*/React.createElement(MenuItemGroup, {
46
+ render(_MenuItemGroup2 || (_MenuItemGroup2 = /*#__PURE__*/React.createElement(MenuItemGroup, {
66
47
  label: "Select one"
67
48
  }, /*#__PURE__*/React.createElement(MenuItem, null, "Foo"), /*#__PURE__*/React.createElement(MenuItem, null, "Bar"), /*#__PURE__*/React.createElement(MenuItemSeparator, null))));
68
49
  const menuItems = screen.getAllByRole('menuitemradio');
69
50
  expect(menuItems).toHaveLength(2);
70
51
  });
71
52
  it('should render children with type "checkbox" if allowMultiple is true', () => {
72
- render(_MenuItemGroup5 || (_MenuItemGroup5 = /*#__PURE__*/React.createElement(MenuItemGroup, {
53
+ render(_MenuItemGroup3 || (_MenuItemGroup3 = /*#__PURE__*/React.createElement(MenuItemGroup, {
73
54
  label: "Select a few",
74
55
  allowMultiple: true
75
56
  }, /*#__PURE__*/React.createElement(MenuItem, null, "Foo"), /*#__PURE__*/React.createElement(MenuItem, null, "Bar"), /*#__PURE__*/React.createElement(MenuItemSeparator, null))));
@@ -77,13 +58,11 @@ describe('<MenuItemGroup />', () => {
77
58
  expect(menuItems).toHaveLength(2);
78
59
  });
79
60
  it('should set aria-disabled', () => {
80
- render(_MenuItemGroup6 || (_MenuItemGroup6 = /*#__PURE__*/React.createElement(MenuItemGroup, {
61
+ render(_MenuItemGroup4 || (_MenuItemGroup4 = /*#__PURE__*/React.createElement(MenuItemGroup, {
81
62
  label: "Select one",
82
63
  disabled: true
83
64
  }, /*#__PURE__*/React.createElement(MenuItem, null, "Foo"), /*#__PURE__*/React.createElement(MenuItem, null, "Bar"), /*#__PURE__*/React.createElement(MenuItemSeparator, null))));
84
- const menu = screen.getByRole('menu');
85
65
  const menuItems = screen.getAllByRole('menuitemradio');
86
- expect(menu).toHaveAttribute('aria-disabled', 'true');
87
66
  expect(menuItems).toHaveLength(2);
88
67
  expect(menuItems[0]).toHaveAttribute('aria-disabled', 'true');
89
68
  expect(menuItems[1]).toHaveAttribute('aria-disabled', 'true');
@@ -42,7 +42,6 @@ id: Menu.Group
42
42
  let MenuItemGroup = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle, generateComponentTheme), _dec3 = testable(), _dec(_class = _dec2(_class = _dec3(_class = (_MenuItemGroup = class MenuItemGroup extends Component {
43
43
  constructor(props) {
44
44
  super(props);
45
- this._labelId = void 0;
46
45
  this.ref = null;
47
46
  this.handleRef = el => {
48
47
  this.ref = el;
@@ -84,7 +83,6 @@ let MenuItemGroup = (_dec = withDeterministicId(), _dec2 = withStyle(generateSty
84
83
  selected: this.selectedFromChildren(props) || props.defaultSelected
85
84
  };
86
85
  }
87
- this._labelId = props.deterministicId('MenuItemGroup');
88
86
  }
89
87
  componentDidMount() {
90
88
  var _this$props$makeStyle, _this$props;
@@ -135,9 +133,7 @@ let MenuItemGroup = (_dec = withDeterministicId(), _dec2 = withStyle(generateSty
135
133
  if (matchComponentTypes(child, [MenuItem])) {
136
134
  ++index;
137
135
  const value = child.props.value || index;
138
- return jsx("li", {
139
- role: "none"
140
- }, ' ', safeCloneElement(child, {
136
+ return safeCloneElement(child, {
141
137
  tabIndex: isTabbable && index === 0 ? 0 : -1,
142
138
  controls,
143
139
  value,
@@ -148,7 +144,7 @@ let MenuItemGroup = (_dec = withDeterministicId(), _dec2 = withStyle(generateSty
148
144
  selected: this.selected.indexOf(value) > -1,
149
145
  onSelect: this.handleSelect,
150
146
  onMouseOver
151
- }), ' ');
147
+ });
152
148
  } else {
153
149
  return child;
154
150
  }
@@ -159,15 +155,10 @@ let MenuItemGroup = (_dec = withDeterministicId(), _dec2 = withStyle(generateSty
159
155
  const props = omitProps(this.props, MenuItemGroup.allowedProps);
160
156
  return jsx("span", Object.assign({}, props, {
161
157
  css: (_this$props$styles2 = this.props.styles) === null || _this$props$styles2 === void 0 ? void 0 : _this$props$styles2.menuItemGroup,
162
- role: "presentation",
163
158
  ref: this.handleRef
164
- }), jsx("span", {
165
- id: this._labelId
166
- }, this.renderLabel()), jsx("ul", {
167
- role: "menu",
159
+ }), this.renderLabel(), jsx("div", {
168
160
  css: (_this$props$styles3 = this.props.styles) === null || _this$props$styles3 === void 0 ? void 0 : _this$props$styles3.items,
169
- "aria-disabled": this.props.disabled ? 'true' : void 0,
170
- "aria-labelledby": this._labelId
161
+ "aria-disabled": this.props.disabled ? 'true' : void 0
171
162
  }, this.renderChildren()));
172
163
  }
173
164
  }, _MenuItemGroup.displayName = "MenuItemGroup", _MenuItemGroup.componentId = 'Menu.Group', _MenuItemGroup.propTypes = propTypes, _MenuItemGroup.allowedProps = allowedProps, _MenuItemGroup.defaultProps = {
@@ -57,6 +57,8 @@ let MenuItemSeparator = (_dec = withStyle(generateStyle, generateComponentTheme)
57
57
  render() {
58
58
  var _this$props$styles;
59
59
  const props = omitProps(this.props, MenuItemSeparator.allowedProps);
60
+ // role="separator" would fit better here, but it causes NVDA to stop the
61
+ // MenuItem count after it
60
62
  return jsx("div", Object.assign({}, props, {
61
63
  role: "presentation",
62
64
  css: (_this$props$styles = this.props.styles) === null || _this$props$styles === void 0 ? void 0 : _this$props$styles.menuItemSeparator,
package/es/Menu/index.js CHANGED
@@ -235,16 +235,12 @@ let Menu = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle, gener
235
235
  count += 1;
236
236
  const isTabbable = !this.state.hasFocus && count === 1;
237
237
  if (matchComponentTypes(child, ['MenuItemSeparator'])) {
238
- return jsx("li", {
239
- role: "none"
240
- }, child);
238
+ return child;
241
239
  }
242
240
  const menuItemChild = child;
243
241
  const controls = menuItemChild.props['aria-controls'] || menuItemChild.props.controls || this.props['aria-controls'] || this.props.controls;
244
242
  if (matchComponentTypes(child, ['MenuItem'])) {
245
- return jsx("li", {
246
- role: "none"
247
- }, safeCloneElement(child, {
243
+ return safeCloneElement(child, {
248
244
  controls,
249
245
  children: child.props.children,
250
246
  disabled: disabled || child.props.disabled,
@@ -253,12 +249,10 @@ let Menu = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle, gener
253
249
  onSelect: this.handleMenuItemSelect,
254
250
  onMouseOver: this.handleMenuItemMouseOver,
255
251
  tabIndex: isTabbable ? 0 : -1
256
- }));
252
+ });
257
253
  }
258
254
  if (matchComponentTypes(child, ['MenuItemGroup'])) {
259
- return jsx("li", {
260
- role: "none"
261
- }, safeCloneElement(child, {
255
+ return safeCloneElement(child, {
262
256
  label: child.props.label,
263
257
  controls,
264
258
  disabled: disabled || child.props.disabled,
@@ -267,13 +261,11 @@ let Menu = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle, gener
267
261
  onSelect: this.handleMenuItemSelect,
268
262
  onMouseOver: this.handleMenuItemMouseOver,
269
263
  isTabbable
270
- }));
264
+ });
271
265
  }
272
266
  if (matchComponentTypes(child, ['Menu'])) {
273
267
  const submenuDisabled = disabled || child.props.disabled;
274
- return jsx("li", {
275
- role: "none"
276
- }, safeCloneElement(child, {
268
+ return safeCloneElement(child, {
277
269
  type: 'flyout',
278
270
  controls,
279
271
  disabled: submenuDisabled,
@@ -293,7 +285,7 @@ let Menu = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle, gener
293
285
  disabled: submenuDisabled,
294
286
  renderLabelInfo: child.props.renderLabelInfo
295
287
  }, child.props.title || child.props.label)
296
- }));
288
+ });
297
289
  }
298
290
  return;
299
291
  });
@@ -312,7 +304,7 @@ let Menu = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle, gener
312
304
  removeMenuItem: this.removeMenuItem,
313
305
  registerMenuItem: this.registerMenuItem
314
306
  }
315
- }, jsx("ul", {
307
+ }, jsx("div", {
316
308
  role: "menu",
317
309
  "aria-label": label,
318
310
  tabIndex: 0,
@@ -154,8 +154,6 @@ let MenuItem = exports.MenuItem = (_dec = (0, _withDeterministicId.withDetermini
154
154
  return 'menuitemcheckbox';
155
155
  case 'radio':
156
156
  return 'menuitemradio';
157
- case 'flyout':
158
- return 'button';
159
157
  default:
160
158
  return 'menuitem';
161
159
  }
@@ -8,7 +8,7 @@ require("@testing-library/jest-dom");
8
8
  var _MenuItem11 = require("../../MenuItem");
9
9
  var _MenuItemSeparator5 = require("../../MenuItemSeparator");
10
10
  var _index = require("../index");
11
- var _MenuItemGroup, _MenuItemGroup2, _MenuItemGroup3, _MenuItemGroup4, _MenuItemGroup5, _MenuItemGroup6, _MenuItem, _MenuItem2, _MenuItemSeparator, _MenuItem3, _MenuItem4, _MenuItemSeparator2, _MenuItem5, _MenuItem6, _MenuItem7, _MenuItem8, _MenuItemSeparator3, _MenuItem9, _MenuItem10, _MenuItemSeparator4;
11
+ var _MenuItemGroup, _MenuItemGroup2, _MenuItemGroup3, _MenuItemGroup4, _MenuItem, _MenuItem2, _MenuItemSeparator, _MenuItem3, _MenuItem4, _MenuItemSeparator2, _MenuItem5, _MenuItem6, _MenuItem7, _MenuItem8, _MenuItemSeparator3, _MenuItem9, _MenuItem10, _MenuItemSeparator4;
12
12
  /*
13
13
  * The MIT License (MIT)
14
14
  *
@@ -38,40 +38,21 @@ describe('<MenuItemGroup />', () => {
38
38
  label: "Menu Label"
39
39
  }, /*#__PURE__*/_react.default.createElement(_MenuItem11.MenuItem, null, "Item Text 1"), /*#__PURE__*/_react.default.createElement(_MenuItem11.MenuItem, null, "Item Text 2"), /*#__PURE__*/_react.default.createElement(_MenuItemSeparator5.MenuItemSeparator, null)))),
40
40
  container = _render.container;
41
- const group = container.querySelector("[id*='MenuItemGroup_']");
42
- const groupMenu = _react2.screen.getByRole('menu');
41
+ const group = container.querySelector("[class*='menuItemGroup']");
43
42
  expect(group).toBeInTheDocument();
44
43
  expect(group).toHaveTextContent('Menu Label');
45
- expect(groupMenu).toBeInTheDocument();
46
- expect(groupMenu).toHaveTextContent('Item Text 1');
47
- expect(groupMenu).toHaveTextContent('Item Text 2');
48
- });
49
- it('should set the role to "menu"', () => {
50
- const _render2 = (0, _react2.render)(_MenuItemGroup2 || (_MenuItemGroup2 = /*#__PURE__*/_react.default.createElement(_index.MenuItemGroup, {
51
- label: "Select one"
52
- }, /*#__PURE__*/_react.default.createElement(_MenuItem11.MenuItem, null, "Foo"), /*#__PURE__*/_react.default.createElement(_MenuItem11.MenuItem, null, "Bar"), /*#__PURE__*/_react.default.createElement(_MenuItemSeparator5.MenuItemSeparator, null)))),
53
- container = _render2.container;
54
- const menuItemGroup = container.querySelector("[class*='menuItemGroup__items']");
55
- expect(menuItemGroup).toHaveAttribute('role', 'menu');
56
- });
57
- it('should set the list item role to "none"', () => {
58
- (0, _react2.render)(_MenuItemGroup3 || (_MenuItemGroup3 = /*#__PURE__*/_react.default.createElement(_index.MenuItemGroup, {
59
- label: "Select one"
60
- }, /*#__PURE__*/_react.default.createElement(_MenuItem11.MenuItem, null, "Food"), /*#__PURE__*/_react.default.createElement(_MenuItem11.MenuItem, null, "Bar"))));
61
- const menu = _react2.screen.getByRole('menu');
62
- const menuListItem = menu.firstChild;
63
- expect(menuListItem.tagName).toBe('LI');
64
- expect(menuListItem).toHaveAttribute('role', 'none');
44
+ expect(group).toHaveTextContent('Item Text 1');
45
+ expect(group).toHaveTextContent('Item Text 2');
65
46
  });
66
47
  it('should default to children with type "radio"', () => {
67
- (0, _react2.render)(_MenuItemGroup4 || (_MenuItemGroup4 = /*#__PURE__*/_react.default.createElement(_index.MenuItemGroup, {
48
+ (0, _react2.render)(_MenuItemGroup2 || (_MenuItemGroup2 = /*#__PURE__*/_react.default.createElement(_index.MenuItemGroup, {
68
49
  label: "Select one"
69
50
  }, /*#__PURE__*/_react.default.createElement(_MenuItem11.MenuItem, null, "Foo"), /*#__PURE__*/_react.default.createElement(_MenuItem11.MenuItem, null, "Bar"), /*#__PURE__*/_react.default.createElement(_MenuItemSeparator5.MenuItemSeparator, null))));
70
51
  const menuItems = _react2.screen.getAllByRole('menuitemradio');
71
52
  expect(menuItems).toHaveLength(2);
72
53
  });
73
54
  it('should render children with type "checkbox" if allowMultiple is true', () => {
74
- (0, _react2.render)(_MenuItemGroup5 || (_MenuItemGroup5 = /*#__PURE__*/_react.default.createElement(_index.MenuItemGroup, {
55
+ (0, _react2.render)(_MenuItemGroup3 || (_MenuItemGroup3 = /*#__PURE__*/_react.default.createElement(_index.MenuItemGroup, {
75
56
  label: "Select a few",
76
57
  allowMultiple: true
77
58
  }, /*#__PURE__*/_react.default.createElement(_MenuItem11.MenuItem, null, "Foo"), /*#__PURE__*/_react.default.createElement(_MenuItem11.MenuItem, null, "Bar"), /*#__PURE__*/_react.default.createElement(_MenuItemSeparator5.MenuItemSeparator, null))));
@@ -79,13 +60,11 @@ describe('<MenuItemGroup />', () => {
79
60
  expect(menuItems).toHaveLength(2);
80
61
  });
81
62
  it('should set aria-disabled', () => {
82
- (0, _react2.render)(_MenuItemGroup6 || (_MenuItemGroup6 = /*#__PURE__*/_react.default.createElement(_index.MenuItemGroup, {
63
+ (0, _react2.render)(_MenuItemGroup4 || (_MenuItemGroup4 = /*#__PURE__*/_react.default.createElement(_index.MenuItemGroup, {
83
64
  label: "Select one",
84
65
  disabled: true
85
66
  }, /*#__PURE__*/_react.default.createElement(_MenuItem11.MenuItem, null, "Foo"), /*#__PURE__*/_react.default.createElement(_MenuItem11.MenuItem, null, "Bar"), /*#__PURE__*/_react.default.createElement(_MenuItemSeparator5.MenuItemSeparator, null))));
86
- const menu = _react2.screen.getByRole('menu');
87
67
  const menuItems = _react2.screen.getAllByRole('menuitemradio');
88
- expect(menu).toHaveAttribute('aria-disabled', 'true');
89
68
  expect(menuItems).toHaveLength(2);
90
69
  expect(menuItems[0]).toHaveAttribute('aria-disabled', 'true');
91
70
  expect(menuItems[1]).toHaveAttribute('aria-disabled', 'true');
@@ -52,7 +52,6 @@ id: Menu.Group
52
52
  let MenuItemGroup = exports.MenuItemGroup = (_dec = (0, _withDeterministicId.withDeterministicId)(), _dec2 = (0, _emotion.withStyle)(_styles.default, _theme.default), _dec3 = (0, _testable.testable)(), _dec(_class = _dec2(_class = _dec3(_class = (_MenuItemGroup = class MenuItemGroup extends _react.Component {
53
53
  constructor(props) {
54
54
  super(props);
55
- this._labelId = void 0;
56
55
  this.ref = null;
57
56
  this.handleRef = el => {
58
57
  this.ref = el;
@@ -94,7 +93,6 @@ let MenuItemGroup = exports.MenuItemGroup = (_dec = (0, _withDeterministicId.wit
94
93
  selected: this.selectedFromChildren(props) || props.defaultSelected
95
94
  };
96
95
  }
97
- this._labelId = props.deterministicId('MenuItemGroup');
98
96
  }
99
97
  componentDidMount() {
100
98
  var _this$props$makeStyle, _this$props;
@@ -145,9 +143,7 @@ let MenuItemGroup = exports.MenuItemGroup = (_dec = (0, _withDeterministicId.wit
145
143
  if ((0, _matchComponentTypes.matchComponentTypes)(child, [_MenuItem.MenuItem])) {
146
144
  ++index;
147
145
  const value = child.props.value || index;
148
- return (0, _emotion.jsx)("li", {
149
- role: "none"
150
- }, ' ', (0, _safeCloneElement.safeCloneElement)(child, {
146
+ return (0, _safeCloneElement.safeCloneElement)(child, {
151
147
  tabIndex: isTabbable && index === 0 ? 0 : -1,
152
148
  controls,
153
149
  value,
@@ -158,7 +154,7 @@ let MenuItemGroup = exports.MenuItemGroup = (_dec = (0, _withDeterministicId.wit
158
154
  selected: this.selected.indexOf(value) > -1,
159
155
  onSelect: this.handleSelect,
160
156
  onMouseOver
161
- }), ' ');
157
+ });
162
158
  } else {
163
159
  return child;
164
160
  }
@@ -169,15 +165,10 @@ let MenuItemGroup = exports.MenuItemGroup = (_dec = (0, _withDeterministicId.wit
169
165
  const props = (0, _omitProps.omitProps)(this.props, MenuItemGroup.allowedProps);
170
166
  return (0, _emotion.jsx)("span", Object.assign({}, props, {
171
167
  css: (_this$props$styles2 = this.props.styles) === null || _this$props$styles2 === void 0 ? void 0 : _this$props$styles2.menuItemGroup,
172
- role: "presentation",
173
168
  ref: this.handleRef
174
- }), (0, _emotion.jsx)("span", {
175
- id: this._labelId
176
- }, this.renderLabel()), (0, _emotion.jsx)("ul", {
177
- role: "menu",
169
+ }), this.renderLabel(), (0, _emotion.jsx)("div", {
178
170
  css: (_this$props$styles3 = this.props.styles) === null || _this$props$styles3 === void 0 ? void 0 : _this$props$styles3.items,
179
- "aria-disabled": this.props.disabled ? 'true' : void 0,
180
- "aria-labelledby": this._labelId
171
+ "aria-disabled": this.props.disabled ? 'true' : void 0
181
172
  }, this.renderChildren()));
182
173
  }
183
174
  }, _MenuItemGroup.displayName = "MenuItemGroup", _MenuItemGroup.componentId = 'Menu.Group', _MenuItemGroup.propTypes = _props.propTypes, _MenuItemGroup.allowedProps = _props.allowedProps, _MenuItemGroup.defaultProps = {
@@ -63,6 +63,8 @@ let MenuItemSeparator = exports.MenuItemSeparator = (_dec = (0, _emotion.withSty
63
63
  render() {
64
64
  var _this$props$styles;
65
65
  const props = (0, _omitProps.omitProps)(this.props, MenuItemSeparator.allowedProps);
66
+ // role="separator" would fit better here, but it causes NVDA to stop the
67
+ // MenuItem count after it
66
68
  return (0, _emotion.jsx)("div", Object.assign({}, props, {
67
69
  role: "presentation",
68
70
  css: (_this$props$styles = this.props.styles) === null || _this$props$styles === void 0 ? void 0 : _this$props$styles.menuItemSeparator,
package/lib/Menu/index.js CHANGED
@@ -264,16 +264,12 @@ let Menu = exports.Menu = (_dec = (0, _withDeterministicId.withDeterministicId)(
264
264
  count += 1;
265
265
  const isTabbable = !this.state.hasFocus && count === 1;
266
266
  if ((0, _matchComponentTypes.matchComponentTypes)(child, ['MenuItemSeparator'])) {
267
- return (0, _emotion.jsx)("li", {
268
- role: "none"
269
- }, child);
267
+ return child;
270
268
  }
271
269
  const menuItemChild = child;
272
270
  const controls = menuItemChild.props['aria-controls'] || menuItemChild.props.controls || this.props['aria-controls'] || this.props.controls;
273
271
  if ((0, _matchComponentTypes.matchComponentTypes)(child, ['MenuItem'])) {
274
- return (0, _emotion.jsx)("li", {
275
- role: "none"
276
- }, (0, _safeCloneElement.safeCloneElement)(child, {
272
+ return (0, _safeCloneElement.safeCloneElement)(child, {
277
273
  controls,
278
274
  children: child.props.children,
279
275
  disabled: disabled || child.props.disabled,
@@ -282,12 +278,10 @@ let Menu = exports.Menu = (_dec = (0, _withDeterministicId.withDeterministicId)(
282
278
  onSelect: this.handleMenuItemSelect,
283
279
  onMouseOver: this.handleMenuItemMouseOver,
284
280
  tabIndex: isTabbable ? 0 : -1
285
- }));
281
+ });
286
282
  }
287
283
  if ((0, _matchComponentTypes.matchComponentTypes)(child, ['MenuItemGroup'])) {
288
- return (0, _emotion.jsx)("li", {
289
- role: "none"
290
- }, (0, _safeCloneElement.safeCloneElement)(child, {
284
+ return (0, _safeCloneElement.safeCloneElement)(child, {
291
285
  label: child.props.label,
292
286
  controls,
293
287
  disabled: disabled || child.props.disabled,
@@ -296,13 +290,11 @@ let Menu = exports.Menu = (_dec = (0, _withDeterministicId.withDeterministicId)(
296
290
  onSelect: this.handleMenuItemSelect,
297
291
  onMouseOver: this.handleMenuItemMouseOver,
298
292
  isTabbable
299
- }));
293
+ });
300
294
  }
301
295
  if ((0, _matchComponentTypes.matchComponentTypes)(child, ['Menu'])) {
302
296
  const submenuDisabled = disabled || child.props.disabled;
303
- return (0, _emotion.jsx)("li", {
304
- role: "none"
305
- }, (0, _safeCloneElement.safeCloneElement)(child, {
297
+ return (0, _safeCloneElement.safeCloneElement)(child, {
306
298
  type: 'flyout',
307
299
  controls,
308
300
  disabled: submenuDisabled,
@@ -322,7 +314,7 @@ let Menu = exports.Menu = (_dec = (0, _withDeterministicId.withDeterministicId)(
322
314
  disabled: submenuDisabled,
323
315
  renderLabelInfo: child.props.renderLabelInfo
324
316
  }, child.props.title || child.props.label)
325
- }));
317
+ });
326
318
  }
327
319
  return;
328
320
  });
@@ -341,7 +333,7 @@ let Menu = exports.Menu = (_dec = (0, _withDeterministicId.withDeterministicId)(
341
333
  removeMenuItem: this.removeMenuItem,
342
334
  registerMenuItem: this.registerMenuItem
343
335
  }
344
- }, (0, _emotion.jsx)("ul", {
336
+ }, (0, _emotion.jsx)("div", {
345
337
  role: "menu",
346
338
  "aria-label": label,
347
339
  tabIndex: 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/ui-menu",
3
- "version": "10.10.1-snapshot-9",
3
+ "version": "10.10.1-snapshot-14",
4
4
  "description": "A dropdown menu component",
5
5
  "author": "Instructure, Inc. Engineering and Product Design",
6
6
  "module": "./es/index.js",
@@ -23,11 +23,11 @@
23
23
  },
24
24
  "license": "MIT",
25
25
  "devDependencies": {
26
- "@instructure/ui-axe-check": "10.10.1-snapshot-9",
27
- "@instructure/ui-babel-preset": "10.10.1-snapshot-9",
28
- "@instructure/ui-color-utils": "10.10.1-snapshot-9",
29
- "@instructure/ui-test-utils": "10.10.1-snapshot-9",
30
- "@instructure/ui-themes": "10.10.1-snapshot-9",
26
+ "@instructure/ui-axe-check": "10.10.1-snapshot-14",
27
+ "@instructure/ui-babel-preset": "10.10.1-snapshot-14",
28
+ "@instructure/ui-color-utils": "10.10.1-snapshot-14",
29
+ "@instructure/ui-test-utils": "10.10.1-snapshot-14",
30
+ "@instructure/ui-themes": "10.10.1-snapshot-14",
31
31
  "@testing-library/jest-dom": "^6.6.3",
32
32
  "@testing-library/react": "^16.0.1",
33
33
  "@testing-library/user-event": "^14.5.2",
@@ -35,19 +35,19 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@babel/runtime": "^7.26.0",
38
- "@instructure/console": "10.10.1-snapshot-9",
39
- "@instructure/emotion": "10.10.1-snapshot-9",
40
- "@instructure/shared-types": "10.10.1-snapshot-9",
41
- "@instructure/ui-a11y-utils": "10.10.1-snapshot-9",
42
- "@instructure/ui-dom-utils": "10.10.1-snapshot-9",
43
- "@instructure/ui-icons": "10.10.1-snapshot-9",
44
- "@instructure/ui-popover": "10.10.1-snapshot-9",
45
- "@instructure/ui-position": "10.10.1-snapshot-9",
46
- "@instructure/ui-prop-types": "10.10.1-snapshot-9",
47
- "@instructure/ui-react-utils": "10.10.1-snapshot-9",
48
- "@instructure/ui-testable": "10.10.1-snapshot-9",
49
- "@instructure/ui-utils": "10.10.1-snapshot-9",
50
- "@instructure/ui-view": "10.10.1-snapshot-9",
38
+ "@instructure/console": "10.10.1-snapshot-14",
39
+ "@instructure/emotion": "10.10.1-snapshot-14",
40
+ "@instructure/shared-types": "10.10.1-snapshot-14",
41
+ "@instructure/ui-a11y-utils": "10.10.1-snapshot-14",
42
+ "@instructure/ui-dom-utils": "10.10.1-snapshot-14",
43
+ "@instructure/ui-icons": "10.10.1-snapshot-14",
44
+ "@instructure/ui-popover": "10.10.1-snapshot-14",
45
+ "@instructure/ui-position": "10.10.1-snapshot-14",
46
+ "@instructure/ui-prop-types": "10.10.1-snapshot-14",
47
+ "@instructure/ui-react-utils": "10.10.1-snapshot-14",
48
+ "@instructure/ui-testable": "10.10.1-snapshot-14",
49
+ "@instructure/ui-utils": "10.10.1-snapshot-14",
50
+ "@instructure/ui-view": "10.10.1-snapshot-14",
51
51
  "keycode": "^2",
52
52
  "prop-types": "^15.8.1"
53
53
  },
@@ -187,8 +187,6 @@ class MenuItem extends Component<MenuItemProps, MenuItemState> {
187
187
  return 'menuitemcheckbox'
188
188
  case 'radio':
189
189
  return 'menuitemradio'
190
- case 'flyout':
191
- return 'button'
192
190
  default:
193
191
  return 'menuitem'
194
192
  }
@@ -40,44 +40,11 @@ describe('<MenuItemGroup />', () => {
40
40
  <MenuItemSeparator />
41
41
  </MenuItemGroup>
42
42
  )
43
- const group = container.querySelector("[id*='MenuItemGroup_']")
44
- const groupMenu = screen.getByRole('menu')
45
-
43
+ const group = container.querySelector("[class*='menuItemGroup']")
46
44
  expect(group).toBeInTheDocument()
47
45
  expect(group).toHaveTextContent('Menu Label')
48
-
49
- expect(groupMenu).toBeInTheDocument()
50
- expect(groupMenu).toHaveTextContent('Item Text 1')
51
- expect(groupMenu).toHaveTextContent('Item Text 2')
52
- })
53
-
54
- it('should set the role to "menu"', () => {
55
- const { container } = render(
56
- <MenuItemGroup label="Select one">
57
- <MenuItem>Foo</MenuItem>
58
- <MenuItem>Bar</MenuItem>
59
- <MenuItemSeparator />
60
- </MenuItemGroup>
61
- )
62
- const menuItemGroup = container.querySelector(
63
- "[class*='menuItemGroup__items']"
64
- )
65
-
66
- expect(menuItemGroup).toHaveAttribute('role', 'menu')
67
- })
68
-
69
- it('should set the list item role to "none"', () => {
70
- render(
71
- <MenuItemGroup label="Select one">
72
- <MenuItem>Food</MenuItem>
73
- <MenuItem>Bar</MenuItem>
74
- </MenuItemGroup>
75
- )
76
- const menu = screen.getByRole('menu')
77
- const menuListItem = menu.firstChild as HTMLElement
78
-
79
- expect(menuListItem.tagName).toBe('LI')
80
- expect(menuListItem).toHaveAttribute('role', 'none')
46
+ expect(group).toHaveTextContent('Item Text 1')
47
+ expect(group).toHaveTextContent('Item Text 2')
81
48
  })
82
49
 
83
50
  it('should default to children with type "radio"', () => {
@@ -114,10 +81,8 @@ describe('<MenuItemGroup />', () => {
114
81
  <MenuItemSeparator />
115
82
  </MenuItemGroup>
116
83
  )
117
- const menu = screen.getByRole('menu')
118
84
  const menuItems = screen.getAllByRole('menuitemradio')
119
85
 
120
- expect(menu).toHaveAttribute('aria-disabled', 'true')
121
86
  expect(menuItems).toHaveLength(2)
122
87
  expect(menuItems[0]).toHaveAttribute('aria-disabled', 'true')
123
88
  expect(menuItems[1]).toHaveAttribute('aria-disabled', 'true')
@@ -82,11 +82,8 @@ class MenuItemGroup extends Component<MenuGroupProps, MenuGroupState> {
82
82
  selected: this.selectedFromChildren(props) || props.defaultSelected!
83
83
  }
84
84
  }
85
-
86
- this._labelId = props.deterministicId!('MenuItemGroup')
87
85
  }
88
86
 
89
- private _labelId: string
90
87
  ref: Element | null = null
91
88
 
92
89
  handleRef = (el: Element | null) => {
@@ -210,23 +207,18 @@ class MenuItemGroup extends Component<MenuGroupProps, MenuGroupState> {
210
207
  ++index
211
208
  const value = child.props.value || index
212
209
 
213
- return (
214
- <li role="none">
215
- {' '}
216
- {safeCloneElement(child, {
217
- tabIndex: isTabbable && index === 0 ? 0 : -1,
218
- controls,
219
- value,
220
- children: child.props.children,
221
- type: allowMultiple ? 'checkbox' : 'radio',
222
- ref: this.props.itemRef,
223
- disabled: disabled || child.props.disabled,
224
- selected: this.selected.indexOf(value) > -1,
225
- onSelect: this.handleSelect,
226
- onMouseOver
227
- })}{' '}
228
- </li>
229
- )
210
+ return safeCloneElement(child, {
211
+ tabIndex: isTabbable && index === 0 ? 0 : -1,
212
+ controls,
213
+ value,
214
+ children: child.props.children,
215
+ type: allowMultiple ? 'checkbox' : 'radio',
216
+ ref: this.props.itemRef,
217
+ disabled: disabled || child.props.disabled,
218
+ selected: this.selected.indexOf(value) > -1,
219
+ onSelect: this.handleSelect,
220
+ onMouseOver
221
+ })
230
222
  } else {
231
223
  return child
232
224
  }
@@ -239,18 +231,15 @@ class MenuItemGroup extends Component<MenuGroupProps, MenuGroupState> {
239
231
  <span
240
232
  {...props}
241
233
  css={this.props.styles?.menuItemGroup}
242
- role="presentation"
243
234
  ref={this.handleRef}
244
235
  >
245
- <span id={this._labelId}>{this.renderLabel()}</span>
246
- <ul
247
- role="menu"
236
+ {this.renderLabel()}
237
+ <div
248
238
  css={this.props.styles?.items}
249
239
  aria-disabled={this.props.disabled ? 'true' : undefined}
250
- aria-labelledby={this._labelId}
251
240
  >
252
241
  {this.renderChildren()}
253
- </ul>
242
+ </div>
254
243
  </span>
255
244
  )
256
245
  }
@@ -66,6 +66,8 @@ class MenuItemSeparator extends Component<MenuSeparatorProps> {
66
66
 
67
67
  render() {
68
68
  const props = omitProps(this.props, MenuItemSeparator.allowedProps)
69
+ // role="separator" would fit better here, but it causes NVDA to stop the
70
+ // MenuItem count after it
69
71
  return (
70
72
  <div
71
73
  {...props}