@vonage/vivid 3.14.0 → 3.16.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 (105) hide show
  1. package/checkbox/index.js +3 -0
  2. package/custom-elements.json +250 -27
  3. package/empty-state/index.js +14 -0
  4. package/fab/index.js +1 -1
  5. package/header/index.js +1 -1
  6. package/index.js +31 -29
  7. package/layout/index.js +1 -1
  8. package/lib/checkbox/checkbox.d.ts +6 -3
  9. package/lib/components.d.ts +2 -0
  10. package/lib/data-grid/data-grid-cell.d.ts +2 -0
  11. package/lib/data-grid/data-grid-row.d.ts +1 -0
  12. package/lib/data-grid/data-grid.d.ts +1 -1
  13. package/lib/empty-state/definition.d.ts +3 -0
  14. package/lib/empty-state/empty-state.d.ts +5 -0
  15. package/lib/empty-state/empty-state.template.d.ts +4 -0
  16. package/lib/empty-state/index.d.ts +1 -0
  17. package/listbox/index.js +1 -1
  18. package/menu/index.js +2 -2
  19. package/menu-item/index.js +1 -1
  20. package/nav/index.js +1 -1
  21. package/nav-disclosure/index.js +1 -1
  22. package/nav-item/index.js +1 -1
  23. package/note/index.js +1 -1
  24. package/number-field/index.js +1 -1
  25. package/package.json +1 -1
  26. package/pagination/index.js +14 -232
  27. package/progress/index.js +1 -1
  28. package/radio/index.js +1 -1
  29. package/radio-group/index.js +1 -1
  30. package/select/index.js +1 -1
  31. package/shared/definition.js +1 -1
  32. package/shared/definition10.js +1 -1
  33. package/shared/definition11.js +1 -1
  34. package/shared/definition12.js +1 -1
  35. package/shared/definition14.js +1 -1
  36. package/shared/definition15.js +1 -1
  37. package/shared/definition16.js +1 -1
  38. package/shared/definition17.js +1 -1
  39. package/shared/definition18.js +23 -8
  40. package/shared/definition19.js +1 -1
  41. package/shared/definition2.js +1 -1
  42. package/shared/definition21.js +1 -1
  43. package/shared/definition22.js +114 -40
  44. package/shared/definition23.js +1 -1
  45. package/shared/definition24.js +1 -1
  46. package/shared/definition25.js +39 -76
  47. package/shared/definition26.js +76 -47
  48. package/shared/definition27.js +46 -36
  49. package/shared/definition28.js +39 -49
  50. package/shared/definition29.js +48 -344
  51. package/shared/definition30.js +272 -291
  52. package/shared/definition31.js +366 -14
  53. package/shared/definition32.js +13 -67
  54. package/shared/definition33.js +66 -21
  55. package/shared/definition34.js +21 -39
  56. package/shared/definition35.js +31 -432
  57. package/shared/definition36.js +432 -76
  58. package/shared/definition37.js +223 -34
  59. package/shared/definition38.js +82 -425
  60. package/shared/definition39.js +30 -635
  61. package/shared/definition4.js +1 -1
  62. package/shared/definition40.js +420 -73
  63. package/shared/definition41.js +530 -484
  64. package/shared/definition42.js +76 -133
  65. package/shared/definition43.js +577 -40
  66. package/shared/definition44.js +135 -20
  67. package/shared/definition45.js +42 -423
  68. package/shared/definition46.js +22 -112
  69. package/shared/definition47.js +440 -18
  70. package/shared/definition48.js +92 -247
  71. package/shared/definition49.js +20 -112
  72. package/shared/definition5.js +1 -1
  73. package/shared/definition50.js +259 -590
  74. package/shared/definition51.js +110 -91
  75. package/shared/definition52.js +626 -67
  76. package/shared/definition53.js +111 -292
  77. package/shared/definition54.js +80 -0
  78. package/shared/definition55.js +305 -0
  79. package/shared/definition6.js +1 -1
  80. package/shared/definition7.js +1 -1
  81. package/shared/definition9.js +1 -1
  82. package/shared/form-elements.js +1 -1
  83. package/shared/icon.js +1 -1
  84. package/shared/patterns/form-elements/form-elements.d.ts +4 -4
  85. package/shared/text-field.js +1 -1
  86. package/side-drawer/index.js +1 -1
  87. package/slider/index.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/switch/index.js +1 -1
  94. package/tab/index.js +1 -1
  95. package/tab-panel/index.js +1 -1
  96. package/tabs/index.js +3 -3
  97. package/tag/index.js +1 -1
  98. package/tag-group/index.js +1 -1
  99. package/text-area/index.js +1 -1
  100. package/text-field/index.js +1 -1
  101. package/toggletip/index.js +1 -1
  102. package/tooltip/index.js +1 -1
  103. package/tree-item/index.js +1 -1
  104. package/tree-view/index.js +1 -1
  105. package/vivid.api.json +210 -0
