@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
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description Editor composition types
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* Type definitions for the rich text editor composable.
|
|
8
|
-
*/
|
|
9
|
-
import type { Editor } from '@tiptap/core';
|
|
10
|
-
import type { ShallowRef, Ref, ComputedRef } from 'vue';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Toolbar feature toggle. Each key controls visibility of a toolbar group.
|
|
14
|
-
* All default to true when omitted.
|
|
15
|
-
*/
|
|
16
|
-
export interface EditorToolbarConfig {
|
|
17
|
-
bold?: boolean;
|
|
18
|
-
italic?: boolean;
|
|
19
|
-
strike?: boolean;
|
|
20
|
-
code?: boolean;
|
|
21
|
-
heading?: boolean;
|
|
22
|
-
bulletList?: boolean;
|
|
23
|
-
orderedList?: boolean;
|
|
24
|
-
blockquote?: boolean;
|
|
25
|
-
codeBlock?: boolean;
|
|
26
|
-
link?: boolean;
|
|
27
|
-
image?: boolean;
|
|
28
|
-
textAlign?: boolean;
|
|
29
|
-
undo?: boolean;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Extension-level configuration that is forwarded to individual tiptap extensions.
|
|
34
|
-
*/
|
|
35
|
-
export interface EditorExtensionConfig {
|
|
36
|
-
link?: {
|
|
37
|
-
openOnClick?: boolean;
|
|
38
|
-
HTMLAttributes?: Record<string, string>;
|
|
39
|
-
};
|
|
40
|
-
image?: {
|
|
41
|
-
allowBase64?: boolean;
|
|
42
|
-
HTMLAttributes?: Record<string, string>;
|
|
43
|
-
};
|
|
44
|
-
placeholder?: {
|
|
45
|
-
text?: string;
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Top-level editor configuration passed via props.
|
|
51
|
-
*/
|
|
52
|
-
export interface EditorConfig {
|
|
53
|
-
toolbar?: EditorToolbarConfig;
|
|
54
|
-
extensions?: EditorExtensionConfig;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Options accepted by the useEditor composable.
|
|
59
|
-
*/
|
|
60
|
-
export interface UseEditorOptions {
|
|
61
|
-
/** Initial HTML or plain-text content */
|
|
62
|
-
content?: string;
|
|
63
|
-
/** When true the editor is not editable */
|
|
64
|
-
readonly?: boolean;
|
|
65
|
-
/** Placeholder text shown when the editor is empty */
|
|
66
|
-
placeholder?: string;
|
|
67
|
-
/** Feature configuration */
|
|
68
|
-
config?: EditorConfig;
|
|
69
|
-
/** Callback fired when content changes (HTML string) */
|
|
70
|
-
onUpdate?: (html: string) => void;
|
|
71
|
-
/** Callback fired when the editor is ready */
|
|
72
|
-
onReady?: () => void;
|
|
73
|
-
/** Callback fired on focus */
|
|
74
|
-
onFocus?: () => void;
|
|
75
|
-
/** Callback fired on blur */
|
|
76
|
-
onBlur?: () => void;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Toolbar action functions returned by the composable.
|
|
81
|
-
*/
|
|
82
|
-
export interface EditorToolbarActions {
|
|
83
|
-
toggleBold: () => void;
|
|
84
|
-
toggleItalic: () => void;
|
|
85
|
-
toggleStrike: () => void;
|
|
86
|
-
toggleCode: () => void;
|
|
87
|
-
setParagraph: () => void;
|
|
88
|
-
setHeading: (level: 1 | 2 | 3) => void;
|
|
89
|
-
toggleBulletList: () => void;
|
|
90
|
-
toggleOrderedList: () => void;
|
|
91
|
-
toggleBlockquote: () => void;
|
|
92
|
-
toggleCodeBlock: () => void;
|
|
93
|
-
setLink: (href: string) => void;
|
|
94
|
-
unsetLink: () => void;
|
|
95
|
-
setImage: (src: string, alt?: string) => void;
|
|
96
|
-
setTextAlign: (alignment: 'left' | 'center' | 'right') => void;
|
|
97
|
-
undo: () => void;
|
|
98
|
-
redo: () => void;
|
|
99
|
-
focus: () => void;
|
|
100
|
-
blur: () => void;
|
|
101
|
-
clear: () => void;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Active-state flags for toolbar highlighting.
|
|
106
|
-
*/
|
|
107
|
-
export interface EditorActiveState {
|
|
108
|
-
bold: boolean;
|
|
109
|
-
italic: boolean;
|
|
110
|
-
strike: boolean;
|
|
111
|
-
code: boolean;
|
|
112
|
-
paragraph: boolean;
|
|
113
|
-
heading1: boolean;
|
|
114
|
-
heading2: boolean;
|
|
115
|
-
heading3: boolean;
|
|
116
|
-
bulletList: boolean;
|
|
117
|
-
orderedList: boolean;
|
|
118
|
-
blockquote: boolean;
|
|
119
|
-
codeBlock: boolean;
|
|
120
|
-
link: boolean;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Return type of the useEditor composable.
|
|
125
|
-
*/
|
|
126
|
-
export interface UseEditorReturn {
|
|
127
|
-
/** The raw tiptap Editor instance (may be null before creation) */
|
|
128
|
-
editor: ShallowRef<Editor | undefined>;
|
|
129
|
-
/** Whether the editor has been created and is ready */
|
|
130
|
-
isReady: Ref<boolean>;
|
|
131
|
-
/** Toolbar action methods */
|
|
132
|
-
actions: ComputedRef<EditorToolbarActions | null>;
|
|
133
|
-
/** Active formatting state */
|
|
134
|
-
activeState: ComputedRef<EditorActiveState>;
|
|
135
|
-
/** Update editor content programmatically */
|
|
136
|
-
setContent: (html: string) => void;
|
|
137
|
-
/** Toggle the editable state */
|
|
138
|
-
setEditable: (editable: boolean) => void;
|
|
139
|
-
/** Get current content as HTML */
|
|
140
|
-
getHTML: () => string;
|
|
141
|
-
/** Get current content as plain text */
|
|
142
|
-
getText: () => string;
|
|
143
|
-
/** Whether undo is available */
|
|
144
|
-
canUndo: ComputedRef<boolean>;
|
|
145
|
-
/** Whether redo is available */
|
|
146
|
-
canRedo: ComputedRef<boolean>;
|
|
147
|
-
}
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description Headless editor composable built on tiptap
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* Provides editor state, toolbar actions, and active-state tracking
|
|
8
|
-
* without any rendering — the UI layer consumes this composable.
|
|
9
|
-
*/
|
|
10
|
-
import { ref, computed, onBeforeUnmount } from 'vue';
|
|
11
|
-
import { useEditor as useTiptapEditor } from '@tiptap/vue-3';
|
|
12
|
-
import StarterKit from '@tiptap/starter-kit';
|
|
13
|
-
import Link from '@tiptap/extension-link';
|
|
14
|
-
import Image from '@tiptap/extension-image';
|
|
15
|
-
import Placeholder from '@tiptap/extension-placeholder';
|
|
16
|
-
import TextAlign from '@tiptap/extension-text-align';
|
|
17
|
-
import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight';
|
|
18
|
-
import { common, createLowlight } from 'lowlight';
|
|
19
|
-
import type { UseEditorOptions, EditorToolbarActions, EditorActiveState } from './types';
|
|
20
|
-
|
|
21
|
-
const lowlight = createLowlight(common);
|
|
22
|
-
|
|
23
|
-
export function useEditor(options: UseEditorOptions = {}) {
|
|
24
|
-
const {
|
|
25
|
-
content = '',
|
|
26
|
-
readonly = false,
|
|
27
|
-
placeholder = 'Start typing...',
|
|
28
|
-
config = {},
|
|
29
|
-
onUpdate,
|
|
30
|
-
onReady,
|
|
31
|
-
onFocus,
|
|
32
|
-
onBlur,
|
|
33
|
-
} = options;
|
|
34
|
-
|
|
35
|
-
const isReady = ref(false);
|
|
36
|
-
|
|
37
|
-
// Build extension array based on config
|
|
38
|
-
const buildExtensions = () => {
|
|
39
|
-
const toolbar = config.toolbar ?? {};
|
|
40
|
-
const ext = config.extensions ?? {};
|
|
41
|
-
|
|
42
|
-
const extensions = [
|
|
43
|
-
StarterKit.configure({
|
|
44
|
-
heading: toolbar.heading !== false ? { levels: [1, 2, 3] } : false,
|
|
45
|
-
bold: toolbar.bold !== false ? {} : false,
|
|
46
|
-
italic: toolbar.italic !== false ? {} : false,
|
|
47
|
-
strike: toolbar.strike !== false ? {} : false,
|
|
48
|
-
code: toolbar.code !== false ? {} : false,
|
|
49
|
-
bulletList: toolbar.bulletList !== false ? {} : false,
|
|
50
|
-
orderedList: toolbar.orderedList !== false ? {} : false,
|
|
51
|
-
blockquote: toolbar.blockquote !== false ? {} : false,
|
|
52
|
-
// Disable the built-in code block — we use lowlight instead
|
|
53
|
-
codeBlock: false,
|
|
54
|
-
}),
|
|
55
|
-
Placeholder.configure({
|
|
56
|
-
placeholder: ext.placeholder?.text ?? placeholder,
|
|
57
|
-
}),
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
// Code block with syntax highlighting
|
|
61
|
-
if (toolbar.codeBlock !== false) {
|
|
62
|
-
extensions.push(
|
|
63
|
-
CodeBlockLowlight.configure({
|
|
64
|
-
lowlight,
|
|
65
|
-
HTMLAttributes: {
|
|
66
|
-
class: 'k-editor-code-block',
|
|
67
|
-
},
|
|
68
|
-
}),
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Link extension
|
|
73
|
-
if (toolbar.link !== false) {
|
|
74
|
-
extensions.push(
|
|
75
|
-
Link.configure({
|
|
76
|
-
openOnClick: ext.link?.openOnClick ?? false,
|
|
77
|
-
HTMLAttributes: {
|
|
78
|
-
class: 'k-editor-link',
|
|
79
|
-
...ext.link?.HTMLAttributes,
|
|
80
|
-
},
|
|
81
|
-
}),
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Image extension
|
|
86
|
-
if (toolbar.image !== false) {
|
|
87
|
-
extensions.push(
|
|
88
|
-
Image.configure({
|
|
89
|
-
inline: true,
|
|
90
|
-
allowBase64: ext.image?.allowBase64 ?? false,
|
|
91
|
-
HTMLAttributes: {
|
|
92
|
-
class: 'k-editor-image',
|
|
93
|
-
...ext.image?.HTMLAttributes,
|
|
94
|
-
},
|
|
95
|
-
}),
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Text alignment
|
|
100
|
-
if (toolbar.textAlign !== false) {
|
|
101
|
-
extensions.push(
|
|
102
|
-
TextAlign.configure({
|
|
103
|
-
types: ['heading', 'paragraph'],
|
|
104
|
-
}),
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return extensions;
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
// Create the tiptap editor
|
|
112
|
-
const editor = useTiptapEditor({
|
|
113
|
-
content,
|
|
114
|
-
editable: !readonly,
|
|
115
|
-
extensions: buildExtensions(),
|
|
116
|
-
onUpdate: ({ editor: e }) => {
|
|
117
|
-
onUpdate?.(e.getHTML());
|
|
118
|
-
},
|
|
119
|
-
onCreate: () => {
|
|
120
|
-
isReady.value = true;
|
|
121
|
-
onReady?.();
|
|
122
|
-
},
|
|
123
|
-
onFocus: () => {
|
|
124
|
-
onFocus?.();
|
|
125
|
-
},
|
|
126
|
-
onBlur: () => {
|
|
127
|
-
onBlur?.();
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// Toolbar actions
|
|
132
|
-
const actions = computed<EditorToolbarActions | null>(() => {
|
|
133
|
-
const e = editor.value;
|
|
134
|
-
if (!e) return null;
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
toggleBold: () => { e.chain().focus().toggleBold().run(); },
|
|
138
|
-
toggleItalic: () => { e.chain().focus().toggleItalic().run(); },
|
|
139
|
-
toggleStrike: () => { e.chain().focus().toggleStrike().run(); },
|
|
140
|
-
toggleCode: () => { e.chain().focus().toggleCode().run(); },
|
|
141
|
-
setParagraph: () => { e.chain().focus().setParagraph().run(); },
|
|
142
|
-
setHeading: (level: 1 | 2 | 3) => { e.chain().focus().toggleHeading({ level }).run(); },
|
|
143
|
-
toggleBulletList: () => { e.chain().focus().toggleBulletList().run(); },
|
|
144
|
-
toggleOrderedList: () => { e.chain().focus().toggleOrderedList().run(); },
|
|
145
|
-
toggleBlockquote: () => { e.chain().focus().toggleBlockquote().run(); },
|
|
146
|
-
toggleCodeBlock: () => { e.chain().focus().toggleCodeBlock().run(); },
|
|
147
|
-
setLink: (href: string) => { e.chain().focus().setLink({ href }).run(); },
|
|
148
|
-
unsetLink: () => { e.chain().focus().unsetLink().run(); },
|
|
149
|
-
setImage: (src: string, alt?: string) => { e.chain().focus().setImage({ src, alt }).run(); },
|
|
150
|
-
setTextAlign: (alignment: 'left' | 'center' | 'right') => {
|
|
151
|
-
e.chain().focus().setTextAlign(alignment).run();
|
|
152
|
-
},
|
|
153
|
-
undo: () => { e.chain().focus().undo().run(); },
|
|
154
|
-
redo: () => { e.chain().focus().redo().run(); },
|
|
155
|
-
focus: () => { e.chain().focus().run(); },
|
|
156
|
-
blur: () => { e.commands.blur(); },
|
|
157
|
-
clear: () => { e.chain().focus().clearContent().run(); },
|
|
158
|
-
};
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// Active state tracking
|
|
162
|
-
const activeState = computed<EditorActiveState>(() => {
|
|
163
|
-
const e = editor.value;
|
|
164
|
-
if (!e) {
|
|
165
|
-
return {
|
|
166
|
-
bold: false, italic: false, strike: false, code: false,
|
|
167
|
-
paragraph: false, heading1: false, heading2: false, heading3: false,
|
|
168
|
-
bulletList: false, orderedList: false, blockquote: false,
|
|
169
|
-
codeBlock: false, link: false,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
return {
|
|
173
|
-
bold: e.isActive('bold'),
|
|
174
|
-
italic: e.isActive('italic'),
|
|
175
|
-
strike: e.isActive('strike'),
|
|
176
|
-
code: e.isActive('code'),
|
|
177
|
-
paragraph: e.isActive('paragraph'),
|
|
178
|
-
heading1: e.isActive('heading', { level: 1 }),
|
|
179
|
-
heading2: e.isActive('heading', { level: 2 }),
|
|
180
|
-
heading3: e.isActive('heading', { level: 3 }),
|
|
181
|
-
bulletList: e.isActive('bulletList'),
|
|
182
|
-
orderedList: e.isActive('orderedList'),
|
|
183
|
-
blockquote: e.isActive('blockquote'),
|
|
184
|
-
codeBlock: e.isActive('codeBlock'),
|
|
185
|
-
link: e.isActive('link'),
|
|
186
|
-
};
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
const canUndo = computed(() => editor.value?.can().undo() ?? false);
|
|
190
|
-
const canRedo = computed(() => editor.value?.can().redo() ?? false);
|
|
191
|
-
|
|
192
|
-
// Content management
|
|
193
|
-
const setContent = (html: string) => {
|
|
194
|
-
if (!editor.value) return;
|
|
195
|
-
const current = editor.value.getHTML();
|
|
196
|
-
if (current === html) return;
|
|
197
|
-
editor.value.commands.setContent(html);
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
const setEditable = (editable: boolean) => {
|
|
201
|
-
editor.value?.setEditable(editable);
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
const getHTML = () => editor.value?.getHTML() ?? '';
|
|
205
|
-
const getText = () => editor.value?.getText() ?? '';
|
|
206
|
-
|
|
207
|
-
// Cleanup
|
|
208
|
-
onBeforeUnmount(() => {
|
|
209
|
-
editor.value?.destroy();
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
return {
|
|
213
|
-
editor,
|
|
214
|
-
isReady,
|
|
215
|
-
actions,
|
|
216
|
-
activeState,
|
|
217
|
-
setContent,
|
|
218
|
-
setEditable,
|
|
219
|
-
getHTML,
|
|
220
|
-
getText,
|
|
221
|
-
canUndo,
|
|
222
|
-
canRedo,
|
|
223
|
-
};
|
|
224
|
-
}
|
package/compositions/index.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description compositions barrel export
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22 00:00
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
-
*/
|
|
9
|
-
export * from './overlay';
|
|
10
|
-
export * from './contextMenu';
|
|
11
|
-
export * from './peekView';
|
|
12
|
-
export * from './commandPalette';
|
|
13
|
-
export * from './tooltip';
|
|
14
|
-
export * from './editor';
|
|
15
|
-
export * from './theme';
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description overlay composables barrel export
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22 00:00
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
-
*/
|
|
9
|
-
export {
|
|
10
|
-
useOverlayStackStore,
|
|
11
|
-
useOverlayStack,
|
|
12
|
-
useOverlayItem,
|
|
13
|
-
} from './useOverlayStack';
|
|
14
|
-
export type { OverlayItem, OverlayType } from './useOverlayStack';
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description overlay stack manager — unified z-index and ESC handling for all popups
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22 00:00
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
-
*/
|
|
9
|
-
import { defineStore } from 'pinia';
|
|
10
|
-
import { computed, ref, onMounted, onBeforeUnmount } from 'vue';
|
|
11
|
-
|
|
12
|
-
export type OverlayType = 'popover' | 'alert-dialog' | 'context-menu' | 'command-palette';
|
|
13
|
-
|
|
14
|
-
export interface OverlayItem {
|
|
15
|
-
id: string;
|
|
16
|
-
type: OverlayType;
|
|
17
|
-
close: () => void;
|
|
18
|
-
zIndex: number;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const Z_INDEX_BASE = 100;
|
|
22
|
-
|
|
23
|
-
let idCounter = 0;
|
|
24
|
-
const generateId = (type: OverlayType) => `overlay-${type}-${++idCounter}`;
|
|
25
|
-
|
|
26
|
-
export const useOverlayStackStore = defineStore('overlayStack', () => {
|
|
27
|
-
const overlayStack = ref<OverlayItem[]>([]);
|
|
28
|
-
|
|
29
|
-
const isEmpty = computed(() => overlayStack.value.length === 0);
|
|
30
|
-
const topItem = computed(() =>
|
|
31
|
-
overlayStack.value.length > 0
|
|
32
|
-
? overlayStack.value[overlayStack.value.length - 1]
|
|
33
|
-
: undefined,
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
const push = (item: Omit<OverlayItem, 'zIndex'>) => {
|
|
37
|
-
const zIndex = overlayStack.value.length + Z_INDEX_BASE;
|
|
38
|
-
const entry: OverlayItem = { ...item, zIndex };
|
|
39
|
-
overlayStack.value.push(entry);
|
|
40
|
-
return entry;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const pop = () => {
|
|
44
|
-
const item = overlayStack.value.pop();
|
|
45
|
-
if (item) {
|
|
46
|
-
item.close();
|
|
47
|
-
}
|
|
48
|
-
return item;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const remove = (id: string) => {
|
|
52
|
-
const index = overlayStack.value.findIndex(item => item.id === id);
|
|
53
|
-
if (index !== -1) {
|
|
54
|
-
overlayStack.value.splice(index, 1);
|
|
55
|
-
recalculateZIndices();
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const recalculateZIndices = () => {
|
|
60
|
-
overlayStack.value.forEach((item, index) => {
|
|
61
|
-
item.zIndex = index + Z_INDEX_BASE;
|
|
62
|
-
});
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const handleEsc = (e: KeyboardEvent) => {
|
|
66
|
-
if (e.key === 'Escape' && !isEmpty.value) {
|
|
67
|
-
pop();
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
let listenerAttached = false;
|
|
72
|
-
|
|
73
|
-
const attachEscListener = () => {
|
|
74
|
-
if (!listenerAttached) {
|
|
75
|
-
document.addEventListener('keydown', handleEsc);
|
|
76
|
-
listenerAttached = true;
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const detachEscListener = () => {
|
|
81
|
-
if (listenerAttached) {
|
|
82
|
-
document.removeEventListener('keydown', handleEsc);
|
|
83
|
-
listenerAttached = false;
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
overlayStack,
|
|
89
|
-
isEmpty,
|
|
90
|
-
topItem,
|
|
91
|
-
push,
|
|
92
|
-
pop,
|
|
93
|
-
remove,
|
|
94
|
-
attachEscListener,
|
|
95
|
-
detachEscListener,
|
|
96
|
-
};
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
export function useOverlayStack() {
|
|
100
|
-
const store = useOverlayStackStore();
|
|
101
|
-
|
|
102
|
-
onMounted(() => {
|
|
103
|
-
store.attachEscListener();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
onBeforeUnmount(() => {
|
|
107
|
-
store.detachEscListener();
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
return store;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export function useOverlayItem(type: OverlayType) {
|
|
114
|
-
const store = useOverlayStackStore();
|
|
115
|
-
let itemId: string | undefined;
|
|
116
|
-
|
|
117
|
-
const register = (closeFn: () => void) => {
|
|
118
|
-
const id = generateId(type);
|
|
119
|
-
const entry = store.push({ id, type, close: closeFn });
|
|
120
|
-
itemId = entry.id;
|
|
121
|
-
return entry;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const unregister = () => {
|
|
125
|
-
if (itemId) {
|
|
126
|
-
store.remove(itemId);
|
|
127
|
-
itemId = undefined;
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const currentZIndex = computed(() => {
|
|
132
|
-
if (!itemId) return undefined;
|
|
133
|
-
const item = store.overlayStack.find((i: OverlayItem) => i.id === itemId);
|
|
134
|
-
return item?.zIndex;
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
onBeforeUnmount(() => {
|
|
138
|
-
unregister();
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
register,
|
|
143
|
-
unregister,
|
|
144
|
-
currentZIndex,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description peekView composables barrel export
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
-
*/
|
|
9
|
-
export { usePeekView } from './usePeekView';
|
|
10
|
-
export type { PeekViewMode, UsePeekViewOptions } from './usePeekView';
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description PeekView composable — state management for non-modal peek panels
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
-
*/
|
|
9
|
-
import { ref, onMounted } from 'vue';
|
|
10
|
-
import { useOverlayStackStore } from '../overlay/useOverlayStack';
|
|
11
|
-
|
|
12
|
-
export type PeekViewMode = 'side' | 'modal' | 'full';
|
|
13
|
-
|
|
14
|
-
export interface UsePeekViewOptions {
|
|
15
|
-
/** Default mode when opening without explicit mode */
|
|
16
|
-
defaultMode?: PeekViewMode;
|
|
17
|
-
/** Enable URL query param sync (?peek=<id>) */
|
|
18
|
-
urlSync?: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function usePeekView(options: UsePeekViewOptions = {}) {
|
|
22
|
-
const { defaultMode = 'side', urlSync = false } = options;
|
|
23
|
-
|
|
24
|
-
const isOpen = ref(false);
|
|
25
|
-
const mode = ref<PeekViewMode>(defaultMode);
|
|
26
|
-
const peekId = ref<string | undefined>(undefined);
|
|
27
|
-
|
|
28
|
-
// URL sync helpers
|
|
29
|
-
const readPeekFromUrl = (): string | undefined => {
|
|
30
|
-
if (typeof window === 'undefined') return undefined;
|
|
31
|
-
const params = new URLSearchParams(window.location.search);
|
|
32
|
-
return params.get('peek') || undefined;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const writePeekToUrl = (id: string | undefined) => {
|
|
36
|
-
if (typeof window === 'undefined') return;
|
|
37
|
-
const url = new URL(window.location.href);
|
|
38
|
-
if (id) {
|
|
39
|
-
url.searchParams.set('peek', id);
|
|
40
|
-
} else {
|
|
41
|
-
url.searchParams.delete('peek');
|
|
42
|
-
}
|
|
43
|
-
window.history.replaceState(window.history.state, '', url.toString());
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const open = (id: string, openMode?: PeekViewMode) => {
|
|
47
|
-
peekId.value = id;
|
|
48
|
-
mode.value = openMode ?? defaultMode;
|
|
49
|
-
isOpen.value = true;
|
|
50
|
-
if (urlSync) {
|
|
51
|
-
writePeekToUrl(id);
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const close = () => {
|
|
56
|
-
isOpen.value = false;
|
|
57
|
-
peekId.value = undefined;
|
|
58
|
-
if (urlSync) {
|
|
59
|
-
writePeekToUrl(undefined);
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const setMode = (newMode: PeekViewMode) => {
|
|
64
|
-
mode.value = newMode;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// Outside click handler: close only if overlay stack is empty
|
|
68
|
-
const handleOutsideClick = (event: MouseEvent, panelEl: HTMLElement | null) => {
|
|
69
|
-
if (!isOpen.value || !panelEl) return;
|
|
70
|
-
|
|
71
|
-
const overlayStore = useOverlayStackStore();
|
|
72
|
-
if (!overlayStore.isEmpty) return;
|
|
73
|
-
|
|
74
|
-
const target = event.target as Node;
|
|
75
|
-
if (!panelEl.contains(target)) {
|
|
76
|
-
close();
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// Initialize from URL on mount (if urlSync is enabled)
|
|
81
|
-
onMounted(() => {
|
|
82
|
-
if (urlSync) {
|
|
83
|
-
const urlPeekId = readPeekFromUrl();
|
|
84
|
-
if (urlPeekId) {
|
|
85
|
-
open(urlPeekId);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
return {
|
|
91
|
-
isOpen,
|
|
92
|
-
mode,
|
|
93
|
-
peekId,
|
|
94
|
-
open,
|
|
95
|
-
close,
|
|
96
|
-
setMode,
|
|
97
|
-
handleOutsideClick,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description theme composables barrel export
|
|
3
|
-
* @author kine-design
|
|
4
|
-
* @date 2026/5/22
|
|
5
|
-
* @version v1.0.0
|
|
6
|
-
*
|
|
7
|
-
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
-
*/
|
|
9
|
-
export { useThemeStore } from './useTheme';
|
|
10
|
-
export type {
|
|
11
|
-
ThemeDefinition,
|
|
12
|
-
ThemeTokens,
|
|
13
|
-
ThemeTokenCategory,
|
|
14
|
-
ThemeOverrides,
|
|
15
|
-
PersistedThemeState,
|
|
16
|
-
} from './types';
|
|
17
|
-
export { lightTheme, darkTheme, compactTheme } from './presets';
|