@vonage/vivid 3.5.0 → 3.7.0

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 (93) hide show
  1. package/README.md +31 -14
  2. package/banner/index.js +2 -0
  3. package/breadcrumb/index.js +1 -1
  4. package/breadcrumb-item/index.js +1 -1
  5. package/button/index.js +2 -0
  6. package/calendar/index.js +1 -1
  7. package/calendar-event/index.js +1 -1
  8. package/card/index.js +2 -2
  9. package/checkbox/index.js +1 -1
  10. package/combobox/index.js +6 -4
  11. package/custom-elements.json +302 -0
  12. package/data-grid/index.js +1 -1
  13. package/dialog/index.js +4 -2
  14. package/divider/index.js +1 -1
  15. package/elevation/index.js +1 -1
  16. package/fab/index.js +1 -1
  17. package/header/index.js +2 -2
  18. package/index.js +26 -26
  19. package/layout/index.js +1 -1
  20. package/lib/accordion-item/accordion-item.d.ts +3 -0
  21. package/lib/action-group/action-group.d.ts +2 -0
  22. package/lib/button/button.d.ts +1 -0
  23. package/lib/button/button.template.d.ts +1 -1
  24. package/lib/select/select.d.ts +2 -3
  25. package/listbox/index.js +2 -2
  26. package/menu/index.js +6 -4
  27. package/menu-item/index.js +1 -1
  28. package/nav/index.js +1 -1
  29. package/nav-disclosure/index.js +1 -1
  30. package/nav-item/index.js +1 -1
  31. package/note/index.js +1 -1
  32. package/number-field/index.js +4 -2
  33. package/option/index.js +1 -1
  34. package/package.json +1 -1
  35. package/popup/index.js +4 -2
  36. package/progress/index.js +1 -1
  37. package/progress-ring/index.js +1 -1
  38. package/select/index.js +5 -3
  39. package/shared/definition.js +1 -1
  40. package/shared/definition10.js +69 -91
  41. package/shared/definition11.js +91 -40
  42. package/shared/definition12.js +31 -755
  43. package/shared/definition13.js +754 -93
  44. package/shared/definition14.js +100 -103
  45. package/shared/definition15.js +106 -24
  46. package/shared/definition16.js +24 -164
  47. package/shared/definition17.js +108 -663
  48. package/shared/definition18.js +667 -1533
  49. package/shared/definition19.js +1545 -223
  50. package/shared/definition2.js +8 -7
  51. package/shared/definition20.js +183 -964
  52. package/shared/definition21.js +1037 -222
  53. package/shared/definition22.js +226 -67
  54. package/shared/definition23.js +68 -77
  55. package/shared/definition24.js +76 -47
  56. package/shared/definition25.js +46 -32
  57. package/shared/definition26.js +35 -49
  58. package/shared/definition27.js +48 -344
  59. package/shared/definition28.js +273 -282
  60. package/shared/definition29.js +356 -14
  61. package/shared/definition30.js +13 -67
  62. package/shared/definition31.js +65 -21
  63. package/shared/definition32.js +21 -39
  64. package/shared/definition33.js +31 -432
  65. package/shared/definition34.js +432 -76
  66. package/shared/definition35.js +76 -59
  67. package/shared/definition36.js +3 -3
  68. package/shared/definition37.js +1 -1
  69. package/shared/definition38.js +7 -6
  70. package/shared/definition39.js +1 -1
  71. package/shared/definition4.js +1 -1
  72. package/shared/definition41.js +1 -1
  73. package/shared/definition42.js +1 -1
  74. package/shared/definition44.js +1 -1
  75. package/shared/definition45.js +1 -1
  76. package/shared/definition47.js +2 -2
  77. package/shared/definition48.js +1 -1
  78. package/shared/definition5.js +10 -3
  79. package/shared/definition6.js +1 -1
  80. package/shared/definition7.js +1 -1
  81. package/shared/definition8.js +1 -1
  82. package/shared/definition9.js +14 -4
  83. package/shared/form-elements.js +1 -1
  84. package/shared/icon.js +1 -1
  85. package/shared/listbox.js +1 -1
  86. package/shared/patterns/form-elements/form-elements.d.ts +2 -2
  87. package/shared/text-field.js +1 -1
  88. package/styles/core/all.css +1 -1
  89. package/styles/core/theme.css +1 -1
  90. package/styles/core/typography.css +1 -1
  91. package/styles/tokens/theme-dark.css +4 -4
  92. package/styles/tokens/theme-light.css +4 -4
  93. package/tooltip/index.js +4 -2
