@momentum-design/components 0.85.3 → 0.85.5

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.
Files changed (46) hide show
  1. package/dist/browser/index.js +238 -229
  2. package/dist/browser/index.js.map +4 -4
  3. package/dist/components/alertchip/alertchip.component.d.ts +2 -0
  4. package/dist/components/alertchip/alertchip.component.js +2 -0
  5. package/dist/components/avatar/avatar.component.d.ts +6 -0
  6. package/dist/components/avatar/avatar.component.js +6 -0
  7. package/dist/components/avatarbutton/avatarbutton.component.d.ts +9 -0
  8. package/dist/components/avatarbutton/avatarbutton.component.js +10 -0
  9. package/dist/components/formfieldwrapper/formfieldwrapper.component.d.ts +1 -1
  10. package/dist/components/formfieldwrapper/formfieldwrapper.component.js +1 -1
  11. package/dist/components/icon/icon.component.d.ts +2 -0
  12. package/dist/components/icon/icon.component.js +2 -0
  13. package/dist/components/listitem/listitem.component.d.ts +11 -0
  14. package/dist/components/listitem/listitem.component.js +11 -3
  15. package/dist/components/listitem/listitem.constants.d.ts +2 -2
  16. package/dist/components/listitem/listitem.constants.js +3 -2
  17. package/dist/components/listitem/listitem.styles.js +9 -1
  18. package/dist/components/menubar/menubar.component.d.ts +31 -5
  19. package/dist/components/menubar/menubar.component.js +198 -9
  20. package/dist/components/menubar/menubar.constants.d.ts +3 -4
  21. package/dist/components/menubar/menubar.constants.js +3 -4
  22. package/dist/components/menupopover/menupopover.component.d.ts +1 -0
  23. package/dist/components/menupopover/menupopover.component.js +13 -2
  24. package/dist/components/menupopover/menupopover.constants.d.ts +1 -0
  25. package/dist/components/menupopover/menupopover.constants.js +1 -0
  26. package/dist/components/navitemlist/navitemlist.component.d.ts +1 -2
  27. package/dist/components/navitemlist/navitemlist.component.js +1 -4
  28. package/dist/components/popover/popover.component.js +8 -2
  29. package/dist/custom-elements.json +942 -1997
  30. package/dist/react/alertchip/index.d.ts +2 -0
  31. package/dist/react/alertchip/index.js +2 -0
  32. package/dist/react/avatar/index.d.ts +6 -0
  33. package/dist/react/avatar/index.js +6 -0
  34. package/dist/react/avatarbutton/index.d.ts +9 -0
  35. package/dist/react/avatarbutton/index.js +9 -0
  36. package/dist/react/icon/index.d.ts +2 -0
  37. package/dist/react/icon/index.js +2 -0
  38. package/dist/react/index.d.ts +1 -1
  39. package/dist/react/index.js +1 -1
  40. package/dist/react/menubar/index.d.ts +6 -3
  41. package/dist/react/menubar/index.js +6 -3
  42. package/package.json +1 -1
  43. package/dist/components/menubar/menubar.types.d.ts +0 -4
  44. package/dist/components/menubar/menubar.types.js +0 -1
  45. package/dist/utils/mixins/MenuMixin.d.ts +0 -10
  46. package/dist/utils/mixins/MenuMixin.js +0 -479
@@ -19,6 +19,8 @@ import type { VariantType } from './alertchip.types';
19
19
  * @cssproperty --mdc-chip-border-color - The border color of the alertchip
20
20
  * @cssproperty --mdc-chip-background-color - The background color of the alertchip
21
21
  *
22
+ * @csspart icon - The alert icon
23
+ * @csspart label - The text label of the alertchip
22
24
  */
