@ni/nimble-components 30.1.4 → 30.1.5

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.
@@ -5281,14 +5281,14 @@
5281
5281
  /**
5282
5282
  * A test that ensures that all arguments are HTML Elements
5283
5283
  */
5284
- function isHTMLElement(...args) {
5284
+ function isHTMLElement$1(...args) {
5285
5285
  return args.every((arg) => arg instanceof HTMLElement);
5286
5286
  }
5287
5287
  /**
5288
5288
  * Returns all displayed elements inside of a root node that match a provided selector
5289
5289
  */
5290
5290
  function getDisplayedNodes(rootNode, selector) {
5291
- if (!rootNode || !selector || !isHTMLElement(rootNode)) {
5291
+ if (!rootNode || !selector || !isHTMLElement$1(rootNode)) {
5292
5292
  return;
5293
5293
  }
5294
5294
  const nodes = Array.from(rootNode.querySelectorAll(selector));
@@ -7687,7 +7687,7 @@
7687
7687
  * @public
7688
7688
  */
7689
7689
  function isListboxOption(el) {
7690
- return (isHTMLElement(el) &&
7690
+ return (isHTMLElement$1(el) &&
7691
7691
  (el.getAttribute("role") === "option" ||
7692
7692
  el instanceof HTMLOptionElement));
7693
7693
  }
@@ -11098,307 +11098,6 @@
11098
11098
  </template>
11099
11099
  `;
11100
11100
 
11101
- /**
11102
- * The template for the {@link @microsoft/fast-foundation#Menu} component.
11103
- * @public
11104
- */
11105
- const menuTemplate = (context, definition) => html `
11106
- <template
11107
- slot="${x => (x.slot ? x.slot : x.isNestedMenu() ? "submenu" : void 0)}"
11108
- role="menu"
11109
- @keydown="${(x, c) => x.handleMenuKeyDown(c.event)}"
11110
- @focusout="${(x, c) => x.handleFocusOut(c.event)}"
11111
- >
11112
- <slot ${slotted("items")}></slot>
11113
- </template>
11114
- `;
11115
-
11116
- /**
11117
- * A Menu Custom HTML Element.
11118
- * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#menu | ARIA menu }.
11119
- *
11120
- * @slot - The default slot for the menu items
11121
- *
11122
- * @public
11123
- */
11124
- let Menu$1 = class Menu extends FoundationElement {
11125
- constructor() {
11126
- super(...arguments);
11127
- this.expandedItem = null;
11128
- /**
11129
- * The index of the focusable element in the items array
11130
- * defaults to -1
11131
- */
11132
- this.focusIndex = -1;
11133
- /**
11134
- * @internal
11135
- */
11136
- this.isNestedMenu = () => {
11137
- return (this.parentElement !== null &&
11138
- isHTMLElement(this.parentElement) &&
11139
- this.parentElement.getAttribute("role") === "menuitem");
11140
- };
11141
- /**
11142
- * if focus is moving out of the menu, reset to a stable initial state
11143
- * @internal
11144
- */
11145
- this.handleFocusOut = (e) => {
11146
- if (!this.contains(e.relatedTarget) && this.menuItems !== undefined) {
11147
- this.collapseExpandedItem();
11148
- // find our first focusable element
11149
- const focusIndex = this.menuItems.findIndex(this.isFocusableElement);
11150
- // set the current focus index's tabindex to -1
11151
- this.menuItems[this.focusIndex].setAttribute("tabindex", "-1");
11152
- // set the first focusable element tabindex to 0
11153
- this.menuItems[focusIndex].setAttribute("tabindex", "0");
11154
- // set the focus index
11155
- this.focusIndex = focusIndex;
11156
- }
11157
- };
11158
- this.handleItemFocus = (e) => {
11159
- const targetItem = e.target;
11160
- if (this.menuItems !== undefined &&
11161
- targetItem !== this.menuItems[this.focusIndex]) {
11162
- this.menuItems[this.focusIndex].setAttribute("tabindex", "-1");
11163
- this.focusIndex = this.menuItems.indexOf(targetItem);
11164
- targetItem.setAttribute("tabindex", "0");
11165
- }
11166
- };
11167
- this.handleExpandedChanged = (e) => {
11168
- if (e.defaultPrevented ||
11169
- e.target === null ||
11170
- this.menuItems === undefined ||
11171
- this.menuItems.indexOf(e.target) < 0) {
11172
- return;
11173
- }
11174
- e.preventDefault();
11175
- const changedItem = e.target;
11176
- // closing an expanded item without opening another
11177
- if (this.expandedItem !== null &&
11178
- changedItem === this.expandedItem &&
11179
- changedItem.expanded === false) {
11180
- this.expandedItem = null;
11181
- return;
11182
- }
11183
- if (changedItem.expanded) {
11184
- if (this.expandedItem !== null && this.expandedItem !== changedItem) {
11185
- this.expandedItem.expanded = false;
11186
- }
11187
- this.menuItems[this.focusIndex].setAttribute("tabindex", "-1");
11188
- this.expandedItem = changedItem;
11189
- this.focusIndex = this.menuItems.indexOf(changedItem);
11190
- changedItem.setAttribute("tabindex", "0");
11191
- }
11192
- };
11193
- this.removeItemListeners = () => {
11194
- if (this.menuItems !== undefined) {
11195
- this.menuItems.forEach((item) => {
11196
- item.removeEventListener("expanded-change", this.handleExpandedChanged);
11197
- item.removeEventListener("focus", this.handleItemFocus);
11198
- });
11199
- }
11200
- };
11201
- this.setItems = () => {
11202
- const newItems = this.domChildren();
11203
- this.removeItemListeners();
11204
- this.menuItems = newItems;
11205
- const menuItems = this.menuItems.filter(this.isMenuItemElement);
11206
- // if our focus index is not -1 we have items
11207
- if (menuItems.length) {
11208
- this.focusIndex = 0;
11209
- }
11210
- function elementIndent(el) {
11211
- const role = el.getAttribute("role");
11212
- const startSlot = el.querySelector("[slot=start]");
11213
- if (role !== MenuItemRole.menuitem && startSlot === null) {
11214
- return 1;
11215
- }
11216
- else if (role === MenuItemRole.menuitem && startSlot !== null) {
11217
- return 1;
11218
- }
11219
- else if (role !== MenuItemRole.menuitem && startSlot !== null) {
11220
- return 2;
11221
- }
11222
- else {
11223
- return 0;
11224
- }
11225
- }
11226
- const indent = menuItems.reduce((accum, current) => {
11227
- const elementValue = elementIndent(current);
11228
- return accum > elementValue ? accum : elementValue;
11229
- }, 0);
11230
- menuItems.forEach((item, index) => {
11231
- item.setAttribute("tabindex", index === 0 ? "0" : "-1");
11232
- item.addEventListener("expanded-change", this.handleExpandedChanged);
11233
- item.addEventListener("focus", this.handleItemFocus);
11234
- if (item instanceof MenuItem$1 || "startColumnCount" in item) {
11235
- item.startColumnCount = indent;
11236
- }
11237
- });
11238
- };
11239
- /**
11240
- * handle change from child element
11241
- */
11242
- this.changeHandler = (e) => {
11243
- if (this.menuItems === undefined) {
11244
- return;
11245
- }
11246
- const changedMenuItem = e.target;
11247
- const changeItemIndex = this.menuItems.indexOf(changedMenuItem);
11248
- if (changeItemIndex === -1) {
11249
- return;
11250
- }
11251
- if (changedMenuItem.role === "menuitemradio" &&
11252
- changedMenuItem.checked === true) {
11253
- for (let i = changeItemIndex - 1; i >= 0; --i) {
11254
- const item = this.menuItems[i];
11255
- const role = item.getAttribute("role");
11256
- if (role === MenuItemRole.menuitemradio) {
11257
- item.checked = false;
11258
- }
11259
- if (role === "separator") {
11260
- break;
11261
- }
11262
- }
11263
- const maxIndex = this.menuItems.length - 1;
11264
- for (let i = changeItemIndex + 1; i <= maxIndex; ++i) {
11265
- const item = this.menuItems[i];
11266
- const role = item.getAttribute("role");
11267
- if (role === MenuItemRole.menuitemradio) {
11268
- item.checked = false;
11269
- }
11270
- if (role === "separator") {
11271
- break;
11272
- }
11273
- }
11274
- }
11275
- };
11276
- /**
11277
- * check if the item is a menu item
11278
- */
11279
- this.isMenuItemElement = (el) => {
11280
- return (isHTMLElement(el) &&
11281
- Menu.focusableElementRoles.hasOwnProperty(el.getAttribute("role")));
11282
- };
11283
- /**
11284
- * check if the item is focusable
11285
- */
11286
- this.isFocusableElement = (el) => {
11287
- return this.isMenuItemElement(el);
11288
- };
11289
- }
11290
- itemsChanged(oldValue, newValue) {
11291
- // only update children after the component is connected and
11292
- // the setItems has run on connectedCallback
11293
- // (menuItems is undefined until then)
11294
- if (this.$fastController.isConnected && this.menuItems !== undefined) {
11295
- this.setItems();
11296
- }
11297
- }
11298
- /**
11299
- * @internal
11300
- */
11301
- connectedCallback() {
11302
- super.connectedCallback();
11303
- DOM.queueUpdate(() => {
11304
- // wait until children have had a chance to
11305
- // connect before setting/checking their props/attributes
11306
- this.setItems();
11307
- });
11308
- this.addEventListener("change", this.changeHandler);
11309
- }
11310
- /**
11311
- * @internal
11312
- */
11313
- disconnectedCallback() {
11314
- super.disconnectedCallback();
11315
- this.removeItemListeners();
11316
- this.menuItems = undefined;
11317
- this.removeEventListener("change", this.changeHandler);
11318
- }
11319
- /**
11320
- * Focuses the first item in the menu.
11321
- *
11322
- * @public
11323
- */
11324
- focus() {
11325
- this.setFocus(0, 1);
11326
- }
11327
- /**
11328
- * Collapses any expanded menu items.
11329
- *
11330
- * @public
11331
- */
11332
- collapseExpandedItem() {
11333
- if (this.expandedItem !== null) {
11334
- this.expandedItem.expanded = false;
11335
- this.expandedItem = null;
11336
- }
11337
- }
11338
- /**
11339
- * @internal
11340
- */
11341
- handleMenuKeyDown(e) {
11342
- if (e.defaultPrevented || this.menuItems === undefined) {
11343
- return;
11344
- }
11345
- switch (e.key) {
11346
- case keyArrowDown$1:
11347
- // go forward one index
11348
- this.setFocus(this.focusIndex + 1, 1);
11349
- return;
11350
- case keyArrowUp$1:
11351
- // go back one index
11352
- this.setFocus(this.focusIndex - 1, -1);
11353
- return;
11354
- case keyEnd$1:
11355
- // set focus on last item
11356
- this.setFocus(this.menuItems.length - 1, -1);
11357
- return;
11358
- case keyHome$1:
11359
- // set focus on first item
11360
- this.setFocus(0, 1);
11361
- return;
11362
- default:
11363
- // if we are not handling the event, do not prevent default
11364
- return true;
11365
- }
11366
- }
11367
- /**
11368
- * get an array of valid DOM children
11369
- */
11370
- domChildren() {
11371
- return Array.from(this.children).filter(child => !child.hasAttribute("hidden"));
11372
- }
11373
- setFocus(focusIndex, adjustment) {
11374
- if (this.menuItems === undefined) {
11375
- return;
11376
- }
11377
- while (focusIndex >= 0 && focusIndex < this.menuItems.length) {
11378
- const child = this.menuItems[focusIndex];
11379
- if (this.isFocusableElement(child)) {
11380
- // change the previous index to -1
11381
- if (this.focusIndex > -1 &&
11382
- this.menuItems.length >= this.focusIndex - 1) {
11383
- this.menuItems[this.focusIndex].setAttribute("tabindex", "-1");
11384
- }
11385
- // update the focus index
11386
- this.focusIndex = focusIndex;
11387
- // update the tabindex of next focusable element
11388
- child.setAttribute("tabindex", "0");
11389
- // focus the element
11390
- child.focus();
11391
- break;
11392
- }
11393
- focusIndex += adjustment;
11394
- }
11395
- }
11396
- };
11397
- Menu$1.focusableElementRoles = roleForMenuItem;
11398
- __decorate([
11399
- observable
11400
- ], Menu$1.prototype, "items", void 0);
11401
-
11402
11101
  /**
11403
11102
  * The template for the {@link @microsoft/fast-foundation#(NumberField:class)} component.
11404
11103
  * @public
@@ -14779,7 +14478,7 @@
14779
14478
  * determines if element is an HTMLElement and if it has the role treeitem
14780
14479
  */
14781
14480
  function isTreeItemElement(el) {
14782
- return isHTMLElement(el) && el.getAttribute("role") === "treeitem";
14481
+ return isHTMLElement$1(el) && el.getAttribute("role") === "treeitem";
14783
14482
  }
14784
14483
  /**
14785
14484
  * A Tree item Custom HTML Element.
@@ -15139,7 +14838,7 @@
15139
14838
  return;
15140
14839
  }
15141
14840
  const focusItem = visibleNodes[visibleNodes.indexOf(item) + delta];
15142
- if (isHTMLElement(focusItem)) {
14841
+ if (isHTMLElement$1(focusItem)) {
15143
14842
  TreeItem$1.focusItem(focusItem);
15144
14843
  }
15145
14844
  }
@@ -16333,7 +16032,7 @@
16333
16032
 
16334
16033
  /**
16335
16034
  * Do not edit directly
16336
- * Generated on Tue, 30 Jul 2024 16:37:39 GMT
16035
+ * Generated on Tue, 30 Jul 2024 18:01:26 GMT
16337
16036
  */
16338
16037
 
16339
16038
  const Information100DarkUi = "#a46eff";
@@ -16734,6 +16433,13 @@
16734
16433
  return -1;
16735
16434
  }
16736
16435
 
16436
+ /**
16437
+ * A test that ensures that all arguments are HTML Elements
16438
+ */
16439
+ function isHTMLElement(...args) {
16440
+ return args.every((arg) => arg instanceof HTMLElement);
16441
+ }
16442
+
16737
16443
  /**
16738
16444
  * This set of exported strings reference https://developer.mozilla.org/en-US/docs/Web/Events
16739
16445
  * and should include all non-deprecated and non-experimental Standard events
@@ -16788,7 +16494,7 @@
16788
16494
  return `${prefix}${uniqueIdCounter++}`;
16789
16495
  }
16790
16496
 
16791
- const template$K = html `<slot></slot>`;
16497
+ const template$L = html `<slot></slot>`;
16792
16498
 
16793
16499
  const styles$10 = css `
16794
16500
  ${display('contents')}
@@ -16906,7 +16612,7 @@
16906
16612
  const nimbleDesignSystemProvider = ThemeProvider.compose({
16907
16613
  baseName: 'theme-provider',
16908
16614
  styles: styles$10,
16909
- template: template$K
16615
+ template: template$L
16910
16616
  });
16911
16617
  DesignSystem.getOrCreate()
16912
16618
  .withPrefix('nimble')
@@ -17178,7 +16884,7 @@
17178
16884
  `;
17179
16885
 
17180
16886
  // prettier-ignore
17181
- const template$J = (_context, definition) => html `${
16887
+ const template$K = (_context, definition) => html `${
17182
16888
  /* top-container div is necessary because setting contenteditable directly on the native anchor instead
17183
16889
  leaves it focusable, unlike the behavior you get when the anchor is _within_ a contenteditable element.
17184
16890
  */ ''}<div
@@ -17281,7 +16987,7 @@
17281
16987
  const nimbleAnchor = Anchor.compose({
17282
16988
  baseName: 'anchor',
17283
16989
  baseClass: Anchor$1,
17284
- template: template$J,
16990
+ template: template$K,
17285
16991
  styles: styles$$,
17286
16992
  shadowOptions: {
17287
16993
  delegatesFocus: true
@@ -17698,7 +17404,7 @@
17698
17404
  }
17699
17405
  `;
17700
17406
 
17701
- const template$I = (context, definition) => html `
17407
+ const template$J = (context, definition) => html `
17702
17408
  <a
17703
17409
  class="control"
17704
17410
  part="control"
@@ -17780,7 +17486,7 @@
17780
17486
  ], AnchorButton.prototype, "disabled", void 0);
17781
17487
  const nimbleAnchorButton = AnchorButton.compose({
17782
17488
  baseName: 'anchor-button',
17783
- template: template$I,
17489
+ template: template$J,
17784
17490
  styles: styles$Z,
17785
17491
  shadowOptions: {
17786
17492
  delegatesFocus: true
@@ -17872,7 +17578,7 @@
17872
17578
  }
17873
17579
  `;
17874
17580
 
17875
- const template$H = (context, definition) => html `
17581
+ const template$I = (context, definition) => html `
17876
17582
  <template
17877
17583
  role="menuitem"
17878
17584
  class="${x => (typeof x.startColumnCount === 'number'
@@ -17973,7 +17679,7 @@
17973
17679
  // FoundationAnchor already applies the StartEnd mixin, so we don't need to do it here.
17974
17680
  const nimbleAnchorMenuItem = AnchorMenuItem.compose({
17975
17681
  baseName: 'anchor-menu-item',
17976
- template: template$H,
17682
+ template: template$I,
17977
17683
  styles: styles$Y,
17978
17684
  shadowOptions: {
17979
17685
  delegatesFocus: true
@@ -18100,7 +17806,7 @@
18100
17806
  }
18101
17807
  `;
18102
17808
 
18103
- const template$G = (context, definition) => html `
17809
+ const template$H = (context, definition) => html `
18104
17810
  <template slot="anchortab" role="tab" aria-disabled="${x => x.disabled}">
18105
17811
  <a
18106
17812
  download="${x => x.download}"
@@ -18152,7 +17858,7 @@
18152
17858
  // FoundationAnchor already applies the StartEnd mixin, so we don't need to do it here.
18153
17859
  const nimbleAnchorTab = AnchorTab.compose({
18154
17860
  baseName: 'anchor-tab',
18155
- template: template$G,
17861
+ template: template$H,
18156
17862
  styles: styles$X,
18157
17863
  shadowOptions: {
18158
17864
  delegatesFocus: true
@@ -18181,7 +17887,7 @@
18181
17887
  }
18182
17888
  `;
18183
17889
 
18184
- const template$F = (context, definition) => html `
17890
+ const template$G = (context, definition) => html `
18185
17891
  ${startSlotTemplate(context, definition)}
18186
17892
  <div ${ref('tablist')} class="tablist" part="tablist" role="tablist">
18187
17893
  <slot name="anchortab" ${slotted('tabs')}></slot>
@@ -18387,7 +18093,7 @@
18387
18093
  applyMixins(AnchorTabs, StartEnd);
18388
18094
  const nimbleAnchorTabs = AnchorTabs.compose({
18389
18095
  baseName: 'anchor-tabs',
18390
- template: template$F,
18096
+ template: template$G,
18391
18097
  styles: styles$W,
18392
18098
  shadowOptions: {
18393
18099
  delegatesFocus: false
@@ -18509,7 +18215,7 @@
18509
18215
  }
18510
18216
  `;
18511
18217
 
18512
- const template$E = (context, definition) => html `
18218
+ const template$F = (context, definition) => html `
18513
18219
  <template
18514
18220
  role="treeitem"
18515
18221
  slot="${x => (x.isNestedItem() ? 'item' : null)}"
@@ -18646,7 +18352,7 @@
18646
18352
  // FoundationAnchor already applies the StartEnd mixin, so we don't need to do it here.
18647
18353
  const nimbleAnchorTreeItem = AnchorTreeItem.compose({
18648
18354
  baseName: 'anchor-tree-item',
18649
- template: template$E,
18355
+ template: template$F,
18650
18356
  styles: styles$V,
18651
18357
  shadowOptions: {
18652
18358
  delegatesFocus: true
@@ -18895,7 +18601,7 @@
18895
18601
  ${buttonAppearanceVariantStyles}
18896
18602
  `;
18897
18603
 
18898
- const template$D = (context, definition) => html `
18604
+ const template$E = (context, definition) => html `
18899
18605
  <button
18900
18606
  class="control"
18901
18607
  part="control"
@@ -18986,7 +18692,7 @@
18986
18692
  const nimbleButton = Button.compose({
18987
18693
  baseName: 'button',
18988
18694
  baseClass: Button$1,
18989
- template: template$D,
18695
+ template: template$E,
18990
18696
  styles: styles$S,
18991
18697
  shadowOptions: {
18992
18698
  delegatesFocus: true
@@ -19790,7 +19496,7 @@
19790
19496
  };
19791
19497
 
19792
19498
  // Avoiding any whitespace in the template because this is an inline element
19793
- const template$C = html `<div
19499
+ const template$D = html `<div
19794
19500
  class="icon"
19795
19501
  aria-hidden="true"
19796
19502
  :innerHTML=${x => x.icon.data}
@@ -19849,7 +19555,7 @@
19849
19555
  const registerIcon = (baseName, iconClass) => {
19850
19556
  const composedIcon = iconClass.compose({
19851
19557
  baseName,
19852
- template: template$C,
19558
+ template: template$D,
19853
19559
  styles: styles$R
19854
19560
  });
19855
19561
  DesignSystem.getOrCreate().withPrefix('nimble').register(composedIcon());
@@ -19968,7 +19674,7 @@
19968
19674
  }).withDefault(coreLabelDefaults.loadingLabel);
19969
19675
 
19970
19676
  // prettier-ignore
19971
- const template$B = html `
19677
+ const template$C = html `
19972
19678
  <${themeProviderTag} theme="${Theme.color}">
19973
19679
  <div class="container"
19974
19680
  role="status"
@@ -20086,7 +19792,7 @@
20086
19792
  applyMixins(Banner, ARIAGlobalStatesAndProperties);
20087
19793
  const nimbleBanner = Banner.compose({
20088
19794
  baseName: 'banner',
20089
- template: template$B,
19795
+ template: template$C,
20090
19796
  styles: styles$T
20091
19797
  });
20092
19798
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleBanner());
@@ -20253,7 +19959,7 @@ so this becomes the fallback color for the slot */ ''}
20253
19959
  }
20254
19960
  `;
20255
19961
 
20256
- const template$A = html `
19962
+ const template$B = html `
20257
19963
  <section aria-labelledby="title-slot">
20258
19964
  <span id="title-slot"><slot name="title"></slot></span>
20259
19965
  <slot></slot>
@@ -20268,7 +19974,7 @@ so this becomes the fallback color for the slot */ ''}
20268
19974
  const nimbleCard = Card.compose({
20269
19975
  baseName: 'card',
20270
19976
  baseClass: Card$1,
20271
- template: template$A,
19977
+ template: template$B,
20272
19978
  styles: styles$O
20273
19979
  });
20274
19980
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleCard());
@@ -20546,7 +20252,7 @@ so this becomes the fallback color for the slot */ ''}
20546
20252
  }
20547
20253
  `;
20548
20254
 
20549
- const template$z = (_context, definition) => html `
20255
+ const template$A = (_context, definition) => html `
20550
20256
  <template
20551
20257
  role="checkbox"
20552
20258
  aria-checked="${x => x.checked}"
@@ -20595,7 +20301,7 @@ so this becomes the fallback color for the slot */ ''}
20595
20301
  const nimbleCheckbox = Checkbox.compose({
20596
20302
  baseName: 'checkbox',
20597
20303
  baseClass: Checkbox$1,
20598
- template: template$z,
20304
+ template: template$A,
20599
20305
  styles: styles$M,
20600
20306
  checkedIndicator: checkLarge16X16.data,
20601
20307
  indeterminateIndicator: minus16X16.data
@@ -20653,7 +20359,7 @@ so this becomes the fallback color for the slot */ ''}
20653
20359
 
20654
20360
  /* eslint-disable @typescript-eslint/indent */
20655
20361
  // prettier-ignore
20656
- const template$y = (context, definition) => html `
20362
+ const template$z = (context, definition) => html `
20657
20363
  <div
20658
20364
  role="button"
20659
20365
  part="control"
@@ -20749,7 +20455,7 @@ so this becomes the fallback color for the slot */ ''}
20749
20455
  applyMixins(ToggleButton, StartEnd, DelegatesARIAButton);
20750
20456
  const nimbleToggleButton = ToggleButton.compose({
20751
20457
  baseName: 'toggle-button',
20752
- template: template$y,
20458
+ template: template$z,
20753
20459
  styles: styles$L,
20754
20460
  shadowOptions: {
20755
20461
  delegatesFocus: true
@@ -21230,7 +20936,7 @@ so this becomes the fallback color for the slot */ ''}
21230
20936
 
21231
20937
  /* eslint-disable @typescript-eslint/indent */
21232
20938
  // prettier-ignore
21233
- const template$x = (context, definition) => html `
20939
+ const template$y = (context, definition) => html `
21234
20940
  <template
21235
20941
  aria-disabled="${x => x.ariaDisabled}"
21236
20942
  autocomplete="${x => x.autocomplete}"
@@ -21982,7 +21688,7 @@ so this becomes the fallback color for the slot */ ''}
21982
21688
  const nimbleCombobox = Combobox.compose({
21983
21689
  baseName: 'combobox',
21984
21690
  baseClass: FormAssociatedCombobox,
21985
- template: template$x,
21691
+ template: template$y,
21986
21692
  styles: styles$I,
21987
21693
  shadowOptions: {
21988
21694
  delegatesFocus: true
@@ -22134,7 +21840,7 @@ so this becomes the fallback color for the slot */ ''}
22134
21840
  }
22135
21841
  `));
22136
21842
 
22137
- const template$w = html `
21843
+ const template$x = html `
22138
21844
  <template>
22139
21845
  <dialog
22140
21846
  ${ref('dialogElement')}
@@ -22282,7 +21988,7 @@ so this becomes the fallback color for the slot */ ''}
22282
21988
  applyMixins(Dialog, ARIAGlobalStatesAndProperties);
22283
21989
  const nimbleDialog = Dialog.compose({
22284
21990
  baseName: 'dialog',
22285
- template: template$w,
21991
+ template: template$x,
22286
21992
  styles: styles$H,
22287
21993
  baseClass: Dialog
22288
21994
  });
@@ -22440,7 +22146,7 @@ so this becomes the fallback color for the slot */ ''}
22440
22146
  }
22441
22147
  `));
22442
22148
 
22443
- const template$v = html `
22149
+ const template$w = html `
22444
22150
  <dialog
22445
22151
  ${ref('dialog')}
22446
22152
  aria-label="${x => x.ariaLabel}"
@@ -22583,7 +22289,7 @@ so this becomes the fallback color for the slot */ ''}
22583
22289
  applyMixins(Drawer, ARIAGlobalStatesAndProperties);
22584
22290
  const nimbleDrawer = Drawer.compose({
22585
22291
  baseName: 'drawer',
22586
- template: template$v,
22292
+ template: template$w,
22587
22293
  styles: styles$G
22588
22294
  });
22589
22295
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleDrawer());
@@ -25273,7 +24979,7 @@ so this becomes the fallback color for the slot */ ''}
25273
24979
  * @public
25274
24980
  */
25275
24981
  // prettier-ignore
25276
- const template$u = (context, definition) => html `
24982
+ const template$v = (context, definition) => html `
25277
24983
  <template
25278
24984
  aria-checked="${x => x.ariaChecked}"
25279
24985
  aria-disabled="${x => x.ariaDisabled}"
@@ -25378,7 +25084,7 @@ so this becomes the fallback color for the slot */ ''}
25378
25084
  const nimbleListOption = ListOption.compose({
25379
25085
  baseName: 'list-option',
25380
25086
  baseClass: ListboxOption,
25381
- template: template$u,
25087
+ template: template$v,
25382
25088
  styles: styles$E
25383
25089
  });
25384
25090
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleListOption());
@@ -25447,7 +25153,7 @@ so this becomes the fallback color for the slot */ ''}
25447
25153
  return n instanceof ListOption;
25448
25154
  };
25449
25155
  // prettier-ignore
25450
- const template$t = html `
25156
+ const template$u = html `
25451
25157
  <template
25452
25158
  role="group"
25453
25159
  aria-label="${x => x.labelContent}"
@@ -25593,7 +25299,7 @@ so this becomes the fallback color for the slot */ ''}
25593
25299
  const nimbleListOptionGroup = ListOptionGroup.compose({
25594
25300
  baseName: 'list-option-group',
25595
25301
  baseClass: FoundationElement,
25596
- template: template$t,
25302
+ template: template$u,
25597
25303
  styles: styles$D
25598
25304
  });
25599
25305
  DesignSystem.getOrCreate()
@@ -25609,7 +25315,7 @@ so this becomes the fallback color for the slot */ ''}
25609
25315
  attr()
25610
25316
  ], Mapping$1.prototype, "key", void 0);
25611
25317
 
25612
- const template$s = html `<template slot="mapping"></template>`;
25318
+ const template$t = html `<template slot="mapping"></template>`;
25613
25319
 
25614
25320
  const styles$C = css `
25615
25321
  ${display('none')}
@@ -25627,7 +25333,7 @@ so this becomes the fallback color for the slot */ ''}
25627
25333
  ], MappingEmpty.prototype, "text", void 0);