@@ -1,223 +1,191 @@
1
- import { F as FoundationElement, W as DOM, _ as __decorate, a as attr, o as observable, b as __metadata, h as html, r as registerFactory } from './index.js';
2
- import { i as iconRegistries } from './definition3.js';
3
- import { f as focusRegistries } from './definition4.js';
4
- import { b as AffixIcon, a as affixIconTemplateFactory } from './affix.js';
5
- import { S as StartEnd } from './start-end.js';
6
- import { D as Direction, g as getDirection } from './direction.js';
7
- import { a as applyMixins } from './apply-mixins.js';
8
- import { i as keyArrowLeft, h as keyArrowRight, e as keySpace, d as keyEnter } from './key-codes.js';
9
- import { f as focusTemplateFactory } from './focus2.js';
10
- import { w as when } from './when.js';
11
- import { c as classNames } from './class-names.js';
1
+ import { F as FoundationElement, W as DOM, _ as __decorate, o as observable, a as attr, b as __metadata, h as html, r as registerFactory } from './index.js';
2
+ import { P as Popup, p as popupRegistries } from './definition19.js';
3
+ import { M as MenuItem, a as MenuItemRole, r as roleForMenuItem, m as menuItemRegistries } from './definition29.js';
4
+ import { i as isHTMLElement } from './dom.js';
5
+ import { a as keyHome, k as keyEnd, c as keyArrowUp, b as keyArrowDown } from './key-codes.js';
6
+ import { s as slotted } from './slotted.js';
7
+ import { r as ref } from './ref.js';
12
8
 
13
9
  /**
14
- * Menu items roles.
15
- * @public
16
- */
17
- const MenuItemRole = {
18
- /**
19
- * The menu item has a "menuitem" role
20
- */
21
- menuitem: "menuitem",
22
- /**
23
- * The menu item has a "menuitemcheckbox" role
24
- */
25
- menuitemcheckbox: "menuitemcheckbox",
26
- /**
27
- * The menu item has a "menuitemradio" role
28
- */
29
- menuitemradio: "menuitemradio",
30
- };
31
- /**
32
- * @internal
33
- */
34
- const roleForMenuItem = {
35
- [MenuItemRole.menuitem]: "menuitem",
36
- [MenuItemRole.menuitemcheckbox]: "menuitemcheckbox",
37
- [MenuItemRole.menuitemradio]: "menuitemradio",
38
- };
39
-
40
- /**
41
- * A Switch Custom HTML Element.
42
- * Implements {@link https://www.w3.org/TR/wai-aria-1.1/#menuitem | ARIA menuitem }, {@link https://www.w3.org/TR/wai-aria-1.1/#menuitemcheckbox | ARIA menuitemcheckbox}, or {@link https://www.w3.org/TR/wai-aria-1.1/#menuitemradio | ARIA menuitemradio }.
10
+ * A Menu Custom HTML Element.
11
+ * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#menu | ARIA menu }.
43
12
  *
44
- * @slot checked-indicator - The checked indicator
45
- * @slot radio-indicator - The radio indicator
46
- * @slot start - Content which can be provided before the menu item content
47
- * @slot end - Content which can be provided after the menu item content
48
- * @slot - The default slot for menu item content
49
- * @slot expand-collapse-indicator - The expand/collapse indicator
50
- * @slot submenu - Used to nest menu's within menu items
51
- * @csspart input-container - The element representing the visual checked or radio indicator
52
- * @csspart checkbox - The element wrapping the `menuitemcheckbox` indicator
53
- * @csspart radio - The element wrapping the `menuitemradio` indicator
54
- * @csspart content - The element wrapping the menu item content
55
- * @csspart expand-collapse-glyph-container - The element wrapping the expand collapse element
56
- * @csspart expand-collapse - The expand/collapse element
57
- * @csspart submenu-region - The container for the submenu, used for positioning
58
- * @fires expanded-change - Fires a custom 'expanded-change' event when the expanded state changes
59
- * @fires change - Fires a custom 'change' event when a non-submenu item with a role of `menuitemcheckbox`, `menuitemradio`, or `menuitem` is invoked
13
+ * @slot - The default slot for the menu items
60
14
  *
61
15
  * @public
62
16
  */
