@jari-ace/element-plus-component 0.1.10 → 0.2.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 (156) hide show
  1. package/README.md +1 -18
  2. package/dist/components/form/JaForm.vue.d.ts +0 -3
  3. package/dist/components/form/JaForm.vue.d.ts.map +1 -1
  4. package/dist/components/form/JaForm.vue.js +68 -22
  5. package/dist/components/form/JaForm.vue.js.map +1 -1
  6. package/dist/components/formItem/JaFormItem.vue.d.ts +0 -4
  7. package/dist/components/formItem/JaFormItem.vue.d.ts.map +1 -1
  8. package/dist/components/formItem/JaFormItem.vue.js +8 -26
  9. package/dist/components/formItem/JaFormItem.vue.js.map +1 -1
  10. package/dist/components/userPicker/src/UserPicker.vue.d.ts +17 -0
  11. package/dist/components/userPicker/src/UserPicker.vue.d.ts.map +1 -1
  12. package/dist/components/userPicker/src/UserPicker.vue.js +15 -0
  13. package/dist/components/userPicker/src/UserPicker.vue.js.map +1 -1
  14. package/dist/components/userSelectDialog/src/userSelectDialog.vue.d.ts +17 -0
  15. package/dist/components/userSelectDialog/src/userSelectDialog.vue.d.ts.map +1 -1
  16. package/dist/components/userSelectDialog/src/userSelectDialog.vue.js +15 -0
  17. package/dist/components/userSelectDialog/src/userSelectDialog.vue.js.map +1 -1
  18. package/dist/hooks/useBackendValidations.js +0 -1
  19. package/dist/hooks/useBackendValidations.js.map +1 -1
  20. package/dist/hooks/useClassificationLevels.d.ts +21 -0
  21. package/dist/hooks/useClassificationLevels.d.ts.map +1 -0
  22. package/dist/hooks/useClassificationLevels.js +55 -0
  23. package/dist/hooks/useClassificationLevels.js.map +1 -0
  24. package/dist/hooks/useUserRefQuery.d.ts +6 -0
  25. package/dist/hooks/useUserRefQuery.d.ts.map +1 -1
  26. package/dist/hooks/useUserRefQuery.js +4 -0
  27. package/dist/hooks/useUserRefQuery.js.map +1 -1
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +2 -0
  31. package/dist/index.js.map +1 -1
  32. package/lib/index.css +1 -1
  33. package/lib/index.js +1808 -1774
  34. package/lib/index.umd.cjs +2 -2
  35. package/package.json +61 -61
  36. package/packages/components/autoComplete/JaAutoComplete.vue +47 -47
  37. package/packages/components/autoComplete/index.ts +5 -5
  38. package/packages/components/avatar/JaAvatar.vue +126 -126
  39. package/packages/components/avatar/avatarToken.ts +11 -11
  40. package/packages/components/avatar/defaultImg.ts +14 -14
  41. package/packages/components/avatar/index.ts +7 -7
  42. package/packages/components/button/JaButton.vue +51 -51
  43. package/packages/components/button/index.ts +4 -4
  44. package/packages/components/channelPicker/index.ts +7 -7
  45. package/packages/components/channelPicker/src/ChannelPicker.vue +43 -43
  46. package/packages/components/channelPicker/src/JaChannelPicker.vue +42 -42
  47. package/packages/components/checkbox/JaCheckbox.vue +73 -73
  48. package/packages/components/checkbox/index.ts +4 -4
  49. package/packages/components/checkboxGroup/JaCheckboxGroup.vue +45 -45
  50. package/packages/components/checkboxGroup/index.ts +4 -4
  51. package/packages/components/customGroupTree/index.ts +10 -10
  52. package/packages/components/customGroupTree/src/customGroupTree.vue +91 -91
  53. package/packages/components/datePicker/JaDatePicker.vue +52 -52
  54. package/packages/components/datePicker/index.ts +4 -4
  55. package/packages/components/departmentPicker/index.ts +4 -4
  56. package/packages/components/departmentPicker/src/DepartmentPicker.vue +107 -107
  57. package/packages/components/departmentPicker/src/consts.ts +2 -2
  58. package/packages/components/departmentTree/index.ts +10 -10
  59. package/packages/components/departmentTree/src/departmentTree.vue +135 -135
  60. package/packages/components/dropdownButton/JaDropdownButton.vue +59 -59
  61. package/packages/components/dropdownButton/index.ts +4 -4
  62. package/packages/components/enumList/EnumListInput.vue +107 -107
  63. package/packages/components/enumList/JaEnumList.vue +39 -39
  64. package/packages/components/enumList/index.ts +7 -7
  65. package/packages/components/enumPicker/index.ts +5 -5
  66. package/packages/components/enumPicker/src/EnumPicker.vue +103 -103
  67. package/packages/components/form/JaForm.vue +186 -146
  68. package/packages/components/form/index.ts +5 -5
  69. package/packages/components/form/types.ts +4 -4
  70. package/packages/components/formItem/JaFormItem.vue +68 -87
  71. package/packages/components/formItem/index.ts +4 -4
  72. package/packages/components/index.ts +34 -34
  73. package/packages/components/input/JaInput.vue +143 -143
  74. package/packages/components/input/index.ts +4 -4
  75. package/packages/components/inputI18n/I18nBundleEditor.vue +76 -76
  76. package/packages/components/inputI18n/InputI18n.vue +146 -146
  77. package/packages/components/inputI18n/JaInputI18n.vue +50 -50
  78. package/packages/components/inputI18n/index.ts +8 -8
  79. package/packages/components/inputNumber/JaInputNumber.vue +98 -98
  80. package/packages/components/inputNumber/index.ts +4 -4
  81. package/packages/components/mapItemList/JaMapItemList.vue +35 -35
  82. package/packages/components/mapItemList/MapItemListInput.vue +191 -191
  83. package/packages/components/mapItemList/index.ts +7 -7
  84. package/packages/components/numberList/JaNumberList.vue +36 -36
  85. package/packages/components/numberList/NumberListInput.vue +111 -111
  86. package/packages/components/numberList/index.ts +7 -7
  87. package/packages/components/properyPicker/JaPropertyPicker.vue +38 -38
  88. package/packages/components/properyPicker/PropertyPicker.vue +314 -314
  89. package/packages/components/properyPicker/index.ts +7 -7
  90. package/packages/components/radioGroup/JaRadioGroup.vue +50 -50
  91. package/packages/components/radioGroup/index.ts +4 -4
  92. package/packages/components/rolePicker/RoleEditor.vue +129 -129
  93. package/packages/components/rolePicker/RolePicker.vue +44 -44
  94. package/packages/components/rolePicker/RolePickerRaw.vue +56 -56
  95. package/packages/components/rolePicker/baseRolePicker.vue +87 -87
  96. package/packages/components/rolePicker/index.ts +10 -10
  97. package/packages/components/scrollbar/Scrollbar.vue +89 -89
  98. package/packages/components/scrollbar/index.ts +5 -5
  99. package/packages/components/scrollbar/utils.ts +17 -17
  100. package/packages/components/select/JaSelect.vue +48 -48
  101. package/packages/components/select/index.ts +4 -4
  102. package/packages/components/stringList/JaStringList.vue +36 -36
  103. package/packages/components/stringList/StringListInput.vue +96 -96
  104. package/packages/components/stringList/index.ts +7 -7
  105. package/packages/components/switch/JaSwitch.vue +50 -50
  106. package/packages/components/switch/index.ts +4 -4
  107. package/packages/components/timePicker/JaTimePicker.vue +52 -52
  108. package/packages/components/timePicker/index.ts +5 -5
  109. package/packages/components/tip/index.ts +4 -4
  110. package/packages/components/tip/src/AceTip.vue +43 -43
  111. package/packages/components/upload/index.ts +6 -6
  112. package/packages/components/upload/src/Upload.vue +25 -25
  113. package/packages/components/upload/src/type.ts +3 -3
  114. package/packages/components/userGroupPicker/index.ts +4 -4
  115. package/packages/components/userGroupPicker/src/UserGroupPicker.vue +94 -94
  116. package/packages/components/userGroupTree/index.ts +10 -10
  117. package/packages/components/userGroupTree/src/userGroupTree.vue +149 -149
  118. package/packages/components/userPicker/index.ts +10 -10
  119. package/packages/components/userPicker/src/CustomGroupManager.vue +189 -189
  120. package/packages/components/userPicker/src/JaUserList.vue +283 -283
  121. package/packages/components/userPicker/src/JaUserPicker.vue +37 -37
  122. package/packages/components/userPicker/src/UserPicker.vue +376 -368
  123. package/packages/components/userSelectDialog/index.ts +6 -6
  124. package/packages/components/userSelectDialog/src/userSelectDialog.vue +462 -455
  125. package/packages/components/userTag/UserInfoTag.vue +397 -397
  126. package/packages/components/userTag/index.ts +6 -6
  127. package/packages/components/userTag/sharedAxios.ts +8 -8
  128. package/packages/directives/auth/index.ts +41 -41
  129. package/packages/directives/autofocus/index.ts +29 -29
  130. package/packages/directives/index.ts +10 -10
  131. package/packages/directives/shortcut/index.ts +192 -192
  132. package/packages/hooks/useAppInstances.ts +34 -34
  133. package/packages/hooks/useBackendValidations.ts +81 -81
  134. package/packages/hooks/useBridage.ts +157 -157
  135. package/packages/hooks/useClassificationLevels.ts +62 -0
  136. package/packages/hooks/useDateTimeShortCuts.ts +65 -65
  137. package/packages/hooks/useRealms.ts +28 -28
  138. package/packages/hooks/useTreeData.ts +45 -45
  139. package/packages/hooks/useUserRefQuery.ts +232 -224
  140. package/packages/index.ts +24 -22
  141. package/packages/list.json +7 -7
  142. package/packages/types/custom.d.ts +13 -13
  143. package/packages/types/window.d.ts +16 -16
  144. package/packages/utils/install.ts +43 -43
  145. package/packages/utils/objectUtils.ts +31 -31
  146. package/theme-style/fonts/iconfont.json +5196 -5196
  147. package/theme-style/index.scss +10 -10
  148. package/theme-style/styles/element-plus-var.scss +1419 -1419
  149. package/theme-style/styles/iconfont.css +2979 -2979
  150. package/theme-style/styles/theme-var.scss +72 -72
  151. package/theme-style/styles/transition.scss +122 -122
  152. package/dist/utils/formUtils.d.ts +0 -7
  153. package/dist/utils/formUtils.d.ts.map +0 -1
  154. package/dist/utils/formUtils.js +0 -54
  155. package/dist/utils/formUtils.js.map +0 -1
  156. package/packages/utils/formUtils.ts +0 -57
