@kine-design/core 0.0.1-beta.10 → 0.0.1-beta.11
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/.vlaude/last-session-id +1 -1
- package/components/base/autoComplete/api.ts +1 -1
- package/components/base/cascader/api.ts +1 -1
- package/components/base/datePicker/__tests__/useDatePicker.test.ts +8 -17
- package/components/base/datePicker/api.ts +1 -1
- package/components/base/datePicker/index.ts +1 -1
- package/components/base/datePicker/useDatePicker.ts +1 -18
- package/components/base/empty/api.ts +1 -1
- package/components/base/select/api.ts +1 -1
- package/components/base/timePicker/__tests__/useTimePicker.test.ts +5 -4
- package/components/base/timePicker/api.ts +1 -1
- package/components/base/timePicker/useTimePicker.ts +1 -1
- package/components/base/tooltip/api.ts +2 -3
- package/components/base/tooltip/index.ts +2 -3
- package/components/base/tooltip/props.d.ts +6 -12
- package/components/base/tooltip/useTooltip.ts +56 -175
- package/components/base/transfer/api.ts +2 -2
- package/components/message/confirm/api.ts +2 -2
- package/compositions/common/useLocale.ts +53 -0
- package/dist/components/base/datePicker/index.d.ts +1 -1
- package/dist/components/base/datePicker/useDatePicker.d.ts +0 -7
- package/dist/components/base/tooltip/index.d.ts +0 -1
- package/dist/components/base/tooltip/useTooltip.d.ts +17 -20
- package/dist/compositions/common/useLocale.d.ts +14 -0
- package/dist/core.js +498 -851
- package/dist/index.d.ts +2 -1
- package/dist/locale/en.d.ts +3 -0
- package/dist/locale/index.d.ts +9 -0
- package/dist/locale/types.d.ts +222 -0
- package/dist/locale/zh.d.ts +3 -0
- package/index.ts +9 -1
- package/locale/.vlaude/last-session-id +1 -0
- package/locale/en.ts +187 -0
- package/locale/index.ts +29 -0
- package/locale/types.ts +214 -0
- package/locale/zh.ts +190 -0
- package/package.json +19 -32
- package/.vlaude/session-switch.signal +0 -1
- package/compositions/commandPalette/index.ts +0 -11
- package/compositions/commandPalette/types.ts +0 -29
- package/compositions/commandPalette/useCommandPalette.ts +0 -135
- package/compositions/contextMenu/index.ts +0 -10
- package/compositions/contextMenu/types.ts +0 -21
- package/compositions/contextMenu/useContextMenu.ts +0 -101
- package/compositions/editor/index.ts +0 -18
- package/compositions/editor/types.ts +0 -147
- package/compositions/editor/useEditor.ts +0 -224
- package/compositions/index.ts +0 -15
- package/compositions/overlay/index.ts +0 -14
- package/compositions/overlay/useOverlayStack.ts +0 -146
- package/compositions/peekView/index.ts +0 -10
- package/compositions/peekView/usePeekView.ts +0 -99
- package/compositions/theme/index.ts +0 -17
- package/compositions/theme/presets/compact.ts +0 -117
- package/compositions/theme/presets/dark.ts +0 -113
- package/compositions/theme/presets/index.ts +0 -11
- package/compositions/theme/presets/light.ts +0 -113
- package/compositions/theme/types.ts +0 -46
- package/compositions/theme/useTheme.ts +0 -269
- package/compositions/toast/index.ts +0 -10
- package/compositions/toast/useToast.ts +0 -176
- package/compositions/tooltip/index.ts +0 -9
- package/compositions/tooltip/useTooltip.ts +0 -10
- package/dist/compositions/commandPalette/index.d.ts +0 -11
- package/dist/compositions/commandPalette/types.d.ts +0 -20
- package/dist/compositions/commandPalette/useCommandPalette.d.ts +0 -32
- package/dist/compositions/contextMenu/index.d.ts +0 -10
- package/dist/compositions/contextMenu/types.d.ts +0 -12
- package/dist/compositions/contextMenu/useContextMenu.d.ts +0 -52
- package/dist/compositions/editor/index.d.ts +0 -10
- package/dist/compositions/editor/types.d.ts +0 -132
- package/dist/compositions/editor/useEditor.d.ts +0 -13
- package/dist/compositions/index.d.ts +0 -15
- package/dist/compositions/overlay/index.d.ts +0 -10
- package/dist/compositions/overlay/useOverlayStack.d.ts +0 -188
- package/dist/compositions/peekView/index.d.ts +0 -10
- package/dist/compositions/peekView/usePeekView.d.ts +0 -16
- package/dist/compositions/theme/index.d.ts +0 -11
- package/dist/compositions/theme/presets/compact.d.ts +0 -6
- package/dist/compositions/theme/presets/dark.d.ts +0 -2
- package/dist/compositions/theme/presets/index.d.ts +0 -11
- package/dist/compositions/theme/presets/light.d.ts +0 -2
- package/dist/compositions/theme/types.d.ts +0 -41
- package/dist/compositions/theme/useTheme.d.ts +0 -167
- package/dist/compositions/toast/index.d.ts +0 -10
- package/dist/compositions/toast/useToast.d.ts +0 -71
- package/dist/compositions/tooltip/index.d.ts +0 -9
- package/dist/compositions/tooltip/useTooltip.d.ts +0 -10
package/locale/zh.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description Chinese (zh) language pack — the historical default. Strings are
|
|
3
|
+
* lifted verbatim from the components they replace, so existing zh behaviour
|
|
4
|
+
* is preserved exactly. One deliberate fix: `weekNames` previously rendered
|
|
5
|
+
* financial numerals (壹/贰/叁…) which was placeholder data leaked into prod.
|
|
6
|
+
* @author kine-design
|
|
7
|
+
* @version v1.0.0
|
|
8
|
+
*/
|
|
9
|
+
import type { KineLocaleMessages } from './types';
|
|
10
|
+
|
|
11
|
+
const zh: KineLocaleMessages = {
|
|
12
|
+
common: {
|
|
13
|
+
confirm: '确定',
|
|
14
|
+
cancel: '取消',
|
|
15
|
+
close: '关闭',
|
|
16
|
+
search: '搜索',
|
|
17
|
+
reset: '重置',
|
|
18
|
+
all: '全部',
|
|
19
|
+
noData: '暂无数据',
|
|
20
|
+
loading: '加载中...',
|
|
21
|
+
save: '保存',
|
|
22
|
+
},
|
|
23
|
+
pagination: {
|
|
24
|
+
totalPrefix: '共 ',
|
|
25
|
+
totalSuffix: ' 条',
|
|
26
|
+
},
|
|
27
|
+
datePicker: {
|
|
28
|
+
placeholder: '请选择日期...',
|
|
29
|
+
year: (year) => `${year}年`,
|
|
30
|
+
month: (month) => `${month}月`,
|
|
31
|
+
hour: '时',
|
|
32
|
+
minute: '分',
|
|
33
|
+
second: '秒',
|
|
34
|
+
confirm: '确定',
|
|
35
|
+
weekNames: ['日', '一', '二', '三', '四', '五', '六'],
|
|
36
|
+
monthNames: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
|
|
37
|
+
},
|
|
38
|
+
timePicker: {
|
|
39
|
+
placeholder: '请选择时间...',
|
|
40
|
+
hour: '时',
|
|
41
|
+
minute: '分',
|
|
42
|
+
second: '秒',
|
|
43
|
+
},
|
|
44
|
+
select: {
|
|
45
|
+
placeholder: '请选择...',
|
|
46
|
+
clear: '清空',
|
|
47
|
+
noData: '暂无数据',
|
|
48
|
+
loading: '加载中...',
|
|
49
|
+
},
|
|
50
|
+
autoComplete: {
|
|
51
|
+
placeholder: '请输入...',
|
|
52
|
+
loading: '加载中',
|
|
53
|
+
clear: '清空',
|
|
54
|
+
noData: '暂无建议',
|
|
55
|
+
},
|
|
56
|
+
cascader: {
|
|
57
|
+
placeholder: '请选择',
|
|
58
|
+
noMatch: '暂无匹配数据',
|
|
59
|
+
},
|
|
60
|
+
image: {
|
|
61
|
+
loadError: '加载失败',
|
|
62
|
+
zoomOut: '缩小',
|
|
63
|
+
zoomIn: '放大',
|
|
64
|
+
rotate: '旋转',
|
|
65
|
+
close: '关闭',
|
|
66
|
+
},
|
|
67
|
+
transfer: {
|
|
68
|
+
sourceTitle: '源列表',
|
|
69
|
+
targetTitle: '目标列表',
|
|
70
|
+
noData: '暂无数据',
|
|
71
|
+
filterPlaceholder: '请输入搜索内容',
|
|
72
|
+
},
|
|
73
|
+
empty: {
|
|
74
|
+
description: '暂无数据',
|
|
75
|
+
},
|
|
76
|
+
a11y: {
|
|
77
|
+
rate: '评分',
|
|
78
|
+
tagClose: '关闭',
|
|
79
|
+
anchorNav: '锚点导航',
|
|
80
|
+
backTop: '回到顶部',
|
|
81
|
+
carouselPrev: '上一张',
|
|
82
|
+
carouselNext: '下一张',
|
|
83
|
+
toLightMode: '切换到亮色模式',
|
|
84
|
+
toDarkMode: '切换到暗色模式',
|
|
85
|
+
expandSider: '展开侧边栏',
|
|
86
|
+
collapseSider: '折叠侧边栏',
|
|
87
|
+
},
|
|
88
|
+
upload: {
|
|
89
|
+
trigger: '点击或拖拽文件到此处上传',
|
|
90
|
+
triggerSimple: '点击上传文件',
|
|
91
|
+
oversize: (name, max) =>
|
|
92
|
+
max ? `文件 "${name}" 超过大小限制(最大 ${max})` : `文件 "${name}" 超过大小限制`,
|
|
93
|
+
uploadFailed: '上传失败',
|
|
94
|
+
statusWaiting: '等待中',
|
|
95
|
+
statusUploading: '上传中',
|
|
96
|
+
statusDone: '已完成',
|
|
97
|
+
statusFailed: '上传失败',
|
|
98
|
+
},
|
|
99
|
+
searchTable: {
|
|
100
|
+
search: '搜索',
|
|
101
|
+
reset: '重置',
|
|
102
|
+
},
|
|
103
|
+
editableTable: {
|
|
104
|
+
summary: '合计',
|
|
105
|
+
addRow: '+ 添加行',
|
|
106
|
+
addFirstRow: '添加第一行',
|
|
107
|
+
confirmDelete: '确定删除这一行?',
|
|
108
|
+
delete: '删除',
|
|
109
|
+
cancel: '取消',
|
|
110
|
+
noData: '暂无数据',
|
|
111
|
+
},
|
|
112
|
+
formPage: {
|
|
113
|
+
loading: '加载中...',
|
|
114
|
+
cancel: '取消',
|
|
115
|
+
saveDraft: '保存草稿',
|
|
116
|
+
save: '保存',
|
|
117
|
+
saving: '保存中...',
|
|
118
|
+
submit: '提交',
|
|
119
|
+
submitting: '提交中...',
|
|
120
|
+
basicInfo: '基本信息',
|
|
121
|
+
editTitle: (title) => `编辑${title}`,
|
|
122
|
+
createTitle: (title) => `新建${title}`,
|
|
123
|
+
},
|
|
124
|
+
approvalDialog: {
|
|
125
|
+
submitTitle: '提交审批',
|
|
126
|
+
submitConfirm: '确认提交',
|
|
127
|
+
approveTitle: '审批通过',
|
|
128
|
+
approveConfirm: '确认通过',
|
|
129
|
+
rejectTitle: '驳回申请',
|
|
130
|
+
rejectConfirm: '确认驳回',
|
|
131
|
+
rejectPlaceholder: '请输入驳回原因...',
|
|
132
|
+
remarkPlaceholder: '添加备注(可选)...',
|
|
133
|
+
required: '* 必填',
|
|
134
|
+
cancel: '取消',
|
|
135
|
+
processing: '处理中...',
|
|
136
|
+
},
|
|
137
|
+
crudPage: {
|
|
138
|
+
all: '全部',
|
|
139
|
+
fieldPlaceholder: (label) => `请输入${label}`,
|
|
140
|
+
},
|
|
141
|
+
login: {
|
|
142
|
+
username: '用户名',
|
|
143
|
+
usernamePlaceholder: '请输入用户名',
|
|
144
|
+
password: '密码',
|
|
145
|
+
passwordPlaceholder: '请输入密码',
|
|
146
|
+
remember: '记住我',
|
|
147
|
+
login: '登 录',
|
|
148
|
+
loggingIn: '登录中...',
|
|
149
|
+
},
|
|
150
|
+
form: {
|
|
151
|
+
inputPlaceholder: (label) => `请输入${label}`,
|
|
152
|
+
selectPlaceholder: (label) => `请选择${label}`,
|
|
153
|
+
},
|
|
154
|
+
routes: {
|
|
155
|
+
createSuffix: ' - 新建',
|
|
156
|
+
editSuffix: ' - 编辑',
|
|
157
|
+
detailSuffix: ' - 详情',
|
|
158
|
+
},
|
|
159
|
+
request: {
|
|
160
|
+
success: '操作成功',
|
|
161
|
+
opFailed: '操作失败',
|
|
162
|
+
failed: '请求失败',
|
|
163
|
+
failedWithStatus: (status) => `请求失败(${status})`,
|
|
164
|
+
failedWithMsg: (msg) => `请求失败: ${msg}`,
|
|
165
|
+
timeout: '请求超时',
|
|
166
|
+
timeoutRetry: '请求超时,请稍后重试',
|
|
167
|
+
canceled: '请求已取消',
|
|
168
|
+
permissionDenied: '权限不足,无法执行此操作',
|
|
169
|
+
invalidUrl: (url) => `无效的请求地址: ${url}`,
|
|
170
|
+
decodeFailed: (reason) => `解码失败: ${reason}`,
|
|
171
|
+
parseFailed: '数据解析失败',
|
|
172
|
+
networkError: '网络错误',
|
|
173
|
+
networkException: '网络异常,请检查网络连接',
|
|
174
|
+
unknownError: (error) => `未知错误: ${error}`,
|
|
175
|
+
unknown: '发生了未知错误',
|
|
176
|
+
uploadFailed: '上传失败',
|
|
177
|
+
uploadCanceled: '上传已取消',
|
|
178
|
+
},
|
|
179
|
+
aiChat: {
|
|
180
|
+
inputPlaceholder: '输入消息…',
|
|
181
|
+
send: '发送',
|
|
182
|
+
defaultTitle: (n) => `对话 ${n}`,
|
|
183
|
+
phaseTyping: '正在输入…',
|
|
184
|
+
phaseThinking: '思考中…',
|
|
185
|
+
phaseReplying: '回复中…',
|
|
186
|
+
phaseSending: '发送中…',
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
export default zh;
|
package/package.json
CHANGED
|
@@ -1,51 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kine-design/core",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.11",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "
|
|
7
|
-
"types": "index.ts",
|
|
8
|
-
"scripts": {
|
|
9
|
-
"build": "vite build --config vite.config.build.ts",
|
|
10
|
-
"test": "vitest --config vitest.config.ts --run"
|
|
11
|
-
},
|
|
6
|
+
"main": "./dist/core.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
12
8
|
"peerDependencies": {
|
|
13
|
-
"pinia": "^3.0.0",
|
|
14
9
|
"vue": "^3.5.30"
|
|
15
10
|
},
|
|
16
11
|
"dependencies": {
|
|
17
12
|
"@floating-ui/dom": "^1.7.6",
|
|
18
|
-
"@tiptap/core": "^2.12.0",
|
|
19
|
-
"@tiptap/extension-code-block-lowlight": "^2.12.0",
|
|
20
|
-
"@tiptap/extension-image": "^2.12.0",
|
|
21
|
-
"@tiptap/extension-link": "^2.12.0",
|
|
22
|
-
"@tiptap/extension-placeholder": "^2.12.0",
|
|
23
|
-
"@tiptap/extension-text-align": "^2.12.0",
|
|
24
|
-
"@tiptap/pm": "^2.12.0",
|
|
25
|
-
"@tiptap/starter-kit": "^2.12.0",
|
|
26
|
-
"@tiptap/vue-3": "^2.12.0",
|
|
27
13
|
"dayjs": "^1.11.20",
|
|
28
|
-
"interactjs": "^1.10.26"
|
|
29
|
-
"lowlight": "^3.2.0"
|
|
14
|
+
"interactjs": "^1.10.26"
|
|
30
15
|
},
|
|
31
16
|
"publishConfig": {
|
|
32
17
|
"access": "public",
|
|
33
18
|
"files": [
|
|
34
19
|
"dist"
|
|
35
|
-
]
|
|
36
|
-
"main": "./dist/core.js",
|
|
37
|
-
"module": "./dist/core.js",
|
|
38
|
-
"types": "./dist/index.d.ts",
|
|
39
|
-
"exports": {
|
|
40
|
-
".": {
|
|
41
|
-
"import": {
|
|
42
|
-
"types": "./dist/index.d.ts",
|
|
43
|
-
"default": "./dist/core.js"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
20
|
+
]
|
|
47
21
|
},
|
|
48
22
|
"devDependencies": {
|
|
49
23
|
"vitest": "^4.1.0"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "vite build --config vite.config.build.ts",
|
|
27
|
+
"test": "vitest --config vitest.config.ts --run"
|
|
28
|
+
},
|
|
29
|
+
"module": "./dist/core.js",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"import": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"default": "./dist/core.js"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
50
37
|
}
|
|
51
|
-
}
|
|
38
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"previousSessionId":"df71de08-cd98-459a-a68b-575554f7a6ed","currentSessionId":"dd5e7d65-f4f9-4e97-acdf-d3bb42303812","timestamp":1778142522500}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description commandPalette composition barrel export
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
-
*/
|
|
9
|
-
export { useCommandPalette } from './useCommandPalette';
|
|
10
|
-
export type { UseCommandPaletteReturn } from './useCommandPalette';
|
|
11
|
-
export type { Command } from './types';
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description CommandPalette command type definitions
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
-
*/
|
|
9
|
-
import type { VNode } from 'vue';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* A single command registered in the palette.
|
|
13
|
-
*/
|
|
14
|
-
export interface Command {
|
|
15
|
-
/** Unique identifier */
|
|
16
|
-
id: string;
|
|
17
|
-
/** Display label (also used for search) */
|
|
18
|
-
label: string;
|
|
19
|
-
/** Optional icon render function */
|
|
20
|
-
icon?: () => VNode;
|
|
21
|
-
/** Additional search terms beyond the label */
|
|
22
|
-
keywords?: string[];
|
|
23
|
-
/** Grouping category (e.g. "Navigation", "Actions") */
|
|
24
|
-
group?: string;
|
|
25
|
-
/** Shortcut hint text displayed on the right side of the item */
|
|
26
|
-
shortcut?: string;
|
|
27
|
-
/** Callback executed when the command is selected */
|
|
28
|
-
action: () => void;
|
|
29
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description CommandPalette composable — global search + command execution
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
-
*
|
|
9
|
-
* Manages open/close state, command registration, query filtering, and execution.
|
|
10
|
-
* Does NOT participate in overlayStack — fixed z-index 9500.
|
|
11
|
-
*/
|
|
12
|
-
import { ref, computed, type Ref, type ComputedRef } from 'vue';
|
|
13
|
-
import type { Command } from './types';
|
|
14
|
-
|
|
15
|
-
export interface UseCommandPaletteReturn {
|
|
16
|
-
/** Whether the palette is open */
|
|
17
|
-
isOpen: Ref<boolean>;
|
|
18
|
-
/** Current search query */
|
|
19
|
-
query: Ref<string>;
|
|
20
|
-
/** Index of the currently highlighted item */
|
|
21
|
-
activeIndex: Ref<number>;
|
|
22
|
-
/** All registered commands */
|
|
23
|
-
commands: Ref<Command[]>;
|
|
24
|
-
/** Filtered commands based on query */
|
|
25
|
-
filtered: ComputedRef<Command[]>;
|
|
26
|
-
/** Open the palette */
|
|
27
|
-
open: () => void;
|
|
28
|
-
/** Close the palette */
|
|
29
|
-
close: () => void;
|
|
30
|
-
/** Toggle open/close */
|
|
31
|
-
toggle: () => void;
|
|
32
|
-
/** Register a command */
|
|
33
|
-
registerCommand: (cmd: Command) => void;
|
|
34
|
-
/** Unregister a command by id */
|
|
35
|
-
unregisterCommand: (id: string) => void;
|
|
36
|
-
/** Execute the command at a given index in the filtered list, then close */
|
|
37
|
-
execute: (index: number) => void;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* CommandPalette composable
|
|
42
|
-
*
|
|
43
|
-
* Provides reactive state for opening, searching, and executing commands.
|
|
44
|
-
*/
|
|
45
|
-
export function useCommandPalette(): UseCommandPaletteReturn {
|
|
46
|
-
const isOpen = ref(false);
|
|
47
|
-
const query = ref('');
|
|
48
|
-
const activeIndex = ref(0);
|
|
49
|
-
const commands = ref<Command[]>([]);
|
|
50
|
-
|
|
51
|
-
/** element that had focus before the palette opened */
|
|
52
|
-
let previousActiveElement: Element | null = null;
|
|
53
|
-
|
|
54
|
-
const open = () => {
|
|
55
|
-
previousActiveElement = document.activeElement;
|
|
56
|
-
isOpen.value = true;
|
|
57
|
-
query.value = '';
|
|
58
|
-
activeIndex.value = 0;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const close = () => {
|
|
62
|
-
isOpen.value = false;
|
|
63
|
-
query.value = '';
|
|
64
|
-
activeIndex.value = 0;
|
|
65
|
-
// restore focus to the previously focused element
|
|
66
|
-
if (previousActiveElement && previousActiveElement instanceof HTMLElement) {
|
|
67
|
-
previousActiveElement.focus();
|
|
68
|
-
}
|
|
69
|
-
previousActiveElement = null;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const toggle = () => {
|
|
73
|
-
if (isOpen.value) {
|
|
74
|
-
close();
|
|
75
|
-
} else {
|
|
76
|
-
open();
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const registerCommand = (cmd: Command) => {
|
|
81
|
-
// prevent duplicates
|
|
82
|
-
const exists = commands.value.some(c => c.id === cmd.id);
|
|
83
|
-
if (!exists) {
|
|
84
|
-
commands.value.push(cmd);
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const unregisterCommand = (id: string) => {
|
|
89
|
-
const idx = commands.value.findIndex(c => c.id === id);
|
|
90
|
-
if (idx !== -1) {
|
|
91
|
-
commands.value.splice(idx, 1);
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Simple case-insensitive substring match on label + keywords.
|
|
97
|
-
*/
|
|
98
|
-
const filtered = computed<Command[]>(() => {
|
|
99
|
-
const q = query.value.trim().toLowerCase();
|
|
100
|
-
if (!q) {
|
|
101
|
-
return commands.value;
|
|
102
|
-
}
|
|
103
|
-
return commands.value.filter(cmd => {
|
|
104
|
-
if (cmd.label.toLowerCase().includes(q)) {
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
if (cmd.keywords) {
|
|
108
|
-
return cmd.keywords.some(kw => kw.toLowerCase().includes(q));
|
|
109
|
-
}
|
|
110
|
-
return false;
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
const execute = (index: number) => {
|
|
115
|
-
const cmd = filtered.value[index];
|
|
116
|
-
if (cmd) {
|
|
117
|
-
close();
|
|
118
|
-
cmd.action();
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
return {
|
|
123
|
-
isOpen,
|
|
124
|
-
query,
|
|
125
|
-
activeIndex,
|
|
126
|
-
commands,
|
|
127
|
-
filtered,
|
|
128
|
-
open,
|
|
129
|
-
close,
|
|
130
|
-
toggle,
|
|
131
|
-
registerCommand,
|
|
132
|
-
unregisterCommand,
|
|
133
|
-
execute,
|
|
134
|
-
};
|
|
135
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description context menu types
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
-
*/
|
|
9
|
-
import type { VNode } from 'vue';
|
|
10
|
-
|
|
11
|
-
export interface MenuItem {
|
|
12
|
-
key: string;
|
|
13
|
-
label: string;
|
|
14
|
-
icon?: () => VNode;
|
|
15
|
-
action: () => void;
|
|
16
|
-
visible?: boolean;
|
|
17
|
-
disabled?: boolean;
|
|
18
|
-
danger?: boolean;
|
|
19
|
-
children?: MenuItem[];
|
|
20
|
-
separator?: boolean;
|
|
21
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description context menu composable — manages open/close state, positioning, and keyboard navigation
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
-
*/
|
|
9
|
-
import { ref, computed } from 'vue';
|
|
10
|
-
import type { MenuItem } from './types';
|
|
11
|
-
|
|
12
|
-
export function useContextMenu() {
|
|
13
|
-
const isOpen = ref(false);
|
|
14
|
-
const position = ref({ x: 0, y: 0 });
|
|
15
|
-
const items = ref<MenuItem[]>([]);
|
|
16
|
-
const activeIndex = ref(-1);
|
|
17
|
-
|
|
18
|
-
const visibleItems = computed(() =>
|
|
19
|
-
items.value.filter(item => item.visible !== false),
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
const open = (event: MouseEvent, menuItems: MenuItem[]) => {
|
|
23
|
-
event.preventDefault();
|
|
24
|
-
event.stopPropagation();
|
|
25
|
-
|
|
26
|
-
items.value = menuItems;
|
|
27
|
-
activeIndex.value = -1;
|
|
28
|
-
|
|
29
|
-
// Calculate position with viewport edge flipping
|
|
30
|
-
const x = event.clientX;
|
|
31
|
-
const y = event.clientY;
|
|
32
|
-
|
|
33
|
-
position.value = { x, y };
|
|
34
|
-
isOpen.value = true;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const close = () => {
|
|
38
|
-
isOpen.value = false;
|
|
39
|
-
activeIndex.value = -1;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const moveUp = () => {
|
|
43
|
-
const visible = visibleItems.value;
|
|
44
|
-
if (visible.length === 0) return;
|
|
45
|
-
|
|
46
|
-
let next = activeIndex.value - 1;
|
|
47
|
-
// Skip separators
|
|
48
|
-
while (next >= 0 && visible[next]?.separator) {
|
|
49
|
-
next--;
|
|
50
|
-
}
|
|
51
|
-
if (next < 0) {
|
|
52
|
-
// Wrap to last non-separator item
|
|
53
|
-
next = visible.length - 1;
|
|
54
|
-
while (next >= 0 && visible[next]?.separator) {
|
|
55
|
-
next--;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
activeIndex.value = next;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const moveDown = () => {
|
|
62
|
-
const visible = visibleItems.value;
|
|
63
|
-
if (visible.length === 0) return;
|
|
64
|
-
|
|
65
|
-
let next = activeIndex.value + 1;
|
|
66
|
-
// Skip separators
|
|
67
|
-
while (next < visible.length && visible[next]?.separator) {
|
|
68
|
-
next++;
|
|
69
|
-
}
|
|
70
|
-
if (next >= visible.length) {
|
|
71
|
-
// Wrap to first non-separator item
|
|
72
|
-
next = 0;
|
|
73
|
-
while (next < visible.length && visible[next]?.separator) {
|
|
74
|
-
next++;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
activeIndex.value = next;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const executeCurrent = () => {
|
|
81
|
-
const visible = visibleItems.value;
|
|
82
|
-
const item = visible[activeIndex.value];
|
|
83
|
-
if (item && !item.disabled && !item.separator) {
|
|
84
|
-
item.action();
|
|
85
|
-
close();
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
return {
|
|
90
|
-
isOpen,
|
|
91
|
-
position,
|
|
92
|
-
items,
|
|
93
|
-
activeIndex,
|
|
94
|
-
visibleItems,
|
|
95
|
-
open,
|
|
96
|
-
close,
|
|
97
|
-
moveUp,
|
|
98
|
-
moveDown,
|
|
99
|
-
executeCurrent,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description Editor composition barrel export
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* Headless editor composable — provides logic, no rendering.
|
|
8
|
-
*/
|
|
9
|
-
export { useEditor } from './useEditor';
|
|
10
|
-
export type {
|
|
11
|
-
UseEditorOptions,
|
|
12
|
-
EditorConfig,
|
|
13
|
-
EditorToolbarConfig,
|
|
14
|
-
EditorExtensionConfig,
|
|
15
|
-
EditorToolbarActions,
|
|
16
|
-
EditorActiveState,
|
|
17
|
-
UseEditorReturn,
|
|
18
|
-
} from './types';
|