@jari-ace/element-plus-component 0.2.2 → 0.2.3

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 (124) hide show
  1. package/README.md +1 -1
  2. package/dist/components/rolePicker/baseRolePicker.vue.d.ts.map +1 -1
  3. package/dist/components/rolePicker/baseRolePicker.vue.js +4 -2
  4. package/dist/components/rolePicker/baseRolePicker.vue.js.map +1 -1
  5. package/lib/index.css +1 -1
  6. package/lib/index.js +297 -297
  7. package/lib/index.umd.cjs +2 -2
  8. package/package.json +61 -61
  9. package/packages/components/autoComplete/JaAutoComplete.vue +47 -47
  10. package/packages/components/autoComplete/index.ts +5 -5
  11. package/packages/components/avatar/JaAvatar.vue +126 -126
  12. package/packages/components/avatar/avatarToken.ts +11 -11
  13. package/packages/components/avatar/defaultImg.ts +14 -14
  14. package/packages/components/avatar/index.ts +7 -7
  15. package/packages/components/button/JaButton.vue +51 -51
  16. package/packages/components/button/index.ts +4 -4
  17. package/packages/components/channelPicker/index.ts +7 -7
  18. package/packages/components/channelPicker/src/ChannelPicker.vue +43 -43
  19. package/packages/components/channelPicker/src/JaChannelPicker.vue +42 -42
  20. package/packages/components/checkbox/JaCheckbox.vue +73 -73
  21. package/packages/components/checkbox/index.ts +4 -4
  22. package/packages/components/checkboxGroup/JaCheckboxGroup.vue +45 -45
  23. package/packages/components/checkboxGroup/index.ts +4 -4
  24. package/packages/components/customGroupTree/index.ts +10 -10
  25. package/packages/components/customGroupTree/src/customGroupTree.vue +91 -91
  26. package/packages/components/datePicker/JaDatePicker.vue +52 -52
  27. package/packages/components/datePicker/index.ts +4 -4
  28. package/packages/components/departmentPicker/index.ts +4 -4
  29. package/packages/components/departmentPicker/src/DepartmentPicker.vue +107 -107
  30. package/packages/components/departmentPicker/src/consts.ts +2 -2
  31. package/packages/components/departmentTree/index.ts +10 -10
  32. package/packages/components/departmentTree/src/departmentTree.vue +135 -135
  33. package/packages/components/dropdownButton/JaDropdownButton.vue +59 -59
  34. package/packages/components/dropdownButton/index.ts +4 -4
  35. package/packages/components/enumList/EnumListInput.vue +107 -107
  36. package/packages/components/enumList/JaEnumList.vue +39 -39
  37. package/packages/components/enumList/index.ts +7 -7
  38. package/packages/components/enumPicker/index.ts +5 -5
  39. package/packages/components/enumPicker/src/EnumPicker.vue +103 -103
  40. package/packages/components/form/JaForm.vue +146 -146
  41. package/packages/components/form/index.ts +5 -5
  42. package/packages/components/form/types.ts +4 -4
  43. package/packages/components/formItem/JaFormItem.vue +87 -87
  44. package/packages/components/formItem/index.ts +4 -4
  45. package/packages/components/index.ts +34 -34
  46. package/packages/components/input/JaInput.vue +143 -143
  47. package/packages/components/input/index.ts +4 -4
  48. package/packages/components/inputI18n/I18nBundleEditor.vue +76 -76
  49. package/packages/components/inputI18n/InputI18n.vue +146 -146
  50. package/packages/components/inputI18n/JaInputI18n.vue +50 -50
  51. package/packages/components/inputI18n/index.ts +8 -8
  52. package/packages/components/inputNumber/JaInputNumber.vue +98 -98
  53. package/packages/components/inputNumber/index.ts +4 -4
  54. package/packages/components/mapItemList/JaMapItemList.vue +35 -35
  55. package/packages/components/mapItemList/MapItemListInput.vue +191 -191
  56. package/packages/components/mapItemList/index.ts +7 -7
  57. package/packages/components/numberList/JaNumberList.vue +36 -36
  58. package/packages/components/numberList/NumberListInput.vue +111 -111
  59. package/packages/components/numberList/index.ts +7 -7
  60. package/packages/components/properyPicker/JaPropertyPicker.vue +38 -38
  61. package/packages/components/properyPicker/PropertyPicker.vue +314 -314
  62. package/packages/components/properyPicker/index.ts +7 -7
  63. package/packages/components/radioGroup/JaRadioGroup.vue +50 -50
  64. package/packages/components/radioGroup/index.ts +4 -4
  65. package/packages/components/rolePicker/RoleEditor.vue +129 -129
  66. package/packages/components/rolePicker/RolePicker.vue +44 -44
  67. package/packages/components/rolePicker/RolePickerRaw.vue +56 -56
  68. package/packages/components/rolePicker/baseRolePicker.vue +91 -87
  69. package/packages/components/rolePicker/index.ts +10 -10
  70. package/packages/components/scrollbar/Scrollbar.vue +89 -89
  71. package/packages/components/scrollbar/index.ts +5 -5
  72. package/packages/components/scrollbar/utils.ts +17 -17
  73. package/packages/components/select/JaSelect.vue +48 -48
  74. package/packages/components/select/index.ts +4 -4
  75. package/packages/components/stringList/JaStringList.vue +36 -36
  76. package/packages/components/stringList/StringListInput.vue +96 -96
  77. package/packages/components/stringList/index.ts +7 -7
  78. package/packages/components/switch/JaSwitch.vue +50 -50
  79. package/packages/components/switch/index.ts +4 -4
  80. package/packages/components/timePicker/JaTimePicker.vue +52 -52
  81. package/packages/components/timePicker/index.ts +5 -5
  82. package/packages/components/tip/index.ts +4 -4
  83. package/packages/components/tip/src/AceTip.vue +43 -43
  84. package/packages/components/upload/index.ts +6 -6
  85. package/packages/components/upload/src/Upload.vue +25 -25
  86. package/packages/components/upload/src/type.ts +3 -3
  87. package/packages/components/userGroupPicker/index.ts +4 -4
  88. package/packages/components/userGroupPicker/src/UserGroupPicker.vue +94 -94
  89. package/packages/components/userGroupTree/index.ts +10 -10
  90. package/packages/components/userGroupTree/src/userGroupTree.vue +149 -149
  91. package/packages/components/userPicker/index.ts +10 -10
  92. package/packages/components/userPicker/src/CustomGroupManager.vue +189 -189
  93. package/packages/components/userPicker/src/JaUserList.vue +317 -317
  94. package/packages/components/userPicker/src/JaUserPicker.vue +40 -40
  95. package/packages/components/userPicker/src/UserPicker.vue +472 -472
  96. package/packages/components/userSelectDialog/index.ts +6 -6
  97. package/packages/components/userSelectDialog/src/userSelectDialog.vue +462 -462
  98. package/packages/components/userTag/UserInfoTag.vue +397 -397
  99. package/packages/components/userTag/index.ts +6 -6
  100. package/packages/components/userTag/sharedAxios.ts +8 -8
  101. package/packages/directives/auth/index.ts +41 -41
  102. package/packages/directives/autofocus/index.ts +29 -29
  103. package/packages/directives/index.ts +10 -10
  104. package/packages/directives/shortcut/index.ts +192 -192
  105. package/packages/hooks/useAppInstances.ts +34 -34
  106. package/packages/hooks/useBackendValidations.ts +81 -81
  107. package/packages/hooks/useBridage.ts +157 -157
  108. package/packages/hooks/useClassificationLevels.ts +62 -62
  109. package/packages/hooks/useDateTimeShortCuts.ts +65 -65
  110. package/packages/hooks/useRealms.ts +28 -28
  111. package/packages/hooks/useTreeData.ts +45 -45
  112. package/packages/hooks/useUserRefQuery.ts +232 -232
  113. package/packages/index.ts +24 -24
  114. package/packages/list.json +7 -7
  115. package/packages/types/custom.d.ts +13 -13
  116. package/packages/types/window.d.ts +16 -16
  117. package/packages/utils/install.ts +43 -43
  118. package/packages/utils/objectUtils.ts +31 -31
  119. package/theme-style/fonts/iconfont.json +5196 -5196
  120. package/theme-style/index.scss +10 -10
  121. package/theme-style/styles/element-plus-var.scss +1419 -1419
  122. package/theme-style/styles/iconfont.css +2979 -2979
  123. package/theme-style/styles/theme-var.scss +72 -72
  124. package/theme-style/styles/transition.scss +122 -122
@@ -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
+ }