@@ -1,6 +1,6 @@
1
- import {type SFCWithInstall, withInstall} from "../../utils/install";
2
- import UserInfoTag from "./UserInfoTag.vue";
3
-
4
- export const JaUserInfoTag: SFCWithInstall<typeof UserInfoTag> = withInstall(UserInfoTag);
5
-
6
-
1
+ import {type SFCWithInstall, withInstall} from "../../utils/install";
2
+ import UserInfoTag from "./UserInfoTag.vue";
3
+
4
+ export const JaUserInfoTag: SFCWithInstall<typeof UserInfoTag> = withInstall(UserInfoTag);
5
+
6
+
@@ -1,8 +1,8 @@
1
- import {createAxiosWithoutCache, type IAceAxios} from "@jari-ace/app-bolts";
2
-
3
- let axios: IAceAxios | undefined;
4
-
5
- export function useAxios() {
6
- if (!axios) axios = createAxiosWithoutCache();
7
- return axios;
8
- }
1
+ import {createAxiosWithoutCache, type IAceAxios} from "@jari-ace/app-bolts";
2
+
3
+ let axios: IAceAxios | undefined;
4
+
5
+ export function useAxios() {
6
+ if (!axios) axios = createAxiosWithoutCache();
7
+ return axios;
8
+ }
@@ -1,41 +1,41 @@
1
- import type {DirectiveBinding} from "vue";
2
- import {useLoginUser} from "@jari-ace/app-bolts";
3
-
4
- function disableOrHideElement(modifiers: any, el: HTMLElement) {
5
- if (modifiers.disable) {
6
- (el as any).disabled = true;
7
- el.classList.add('disabled');
8
- } else {
9
- el.style.display = 'none';
10
- }
11
- }
12
-
13
- /**
14
- * v-auth指令用法:
15
- * 默认如果用户有指定角色,就显示,否则隐藏:
16
- * v-auth="role1"
17
- * 支持多个角色检查,默认为并且关系,即要求用户拥有全部指定角色:
18
- * 数组参数形式 v-auth="[role1, role2] 或者 字符串参数 v-auth="'role1-name,role2-name'"
19
- * 也可以修改为拥有任一角色即可:
20
- * v-auth.any="[role1, role2]"
21
- * 如果要不隐藏只禁用:
22
- * v-auth.disable="role1"
23
- */
24
- export default {
25
- // 当指令绑定到元素时调用
26
- mounted(el: HTMLElement, binding: DirectiveBinding<string | string[] | undefined>) {
27
- const user = useLoginUser();
28
- const {value, modifiers} = binding;
29
- const userPermissions = (typeof value === "string" ? value.split(/,/) : (value ?? []));
30
- if (!userPermissions || userPermissions.length === 0) return;
31
- if (modifiers.any) {
32
- if (!userPermissions.some(p => user.hasRole(p))) {
33
- disableOrHideElement(modifiers, el);
34
- }
35
- } else {
36
- if (!userPermissions.every(p => user.hasRole(p))) {
37
- disableOrHideElement(modifiers, el);
38
- }
39
- }
40
- }
41
- }
1
+ import type {DirectiveBinding} from "vue";
2
+ import {useLoginUser} from "@jari-ace/app-bolts";
3
+
4
+ function disableOrHideElement(modifiers: any, el: HTMLElement) {
5
+ if (modifiers.disable) {
6
+ (el as any).disabled = true;
7
+ el.classList.add('disabled');
8
+ } else {
9
+ el.style.display = 'none';
10
+ }
11
+ }
12
+
13
+ /**
14
+ * v-auth指令用法:
15
+ * 默认如果用户有指定角色,就显示,否则隐藏:
16
+ * v-auth="role1"
17
+ * 支持多个角色检查,默认为并且关系,即要求用户拥有全部指定角色:
18
+ * 数组参数形式 v-auth="[role1, role2] 或者 字符串参数 v-auth="'role1-name,role2-name'"
19
+ * 也可以修改为拥有任一角色即可:
20
+ * v-auth.any="[role1, role2]"
21
+ * 如果要不隐藏只禁用:
22
+ * v-auth.disable="role1"
23
+ */
24
+ export default {
25
+ // 当指令绑定到元素时调用
26
+ mounted(el: HTMLElement, binding: DirectiveBinding<string | string[] | undefined>) {
27
+ const user = useLoginUser();
28
+ const {value, modifiers} = binding;
29
+ const userPermissions = (typeof value === "string" ? value.split(/,/) : (value ?? []));
30
+ if (!userPermissions || userPermissions.length === 0) return;
31
+ if (modifiers.any) {
32
+ if (!userPermissions.some(p => user.hasRole(p))) {
33
+ disableOrHideElement(modifiers, el);
34
+ }
35
+ } else {
36
+ if (!userPermissions.every(p => user.hasRole(p))) {
37
+ disableOrHideElement(modifiers, el);
38
+ }
39
+ }
40
+ }
41
+ }
@@ -1,29 +1,29 @@
1
- /**
2
- * 在组件mount后自动聚焦控件
3
- */
4
-
5
- const timeoutHandles = new Map<HTMLElement, number>();
6
-
7
- export default {
8
- mounted(el: HTMLElement) {
9
- let handle;
10
- if (el instanceof HTMLInputElement) {
11
- handle = setTimeout(() => el?.focus(), 500)
12
- timeoutHandles.set(el, handle);
13
- } else {
14
- const el1 = el.querySelectorAll('input')
15
- if (el1.length > 0 && el1.item(0) instanceof HTMLInputElement) {
16
- handle = setTimeout(() => (
17
- el1?.item(0) as HTMLInputElement
18
- )?.focus(), 500)
19
- timeoutHandles.set(el, handle)
20
- }
21
- }
22
- },
23
- onUnmounted(el: HTMLElement) {
24
- if (timeoutHandles.has(el)) {
25
- clearTimeout(timeoutHandles.get(el))
26
- timeoutHandles.delete(el)
27
- }
28
- }
29
- }
1
+ /**
2
+ * 在组件mount后自动聚焦控件
3
+ */
4
+
5
+ const timeoutHandles = new Map<HTMLElement, number>();
6
+
7
+ export default {
8
+ mounted(el: HTMLElement) {
9
+ let handle;
10
+ if (el instanceof HTMLInputElement) {
11
+ handle = setTimeout(() => el?.focus(), 500)
12
+ timeoutHandles.set(el, handle);
13
+ } else {
14
+ const el1 = el.querySelectorAll('input')
15
+ if (el1.length > 0 && el1.item(0) instanceof HTMLInputElement) {
16
+ handle = setTimeout(() => (
17
+ el1?.item(0) as HTMLInputElement
18
+ )?.focus(), 500)
19
+ timeoutHandles.set(el, handle)
20
+ }
21
+ }
22
+ },
23
+ onUnmounted(el: HTMLElement) {
24
+ if (timeoutHandles.has(el)) {
25
+ clearTimeout(timeoutHandles.get(el))
26
+ timeoutHandles.delete(el)
27
+ }
28
+ }
29
+ }
@@ -1,10 +1,10 @@
1
- import autofocus from "./autofocus";
2
- import shortcut from "./shortcut";
3
- import auth from "./auth";
4
- import type {App} from "vue";
5
-
6
- export function installDirectives(app: App) {
7
- app.directive('focus', autofocus)
8
- app.directive('shortcut', shortcut)
9
- app.directive('auth', auth)
10
- }
1
+ import autofocus from "./autofocus";
2
+ import shortcut from "./shortcut";
3
+ import auth from "./auth";
4
+ import type {App} from "vue";
5
+
6
+ export function installDirectives(app: App) {
7
+ app.directive('focus', autofocus)
8
+ app.directive('shortcut', shortcut)
9
+ app.directive('auth', auth)
10
+ }
@@ -1,192 +1,192 @@
1
- import {
2
- type DirectiveBinding,
3
- type RendererElement,
4
- type RendererNode,
5
- type VNode
6
- } from "vue";
7
-
8
- function isValidShortcut(keys: string[]): boolean {
9
- const validModifiers = ["Ctrl", "Alt", "Shift", "Meta"];
10
- const validKeys = [
11
- "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
12
- "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
13
- "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "Tab",
14
- "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
15
- "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight",
16
- "Enter", "Escape", "Space"
17
- ];
18
- if (keys.length < 2) {
19
- return false;
20
- }
21
- for (let i = 0; i < keys.length - 1; i++) {
22
- if (!validModifiers.includes(keys[i])) {
23
- return false;
24
- }
25
- }
26
- const mainKey = keys[keys.length - 1];
27
- return validKeys.includes(mainKey);
28
- }
29
-
30
- type ShortCutCallback = (el: HTMLElement, binding: DirectiveBinding<ShortCutCallback>, vNode: VNode) => void;
31
-
32
- let currentHandler: Record<string, ShortcutHandlerStackItem> = {};
33
-
34
- function registerShortcut(binding: DirectiveBinding<ShortCutCallback>,
35
- el: HTMLElement,
36
- vNode: VNode<RendererNode, RendererElement, {
37
- [p: string]: any
38
- }>) {
39
- const keys = binding.arg?.split('+') ?? [];
40
- if (!keys || keys.length === 0) return;
41
- if (isValidShortcut(keys)) {
42
- if (el.__vueShortcutHandler__) {
43
- return;
44
- }
45
- const handler = (event: KeyboardEvent) => {
46
- let isMatch = true;
47
- for (const key of keys) {
48
- if (key === 'Ctrl' && !event.ctrlKey) isMatch = false;
49
- if (key === 'Alt' && !event.altKey) isMatch = false;
50
- if (key === 'Shift' && !event.shiftKey) isMatch = false;
51
- if (key === 'Meta' && !event.metaKey) isMatch = false;
52
- }
53
- const mainKey = keys.length > 0 ? keys[keys.length - 1] : null;
54
- if (event.key && mainKey && event.key.toUpperCase()
55
- !== mainKey.toUpperCase()) isMatch = false;
56
- let disabled = false;
57
- if (vNode.component) {
58
- disabled = vNode.component.props?.disabled as boolean
59
- } else if (vNode.props) {
60
- disabled = vNode.props.disabled as boolean
61
- } else {
62
- disabled = el.hasAttribute('disabled')
63
- }
64
- if (isMatch && !disabled) {
65
- event.preventDefault();
66
- if (binding.value) {
67
- binding.value(el, binding, vNode)
68
- } else {
69
- el.focus();
70
- el.click();
71
- }
72
- }
73
- };
74
- doRegister({
75
- keys: binding.arg,
76
- handler,
77
- el,
78
- prev: currentHandler[binding.arg]
79
- });
80
- } else {
81
- console.warn(`Invalid shortcut key combination: ${keys.join('+')}`);
82
- }
83
- }
84
-
85
- function unregisterShortcut(el: HTMLElement) {
86
- if (el.__vueShortcutHandler__) {
87
- doUnregister(el.__vueShortcutHandler__);
88
-
89
- }
90
- }
91
-
92
- function doRegister(item: ShortcutHandlerStackItem) {
93
- const current = item.prev;
94
- const doc = (
95
- window.rawWindow ?? window
96
- ).document;
97
- if (current) {
98
- doc.removeEventListener('keydown', current.handler);
99
- }
100
- doc.addEventListener('keydown', item.handler);
101
- currentHandler[item.keys] = item;
102
- item.el.__vueShortcutHandler__ = item;
103
- }
104
-
105
- function doUnregister(item: ShortcutHandlerStackItem) {
106
- const current = currentHandler[item.keys];
107
- if (current && current == item) {
108
- const doc = (
109
- window.rawWindow ?? window
110
- ).document;
111
- doc.removeEventListener('keydown', item.handler);
112
- if (item.prev) {
113
- doc.addEventListener('keydown', item.prev.handler);
114
- currentHandler[item.keys] = item.prev;
115
- } else {
116
- currentHandler[item.keys] = undefined;
117
- }
118
- } else if (current) {
119
- //如果不是当前快捷键,就从栈链中移除
120
- let p = current;
121
- while (p && p.prev != item) {
122
- p = p.prev;
123
- }
124
- if (p) {
125
- p.prev = item.prev;
126
- }
127
- }
128
- if (item.prev) {
129
- delete item.prev;
130
- }
131
- delete item.el.__vueShortcutHandler__;
132
- }
133
-
134
- // 判断元素是否可见的辅助函数
135
- const isElementVisible = (el: HTMLElement) => {
136
- // 检查元素或其父元素是否被隐藏
137
- if (el.offsetParent === null) {
138
- return false; // 如果 offsetParent 为 null,说明元素或其父元素被隐藏
139
- }
140
-
141
- // 检查元素是否在视口内
142
- const rect = el.getBoundingClientRect();
143
- const win = window.rawWindow ?? window;
144
- return (
145
- rect.top <= win.innerHeight &&
146
- rect.bottom >= 0 &&
147
- rect.left <= win.innerWidth &&
148
- rect.right >= 0
149
- );
150
- };
151
-
152
- // 配置 Intersection Observer
153
- const observerOption = {
154
- root: null, // 默认为视口
155
- rootMargin: '0px',
156
- threshold: 0.1, // 当 10% 的元素可见时触发
157
- };
158
- /**
159
- * 支持对元素标签点击事件添加快捷键触发,完整的写法:
160
- * <div v-shortcut:Alt+N="() => doClick()"></div>
161
- * 如果元素已经定义了click事件,那么可以简写为
162
- * <div v-shortcut:Alt+N @click="doClick"><div>
163
- */
164
- export default {
165
- mounted(el: HTMLElement, binding: DirectiveBinding<ShortCutCallback>, vNode: VNode) {
166
- // 如果元素已经可见,直接注册快捷键
167
- if (isElementVisible(el)) {
168
- registerShortcut(binding, el, vNode);
169
- }
170
- // 回调函数,处理可见性变化
171
- const callback = (entries) => {
172
- entries.forEach((entry) => {
173
- if (entry.isIntersecting) {
174
- // 元素可见时触发
175
- registerShortcut(binding, el, vNode);
176
- } else {
177
- // 元素不可见时触发
178
- unregisterShortcut(el);
179
- }
180
- });
181
- };
182
- // 创建观察器
183
- const observer = new IntersectionObserver(callback, observerOption);
184
- el.__visibilityObserver__ = observer; // 将观察器挂载到元素上,便于卸载时使用
185
- observer.observe(el); // 开始观察
186
- },
187
- unmounted(el: HTMLElement) {
188
- el.__visibilityObserver__.disconnect();
189
- delete el.__visibilityObserver__;
190
- unregisterShortcut(el);
191
- }
192
- };
1
+ import {
2
+ type DirectiveBinding,
3
+ type RendererElement,
4
+ type RendererNode,
5
+ type VNode
6
+ } from "vue";
7
+
8
+ function isValidShortcut(keys: string[]): boolean {
9
+ const validModifiers = ["Ctrl", "Alt", "Shift", "Meta"];
10
+ const validKeys = [
11
+ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
12
+ "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
13
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "Tab",
14
+ "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
15
+ "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight",
16
+ "Enter", "Escape", "Space"
17
+ ];
18
+ if (keys.length < 2) {
19
+ return false;
20
+ }
21
+ for (let i = 0; i < keys.length - 1; i++) {
22
+ if (!validModifiers.includes(keys[i])) {
23
+ return false;
24
+ }
25
+ }
26
+ const mainKey = keys[keys.length - 1];
27
+ return validKeys.includes(mainKey);
28
+ }
29
+
30
+ type ShortCutCallback = (el: HTMLElement, binding: DirectiveBinding<ShortCutCallback>, vNode: VNode) => void;
31
+
32
+ let currentHandler: Record<string, ShortcutHandlerStackItem> = {};
33
+
34
+ function registerShortcut(binding: DirectiveBinding<ShortCutCallback>,
35
+ el: HTMLElement,
36
+ vNode: VNode<RendererNode, RendererElement, {
37
+ [p: string]: any
38
+ }>) {
39
+ const keys = binding.arg?.split('+') ?? [];
40
+ if (!keys || keys.length === 0) return;
41
+ if (isValidShortcut(keys)) {
42
+ if (el.__vueShortcutHandler__) {
43
+ return;
44
+ }
45
+ const handler = (event: KeyboardEvent) => {
46
+ let isMatch = true;
47
+ for (const key of keys) {
48
+ if (key === 'Ctrl' && !event.ctrlKey) isMatch = false;
49
+ if (key === 'Alt' && !event.altKey) isMatch = false;
50
+ if (key === 'Shift' && !event.shiftKey) isMatch = false;
51
+ if (key === 'Meta' && !event.metaKey) isMatch = false;
52
+ }
53
+ const mainKey = keys.length > 0 ? keys[keys.length - 1] : null;
54
+ if (event.key && mainKey && event.key.toUpperCase()
55
+ !== mainKey.toUpperCase()) isMatch = false;
56
+ let disabled = false;
57
+ if (vNode.component) {
58
+ disabled = vNode.component.props?.disabled as boolean
59
+ } else if (vNode.props) {
60
+ disabled = vNode.props.disabled as boolean
61
+ } else {
62
+ disabled = el.hasAttribute('disabled')
63
+ }
64
+ if (isMatch && !disabled) {
65
+ event.preventDefault();
66
+ if (binding.value) {
67
+ binding.value(el, binding, vNode)
68
+ } else {
69
+ el.focus();
70
+ el.click();
71
+ }
72
+ }
73
+ };
74
+ doRegister({
75
+ keys: binding.arg,
76
+ handler,
77
+ el,
78
+ prev: currentHandler[binding.arg]
79
+ });
80
+ } else {
81
+ console.warn(`Invalid shortcut key combination: ${keys.join('+')}`);
82
+ }
83
+ }
84
+
85
+ function unregisterShortcut(el: HTMLElement) {
86
+ if (el.__vueShortcutHandler__) {
87
+ doUnregister(el.__vueShortcutHandler__);
88
+
89
+ }
90
+ }
91
+
92
+ function doRegister(item: ShortcutHandlerStackItem) {
93
+ const current = item.prev;
94
+ const doc = (
95
+ window.rawWindow ?? window
96
+ ).document;
97
+ if (current) {
98
+ doc.removeEventListener('keydown', current.handler);
99
+ }
100
+ doc.addEventListener('keydown', item.handler);
101
+ currentHandler[item.keys] = item;
102
+ item.el.__vueShortcutHandler__ = item;
103
+ }
104
+
105
+ function doUnregister(item: ShortcutHandlerStackItem) {
106
+ const current = currentHandler[item.keys];
107
+ if (current && current == item) {
108
+ const doc = (
109
+ window.rawWindow ?? window
110
+ ).document;
111
+ doc.removeEventListener('keydown', item.handler);
112
+ if (item.prev) {
113
+ doc.addEventListener('keydown', item.prev.handler);
114
+ currentHandler[item.keys] = item.prev;
115
+ } else {
116
+ currentHandler[item.keys] = undefined;
117
+ }
118
+ } else if (current) {
119
+ //如果不是当前快捷键,就从栈链中移除
120
+ let p = current;
121
+ while (p && p.prev != item) {
122
+ p = p.prev;
123
+ }
124
+ if (p) {
125
+ p.prev = item.prev;
126
+ }
127
+ }
128
+ if (item.prev) {
129
+ delete item.prev;
130
+ }
131
+ delete item.el.__vueShortcutHandler__;
132
+ }
133
+
134
+ // 判断元素是否可见的辅助函数
135
+ const isElementVisible = (el: HTMLElement) => {
136
+ // 检查元素或其父元素是否被隐藏
137
+ if (el.offsetParent === null) {
138
+ return false; // 如果 offsetParent 为 null,说明元素或其父元素被隐藏
139
+ }
140
+
141
+ // 检查元素是否在视口内
142
+ const rect = el.getBoundingClientRect();
143
+ const win = window.rawWindow ?? window;
144
+ return (
145
+ rect.top <= win.innerHeight &&
146
+ rect.bottom >= 0 &&
147
+ rect.left <= win.innerWidth &&
148
+ rect.right >= 0
149
+ );
150
+ };
151
+
152
+ // 配置 Intersection Observer
153
+ const observerOption = {
154
+ root: null, // 默认为视口
155
+ rootMargin: '0px',
156
+ threshold: 0.1, // 当 10% 的元素可见时触发
157
+ };
158
+ /**
159
+ * 支持对元素标签点击事件添加快捷键触发,完整的写法:
160
+ * <div v-shortcut:Alt+N="() => doClick()"></div>
161
+ * 如果元素已经定义了click事件,那么可以简写为
162
+ * <div v-shortcut:Alt+N @click="doClick"><div>
163
+ */
164
+ export default {
165
+ mounted(el: HTMLElement, binding: DirectiveBinding<ShortCutCallback>, vNode: VNode) {
166
+ // 如果元素已经可见,直接注册快捷键
167
+ if (isElementVisible(el)) {
168
+ registerShortcut(binding, el, vNode);
169
+ }
170
+ // 回调函数,处理可见性变化
171
+ const callback = (entries) => {
172
+ entries.forEach((entry) => {
173
+ if (entry.isIntersecting) {
174
+ // 元素可见时触发
175
+ registerShortcut(binding, el, vNode);
176
+ } else {
177
+ // 元素不可见时触发
178
+ unregisterShortcut(el);
179
+ }
180
+ });
181
+ };
182
+ // 创建观察器
183
+ const observer = new IntersectionObserver(callback, observerOption);
184
+ el.__visibilityObserver__ = observer; // 将观察器挂载到元素上,便于卸载时使用
185
+ observer.observe(el); // 开始观察
186
+ },
187
+ unmounted(el: HTMLElement) {
188
+ el.__visibilityObserver__.disconnect();
189
+ delete el.__visibilityObserver__;
190
+ unregisterShortcut(el);
191
+ }
192
+ };
@@ -1,34 +1,34 @@
1
- import {type AppInstance, createAxiosWithoutCache, useAppApi} from "@jari-ace/app-bolts";
2
-
3
-
4
- let appCache: AppInstance[] = [];
5
-
6
- export async function useAppInstances() {
7
- const axios = createAxiosWithoutCache()
8
- const api = useAppApi(axios)
9
- if (appCache.length === 0) {
10
- appCache = await api.getAll(true);
11
- }
12
- return {
13
- async getById(appId: string) {
14
- let app = appCache.find(a => a.id === appId);
15
- if (!app) {
16
- app = await api.getById(appId);
17
- if (app) {
18
- appCache.push(app);
19
- }
20
- }
21
- return app;
22
- },
23
- async getByName(appName: string) {
24
- let app = appCache.find(a => a.name === appName);
25
- if (!app) {
26
- app = await api.getByName(appName);
27
- if (app) {
28
- appCache.push(app);
29
- }
30
- }
31
- return app;
32
- }
33
- }
34
- }
1
+ import {type AppInstance, createAxiosWithoutCache, useAppApi} from "@jari-ace/app-bolts";
2
+
3
+
4
+ let appCache: AppInstance[] = [];
5
+
6
+ export async function useAppInstances() {
7
+ const axios = createAxiosWithoutCache()
8
+ const api = useAppApi(axios)
9
+ if (appCache.length === 0) {
10
+ appCache = await api.getAll(true);
11
+ }
12
+ return {
13
+ async getById(appId: string) {
14
+ let app = appCache.find(a => a.id === appId);
15
+ if (!app) {
16
+ app = await api.getById(appId);
17
+ if (app) {
18
+ appCache.push(app);
19
+ }
20
+ }
21
+ return app;
22
+ },
23
+ async getByName(appName: string) {
24
+ let app = appCache.find(a => a.name === appName);
25
+ if (!app) {
26
+ app = await api.getByName(appName);
27
+ if (app) {
28
+ appCache.push(app);
29
+ }
30
+ }
31
+ return app;
32
+ }
33
+ }
34
+ }