@m3e/menu 1.0.0-rc.1 → 1.0.0-rc.2

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 (40) hide show
  1. package/README.md +1 -2
  2. package/dist/custom-elements.json +3270 -34
  3. package/dist/html-custom-data.json +12 -6
  4. package/dist/index.js +8 -8
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.min.js +7 -7
  7. package/dist/index.min.js.map +1 -1
  8. package/package.json +4 -4
  9. package/cem.config.mjs +0 -16
  10. package/demo/index.html +0 -112
  11. package/dist/src/MenuElement.d.ts +0 -143
  12. package/dist/src/MenuElement.d.ts.map +0 -1
  13. package/dist/src/MenuItemCheckboxElement.d.ts +0 -76
  14. package/dist/src/MenuItemCheckboxElement.d.ts.map +0 -1
  15. package/dist/src/MenuItemElement.d.ts +0 -113
  16. package/dist/src/MenuItemElement.d.ts.map +0 -1
  17. package/dist/src/MenuItemElementBase.d.ts +0 -21
  18. package/dist/src/MenuItemElementBase.d.ts.map +0 -1
  19. package/dist/src/MenuItemGroupElement.d.ts +0 -28
  20. package/dist/src/MenuItemGroupElement.d.ts.map +0 -1
  21. package/dist/src/MenuItemRadioElement.d.ts +0 -77
  22. package/dist/src/MenuItemRadioElement.d.ts.map +0 -1
  23. package/dist/src/MenuPosition.d.ts +0 -5
  24. package/dist/src/MenuPosition.d.ts.map +0 -1
  25. package/dist/src/MenuTriggerElement.d.ts +0 -86
  26. package/dist/src/MenuTriggerElement.d.ts.map +0 -1
  27. package/dist/src/index.d.ts +0 -8
  28. package/dist/src/index.d.ts.map +0 -1
  29. package/eslint.config.mjs +0 -13
  30. package/rollup.config.js +0 -32
  31. package/src/MenuElement.ts +0 -449
  32. package/src/MenuItemCheckboxElement.ts +0 -178
  33. package/src/MenuItemElement.ts +0 -210
  34. package/src/MenuItemElementBase.ts +0 -158
  35. package/src/MenuItemGroupElement.ts +0 -37
  36. package/src/MenuItemRadioElement.ts +0 -169
  37. package/src/MenuPosition.ts +0 -5
  38. package/src/MenuTriggerElement.ts +0 -154
  39. package/src/index.ts +0 -7
  40. package/tsconfig.json +0 -9
