@v-c/menu 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/LICENSE +21 -0
  2. package/dist/Divider.cjs +38 -0
  3. package/dist/Divider.d.ts +4 -0
  4. package/dist/Divider.js +38 -0
  5. package/dist/Icon.cjs +38 -0
  6. package/dist/Icon.d.ts +7 -0
  7. package/dist/Icon.js +38 -0
  8. package/dist/Menu.cjs +580 -0
  9. package/dist/Menu.d.ts +77 -0
  10. package/dist/Menu.js +580 -0
  11. package/dist/MenuItem.cjs +350 -0
  12. package/dist/MenuItem.d.ts +14 -0
  13. package/dist/MenuItem.js +350 -0
  14. package/dist/MenuItemGroup.cjs +120 -0
  15. package/dist/MenuItemGroup.d.ts +16 -0
  16. package/dist/MenuItemGroup.js +120 -0
  17. package/dist/SubMenu/InlineSubMenuList.cjs +84 -0
  18. package/dist/SubMenu/InlineSubMenuList.d.ts +7 -0
  19. package/dist/SubMenu/InlineSubMenuList.js +84 -0
  20. package/dist/SubMenu/PopupTrigger.cjs +168 -0
  21. package/dist/SubMenu/PopupTrigger.d.ts +16 -0
  22. package/dist/SubMenu/PopupTrigger.js +168 -0
  23. package/dist/SubMenu/SubMenuList.cjs +28 -0
  24. package/dist/SubMenu/SubMenuList.d.ts +2 -0
  25. package/dist/SubMenu/SubMenuList.js +28 -0
  26. package/dist/SubMenu/index.cjs +532 -0
  27. package/dist/SubMenu/index.d.ts +18 -0
  28. package/dist/SubMenu/index.js +532 -0
  29. package/dist/context/IdContext.cjs +33 -0
  30. package/dist/context/IdContext.d.ts +12 -0
  31. package/dist/context/IdContext.js +33 -0
  32. package/dist/context/MenuContext.cjs +184 -0
  33. package/dist/context/MenuContext.d.ts +42 -0
  34. package/dist/context/MenuContext.js +184 -0
  35. package/dist/context/PathContext.cjs +100 -0
  36. package/dist/context/PathContext.d.ts +33 -0
  37. package/dist/context/PathContext.js +100 -0
  38. package/dist/context/PrivateContext.cjs +24 -0
  39. package/dist/context/PrivateContext.d.ts +8 -0
  40. package/dist/context/PrivateContext.js +24 -0
  41. package/dist/hooks/useAccessibility.cjs +210 -0
  42. package/dist/hooks/useAccessibility.d.ts +12 -0
  43. package/dist/hooks/useAccessibility.js +210 -0
  44. package/dist/hooks/useActive.cjs +31 -0
  45. package/dist/hooks/useActive.d.ts +9 -0
  46. package/dist/hooks/useActive.js +31 -0
  47. package/dist/hooks/useDirectionStyle.cjs +20 -0
  48. package/dist/hooks/useDirectionStyle.d.ts +2 -0
  49. package/dist/hooks/useDirectionStyle.js +20 -0
  50. package/dist/hooks/useKeyRecords.cjs +93 -0
  51. package/dist/hooks/useKeyRecords.d.ts +10 -0
  52. package/dist/hooks/useKeyRecords.js +93 -0
  53. package/dist/hooks/useMemoCallback.cjs +12 -0
  54. package/dist/hooks/useMemoCallback.d.ts +4 -0
  55. package/dist/hooks/useMemoCallback.js +12 -0
  56. package/dist/index.cjs +21 -0
  57. package/dist/index.d.ts +19 -0
  58. package/dist/index.js +21 -0
  59. package/dist/interface.cjs +1 -0
  60. package/dist/interface.d.ts +94 -0
  61. package/dist/interface.js +1 -0
  62. package/dist/placements.cjs +77 -0
  63. package/dist/placements.d.ts +117 -0
  64. package/dist/placements.js +77 -0
  65. package/dist/utils/commonUtil.cjs +29 -0
  66. package/dist/utils/commonUtil.d.ts +1 -0
  67. package/dist/utils/commonUtil.js +29 -0
  68. package/dist/utils/motionUtil.cjs +12 -0
  69. package/dist/utils/motionUtil.d.ts +2 -0
  70. package/dist/utils/motionUtil.js +12 -0
  71. package/dist/utils/nodeUtil.cjs +82 -0
  72. package/dist/utils/nodeUtil.d.ts +3 -0
  73. package/dist/utils/nodeUtil.js +82 -0
  74. package/dist/utils/timeUtil.cjs +6 -0
  75. package/dist/utils/timeUtil.d.ts +1 -0
  76. package/dist/utils/timeUtil.js +6 -0
  77. package/dist/utils/warnUtil.cjs +16 -0
  78. package/dist/utils/warnUtil.d.ts +7 -0
  79. package/dist/utils/warnUtil.js +16 -0
  80. package/package.json +37 -0
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const KeyCode = require("@v-c/util/dist/KeyCode");
4
+ const vue = require("vue");
5
+ const IdContext = require("../context/IdContext.cjs");
6
+ const { LEFT, RIGHT, UP, DOWN, ENTER, ESC, HOME, END } = KeyCode;
7
+ const ArrowKeys = [UP, DOWN, LEFT, RIGHT];
8
+ function getOffset(mode, isRootLevel, isRtl, which) {
9
+ const prev = "prev";
10
+ const next = "next";
11
+ const children = "children";
12
+ const parent = "parent";
13
+ if (mode === "inline" && which === ENTER) {
14
+ return { inlineTrigger: true };
15
+ }
16
+ const inline = { [UP]: prev, [DOWN]: next };
17
+ const horizontal = {
18
+ [LEFT]: isRtl ? next : prev,
19
+ [RIGHT]: isRtl ? prev : next,
20
+ [DOWN]: children,
21
+ [ENTER]: children
22
+ };
23
+ const vertical = {
24
+ [UP]: prev,
25
+ [DOWN]: next,
26
+ [ENTER]: children,
27
+ [ESC]: parent,
28
+ [LEFT]: isRtl ? children : parent,
29
+ [RIGHT]: isRtl ? parent : children
30
+ };
31
+ const offsets = {
32
+ inline,
33
+ horizontal,
34
+ vertical,
35
+ inlineSub: inline,
36
+ horizontalSub: vertical,
37
+ verticalSub: vertical
38
+ };
39
+ const type = offsets[`${mode}${isRootLevel ? "" : "Sub"}`]?.[which];
40
+ switch (type) {
41
+ case prev:
42
+ return { offset: -1, sibling: true };
43
+ case next:
44
+ return { offset: 1, sibling: true };
45
+ case parent:
46
+ return { offset: -1, sibling: false };
47
+ case children:
48
+ return { offset: 1, sibling: false };
49
+ default:
50
+ return null;
51
+ }
52
+ }
53
+ function findContainerUL(element) {
54
+ let current = element;
55
+ while (current) {
56
+ if (current.getAttribute("data-menu-list")) {
57
+ return current;
58
+ }
59
+ current = current.parentElement;
60
+ }
61
+ return null;
62
+ }
63
+ function getFocusNodeList(container, includeDisabled) {
64
+ const selector = "[tabindex]";
65
+ return Array.from(container.querySelectorAll(selector));
66
+ }
67
+ function getFocusElement(activeElement, elements) {
68
+ let current = activeElement || document.activeElement;
69
+ while (current) {
70
+ if (elements.has(current)) {
71
+ return current;
72
+ }
73
+ current = current.parentElement;
74
+ }
75
+ return null;
76
+ }
77
+ function getFocusableElements(container, elements) {
78
+ if (!container)
79
+ return [];
80
+ const list = getFocusNodeList(container);
81
+ return list.filter((ele) => elements.has(ele));
82
+ }
83
+ function getNextFocusElement(parentQueryContainer, elements, focusMenuElement, offset = 1) {
84
+ if (!parentQueryContainer) {
85
+ return null;
86
+ }
87
+ const sameLevelFocusableMenuElementList = getFocusableElements(parentQueryContainer, elements);
88
+ const count = sameLevelFocusableMenuElementList.length;
89
+ let focusIndex = sameLevelFocusableMenuElementList.findIndex((ele) => focusMenuElement === ele);
90
+ if (offset < 0) {
91
+ if (focusIndex === -1) {
92
+ focusIndex = count - 1;
93
+ } else {
94
+ focusIndex -= 1;
95
+ }
96
+ } else if (offset > 0) {
97
+ focusIndex += 1;
98
+ }
99
+ focusIndex = (focusIndex + count) % count;
100
+ return sameLevelFocusableMenuElementList[focusIndex];
101
+ }
102
+ function refreshElements(keys, id) {
103
+ const elements = /* @__PURE__ */ new Set();
104
+ const key2element = /* @__PURE__ */ new Map();
105
+ const element2key = /* @__PURE__ */ new Map();
106
+ keys.forEach((key) => {
107
+ const element = document.querySelector(`[data-menu-id='${IdContext.getMenuId(id, key)}']`);
108
+ if (element) {
109
+ elements.add(element);
110
+ element2key.set(element, key);
111
+ key2element.set(key, element);
112
+ }
113
+ });
114
+ return { elements, key2element, element2key };
115
+ }
116
+ function useAccessibility(mode, activeKey, isRtl, id, containerRef, getKeys, getKeyPath, triggerActiveKey, triggerAccessibilityOpen, originOnKeyDown) {
117
+ const rafRef = vue.shallowRef();
118
+ const activeRef = vue.shallowRef();
119
+ const cleanRaf = () => {
120
+ if (rafRef.value !== void 0) {
121
+ cancelAnimationFrame(rafRef.value);
122
+ }
123
+ };
124
+ vue.onBeforeUnmount(() => {
125
+ cleanRaf();
126
+ });
127
+ return (e) => {
128
+ activeRef.value = activeKey.value;
129
+ const { which } = e;
130
+ if ([...ArrowKeys, ENTER, ESC, HOME, END].includes(which)) {
131
+ const keys = getKeys();
132
+ let refreshedElements = refreshElements(keys, id);
133
+ const { elements, key2element, element2key } = refreshedElements;
134
+ const activeElement = key2element.get(activeKey.value);
135
+ const focusMenuElement = getFocusElement(activeElement || null, elements);
136
+ const focusMenuKey = element2key.get(focusMenuElement);
137
+ const offsetObj = getOffset(mode.value, getKeyPath(focusMenuKey, true).length === 1, isRtl.value, which);
138
+ if (!offsetObj && which !== HOME && which !== END) {
139
+ return;
140
+ }
141
+ if (ArrowKeys.includes(which) || [HOME, END].includes(which)) {
142
+ e.preventDefault();
143
+ }
144
+ const tryFocus = (menuElement) => {
145
+ if (menuElement) {
146
+ let focusTargetElement = menuElement;
147
+ const link = menuElement.querySelector("a");
148
+ if (link?.getAttribute("href")) {
149
+ focusTargetElement = link;
150
+ }
151
+ const targetKey = element2key.get(menuElement);
152
+ if (targetKey) {
153
+ triggerActiveKey(targetKey);
154
+ }
155
+ cleanRaf();
156
+ rafRef.value = requestAnimationFrame(() => {
157
+ if (activeRef.value === targetKey) {
158
+ focusTargetElement.focus();
159
+ }
160
+ });
161
+ }
162
+ };
163
+ if ([HOME, END].includes(which) || offsetObj?.sibling || !focusMenuElement) {
164
+ let parentQueryContainer;
165
+ if (!focusMenuElement || mode.value === "inline") {
166
+ parentQueryContainer = containerRef.value;
167
+ } else {
168
+ parentQueryContainer = findContainerUL(focusMenuElement);
169
+ }
170
+ let targetElement;
171
+ const focusableElements = getFocusableElements(parentQueryContainer, elements);
172
+ if (which === HOME) {
173
+ targetElement = focusableElements[0];
174
+ } else if (which === END) {
175
+ targetElement = focusableElements[focusableElements.length - 1];
176
+ } else {
177
+ targetElement = getNextFocusElement(
178
+ parentQueryContainer,
179
+ elements,
180
+ focusMenuElement,
181
+ offsetObj?.offset
182
+ );
183
+ }
184
+ tryFocus(targetElement);
185
+ } else if (offsetObj.inlineTrigger) {
186
+ triggerAccessibilityOpen(focusMenuKey);
187
+ } else if (offsetObj.offset > 0) {
188
+ triggerAccessibilityOpen(focusMenuKey, true);
189
+ cleanRaf();
190
+ rafRef.value = requestAnimationFrame(() => {
191
+ refreshedElements = refreshElements(keys, id);
192
+ const controlId = focusMenuElement.getAttribute("aria-controls");
193
+ const subQueryContainer = controlId ? document.getElementById(controlId) : null;
194
+ const targetElement = getNextFocusElement(subQueryContainer, refreshedElements.elements);
195
+ tryFocus(targetElement);
196
+ });
197
+ } else if (offsetObj.offset < 0) {
198
+ const keyPath = getKeyPath(focusMenuKey, true);
199
+ const parentKey = keyPath[keyPath.length - 2];
200
+ const parentMenuElement = key2element.get(parentKey);
201
+ triggerAccessibilityOpen(parentKey, false);
202
+ tryFocus(parentMenuElement);
203
+ }
204
+ }
205
+ originOnKeyDown?.(e);
206
+ };
207
+ }
208
+ exports.default = useAccessibility;
209
+ exports.getFocusableElements = getFocusableElements;
210
+ exports.refreshElements = refreshElements;
@@ -0,0 +1,12 @@
1
+ import { Ref } from 'vue';
2
+ import { MenuMode } from '../interface';
3
+ /**
4
+ * Get focusable elements from the element set under provided container
5
+ */
6
+ export declare function getFocusableElements(container: HTMLElement | null, elements: Set<HTMLElement>): HTMLElement[];
7
+ export declare function refreshElements(keys: string[], id: string): {
8
+ elements: Set<HTMLElement>;
9
+ key2element: Map<string, HTMLElement>;
10
+ element2key: Map<HTMLElement, string>;
11
+ };
12
+ export default function useAccessibility(mode: Ref<MenuMode>, activeKey: Ref<string>, isRtl: Ref<boolean>, id: string, containerRef: Ref<HTMLUListElement | null>, getKeys: () => string[], getKeyPath: (key: string, includeOverflow?: boolean) => string[], triggerActiveKey: (key: string) => void, triggerAccessibilityOpen: (key: string, open?: boolean) => void, originOnKeyDown?: (e: KeyboardEvent) => void): (e: KeyboardEvent) => void;
@@ -0,0 +1,210 @@
1
+ import KeyCode from "@v-c/util/dist/KeyCode";
2
+ import { shallowRef, onBeforeUnmount } from "vue";
3
+ import { getMenuId } from "../context/IdContext.js";
4
+ const { LEFT, RIGHT, UP, DOWN, ENTER, ESC, HOME, END } = KeyCode;
5
+ const ArrowKeys = [UP, DOWN, LEFT, RIGHT];
6
+ function getOffset(mode, isRootLevel, isRtl, which) {
7
+ const prev = "prev";
8
+ const next = "next";
9
+ const children = "children";
10
+ const parent = "parent";
11
+ if (mode === "inline" && which === ENTER) {
12
+ return { inlineTrigger: true };
13
+ }
14
+ const inline = { [UP]: prev, [DOWN]: next };
15
+ const horizontal = {
16
+ [LEFT]: isRtl ? next : prev,
17
+ [RIGHT]: isRtl ? prev : next,
18
+ [DOWN]: children,
19
+ [ENTER]: children
20
+ };
21
+ const vertical = {
22
+ [UP]: prev,
23
+ [DOWN]: next,
24
+ [ENTER]: children,
25
+ [ESC]: parent,
26
+ [LEFT]: isRtl ? children : parent,
27
+ [RIGHT]: isRtl ? parent : children
28
+ };
29
+ const offsets = {
30
+ inline,
31
+ horizontal,
32
+ vertical,
33
+ inlineSub: inline,
34
+ horizontalSub: vertical,
35
+ verticalSub: vertical
36
+ };
37
+ const type = offsets[`${mode}${isRootLevel ? "" : "Sub"}`]?.[which];
38
+ switch (type) {
39
+ case prev:
40
+ return { offset: -1, sibling: true };
41
+ case next:
42
+ return { offset: 1, sibling: true };
43
+ case parent:
44
+ return { offset: -1, sibling: false };
45
+ case children:
46
+ return { offset: 1, sibling: false };
47
+ default:
48
+ return null;
49
+ }
50
+ }
51
+ function findContainerUL(element) {
52
+ let current = element;
53
+ while (current) {
54
+ if (current.getAttribute("data-menu-list")) {
55
+ return current;
56
+ }
57
+ current = current.parentElement;
58
+ }
59
+ return null;
60
+ }
61
+ function getFocusNodeList(container, includeDisabled) {
62
+ const selector = "[tabindex]";
63
+ return Array.from(container.querySelectorAll(selector));
64
+ }
65
+ function getFocusElement(activeElement, elements) {
66
+ let current = activeElement || document.activeElement;
67
+ while (current) {
68
+ if (elements.has(current)) {
69
+ return current;
70
+ }
71
+ current = current.parentElement;
72
+ }
73
+ return null;
74
+ }
75
+ function getFocusableElements(container, elements) {
76
+ if (!container)
77
+ return [];
78
+ const list = getFocusNodeList(container);
79
+ return list.filter((ele) => elements.has(ele));
80
+ }
81
+ function getNextFocusElement(parentQueryContainer, elements, focusMenuElement, offset = 1) {
82
+ if (!parentQueryContainer) {
83
+ return null;
84
+ }
85
+ const sameLevelFocusableMenuElementList = getFocusableElements(parentQueryContainer, elements);
86
+ const count = sameLevelFocusableMenuElementList.length;
87
+ let focusIndex = sameLevelFocusableMenuElementList.findIndex((ele) => focusMenuElement === ele);
88
+ if (offset < 0) {
89
+ if (focusIndex === -1) {
90
+ focusIndex = count - 1;
91
+ } else {
92
+ focusIndex -= 1;
93
+ }
94
+ } else if (offset > 0) {
95
+ focusIndex += 1;
96
+ }
97
+ focusIndex = (focusIndex + count) % count;
98
+ return sameLevelFocusableMenuElementList[focusIndex];
99
+ }
100
+ function refreshElements(keys, id) {
101
+ const elements = /* @__PURE__ */ new Set();
102
+ const key2element = /* @__PURE__ */ new Map();
103
+ const element2key = /* @__PURE__ */ new Map();
104
+ keys.forEach((key) => {
105
+ const element = document.querySelector(`[data-menu-id='${getMenuId(id, key)}']`);
106
+ if (element) {
107
+ elements.add(element);
108
+ element2key.set(element, key);
109
+ key2element.set(key, element);
110
+ }
111
+ });
112
+ return { elements, key2element, element2key };
113
+ }
114
+ function useAccessibility(mode, activeKey, isRtl, id, containerRef, getKeys, getKeyPath, triggerActiveKey, triggerAccessibilityOpen, originOnKeyDown) {
115
+ const rafRef = shallowRef();
116
+ const activeRef = shallowRef();
117
+ const cleanRaf = () => {
118
+ if (rafRef.value !== void 0) {
119
+ cancelAnimationFrame(rafRef.value);
120
+ }
121
+ };
122
+ onBeforeUnmount(() => {
123
+ cleanRaf();
124
+ });
125
+ return (e) => {
126
+ activeRef.value = activeKey.value;
127
+ const { which } = e;
128
+ if ([...ArrowKeys, ENTER, ESC, HOME, END].includes(which)) {
129
+ const keys = getKeys();
130
+ let refreshedElements = refreshElements(keys, id);
131
+ const { elements, key2element, element2key } = refreshedElements;
132
+ const activeElement = key2element.get(activeKey.value);
133
+ const focusMenuElement = getFocusElement(activeElement || null, elements);
134
+ const focusMenuKey = element2key.get(focusMenuElement);
135
+ const offsetObj = getOffset(mode.value, getKeyPath(focusMenuKey, true).length === 1, isRtl.value, which);
136
+ if (!offsetObj && which !== HOME && which !== END) {
137
+ return;
138
+ }
139
+ if (ArrowKeys.includes(which) || [HOME, END].includes(which)) {
140
+ e.preventDefault();
141
+ }
142
+ const tryFocus = (menuElement) => {
143
+ if (menuElement) {
144
+ let focusTargetElement = menuElement;
145
+ const link = menuElement.querySelector("a");
146
+ if (link?.getAttribute("href")) {
147
+ focusTargetElement = link;
148
+ }
149
+ const targetKey = element2key.get(menuElement);
150
+ if (targetKey) {
151
+ triggerActiveKey(targetKey);
152
+ }
153
+ cleanRaf();
154
+ rafRef.value = requestAnimationFrame(() => {
155
+ if (activeRef.value === targetKey) {
156
+ focusTargetElement.focus();
157
+ }
158
+ });
159
+ }
160
+ };
161
+ if ([HOME, END].includes(which) || offsetObj?.sibling || !focusMenuElement) {
162
+ let parentQueryContainer;
163
+ if (!focusMenuElement || mode.value === "inline") {
164
+ parentQueryContainer = containerRef.value;
165
+ } else {
166
+ parentQueryContainer = findContainerUL(focusMenuElement);
167
+ }
168
+ let targetElement;
169
+ const focusableElements = getFocusableElements(parentQueryContainer, elements);
170
+ if (which === HOME) {
171
+ targetElement = focusableElements[0];
172
+ } else if (which === END) {
173
+ targetElement = focusableElements[focusableElements.length - 1];
174
+ } else {
175
+ targetElement = getNextFocusElement(
176
+ parentQueryContainer,
177
+ elements,
178
+ focusMenuElement,
179
+ offsetObj?.offset
180
+ );
181
+ }
182
+ tryFocus(targetElement);
183
+ } else if (offsetObj.inlineTrigger) {
184
+ triggerAccessibilityOpen(focusMenuKey);
185
+ } else if (offsetObj.offset > 0) {
186
+ triggerAccessibilityOpen(focusMenuKey, true);
187
+ cleanRaf();
188
+ rafRef.value = requestAnimationFrame(() => {
189
+ refreshedElements = refreshElements(keys, id);
190
+ const controlId = focusMenuElement.getAttribute("aria-controls");
191
+ const subQueryContainer = controlId ? document.getElementById(controlId) : null;
192
+ const targetElement = getNextFocusElement(subQueryContainer, refreshedElements.elements);
193
+ tryFocus(targetElement);
194
+ });
195
+ } else if (offsetObj.offset < 0) {
196
+ const keyPath = getKeyPath(focusMenuKey, true);
197
+ const parentKey = keyPath[keyPath.length - 2];
198
+ const parentMenuElement = key2element.get(parentKey);
199
+ triggerAccessibilityOpen(parentKey, false);
200
+ tryFocus(parentMenuElement);
201
+ }
202
+ }
203
+ originOnKeyDown?.(e);
204
+ };
205
+ }
206
+ export {
207
+ useAccessibility as default,
208
+ getFocusableElements,
209
+ refreshElements
210
+ };
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const vue = require("vue");
4
+ const MenuContext = require("../context/MenuContext.cjs");
5
+ function useActive(eventKey, disabled, onMouseEnter, onMouseLeave) {
6
+ const menuContext = MenuContext.useMenuContext();
7
+ const active = vue.computed(() => menuContext?.value?.activeKey === eventKey.value);
8
+ const ret = {
9
+ active
10
+ };
11
+ vue.watchEffect(() => {
12
+ if (!disabled.value) {
13
+ ret.onMouseEnter = (domEvent) => {
14
+ onMouseEnter?.({
15
+ key: eventKey.value,
16
+ domEvent
17
+ });
18
+ menuContext?.value?.onActive?.(eventKey.value);
19
+ };
20
+ ret.onMouseLeave = (domEvent) => {
21
+ onMouseLeave?.({
22
+ key: eventKey.value,
23
+ domEvent
24
+ });
25
+ menuContext?.value?.onInactive?.(eventKey.value);
26
+ };
27
+ }
28
+ });
29
+ return ret;
30
+ }
31
+ exports.default = useActive;
@@ -0,0 +1,9 @@
1
+ import { Ref } from 'vue';
2
+ import { MenuHoverEventHandler } from '../interface.ts';
3
+ interface ActiveObj {
4
+ active: Ref<boolean>;
5
+ onMouseEnter?: (event: MouseEvent) => void;
6
+ onMouseLeave?: (event: MouseEvent) => void;
7
+ }
8
+ export default function useActive(eventKey: Ref<string>, disabled: Ref<boolean>, onMouseEnter?: MenuHoverEventHandler, onMouseLeave?: MenuHoverEventHandler): ActiveObj;
9
+ export {};
@@ -0,0 +1,31 @@
1
+ import { computed, watchEffect } from "vue";
2
+ import { useMenuContext } from "../context/MenuContext.js";
3
+ function useActive(eventKey, disabled, onMouseEnter, onMouseLeave) {
4
+ const menuContext = useMenuContext();
5
+ const active = computed(() => menuContext?.value?.activeKey === eventKey.value);
6
+ const ret = {
7
+ active
8
+ };
9
+ watchEffect(() => {
10
+ if (!disabled.value) {
11
+ ret.onMouseEnter = (domEvent) => {
12
+ onMouseEnter?.({
13
+ key: eventKey.value,
14
+ domEvent
15
+ });
16
+ menuContext?.value?.onActive?.(eventKey.value);
17
+ };
18
+ ret.onMouseLeave = (domEvent) => {
19
+ onMouseLeave?.({
20
+ key: eventKey.value,
21
+ domEvent
22
+ });
23
+ menuContext?.value?.onInactive?.(eventKey.value);
24
+ };
25
+ }
26
+ });
27
+ return ret;
28
+ }
29
+ export {
30
+ useActive as default
31
+ };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const vue = require("vue");
4
+ const MenuContext = require("../context/MenuContext.cjs");
5
+ function useDirectionStyle(level) {
6
+ const menuContext = MenuContext.useMenuContext();
7
+ return vue.computed(() => {
8
+ const { mode, rtl, inlineIndent } = menuContext?.value ?? {};
9
+ if (mode !== "inline") {
10
+ return null;
11
+ }
12
+ const len = level.value;
13
+ return rtl ? {
14
+ paddingRight: `${len * inlineIndent}px`
15
+ } : {
16
+ paddingLeft: `${len * inlineIndent}px`
17
+ };
18
+ });
19
+ }
20
+ exports.default = useDirectionStyle;
@@ -0,0 +1,2 @@
1
+ import { CSSProperties, Ref } from 'vue';
2
+ export default function useDirectionStyle(level: Ref<number>): Ref<CSSProperties | null>;
@@ -0,0 +1,20 @@
1
+ import { computed } from "vue";
2
+ import { useMenuContext } from "../context/MenuContext.js";
3
+ function useDirectionStyle(level) {
4
+ const menuContext = useMenuContext();
5
+ return computed(() => {
6
+ const { mode, rtl, inlineIndent } = menuContext?.value ?? {};
7
+ if (mode !== "inline") {
8
+ return null;
9
+ }
10
+ const len = level.value;
11
+ return rtl ? {
12
+ paddingRight: `${len * inlineIndent}px`
13
+ } : {
14
+ paddingLeft: `${len * inlineIndent}px`
15
+ };
16
+ });
17
+ }
18
+ export {
19
+ useDirectionStyle as default
20
+ };
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const vue = require("vue");
4
+ const timeUtil = require("../utils/timeUtil.cjs");
5
+ const PATH_SPLIT = "__VC_UTIL_PATH_SPLIT__";
6
+ const getPathStr = (keyPath) => keyPath.join(PATH_SPLIT);
7
+ const getPathKeys = (keyPathStr) => keyPathStr.split(PATH_SPLIT);
8
+ const OVERFLOW_KEY = "vc-menu-more";
9
+ function useKeyRecords() {
10
+ const forceUpdateCount = vue.ref(0);
11
+ const key2pathRef = vue.shallowRef(/* @__PURE__ */ new Map());
12
+ const path2keyRef = vue.shallowRef(/* @__PURE__ */ new Map());
13
+ const overflowKeys = vue.ref([]);
14
+ const updateRef = vue.ref(0);
15
+ const destroyRef = vue.ref(false);
16
+ const forceUpdate = () => {
17
+ if (!destroyRef.value) {
18
+ forceUpdateCount.value += 1;
19
+ }
20
+ };
21
+ const registerPath = (key, keyPath) => {
22
+ if (process.env.NODE_ENV !== "production") {
23
+ if (key2pathRef.value.has(key)) {
24
+ console.warn(
25
+ `Duplicated key '${key}' used in Menu by path [${keyPath.join(" > ")}]`
26
+ );
27
+ }
28
+ }
29
+ const connectedPath = getPathStr(keyPath);
30
+ path2keyRef.value.set(connectedPath, key);
31
+ key2pathRef.value.set(key, connectedPath);
32
+ updateRef.value += 1;
33
+ const id = updateRef.value;
34
+ timeUtil.nextSlice(() => {
35
+ if (id === updateRef.value) {
36
+ forceUpdate();
37
+ }
38
+ });
39
+ };
40
+ const unregisterPath = (key, keyPath) => {
41
+ const connectedPath = getPathStr(keyPath);
42
+ path2keyRef.value.delete(connectedPath);
43
+ key2pathRef.value.delete(key);
44
+ };
45
+ const refreshOverflowKeys = (keys) => {
46
+ overflowKeys.value = keys;
47
+ };
48
+ const getKeyPath = (eventKey, includeOverflow) => {
49
+ const fullPath = key2pathRef.value.get(eventKey) || "";
50
+ const keys = getPathKeys(fullPath);
51
+ if (includeOverflow && overflowKeys.value.includes(keys[0])) {
52
+ keys.unshift(OVERFLOW_KEY);
53
+ }
54
+ return keys;
55
+ };
56
+ const isSubPathKey = (pathKeys, eventKey) => pathKeys.filter((item) => item !== void 0).some((pathKey) => {
57
+ const pathKeyList = getKeyPath(pathKey, true);
58
+ return pathKeyList.includes(eventKey);
59
+ });
60
+ const getKeys = () => {
61
+ const keys = [...key2pathRef.value.keys()];
62
+ if (overflowKeys.value.length) {
63
+ keys.push(OVERFLOW_KEY);
64
+ }
65
+ return keys;
66
+ };
67
+ const getSubPathKeys = (key) => {
68
+ const connectedPath = `${key2pathRef.value.get(key)}${PATH_SPLIT}`;
69
+ const pathKeys = /* @__PURE__ */ new Set();
70
+ [...path2keyRef.value.keys()].forEach((pathKey) => {
71
+ if (pathKey.startsWith(connectedPath)) {
72
+ pathKeys.add(path2keyRef.value.get(pathKey));
73
+ }
74
+ });
75
+ return pathKeys;
76
+ };
77
+ vue.onBeforeUnmount(() => {
78
+ destroyRef.value = true;
79
+ });
80
+ return {
81
+ // Register
82
+ registerPath,
83
+ unregisterPath,
84
+ refreshOverflowKeys,
85
+ // Util
86
+ isSubPathKey,
87
+ getKeyPath,
88
+ getKeys,
89
+ getSubPathKeys
90
+ };
91
+ }
92
+ exports.OVERFLOW_KEY = OVERFLOW_KEY;
93
+ exports.default = useKeyRecords;
@@ -0,0 +1,10 @@
1
+ export declare const OVERFLOW_KEY = "vc-menu-more";
2
+ export default function useKeyRecords(): {
3
+ registerPath: (key: string, keyPath: string[]) => void;
4
+ unregisterPath: (key: string, keyPath: string[]) => void;
5
+ refreshOverflowKeys: (keys: string[]) => void;
6
+ isSubPathKey: (pathKeys: string[], eventKey: string) => boolean;
7
+ getKeyPath: (eventKey: string, includeOverflow?: boolean) => string[];
8
+ getKeys: () => string[];
9
+ getSubPathKeys: (key: string) => Set<string>;
10
+ };