@@ -1,224 +1,191 @@
1
- import { F as FoundationElement, Y 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';
1
+ import { F as FoundationElement, Y 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 './definition20.js';
3
+ import { M as MenuItem, a as MenuItemRole, r as roleForMenuItem, m as menuItemRegistries } from './definition31.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';
11
6
  import { s as slotted } from './slotted.js';
12
- import { c as classNames } from './class-names.js';
7
+ import { r as ref } from './ref.js';
13
8
 
14
9
  /**
15
- * Menu items roles.
16
- * @public
17
- */
18
- const MenuItemRole = {
19
- /**
20
- * The menu item has a "menuitem" role
21
- */
22
- menuitem: "menuitem",
23
- /**
24
- * The menu item has a "menuitemcheckbox" role
25
- */
26
- menuitemcheckbox: "menuitemcheckbox",
27
- /**
28
- * The menu item has a "menuitemradio" role
29
- */
30
- menuitemradio: "menuitemradio",
31
- };
32
- /**
33
- * @internal
34
- */
35
- const roleForMenuItem = {
36
- [MenuItemRole.menuitem]: "menuitem",
37
- [MenuItemRole.menuitemcheckbox]: "menuitemcheckbox",
38
- [MenuItemRole.menuitemradio]: "menuitemradio",
39
- };
40
-
41
- /**
42
- * A Switch Custom HTML Element.
43
- * 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 }.
44
12
  *
45
- * @slot checked-indicator - The checked indicator
46
- * @slot radio-indicator - The radio indicator
47
- * @slot start - Content which can be provided before the menu item content
48
- * @slot end - Content which can be provided after the menu item content
49
- * @slot - The default slot for menu item content
50
- * @slot expand-collapse-indicator - The expand/collapse indicator
51
- * @slot submenu - Used to nest menu's within menu items
52
- * @csspart input-container - The element representing the visual checked or radio indicator
53
- * @csspart checkbox - The element wrapping the `menuitemcheckbox` indicator
54
- * @csspart radio - The element wrapping the `menuitemradio` indicator
55
- * @csspart content - The element wrapping the menu item content
56
- * @csspart expand-collapse-glyph-container - The element wrapping the expand collapse element
57
- * @csspart expand-collapse - The expand/collapse element
58
- * @csspart submenu-region - The container for the submenu, used for positioning
59
- * @fires expanded-change - Fires a custom 'expanded-change' event when the expanded state changes
60
- * @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
61
14
  *
62
15
  * @public
63
16
  */
64
- class MenuItem$1 extends FoundationElement {
17
+ class Menu$1 extends FoundationElement {
65
18
  constructor() {
66
19
  super(...arguments);
20
+ this.expandedItem = null;
67
21
  /**
68
- * The role of the element.
69
- *
70
- * @public
71
- * @remarks
72
- * HTML Attribute: role
73
- */
74
- this.role = MenuItemRole.menuitem;
75
- /**
76
- * @internal
22
+ * The index of the focusable element in the items array
23
+ * defaults to -1
77
24
  */
78
- this.hasSubmenu = false;
25
+ this.focusIndex = -1;
79
26
  /**
80
- * Track current direction to pass to the anchored region
81
- *
82
27
  * @internal
83
28
  */
84
- this.currentDirection = Direction.ltr;
85
- this.focusSubmenuOnLoad = false;
29
+ this.isNestedMenu = () => {
30
+ return (this.parentElement !== null &&
31
+ isHTMLElement(this.parentElement) &&
32
+ this.parentElement.getAttribute("role") === "menuitem");
33
+ };
86
34
  /**
35
+ * if focus is moving out of the menu, reset to a stable initial state
87
36
  * @internal
88
37
  */
89
- this.handleMenuItemKeyDown = (e) => {
90
- if (e.defaultPrevented) {
91
- return false;
92
- }
93
- switch (e.key) {
94
- case keyEnter:
95
- case keySpace:
96
- this.invoke();
97
- return false;
98
- case keyArrowRight:
99
- //open/focus on submenu
100
- this.expandAndFocus();
101
- return false;
102
- case keyArrowLeft:
103
- //close submenu
104
- if (this.expanded) {
105
- this.expanded = false;
106
- this.focus();
107
- return false;
108
- }
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;
109
49
  }
110
- return true;
111
50
  };
112
- /**
113
- * @internal
114
- */
115
- this.handleMenuItemClick = (e) => {
116
- if (e.defaultPrevented || this.disabled) {
117
- 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");
118
58
  }
119
- this.invoke();
120
- return false;
121
59
  };
122
- /**
123
- * @internal
124
- */
125
- this.submenuLoaded = () => {
126
- 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;
127
74
  return;
128
75
  }
129
- this.focusSubmenuOnLoad = false;
130
- if (this.hasSubmenu) {
131
- this.submenu.focus();
132
- 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");
133
84
  }
134
85
  };
135
- /**
136
- * @internal
137
- */
138
- this.handleMouseOver = (e) => {
139
- if (this.disabled || !this.hasSubmenu || this.expanded) {
140
- 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
+ });
141
92
  }
142
- this.expanded = true;
143
- return false;
144
93
  };
145
- /**
146
- * @internal
147
- */
148
- this.handleMouseOut = (e) => {
149
- if (!this.expanded || this.contains(document.activeElement)) {
150
- 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;
151
102
  }
152
- this.expanded = false;
153
- 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
+ });
154
131
  };