63
- class MenuItem$1 extends FoundationElement {
17
+ class Menu$1 extends FoundationElement {
64
18
  constructor() {
65
19
  super(...arguments);
20
+ this.expandedItem = null;
66
21
  /**
67
- * The role of the element.
68
- *
69
- * @public
70
- * @remarks
71
- * HTML Attribute: role
72
- */
73
- this.role = MenuItemRole.menuitem;
74
- /**
75
- * @internal
22
+ * The index of the focusable element in the items array
23
+ * defaults to -1
76
24
  */
77
- this.hasSubmenu = false;
25
+ this.focusIndex = -1;
78
26
  /**
79
- * Track current direction to pass to the anchored region
80
- *
81
27
  * @internal
82
28
  */
83
- this.currentDirection = Direction.ltr;
84
- this.focusSubmenuOnLoad = false;
29
+ this.isNestedMenu = () => {
30
+ return (this.parentElement !== null &&
31
+ isHTMLElement(this.parentElement) &&
32
+ this.parentElement.getAttribute("role") === "menuitem");
33
+ };
85
34
  /**
35
+ * if focus is moving out of the menu, reset to a stable initial state
86
36
  * @internal
87
37
  */
88
- this.handleMenuItemKeyDown = (e) => {
89
- if (e.defaultPrevented) {
90
- return false;
91
- }
92
- switch (e.key) {
93
- case keyEnter:
94
- case keySpace:
95
- this.invoke();
96
- return false;
97
- case keyArrowRight:
98
- //open/focus on submenu
99
- this.expandAndFocus();
100
- return false;
101
- case keyArrowLeft:
102
- //close submenu
103
- if (this.expanded) {
104
- this.expanded = false;
105
- this.focus();
106
- return false;
107
- }
38
+ this.handleFocusOut = (e) => {
39
+ if (!this.contains(e.relatedTarget) && this.menuItems !== undefined) {
40
+ this.collapseExpandedItem();
41
+ // find our first focusable element
42
+ const focusIndex = this.menuItems.findIndex(this.isFocusableElement);
43
+ // set the current focus index's tabindex to -1
44
+ this.menuItems[this.focusIndex].setAttribute("tabindex", "-1");
45
+ // set the first focusable element tabindex to 0
46
+ this.menuItems[focusIndex].setAttribute("tabindex", "0");
47
+ // set the focus index
48
+ this.focusIndex = focusIndex;
108
49
  }
109
- return true;
110
50
  };
111
- /**
112
- * @internal
113
- */
114
- this.handleMenuItemClick = (e) => {
115
- if (e.defaultPrevented || this.disabled) {
116
- return false;
51
+ this.handleItemFocus = (e) => {
52
+ const targetItem = e.target;
53
+ if (this.menuItems !== undefined &&
54
+ targetItem !== this.menuItems[this.focusIndex]) {
55
+ this.menuItems[this.focusIndex].setAttribute("tabindex", "-1");
56
+ this.focusIndex = this.menuItems.indexOf(targetItem);
57
+ targetItem.setAttribute("tabindex", "0");
117
58
  }
118
- this.invoke();
119
- return false;
120
59
  };
121
- /**
122
- * @internal
123
- */
124
- this.submenuLoaded = () => {
125
- if (!this.focusSubmenuOnLoad) {
60
+ this.handleExpandedChanged = (e) => {
61
+ if (e.defaultPrevented ||
62
+ e.target === null ||
63
+ this.menuItems === undefined ||
64
+ this.menuItems.indexOf(e.target) < 0) {
65
+ return;
66
+ }
67
+ e.preventDefault();
68
+ const changedItem = e.target;
69
+ // closing an expanded item without opening another
70
+ if (this.expandedItem !== null &&
71
+ changedItem === this.expandedItem &&
72
+ changedItem.expanded === false) {
73
+ this.expandedItem = null;
126
74
  return;
127
75
  }
128
- this.focusSubmenuOnLoad = false;
129
- if (this.hasSubmenu) {
130
- this.submenu.focus();
131
- this.setAttribute("tabindex", "-1");
76
+ if (changedItem.expanded) {
77
+ if (this.expandedItem !== null && this.expandedItem !== changedItem) {
78
+ this.expandedItem.expanded = false;
79
+ }
80
+ this.menuItems[this.focusIndex].setAttribute("tabindex", "-1");
81
+ this.expandedItem = changedItem;
82
+ this.focusIndex = this.menuItems.indexOf(changedItem);
83
+ changedItem.setAttribute("tabindex", "0");
132
84
  }
133
85
  };
134
- /**
135
- * @internal
136
- */
137
- this.handleMouseOver = (e) => {
138
- if (this.disabled || !this.hasSubmenu || this.expanded) {
139
- return false;
86
+ this.removeItemListeners = () => {
87
+ if (this.menuItems !== undefined) {
88
+ this.menuItems.forEach((item) => {
89
+ item.removeEventListener("expanded-change", this.handleExpandedChanged);
90
+ item.removeEventListener("focus", this.handleItemFocus);
91
+ });
140
92
  }
141
- this.expanded = true;
142
- return false;
143
93
  };
144
- /**
145
- * @internal
146
- */
147
- this.handleMouseOut = (e) => {
148
- if (!this.expanded || this.contains(document.activeElement)) {
149
- return false;
94
+ this.setItems = () => {
95
+ const newItems = this.domChildren();
96
+ this.removeItemListeners();
97
+ this.menuItems = newItems;
98
+ const menuItems = this.menuItems.filter(this.isMenuItemElement);
99
+ // if our focus index is not -1 we have items
100
+ if (menuItems.length) {
101
+ this.focusIndex = 0;
150
102
  }
151
- this.expanded = false;
152
- return false;
103
+ function elementIndent(el) {
104
+ const role = el.getAttribute("role");
105
+ const startSlot = el.querySelector("[slot=start]");
106
+ if (role !== MenuItemRole.menuitem && startSlot === null) {
107
+ return 1;
108
+ }
109
+ else if (role === MenuItemRole.menuitem && startSlot !== null) {
110
+ return 1;
111
+ }
112
+ else if (role !== MenuItemRole.menuitem && startSlot !== null) {
113
+ return 2;
114
+ }
115
+ else {
116
+ return 0;
117
+ }
118
+ }
119
+ const indent = menuItems.reduce((accum, current) => {
120
+ const elementValue = elementIndent(current);
121
+ return accum > elementValue ? accum : elementValue;
122
+ }, 0);
123
+ menuItems.forEach((item, index) => {
124
+ item.setAttribute("tabindex", index === 0 ? "0" : "-1");
125
+ item.addEventListener("expanded-change", this.handleExpandedChanged);
126
+ item.addEventListener("focus", this.handleItemFocus);
127
+ if (item instanceof MenuItem) {
128
+ item.startColumnCount = indent;
129
+ }
130
+ });
153
131
  };
154
132
  /**
155
- * @internal
133
+ * handle change from child element
156
134
  */
157
- this.expandAndFocus = () => {
158
- if (!this.hasSubmenu) {
135
+ this.changeHandler = (e) => {
136
+ if (this.menuItems === undefined) {
159
137
  return;
160
138
  }
161
- this.focusSubmenuOnLoad = true;
162
- this.expanded = true;
163
- };
164
- /**
165
- * @internal
166
- */
167
- this.invoke = () => {
168
- if (this.disabled) {
139
+ const changedMenuItem = e.target;
140
+ const changeItemIndex = this.menuItems.indexOf(changedMenuItem);
141
+ if (changeItemIndex === -1) {
169
142
  return;
170
143
  }
171
- switch (this.role) {
172
- case MenuItemRole.menuitemcheckbox:
173
- this.checked = !this.checked;
174
- break;
175
- case MenuItemRole.menuitem:
176
- // update submenu
177
- this.updateSubmenu();
178
- if (this.hasSubmenu) {
179
- this.expandAndFocus();
144
+ if (changedMenuItem.role === "menuitemradio" &&
145
+ changedMenuItem.checked === true) {
146
+ for (let i = changeItemIndex - 1; i >= 0; --i) {
147
+ const item = this.menuItems[i];
148
+ const role = item.getAttribute("role");
149
+ if (role === MenuItemRole.menuitemradio) {
150
+ item.checked = false;
151
+ }
152
+ if (role === "separator") {
153
+ break;
180
154
  }
181
- else {
182
- this.$emit("change");
155
+ }
156
+ const maxIndex = this.menuItems.length - 1;
157
+ for (let i = changeItemIndex + 1; i <= maxIndex; ++i) {
158
+ const item = this.menuItems[i];
159
+ const role = item.getAttribute("role");
160
+ if (role === MenuItemRole.menuitemradio) {
161
+ item.checked = false;
183
162
  }
184
- break;
185
- case MenuItemRole.menuitemradio:
186
- if (!this.checked) {
187
- this.checked = true;
163
+ if (role === "separator") {
164
+ break;
188
165
  }
189
- break;
166
+ }
190
167
  }
191
168
  };
192
169
  /**
193
- * Gets the submenu element if any
194
- *
195
- * @internal
170
+ * check if the item is a menu item
196
171
  */
197
- this.updateSubmenu = () => {
198
- this.submenu = this.domChildren().find((element) => {
199
- return element.getAttribute("role") === "menu";
200
- });
201
- this.hasSubmenu = this.submenu === undefined ? false : true;
172
+ this.isMenuItemElement = (el) => {
173
+ return (isHTMLElement(el) &&
174
+ Menu$1.focusableElementRoles.hasOwnProperty(el.getAttribute("role")));
175
+ };
176
+ /**
177
+ * check if the item is focusable
178
+ */
179
+ this.isFocusableElement = (el) => {
180
+ return this.isMenuItemElement(el);
202
181
  };
203
182
  }
204
- expandedChanged(oldValue) {
205
- if (this.$fastController.isConnected) {
206
- if (this.submenu === undefined) {
207
- return;
208
- }
209
- if (this.expanded === false) {
210
- this.submenu.collapseExpandedItem();
211
- }
212
- else {
213
- this.currentDirection = getDirection(this);
214
- }
215
- this.$emit("expanded-change", this, { bubbles: false });
216
- }
217
- }
218
- checkedChanged(oldValue, newValue) {
219
- if (this.$fastController.isConnected) {
220
- this.$emit("change");
183
+ itemsChanged(oldValue, newValue) {
184
+ // only update children after the component is connected and
185
+ // the setItems has run on connectedCallback
186
+ // (menuItems is undefined until then)
187
+ if (this.$fastController.isConnected && this.menuItems !== undefined) {
188
+ this.setItems();
221
189
  }
222
190
  }
223
191
  /**
@@ -226,22 +194,67 @@ class MenuItem$1 extends FoundationElement {
226
194
  connectedCallback() {
227
195
  super.connectedCallback();
228
196
  DOM.queueUpdate(() => {
229
- this.updateSubmenu();
197
+ // wait until children have had a chance to
198
+ // connect before setting/checking their props/attributes
199
+ this.setItems();
230
200
  });
231
- if (!this.startColumnCount) {
232
- this.startColumnCount = 1;
233
- }
234
- this.observer = new MutationObserver(this.updateSubmenu);
201
+ this.addEventListener("change", this.changeHandler);
235
202
  }
236
203
  /**
237
204
  * @internal
238
205
  */
239
206
  disconnectedCallback() {
240
207
  super.disconnectedCallback();
241
- this.submenu = undefined;
242
- if (this.observer !== undefined) {
243
- this.observer.disconnect();
244
- this.observer = undefined;
208
+ this.removeItemListeners();
209
+ this.menuItems = undefined;
210
+ this.removeEventListener("change", this.changeHandler);
211
+ }
212
+ /**
213
+ * Focuses the first item in the menu.
214
+ *
215
+ * @public
216
+ */
217
+ focus() {
218
+ this.setFocus(0, 1);
219
+ }
220
+ /**
221
+ * Collapses any expanded menu items.
222
+ *
223
+ * @public
224
+ */
225
+ collapseExpandedItem() {
226
+ if (this.expandedItem !== null) {
227
+ this.expandedItem.expanded = false;
228
+ this.expandedItem = null;
229
+ }
230
+ }
231
+ /**
232
+ * @internal
233
+ */
234
+ handleMenuKeyDown(e) {
235
+ if (e.defaultPrevented || this.menuItems === undefined) {
236
+ return;
237
+ }
238
+ switch (e.key) {
239
+ case keyArrowDown:
240
+ // go forward one index
241
+ this.setFocus(this.focusIndex + 1, 1);
242
+ return;
243
+ case keyArrowUp:
244
+ // go back one index
245
+ this.setFocus(this.focusIndex - 1, -1);
246
+ return;
247
+ case keyEnd:
248
+ // set focus on last item
249
+ this.setFocus(this.menuItems.length - 1, -1);
250
+ return;
251
+ case keyHome:
252
+ // set focus on first item
253
+ this.setFocus(0, 1);
254
+ return;
255
+ default:
256
+ // if we are not handling the event, do not prevent default
257
+ return true;
245
258
  }
246
259
  }
247
260
  /**
@@ -250,114 +263,92 @@ class MenuItem$1 extends FoundationElement {
250
263
  domChildren() {
251
264
  return Array.from(this.children).filter(child => !child.hasAttribute("hidden"));
252
265
  }
266
+ setFocus(focusIndex, adjustment) {
267
+ if (this.menuItems === undefined) {
268
+ return;
269
+ }
270
+ while (focusIndex >= 0 && focusIndex < this.menuItems.length) {
271
+ const child = this.menuItems[focusIndex];
272
+ if (this.isFocusableElement(child)) {
273
+ // change the previous index to -1
274
+ if (this.focusIndex > -1 &&
275
+ this.menuItems.length >= this.focusIndex - 1) {
276
+ this.menuItems[this.focusIndex].setAttribute("tabindex", "-1");
277
+ }
278
+ // update the focus index
279
+ this.focusIndex = focusIndex;
280
+ // update the tabindex of next focusable element
281
+ child.setAttribute("tabindex", "0");
282
+ // focus the element
283
+ child.focus();
284
+ break;
285
+ }
286
+ focusIndex += adjustment;
287
+ }
288
+ }
253
289
  }
254
- __decorate([
255
- attr({ mode: "boolean" })
256
- ], MenuItem$1.prototype, "disabled", void 0);
257
- __decorate([
258
- attr({ mode: "boolean" })
259
- ], MenuItem$1.prototype, "expanded", void 0);
260
- __decorate([
261
- observable
262
- ], MenuItem$1.prototype, "startColumnCount", void 0);
263
- __decorate([
264
- attr
265
- ], MenuItem$1.prototype, "role", void 0);
266
- __decorate([
267
- attr({ mode: "boolean" })
268
- ], MenuItem$1.prototype, "checked", void 0);
269
- __decorate([
270
- observable
271
- ], MenuItem$1.prototype, "submenuRegion", void 0);
272
- __decorate([
273
- observable
274
- ], MenuItem$1.prototype, "hasSubmenu", void 0);
275
- __decorate([
276
- observable
277
- ], MenuItem$1.prototype, "currentDirection", void 0);
290
+ Menu$1.focusableElementRoles = roleForMenuItem;
278
291
  __decorate([
279
292
  observable
280
- ], MenuItem$1.prototype, "submenu", void 0);
281
- applyMixins(MenuItem$1, StartEnd);
293
+ ], Menu$1.prototype, "items", void 0);
282
294
 
283
- var css_248z = "/**\n * Do not edit directly\n * Generated on Mon, 27 Mar 2023 07:48:02 GMT\n */\n@supports selector(:focus-visible) {\n :host(:focus) {\n outline: none;\n }\n}\n.base {\n position: relative;\n display: flex;\n box-sizing: border-box;\n align-items: center;\n background-color: var(--_appearance-color-fill);\n box-shadow: inset 0 0 0 1px var(--_appearance-color-outline);\n gap: 12px;\n inline-size: 100%;\n padding-inline: 16px;\n}\n.base {\n --_appearance-color-text: var(--_connotation-color-primary);\n --_appearance-color-fill: transparent;\n --_appearance-color-outline: transparent;\n}\n.base:where(:hover, .hover):where(:not(:disabled, .disabled, .readonly)) {\n --_appearance-color-text: var(--_connotation-color-primary);\n --_appearance-color-fill: var(--_connotation-color-faint);\n --_appearance-color-outline: transparent;\n}\n.base:where(:disabled, .disabled) {\n --_appearance-color-text: var(--vvd-color-neutral-400);\n --_appearance-color-fill: transparent;\n --_appearance-color-outline: transparent;\n}\n.base:where(:active, .active):where(:not(:disabled, .disabled)) {\n --_appearance-color-text: var(--_connotation-color-primary);\n --_appearance-color-fill: var(--_connotation-color-soft);\n --_appearance-color-outline: transparent;\n}\n.base:where(.selected, [aria-current]):where(:not(:disabled, .disabled, :hover, .hover)) {\n --_appearance-color-text: var(--_connotation-color-primary-text);\n --_appearance-color-fill: var(--_connotation-color-primary);\n --_appearance-color-outline: transparent;\n}\n.base:where(.selected, [aria-current]):where(:hover, .hover) {\n --_appearance-color-text: var(--_connotation-color-primary-text);\n --_appearance-color-fill: var(--_connotation-color-primary-increment);\n --_appearance-color-outline: transparent;\n}\n.base {\n --_connotation-color-primary: var(--vvd-color-canvas-text);\n --_connotation-color-primary-text: var(--vvd-color-canvas);\n --_connotation-color-primary-increment: var(--vvd-color-neutral-800);\n --_connotation-color-faint: var(--vvd-color-neutral-50);\n --_connotation-color-soft: var(--vvd-color-neutral-100);\n}\n.base:not(.two-lines) {\n block-size: calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density, 0), 2)));\n}\n.base.two-lines {\n block-size: calc(calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density, 0), 2))) + calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density, 0), 2) - 16)));\n}\n@supports (user-select: none) {\n .base {\n user-select: none;\n }\n}\n.base:not(.disabled) {\n cursor: pointer;\n}\n.base.disabled {\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.focus-indicator {\n border-radius: 6px;\n}\n:host(:not(:focus-visible)) .focus-indicator {\n display: none;\n}\n\n.icon {\n font-size: calc(calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density, 0), 2))) / 2);\n}\n.base:not(.disabled, .item-checkbox, .item-radio) .icon {\n color: var(--vvd-color-neutral-600);\n}\n.base:is(.disabled, .item-checkbox, .item-radio) .icon {\n color: var(--_appearance-color-text);\n}\n\n.text {\n display: flex;\n overflow: hidden;\n flex-direction: column;\n}\n\n.text-primary,\n.text-secondary {\n overflow: hidden;\n color: var(--_appearance-color-text);\n font: var(--vvd-typography-base);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.base.two-lines .text-primary {\n font: var(--vvd-typography-base-bold);\n}\n\n.base.two-lines .text-secondary {\n color: var(--vvd-color-neutral-600);\n}";
295
+ var css_248z = ".base {\n max-inline-size: var(--menu-max-inline-size, 100%);\n min-inline-size: var(--menu-max-inline-size);\n padding-block: 8px;\n}";
284
296
 
285
- class MenuItem extends MenuItem$1 {}
286
- __decorate([attr, __metadata("design:type", String)], MenuItem.prototype, "text", void 0);
297
+ class Menu extends Menu$1 {
298
+ constructor() {
299
+ super(...arguments);
300
+ this.open = false;
301
+ this.popupOpenChanged = () => {
302
+ this.open = this._popup.open;
303
+ };
304
+ }
305
+ anchorChanged(prevAnchor, newAnchor) {
306
+ const prevAnchorEl = document.getElementById(prevAnchor);
307
+ const newAnchorEl = document.getElementById(newAnchor);
308
+ prevAnchorEl === null || prevAnchorEl === void 0 ? void 0 : prevAnchorEl.removeAttribute('aria-haspopup');
309
+ newAnchorEl === null || newAnchorEl === void 0 ? void 0 : newAnchorEl.setAttribute('aria-haspopup', 'menu');
310
+ }
311
+ }
287
312
  __decorate([attr({
288
- attribute: 'text-secondary'
289
- }), __metadata("design:type", String)], MenuItem.prototype, "textSecondary", void 0);
290
- applyMixins(MenuItem, AffixIcon);
313
+ mode: 'boolean'
314
+ }), __metadata("design:type", Object)], Menu.prototype, "open", void 0);
315
+ __decorate([attr, __metadata("design:type", String)], Menu.prototype, "placement", void 0);
316
+ __decorate([attr, __metadata("design:type", String)], Menu.prototype, "anchor", void 0);
291
317
 
292
318
  let _ = t => t,
293
- _t,
294
- _t2,
295
- _t3,
296
- _t4,
297
- _t5,
298
- _t6,
299
- _t7,
300
- _t8;
301
- const getClasses = ({
302
- disabled,
303
- checked,
304
- expanded,
305
- role,
306
- text,
307
- textSecondary
308
- }) => classNames('base', ['disabled', Boolean(disabled)], ['selected', role !== MenuItemRole.menuitem && Boolean(checked)], ['expanded', Boolean(expanded)], ['item-checkbox', role === MenuItemRole.menuitemcheckbox], ['item-radio', role === MenuItemRole.menuitemradio], ['two-lines', Boolean(text === null || text === void 0 ? void 0 : text.length) && Boolean(textSecondary === null || textSecondary === void 0 ? void 0 : textSecondary.length)]);
309
- const MenuItemTemplate = (context, definition) => {
310
- const affixIconTemplate = affixIconTemplateFactory(context);
311
- const focusTemplate = focusTemplateFactory(context);
319
+ _t;
320
+ const MenuTemplate = context => {
321
+ const popupTag = context.tagFor(Popup);
312
322
  return html(_t || (_t = _`
313
- <template
314
- aria-checked="${0}"
315
- aria-disabled="${0}"
316
- aria-expanded="${0}"
317
- @keydown="${0}"
318
- @click="${0}"
319
- @mouseover="${0}"
320
- @mouseout="${0}"
321
- >
322
- <div class="${0}">
323
-
324
- ${0}
325
- ${0}
326
-
327
- ${0}
328
-
329
- ${0}
330
-
331
- ${0}
332
-
333
- ${0}
334
-
335
-
336
-
337
- </div>
338
- </template>
339
- `), x => x.role !== MenuItemRole.menuitem ? x.checked : void 0, x => x.disabled, x => x.expanded, (x, c) => x.handleMenuItemKeyDown(c.event), (x, c) => x.handleMenuItemClick(c.event), (x, c) => x.handleMouseOver(c.event), (x, c) => x.handleMouseOut(c.event), getClasses, when(x => x.hasSubmenu, html(_t2 || (_t2 = _`
340
- <div
341
- class="expand-collapse-glyph-container"
342
- >
343
- <span class="expand-collapse">
344
- <slot name="expand-collapse-indicator">
345
- ${0}
346
- </slot>
347
- </span>
348
- </div>
349
- `), definition.expandCollapseGlyph || '')), () => focusTemplate, when(x => x.role === MenuItemRole.menuitemcheckbox, html(_t3 || (_t3 = _`${0}`), x => affixIconTemplate(x.checked ? 'checkbox-checked-line' : 'checkbox-unchecked-line'))), when(x => x.role === MenuItemRole.menuitemradio, html(_t4 || (_t4 = _`${0}`), x => affixIconTemplate(x.checked ? 'radio-checked-line' : 'radio-unchecked-line'))), when(x => x.role === MenuItemRole.menuitem && x.icon, html(_t5 || (_t5 = _`${0}`), x => affixIconTemplate(x.icon))), when(x => x.text || x.textSecondary, html(_t6 || (_t6 = _`<span class="text">
350
- ${0}
323
+ <template
324
+ slot="${0}"
325
+ >
326
+ <${0}
327
+ :placement=${0}
328
+ :open=${0}
329
+ :anchor=${0}
330
+ @open="${0}"
331
+ @close="${0}"
351
332
  ${0}
352
- </span>`), when(x => x.text, html(_t7 || (_t7 = _`<span class="text-primary">${0}</span>`), x => x.text)), when(x => x.textSecondary, html(_t8 || (_t8 = _`<span class="text-secondary">${0}</span>`), x => x.textSecondary)))));
333
+ >
334
+ <div
335
+ class="base"
336
+ role="menu"
337
+ @keydown="${0}"
338
+ @focusout="${0}"
339
+ >
340
+ <slot ${0}></slot>
341
+ </div>
342
+ </${0}>
343
+ </template>`), x => x.slot || x.isNestedMenu() ? 'submenu' : void 0, popupTag, x => x.placement, x => x.open, x => x.anchor, x => x.popupOpenChanged(), x => x.popupOpenChanged(), ref('_popup'), (x, c) => x.handleMenuKeyDown(c.event), (x, c) => x.handleFocusOut(c.event), slotted('items'), popupTag);
353
344
  };
354
345
 
355
- const menuItemDefinition = MenuItem.compose({
356
- baseName: 'menu-item',
357
- template: MenuItemTemplate,
346
+ const menuDefinition = Menu.compose({
347
+ baseName: 'menu',
348
+ template: MenuTemplate,
358
349
  styles: css_248z
359
350
  });
360
- const menuItemRegistries = [menuItemDefinition(), ...iconRegistries, ...focusRegistries];
361
- const registerMenuItem = registerFactory(menuItemRegistries);
351
+ const menuRegistries = [menuDefinition(), ...popupRegistries, ...menuItemRegistries];
352
+ const registerMenu = registerFactory(menuRegistries);
362
353
 
363
- export { MenuItem$1 as M, MenuItemRole as a, registerMenuItem as b, menuItemDefinition as c, menuItemRegistries as m, roleForMenuItem as r };
354
+ export { menuRegistries as a, menuDefinition as m, registerMenu as r };