@ni/nimble-components 17.2.0 → 18.0.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.
@@ -21238,7 +21238,7 @@
21238
21238
  ${ref('region')}
21239
21239
  >
21240
21240
  <span part="menu">
21241
- <slot name="menu" ${slotted({ property: 'slottedMenus', filter: elements('[role=menu]') })}></slot>
21241
+ <slot name="menu" ${slotted({ property: 'slottedMenus' })}></slot>
21242
21242
  </span>
21243
21243
  </${DesignSystem.tagFor(AnchoredRegion)}>
21244
21244
  `)}
@@ -21281,7 +21281,7 @@
21281
21281
  */
21282
21282
  this.focusLastItemWhenOpened = false;
21283
21283
  this.menuChangeHandler = () => {
21284
- this.open = false;
21284
+ this.setOpen(false);
21285
21285
  this.toggleButton.focus();
21286
21286
  };
21287
21287
  }
@@ -21316,7 +21316,11 @@
21316
21316
  if (!this.open) {
21317
21317
  // Only fire an event here if the menu is changing to being closed. Otherwise,
21318
21318
  // wait until the menu is actually opened before firing the event.
21319
- this.$emit('open-change');
21319
+ const eventDetail = {
21320
+ oldState: true,
21321
+ newState: false
21322
+ };
21323
+ this.$emit('toggle', eventDetail);
21320
21324
  }
21321
21325
  }
21322
21326
  regionLoadedHandler() {
@@ -21327,23 +21331,28 @@
21327
21331
  else {
21328
21332
  this.focusMenu();
21329
21333
  }
21330
- this.$emit('open-change');
21334
+ const eventDetail = {
21335
+ oldState: false,
21336
+ newState: true
21337
+ };
21338
+ this.$emit('toggle', eventDetail);
21331
21339
  }
21332
21340
  focusoutHandler(e) {
21333
21341
  if (!this.open) {
21334
21342
  return true;
21335
21343
  }
21336
21344
  const focusTarget = e.relatedTarget;
21337
- if (!this.contains(focusTarget)) {
21338
- this.open = false;
21345
+ if (!this.contains(focusTarget)
21346
+ && !this.getMenu()?.contains(focusTarget)) {
21347
+ this.setOpen(false);
21339
21348
  return false;
21340
21349
  }
21341
21350
  return true;
21342
21351
  }
21343
21352
  toggleButtonCheckedChangeHandler(e) {
21344
- this.open = this.toggleButton.checked;
21353
+ this.setOpen(this.toggleButton.checked);
21345
21354
  // Don't bubble the 'change' event from the toggle button because
21346
- // the menu button has its own 'open-change' event.
21355
+ // the menu button has its own 'toggle' event.
21347
21356
  e.stopPropagation();
21348
21357
  return false;
21349
21358
  }
@@ -21351,10 +21360,10 @@
21351
21360
  switch (e.key) {
21352
21361
  case keyArrowUp:
21353
21362
  this.focusLastItemWhenOpened = true;
21354
- this.open = true;
21363
+ this.setOpen(true);
21355
21364
  return false;
21356
21365
  case keyArrowDown:
21357
- this.open = true;
21366
+ this.setOpen(true);
21358
21367
  return false;
21359
21368
  default:
21360
21369
  return true;
@@ -21363,21 +21372,59 @@
21363
21372
  menuKeyDownHandler(e) {
21364
21373
  switch (e.key) {
21365
21374
  case keyEscape:
21366
- this.open = false;
21375
+ this.setOpen(false);
21367
21376
  this.toggleButton.focus();
21368
21377
  return false;
21369
21378
  default:
21370
21379
  return true;
21371
21380
  }
21372
21381
  }
21373
- get menu() {
21374
- return this.slottedMenus?.length ? this.slottedMenus[0] : undefined;
21382
+ setOpen(newValue) {
21383
+ if (this.open === newValue) {
21384
+ return;
21385
+ }
21386
+ const eventDetail = {
21387
+ oldState: this.open,
21388
+ newState: newValue
21389
+ };
21390
+ this.$emit('beforetoggle', eventDetail);
21391
+ this.open = newValue;
21392
+ }
21393
+ getMenu() {
21394
+ // Get the menu that is slotted within the menu-button, taking into account
21395
+ // that it may be nested within multiple 'slot' elements, such as when used
21396
+ // within a table.
21397
+ if (!this.slottedMenus?.length) {
21398
+ return undefined;
21399
+ }
21400
+ let currentItem = this.slottedMenus[0];
21401
+ while (currentItem) {
21402
+ if (currentItem.getAttribute('role') === 'menu') {
21403
+ return currentItem;
21404
+ }
21405
+ if (this.isSlotElement(currentItem)) {
21406
+ const firstNode = currentItem.assignedNodes()[0];
21407
+ if (firstNode instanceof HTMLElement) {
21408
+ currentItem = firstNode;
21409
+ }
21410
+ else {
21411
+ currentItem = undefined;
21412
+ }
21413
+ }
21414
+ else {
21415
+ return undefined;
21416
+ }
21417
+ }
21418
+ return undefined;
21419
+ }
21420
+ isSlotElement(element) {
21421
+ return element?.nodeName === 'SLOT';
21375
21422
  }
21376
21423
  focusMenu() {
21377
- this.menu?.focus();
21424
+ this.getMenu()?.focus();
21378
21425
  }
21379
21426
  focusLastMenuItem() {
21380
- const menuItems = this.menu?.querySelectorAll('[role=menuitem]');
21427
+ const menuItems = this.getMenu()?.querySelectorAll('[role=menuitem]');
21381
21428
  if (menuItems?.length) {
21382
21429
  const lastMenuItem = menuItems[menuItems.length - 1];
21383
21430
  lastMenuItem.focus();