23
25
  declare class AlertChip extends Buttonsimple {
24
26
  /**
@@ -32,6 +32,8 @@ import { getAlertIcon } from './alertchip.utils';
32
32
  * @cssproperty --mdc-chip-border-color - The border color of the alertchip
33
33
  * @cssproperty --mdc-chip-background-color - The background color of the alertchip
34
34
  *
35
+ * @csspart icon - The alert icon
36
+ * @csspart label - The text label of the alertchip
35
37
  */
36
38
  class AlertChip extends Buttonsimple {
37
39
  constructor() {
@@ -36,6 +36,12 @@ declare const Avatar_base: import("../../utils/mixins/index.types").Constructor<
36
36
  * Allows customization of the loading indicator foreground color.
37
37
  * @cssproperty --mdc-avatar-loading-overlay-background-color -
38
38
  * Allows customization of the loading overlay background color.
39
+ *
40
+ * @csspart content - The main content of the avatar.
41
+ * @csspart photo - The photo of the avatar.
42
+ * @csspart presence - The presence indicator of the avatar.
43
+ * @csspart loading-wrapper - The wrapper for the loading indicator.
44
+ * @csspart loader - The loading indicator of the avatar.
39
45
  */
40
46
  declare class Avatar extends Avatar_base {
41
47
  /**
@@ -50,6 +50,12 @@ import { getAvatarIconSize, getAvatarTextFontSize, getPresenceSize } from './ava
50
50
  * Allows customization of the loading indicator foreground color.
51
51
  * @cssproperty --mdc-avatar-loading-overlay-background-color -
52
52
  * Allows customization of the loading overlay background color.
53
+ *
54
+ * @csspart content - The main content of the avatar.
55
+ * @csspart photo - The photo of the avatar.
56
+ * @csspart presence - The presence indicator of the avatar.
57
+ * @csspart loading-wrapper - The wrapper for the loading indicator.
58
+ * @csspart loader - The loading indicator of the avatar.
53
59
  */
54
60
  class Avatar extends AvatarComponentMixin(IconNameMixin(Component)) {
55
61
  constructor() {
@@ -8,6 +8,8 @@ declare const AvatarButton_base: import("../../utils/mixins/index.types").Constr
8
8
  * This component is made by extending `buttonsimple` class.
9
9
  * The button component acts as a wrapper for the avatar component.
10
10
  *
11
+ * To override styles of the avatar inside, use the specified css parts.
12
+ *
11
13
  * @dependency mdc-avatar
12
14
  *
13
15
  * @event click - (React: onClick) This event is dispatched when the avatarbutton is clicked.
@@ -20,6 +22,13 @@ declare const AvatarButton_base: import("../../utils/mixins/index.types").Constr
20
22
  * @cssproperty --mdc-avatarbutton-overlay-background-color-rest - Background color of the overlay in rest state
21
23
  * @cssproperty --mdc-avatarbutton-overlay-background-color-hover - Background color of the overlay in hover state
22
24
  * @cssproperty --mdc-avatarbutton-overlay-background-color-active - Background color of the overlay in active state
25
+ *
26
+ * @csspart overlay - The overlay part of the avatar button.
27
+ * @csspart content - The main content of the avatar.
28
+ * @csspart photo - The photo part of the avatar.
29
+ * @csspart presence - The presence indicator part of the avatar.
30
+ * @csspart loading-wrapper - The wrapper for the loading indicator of the avatar.
31
+ * @csspart loader - The loading indicator part of the avatar.
23
32
  */
24
33
  declare class AvatarButton extends AvatarButton_base {
25
34
  /**
@@ -23,6 +23,8 @@ import styles from './avatarbutton.styles';
23
23
  * This component is made by extending `buttonsimple` class.
24
24
  * The button component acts as a wrapper for the avatar component.
25
25
  *
26
+ * To override styles of the avatar inside, use the specified css parts.
27
+ *
26
28
  * @dependency mdc-avatar
27
29
  *
28
30
  * @event click - (React: onClick) This event is dispatched when the avatarbutton is clicked.
@@ -35,6 +37,13 @@ import styles from './avatarbutton.styles';
35
37
  * @cssproperty --mdc-avatarbutton-overlay-background-color-rest - Background color of the overlay in rest state
36
38
  * @cssproperty --mdc-avatarbutton-overlay-background-color-hover - Background color of the overlay in hover state
37
39
  * @cssproperty --mdc-avatarbutton-overlay-background-color-active - Background color of the overlay in active state
40
+ *
41
+ * @csspart overlay - The overlay part of the avatar button.
42
+ * @csspart content - The main content of the avatar.
43
+ * @csspart photo - The photo part of the avatar.
44
+ * @csspart presence - The presence indicator part of the avatar.
45
+ * @csspart loading-wrapper - The wrapper for the loading indicator of the avatar.
46
+ * @csspart loader - The loading indicator part of the avatar.
38
47
  */
39
48
  class AvatarButton extends AvatarComponentMixin(IconNameMixin(Buttonsimple)) {
40
49
  constructor() {
@@ -65,6 +74,7 @@ class AvatarButton extends AvatarComponentMixin(IconNameMixin(Buttonsimple)) {
65
74
  return html `
66
75
  <div part="overlay" aria-hidden="true"></div>
67
76
  <mdc-avatar
77
+ exportparts="content, photo, presence, loading-wrapper, loader"
68
78
  ?is-typing="${this.isTyping}"
69
79
  counter="${ifDefined(this.counter)}"
70
80
  icon-name="${ifDefined(this.iconName)}"
@@ -30,7 +30,7 @@ declare class FormfieldWrapper extends FormfieldWrapper_base {
30
30
  required: boolean;
31
31
  /**
32
32
  * The unique id of the input field. It is used to link the input field with the label.
33
- * @default `mdc-input-${uuidv4()}`
33
+ * @default ''
34
34
  */
35
35
  id: string;
36
36
  /**
@@ -41,7 +41,7 @@ class FormfieldWrapper extends DisabledMixin(Component) {
41
41
  this.required = false;
42
42
  /**
43
43
  * The unique id of the input field. It is used to link the input field with the label.
44
- * @default `mdc-input-${uuidv4()}`
44
+ * @default ''
45
45
  */
46
46
  this.id = '';
47
47
  /**
@@ -46,6 +46,8 @@ import type { IconNames } from './icon.types';
46
46
  * @cssproperty --mdc-icon-fill-color - Allows customization of the default fill color.
47
47
  * @cssproperty --mdc-icon-size - Allows customization of the icon size.
48
48
  * @cssproperty --mdc-icon-border-radius - Allows customization of the icon border radius.
49
+ *
50
+ * @csspart icon - The svg inside the icon element.
49
51
  */
50
52
  declare class Icon extends Component {
51
53
  private iconData?;
@@ -60,6 +60,8 @@ import { DEFAULTS } from './icon.constants';
60
60
  * @cssproperty --mdc-icon-fill-color - Allows customization of the default fill color.
61
61
  * @cssproperty --mdc-icon-size - Allows customization of the icon size.
62
62
  * @cssproperty --mdc-icon-border-radius - Allows customization of the icon border radius.
63
+ *
64
+ * @csspart icon - The svg inside the icon element.
63
65
  */
64
66
  class Icon extends Component {
65
67
  constructor() {
@@ -85,6 +85,17 @@ declare class ListItem extends ListItem_base {
85
85
  * This appears on the trailing side of the list item.
86
86
  */
87
87
  sublineText?: string;
88
+ /**
89
+ * Indicates whether the element is soft disabled.
90
+ * When set to `true`, the element appears visually disabled but still allows
91
+ * focus, click, and keyboard actions to be passed through.
92
+ *
93
+ * **Important:** When using soft disabled, consumers must ensure that
94
+ * the element behaves like a disabled element, allowing only focus and
95
+ * preventing any interactions (clicks or keyboard actions) from triggering unintended actions.
96
+ * @default undefined
97
+ */
98
+ softDisabled?: boolean;
88
99
  /**
89
100
  * The tooltip text is displayed on hover of the list item.
90
101
  */
@@ -80,7 +80,7 @@ class ListItem extends DisabledMixin(TabIndexMixin(Component)) {
80
80
  this.tooltipPlacement = DEFAULTS.TOOLTIP_PLACEMENT;
81
81
  this.addEventListener('keydown', this.handleKeyDown);
82
82
  this.addEventListener('focusin', this.displayTooltipForLongText);
83
- this.addEventListener('mouseover', this.displayTooltipForLongText);
83
+ this.addEventListener('mouseenter', this.displayTooltipForLongText);
84
84
  this.addEventListener('focusout', this.hideTooltipOnLeave);
85
85
  this.addEventListener('mouseout', this.hideTooltipOnLeave);
86
86
  this.addEventListener('click', this.handleClick);
@@ -183,7 +183,7 @@ class ListItem extends DisabledMixin(TabIndexMixin(Component)) {
183
183
  * This is useful when the list item is disabled, to prevent the user from interacting with the controls.
184
184
  * @param disabled - Whether to disable or enable the controls.
185
185
  */
186
- disableSlottedChildren(disabled) {
186
+ disableSlottedChildren(disabled = false) {
187
187
  [...this.leadingControlsSlot, ...this.trailingControlsSlot].forEach(element => {
188
188
  if (disabled) {
189
189
  element.setAttribute('disabled', '');
@@ -192,13 +192,17 @@ class ListItem extends DisabledMixin(TabIndexMixin(Component)) {
192
192
  element.removeAttribute('disabled');
193
193
  }
194
194
  });
195
+ // Set the aria-disabled attribute to indicate that the list item is disabled.
196
+ this.setAttribute('aria-disabled', `${disabled}`);
195
197
  }
196
198
  update(changedProperties) {
197
199
  super.update(changedProperties);
198
200
  if (changedProperties.has('disabled')) {
199
201
  this.tabIndex = this.disabled ? -1 : 0;
200
202
  this.disableSlottedChildren(this.disabled);
201
- this.setAttribute('aria-disabled', `${this.disabled}`);
203
+ }
204
+ if (changedProperties.has('softDisabled')) {
205
+ this.disableSlottedChildren(this.softDisabled);
202
206
  }
203
207
  }
204
208
  /**
@@ -291,6 +295,10 @@ __decorate([
291
295
  property({ type: String, reflect: true, attribute: 'subline-text' }),
292
296
  __metadata("design:type", String)
293
297
  ], ListItem.prototype, "sublineText", void 0);
298
+ __decorate([
299
+ property({ type: Boolean, reflect: true, attribute: 'soft-disabled' }),
300
+ __metadata("design:type", Boolean)
301
+ ], ListItem.prototype, "softDisabled", void 0);
294
302
  __decorate([
295
303
  property({ type: String, reflect: true, attribute: 'tooltip-text' }),
296
304
  __metadata("design:type", String)
@@ -1,6 +1,6 @@
1
1
  declare const TAG_NAME: "mdc-listitem";
2
- declare const TOOLTIP_ID = "dynamic-listitem-tooltip-popover";
3
- declare const LISTITEM_ID = "dynamic-listitem-tooltip-triggerid";
2
+ declare const TOOLTIP_ID: string;
3
+ declare const LISTITEM_ID: string;
4
4
  declare const LISTITEM_VARIANTS: {
5
5
  readonly FULL_WIDTH: "full-width";
6
6
  readonly INSET_PILL: "inset-pill";
@@ -1,8 +1,9 @@
1
+ import { v4 as uuidv4 } from 'uuid';
1
2
  import utils from '../../utils/tag-name';
2
3
  import { POPOVER_PLACEMENT } from '../popover/popover.constants';
3
4
  const TAG_NAME = utils.constructTagName('listitem');
4
- const TOOLTIP_ID = 'dynamic-listitem-tooltip-popover';
5
- const LISTITEM_ID = 'dynamic-listitem-tooltip-triggerid';
5
+ const TOOLTIP_ID = `listitem-tooltip-popover-${uuidv4()}`;
6
+ const LISTITEM_ID = `listitem-tooltip-triggerid-${uuidv4()}`;
6
7
  const LISTITEM_VARIANTS = {
7
8
  FULL_WIDTH: 'full-width',
8
9
  INSET_PILL: 'inset-pill',
@@ -47,7 +47,15 @@ const styles = css `
47
47
  :host([disabled])::part(leading-text-tertiary-label),
48
48
  :host([disabled])::part(leading-text-primary-label),
49
49
  :host([disabled])::part(trailing-text-side-header),
50
- :host([disabled])::part(trailing-text-subline) {
50
+ :host([disabled])::part(trailing-text-subline),
51
+ :host([soft-disabled]),
52
+ :host([soft-disabled]:hover),
53
+ :host([soft-disabled]:active),
54
+ :host([soft-disabled])::part(leading-text-secondary-label),
55
+ :host([soft-disabled])::part(leading-text-tertiary-label),
56
+ :host([soft-disabled])::part(leading-text-primary-label),
57
+ :host([soft-disabled])::part(trailing-text-side-header),
58
+ :host([soft-disabled])::part(trailing-text-subline) {
51
59
  background-color: unset;
52
60
  color: var(--mdc-listitem-disabled-color);
53
61
  cursor: default;
@@ -1,15 +1,13 @@
1
1
  import type { CSSResult, PropertyValues } from 'lit';
2
2
  import { Component } from '../../models';
3
- declare const MenuBar_base: import("../../utils/mixins/index.types").Constructor<import("../../utils/mixins/MenuMixin").MenuMixinInterface> & typeof Component;
4
3
  /**
5
- * Menubar is a navigational menu component that provides a horizontal (default) or vertical fixed list of menu items,
4
+ * Menubar is a navigational menu component that provides a vertical fixed list of menu items,
6
5
  * with support for nested submenus and keyboard navigation. It serves as a container
7
6
  * for menu items and manages their interaction patterns, including:
8
- * - Keyboard navigation (arrow keys, Home, End)
7
+ * - Keyboard navigation (Arrow keys, Home, End)
9
8
  * - Menu item activation (Enter/Space)
10
9
  * - Submenu toggling (Right/Left arrow keys)
11
10
  * - Focus management
12
- * - Support for both horizontal and vertical orientations
13
11
  * - Integration with MenuPopover for nested menus
14
12
  *
15
13
  * A menubar will contain a set of menu items and their associated popovers.
@@ -18,13 +16,41 @@ declare const MenuBar_base: import("../../utils/mixins/index.types").Constructor
18
16
  * The component automatically handles ARIA attributes and follows WAI-ARIA menu design patterns.
19
17
  * It works in conjunction with `mdc-menuitem` and `mdc-menupopover` to create accessible menu structures.
20
18
  *
19
+ * **Note:** A menubar contains three types of menu items, including menuitem, menuitemradio and menuitemcheckbox. These menu items may optionally be nested in one or more group containers. Groups or items may optionally by separated with separator elements.
20
+ *
21
+ * `mdc-menubar` contains a group that wraps all its chilren passed within the default slot. This has been added to ensure the right accessibility behavior while using screen readers.
22
+ *
21
23
  * @tagname mdc-menubar
22
24
  * @slot default - Contains the menu items and their associated popovers
23
25
  */
24
- declare class MenuBar extends MenuBar_base {
26
+ declare class MenuBar extends Component {
25
27
  constructor();
26
28
  connectedCallback(): void;
29
+ menuItems: Array<HTMLElement>;
27
30
  update(changedProperties: PropertyValues): void;
31
+ firstUpdated(changedProperties: PropertyValues): void;
32
+ /**
33
+ * Resets all list items tabindex to -1 and sets the tabindex of the
34
+ * element at the given index to 0, effectively setting the active
35
+ * element. This is used when navigating the list via keyboard.
36
+ *
37
+ * @param newIndex - The index of the new active element in the list.
38
+ */
39
+ private resetTabIndexAndSetActiveTabIndex;
40
+ private getCurrentIndex;
41
+ private updatePopoverPlacement;
42
+ private updateTabIndexAndFocus;
43
+ private navigateToMenuItem;
44
+ private showSubmenu;
45
+ private getKeyWithDirectionFix;
46
+ private isTopLevelMenuItem;
47
+ private isNestedMenuItem;
48
+ private closeAllMenuPopovers;
49
+ private crossMenubarNavigationOnLeft;
50
+ private crossMenubarNavigationOnRight;
51
+ private hasSubmenu;
52
+ private getParentMenuItemIndex;
53
+ private handleKeyDown;
28
54
  render(): import("lit-html").TemplateResult<1>;
29
55
  static styles: Array<CSSResult>;
30
56
  }
@@ -1,17 +1,31 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
1
10
  import { html } from 'lit';
11
+ import { queryAssignedElements } from 'lit/decorators.js';
2
12
  import { Component } from '../../models';
3
- import { MenuMixin } from '../../utils/mixins/MenuMixin';
4
13
  import { ROLE } from '../../utils/roles';
14
+ import { POPOVER_PLACEMENT } from '../popover/popover.constants';
15
+ import { TAG_NAME as MENUPOPOVER_TAGNAME } from '../menupopover/menupopover.constants';
16
+ import { TAG_NAME as MENUITEM_TAGNAME } from '../menuitem/menuitem.constants';
17
+ import { KEYS } from '../../utils/keys';
18
+ import { popoverStack } from '../popover/popover.stack';
19
+ import { DEFAULTS, TAG_NAME as MENUBAR_TAGNAME } from './menubar.constants';
5
20
  import styles from './menubar.styles';
6
21
  /**
7
- * Menubar is a navigational menu component that provides a horizontal (default) or vertical fixed list of menu items,
22
+ * Menubar is a navigational menu component that provides a vertical fixed list of menu items,
8
23
  * with support for nested submenus and keyboard navigation. It serves as a container
9
24
  * for menu items and manages their interaction patterns, including:
10
- * - Keyboard navigation (arrow keys, Home, End)
25
+ * - Keyboard navigation (Arrow keys, Home, End)
11
26
  * - Menu item activation (Enter/Space)
12
27
  * - Submenu toggling (Right/Left arrow keys)
13
28
  * - Focus management
14
- * - Support for both horizontal and vertical orientations
15
29
  * - Integration with MenuPopover for nested menus
16
30
  *
17
31
  * A menubar will contain a set of menu items and their associated popovers.
@@ -20,28 +34,203 @@ import styles from './menubar.styles';
20
34
  * The component automatically handles ARIA attributes and follows WAI-ARIA menu design patterns.
21
35
  * It works in conjunction with `mdc-menuitem` and `mdc-menupopover` to create accessible menu structures.
22
36
  *
37
+ * **Note:** A menubar contains three types of menu items, including menuitem, menuitemradio and menuitemcheckbox. These menu items may optionally be nested in one or more group containers. Groups or items may optionally by separated with separator elements.
38
+ *
39
+ * `mdc-menubar` contains a group that wraps all its chilren passed within the default slot. This has been added to ensure the right accessibility behavior while using screen readers.
40
+ *
23
41
  * @tagname mdc-menubar
24
42
  * @slot default - Contains the menu items and their associated popovers
25
43
  */
26
- class MenuBar extends MenuMixin(Component) {
44
+ class MenuBar extends Component {
27
45
  constructor() {
28
46
  super();
29
47
  this.addEventListener('keydown', this.handleKeyDown);
30
- this.addEventListener('click', this.handleMouseClick);
31
48
  }
32
49
  connectedCallback() {
33
50
  super.connectedCallback();
34
51
  this.role = ROLE.MENUBAR;
52
+ this.ariaOrientation = DEFAULTS.ORIENTATION;
35
53
  }
36
54
  update(changedProperties) {
37
55
  super.update(changedProperties);
38
- if (changedProperties.has('ariaOrientation')) {
39
- this.updatePopoverPlacementBasedOnOrientation();
56
+ this.updatePopoverPlacement();
57
+ }
58
+ firstUpdated(changedProperties) {
59
+ super.firstUpdated(changedProperties);
60
+ this.resetTabIndexAndSetActiveTabIndex(this.menuItems);
61
+ }
62
+ /**
63
+ * Resets all list items tabindex to -1 and sets the tabindex of the
64
+ * element at the given index to 0, effectively setting the active
65
+ * element. This is used when navigating the list via keyboard.
66
+ *
67
+ * @param newIndex - The index of the new active element in the list.
68
+ */
69
+ resetTabIndexAndSetActiveTabIndex(menuItems) {
70
+ menuItems.forEach((node, index) => {
71
+ const newTabindex = index === 0 ? '0' : '-1';
72
+ node === null || node === void 0 ? void 0 : node.setAttribute('tabindex', newTabindex);
73
+ });
74
+ }
75
+ getCurrentIndex(target) {
76
+ return this.menuItems.findIndex(item => item === target || item === target.parentElement);
77
+ }
78
+ updatePopoverPlacement() {
79
+ const allPopovers = this.querySelectorAll(`${MENUPOPOVER_TAGNAME}:not([disabled])`);
80
+ const placement = POPOVER_PLACEMENT.RIGHT_START;
81
+ allPopovers.forEach(popover => popover.setAttribute('placement', placement));
82
+ }
83
+ updateTabIndexAndFocus(menuItems, currentIndex, newIndex) {
84
+ var _a, _b, _c;
85
+ if (newIndex < 0 || currentIndex < 0)
86
+ return;
87
+ if (currentIndex !== newIndex) {
88
+ (_a = menuItems[currentIndex]) === null || _a === void 0 ? void 0 : _a.setAttribute('tabindex', '-1');
89
+ (_b = menuItems[newIndex]) === null || _b === void 0 ? void 0 : _b.setAttribute('tabindex', '0');
90
+ }
91
+ (_c = menuItems[newIndex]) === null || _c === void 0 ? void 0 : _c.focus();
92
+ }
93
+ navigateToMenuItem(currentIndex, direction, shouldOpenSubmenu = false) {
94
+ var _a;
95
+ const { length } = this.menuItems;
96
+ if (length === 0)
97
+ return;
98
+ let newIndex = currentIndex;
99
+ if (direction === 'prev') {
100
+ newIndex = (currentIndex - 1 + length) % length;
101
+ }
102
+ else {
103
+ newIndex = (currentIndex + 1) % length;
104
+ }
105
+ this.updateTabIndexAndFocus(this.menuItems, currentIndex, newIndex);
106
+ if (shouldOpenSubmenu) {
107
+ const triggerId = (_a = this.menuItems[newIndex]) === null || _a === void 0 ? void 0 : _a.getAttribute('id');
108
+ if (this.hasSubmenu(triggerId) && !this.menuItems[newIndex].hasAttribute('soft-disabled')) {
109
+ this.showSubmenu(triggerId);
110
+ }
111
+ }
112
+ }
113
+ showSubmenu(triggerId) {
114
+ const submenu = this.querySelector(`${MENUPOPOVER_TAGNAME}[triggerid="${triggerId}"]`);
115
+ submenu === null || submenu === void 0 ? void 0 : submenu.showPopover();
116
+ }
117
+ getKeyWithDirectionFix(originalKey) {
118
+ const isRtl = window.getComputedStyle(this).direction === 'rtl';
119
+ if (!isRtl)
120
+ return originalKey;
121
+ if (originalKey === KEYS.ARROW_LEFT)
122
+ return KEYS.ARROW_RIGHT;
123
+ if (originalKey === KEYS.ARROW_RIGHT)
124
+ return KEYS.ARROW_LEFT;
125
+ return originalKey;
126
+ }
127
+ isTopLevelMenuItem(element) {
128
+ var _a;
129
+ return (((_a = element.parentElement) === null || _a === void 0 ? void 0 : _a.tagName.toLowerCase()) === MENUBAR_TAGNAME &&
130
+ element.tagName.toLowerCase() === MENUITEM_TAGNAME);
131
+ }
132
+ isNestedMenuItem(element) {
133
+ return !!element.closest(MENUPOPOVER_TAGNAME) && element.tagName.toLowerCase() === MENUITEM_TAGNAME;
134
+ }
135
+ async closeAllMenuPopovers() {
136
+ const popovers = [];
137
+ while (popoverStack.peek()) {
138
+ const popover = popoverStack.pop();
139
+ if (popover) {
140
+ popover.hidePopover();
141
+ popovers.push(popover);
142
+ }
143
+ }
144
+ await Promise.all(popovers.map(popover => popover.updateComplete));
145
+ }
146
+ async crossMenubarNavigationOnLeft(element) {
147
+ const isMenuItem = element.tagName.toLowerCase() === MENUITEM_TAGNAME;
148
+ if (isMenuItem) {
149
+ const parentPopover = element.closest(MENUPOPOVER_TAGNAME);
150
+ const triggerId = parentPopover === null || parentPopover === void 0 ? void 0 : parentPopover.getAttribute('triggerid');
151
+ const triggerMenuItem = this.menuItems.find(item => item.getAttribute('id') === triggerId);
152
+ if (triggerMenuItem) {
153
+ if (this.isTopLevelMenuItem(triggerMenuItem)) {
154
+ parentPopover === null || parentPopover === void 0 ? void 0 : parentPopover.hidePopover();
155
+ }
156
+ await (parentPopover === null || parentPopover === void 0 ? void 0 : parentPopover.updateComplete);
157
+ const parentMenuItemIndex = this.getCurrentIndex(triggerMenuItem);
158
+ this.navigateToMenuItem(parentMenuItemIndex, 'prev', true);
159
+ }
160
+ }
161
+ }
162
+ async crossMenubarNavigationOnRight(element) {
163
+ if (this.isTopLevelMenuItem(element) && this.hasSubmenu(element.id) && !element.hasAttribute('soft-disabled')) {
164
+ this.showSubmenu(element.id);
165
+ }
166
+ else if (this.isNestedMenuItem(element) && !this.hasSubmenu(element.id)) {
167
+ await this.closeAllMenuPopovers();
168
+ const parentIndex = this.getParentMenuItemIndex(element);
169
+ if (parentIndex >= 0)
170
+ this.navigateToMenuItem(parentIndex, 'next', true);
171
+ }
172
+ }
173
+ hasSubmenu(triggerId) {
174
+ return !!this.querySelector(`${MENUPOPOVER_TAGNAME}[triggerid="${triggerId}"]`);
175
+ }
176
+ getParentMenuItemIndex(element) {
177
+ let parent = element.parentElement;
178
+ while (parent) {
179
+ if (parent.tagName.toLowerCase() === MENUPOPOVER_TAGNAME) {
180
+ const triggerId = parent.getAttribute('triggerid');
181
+ const triggerElement = this.menuItems.find(item => item.getAttribute('id') === triggerId);
182
+ if (triggerElement) {
183
+ if (this.isTopLevelMenuItem(triggerElement)) {
184
+ return this.menuItems.findIndex(item => item === triggerElement);
185
+ }
186
+ return this.getParentMenuItemIndex(triggerElement);
187
+ }
188
+ }
189
+ parent = parent.parentElement;
190
+ }
191
+ return -1;
192
+ }
193
+ async handleKeyDown(event) {
194
+ const currentIndex = this.getCurrentIndex(event.target);
195
+ const key = this.getKeyWithDirectionFix(event.key);
196
+ switch (key) {
197
+ case KEYS.HOME:
198
+ this.updateTabIndexAndFocus(this.menuItems, currentIndex, 0);
199
+ break;
200
+ case KEYS.END:
201
+ this.updateTabIndexAndFocus(this.menuItems, currentIndex, this.menuItems.length - 1);
202
+ break;
203
+ case KEYS.ARROW_LEFT: {
204
+ const element = currentIndex >= 0 ? this.menuItems[currentIndex] : event.target;
205
+ await this.crossMenubarNavigationOnLeft(element);
206
+ break;
207
+ }
208
+ case KEYS.ARROW_RIGHT: {
209
+ const element = currentIndex >= 0 ? this.menuItems[currentIndex] : event.target;
210
+ await this.crossMenubarNavigationOnRight(element);
211
+ break;
212
+ }
213
+ case KEYS.ARROW_UP: {
214
+ this.navigateToMenuItem(currentIndex, 'prev');
215
+ event.preventDefault();
216
+ break;
217
+ }
218
+ case KEYS.ARROW_DOWN: {
219
+ this.navigateToMenuItem(currentIndex, 'next');
220
+ event.preventDefault();
221
+ break;
222
+ }
223
+ default:
224
+ break;
40
225
  }
41
226
  }
42
227
  render() {
43
- return html `<slot></slot>`;
228
+ return html `<slot role="${ROLE.GROUP}"></slot>`;
44
229
  }
45
230
  }
46
231
  MenuBar.styles = [...Component.styles, ...styles];
232
+ __decorate([
233
+ queryAssignedElements({ selector: `${MENUITEM_TAGNAME}:not([disabled])` }),
234
+ __metadata("design:type", Array)
235
+ ], MenuBar.prototype, "menuItems", void 0);
47
236
  export default MenuBar;
@@ -1,6 +1,5 @@
1
1
  declare const TAG_NAME: "mdc-menubar";
2
- declare const ORIENTATION: {
3
- readonly HORIZONTAL: "horizontal";
4
- readonly VERTICAL: "vertical";
2
+ declare const DEFAULTS: {
3
+ ORIENTATION: string;
5
4
  };
6
- export { TAG_NAME, ORIENTATION };
5
+ export { TAG_NAME, DEFAULTS };
@@ -1,7 +1,6 @@
1
1
  import utils from '../../utils/tag-name';
2
2
  const TAG_NAME = utils.constructTagName('menubar');
3
- const ORIENTATION = {
4
- HORIZONTAL: 'horizontal',
5
- VERTICAL: 'vertical',
3
+ const DEFAULTS = {
4
+ ORIENTATION: 'vertical',
6
5
  };
7
- export { TAG_NAME, ORIENTATION };
6
+ export { TAG_NAME, DEFAULTS };
@@ -83,6 +83,7 @@ declare class MenuPopover extends Popover {
83
83
  * @returns - A boolean indicating whether a submenu with the specified trigger ID exists.
84
84
  */
85
85
  private hasSubmenuWithTriggerId;
86
+ togglePopoverVisible: () => void;
86
87
  /**
87
88
  * Handles mouse click events on the menu items.
88
89
  * This method checks if the clicked element is a valid menu item and not a submenu trigger.
@@ -11,7 +11,6 @@ import { property } from 'lit/decorators.js';
11
11
  import { KEYS } from '../../utils/keys';
12
12
  import { ROLE } from '../../utils/roles';
13
13
  import { TAG_NAME as MENUSECTION_TAGNAME } from '../menusection/menusection.constants';
14
- import { ORIENTATION } from '../menubar/menubar.constants';
15
14
  import Popover from '../popover/popover.component';
16
15
  import { COLOR } from '../popover/popover.constants';
17
16
  import { popoverStack } from '../popover/popover.stack';
@@ -82,6 +81,18 @@ class MenuPopover extends Popover {
82
81
  this.closeAllMenuPopovers();
83
82
  }
84
83
  };
84
+ this.togglePopoverVisible = () => {
85
+ var _a;
86
+ if ((_a = this.triggerElement) === null || _a === void 0 ? void 0 : _a.hasAttribute('soft-disabled'))
87
+ return;
88
+ if (this.isTriggerClicked) {
89
+ this.hidePopover();
90
+ }
91
+ else {
92
+ this.showPopover();
93
+ this.isTriggerClicked = true;
94
+ }
95
+ };
85
96
  this.addEventListener('keydown', this.handleKeyDown);
86
97
  this.addEventListener('click', this.handleMouseClick);
87
98
  }
@@ -103,7 +114,7 @@ class MenuPopover extends Popover {
103
114
  connectedCallback() {
104
115
  super.connectedCallback();
105
116
  this.role = ROLE.MENU;
106
- this.ariaOrientation = ORIENTATION.VERTICAL;
117
+ this.ariaOrientation = DEFAULTS.ORIENTATION;
107
118
  this.backdrop = false;
108
119
  this.color = COLOR.TONAL;
109
120
  this.disableAriaExpanded = false;
@@ -1,5 +1,6 @@
1
1
  declare const TAG_NAME: "mdc-menupopover";
2
2
  declare const DEFAULTS: {
3
3
  PLACEMENT: "bottom-start";
4
+ ORIENTATION: string;
4
5
  };
5
6
  export { TAG_NAME, DEFAULTS };
@@ -3,5 +3,6 @@ import { POPOVER_PLACEMENT } from '../popover/popover.constants';
3
3
  const TAG_NAME = utils.constructTagName('menupopover');
4
4
  const DEFAULTS = {
5
5
  PLACEMENT: POPOVER_PLACEMENT.BOTTOM_START,
6
+ ORIENTATION: 'vertical',
6
7
  };
7
8
  export { TAG_NAME, DEFAULTS };