@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.
- package/dist/admin.cjs +363 -264
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.d.cts +1 -0
- package/dist/admin.d.ts +1 -0
- package/dist/admin.js +1 -1
- package/dist/{chunk-ZWFSGMOB.js → chunk-AMNHDYFY.js} +367 -268
- package/dist/chunk-AMNHDYFY.js.map +1 -0
- package/dist/index.cjs +367 -268
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/dist/chunk-ZWFSGMOB.js.map +0 -1
package/dist/admin.cjs
CHANGED
|
@@ -355,6 +355,7 @@ var CSS = `
|
|
|
355
355
|
--iris-nav-item-padding-block: 8px;
|
|
356
356
|
--iris-nav-item-border-radius: var(--iris-radius-md, 6px);
|
|
357
357
|
--iris-nav-item-hover: var(--iris-surface-hover, var(--iris-surface));
|
|
358
|
+
--iris-nav-item-active-hover: color-mix(in srgb, var(--iris-primary) 88%, black);
|
|
358
359
|
--iris-nav-item-height: 34px;
|
|
359
360
|
display: flex;
|
|
360
361
|
flex-direction: column;
|
|
@@ -460,6 +461,13 @@ var CSS = `
|
|
|
460
461
|
font-weight: 600;
|
|
461
462
|
}
|
|
462
463
|
|
|
464
|
+
/* active \u9879\u7684 hover \u53CD\u9988\uFF1Aprimary \u52A0\u6DF1\u53D8\u4F53\uFF08\u76AE\u80A4\u53EF\u7528
|
|
465
|
+
--iris-nav-item-active-hover \u8986\u76D6\uFF09\uFF1B\u7279\u5F02\u5EA6\u9AD8\u4E8E :hover/:where \u89C4\u5219 */
|
|
466
|
+
.iris-nav-menu-item[data-active='true']:hover,
|
|
467
|
+
.iris-nav-menu-item[data-active='true'].is-hovered:not([disabled], .is-disabled) {
|
|
468
|
+
background: var(--iris-nav-item-active-hover, color-mix(in srgb, var(--iris-primary) 88%, black));
|
|
469
|
+
}
|
|
470
|
+
|
|
463
471
|
:where(.iris-nav-menu-item[data-active-trail='true']) {
|
|
464
472
|
color: var(--iris-primary);
|
|
465
473
|
font-weight: 600;
|
|
@@ -626,10 +634,317 @@ function installNavMenuStyles() {
|
|
|
626
634
|
document.head.appendChild(style);
|
|
627
635
|
installed = true;
|
|
628
636
|
}
|
|
637
|
+
var HOVER_OPEN_DELAY_VAL = 60;
|
|
638
|
+
var HOVER_CLOSE_DELAY_VAL = 150;
|
|
639
|
+
function createNavMenuFlyout(ctx) {
|
|
640
|
+
const hovered = vue.ref(null);
|
|
641
|
+
const hoveredBranches = vue.ref([]);
|
|
642
|
+
const focusedBranches = vue.ref([]);
|
|
643
|
+
const clickedBranches = vue.ref([]);
|
|
644
|
+
let suppressFocusOpen = false;
|
|
645
|
+
let openTimer = null;
|
|
646
|
+
const closeTimers = /* @__PURE__ */ new Map();
|
|
647
|
+
const clearOpenTimer = () => {
|
|
648
|
+
if (openTimer) {
|
|
649
|
+
clearTimeout(openTimer);
|
|
650
|
+
openTimer = null;
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
const cancelClose = (key) => {
|
|
654
|
+
const timer = closeTimers.get(key);
|
|
655
|
+
if (timer) {
|
|
656
|
+
clearTimeout(timer);
|
|
657
|
+
closeTimers.delete(key);
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
const cancelAllTimers = () => {
|
|
661
|
+
clearOpenTimer();
|
|
662
|
+
for (const timer of closeTimers.values()) clearTimeout(timer);
|
|
663
|
+
closeTimers.clear();
|
|
664
|
+
};
|
|
665
|
+
vue.onBeforeUnmount(cancelAllTimers);
|
|
666
|
+
const flyoutTriggers = /* @__PURE__ */ new Map();
|
|
667
|
+
const flyoutPanels = /* @__PURE__ */ new Map();
|
|
668
|
+
const setFlyoutRef = (map, key, el) => {
|
|
669
|
+
if (el instanceof HTMLElement) map.set(key, el);
|
|
670
|
+
else map.delete(key);
|
|
671
|
+
};
|
|
672
|
+
const positionFlyout = (key) => {
|
|
673
|
+
const trigger = flyoutTriggers.get(key);
|
|
674
|
+
const panel = flyoutPanels.get(key);
|
|
675
|
+
if (!trigger || !panel || typeof document === "undefined") return;
|
|
676
|
+
const rect = trigger.getBoundingClientRect();
|
|
677
|
+
const dir = getComputedStyle(trigger).direction;
|
|
678
|
+
panel.style.position = "fixed";
|
|
679
|
+
panel.style.top = `${ctx.collapsed ? rect.top : rect.bottom}px`;
|
|
680
|
+
if (dir === "rtl") {
|
|
681
|
+
panel.style.left = "";
|
|
682
|
+
panel.style.right = `${window.innerWidth - (ctx.collapsed ? rect.left : rect.right)}px`;
|
|
683
|
+
} else {
|
|
684
|
+
panel.style.right = "";
|
|
685
|
+
panel.style.left = `${ctx.collapsed ? rect.right : rect.left}px`;
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
vue.onBeforeUnmount(() => {
|
|
689
|
+
detachViewportListeners();
|
|
690
|
+
flyoutTriggers.clear();
|
|
691
|
+
flyoutPanels.clear();
|
|
692
|
+
});
|
|
693
|
+
const isolateAtDepth = (key) => {
|
|
694
|
+
const depth = core.findNavPath(ctx.items, key).length - 1;
|
|
695
|
+
const isSameDepthOther = (k) => k !== key && core.findNavPath(ctx.items, k).length - 1 === depth;
|
|
696
|
+
for (const state of [hoveredBranches, clickedBranches, focusedBranches]) {
|
|
697
|
+
if (state.value.some(isSameDepthOther)) {
|
|
698
|
+
state.value = state.value.filter((k) => !isSameDepthOther(k));
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
const scheduleOpen = (key) => {
|
|
703
|
+
clearOpenTimer();
|
|
704
|
+
openTimer = setTimeout(() => {
|
|
705
|
+
openTimer = null;
|
|
706
|
+
isolateAtDepth(key);
|
|
707
|
+
setBranchInteraction(hoveredBranches, key, true);
|
|
708
|
+
}, HOVER_OPEN_DELAY_VAL);
|
|
709
|
+
};
|
|
710
|
+
const scheduleClose = (key) => {
|
|
711
|
+
cancelClose(key);
|
|
712
|
+
closeTimers.set(
|
|
713
|
+
key,
|
|
714
|
+
setTimeout(() => {
|
|
715
|
+
closeTimers.delete(key);
|
|
716
|
+
setBranchInteraction(hoveredBranches, key, false);
|
|
717
|
+
}, HOVER_CLOSE_DELAY_VAL)
|
|
718
|
+
);
|
|
719
|
+
};
|
|
720
|
+
const closeHorizontalMenus = () => {
|
|
721
|
+
if (!ctx.flyoutMode.value) return;
|
|
722
|
+
cancelAllTimers();
|
|
723
|
+
hovered.value = null;
|
|
724
|
+
hoveredBranches.value = [];
|
|
725
|
+
focusedBranches.value = [];
|
|
726
|
+
clickedBranches.value = [];
|
|
727
|
+
};
|
|
728
|
+
const select = (node) => {
|
|
729
|
+
if (node.disabled) return;
|
|
730
|
+
closeHorizontalMenus();
|
|
731
|
+
ctx.emitSelect(node.key, node);
|
|
732
|
+
};
|
|
733
|
+
const toggleFlyout = (key) => {
|
|
734
|
+
cancelAllTimers();
|
|
735
|
+
const current = clickedBranches.value;
|
|
736
|
+
if (current.includes(key)) {
|
|
737
|
+
clickedBranches.value = current.filter((k) => k !== key);
|
|
738
|
+
setBranchInteraction(hoveredBranches, key, false);
|
|
739
|
+
setBranchInteraction(focusedBranches, key, false);
|
|
740
|
+
} else {
|
|
741
|
+
isolateAtDepth(key);
|
|
742
|
+
clickedBranches.value = [...clickedBranches.value, key];
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
const openFlyout = (key) => {
|
|
746
|
+
cancelAllTimers();
|
|
747
|
+
isolateAtDepth(key);
|
|
748
|
+
setBranchInteraction(focusedBranches, key, true);
|
|
749
|
+
};
|
|
750
|
+
const setBranchInteraction = (state, key, enabled) => {
|
|
751
|
+
const current = state.value;
|
|
752
|
+
if (enabled) {
|
|
753
|
+
if (!current.includes(key)) state.value = [...current, key];
|
|
754
|
+
} else if (current.includes(key)) {
|
|
755
|
+
state.value = current.filter((item) => item !== key);
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
const keepsPointerInside = (container, event) => {
|
|
759
|
+
if (!container || !(container instanceof HTMLElement)) return false;
|
|
760
|
+
const next = event.relatedTarget;
|
|
761
|
+
return !!(next && next instanceof Node && container.contains(next));
|
|
762
|
+
};
|
|
763
|
+
const interactionKeyAtDepth = (keys, depth) => keys.find((key) => core.findNavPath(ctx.items, key).length === depth + 1);
|
|
764
|
+
const horizontalBranchVisible = (key, depth) => {
|
|
765
|
+
const hoveredAtDepth = interactionKeyAtDepth(hoveredBranches.value, depth);
|
|
766
|
+
if (hoveredAtDepth) return hoveredAtDepth === key;
|
|
767
|
+
const clickedAtDepth = interactionKeyAtDepth(clickedBranches.value, depth);
|
|
768
|
+
if (clickedAtDepth) return clickedAtDepth === key;
|
|
769
|
+
return interactionKeyAtDepth(focusedBranches.value, depth) === key;
|
|
770
|
+
};
|
|
771
|
+
const shownFlyoutKeys = vue.computed(() => {
|
|
772
|
+
if (!ctx.flyoutMode.value) return [];
|
|
773
|
+
const keys = [];
|
|
774
|
+
for (const node of ctx.tree.value) {
|
|
775
|
+
if (core.isBranch(node) && horizontalBranchVisible(node.key, 0)) keys.push(node.key);
|
|
776
|
+
}
|
|
777
|
+
return keys;
|
|
778
|
+
});
|
|
779
|
+
const repositionOpenFlyouts = () => {
|
|
780
|
+
for (const key of shownFlyoutKeys.value) positionFlyout(key);
|
|
781
|
+
};
|
|
782
|
+
let viewportListenersActive = false;
|
|
783
|
+
const attachViewportListeners = () => {
|
|
784
|
+
if (viewportListenersActive || typeof document === "undefined") return;
|
|
785
|
+
viewportListenersActive = true;
|
|
786
|
+
document.addEventListener("scroll", repositionOpenFlyouts, true);
|
|
787
|
+
window.addEventListener("resize", repositionOpenFlyouts);
|
|
788
|
+
};
|
|
789
|
+
const detachViewportListeners = () => {
|
|
790
|
+
if (!viewportListenersActive || typeof document === "undefined") return;
|
|
791
|
+
viewportListenersActive = false;
|
|
792
|
+
document.removeEventListener("scroll", repositionOpenFlyouts, true);
|
|
793
|
+
window.removeEventListener("resize", repositionOpenFlyouts);
|
|
794
|
+
};
|
|
795
|
+
vue.watch(
|
|
796
|
+
shownFlyoutKeys,
|
|
797
|
+
(keys, prev) => {
|
|
798
|
+
if (keys.length > 0 && prev.length === 0) attachViewportListeners();
|
|
799
|
+
else if (keys.length === 0 && prev.length > 0) detachViewportListeners();
|
|
800
|
+
for (const key of keys) positionFlyout(key);
|
|
801
|
+
},
|
|
802
|
+
{ flush: "post" }
|
|
803
|
+
);
|
|
804
|
+
return {
|
|
805
|
+
hovered,
|
|
806
|
+
hoveredBranches,
|
|
807
|
+
focusedBranches,
|
|
808
|
+
clickedBranches,
|
|
809
|
+
select,
|
|
810
|
+
toggleFlyout,
|
|
811
|
+
openFlyout,
|
|
812
|
+
closeHorizontalMenus,
|
|
813
|
+
setBranchInteraction,
|
|
814
|
+
keepsPointerInside,
|
|
815
|
+
interactionKeyAtDepth,
|
|
816
|
+
horizontalBranchVisible,
|
|
817
|
+
shownFlyoutKeys,
|
|
818
|
+
setFlyoutRef,
|
|
819
|
+
flyoutTriggers,
|
|
820
|
+
flyoutPanels,
|
|
821
|
+
suppressFocusOpen: { get: () => suppressFocusOpen },
|
|
822
|
+
setSuppressFocusOpen: (value) => {
|
|
823
|
+
suppressFocusOpen = value;
|
|
824
|
+
},
|
|
825
|
+
cancelClose,
|
|
826
|
+
scheduleOpen,
|
|
827
|
+
scheduleClose,
|
|
828
|
+
cancelAllTimers
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
function createNavMenuKeydownHandler(deps) {
|
|
832
|
+
const {
|
|
833
|
+
items,
|
|
834
|
+
flyoutMode,
|
|
835
|
+
expanded,
|
|
836
|
+
toggle,
|
|
837
|
+
openFlyout,
|
|
838
|
+
closeHorizontalMenus,
|
|
839
|
+
horizontalBranchVisible,
|
|
840
|
+
setBranchInteraction,
|
|
841
|
+
focusedBranches,
|
|
842
|
+
collapsed,
|
|
843
|
+
hoveredBranches,
|
|
844
|
+
clickedBranches,
|
|
845
|
+
setSuppressFocusOpen
|
|
846
|
+
} = deps;
|
|
847
|
+
return (e) => {
|
|
848
|
+
const root = e.currentTarget;
|
|
849
|
+
const buttons = Array.from(root.querySelectorAll("[data-iris-nav-item]")).filter(
|
|
850
|
+
(button) => !button.closest('[data-iris-nav-children][aria-hidden="true"]')
|
|
851
|
+
);
|
|
852
|
+
if (buttons.length === 0) return;
|
|
853
|
+
const idx = buttons.indexOf(document.activeElement);
|
|
854
|
+
const focusAt = (i) => buttons[(i + buttons.length) % buttons.length]?.focus();
|
|
855
|
+
const key = idx >= 0 ? buttons[idx]?.getAttribute("data-key") : void 0;
|
|
856
|
+
const node = key ? core.findNavNode(items, key) : void 0;
|
|
857
|
+
const depth = idx >= 0 ? Number(buttons[idx]?.getAttribute("data-depth") ?? 0) : 0;
|
|
858
|
+
switch (e.key) {
|
|
859
|
+
case "ArrowDown": {
|
|
860
|
+
e.preventDefault();
|
|
861
|
+
if (flyoutMode() && node && core.isBranch(node)) {
|
|
862
|
+
openFlyout(key);
|
|
863
|
+
const group = buttons[idx].closest("[data-iris-nav-group]");
|
|
864
|
+
void vue.nextTick(() => {
|
|
865
|
+
group?.querySelector("[data-iris-nav-children] [data-iris-nav-item]")?.focus();
|
|
866
|
+
});
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
focusAt(idx < 0 ? 0 : idx + 1);
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
case "ArrowUp": {
|
|
873
|
+
e.preventDefault();
|
|
874
|
+
if (flyoutMode() && node && core.isBranch(node) && horizontalBranchVisible(key, depth)) {
|
|
875
|
+
setBranchInteraction(focusedBranches, key, false);
|
|
876
|
+
setBranchInteraction(clickedBranches, key, false);
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
focusAt(idx < 0 ? buttons.length - 1 : idx - 1);
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
case "Home":
|
|
883
|
+
e.preventDefault();
|
|
884
|
+
buttons[0]?.focus();
|
|
885
|
+
return;
|
|
886
|
+
case "End":
|
|
887
|
+
e.preventDefault();
|
|
888
|
+
buttons[buttons.length - 1]?.focus();
|
|
889
|
+
return;
|
|
890
|
+
case "Escape": {
|
|
891
|
+
if (flyoutMode()) {
|
|
892
|
+
const openKeys = [
|
|
893
|
+
...hoveredBranches.value,
|
|
894
|
+
...clickedBranches.value,
|
|
895
|
+
...focusedBranches.value
|
|
896
|
+
];
|
|
897
|
+
if (openKeys.length > 0) {
|
|
898
|
+
e.preventDefault();
|
|
899
|
+
const openTop = openKeys.find((k) => core.findNavPath(items, k).length === 1);
|
|
900
|
+
closeHorizontalMenus();
|
|
901
|
+
if (openTop) {
|
|
902
|
+
setSuppressFocusOpen(true);
|
|
903
|
+
buttons.find((b) => b.getAttribute("data-key") === openTop)?.focus();
|
|
904
|
+
void vue.nextTick(() => {
|
|
905
|
+
setSuppressFocusOpen(false);
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
if (collapsed || idx < 0 || !key || !node) return;
|
|
914
|
+
if (e.key === "ArrowRight") {
|
|
915
|
+
e.preventDefault();
|
|
916
|
+
if (core.isBranch(node)) {
|
|
917
|
+
if (flyoutMode() || !expanded().includes(key)) {
|
|
918
|
+
if (flyoutMode()) openFlyout(key);
|
|
919
|
+
else toggle(key);
|
|
920
|
+
const group = buttons[idx].closest("[data-iris-nav-group]");
|
|
921
|
+
void vue.nextTick(() => {
|
|
922
|
+
group?.querySelector("[data-iris-nav-children] [data-iris-nav-item]")?.focus();
|
|
923
|
+
});
|
|
924
|
+
} else {
|
|
925
|
+
focusAt(idx + 1);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
} else if (e.key === "ArrowLeft") {
|
|
929
|
+
e.preventDefault();
|
|
930
|
+
if (flyoutMode() && core.isBranch(node)) {
|
|
931
|
+
setBranchInteraction(focusedBranches, key, false);
|
|
932
|
+
setBranchInteraction(clickedBranches, key, false);
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
if (core.isBranch(node) && expanded().includes(key)) {
|
|
936
|
+
toggle(key);
|
|
937
|
+
} else {
|
|
938
|
+
const parentKey = core.findNavPath(items, key).at(-2)?.key;
|
|
939
|
+
if (parentKey) {
|
|
940
|
+
buttons.find((b) => b.getAttribute("data-key") === parentKey)?.focus();
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
}
|
|
629
946
|
|
|
630
947
|
// src/admin/NavMenu.ts
|
|
631
|
-
var HOVER_OPEN_DELAY = 100;
|
|
632
|
-
var HOVER_CLOSE_DELAY = 150;
|
|
633
948
|
var IrisNavMenu = vue.defineComponent({
|
|
634
949
|
name: "IrisNavMenu",
|
|
635
950
|
inheritAttrs: false,
|
|
@@ -691,170 +1006,35 @@ var IrisNavMenu = vue.defineComponent({
|
|
|
691
1006
|
emit("update:expandedKeys", model.get());
|
|
692
1007
|
}
|
|
693
1008
|
};
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
if (openTimer) {
|
|
703
|
-
clearTimeout(openTimer);
|
|
704
|
-
openTimer = null;
|
|
705
|
-
}
|
|
706
|
-
};
|
|
707
|
-
const cancelClose = (key) => {
|
|
708
|
-
const timer = closeTimers.get(key);
|
|
709
|
-
if (timer) {
|
|
710
|
-
clearTimeout(timer);
|
|
711
|
-
closeTimers.delete(key);
|
|
712
|
-
}
|
|
713
|
-
};
|
|
714
|
-
const cancelAllTimers = () => {
|
|
715
|
-
clearOpenTimer();
|
|
716
|
-
for (const timer of closeTimers.values()) clearTimeout(timer);
|
|
717
|
-
closeTimers.clear();
|
|
718
|
-
};
|
|
719
|
-
vue.onBeforeUnmount(cancelAllTimers);
|
|
720
|
-
const flyoutTriggers = /* @__PURE__ */ new Map();
|
|
721
|
-
const flyoutPanels = /* @__PURE__ */ new Map();
|
|
722
|
-
const setFlyoutRef = (map, key, el) => {
|
|
723
|
-
if (el instanceof HTMLElement) map.set(key, el);
|
|
724
|
-
else map.delete(key);
|
|
725
|
-
};
|
|
726
|
-
const positionFlyout = (key) => {
|
|
727
|
-
const trigger = flyoutTriggers.get(key);
|
|
728
|
-
const panel = flyoutPanels.get(key);
|
|
729
|
-
if (!trigger || !panel || typeof document === "undefined") return;
|
|
730
|
-
const rect = trigger.getBoundingClientRect();
|
|
731
|
-
const dir = getComputedStyle(trigger).direction;
|
|
732
|
-
panel.style.position = "fixed";
|
|
733
|
-
panel.style.top = `${props.collapsed ? rect.top : rect.bottom}px`;
|
|
734
|
-
if (dir === "rtl") {
|
|
735
|
-
panel.style.left = "";
|
|
736
|
-
panel.style.right = `${window.innerWidth - (props.collapsed ? rect.left : rect.right)}px`;
|
|
737
|
-
} else {
|
|
738
|
-
panel.style.right = "";
|
|
739
|
-
panel.style.left = `${props.collapsed ? rect.right : rect.left}px`;
|
|
740
|
-
}
|
|
741
|
-
};
|
|
742
|
-
vue.onBeforeUnmount(() => {
|
|
743
|
-
detachViewportListeners();
|
|
744
|
-
flyoutTriggers.clear();
|
|
745
|
-
flyoutPanels.clear();
|
|
746
|
-
});
|
|
747
|
-
const isolateAtDepth = (key) => {
|
|
748
|
-
const depth = core.findNavPath(props.items, key).length - 1;
|
|
749
|
-
const isSameDepthOther = (k) => k !== key && core.findNavPath(props.items, k).length - 1 === depth;
|
|
750
|
-
for (const state of [hoveredBranches, clickedBranches, focusedBranches]) {
|
|
751
|
-
if (state.value.some(isSameDepthOther)) {
|
|
752
|
-
state.value = state.value.filter((k) => !isSameDepthOther(k));
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
};
|
|
756
|
-
const scheduleOpen = (key) => {
|
|
757
|
-
clearOpenTimer();
|
|
758
|
-
openTimer = setTimeout(() => {
|
|
759
|
-
openTimer = null;
|
|
760
|
-
isolateAtDepth(key);
|
|
761
|
-
setBranchInteraction(hoveredBranches, key, true);
|
|
762
|
-
}, HOVER_OPEN_DELAY);
|
|
763
|
-
};
|
|
764
|
-
const scheduleClose = (key) => {
|
|
765
|
-
cancelClose(key);
|
|
766
|
-
closeTimers.set(
|
|
767
|
-
key,
|
|
768
|
-
setTimeout(() => {
|
|
769
|
-
closeTimers.delete(key);
|
|
770
|
-
setBranchInteraction(hoveredBranches, key, false);
|
|
771
|
-
}, HOVER_CLOSE_DELAY)
|
|
772
|
-
);
|
|
773
|
-
};
|
|
774
|
-
const closeHorizontalMenus = () => {
|
|
775
|
-
if (!flyoutMode.value) return;
|
|
776
|
-
cancelAllTimers();
|
|
777
|
-
hovered.value = null;
|
|
778
|
-
hoveredBranches.value = [];
|
|
779
|
-
focusedBranches.value = [];
|
|
780
|
-
clickedBranches.value = [];
|
|
781
|
-
};
|
|
782
|
-
const select = (node) => {
|
|
783
|
-
if (node.disabled) return;
|
|
784
|
-
closeHorizontalMenus();
|
|
785
|
-
emit("select", node.key, node);
|
|
786
|
-
};
|
|
787
|
-
const toggleFlyout = (key) => {
|
|
788
|
-
cancelAllTimers();
|
|
789
|
-
const current = clickedBranches.value;
|
|
790
|
-
if (current.includes(key)) {
|
|
791
|
-
clickedBranches.value = current.filter((k) => k !== key);
|
|
792
|
-
setBranchInteraction(hoveredBranches, key, false);
|
|
793
|
-
setBranchInteraction(focusedBranches, key, false);
|
|
794
|
-
} else {
|
|
795
|
-
isolateAtDepth(key);
|
|
796
|
-
clickedBranches.value = [...clickedBranches.value, key];
|
|
797
|
-
}
|
|
798
|
-
};
|
|
799
|
-
const openFlyout = (key) => {
|
|
800
|
-
cancelAllTimers();
|
|
801
|
-
isolateAtDepth(key);
|
|
802
|
-
setBranchInteraction(focusedBranches, key, true);
|
|
803
|
-
};
|
|
804
|
-
const setBranchInteraction = (state, key, enabled) => {
|
|
805
|
-
const current = state.value;
|
|
806
|
-
if (enabled) {
|
|
807
|
-
if (!current.includes(key)) state.value = [...current, key];
|
|
808
|
-
} else if (current.includes(key)) {
|
|
809
|
-
state.value = current.filter((item) => item !== key);
|
|
810
|
-
}
|
|
811
|
-
};
|
|
812
|
-
const keepsPointerInside = (container, event) => {
|
|
813
|
-
if (!container || !(container instanceof HTMLElement)) return false;
|
|
814
|
-
const next = event.relatedTarget;
|
|
815
|
-
return !!(next && next instanceof Node && container.contains(next));
|
|
816
|
-
};
|
|
817
|
-
const interactionKeyAtDepth = (keys, depth) => keys.find((key) => core.findNavPath(props.items, key).length === depth + 1);
|
|
818
|
-
const horizontalBranchVisible = (key, depth) => {
|
|
819
|
-
const hoveredAtDepth = interactionKeyAtDepth(hoveredBranches.value, depth);
|
|
820
|
-
if (hoveredAtDepth) return hoveredAtDepth === key;
|
|
821
|
-
const clickedAtDepth = interactionKeyAtDepth(clickedBranches.value, depth);
|
|
822
|
-
if (clickedAtDepth) return clickedAtDepth === key;
|
|
823
|
-
return interactionKeyAtDepth(focusedBranches.value, depth) === key;
|
|
824
|
-
};
|
|
825
|
-
const shownFlyoutKeys = vue.computed(() => {
|
|
826
|
-
if (!flyoutMode.value) return [];
|
|
827
|
-
const keys = [];
|
|
828
|
-
for (const node of tree.value) {
|
|
829
|
-
if (core.isBranch(node) && horizontalBranchVisible(node.key, 0)) keys.push(node.key);
|
|
830
|
-
}
|
|
831
|
-
return keys;
|
|
1009
|
+
const flyout = createNavMenuFlyout({
|
|
1010
|
+
items: props.items,
|
|
1011
|
+
tree,
|
|
1012
|
+
expanded,
|
|
1013
|
+
flyoutMode: { value: flyoutMode.value },
|
|
1014
|
+
collapsed: props.collapsed,
|
|
1015
|
+
toggle,
|
|
1016
|
+
emitSelect: (key, node) => emit("select", key, node)
|
|
832
1017
|
});
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
else if (keys.length === 0 && prev.length > 0) detachViewportListeners();
|
|
854
|
-
for (const key of keys) positionFlyout(key);
|
|
855
|
-
},
|
|
856
|
-
{ flush: "post" }
|
|
857
|
-
);
|
|
1018
|
+
const {
|
|
1019
|
+
hovered,
|
|
1020
|
+
hoveredBranches,
|
|
1021
|
+
focusedBranches,
|
|
1022
|
+
clickedBranches,
|
|
1023
|
+
select,
|
|
1024
|
+
toggleFlyout,
|
|
1025
|
+
openFlyout,
|
|
1026
|
+
closeHorizontalMenus,
|
|
1027
|
+
setBranchInteraction,
|
|
1028
|
+
keepsPointerInside,
|
|
1029
|
+
horizontalBranchVisible,
|
|
1030
|
+
setFlyoutRef,
|
|
1031
|
+
flyoutTriggers,
|
|
1032
|
+
flyoutPanels,
|
|
1033
|
+
suppressFocusOpen,
|
|
1034
|
+
cancelClose,
|
|
1035
|
+
scheduleOpen,
|
|
1036
|
+
scheduleClose
|
|
1037
|
+
} = flyout;
|
|
858
1038
|
const itemClass = (opts) => {
|
|
859
1039
|
const depth = Math.min(9, opts.depth);
|
|
860
1040
|
return [
|
|
@@ -990,7 +1170,7 @@ var IrisNavMenu = vue.defineComponent({
|
|
|
990
1170
|
}
|
|
991
1171
|
},
|
|
992
1172
|
onFocusin: () => {
|
|
993
|
-
if (suppressFocusOpen) return;
|
|
1173
|
+
if (suppressFocusOpen.get()) return;
|
|
994
1174
|
setBranchInteraction(focusedBranches, node.key, true);
|
|
995
1175
|
},
|
|
996
1176
|
onFocusout: (event) => {
|
|
@@ -1043,104 +1223,23 @@ var IrisNavMenu = vue.defineComponent({
|
|
|
1043
1223
|
},
|
|
1044
1224
|
{ flush: "post" }
|
|
1045
1225
|
);
|
|
1046
|
-
const onKeydown = (
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
void vue.nextTick(() => {
|
|
1064
|
-
group?.querySelector("[data-iris-nav-children] [data-iris-nav-item]")?.focus();
|
|
1065
|
-
});
|
|
1066
|
-
return;
|
|
1067
|
-
}
|
|
1068
|
-
focusAt(idx < 0 ? 0 : idx + 1);
|
|
1069
|
-
return;
|
|
1070
|
-
}
|
|
1071
|
-
case "ArrowUp": {
|
|
1072
|
-
e.preventDefault();
|
|
1073
|
-
if (flyoutMode.value && node && core.isBranch(node) && horizontalBranchVisible(key, depth)) {
|
|
1074
|
-
setBranchInteraction(focusedBranches, key, false);
|
|
1075
|
-
setBranchInteraction(clickedBranches, key, false);
|
|
1076
|
-
return;
|
|
1077
|
-
}
|
|
1078
|
-
focusAt(idx < 0 ? buttons.length - 1 : idx - 1);
|
|
1079
|
-
return;
|
|
1080
|
-
}
|
|
1081
|
-
case "Home":
|
|
1082
|
-
e.preventDefault();
|
|
1083
|
-
buttons[0]?.focus();
|
|
1084
|
-
return;
|
|
1085
|
-
case "End":
|
|
1086
|
-
e.preventDefault();
|
|
1087
|
-
buttons[buttons.length - 1]?.focus();
|
|
1088
|
-
return;
|
|
1089
|
-
case "Escape": {
|
|
1090
|
-
if (flyoutMode.value) {
|
|
1091
|
-
const openKeys = [
|
|
1092
|
-
...hoveredBranches.value,
|
|
1093
|
-
...clickedBranches.value,
|
|
1094
|
-
...focusedBranches.value
|
|
1095
|
-
];
|
|
1096
|
-
if (openKeys.length > 0) {
|
|
1097
|
-
e.preventDefault();
|
|
1098
|
-
const openTop = openKeys.find((k) => core.findNavPath(props.items, k).length === 1);
|
|
1099
|
-
closeHorizontalMenus();
|
|
1100
|
-
if (openTop) {
|
|
1101
|
-
suppressFocusOpen = true;
|
|
1102
|
-
buttons.find((b) => b.getAttribute("data-key") === openTop)?.focus();
|
|
1103
|
-
void vue.nextTick(() => {
|
|
1104
|
-
suppressFocusOpen = false;
|
|
1105
|
-
});
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
return;
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
if (props.collapsed || idx < 0 || !key || !node) return;
|
|
1113
|
-
if (e.key === "ArrowRight") {
|
|
1114
|
-
e.preventDefault();
|
|
1115
|
-
if (core.isBranch(node)) {
|
|
1116
|
-
if (flyoutMode.value || !expanded.value.includes(key)) {
|
|
1117
|
-
if (flyoutMode.value) openFlyout(key);
|
|
1118
|
-
else toggle(key);
|
|
1119
|
-
const group = buttons[idx].closest("[data-iris-nav-group]");
|
|
1120
|
-
void vue.nextTick(() => {
|
|
1121
|
-
group?.querySelector("[data-iris-nav-children] [data-iris-nav-item]")?.focus();
|
|
1122
|
-
});
|
|
1123
|
-
} else {
|
|
1124
|
-
focusAt(idx + 1);
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
} else if (e.key === "ArrowLeft") {
|
|
1128
|
-
e.preventDefault();
|
|
1129
|
-
if (flyoutMode.value && core.isBranch(node)) {
|
|
1130
|
-
setBranchInteraction(focusedBranches, key, false);
|
|
1131
|
-
setBranchInteraction(clickedBranches, key, false);
|
|
1132
|
-
return;
|
|
1133
|
-
}
|
|
1134
|
-
if (core.isBranch(node) && expanded.value.includes(key)) {
|
|
1135
|
-
toggle(key);
|
|
1136
|
-
} else {
|
|
1137
|
-
const parentKey = core.findNavPath(props.items, key).at(-2)?.key;
|
|
1138
|
-
if (parentKey) {
|
|
1139
|
-
buttons.find((b) => b.getAttribute("data-key") === parentKey)?.focus();
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
};
|
|
1226
|
+
const onKeydown = createNavMenuKeydownHandler({
|
|
1227
|
+
items: props.items,
|
|
1228
|
+
flyoutMode: () => flyoutMode.value,
|
|
1229
|
+
expanded: () => expanded.value,
|
|
1230
|
+
toggle,
|
|
1231
|
+
openFlyout,
|
|
1232
|
+
closeHorizontalMenus,
|
|
1233
|
+
horizontalBranchVisible,
|
|
1234
|
+
setBranchInteraction,
|
|
1235
|
+
focusedBranches,
|
|
1236
|
+
hoveredBranches,
|
|
1237
|
+
clickedBranches,
|
|
1238
|
+
setSuppressFocusOpen: (v) => {
|
|
1239
|
+
flyout.setSuppressFocusOpen(v);
|
|
1240
|
+
},
|
|
1241
|
+
collapsed: props.collapsed
|
|
1242
|
+
});
|
|
1144
1243
|
const menuClass = [
|
|
1145
1244
|
"iris-nav-menu",
|
|
1146
1245
|
`iris-nav-menu--${props.orientation}`,
|