@@ -1,178 +0,0 @@
1
- import { css, CSSResultGroup, html } from "lit";
2
- import { customElement } from "lit/decorators.js";
3
-
4
- import { Checked, hasAssignedNodes, Role } from "@m3e/core";
5
-
6
- import { M3eMenuItemElement } from "./MenuItemElement";
7
- import { MenuItemElementBase } from "./MenuItemElementBase";
8
-
9
- /**
10
- * @summary
11
- * An item of a menu which supports a checkable state.
12
- *
13
- * @description
14
- * The `m3e-menu-item-checkbox` component represents a menu item that supports an independent checkable state.
15
- * It allows users to toggle options on or off without affecting other items in the menu, making it ideal for
16
- * multi-select scenarios such as filters, visibility toggles, or feature flags. This component encodes a persistent
17
- * selection contract and can coexist with other checkbox or radio items within the same menu.
18
- *
19
- * @example
20
- * The following example illustrates use of the `m3e-menu-item-checkbox` to present multiple independent checkable
21
- * items in a menu.
22
- * ```html
23
- * <m3e-button>
24
- * <m3e-menu-trigger for="menu">Format</m3e-menu-trigger>
25
- * </m3e-button>
26
- * <m3e-menu id="menu">
27
- * <m3e-menu-item-checkbox>Bold</m3e-menu-item-checkbox>
28
- * <m3e-menu-item-checkbox>Italic</m3e-menu-item-checkbox>
29
- * <m3e-menu-item-checkbox>Underline</m3e-menu-item-checkbox>
30
- * </m3e-menu>
31
- * ```
32
- *
33
- * @tag m3e-menu-item-checkbox
34
- *
35
- * @slot - Renders the label of the item.
36
- * @slot icon - Renders an icon before the items's label.
37
- * @slot trailing-icon - Renders an icon after the item's label.
38
- *
39
- * @attr disabled - Whether the element is disabled.
40
- * @attr checked - Whether the element is checked.
41
- *
42
- * @cssprop --m3e-menu-item-container-height - Height of the menu item container.
43
- * @cssprop --m3e-menu-item-color - Text color for unselected, enabled menu items.
44
- * @cssprop --m3e-menu-item-container-hover-color - State layer hover color for unselected items.
45
- * @cssprop --m3e-menu-item-container-focus-color - State layer focus color for unselected items.
46
- * @cssprop --m3e-menu-item-ripple-color - Ripple color for unselected items.
47
- * @cssprop --m3e-menu-selected-color - Text color for selected or expanded items.
48
- * @cssprop --m3e-menu-selected-container-color - Background color for selected or expanded items.
49
- * @cssprop --m3e-menu-item-selected-container-hover-color - State layer hover color for selected items.
50
- * @cssprop --m3e-menu-item-selected-container-focus-color - State layer focus color for selected items.
51
- * @cssprop --m3e-menu-item-selected-ripple-color - Ripple color for selected items.
52
- * @cssprop --m3e-menu-item-disabled-color - Base color for disabled items.
53
- * @cssprop --m3e-menu-item-disabled-opacity - Opacity percentage for disabled item color mix.
54
- * @cssprop --m3e-menu-item-icon-label-space - Horizontal gap between icon and content.
55
- * @cssprop --m3e-menu-item-padding-start - Start padding for the item wrapper.
56
- * @cssprop --m3e-menu-item-padding-end - End padding for the item wrapper.
57
- * @cssprop --m3e-menu-item-label-text-font-size - Font size for menu item text.
58
- * @cssprop --m3e-menu-item-label-text-font-weight - Font weight for menu item text.
59
- * @cssprop --m3e-menu-item-label-text-line-height - Line height for menu item text.
60
- * @cssprop --m3e-menu-item-label-text-tracking - Letter spacing for menu item text.
61
- * @cssprop --m3e-menu-item-focus-ring-shape - Border radius for the focus ring.
62
- * @cssprop --m3e-menu-item-icon-size - Font size for leading and trailing icons.
63
- */
64
- @customElement("m3e-menu-item-checkbox")
65
- export class M3eMenuItemCheckboxElement extends Checked(Role(MenuItemElementBase, "menuitemcheckbox")) {
66
- /** The styles of the element. */
67
- static override styles: CSSResultGroup = [
68
- MenuItemElementBase.styles,
69
- css`
70
- .icon {
71
- display: flex;
72
- align-items: center;
73
- justify-content: center;
74
- }
75
- :host(:not(.-with-icon)) .icon {
76
- margin-inline-start: calc(0px - var(--m3e-menu-item-icon-label-space, 0.75rem));
77
- }
78
- .check {
79
- width: 1em;
80
- font-size: var(--m3e-menu-item-icon-size, 1.5rem) !important;
81
- }
82
- :host(:not([checked])) .check {
83
- display: none;
84
- }
85
- :host([checked]) .icon {
86
- margin-inline-start: 0;
87
- }
88
- :host([checked]) ::slotted([slot="icon"]) {
89
- display: none !important;
90
- }
91
- `,
92
- ];
93
-
94
- /** @internal */ readonly #clickHandler = (e: Event) => this.#handleClick(e);
95
- /** @internal */ readonly #keyDownHandler = (e: KeyboardEvent) => this.#handleKeyDown(e);
96
- /** @internal */ readonly #keyUpHandler = () => this.#handleKeyUp();
97
- /** @internal */ readonly #mouseEnterHandler = () => this.#handleMouseEnter();
98
- /** @internal */ #spacePressed = false;
99
-
100
- /** @inheritdoc */
101
- override connectedCallback(): void {
102
- super.connectedCallback();
103
-
104
- this.addEventListener("click", this.#clickHandler);
105
- this.addEventListener("keydown", this.#keyDownHandler);
106
- this.addEventListener("keyup", this.#keyUpHandler);
107
- this.addEventListener("mouseenter", this.#mouseEnterHandler);
108
- }
109
-
110
- /** @inheritdoc */
111
- override disconnectedCallback(): void {
112
- super.disconnectedCallback();
113
-
114
- this.removeEventListener("click", this.#clickHandler);
115
- this.removeEventListener("keydown", this.#keyDownHandler);
116
- this.removeEventListener("keyup", this.#keyUpHandler);
117
- this.removeEventListener("mouseenter", this.#mouseEnterHandler);
118
- }
119
-
120
- /** @internal @inheritdoc */
121
- protected override _renderContent(): unknown {
122
- return html` <div class="icon">
123
- <svg class="check" viewBox="0 -960 960 960" aria-hidden="true">
124
- <path fill="currentColor" d="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z" />
125
- </svg>
126
- <slot name="icon" @slotchange="${this.#handleIconSlotChange}"></slot>
127
- </div>
128
- <slot></slot>
129
- <slot name="trailing-icon" aria-hidden="true" @slotchange="${this.#handleTrailingIconSlotChange}"></slot>`;
130
- }
131
-
132
- /** @internal */
133
- #handleIconSlotChange(e: Event): void {
134
- this.classList.toggle("-with-icon", hasAssignedNodes(<HTMLSlotElement>e.target));
135
- }
136
-
137
- /** @internal */
138
- #handleTrailingIconSlotChange(e: Event): void {
139
- this.classList.toggle("-with-trailing-icon", hasAssignedNodes(<HTMLSlotElement>e.target));
140
- }
141
-
142
- /** @internal */
143
- #handleClick(e: Event): void {
144
- if (!e.defaultPrevented) {
145
- this.checked = !this.checked;
146
- this.performUpdate();
147
-
148
- if (!this.#spacePressed) {
149
- this.menu?.hideAll(true);
150
- }
151
- }
152
- }
153
-
154
- /** @internal */
155
- #handleKeyDown(e: KeyboardEvent): void {
156
- this.#spacePressed = e.key === " ";
157
- }
158
-
159
- /** @internal */
160
- #handleKeyUp(): void {
161
- this.#spacePressed = false;
162
- }
163
-
164
- /** @internal */
165
- #handleMouseEnter(): void {
166
- this.menu?.items.forEach((item) => {
167
- if (item instanceof M3eMenuItemElement && item.submenu?.isOpen) {
168
- item.submenu.hide();
169
- }
170
- });
171
- }
172
- }
173
-
174
- declare global {
175
- interface HTMLElementTagNameMap {
176
- "m3e-menu-item-checkbox": M3eMenuItemCheckboxElement;
177
- }
178
- }
@@ -1,210 +0,0 @@
1
- import { html } from "lit";
2
- import { customElement, state } from "lit/decorators.js";
3
-
4
- import { hasAssignedNodes, HoverController, LinkButton, Role } from "@m3e/core";
5
-
6
- import type { M3eMenuElement } from "./MenuElement";
7
- import { MenuItemElementBase } from "./MenuItemElementBase";
8
- import { M3eMenuTriggerElement } from "./MenuTriggerElement";
9
-
10
- /**
11
- * @summary
12
- * An item of a menu.
13
- *
14
- * @description
15
- * The `m3e-menu-item` component represents a single actionable item within a menu, supporting standard
16
- * click behavior, optional link semantics, and flexible icon placement for navigation, commands, or
17
- * contextual actions. It behaves as a button or link depending on its attributes, and can trigger a submenu
18
- * when a nested `m3e-menu-trigger` is present—enabling hierarchical flows.
19
- *
20
- * @example
21
- * The following example illustrates a basic menu. The `m3e-menu-trigger` is used to trigger a `m3e-menu` specified
22
- * by the `for` attribute when its parenting element is activated.
23
- * ```html
24
- * <m3e-button>
25
- * <m3e-menu-trigger for="menu1">Basic menu</m3e-menu-trigger>
26
- * </m3e-button>
27
- * <m3e-menu id="menu1">
28
- * <m3e-menu-item>Apple</m3e-menu-item>
29
- * <m3e-menu-item>Apricot</m3e-menu-item>
30
- * <m3e-menu-item>Avocado</m3e-menu-item>
31
- * <m3e-menu-item>Green Apple</m3e-menu-item>
32
- * <m3e-menu-item>Green Grapes</m3e-menu-item>
33
- * <m3e-menu-item>Olive</m3e-menu-item>
34
- * <m3e-menu-item>Orange</m3e-menu-item>
35
- * </m3e-menu>
36
- * ```
37
- *
38
- * @example
39
- * The next example illustrates nested menus. Submenus are triggered by placing a `m3e-menu-trigger` inside a `m3e-menu-item`.
40
- * ```html
41
- * <m3e-button>
42
- * <m3e-menu-trigger for="menu2">Nested menus</m3e-menu-trigger>
43
- * </m3e-button>
44
- * <m3e-menu id="menu2">
45
- * <m3e-menu-item>
46
- * <m3e-menu-trigger for="menu3">Fruits with A</m3e-menu-trigger>
47
- * </m3e-menu-item>
48
- * <m3e-menu-item>Grapes</m3e-menu-item>
49
- * <m3e-menu-item>Olive</m3e-menu-item>
50
- * <m3e-menu-item>Orange</m3e-menu-item>
51
- * </m3e-menu>
52
- * <m3e-menu id="menu3">
53
- * <m3e-menu-item>Apricot</m3e-menu-item>
54
- * <m3e-menu-item>Avocado</m3e-menu-item>
55
- * <m3e-menu-item>
56
- * <m3e-menu-trigger for="menu4">Apples</m3e-menu-trigger>
57
- * </m3e-menu-item>
58
- * </m3e-menu>
59
- * <m3e-menu id="menu4">
60
- * <m3e-menu-item>Fuji</m3e-menu-item>
61
- * <m3e-menu-item>Granny Smith</m3e-menu-item>
62
- * <m3e-menu-item>Red Delicious</m3e-menu-item>
63
- * </m3e-menu>
64
- * ```
65
- *
66
- * @tag m3e-menu-item
67
- *
68
- * @slot - Renders the label of the item.
69
- * @slot icon - Renders an icon before the items's label.
70
- * @slot trailing-icon - Renders an icon after the item's label.
71
- *
72
- * @attr disabled - Whether the element is disabled.
73
- * @attr download - Whether the `target` of the link button will be downloaded, optionally specifying the new name of the file.
74
- * @attr href - The URL to which the link button points.
75
- * @attr rel - The relationship between the `target` of the link button and the document.
76
- * @attr target - The target of the link button.
77
- *
78
- * @cssprop --m3e-menu-item-container-height - Height of the menu item container.
79
- * @cssprop --m3e-menu-item-color - Text color for unselected, enabled menu items.
80
- * @cssprop --m3e-menu-item-container-hover-color - State layer hover color for unselected items.
81
- * @cssprop --m3e-menu-item-container-focus-color - State layer focus color for unselected items.
82
- * @cssprop --m3e-menu-item-ripple-color - Ripple color for unselected items.
83
- * @cssprop --m3e-menu-selected-color - Text color for selected or expanded items.
84
- * @cssprop --m3e-menu-selected-container-color - Background color for selected or expanded items.
85
- * @cssprop --m3e-menu-item-selected-container-hover-color - State layer hover color for selected items.
86
- * @cssprop --m3e-menu-item-selected-container-focus-color - State layer focus color for selected items.
87
- * @cssprop --m3e-menu-item-selected-ripple-color - Ripple color for selected items.
88
- * @cssprop --m3e-menu-item-disabled-color - Base color for disabled items.
89
- * @cssprop --m3e-menu-item-disabled-opacity - Opacity percentage for disabled item color mix.
90
- * @cssprop --m3e-menu-item-icon-label-space - Horizontal gap between icon and content.
91
- * @cssprop --m3e-menu-item-padding-start - Start padding for the item wrapper.
92
- * @cssprop --m3e-menu-item-padding-end - End padding for the item wrapper.
93
- * @cssprop --m3e-menu-item-label-text-font-size - Font size for menu item text.
94
- * @cssprop --m3e-menu-item-label-text-font-weight - Font weight for menu item text.
95
- * @cssprop --m3e-menu-item-label-text-line-height - Line height for menu item text.
96
- * @cssprop --m3e-menu-item-label-text-tracking - Letter spacing for menu item text.
97
- * @cssprop --m3e-menu-item-focus-ring-shape - Border radius for the focus ring.
98
- * @cssprop --m3e-menu-item-icon-size - Font size for leading and trailing icons.
99
- */
100
- @customElement("m3e-menu-item")
101
- export class M3eMenuItemElement extends LinkButton(Role(MenuItemElementBase, "menuitem")) {
102
- /** @private */ readonly #clickHandler = (e: Event) => this.#handleClick(e);
103
- /** @private */ readonly #keyDownHandler = (e: KeyboardEvent) => this.#handleKeyDown(e);
104
- /** @private */ readonly #mouseEnterHandler = () => this.#handleMouseEnter();
105
-
106
- /** @private */ @state() private _hasSubmenu = false;
107
- /** @private */ #submenuTrigger?: M3eMenuTriggerElement;
108
-
109
- constructor() {
110
- super();
111
-
112
- new HoverController(this, {
113
- startDelay: 500,
114
- endDelay: 500,
115
- callback: (hovering) => {
116
- if (hovering && !this.disabled && this.#submenuTrigger) {
117
- this.#submenuTrigger.menu?.show(this);
118
- }
119
- },
120
- });
121
- }
122
-
123
- /** The submenu triggered by the item. */
124
- get submenu(): M3eMenuElement | null {
125
- return this.#submenuTrigger?.menu ?? null;
126
- }
127
-
128
- /** @inheritdoc */
129
- override connectedCallback(): void {
130
- super.connectedCallback();
131
-
132
- this.addEventListener("click", this.#clickHandler);
133
- this.addEventListener("keydown", this.#keyDownHandler);
134
- this.addEventListener("mouseenter", this.#mouseEnterHandler);
135
- }
136
-
137
- /** @inheritdoc */
138
- override disconnectedCallback(): void {
139
- super.disconnectedCallback();
140
-
141
- this.removeEventListener("click", this.#clickHandler);
142
- this.removeEventListener("keydown", this.#keyDownHandler);
143
- this.removeEventListener("mouseenter", this.#mouseEnterHandler);
144
- }
145
-
146
- /** @internal @inheritdoc */
147
- protected override _renderContent(): unknown {
148
- return html`<slot name="icon" aria-hidden="true" @slotchange="${this.#iconSlotChangeHandler}"></slot>
149
- <span class="content"><slot @slotchange="${this.#defaultSlotChangeHandler}"></slot></span>
150
- ${this._hasSubmenu
151
- ? html`<svg class="trailing-icon" aria-hidden="true" viewBox="0 -960 960 960" fill="currentColor">
152
- <path d="M400-280v-400l200 200-200 200Z" />
153
- </svg>`
154
- : html`<slot name="trailing-icon" aria-hidden="true" @slotchange="${this.#trailingIconSlotChangeHandler}">
155
- </slot>`}`;
156
- }
157
-
158
- /** @private */
159
- #defaultSlotChangeHandler(e: Event): void {
160
- this.#submenuTrigger = (<HTMLSlotElement>e.target)
161
- .assignedElements({ flatten: true })
162
- .find((x) => x instanceof M3eMenuTriggerElement);
163
- this._hasSubmenu = this.#submenuTrigger !== undefined;
164
- }
165
-
166
- /** @private */
167
- #iconSlotChangeHandler(e: Event): void {
168
- this.classList.toggle("-with-icon", hasAssignedNodes(<HTMLSlotElement>e.target));
169
- }
170
-
171
- /** @private */
172
- #trailingIconSlotChangeHandler(e: Event): void {
173
- this.classList.toggle("-with-trailing-icon", hasAssignedNodes(<HTMLSlotElement>e.target));
174
- }
175
-
176
- /** @private */
177
- #handleClick(e: Event): void {
178
- if (!e.defaultPrevented && !this._hasSubmenu) {
179
- this.menu?.hideAll(true);
180
- }
181
- }
182
-
183
- /** @private */
184
- #handleKeyDown(e: KeyboardEvent): void {
185
- if (e.defaultPrevented || this.disabled) return;
186
-
187
- switch (e.key) {
188
- case "Right":
189
- case "ArrowRight":
190
- e.preventDefault();
191
- this.submenu?.show(this);
192
- break;
193
- }
194
- }
195
-
196
- /** @private */
197
- #handleMouseEnter(): void {
198
- this.menu?.items.forEach((item) => {
199
- if (item instanceof M3eMenuItemElement && item !== this && item.submenu?.isOpen) {
200
- item.submenu.hide();
201
- }
202
- });
203
- }
204
- }
205
-
206
- declare global {
207
- interface HTMLElementTagNameMap {
208
- "m3e-menu-item": M3eMenuItemElement;
209
- }
210
- }
@@ -1,158 +0,0 @@
1
- import { css, CSSResultGroup, html, LitElement, nothing, PropertyValues } from "lit";
2
- import { query } from "lit/decorators.js";
3
-
4
- import {
5
- AttachInternals,
6
- DesignToken,
7
- Disabled,
8
- Focusable,
9
- isLinkButtonMixin,
10
- KeyboardClick,
11
- M3eFocusRingElement,
12
- M3eRippleElement,
13
- M3eStateLayerElement,
14
- renderPseudoLink,
15
- } from "@m3e/core";
16
-
17
- import type { M3eMenuElement } from "./MenuElement";
18
-
19
- /** A base implementation for an item of a menu. This class must be inherited. */
20
- export abstract class MenuItemElementBase extends KeyboardClick(
21
- Focusable(AttachInternals(Disabled(LitElement), true))
22
- ) {
23
- /** The styles of the element. */
24
- static override styles: CSSResultGroup = css`
25
- :host {
26
- display: inline-block;
27
- outline: none;
28
- user-select: none;
29
- flex: none;
30
- height: var(--m3e-menu-item-container-height, 3rem);
31
- }
32
- :host(:not(:focus-visible)) .base {
33
- --m3e-state-layer-focus-opacity: 0;
34
- }
35
- :host(:not(:disabled):not([aria-expanded="true"])) .base {
36
- color: var(--m3e-menu-item-color, ${DesignToken.color.onSurface});
37
- }
38
- :host(:not([aria-expanded="true"])) .base {
39
- --m3e-state-layer-hover-color: var(--m3e-menu-item-container-hover-color, ${DesignToken.color.onSurface});
40
- --m3e-state-layer-focus-color: var(--m3e-menu-item-container-focus-color, ${DesignToken.color.onSurface});
41
- --m3e-ripple-color: var(--m3e-menu-item-ripple-color, ${DesignToken.color.onSurface});
42
- }
43
- :host(:not(:disabled)[checked]) .base,
44
- :host(:not(:disabled)[aria-expanded="true"]) .base {
45
- color: var(--m3e-menu-selected-color, ${DesignToken.color.onSecondaryContainer});
46
- background-color: var(--m3e-menu-selected-container-color, ${DesignToken.color.secondaryContainer});
47
- }
48
- :host([checked]) .base,
49
- :host([aria-expanded="true"]) .base {
50
- --m3e-state-layer-hover-color: var(
51
- --m3e-menu-item-selected-container-hover-color,
52
- ${DesignToken.color.onSecondaryContainer}
53
- );
54
- --m3e-state-layer-focus-color: var(
55
- --m3e-menu-item-selected-container-focus-color,
56
- ${DesignToken.color.onSecondaryContainer}
57
- );
58
- --m3e-ripple-color: var(--m3e-menu-item-selected-ripple-color, ${DesignToken.color.onSecondaryContainer});
59
- }
60
- :host(:not(:disabled)) {
61
- cursor: pointer;
62
- }
63
- :host(:disabled) .base {
64
- color: color-mix(
65
- in srgb,
66
- var(--m3e-menu-item-disabled-color, ${DesignToken.color.onSurface}) var(--m3e-menu-item-disabled-opacity, 38%),
67
- transparent
68
- );
69
- }
70
- .base {
71
- box-sizing: border-box;
72
- vertical-align: middle;
73
- display: inline-flex;
74
- align-items: center;
75
- position: relative;
76
- width: 100%;
77
- height: 100%;
78
- }
79
- .touch {
80
- position: absolute;
81
- height: 3rem;
82
- left: 0;
83
- right: 0;
84
- }
85
- .wrapper {
86
- display: inline-flex;
87
- align-items: center;
88
- column-gap: var(--m3e-menu-item-icon-label-space, 0.75rem);
89
- padding-inline-start: var(--m3e-menu-item-padding-start, 0.75rem);
90
- padding-inline-end: var(--m3e-menu-item-padding-end, 0.75rem);
91
- font-size: var(--m3e-menu-item-label-text-font-size, ${DesignToken.typescale.standard.label.large.fontSize});
92
- font-weight: var(
93
- --m3e-menu-item-label-text-font-weight,
94
- ${DesignToken.typescale.standard.label.large.fontWeight}
95
- );
96
- line-height: var(
97
- --m3e-menu-item-label-text-line-height,
98
- ${DesignToken.typescale.standard.label.large.lineHeight}
99
- );
100
- letter-spacing: var(--m3e-menu-item-label-text-tracking, ${DesignToken.typescale.standard.label.large.tracking});
101
- }
102
- .focus-ring {
103
- border-radius: var(--m3e-menu-item-focus-ring-shape, ${DesignToken.shape.corner.medium});
104
- }
105
- .content {
106
- flex: 1 1 auto;
107
- overflow: hidden;
108
- text-overflow: ellipsis;
109
- white-space: nowrap;
110
- }
111
- ::slotted([slot="icon"]),
112
- ::slotted([slot="trailing-icon"]),
113
- .trailing-icon {
114
- flex: none;
115
- width: 1em;
116
- font-size: var(--m3e-menu-item-icon-size, 1.5rem) !important;
117
- }
118
- @media (forced-colors: active) {
119
- .base {
120
- background-color: Menu;
121
- color: MenuText;
122
- }
123
- :host(:disabled) .base {
124
- color: GrayText;
125
- }
126
- }
127
- `;
128
-
129
- /** @private */ @query(".focus-ring") private readonly _focusRing?: M3eFocusRingElement;
130
- /** @private */ @query(".state-layer") private readonly _stateLayer?: M3eStateLayerElement;
131
- /** @private */ @query(".ripple") private readonly _ripple?: M3eRippleElement;
132
-
133
- /** The menu to which this item belongs. */
134
- get menu(): M3eMenuElement | null {
135
- return this.closest("m3e-menu");
136
- }
137
-
138
- /** @inheritdoc */
139
- protected override firstUpdated(_changedProperties: PropertyValues<this>): void {
140
- super.firstUpdated(_changedProperties);
141
- [this._focusRing, this._stateLayer, this._ripple].forEach((x) => x?.attach(this));
142
- }
143
-
144
- /** @inheritdoc */
145
- override render(): unknown {
146
- return html`<div class="base">
147
- <m3e-state-layer class="state-layer" ?disabled="${this.disabled}"></m3e-state-layer>
148
- <m3e-focus-ring class="focus-ring" inward ?disabled="${this.disabled}"></m3e-focus-ring>
149
- <m3e-ripple class="ripple" ?disabled="${this.disabled}"></m3e-ripple>
150
- <div class="touch" aria-hidden="true"></div>
151
- ${isLinkButtonMixin(this) ? this[renderPseudoLink]() : nothing}
152
- <div class="wrapper">${this._renderContent()}</div>
153
- </div>`;
154
- }
155
-
156
- /** @internal Renders the content of the item. */
157
- protected abstract _renderContent(): unknown;
158
- }
@@ -1,37 +0,0 @@
1
- import { Role } from "@m3e/core";
2
- import { css, CSSResultGroup, html, LitElement } from "lit";
3
- import { customElement } from "lit/decorators.js";
4
-
5
- /**
6
- * @summary
7
- * Groups related items (such a radios) in a menu.
8
- *
9
- * @description
10
- * The `m3e-menu-item-group` component groups related items within a menu, establishing a shared
11
- * context for interaction and selection. It enables separation of concerns—such as organizing radio
12
- * items into mutually exclusive sets.
13
- *
14
- * @tag m3e-menu-item-group
15
- *
16
- * @slot - Renders the contents of the group.
17
- */
18
- @customElement("m3e-menu-item-group")
19
- export class M3eMenuItemGroupElement extends Role(LitElement, "group") {
20
- /** The styles of the element. */
21
- static override styles: CSSResultGroup = css`
22
- :host {
23
- display: contents;
24
- }
25
- `;
26
-
27
- /** @inheritdoc */
28
- protected override render(): unknown {
29
- return html`<slot></slot>`;
30
- }
31
- }
32
-
33
- declare global {
34
- interface HTMLElementTagNameMap {
35
- "m3e-menu-item-group": M3eMenuItemGroupElement;
36
- }
37
- }