@momentum-design/components 0.85.6 → 0.85.7

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 (44) hide show
  1. package/dist/browser/index.js +225 -201
  2. package/dist/browser/index.js.map +4 -4
  3. package/dist/components/menuitem/menuitem.component.d.ts +21 -1
  4. package/dist/components/menuitem/menuitem.component.js +29 -1
  5. package/dist/components/menuitemcheckbox/menuitemcheckbox.component.d.ts +26 -15
  6. package/dist/components/menuitemcheckbox/menuitemcheckbox.component.js +42 -25
  7. package/dist/components/menuitemcheckbox/menuitemcheckbox.constants.d.ts +1 -1
  8. package/dist/components/menuitemcheckbox/menuitemcheckbox.constants.js +1 -2
  9. package/dist/components/menuitemcheckbox/menuitemcheckbox.styles.js +0 -6
  10. package/dist/components/menuitemradio/menuitemradio.component.d.ts +61 -12
  11. package/dist/components/menuitemradio/menuitemradio.component.js +125 -40
  12. package/dist/components/menuitemradio/menuitemradio.constants.d.ts +9 -1
  13. package/dist/components/menuitemradio/menuitemradio.constants.js +9 -1
  14. package/dist/components/menuitemradio/menuitemradio.styles.d.ts +2 -0
  15. package/dist/components/menuitemradio/menuitemradio.styles.js +7 -0
  16. package/dist/components/menuitemradio/menuitemradio.types.d.ts +4 -1
  17. package/dist/components/menupopover/menupopover.component.d.ts +6 -0
  18. package/dist/components/menupopover/menupopover.component.js +11 -3
  19. package/dist/components/menupopover/menupopover.styles.js +4 -0
  20. package/dist/components/menupopover/menupopover.types.d.ts +11 -0
  21. package/dist/components/menupopover/menupopover.types.js +1 -0
  22. package/dist/components/menupopover/menupopover.utils.d.ts +4 -2
  23. package/dist/components/menupopover/menupopover.utils.js +1 -1
  24. package/dist/components/menusection/menusection.component.d.ts +15 -2
  25. package/dist/components/menusection/menusection.component.js +55 -4
  26. package/dist/components/menusection/menusection.constants.d.ts +1 -5
  27. package/dist/components/menusection/menusection.constants.js +1 -5
  28. package/dist/components/menusection/menusection.styles.d.ts +2 -0
  29. package/dist/components/menusection/menusection.styles.js +11 -0
  30. package/dist/components/menusection/menusection.types.d.ts +7 -4
  31. package/dist/custom-elements.json +611 -293
  32. package/dist/index.d.ts +3 -1
  33. package/dist/react/menuitem/index.d.ts +12 -1
  34. package/dist/react/menuitem/index.js +12 -1
  35. package/dist/react/menuitemcheckbox/index.d.ts +18 -7
  36. package/dist/react/menuitemcheckbox/index.js +18 -7
  37. package/dist/react/menuitemradio/index.d.ts +25 -2
  38. package/dist/react/menuitemradio/index.js +25 -2
  39. package/dist/react/menupopover/index.d.ts +8 -0
  40. package/dist/react/menupopover/index.js +8 -0
  41. package/dist/react/menusection/index.d.ts +6 -1
  42. package/dist/react/menusection/index.js +5 -1
  43. package/dist/utils/types.d.ts +10 -0
  44. package/package.json +1 -1
@@ -7,29 +7,54 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
- import { html } from 'lit';
10
+ import { html, nothing } from 'lit';
11
11
  import { property } from 'lit/decorators.js';
12
12
  import { ROLE } from '../../utils/roles';
13
13
  import MenuItem from '../menuitem/menuitem.component';
14
14
  import { TYPE } from '../text/text.constants';
15
- import { ARIA_CHECKED_STATES, TAG_NAME as MENUSECTION_TAGNAME } from '../menusection/menusection.constants';
15
+ import { TAG_NAME as MENUSECTION_TAGNAME } from '../menusection/menusection.constants';
16
16
  import { TAG_NAME as MENUPOPOVER_TAGNAME } from '../menupopover/menupopover.constants';
