@iris-ui-kit/vue 0.2.26 → 0.2.28

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.
@@ -6,8 +6,8 @@ import { IrisThemeKey } from './chunk-ZTPIXL7Q.js';
6
6
  import { IrisSortable } from './chunk-W3B6E5GN.js';
7
7
  import { useStore } from './chunk-75GSYEJS.js';
8
8
  import { useI18n } from './chunk-TCAXRWT6.js';
9
- import { defineComponent, inject, h, computed, shallowRef, onBeforeUnmount, watch, ref, provide, useId, nextTick, Teleport, Fragment, watchEffect, toValue, onMounted } from 'vue';
10
- import { visibleNav, findNavPath, createExpansion, branchTrail, isBranch, createFloatingMachine, findNavNode, firstLeaf, matchTypeahead, nextEnabledIndex, isClosable, createAdminShell } from '@iris-ui-kit/core';
9
+ import { defineComponent, inject, h, computed, shallowRef, onBeforeUnmount, watch, provide, useId, ref, nextTick, Teleport, Fragment, watchEffect, toValue, onMounted } from 'vue';
10
+ import { visibleNav, findNavPath, createExpansion, branchTrail, createFloatingMachine, isBranch, findNavNode, firstLeaf, matchTypeahead, nextEnabledIndex, isClosable, createAdminShell } from '@iris-ui-kit/core';
11
11
  export { createAdminPreferences, createTabsNav, filterNavByAccess, findNavNode, findNavPath, firstLeaf, flattenNav, isBranch, isClosable, localStorageAdminPreferencesStorage, nodeAllowsRoles, visibleNav } from '@iris-ui-kit/core';
12
12
  import { defaultIconRegistry, resolveThemedIcon } from '@iris-ui-kit/icons';
13
13
 
@@ -77,6 +77,7 @@ var CSS = `
77
77
  --iris-nav-item-padding-block: 8px;
78
78
  --iris-nav-item-border-radius: var(--iris-radius-md, 6px);
79
79
  --iris-nav-item-hover: var(--iris-surface-hover, var(--iris-surface));
80
+ --iris-nav-item-active-hover: color-mix(in srgb, var(--iris-primary) 88%, black);
80
81
  --iris-nav-item-height: 34px;
81
82
  display: flex;
82
83
  flex-direction: column;
@@ -182,6 +183,13 @@ var CSS = `
182
183
  font-weight: 600;
183
184
  }
184
185
 