155
132
  /**
156
- * @internal
133
+ * handle change from child element
157
134
  */
158
- this.expandAndFocus = () => {
159
- if (!this.hasSubmenu) {
135
+ this.changeHandler = (e) => {
136
+ if (this.menuItems === undefined) {
160
137
  return;
161
138
  }
162
- this.focusSubmenuOnLoad = true;
163
- this.expanded = true;
164
- };
165
- /**
166
- * @internal
167
- */
168
- this.invoke = () => {
169
- if (this.disabled) {
139
+ const changedMenuItem = e.target;
140
+ const changeItemIndex = this.menuItems.indexOf(changedMenuItem);
141
+ if (changeItemIndex === -1) {
170
142
  return;
171
143
  }
172
- switch (this.role) {
173
- case MenuItemRole.menuitemcheckbox:
174
- this.checked = !this.checked;
175
- break;
176
- case MenuItemRole.menuitem:
177
- // update submenu
178
- this.updateSubmenu();
179
- if (this.hasSubmenu) {
180
- 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;
181
154
  }
182
- else {
183
- 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;
184
162
  }
185
- break;
186
- case MenuItemRole.menuitemradio:
187
- if (!this.checked) {
188
- this.checked = true;
163
+ if (role === "separator") {
164
+ break;
189
165
  }
190
- break;
166
+ }
191
167
  }
192
168
  };
193
169
  /**
194
- * Gets the submenu element if any
195
- *
196
- * @internal
170
+ * check if the item is a menu item
197
171
  */
198
- this.updateSubmenu = () => {
199
- this.submenu = this.domChildren().find((element) => {
200
- return element.getAttribute("role") === "menu";
201
- });
202
- 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);
203
181
  };
204
182
  }
205
- expandedChanged(oldValue) {
206
- if (this.$fastController.isConnected) {
207
- if (this.submenu === undefined) {
208
- return;
209
- }
210
- if (this.expanded === false) {
211
- this.submenu.collapseExpandedItem();
212
- }
213
- else {
214
- this.currentDirection = getDirection(this);
215
- }
216
- this.$emit("expanded-change", this, { bubbles: false });
217
- }
218
- }
219
- checkedChanged(oldValue, newValue) {
220
- if (this.$fastController.isConnected) {
221
- 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();
222
189
  }
223
190
  }
224
191
  /**
@@ -227,22 +194,67 @@ class MenuItem$1 extends FoundationElement {
227
194
  connectedCallback() {
228
195
  super.connectedCallback();
229
196
  DOM.queueUpdate(() => {
230
- this.updateSubmenu();
197
+ // wait until children have had a chance to
198
+ // connect before setting/checking their props/attributes
199
+ this.setItems();
231
200
  });
232
- if (!this.startColumnCount) {
233
- this.startColumnCount = 1;
234
- }
235
- this.observer = new MutationObserver(this.updateSubmenu);
201
+ this.addEventListener("change", this.changeHandler);
236
202
  }
237
203
  /**
238
204
  * @internal
239
205
  */
240
206
  disconnectedCallback() {
241
207
  super.disconnectedCallback();
242
- this.submenu = undefined;
243
- if (this.observer !== undefined) {
244
- this.observer.disconnect();
245
- 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;
246
258
  }
247
259
  }
248
260
  /**
@@ -251,123 +263,92 @@ class MenuItem$1 extends FoundationElement {
251
263
  domChildren() {
252
264
  return Array.from(this.children).filter(child => !child.hasAttribute("hidden"));
253
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
+ }
254
289
  }
255
- __decorate([
256
- attr({ mode: "boolean" })
257
- ], MenuItem$1.prototype, "disabled", void 0);
258
- __decorate([
259
- attr({ mode: "boolean" })
260
- ], MenuItem$1.prototype, "expanded", void 0);
261
- __decorate([
262
- observable
263
- ], MenuItem$1.prototype, "startColumnCount", void 0);
264
- __decorate([
265
- attr
266
- ], MenuItem$1.prototype, "role", void 0);
267
- __decorate([
268
- attr({ mode: "boolean" })
269
- ], MenuItem$1.prototype, "checked", void 0);
270
- __decorate([
271
- observable
272
- ], MenuItem$1.prototype, "submenuRegion", void 0);
273
- __decorate([
274
- observable
275
- ], MenuItem$1.prototype, "hasSubmenu", void 0);
276
- __decorate([
277
- observable
278
- ], MenuItem$1.prototype, "currentDirection", void 0);
290
+ Menu$1.focusableElementRoles = roleForMenuItem;
279
291
  __decorate([
280
292
  observable
281
- ], MenuItem$1.prototype, "submenu", void 0);
282
- applyMixins(MenuItem$1, StartEnd);
293
+ ], Menu$1.prototype, "items", void 0);
283
294
 
284
- var css_248z = "/**\n * Do not edit directly\n * Generated on Tue, 30 May 2023 12:49:14 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-block: 2px;\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);\n --_appearance-color-fill: var(--_connotation-color-dim);\n --_appearance-color-outline: transparent;\n}\n.base:where(.selected, [aria-current]):where(:hover, .hover) {\n --_appearance-color-text: var(--_connotation-color-primary);\n --_appearance-color-fill: var(--_connotation-color-pale);\n --_appearance-color-outline: transparent;\n}\n.base {\n /* @cssprop [--vvd-menu-item-accent-primary=var(--vvd-color-canvas-text)] */\n --_connotation-color-primary: var(--vvd-menu-item-accent-primary, var(--vvd-color-canvas-text));\n /* @cssprop [--vvd-menu-item-accent-primary-text=var(--vvd-color-canvas)] */\n --_connotation-color-primary-text: var(--vvd-menu-item-accent-primary-text, var(--vvd-color-canvas));\n /* @cssprop [--vvd-menu-item-accent-primary-increment=var(--vvd-color-neutral-800)] */\n --_connotation-color-primary-increment: var(--vvd-menu-item-accent-primary-increment, var(--vvd-color-neutral-800));\n /* @cssprop [--vvd-menu-item-accent-faint=var(--vvd-color-neutral-50)] */\n --_connotation-color-faint: var(--vvd-menu-item-accent-faint, var(--vvd-color-neutral-50));\n /* @cssprop [--vvd-menu-item-accent-soft=var(--vvd-color-neutral-100)] */\n --_connotation-color-soft: var(--vvd-menu-item-accent-soft, var(--vvd-color-neutral-100));\n /* @cssprop [--vvd-menu-item-accent-pale=var(--vvd-color-neutral-300)] */\n --_connotation-color-pale: var(--vvd-menu-item-accent-pale, var(--vvd-color-neutral-300));\n /* @cssprop [--vvd-menu-item-accent-dim=var(--vvd-color-neutral-200)] */\n --_connotation-color-dim: var(--vvd-menu-item-accent-dim, var(--vvd-color-neutral-200));\n}\n.base:not(.two-lines) {\n min-block-size: calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density, 0), 2)));\n}\n.base.two-lines {\n min-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 flex-shrink: 0;\n font-size: calc(calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density, 0), 2))) / 2);\n line-height: 1;\n}\n\n.action,\n.decorative {\n display: flex;\n place-content: center;\n}\n\n.action {\n color: var(--_appearance-color-text);\n}\n.base.trailing .action {\n order: 1;\n margin-inline-start: auto;\n}\n\n.base:not(.disabled) .decorative {\n color: var(--vvd-color-neutral-600);\n}\n.base.disabled .decorative {\n color: var(--vvd-color-neutral-200);\n}\n.base.has-meta .decorative {\n order: 1;\n margin-inline-start: auto;\n}\n\n.text {\n display: flex;\n overflow: hidden;\n flex-direction: column;\n}\n\n.text-primary,\n.text-secondary {\n /* stylelint-disable value-no-vendor-prefix */\n display: -webkit-box;\n /* stylelint-enable value-no-vendor-prefix */\n overflow: hidden;\n -webkit-box-orient: vertical;\n color: var(--_appearance-color-text);\n font: var(--vvd-typography-base);\n}\n\n.text-primary {\n -webkit-line-clamp: var(--text-primary-line-clamp, 1);\n}\n.base.two-lines .text-primary {\n font: var(--vvd-typography-base-bold);\n}\n\n.text-secondary {\n -webkit-line-clamp: var(--text-secondary-line-clamp, 1);\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-min-inline-size);\n padding-block: 8px;\n}";
285
296
 