17
+ import { INDICATOR, DEFAULTS } from './menuitemradio.constants';
18
+ import styles from './menuitemradio.styles';
17
19
  /**
18
20
  * A menuitemradio component is a checkable menuitem that is used in a menu.
19
21
  * A menuitemradio should be checked only one at a time. <br/>
20
22
  * There should be no focusable descendants inside this menuitemradio component.
21
23
  *
22
- * The `aria-checked` menuitemradio attribute is used to indicate that the menuitemradio is checked or not.
24
+ * The `checked` menuitemradio attribute is used to indicate that the menuitemradio is checked or not.
25
+ *
26
+ * Menu item radio has `name` and `value` attribute that can be used to identify the menu item when it is selected.
23
27
  *
24
28
  * If you want more than one item in a group to be checked, consider using menuitemcheckbox component.
25
29
  *
26
- * If a menuitemradio is disabled, then the `aria-disabled` attribute is set to `true`.
30
+ * The `indicator` attribute is used to differentiate between <b>radio</b>, <b>checkmark</b> and <b>none</b>.
31
+ * By default, the `indicator` is set to <b>radio</b>.<br/>
32
+ *
33
+ * The checkbox will always be positioned on the leading side of the menuitem label and
34
+ * the checkmark will always be positioned on the trailing side.
35
+ *
36
+ * The radio will have the possible states of `true` or `false`.
37
+ * If the indicator is set to <b>checkmark</b> and if the `checked` attribute is set to `true`,
38
+ * then the checkmark will be displayed. if not, then no indicator will be displayed.
39
+ *
40
+ * The third options for the `indicator` is <b>none</b>, which will not display any indicator at all.
41
+ * It is intended to be used for customised menu items where the indicator is implemented differently.
42
+ * For example, you can use a custom icon or a different visual element to indicate the state of the menu item.
43
+ * Make sure the new indicator is accessible.
27
44
  *
28
45
  * @dependency mdc-staticradio
29
46
  * @dependency mdc-text
30
47
  *
31
48
  * @tagname mdc-menuitemradio
32
49
  *
50
+ * @slot leading-controls - slot for menu item radio controls to appear of leading end.
51
+ * @slot leading-text-primary-label - slot for menu item radio primary label.
52
+ * @slot leading-text-secondary-label - slot for menu item radio secondary label.
53
+ * @slot leading-text-tertiary-label - slot for menu item radio tertiary label.
54
+ * @slot trailing-text-side-header - slot for menu item radio side header text.
55
+ * @slot trailing-text-subline - slot for menu item radio subline text.
56
+ * @slot trailing-controls - slot for menu item radio controls to appear of trailing end.
57
+ *
33
58
  * @event change - (React: onChange) This event is dispatched when the menuitemradio changes.
34
59
  * @event click - (React: onClick) This event is dispatched when the menuitemradio is clicked.
35
60
  * @event focus - (React: onFocus) This event is dispatched when the menuitemradio receives focus.
@@ -39,63 +64,123 @@ class MenuItemRadio extends MenuItem {
39
64
  super();
40
65
  /**
41
66
  * The aria-checked attribute is used to indicate that the menuitemradio is checked or not.
42
- * @default 'false'
67
+ * @default false
43
68
  */
44
- this.ariaChecked = ARIA_CHECKED_STATES.FALSE;
69
+ this.checked = false;
45
70
  /**
46
- * The name attribute is used to group radio items within the same menu container.
71
+ * The indicator attribute is used to differentiate between <b>radio</b>, <b>checkmark</b> and <b>none</b>.
72
+ * @default 'radio'
47
73
  */
48
- this.name = '';
74
+ this.indicator = DEFAULTS.INDICATOR;
49
75
  /**
50
76
  * Handles click events to set checked state and uncheck siblings in the same group and container.
51
- * If the menuitemradio is not checked, it sets its aria-checked state to `true`
52
- * and sets all other menuitemradio elements of the same group with aria-checked state to `false`.
77
+ * If the menuitemradio is not checked, it sets its checked state to `true`
78
+ * and sets all other menuitemradio elements of the same group with checked state to `false`.
53
79
  */