25628
25334
  const emptyMapping = MappingEmpty.compose({
25629
25335
  baseName: 'mapping-empty',
25630
- template: template$s,
25336
+ template: template$t,
25631
25337
  styles: styles$C
25632
25338
  });
25633
25339
  DesignSystem.getOrCreate().withPrefix('nimble').register(emptyMapping());
@@ -25698,7 +25404,7 @@ so this becomes the fallback color for the slot */ ''}
25698
25404
  ], MappingIcon.prototype, "resolvedIcon", void 0);
25699
25405
  const iconMapping = MappingIcon.compose({
25700
25406
  baseName: 'mapping-icon',
25701
- template: template$s,
25407
+ template: template$t,
25702
25408
  styles: styles$C
25703
25409
  });
25704
25410
  DesignSystem.getOrCreate().withPrefix('nimble').register(iconMapping());
@@ -25722,7 +25428,7 @@ so this becomes the fallback color for the slot */ ''}
25722
25428
  ], MappingSpinner.prototype, "textHidden", void 0);
25723
25429
  const spinnerMapping = MappingSpinner.compose({
25724
25430
  baseName: 'mapping-spinner',
25725
- template: template$s,
25431
+ template: template$t,
25726
25432
  styles: styles$C
25727
25433
  });
25728
25434
  DesignSystem.getOrCreate().withPrefix('nimble').register(spinnerMapping());