186
+ /* active \u9879\u7684 hover \u53CD\u9988\uFF1Aprimary \u52A0\u6DF1\u53D8\u4F53\uFF08\u76AE\u80A4\u53EF\u7528
187
+ --iris-nav-item-active-hover \u8986\u76D6\uFF09\uFF1B\u7279\u5F02\u5EA6\u9AD8\u4E8E :hover/:where \u89C4\u5219 */
188
+ .iris-nav-menu-item[data-active='true']:hover,
189
+ .iris-nav-menu-item[data-active='true'].is-hovered:not([disabled], .is-disabled) {
190
+ background: var(--iris-nav-item-active-hover, color-mix(in srgb, var(--iris-primary) 88%, black));
191
+ }
192
+
185
193
  :where(.iris-nav-menu-item[data-active-trail='true']) {
186
194
  color: var(--iris-primary);
187
195
  font-weight: 600;
@@ -348,10 +356,317 @@ function installNavMenuStyles() {
348
356
  document.head.appendChild(style);
349
357
  installed = true;
350
358
  }
359
+ var HOVER_OPEN_DELAY_VAL = 60;
360
+ var HOVER_CLOSE_DELAY_VAL = 150;
361
+ function createNavMenuFlyout(ctx) {
362
+ const hovered = ref(null);
363
+ const hoveredBranches = ref([]);
364
+ const focusedBranches = ref([]);
365
+ const clickedBranches = ref([]);
366
+ let suppressFocusOpen = false;
367
+ let openTimer = null;
368
+ const closeTimers = /* @__PURE__ */ new Map();
369
+ const clearOpenTimer = () => {
370
+ if (openTimer) {
371
+ clearTimeout(openTimer);
372
+ openTimer = null;
373
+ }
374
+ };
375
+ const cancelClose = (key) => {
376
+ const timer = closeTimers.get(key);
377
+ if (timer) {
378
+ clearTimeout(timer);
379
+ closeTimers.delete(key);
380
+ }
381
+ };
382
+ const cancelAllTimers = () => {
383
+ clearOpenTimer();
384
+ for (const timer of closeTimers.values()) clearTimeout(timer);
385
+ closeTimers.clear();
386
+ };
387
+ onBeforeUnmount(cancelAllTimers);
388
+ const flyoutTriggers = /* @__PURE__ */ new Map();
389
+ const flyoutPanels = /* @__PURE__ */ new Map();
390
+ const setFlyoutRef = (map, key, el) => {
391
+ if (el instanceof HTMLElement) map.set(key, el);
392
+ else map.delete(key);
393
+ };
394
+ const positionFlyout = (key) => {
395
+ const trigger = flyoutTriggers.get(key);
396
+ const panel = flyoutPanels.get(key);
397
+ if (!trigger || !panel || typeof document === "undefined") return;
398
+ const rect = trigger.getBoundingClientRect();
399
+ const dir = getComputedStyle(trigger).direction;
400
+ panel.style.position = "fixed";
401
+ panel.style.top = `${ctx.collapsed ? rect.top : rect.bottom}px`;
402
+ if (dir === "rtl") {
403
+ panel.style.left = "";
404
+ panel.style.right = `${window.innerWidth - (ctx.collapsed ? rect.left : rect.right)}px`;
405
+ } else {
406
+ panel.style.right = "";
407
+ panel.style.left = `${ctx.collapsed ? rect.right : rect.left}px`;
408
+ }
409
+ };
410
+ onBeforeUnmount(() => {
411
+ detachViewportListeners();
412
+ flyoutTriggers.clear();
413
+ flyoutPanels.clear();
414
+ });
415
+ const isolateAtDepth = (key) => {
416
+ const depth = findNavPath(ctx.items, key).length - 1;
417
+ const isSameDepthOther = (k) => k !== key && findNavPath(ctx.items, k).length - 1 === depth;
418
+ for (const state of [hoveredBranches, clickedBranches, focusedBranches]) {
419
+ if (state.value.some(isSameDepthOther)) {
420
+ state.value = state.value.filter((k) => !isSameDepthOther(k));
421
+ }
422
+ }
423
+ };
424
+ const scheduleOpen = (key) => {
425
+ clearOpenTimer();
426
+ openTimer = setTimeout(() => {
427
+ openTimer = null;
428
+ isolateAtDepth(key);
429
+ setBranchInteraction(hoveredBranches, key, true);
430
+ }, HOVER_OPEN_DELAY_VAL);
431
+ };
432
+ const scheduleClose = (key) => {
433
+ cancelClose(key);
434
+ closeTimers.set(
435
+ key,
436
+ setTimeout(() => {
437
+ closeTimers.delete(key);
438
+ setBranchInteraction(hoveredBranches, key, false);
439
+ }, HOVER_CLOSE_DELAY_VAL)
440
+ );
441
+ };
442
+ const closeHorizontalMenus = () => {
443
+ if (!ctx.flyoutMode.value) return;
444
+ cancelAllTimers();
445
+ hovered.value = null;
446
+ hoveredBranches.value = [];
447
+ focusedBranches.value = [];
448
+ clickedBranches.value = [];
449
+ };
450
+ const select = (node) => {
451
+ if (node.disabled) return;
452
+ closeHorizontalMenus();
453
+ ctx.emitSelect(node.key, node);
454
+ };
455
+ const toggleFlyout = (key) => {
456
+ cancelAllTimers();
457
+ const current = clickedBranches.value;
458
+ if (current.includes(key)) {
459
+ clickedBranches.value = current.filter((k) => k !== key);
460
+ setBranchInteraction(hoveredBranches, key, false);
461
+ setBranchInteraction(focusedBranches, key, false);
462
+ } else {
463
+ isolateAtDepth(key);
464
+ clickedBranches.value = [...clickedBranches.value, key];
465
+ }
466
+ };
467
+ const openFlyout = (key) => {
468
+ cancelAllTimers();
469
+ isolateAtDepth(key);
470
+ setBranchInteraction(focusedBranches, key, true);
471
+ };
472
+ const setBranchInteraction = (state, key, enabled) => {
473
+ const current = state.value;
474
+ if (enabled) {
475
+ if (!current.includes(key)) state.value = [...current, key];
476
+ } else if (current.includes(key)) {
477
+ state.value = current.filter((item) => item !== key);
478
+ }
479
+ };
480
+ const keepsPointerInside = (container, event) => {
481
+ if (!container || !(container instanceof HTMLElement)) return false;
482
+ const next = event.relatedTarget;
483
+ return !!(next && next instanceof Node && container.contains(next));
484
+ };
485
+ const interactionKeyAtDepth = (keys, depth) => keys.find((key) => findNavPath(ctx.items, key).length === depth + 1);
486
+ const horizontalBranchVisible = (key, depth) => {
487
+ const hoveredAtDepth = interactionKeyAtDepth(hoveredBranches.value, depth);
488
+ if (hoveredAtDepth) return hoveredAtDepth === key;
489
+ const clickedAtDepth = interactionKeyAtDepth(clickedBranches.value, depth);
490
+ if (clickedAtDepth) return clickedAtDepth === key;
491
+ return interactionKeyAtDepth(focusedBranches.value, depth) === key;
492
+ };
493
+ const shownFlyoutKeys = computed(() => {
494
+ if (!ctx.flyoutMode.value) return [];
495
+ const keys = [];
496
+ for (const node of ctx.tree.value) {
497
+ if (isBranch(node) && horizontalBranchVisible(node.key, 0)) keys.push(node.key);
498
+ }
499
+ return keys;
500
+ });
501
+ const repositionOpenFlyouts = () => {
502
+ for (const key of shownFlyoutKeys.value) positionFlyout(key);
503
+ };
504
+ let viewportListenersActive = false;
505
+ const attachViewportListeners = () => {
506
+ if (viewportListenersActive || typeof document === "undefined") return;
507
+ viewportListenersActive = true;
508
+ document.addEventListener("scroll", repositionOpenFlyouts, true);
509
+ window.addEventListener("resize", repositionOpenFlyouts);
510
+ };
511
+ const detachViewportListeners = () => {
512
+ if (!viewportListenersActive || typeof document === "undefined") return;
513
+ viewportListenersActive = false;
514
+ document.removeEventListener("scroll", repositionOpenFlyouts, true);
515
+ window.removeEventListener("resize", repositionOpenFlyouts);
516
+ };
517
+ watch(
518
+ shownFlyoutKeys,
519
+ (keys, prev) => {
520
+ if (keys.length > 0 && prev.length === 0) attachViewportListeners();
521
+ else if (keys.length === 0 && prev.length > 0) detachViewportListeners();
522
+ for (const key of keys) positionFlyout(key);
523
+ },
524
+ { flush: "post" }
525
+ );
526
+ return {
527
+ hovered,
528
+ hoveredBranches,
529
+ focusedBranches,
530
+ clickedBranches,
531
+ select,
532
+ toggleFlyout,
533
+ openFlyout,
534
+ closeHorizontalMenus,
535
+ setBranchInteraction,
536
+ keepsPointerInside,
537
+ interactionKeyAtDepth,
538
+ horizontalBranchVisible,
539
+ shownFlyoutKeys,
540
+ setFlyoutRef,
541
+ flyoutTriggers,
542
+ flyoutPanels,
543
+ suppressFocusOpen: { get: () => suppressFocusOpen },
544
+ setSuppressFocusOpen: (value) => {
545
+ suppressFocusOpen = value;
546
+ },
547
+ cancelClose,
548
+ scheduleOpen,
549
+ scheduleClose,
550
+ cancelAllTimers
551
+ };
552
+ }
553
+ function createNavMenuKeydownHandler(deps) {
554
+ const {
555
+ items,
556
+ flyoutMode,
557
+ expanded,
558
+ toggle,
559
+ openFlyout,
560
+ closeHorizontalMenus,
561
+ horizontalBranchVisible,
562
+ setBranchInteraction,
563
+ focusedBranches,
564
+ collapsed,
565
+ hoveredBranches,
566
+ clickedBranches,
567
+ setSuppressFocusOpen
568
+ } = deps;
569
+ return (e) => {
570
+ const root = e.currentTarget;
571
+ const buttons = Array.from(root.querySelectorAll("[data-iris-nav-item]")).filter(
572
+ (button) => !button.closest('[data-iris-nav-children][aria-hidden="true"]')
573
+ );
574
+ if (buttons.length === 0) return;
575
+ const idx = buttons.indexOf(document.activeElement);
576
+ const focusAt = (i) => buttons[(i + buttons.length) % buttons.length]?.focus();
577
+ const key = idx >= 0 ? buttons[idx]?.getAttribute("data-key") : void 0;
578
+ const node = key ? findNavNode(items, key) : void 0;
579
+ const depth = idx >= 0 ? Number(buttons[idx]?.getAttribute("data-depth") ?? 0) : 0;
580
+ switch (e.key) {
581
+ case "ArrowDown": {
582
+ e.preventDefault();
583
+ if (flyoutMode() && node && isBranch(node)) {
584
+ openFlyout(key);
585
+ const group = buttons[idx].closest("[data-iris-nav-group]");
586
+ void nextTick(() => {
587
+ group?.querySelector("[data-iris-nav-children] [data-iris-nav-item]")?.focus();
588
+ });
589
+ return;
590
+ }
591
+ focusAt(idx < 0 ? 0 : idx + 1);
592
+ return;
593
+ }
594
+ case "ArrowUp": {
595
+ e.preventDefault();
596
+ if (flyoutMode() && node && isBranch(node) && horizontalBranchVisible(key, depth)) {
597
+ setBranchInteraction(focusedBranches, key, false);
598
+ setBranchInteraction(clickedBranches, key, false);
599
+ return;
600
+ }
601
+ focusAt(idx < 0 ? buttons.length - 1 : idx - 1);
602
+ return;
603
+ }
604
+ case "Home":
605
+ e.preventDefault();
606
+ buttons[0]?.focus();
607
+ return;
608
+ case "End":
609
+ e.preventDefault();
610
+ buttons[buttons.length - 1]?.focus();
611
+ return;
612
+ case "Escape": {
613
+ if (flyoutMode()) {
614
+ const openKeys = [
615
+ ...hoveredBranches.value,
616
+ ...clickedBranches.value,
617
+ ...focusedBranches.value
618
+ ];
619
+ if (openKeys.length > 0) {
620
+ e.preventDefault();
621
+ const openTop = openKeys.find((k) => findNavPath(items, k).length === 1);
622
+ closeHorizontalMenus();
623
+ if (openTop) {
624
+ setSuppressFocusOpen(true);
625
+ buttons.find((b) => b.getAttribute("data-key") === openTop)?.focus();
626
+ void nextTick(() => {
627
+ setSuppressFocusOpen(false);
628
+ });
629
+ }
630
+ }
631
+ }
632
+ return;
633
+ }
634
+ }
635
+ if (collapsed || idx < 0 || !key || !node) return;
636
+ if (e.key === "ArrowRight") {
637
+ e.preventDefault();
638
+ if (isBranch(node)) {
639
+ if (flyoutMode() || !expanded().includes(key)) {
640
+ if (flyoutMode()) openFlyout(key);
641
+ else toggle(key);
642
+ const group = buttons[idx].closest("[data-iris-nav-group]");
643
+ void nextTick(() => {
644
+ group?.querySelector("[data-iris-nav-children] [data-iris-nav-item]")?.focus();
645
+ });
646
+ } else {
647
+ focusAt(idx + 1);
648
+ }
649
+ }
650
+ } else if (e.key === "ArrowLeft") {
651
+ e.preventDefault();
652
+ if (flyoutMode() && isBranch(node)) {
653
+ setBranchInteraction(focusedBranches, key, false);
654
+ setBranchInteraction(clickedBranches, key, false);
655
+ return;
656
+ }
657
+ if (isBranch(node) && expanded().includes(key)) {
658
+ toggle(key);
659
+ } else {
660
+ const parentKey = findNavPath(items, key).at(-2)?.key;
661
+ if (parentKey) {
662
+ buttons.find((b) => b.getAttribute("data-key") === parentKey)?.focus();
663
+ }
664
+ }
665
+ }
666
+ };
667
+ }
351
668
 
352
669
  // src/admin/NavMenu.ts
353
- var HOVER_OPEN_DELAY = 100;
354
- var HOVER_CLOSE_DELAY = 150;
355
670
  var IrisNavMenu = defineComponent({
356
671
  name: "IrisNavMenu",
357
672
  inheritAttrs: false,
@@ -413,170 +728,35 @@ var IrisNavMenu = defineComponent({
413
728
  emit("update:expandedKeys", model.get());
414
729
  }
415
730
  };
416
- const hovered = ref(null);
417
- const hoveredBranches = ref([]);
418
- const focusedBranches = ref([]);
419
- const clickedBranches = ref([]);
420
- let suppressFocusOpen = false;
421
- let openTimer = null;
422
- const closeTimers = /* @__PURE__ */ new Map();
423
- const clearOpenTimer = () => {
424
- if (openTimer) {
425
- clearTimeout(openTimer);
426
- openTimer = null;
427
- }
428
- };
429
- const cancelClose = (key) => {
430
- const timer = closeTimers.get(key);
431
- if (timer) {
432
- clearTimeout(timer);
433
- closeTimers.delete(key);
434
- }
435
- };
436
- const cancelAllTimers = () => {
437
- clearOpenTimer();
438
- for (const timer of closeTimers.values()) clearTimeout(timer);
439
- closeTimers.clear();
440
- };
441
- onBeforeUnmount(cancelAllTimers);
442
- const flyoutTriggers = /* @__PURE__ */ new Map();
443
- const flyoutPanels = /* @__PURE__ */ new Map();
444
- const setFlyoutRef = (map, key, el) => {
445
- if (el instanceof HTMLElement) map.set(key, el);
446
- else map.delete(key);
447
- };
448
- const positionFlyout = (key) => {
449
- const trigger = flyoutTriggers.get(key);
450
- const panel = flyoutPanels.get(key);
451
- if (!trigger || !panel || typeof document === "undefined") return;
452
- const rect = trigger.getBoundingClientRect();
453
- const dir = getComputedStyle(trigger).direction;
454
- panel.style.position = "fixed";
455
- panel.style.top = `${props.collapsed ? rect.top : rect.bottom}px`;
456
- if (dir === "rtl") {
457
- panel.style.left = "";
458
- panel.style.right = `${window.innerWidth - (props.collapsed ? rect.left : rect.right)}px`;
459
- } else {
460
- panel.style.right = "";
461
- panel.style.left = `${props.collapsed ? rect.right : rect.left}px`;
462
- }
463
- };
464
- onBeforeUnmount(() => {
465
- detachViewportListeners();
466
- flyoutTriggers.clear();
467
- flyoutPanels.clear();
731
+ const flyout = createNavMenuFlyout({
732
+ items: props.items,
733
+ tree,
734
+ expanded,
735
+ flyoutMode: { value: flyoutMode.value },
736
+ collapsed: props.collapsed,
737
+ toggle,
738
+ emitSelect: (key, node) => emit("select", key, node)
468
739
  });
469
- const isolateAtDepth = (key) => {
470
- const depth = findNavPath(props.items, key).length - 1;
471
- const isSameDepthOther = (k) => k !== key && findNavPath(props.items, k).length - 1 === depth;
472
- for (const state of [hoveredBranches, clickedBranches, focusedBranches]) {
473
- if (state.value.some(isSameDepthOther)) {
474
- state.value = state.value.filter((k) => !isSameDepthOther(k));
475
- }
476
- }
477
- };
478
- const scheduleOpen = (key) => {
479
- clearOpenTimer();
480
- openTimer = setTimeout(() => {
481
- openTimer = null;
482
- isolateAtDepth(key);
483
- setBranchInteraction(hoveredBranches, key, true);
484
- }, HOVER_OPEN_DELAY);
485
- };
486
- const scheduleClose = (key) => {
487
- cancelClose(key);
488
- closeTimers.set(
489
- key,
490
- setTimeout(() => {
491
- closeTimers.delete(key);
492
- setBranchInteraction(hoveredBranches, key, false);
493
- }, HOVER_CLOSE_DELAY)
494
- );
495
- };
496
- const closeHorizontalMenus = () => {
497
- if (!flyoutMode.value) return;
498
- cancelAllTimers();
499
- hovered.value = null;
500
- hoveredBranches.value = [];
501
- focusedBranches.value = [];
502
- clickedBranches.value = [];
503
- };
504
- const select = (node) => {
505
- if (node.disabled) return;
506
- closeHorizontalMenus();
507
- emit("select", node.key, node);
508
- };
509
- const toggleFlyout = (key) => {
510
- cancelAllTimers();
511
- const current = clickedBranches.value;
512
- if (current.includes(key)) {
513
- clickedBranches.value = current.filter((k) => k !== key);
514
- setBranchInteraction(hoveredBranches, key, false);
515
- setBranchInteraction(focusedBranches, key, false);
516
- } else {
517
- isolateAtDepth(key);
518
- clickedBranches.value = [...clickedBranches.value, key];
519
- }
520
- };
521
- const openFlyout = (key) => {
522
- cancelAllTimers();
523
- isolateAtDepth(key);
524
- setBranchInteraction(focusedBranches, key, true);
525
- };
526
- const setBranchInteraction = (state, key, enabled) => {
527
- const current = state.value;
528
- if (enabled) {
529
- if (!current.includes(key)) state.value = [...current, key];
530
- } else if (current.includes(key)) {
531
- state.value = current.filter((item) => item !== key);
532
- }
533
- };
534
- const keepsPointerInside = (container, event) => {
535
- if (!container || !(container instanceof HTMLElement)) return false;
536
- const next = event.relatedTarget;
537
- return !!(next && next instanceof Node && container.contains(next));
538
- };
539
- const interactionKeyAtDepth = (keys, depth) => keys.find((key) => findNavPath(props.items, key).length === depth + 1);
540
- const horizontalBranchVisible = (key, depth) => {
541
- const hoveredAtDepth = interactionKeyAtDepth(hoveredBranches.value, depth);
542
- if (hoveredAtDepth) return hoveredAtDepth === key;
543
- const clickedAtDepth = interactionKeyAtDepth(clickedBranches.value, depth);
544
- if (clickedAtDepth) return clickedAtDepth === key;
545
- return interactionKeyAtDepth(focusedBranches.value, depth) === key;
546
- };
547
- const shownFlyoutKeys = computed(() => {
548
- if (!flyoutMode.value) return [];
549
- const keys = [];
550
- for (const node of tree.value) {
551
- if (isBranch(node) && horizontalBranchVisible(node.key, 0)) keys.push(node.key);
552
- }
553
- return keys;
554
- });
555
- const repositionOpenFlyouts = () => {
556
- for (const key of shownFlyoutKeys.value) positionFlyout(key);
557
- };
558
- let viewportListenersActive = false;
559
- const attachViewportListeners = () => {
560
- if (viewportListenersActive || typeof document === "undefined") return;
561
- viewportListenersActive = true;
562
- document.addEventListener("scroll", repositionOpenFlyouts, true);
563
- window.addEventListener("resize", repositionOpenFlyouts);
564
- };
565
- const detachViewportListeners = () => {
566
- if (!viewportListenersActive || typeof document === "undefined") return;
567
- viewportListenersActive = false;
568
- document.removeEventListener("scroll", repositionOpenFlyouts, true);
569
- window.removeEventListener("resize", repositionOpenFlyouts);
570
- };
571
- watch(
572
- shownFlyoutKeys,
573
- (keys, prev) => {
574
- if (keys.length > 0 && prev.length === 0) attachViewportListeners();
575
- else if (keys.length === 0 && prev.length > 0) detachViewportListeners();
576
- for (const key of keys) positionFlyout(key);
577
- },
578
- { flush: "post" }
579
- );
740
+ const {
741
+ hovered,
742
+ hoveredBranches,
743
+ focusedBranches,
744
+ clickedBranches,
745
+ select,
746
+ toggleFlyout,
747
+ openFlyout,
748
+ closeHorizontalMenus,
749
+ setBranchInteraction,
750
+ keepsPointerInside,
751
+ horizontalBranchVisible,
752
+ setFlyoutRef,
753
+ flyoutTriggers,
754
+ flyoutPanels,
755
+ suppressFocusOpen,
756
+ cancelClose,
757
+ scheduleOpen,
758
+ scheduleClose
759
+ } = flyout;
580
760
  const itemClass = (opts) => {
581
761
  const depth = Math.min(9, opts.depth);
582
762
  return [
@@ -712,7 +892,7 @@ var IrisNavMenu = defineComponent({
712
892
  }
713
893
  },
714
894
  onFocusin: () => {
715
- if (suppressFocusOpen) return;
895
+ if (suppressFocusOpen.get()) return;
716
896
  setBranchInteraction(focusedBranches, node.key, true);
717
897
  },
718
898
  onFocusout: (event) => {
@@ -765,104 +945,23 @@ var IrisNavMenu = defineComponent({
765
945
  },
766
946
  { flush: "post" }
767
947
  );
768
- const onKeydown = (e) => {
769
- const root = e.currentTarget;
770
- const buttons = Array.from(root.querySelectorAll("[data-iris-nav-item]")).filter(
771
- (button) => !button.closest('[data-iris-nav-children][aria-hidden="true"]')
772
- );
773
- if (buttons.length === 0) return;
774
- const idx = buttons.indexOf(document.activeElement);
775
- const focusAt = (i) => buttons[(i + buttons.length) % buttons.length]?.focus();
776
- const key = idx >= 0 ? buttons[idx]?.getAttribute("data-key") : void 0;
777
- const node = key ? findNavNode(props.items, key) : void 0;
778
- const depth = idx >= 0 ? Number(buttons[idx]?.getAttribute("data-depth") ?? 0) : 0;
779
- switch (e.key) {
780
- case "ArrowDown": {
781
- e.preventDefault();
782
- if (flyoutMode.value && node && isBranch(node)) {
783
- openFlyout(key);
784
- const group = buttons[idx].closest("[data-iris-nav-group]");
785
- void nextTick(() => {
786
- group?.querySelector("[data-iris-nav-children] [data-iris-nav-item]")?.focus();
787
- });
788
- return;
789
- }
790
- focusAt(idx < 0 ? 0 : idx + 1);
791
- return;
792
- }
793
- case "ArrowUp": {
794
- e.preventDefault();
795
- if (flyoutMode.value && node && isBranch(node) && horizontalBranchVisible(key, depth)) {
796
- setBranchInteraction(focusedBranches, key, false);
797
- setBranchInteraction(clickedBranches, key, false);
798
- return;
799
- }
800
- focusAt(idx < 0 ? buttons.length - 1 : idx - 1);
801
- return;
802
- }
803
- case "Home":
804
- e.preventDefault();
805
- buttons[0]?.focus();
806
- return;
807
- case "End":
808
- e.preventDefault();
809
- buttons[buttons.length - 1]?.focus();
810
- return;
811
- case "Escape": {
812
- if (flyoutMode.value) {
813
- const openKeys = [
814
- ...hoveredBranches.value,
815
- ...clickedBranches.value,
816
- ...focusedBranches.value
817
- ];
818
- if (openKeys.length > 0) {
819
- e.preventDefault();
820
- const openTop = openKeys.find((k) => findNavPath(props.items, k).length === 1);
821
- closeHorizontalMenus();
822
- if (openTop) {
823
- suppressFocusOpen = true;
824
- buttons.find((b) => b.getAttribute("data-key") === openTop)?.focus();
825
- void nextTick(() => {
826
- suppressFocusOpen = false;
827
- });
828
- }
829
- }
830
- }
831
- return;
832
- }
833
- }
834
- if (props.collapsed || idx < 0 || !key || !node) return;
835
- if (e.key === "ArrowRight") {
836
- e.preventDefault();
837
- if (isBranch(node)) {
838
- if (flyoutMode.value || !expanded.value.includes(key)) {
839
- if (flyoutMode.value) openFlyout(key);
840
- else toggle(key);
841
- const group = buttons[idx].closest("[data-iris-nav-group]");
842
- void nextTick(() => {
843
- group?.querySelector("[data-iris-nav-children] [data-iris-nav-item]")?.focus();
844
- });
845
- } else {
846
- focusAt(idx + 1);
847
- }
848
- }
849
- } else if (e.key === "ArrowLeft") {
850
- e.preventDefault();
851
- if (flyoutMode.value && isBranch(node)) {
852
- setBranchInteraction(focusedBranches, key, false);
853
- setBranchInteraction(clickedBranches, key, false);
854
- return;
855
- }
856
- if (isBranch(node) && expanded.value.includes(key)) {
857
- toggle(key);
858
- } else {
859
- const parentKey = findNavPath(props.items, key).at(-2)?.key;
860
- if (parentKey) {
861
- buttons.find((b) => b.getAttribute("data-key") === parentKey)?.focus();
862
- }
863
- }
864
- }
865
- };
948
+ const onKeydown = createNavMenuKeydownHandler({
949
+ items: props.items,
950
+ flyoutMode: () => flyoutMode.value,
951
+ expanded: () => expanded.value,
952
+ toggle,
953
+ openFlyout,
954
+ closeHorizontalMenus,
955
+ horizontalBranchVisible,
956
+ setBranchInteraction,
957
+ focusedBranches,
958
+ hoveredBranches,
959
+ clickedBranches,
960
+ setSuppressFocusOpen: (v) => {
961
+ flyout.setSuppressFocusOpen(v);
962
+ },
963
+ collapsed: props.collapsed
964
+ });
866
965
  const menuClass = [
867
966
  "iris-nav-menu",
868
967
  `iris-nav-menu--${props.orientation}`,
@@ -2033,5 +2132,5 @@ function useAdminPreferences(preferences, hydrate = true) {
2033
2132
  }
2034
2133
 
2035
2134
  export { DropdownContextKey, IrisAdminBreadcrumb, IrisAdminLayout, IrisAdminTabs, IrisBreadcrumb, IrisBreadcrumbItem, IrisDropdown, IrisDropdownItem, IrisDropdownMenu, IrisDropdownSeparator, IrisDropdownTrigger, IrisIcon, IrisNavMenu, useAdminPreferences, useAdminShell, useTabsNav };
2036
- //# sourceMappingURL=chunk-ZWFSGMOB.js.map
2037
- //# sourceMappingURL=chunk-ZWFSGMOB.js.map
2135
+ //# sourceMappingURL=chunk-AMNHDYFY.js.map
2136
+ //# sourceMappingURL=chunk-AMNHDYFY.js.map