54
- this.menuitemradioHandleClick = () => {
55
- if (this.disabled || this.ariaChecked === ARIA_CHECKED_STATES.TRUE)
80
+ this.radioHandleClick = (event) => {
81
+ event.stopPropagation();
82
+ if (this.disabled || this.checked)
56
83
  return;
57
- // Find the closest menu container (menupopover or menusection)
58
- const container = this.closest(`${MENUSECTION_TAGNAME}, ${MENUPOPOVER_TAGNAME}`);
59
- if (container) {
60
- const radios = Array.from(container.querySelectorAll(this.tagName));
61
- radios.forEach(item => {
62
- const radio = item;
63
- if (radio.name === this.name) {
64
- radio.ariaChecked = ARIA_CHECKED_STATES.FALSE;
65
- }
66
- });
67
- }
68
- this.ariaChecked = ARIA_CHECKED_STATES.TRUE;
84
+ this.updateOtherRadiosCheckedState();
85
+ this.checked = true;
86
+ this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
69
87
  };
70
- this.addEventListener('click', this.menuitemradioHandleClick);
88
+ this.addEventListener('click', this.radioHandleClick);
71
89
  }
72
90
  connectedCallback() {
73
91
  super.connectedCallback();
74
92
  this.role = ROLE.MENUITEMRADIO;
75
93
  }
94
+ /**
95
+ * Returns all radios within the same group (name).
96
+ */
97
+ getAllRadiosWithinSameGroup() {
98
+ const container = this.closest(`${MENUSECTION_TAGNAME}, ${MENUPOPOVER_TAGNAME}`);
99
+ if (!container || !this.name)
100
+ return [];
101
+ return Array.from(container.querySelectorAll(`${this.tagName}[name="${this.name}"]`));
102
+ }
103
+ /**
104
+ * Updates the checked state of all other radios in the same group.
105
+ * This method is called when a radio is clicked to ensure that only one radio in the group can be checked at a time.
106
+ * It sets the `checked` property of all other radios in the same group to `false`.
107
+ */
108
+ updateOtherRadiosCheckedState() {
109
+ const radios = this.getAllRadiosWithinSameGroup();
110
+ radios.forEach(radio => {
111
+ // eslint-disable-next-line no-param-reassign
112
+ if (radio !== this)
113
+ radio.checked = false;
114
+ });
115
+ }
116
+ update(changedProperties) {
117
+ super.update(changedProperties);
118
+ if (changedProperties.has('checked')) {
119
+ this.ariaChecked = `${this.checked}`;
120
+ if (changedProperties.get('checked') === false && this.checked) {
121
+ this.updateOtherRadiosCheckedState();
122
+ }
123
+ }
124
+ }
125
+ /**
126
+ * Returns a static checkbox element if the indicator is set to checkbox.
127
+ * If the indicator is not set to checkbox, it returns nothing.
128
+ * @returns TemplateResult | typeof nothing
129
+ */
130
+ renderStaticRadio() {
131
+ if (this.indicator !== INDICATOR.RADIO) {
132
+ return nothing;
133
+ }
134
+ return html `
135
+ <mdc-staticradio
136
+ slot="leading-controls"
137
+ ?checked="${this.checked}"
138
+ ?disabled="${this.disabled}"
139
+ ></mdc-staticradio>
140
+ `;
141
+ }
142
+ /**
143
+ * Returns a checkmark icon if the indicator is set to checkmark and the checked state is true.
144
+ * If the indicator is not set to checkmark or the checked state is false, it returns nothing.
145
+ *
146
+ * The checkmark icon will always be positioned on the trailing side of the menuitem label.
147
+ * @returns TemplateResult | typeof nothing
148
+ */
149
+ renderCheckmarkIcon() {
150
+ if (this.checked && this.indicator === INDICATOR.CHECKMARK) {
151
+ return html ` <mdc-icon slot="trailing-controls" name="check-bold" part="checkmark-icon"></mdc-icon> `;
152
+ }
153
+ return nothing;
154
+ }
76
155
  render() {
77
156
  return html `
78
- <div part="leading-controls">
79
- <mdc-staticradio
80
- slot="leading-controls"
81
- ?checked="${this.ariaChecked === ARIA_CHECKED_STATES.TRUE}"
82
- ?disabled="${this.disabled}"
83
- ></mdc-staticradio>
157
+ <div part="leading">
158
+ ${this.renderStaticRadio()}
159
+ <slot name="leading-controls"></slot>
160
+ <div part="leading-text">
161
+ ${this.getText('leading-text-primary-label', TYPE.BODY_MIDSIZE_REGULAR, this.label)}
162
+ ${this.getText('leading-text-secondary-label', TYPE.BODY_SMALL_REGULAR, this.secondaryLabel)}
163
+ ${this.getText('leading-text-tertiary-label', TYPE.BODY_SMALL_REGULAR, this.tertiaryLabel)}
164
+ </div>
84
165
  </div>
85
- <div part="leading-text">
86
- ${this.getText('leading-text-primary-label', TYPE.BODY_MIDSIZE_REGULAR, this.label)}
87
- ${this.getText('leading-text-secondary-label', TYPE.BODY_MIDSIZE_REGULAR, this.secondaryLabel)}
166
+ <div part="trailing">
167
+ <div part="trailing-text">
168
+ ${this.getText('trailing-text-side-header', TYPE.BODY_MIDSIZE_REGULAR, this.sideHeaderText)}
169
+ ${this.getText('trailing-text-subline', TYPE.BODY_SMALL_REGULAR, this.sublineText)}
170
+ </div>
171
+ <slot name="trailing-controls"></slot>
172
+ ${this.renderCheckmarkIcon()}
88
173
  </div>
89
174
  `;
90
175
  }