@@ -25739,11 +25445,330 @@ so this becomes the fallback color for the slot */ ''}
25739
25445
  ], MappingText.prototype, "text", void 0);
25740
25446
  const textMapping = MappingText.compose({
25741
25447
  baseName: 'mapping-text',
25742
- template: template$s,
25448
+ template: template$t,
25743
25449
  styles: styles$C
25744
25450
  });
25745
25451
  DesignSystem.getOrCreate().withPrefix('nimble').register(textMapping());
25746
25452
 
25453
+ /**
25454
+ * A Menu Custom HTML Element.
25455
+ * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#menu | ARIA menu }.
25456
+ *
25457
+ * @slot - The default slot for the menu items
25458
+ *
25459
+ * @public
25460
+ */
25461
+ let Menu$1 = class Menu extends FoundationElement {
25462
+ constructor() {
25463
+ super(...arguments);
25464
+ this.expandedItem = null;
25465
+ /**
25466
+ * The index of the focusable element in the items array
25467
+ * defaults to -1
25468
+ */
25469
+ this.focusIndex = -1;
25470
+ /**
25471
+ * @internal
25472
+ */
25473
+ this.isNestedMenu = () => {
25474
+ return (this.parentElement !== null
25475
+ && isHTMLElement(this.parentElement)
25476
+ && this.parentElement.getAttribute('role') === 'menuitem');
25477
+ };
25478
+ /**
25479
+ * if focus is moving out of the menu, reset to a stable initial state
25480
+ * @internal
25481
+ */
25482
+ this.handleFocusOut = (e) => {
25483
+ if (!this.contains(e.relatedTarget)
25484
+ && this.menuItems !== undefined) {
25485
+ this.collapseExpandedItem();
25486
+ // find our first focusable element
25487
+ const focusIndex = this.menuItems.findIndex(this.isFocusableElement);
25488
+ // set the current focus index's tabindex to -1
25489
+ this.menuItems[this.focusIndex]?.setAttribute('tabindex', '-1');
25490
+ // set the first focusable element tabindex to 0
25491
+ this.menuItems[focusIndex]?.setAttribute('tabindex', '0');
25492
+ // set the focus index
25493
+ this.focusIndex = focusIndex;
25494
+ }
25495
+ };
25496
+ this.handleItemFocus = (e) => {
25497
+ const targetItem = e.target;
25498
+ if (this.menuItems !== undefined
25499
+ && targetItem !== this.menuItems[this.focusIndex]) {
25500
+ this.menuItems[this.focusIndex]?.setAttribute('tabindex', '-1');
25501
+ this.focusIndex = this.menuItems.indexOf(targetItem);
25502
+ targetItem.setAttribute('tabindex', '0');
25503
+ }
25504
+ };
25505
+ this.handleExpandedChanged = (e) => {
25506
+ if (e.defaultPrevented
25507
+ || e.target === null
25508
+ || this.menuItems === undefined
25509
+ || !this.menuItems.includes(e.target)) {
25510
+ return;
25511
+ }
25512
+ e.preventDefault();
25513
+ const changedItem = e.target;
25514
+ // closing an expanded item without opening another
25515
+ if (this.expandedItem !== null
25516
+ && changedItem === this.expandedItem
25517
+ && changedItem.expanded === false) {
25518
+ this.expandedItem = null;
25519
+ return;
25520
+ }
25521
+ if (changedItem.expanded) {
25522
+ if (this.expandedItem !== null
25523
+ && this.expandedItem !== changedItem) {
25524
+ this.expandedItem.expanded = false;
25525
+ }
25526
+ this.menuItems[this.focusIndex]?.setAttribute('tabindex', '-1');
25527
+ this.expandedItem = changedItem;
25528
+ this.focusIndex = this.menuItems.indexOf(changedItem);
25529
+ changedItem.setAttribute('tabindex', '0');
25530
+ }
25531
+ };
25532
+ this.removeItemListeners = () => {
25533
+ if (this.menuItems !== undefined) {
25534
+ this.menuItems.forEach((item) => {
25535
+ item.removeEventListener('expanded-change', this.handleExpandedChanged);
25536
+ item.removeEventListener('focus', this.handleItemFocus);
25537
+ });
25538
+ }
25539
+ };
25540
+ this.setItems = () => {
25541
+ const newItems = this.domChildren();
25542
+ this.removeItemListeners();
25543
+ this.menuItems = newItems;
25544
+ const menuItems = this.menuItems.filter(this.isMenuItemElement);
25545
+ // if our focus index is not -1 we have items
25546
+ if (menuItems.length) {
25547
+ this.focusIndex = 0;
25548
+ }
25549
+ function elementIndent(el) {
25550
+ const role = el.getAttribute('role');
25551
+ const startSlot = el.querySelector('[slot=start]');
25552
+ if (role !== MenuItemRole.menuitem && startSlot === null) {
25553
+ return 1;
25554
+ }
25555
+ if (role === MenuItemRole.menuitem && startSlot !== null) {
25556
+ return 1;
25557
+ }
25558
+ if (role !== MenuItemRole.menuitem && startSlot !== null) {
25559
+ return 2;
25560
+ }
25561
+ return 0;
25562
+ }
25563
+ const indent = menuItems.reduce((accum, current) => {
25564
+ const elementValue = elementIndent(current);
25565
+ return accum > elementValue ? accum : elementValue;
25566
+ }, 0);
25567
+ menuItems.forEach((item, index) => {
25568
+ item.setAttribute('tabindex', index === 0 ? '0' : '-1');
25569
+ item.addEventListener('expanded-change', this.handleExpandedChanged);
25570
+ item.addEventListener('focus', this.handleItemFocus);
25571
+ if (item instanceof MenuItem$1 || 'startColumnCount' in item) {
25572
+ item.startColumnCount = indent;
25573
+ }
25574
+ });
25575
+ };
25576
+ /**
25577
+ * handle change from child element
25578
+ */
25579
+ this.changeHandler = (e) => {
25580
+ if (this.menuItems === undefined) {
25581
+ return;
25582
+ }
25583
+ const changedMenuItem = e.target;
25584
+ const changeItemIndex = this.menuItems.indexOf(changedMenuItem);
25585
+ if (changeItemIndex === -1) {
25586
+ return;
25587
+ }
25588
+ if (changedMenuItem.role === 'menuitemradio'
25589
+ && changedMenuItem.checked === true) {
25590
+ for (let i = changeItemIndex - 1; i >= 0; --i) {
25591
+ const item = this.menuItems[i];
25592
+ const role = item.getAttribute('role');
25593
+ if (role === MenuItemRole.menuitemradio) {
25594
+ item.checked = false;
25595
+ }
25596
+ if (role === 'separator') {
25597
+ break;
25598
+ }
25599
+ }
25600
+ const maxIndex = this.menuItems.length - 1;
25601
+ for (let i = changeItemIndex + 1; i <= maxIndex; ++i) {
25602
+ const item = this.menuItems[i];
25603
+ const role = item.getAttribute('role');
25604
+ if (role === MenuItemRole.menuitemradio) {
25605
+ item.checked = false;
25606
+ }
25607
+ if (role === 'separator') {
25608
+ break;
25609
+ }
25610
+ }
25611
+ }
25612
+ };
25613
+ /**
25614
+ * check if the item is a menu item
25615
+ */
25616
+ this.isMenuItemElement = (el) => {
25617
+ return (isHTMLElement(el)
25618
+ && Object.prototype.hasOwnProperty.call(Menu.focusableElementRoles, el.getAttribute('role')));
25619
+ };
25620
+ /**
25621
+ * check if the item is focusable
25622
+ */
25623
+ this.isFocusableElement = (el) => {
25624
+ return this.isMenuItemElement(el);
25625
+ };
25626
+ }
25627
+ /**
25628
+ * @internal
25629
+ */
25630
+ connectedCallback() {
25631
+ super.connectedCallback();
25632
+ DOM.queueUpdate(() => {
25633
+ // wait until children have had a chance to
25634
+ // connect before setting/checking their props/attributes
25635
+ this.setItems();
25636
+ });
25637
+ this.addEventListener('change', this.changeHandler);
25638
+ }
25639
+ /**
25640
+ * @internal
25641
+ */
25642
+ disconnectedCallback() {
25643
+ super.disconnectedCallback();
25644
+ this.removeItemListeners();
25645
+ this.menuItems = undefined;
25646
+ this.removeEventListener('change', this.changeHandler);
25647
+ }
25648
+ /**
25649
+ * Focuses the first item in the menu.
25650
+ *
25651
+ * @public
25652
+ */
25653
+ focus() {
25654
+ this.setFocus(0, 1);
25655
+ }
25656
+ /**
25657
+ * Collapses any expanded menu items.
25658
+ *
25659
+ * @public
25660
+ */
25661
+ collapseExpandedItem() {
25662
+ if (this.expandedItem !== null) {
25663
+ this.expandedItem.expanded = false;
25664
+ this.expandedItem = null;
25665
+ }
25666
+ }
25667
+ /**
25668
+ * @internal
25669
+ */
25670
+ handleMenuKeyDown(e) {
25671
+ if (e.defaultPrevented || this.menuItems === undefined) {
25672
+ return false;
25673
+ }
25674
+ switch (e.key) {
25675
+ case keyArrowDown:
25676
+ // go forward one index
25677
+ this.setFocus(this.focusIndex + 1, 1);
25678
+ return false;
25679
+ case keyArrowUp:
25680
+ // go back one index
25681
+ this.setFocus(this.focusIndex - 1, -1);
25682
+ return false;
25683
+ case keyEnd:
25684
+ // set focus on last item
25685
+ this.setFocus(this.menuItems.length - 1, -1);
25686
+ return false;
25687
+ case keyHome:
25688
+ // set focus on first item
25689
+ this.setFocus(0, 1);
25690
+ return false;
25691
+ default:
25692
+ // if we are not handling the event, do not prevent default
25693
+ return true;
25694
+ }
25695
+ }
25696
+ itemsChanged() {
25697
+ // only update children after the component is connected and
25698
+ // the setItems has run on connectedCallback
25699
+ // (menuItems is undefined until then)
25700
+ if (this.$fastController.isConnected && this.menuItems !== undefined) {
25701
+ this.setItems();
25702
+ }
25703
+ }
25704
+ itemIconsChanged(oldIcons, newIcons) {
25705
+ // must check if set of icon elements is actually different
25706
+ if (this.$fastController.isConnected
25707
+ && this.menuItems !== undefined
25708
+ && (oldIcons.length !== newIcons.length
25709
+ || new Set(oldIcons.concat(newIcons)).size !== oldIcons.length)) {
25710
+ this.setItems();
25711
+ }
25712
+ }
25713
+ /**
25714
+ * get an array of valid DOM children
25715
+ */
25716
+ domChildren() {
25717
+ return Array.from(this.children).filter(child => !child.hasAttribute('hidden'));
25718
+ }
25719
+ setFocus(focusIndex, adjustment) {
25720
+ if (this.menuItems === undefined) {
25721
+ return;
25722
+ }
25723
+ let updatedIndex = focusIndex;
25724
+ while (updatedIndex >= 0 && updatedIndex < this.menuItems.length) {
25725
+ const child = this.menuItems[updatedIndex];
25726
+ if (this.isFocusableElement(child)) {
25727
+ // change the previous index to -1
25728
+ if (this.focusIndex > -1
25729
+ && this.menuItems.length >= this.focusIndex - 1) {
25730
+ this.menuItems[this.focusIndex]?.setAttribute('tabindex', '-1');
25731
+ }
25732
+ // update the focus index
25733
+ this.focusIndex = updatedIndex;
25734
+ // update the tabindex of next focusable element
25735
+ child.setAttribute('tabindex', '0');
25736
+ // focus the element
25737
+ child.focus();
25738
+ break;
25739
+ }
25740
+ updatedIndex += adjustment;
25741
+ }
25742
+ }
25743
+ };
25744
+ Menu$1.focusableElementRoles = roleForMenuItem;
25745
+ __decorate$1([
25746
+ observable
25747
+ ], Menu$1.prototype, "items", void 0);
25748
+ __decorate$1([
25749
+ observable
25750
+ ], Menu$1.prototype, "itemIcons", void 0);
25751
+
25752
+ /* eslint-disable @typescript-eslint/indent */
25753
+ // prettier-ignore
25754
+ const template$s = () => html `
25755
+ <template
25756
+ slot="${x => {
25757
+ if (x.slot) {
25758
+ return x.slot;
25759
+ }
25760
+ return x.isNestedMenu() ? 'submenu' : undefined;
25761
+ }}"
25762
+ role="menu"
25763
+ @keydown="${(x, c) => x.handleMenuKeyDown(c.event)}"
25764
+ @focusout="${(x, c) => x.handleFocusOut(c.event)}"
25765
+ ${children$1({ property: 'itemIcons', subtree: true, attributeFilter: ['slot'], selector: ':scope > * > [slot="start"]' })}
25766
+ >
25767
+ <slot ${slotted('items')}></slot>
25768
+ </template>
25769
+ `;
25770
+ /* eslint-enable @typescript-eslint/indent */
25771
+
25747
25772
  const styles$B = css `
25748
25773
  ${display('grid')}
25749
25774
 
@@ -25815,7 +25840,7 @@ so this becomes the fallback color for the slot */ ''}
25815
25840
  const nimbleMenu = Menu.compose({
25816
25841
  baseName: 'menu',
25817
25842
  baseClass: Menu$1,
25818
- template: menuTemplate,
25843
+ template: template$s,
25819
25844
  styles: styles$B
25820
25845
  });
25821
25846
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleMenu());