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