91
176
  }
92
- MenuItemRadio.styles = [...MenuItem.styles];
177
+ MenuItemRadio.styles = [...MenuItem.styles, ...styles];
93
178
  __decorate([
94
- property({ type: String, reflect: true, attribute: 'aria-checked' }),
95
- __metadata("design:type", String)
96
- ], MenuItemRadio.prototype, "ariaChecked", void 0);
179
+ property({ type: Boolean, reflect: true }),
180
+ __metadata("design:type", Boolean)
181
+ ], MenuItemRadio.prototype, "checked", void 0);
97
182
  __decorate([
98
183
  property({ type: String, reflect: true }),
99
- __metadata("design:type", Object)
100
- ], MenuItemRadio.prototype, "name", void 0);
184
+ __metadata("design:type", String)
185
+ ], MenuItemRadio.prototype, "indicator", void 0);
101
186
  export default MenuItemRadio;
@@ -1,2 +1,10 @@
1
1
  declare const TAG_NAME: "mdc-menuitemradio";
2
- export { TAG_NAME };
2
+ declare const INDICATOR: {
3
+ readonly NONE: "none";
4
+ readonly RADIO: "radio";
5
+ readonly CHECKMARK: "checkmark";
6
+ };
7
+ declare const DEFAULTS: {
8
+ readonly INDICATOR: "radio";
9
+ };
10
+ export { TAG_NAME, INDICATOR, DEFAULTS };
@@ -1,3 +1,11 @@
1
1
  import utils from '../../utils/tag-name';
2
2
  const TAG_NAME = utils.constructTagName('menuitemradio');
3
- export { TAG_NAME };
3
+ const INDICATOR = {
4
+ NONE: 'none',
5
+ RADIO: 'radio',
6
+ CHECKMARK: 'checkmark',
7
+ };
8
+ const DEFAULTS = {
9
+ INDICATOR: INDICATOR.RADIO,
10
+ };
11
+ export { TAG_NAME, INDICATOR, DEFAULTS };
@@ -0,0 +1,2 @@
1
+ declare const _default: import("lit").CSSResult[];
2
+ export default _default;
@@ -0,0 +1,7 @@
1
+ import { css } from 'lit';
2
+ const styles = css `
3
+ :host::part(checkmark-icon) {
4
+ --mdc-icon-fill-color: currentColor;
5
+ }
6
+ `;
7
+ export default [styles];
@@ -1,6 +1,9 @@
1
+ import { ValueOf } from '../../utils/types';
2
+ import { INDICATOR } from './menuitemradio.constants';
3
+ type Indicator = ValueOf<typeof INDICATOR>;
1
4
  interface Events {
2
5
  onChangeEvent: Event;
3
6
  onClickEvent: MouseEvent;
4
7
  onFocusEvent: FocusEvent;
5
8
  }