286
- class MenuItem extends MenuItem$1 {}
287
- __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
+ }
288
312
  __decorate([attr({
289
- attribute: 'text-secondary'
290
- }), __metadata("design:type", String)], MenuItem.prototype, "textSecondary", void 0);
291
- __decorate([observable, __metadata("design:type", Array)], MenuItem.prototype, "metaSlottedContent", void 0);
292
- 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);
293
317
 
294
318
  let _ = t => t,
295
- _t,
296
- _t2,
297
- _t3,
298
- _t4,
299
- _t5,
300
- _t6,
301
- _t7,
302
- _t8,
303
- _t9;
304
- const getCheckIcon = (affixIconTemplate, x, iconType) => {
305
- const iconStatus = x.checked ? 'checked' : 'unchecked';
306
- const icon = `${iconType}-${iconStatus}-line`;
307
- return affixIconTemplate(icon, x.icon ? 'trailing' : '');
308
- };
309
- const getClasses = ({
310
- disabled,
311
- checked,
312
- expanded,
313
- role,
314
- text,
315
- textSecondary,
316
- icon,
317
- metaSlottedContent
318
- }) => classNames('base', ['disabled', Boolean(disabled)], ['selected', role !== MenuItemRole.menuitem && Boolean(checked)], ['trailing', role !== MenuItemRole.menuitem && Boolean(icon)], ['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)], ['has-meta', Boolean(metaSlottedContent === null || metaSlottedContent === void 0 ? void 0 : metaSlottedContent.length)]);
319
- const MenuItemTemplate = (context, definition) => {
320
- const affixIconTemplate = affixIconTemplateFactory(context);
321
- const focusTemplate = focusTemplateFactory(context);
319
+ _t;
320
+ const MenuTemplate = context => {
321
+ const popupTag = context.tagFor(Popup);
322
322
  return html(_t || (_t = _`
323
- <template
324
- aria-checked="${0}"
325
- aria-disabled="${0}"
326
- aria-expanded="${0}"
327
- @keydown="${0}"
328
- @click="${0}"
329
- @mouseover="${0}"
330
- @mouseout="${0}"
331
- >
332
- <div class="${0}">
333
-
334
- ${0}
335
- ${0}
336
- ${0}
337
- ${0}
338
-
339
- ${0}
340
-
341
- ${0}
342
-
343
- ${0}
344
-
345
-
346
-
347
- </div>
348
- </template>
349
- `), 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 = _`
350
- <div
351
- class="expand-collapse-glyph-container"
352
- >
353
- <span class="expand-collapse">
354
- <slot name="expand-collapse-indicator">
355
- ${0}
356
- </slot>
357
- </span>
358
- </div>
359
- `), definition.expandCollapseGlyph || '')), () => focusTemplate, when(x => x.role !== MenuItemRole.menuitemcheckbox && x.role !== MenuItemRole.menuitemradio, html(_t3 || (_t3 = _`<slot name="meta" ${0}></slot>`), slotted('metaSlottedContent'))), when(x => x.role === MenuItemRole.menuitemcheckbox, html(_t4 || (_t4 = _`<span class="action">${0}</span>`), x => getCheckIcon(affixIconTemplate, x, 'checkbox'))), when(x => x.role === MenuItemRole.menuitemradio, html(_t5 || (_t5 = _`<span class="action">${0}</span>`), x => getCheckIcon(affixIconTemplate, x, 'radio'))), when(x => x.icon, html(_t6 || (_t6 = _`<span class="decorative">${0}</span>`), x => affixIconTemplate(x.icon))), when(x => x.text || x.textSecondary, html(_t7 || (_t7 = _`<span class="text">
360
- ${0}
323
+ <template
324
+ slot="${0}"
325
+ >
326
+ <${0}
327
+ :placement=${0}
328
+ :open=${0}
329
+ :anchor=${0}
330
+ @open="${0}"
331
+ @close="${0}"
361
332
  ${0}
362
- </span>`), when(x => x.text, html(_t8 || (_t8 = _`<span class="text-primary">${0}</span>`), x => x.text)), when(x => x.textSecondary, html(_t9 || (_t9 = _`<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);
363
344
  };
364
345
 
365
- const menuItemDefinition = MenuItem.compose({
366
- baseName: 'menu-item',
367
- template: MenuItemTemplate,
346
+ const menuDefinition = Menu.compose({
347
+ baseName: 'menu',
348
+ template: MenuTemplate,
368
349
  styles: css_248z
369
350
  });
370
- const menuItemRegistries = [menuItemDefinition(), ...iconRegistries, ...focusRegistries];
371
- const registerMenuItem = registerFactory(menuItemRegistries);
351
+ const menuRegistries = [menuDefinition(), ...popupRegistries, ...menuItemRegistries];
352
+ const registerMenu = registerFactory(menuRegistries);
372
353
 
373
- 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 };