6
- export type { Events };
9
+ export type { Events, Indicator };
@@ -19,6 +19,12 @@ import { PopoverPlacement } from '../popover/popover.types';
19
19
  * The orientation of the menu popover is always set to `vertical`.
20
20
  *
21
21
  * @tagname mdc-menupopover
22
+ *
23
+ * @slot - Default slot for the menu popover content
24
+ *
25
+ * @event change - (React: onChange) This event is dispatched when a `menuitemcheckbox`, or `menuitemradio` changes.
26
+ * @event action - (React: onAction) This event is dispatched when a menuItem selected and the menu closes.
27
+ *
22
28
  * @slot default - Contains the menu items to be displayed in the popover
23
29
  */
24
30
  declare class MenuPopover extends Popover {
@@ -35,6 +35,12 @@ import { isActiveMenuItem, isValidMenuItem, isValidPopover } from './menupopover
35
35
  * The orientation of the menu popover is always set to `vertical`.
36
36
  *
37
37
  * @tagname mdc-menupopover
38
+ *
39
+ * @slot - Default slot for the menu popover content
40
+ *
41
+ * @event change - (React: onChange) This event is dispatched when a `menuitemcheckbox`, or `menuitemradio` changes.
42
+ * @event action - (React: onAction) This event is dispatched when a menuItem selected and the menu closes.
43
+ *
38
44
  * @slot default - Contains the menu items to be displayed in the popover
39
45
  */
40
46
  class MenuPopover extends Popover {
@@ -73,9 +79,8 @@ class MenuPopover extends Popover {
73
79
  this.closeAllMenuPopovers(popoverOfTarget);
74
80
  return;
75
81
  }
76
- let insidePopoverClick = false;
77
82
  const path = event.composedPath();
78
- insidePopoverClick = this.contains(event.target) || path.includes(this.triggerElement);
83
+ const insidePopoverClick = this.contains(event.target) || path.includes(this.triggerElement);
79
84
  const clickedOnBackdrop = this.backdropElement ? path.includes(this.backdropElement) : false;
80
85
  if (!insidePopoverClick || clickedOnBackdrop) {
81
86
  this.closeAllMenuPopovers();
@@ -199,8 +204,11 @@ class MenuPopover extends Popover {
199
204
  const target = event.target;
200
205
  const triggerId = target.getAttribute('id');
201
206
  if (isActiveMenuItem(target) && // menuitemcheckbox and menuitemradio are not supposed to close the popover
202
- !this.hasSubmenuWithTriggerId(triggerId)) {
207
+ !this.hasSubmenuWithTriggerId(triggerId) &&
208
+ this === target.closest(MENU_POPOVER) // Ensure close all popover called only once
209
+ ) {
203
210
  this.closeAllMenuPopovers();
211
+ target.dispatchEvent(new Event('action', { bubbles: true, composed: true }));
204
212
  }
205
213
  }
206
214
  /**
@@ -3,5 +3,9 @@ const styles = css `
3
3
  :host::part(popover-content) {
4
4
  padding: 0.75rem 0.5rem;
5
5
  }
6
+
7
+ ::slotted(mdc-divider) {
8
+ margin-block: 0.25rem;
9
+ }
6
10
  `;
7
11
  export default [styles];
@@ -0,0 +1,11 @@
1
+ import type MenuItem from '../menuitem';
2
+ export type MenuPopoverChangeEvent = Event & {
3
+ target: MenuItem;
4
+ };
5
+ export type MenuPopoverActionEvent = Event & {
6
+ target: MenuItem;
7
+ };
8
+ export interface Events {
9
+ onChangeEvent: MenuPopoverChangeEvent;
10
+ onActionEvent: MenuPopoverActionEvent;
11
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,9 +1,11 @@
1
+ import type MenuItem from '../menuitem';
2
+ import type MenuPopover from './menupopover.component';
1
3
  /**
2
4
  * Checks if the given menu item is a valid menu item.
3
5
  * @param menuItem - The menu item to check.
4
6
  * @returns True if the menu item is a valid menu item, false otherwise.
5
7
  */
6
8
  declare const isValidMenuItem: (menuItem: Element | null) => boolean;
7
- declare const isValidPopover: (menuItem: Element | null) => boolean;
8
- declare const isActiveMenuItem: (menuItem: Element | null) => boolean;
9
+ declare const isValidPopover: (el: Element | null) => el is MenuPopover;
10
+ declare const isActiveMenuItem: (menuItem: Element | null) => menuItem is MenuItem;
9
11
  export { isValidMenuItem, isValidPopover, isActiveMenuItem };
@@ -11,6 +11,6 @@ const isValidMenuItem = (menuItem) => {
11
11
  var _a, _b;
12
12
  return [MENUITEM_TAGNAME, MENUITEMCHECKBOX_TAGNAME, MENUITEMRADIO_TAGNAME].includes((_b = (_a = menuItem === null || menuItem === void 0 ? void 0 : menuItem.tagName) === null || _a === void 0 ? void 0 : _a.toLowerCase) === null || _b === void 0 ? void 0 : _b.call(_a));
13
13
  };
14
- const isValidPopover = (menuItem) => { var _a; return ((_a = menuItem === null || menuItem === void 0 ? void 0 : menuItem.tagName) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === MENUPOPOVER_TAGNAME; };
14
+ const isValidPopover = (el) => { var _a; return ((_a = el === null || el === void 0 ? void 0 : el.tagName) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === MENUPOPOVER_TAGNAME; };
15
15
  const isActiveMenuItem = (menuItem) => { var _a, _b; return ((_b = (_a = menuItem === null || menuItem === void 0 ? void 0 : menuItem.tagName) === null || _a === void 0 ? void 0 : _a.toLowerCase) === null || _b === void 0 ? void 0 : _b.call(_a)) === MENUITEM_TAGNAME && !menuItem.hasAttribute('disabled'); };
16
16
  export { isValidMenuItem, isValidPopover, isActiveMenuItem };
@@ -1,4 +1,4 @@
1
- import { CSSResult } from 'lit';
1
+ import { CSSResult, PropertyValues } from 'lit';
2
2
  import { Component } from '../../models';
3
3
  /**
4
4
  * `mdc-menusection` is a container element used to group a set of menu items.
@@ -12,10 +12,23 @@ import { Component } from '../../models';
12
12
  * @tagname mdc-menusection
13
13
  *
14
14
  * @slot - Default slot for inserting `menuitem`, `menuitemcheckbox`, or `menuitemradio`
15
+ *
16
+ * @event change - (React: onChange) This event is dispatched when a `menuitemcheckbox`, or `menuitemradio` changes.
15
17
  */
16
18
  declare class MenuSection extends Component {
19
+ /**
20
+ * The primary headerText of the list item.
21
+ * This appears on the leading side of the list item.
22
+ */
23
+ ariaLabel: string | null;
24
+ /**
25
+ * The primary headerText of the list item.
26
+ * This appears on the leading side of the list item.
27
+ */
28
+ headerText: string | null;
17
29
  connectedCallback(): void;
18
- disconnectedCallback(): void;
30
+ update(changedProperties: PropertyValues): void;
31
+ private renderLabel;
19
32
  render(): import("lit-html").TemplateResult<1>;
20
33
  static styles: CSSResult[];
21
34
  }
@@ -1,6 +1,18 @@
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 { property } from 'lit/decorators.js';
2
12
  import { Component } from '../../models';
3
13
  import { ROLE } from '../../utils/roles';
14
+ import { TYPE, VALID_TEXT_TAGS } from '../text/text.constants';
15
+ import styles from './menusection.styles';
4
16
  /**
5
17
  * `mdc-menusection` is a container element used to group a set of menu items.
6
18
  *
@@ -13,18 +25,57 @@ import { ROLE } from '../../utils/roles';
13
25
  * @tagname mdc-menusection
14
26
  *
15
27
  * @slot - Default slot for inserting `menuitem`, `menuitemcheckbox`, or `menuitemradio`
28
+ *
29
+ * @event change - (React: onChange) This event is dispatched when a `menuitemcheckbox`, or `menuitemradio` changes.
16
30
  */
17
31
  class MenuSection extends Component {
32
+ constructor() {
33
+ super(...arguments);
34
+ /**
35
+ * The primary headerText of the list item.
36
+ * This appears on the leading side of the list item.
37
+ */
38
+ this.ariaLabel = null;
39
+ /**
40
+ * The primary headerText of the list item.
41
+ * This appears on the leading side of the list item.
42
+ */
43
+ this.headerText = null;
44
+ }
18
45
  connectedCallback() {
19
46
  super.connectedCallback();
20
47
  this.setAttribute('role', ROLE.GROUP);
21
48
  }
22
- disconnectedCallback() {
23
- super.disconnectedCallback();
49
+ update(changedProperties) {
50
+ super.update(changedProperties);
51
+ if ((changedProperties.has('ariaLabel') || changedProperties.has('headerText')) &&
52
+ (!this.ariaLabel || this.ariaLabel === changedProperties.get('headerText'))) {
53
+ // Because IDREF attribute reflection does not work across light and shadow DOM, we either set the
54
+ // `aria-label` directly or use the `ariaLabelledByElements`.
55
+ // Since the later one just released in the major browsers, we do the first one for now.
56
+ // more details: https://nolanlawson.com/2022/11/28/shadow-dom-and-accessibility-the-trouble-with-aria/
57
+ this.ariaLabel = this.headerText || '';
58
+ }
59
+ }
60
+ renderLabel() {
61
+ if (this.headerText) {
62
+ return html `<mdc-text part="header-text" type=${TYPE.BODY_MIDSIZE_BOLD} tagname=${VALID_TEXT_TAGS.DIV}>
63
+ ${this.headerText}
64
+ </mdc-text> `;
65
+ }
66
+ return null;
24
67
  }
25
68
  render() {
26
- return html `<slot></slot>`;
69
+ return html `${this.renderLabel()}<slot></slot>`;
27
70
  }
28
71
  }
29
- MenuSection.styles = [...Component.styles];
72
+ MenuSection.styles = [...Component.styles, ...styles];
73
+ __decorate([
74
+ property({ type: String, reflect: true, attribute: 'aria-label' }),
75
+ __metadata("design:type", Object)
76
+ ], MenuSection.prototype, "ariaLabel", void 0);
77
+ __decorate([
78
+ property({ type: String, reflect: true }),
79
+ __metadata("design:type", Object)
80
+ ], MenuSection.prototype, "headerText", void 0);
30
81
  export default MenuSection;
@@ -1,6 +1,2 @@
1
1
  declare const TAG_NAME: "mdc-menusection";
2
- declare const ARIA_CHECKED_STATES: {
3
- readonly TRUE: "true";
4
- readonly FALSE: "false";
5
- };
6
- export { ARIA_CHECKED_STATES, TAG_NAME };
2
+ export { TAG_NAME };
@@ -1,7 +1,3 @@
1
1
  import utils from '../../utils/tag-name';
2
2
  const TAG_NAME = utils.constructTagName('menusection');
3
- const ARIA_CHECKED_STATES = {
4
- TRUE: 'true',
5
- FALSE: 'false',
6
- };
7
- export { ARIA_CHECKED_STATES, TAG_NAME };
3
+ export { TAG_NAME };
@@ -0,0 +1,2 @@
1
+ declare const _default: import("lit").CSSResult[];
2
+ export default _default;
@@ -0,0 +1,11 @@
1
+ import { css } from 'lit';
2
+ const styles = css `
3
+ :host > .mdc-menusection__label {
4
+ padding: 0.5rem 0.75rem;
5
+ }
6
+
7
+ ::slotted(mdc-divider) {
8
+ margin-block: 0.25rem;
9
+ }
10
+ `;
11
+ export default [styles];
@@ -1,4 +1,7 @@
1
- import { ValueOf } from '../../utils/types';
2
- import { ARIA_CHECKED_STATES } from './menusection.constants';
3
- type AriaCheckedStates = ValueOf<typeof ARIA_CHECKED_STATES>;
4
- export type { AriaCheckedStates };
1
+ import type MenuItem from '../menuitem';
2
+ export type MenuSectionChangeEvent = Event & {
3
+ target: MenuItem;
4
+ };
5
+ export interface Events {
6
+ onChangeEvent: MenuSectionChangeEvent;
7
+ }