@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/.vlaude/last-session-id
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
4c9b1c27-b707-4b0b-98d7-fde5d511ce47
|
|
@@ -11,7 +11,7 @@ import { AutoCompleteProps, AutoCompleteOption } from './props';
|
|
|
11
11
|
|
|
12
12
|
export const props: MCOPO<AutoCompleteProps> = {
|
|
13
13
|
modelValue: { type: String, default: '' },
|
|
14
|
-
placeholder: { type: String, default:
|
|
14
|
+
placeholder: { type: String, default: undefined },
|
|
15
15
|
disabled: { type: Boolean, default: false },
|
|
16
16
|
clearable: { type: Boolean, default: false },
|
|
17
17
|
debounce: { type: Number, default: 300 },
|
|
@@ -12,7 +12,7 @@ import { CascaderProps, CascaderOption } from './props';
|
|
|
12
12
|
export const props: MCOPO<CascaderProps> = {
|
|
13
13
|
modelValue: { type: undefined, default: () => [] },
|
|
14
14
|
options: { type: Array as MPropType<CascaderOption[]>, default: () => [] },
|
|
15
|
-
placeholder: { type: String, default:
|
|
15
|
+
placeholder: { type: String, default: undefined },
|
|
16
16
|
disabled: { type: Boolean, default: false },
|
|
17
17
|
clearable: { type: Boolean, default: false },
|
|
18
18
|
filterable: { type: Boolean, default: false },
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
8
|
*/
|
|
9
9
|
import { describe, expect, it } from 'vitest';
|
|
10
|
-
import { useDatePicker, generateTimeColumn, toDayjs
|
|
10
|
+
import { useDatePicker, generateTimeColumn, toDayjs } from '../useDatePicker';
|
|
11
11
|
|
|
12
12
|
describe('toDayjs', () => {
|
|
13
13
|
it('字符串转 dayjs', () => {
|
|
@@ -53,20 +53,11 @@ describe('generateTimeColumn', () => {
|
|
|
53
53
|
});
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
describe('常量', () => {
|
|
57
|
-
it('BASE_WEEK_NAME 有 7 天', () => {
|
|
58
|
-
expect(BASE_WEEK_NAME).toHaveLength(7);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('BASE_MONTH_NAME 有 12 个月', () => {
|
|
62
|
-
expect(BASE_MONTH_NAME).toHaveLength(12);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
56
|
describe('useDatePicker', () => {
|
|
67
|
-
it('
|
|
57
|
+
it('初始化空值 displayValue 为空串、标记 placeholder 态', () => {
|
|
58
|
+
// i18n 后 placeholder 文案由 UI 层提供,hook 空值只返回空串 + placeholder class
|
|
68
59
|
const dp = useDatePicker({ type: 'date' });
|
|
69
|
-
expect(dp.displayValue.value).toBe('
|
|
60
|
+
expect(dp.displayValue.value).toBe('');
|
|
70
61
|
expect(dp.spanClass.value).toContain('m-date-picker-placeholder');
|
|
71
62
|
});
|
|
72
63
|
|
|
@@ -78,9 +69,9 @@ describe('useDatePicker', () => {
|
|
|
78
69
|
expect(dp.dateRef.value.day).toBe(15);
|
|
79
70
|
});
|
|
80
71
|
|
|
81
|
-
it('
|
|
72
|
+
it('placeholder 不再由 hook 产出(移交 UI 层),空值仍为空串', () => {
|
|
82
73
|
const dp = useDatePicker({ type: 'date', placeholder: '选择日期' });
|
|
83
|
-
expect(dp.displayValue.value).toBe('
|
|
74
|
+
expect(dp.displayValue.value).toBe('');
|
|
84
75
|
});
|
|
85
76
|
|
|
86
77
|
it('updateDateRef 更新状态', () => {
|
|
@@ -93,11 +84,11 @@ describe('useDatePicker', () => {
|
|
|
93
84
|
expect(dp.displayValue.value).toBe('2025-12-25');
|
|
94
85
|
});
|
|
95
86
|
|
|
96
|
-
it('updateDateRef
|
|
87
|
+
it('updateDateRef 空值恢复空串(placeholder 态)', () => {
|
|
97
88
|
const dp = useDatePicker({ type: 'date', modelValue: '2026-01-01' });
|
|
98
89
|
dp.updateDateRef('');
|
|
99
90
|
|
|
100
|
-
expect(dp.displayValue.value).toBe('
|
|
91
|
+
expect(dp.displayValue.value).toBe('');
|
|
101
92
|
});
|
|
102
93
|
|
|
103
94
|
it('getCalendar 返回 6 行 7 列', () => {
|
|
@@ -11,7 +11,7 @@ import { DatePickerProps } from './props';
|
|
|
11
11
|
|
|
12
12
|
export const props: MCOPO<DatePickerProps> = {
|
|
13
13
|
modelValue: { type: [String, Date], default: '' },
|
|
14
|
-
placeholder: { type: String, default:
|
|
14
|
+
placeholder: { type: String, default: undefined },
|
|
15
15
|
format: { type: String, default: undefined },
|
|
16
16
|
type: { type: String as MPropType<'date' | 'month' | 'datetime'>, default: 'date' },
|
|
17
17
|
disabled: { type: Boolean, default: false },
|
|
@@ -15,5 +15,5 @@ export const DatePickerCore = {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
export type { DatePickerProps, CalendarType, DateRefType, CalendarItem } from './props';
|
|
18
|
-
export { useDatePicker, toDayjs,
|
|
18
|
+
export { useDatePicker, toDayjs, generateTimeColumn } from './useDatePicker';
|
|
19
19
|
export type { TimeRefType } from './useDatePicker';
|
|
@@ -20,23 +20,6 @@ export type TimeRefType = {
|
|
|
20
20
|
seconds: number;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
/** 基础星期头(汉字显示) */
|
|
24
|
-
export const BASE_WEEK_NAME: Array<{ day: string; isCurrentMonth: boolean }> = [
|
|
25
|
-
{ day: '日', isCurrentMonth: true },
|
|
26
|
-
{ day: '壹', isCurrentMonth: true },
|
|
27
|
-
{ day: '贰', isCurrentMonth: true },
|
|
28
|
-
{ day: '叁', isCurrentMonth: true },
|
|
29
|
-
{ day: '肆', isCurrentMonth: true },
|
|
30
|
-
{ day: '伍', isCurrentMonth: true },
|
|
31
|
-
{ day: '陆', isCurrentMonth: true },
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
/** 月份名称 */
|
|
35
|
-
export const BASE_MONTH_NAME = [
|
|
36
|
-
'1月', '2月', '3月', '4月', '5月', '6月',
|
|
37
|
-
'7月', '8月', '9月', '10月', '11月', '12月',
|
|
38
|
-
];
|
|
39
|
-
|
|
40
23
|
/**
|
|
41
24
|
* 将 string | Date 转换为 dayjs 对象。
|
|
42
25
|
* headless 组件需要用此函数更新 currentRef。
|
|
@@ -113,7 +96,7 @@ export function useDatePicker(props: DatePickerProps) {
|
|
|
113
96
|
*/
|
|
114
97
|
const updateDateRef = (value: string | Date | undefined) => {
|
|
115
98
|
if (isEmpty(value)) {
|
|
116
|
-
displayValue.value =
|
|
99
|
+
displayValue.value = '';
|
|
117
100
|
needPlaceholder = true;
|
|
118
101
|
} else {
|
|
119
102
|
needPlaceholder = false;
|
|
@@ -10,6 +10,6 @@ import { MCOPO } from '../../types/props';
|
|
|
10
10
|
import { EmptyProps } from './props';
|
|
11
11
|
|
|
12
12
|
export const props: MCOPO<EmptyProps> = {
|
|
13
|
-
description: { type: String, default:
|
|
13
|
+
description: { type: String, default: undefined },
|
|
14
14
|
image: { type: String, default: undefined },
|
|
15
15
|
};
|
|
@@ -19,7 +19,7 @@ export const props: MCOPO<SelectProps> = {
|
|
|
19
19
|
valueParam: { type: String, default: undefined },
|
|
20
20
|
readonly: { type: Boolean, default: true },
|
|
21
21
|
disabled: { type: Boolean, default: false },
|
|
22
|
-
placeholder: { type: String, default:
|
|
22
|
+
placeholder: { type: String, default: undefined },
|
|
23
23
|
toMatch: { type: Function as MPropType<(option: any, value: any) => boolean>, default: undefined },
|
|
24
24
|
multiple: { type: Boolean, default: false },
|
|
25
25
|
checkbox: { type: Boolean, default: true },
|
|
@@ -36,9 +36,10 @@ describe('useTimePicker', () => {
|
|
|
36
36
|
secondStep: 1,
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
it('
|
|
39
|
+
it('初始化空值 displayValue 为空串、标记 placeholder 态', () => {
|
|
40
|
+
// i18n 后 placeholder 文案由 UI 层提供,hook 空值只返回空串 + placeholder class
|
|
40
41
|
const tp = useTimePicker({ ...defaultProps });
|
|
41
|
-
expect(tp.displayValue.value).toBe('
|
|
42
|
+
expect(tp.displayValue.value).toBe('');
|
|
42
43
|
expect(tp.spanClass.value).toContain('m-time-picker-placeholder');
|
|
43
44
|
});
|
|
44
45
|
|
|
@@ -65,10 +66,10 @@ describe('useTimePicker', () => {
|
|
|
65
66
|
expect(tp.timeRef.value.seconds).toBe(30);
|
|
66
67
|
});
|
|
67
68
|
|
|
68
|
-
it('updateTimeRef
|
|
69
|
+
it('updateTimeRef 空值恢复空串(placeholder 态)', () => {
|
|
69
70
|
const tp = useTimePicker({ ...defaultProps, modelValue: '10:00:00' });
|
|
70
71
|
tp.updateTimeRef('');
|
|
71
|
-
expect(tp.displayValue.value).toBe('
|
|
72
|
+
expect(tp.displayValue.value).toBe('');
|
|
72
73
|
});
|
|
73
74
|
|
|
74
75
|
it('selectHour 更新小时并刷新显示', () => {
|
|
@@ -11,7 +11,7 @@ import { TimePickerProps } from './props';
|
|
|
11
11
|
|
|
12
12
|
export const props: MCOPO<TimePickerProps> = {
|
|
13
13
|
modelValue: { type: String, default: '' },
|
|
14
|
-
placeholder: { type: String, default:
|
|
14
|
+
placeholder: { type: String, default: undefined },
|
|
15
15
|
format: { type: String, default: undefined },
|
|
16
16
|
disabled: { type: Boolean, default: false },
|
|
17
17
|
showSeconds: { type: Boolean, default: true },
|
|
@@ -68,7 +68,7 @@ export function useTimePicker(props: TimePickerProps) {
|
|
|
68
68
|
*/
|
|
69
69
|
const updateTimeRef = (value: string | undefined) => {
|
|
70
70
|
if (isEmpty(value)) {
|
|
71
|
-
displayValue.value =
|
|
71
|
+
displayValue.value = '';
|
|
72
72
|
needPlaceholder = true;
|
|
73
73
|
} else {
|
|
74
74
|
needPlaceholder = false;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @description tooltip
|
|
2
|
+
* @description tooltip 运行时 props
|
|
3
3
|
* @author 阿怪
|
|
4
4
|
* @date 2026/2/25
|
|
5
|
-
* @version
|
|
5
|
+
* @version v1.0.0
|
|
6
6
|
*
|
|
7
7
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
8
|
*/
|
|
@@ -15,7 +15,6 @@ export const props: MCOPO<TooltipProps> = {
|
|
|
15
15
|
type: String as MPropType<NonNullable<TooltipProps['placement']>>,
|
|
16
16
|
default: 'top',
|
|
17
17
|
},
|
|
18
|
-
delay: { type: Number, default: 300 },
|
|
19
18
|
disabled: { type: Boolean, default: false },
|
|
20
19
|
maxWidth: { type: String, default: undefined },
|
|
21
20
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @description tooltip core
|
|
2
|
+
* @description tooltip core 导出
|
|
3
3
|
* @author 阿怪
|
|
4
4
|
* @date 2026/2/25
|
|
5
|
-
* @version
|
|
5
|
+
* @version v1.0.0
|
|
6
6
|
*
|
|
7
7
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
8
|
*/
|
|
@@ -15,4 +15,3 @@ export const TooltipCore = {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
export type { TooltipProps } from './props';
|
|
18
|
-
export type { TooltipPlacement, TooltipPositionData } from './useTooltip';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @description tooltip
|
|
2
|
+
* @description tooltip 类型定义
|
|
3
3
|
* @author 阿怪
|
|
4
4
|
* @date 2026/2/25
|
|
5
|
-
* @version
|
|
5
|
+
* @version v1.0.0
|
|
6
6
|
*
|
|
7
7
|
* @name m-tooltip
|
|
8
8
|
* @docDescription Tooltip component.
|
|
@@ -14,31 +14,25 @@
|
|
|
14
14
|
|
|
15
15
|
export declare type TooltipProps = {
|
|
16
16
|
/**
|
|
17
|
-
* @description
|
|
17
|
+
* @description 提示内容,简单文本可直接通过 prop 传入
|
|
18
18
|
* @type string
|
|
19
19
|
* @default ''
|
|
20
20
|
*/
|
|
21
21
|
content?: string;
|
|
22
22
|
/**
|
|
23
|
-
* @description
|
|
23
|
+
* @description 弹出位置
|
|
24
24
|
* @type 'top' | 'bottom' | 'left' | 'right'
|
|
25
25
|
* @default 'top'
|
|
26
26
|
*/
|
|
27
27
|
placement?: 'top' | 'bottom' | 'left' | 'right';
|
|
28
28
|
/**
|
|
29
|
-
* @description
|
|
30
|
-
* @type number
|
|
31
|
-
* @default 300
|
|
32
|
-
*/
|
|
33
|
-
delay?: number;
|
|
34
|
-
/**
|
|
35
|
-
* @description whether the tooltip is disabled
|
|
29
|
+
* @description 是否禁用
|
|
36
30
|
* @type boolean
|
|
37
31
|
* @default false
|
|
38
32
|
*/
|
|
39
33
|
disabled?: boolean;
|
|
40
34
|
/**
|
|
41
|
-
* @description max width of tooltip content
|
|
35
|
+
* @description max width of tooltip content. 浮层最大宽度
|
|
42
36
|
* @type string
|
|
43
37
|
* @default undefined
|
|
44
38
|
*/
|
|
@@ -1,208 +1,89 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @description tooltip composable
|
|
2
|
+
* @description tooltip composable,管理 hover 显示/隐藏及定位
|
|
3
3
|
* @author 阿怪
|
|
4
4
|
* @date 2026/2/25
|
|
5
|
-
* @version
|
|
5
|
+
* @version v1.0.0
|
|
6
6
|
*
|
|
7
7
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
8
|
*/
|
|
9
|
-
import { ref,
|
|
10
|
-
import { flip, offset, shift } from '@floating-ui/dom';
|
|
11
|
-
import { usePopper, type Placement, type PositionStyle } from '../../../compositions/popper/usePopper';
|
|
9
|
+
import { ref, nextTick } from 'vue';
|
|
12
10
|
import { TooltipProps } from './props';
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
export type TooltipStyle = {
|
|
13
|
+
position: string;
|
|
14
|
+
left: string;
|
|
15
|
+
top: string;
|
|
16
|
+
zIndex: string;
|
|
17
|
+
};
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* 根据 trigger 元素的 getBoundingClientRect 和 placement 计算 tooltip 的 fixed 定位样式
|
|
21
|
+
*/
|
|
22
|
+
function calcPosition(
|
|
23
|
+
rect: DOMRect,
|
|
24
|
+
tooltipEl: HTMLElement,
|
|
25
|
+
placement: NonNullable<TooltipProps['placement']>,
|
|
26
|
+
): TooltipStyle {
|
|
27
|
+
const gap = 8;
|
|
28
|
+
const tooltipRect = tooltipEl.getBoundingClientRect();
|
|
29
|
+
let left = 0;
|
|
30
|
+
let top = 0;
|
|
31
|
+
|
|
32
|
+
switch (placement) {
|
|
33
|
+
case 'top':
|
|
34
|
+
left = rect.left + rect.width / 2 - tooltipRect.width / 2;
|
|
35
|
+
top = rect.top - tooltipRect.height - gap;
|
|
36
|
+
break;
|
|
37
|
+
case 'bottom':
|
|
38
|
+
left = rect.left + rect.width / 2 - tooltipRect.width / 2;
|
|
39
|
+
top = rect.bottom + gap;
|
|
40
|
+
break;
|
|
41
|
+
case 'left':
|
|
42
|
+
left = rect.left - tooltipRect.width - gap;
|
|
43
|
+
top = rect.top + rect.height / 2 - tooltipRect.height / 2;
|
|
44
|
+
break;
|
|
45
|
+
case 'right':
|
|
46
|
+
left = rect.right + gap;
|
|
47
|
+
top = rect.top + rect.height / 2 - tooltipRect.height / 2;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
20
50
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
51
|
+
return {
|
|
52
|
+
position: 'fixed',
|
|
53
|
+
left: `${left}px`,
|
|
54
|
+
top: `${top}px`,
|
|
55
|
+
zIndex: '9999',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
26
58
|
|
|
27
59
|
export function useTooltip(props: Required<TooltipProps>) {
|
|
28
60
|
const visible = ref(false);
|
|
29
|
-
const
|
|
61
|
+
const tooltipStyle = ref<TooltipStyle | Record<string, never>>({});
|
|
30
62
|
|
|
31
63
|
const triggerRef = ref<HTMLElement | null>(null);
|
|
32
64
|
const tooltipRef = ref<HTMLElement | null>(null);
|
|
33
|
-
const arrowRef = ref<HTMLElement | null>(null);
|
|
34
|
-
|
|
35
|
-
let showTimer: ReturnType<typeof setTimeout> | null = null;
|
|
36
|
-
let hideTimer: ReturnType<typeof setTimeout> | null = null;
|
|
37
|
-
let popperCleanup: (() => void) | null = null;
|
|
38
|
-
|
|
39
|
-
const tooltipId = `k-tooltip-${Math.random().toString(36).slice(2, 10)}`;
|
|
40
|
-
|
|
41
|
-
/** Clean up popper auto-update subscription */
|
|
42
|
-
const destroyPopper = () => {
|
|
43
|
-
if (popperCleanup) {
|
|
44
|
-
popperCleanup();
|
|
45
|
-
popperCleanup = null;
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
65
|
|
|
49
|
-
|
|
50
|
-
const hideImmediate = () => {
|
|
51
|
-
clearTimers();
|
|
52
|
-
visible.value = false;
|
|
53
|
-
positionData.value = null;
|
|
54
|
-
destroyPopper();
|
|
55
|
-
if (activeHide === hideImmediate) {
|
|
56
|
-
activeHide = null;
|
|
57
|
-
}
|
|
58
|
-
removeInteractionListeners();
|
|
59
|
-
removeScrollListeners();
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
/** Show tooltip after delay */
|
|
63
|
-
const show = () => {
|
|
66
|
+
const show = async () => {
|
|
64
67
|
if (props.disabled) return;
|
|
65
|
-
|
|
66
|
-
// Dismiss any existing tooltip (singleton)
|
|
67
|
-
if (activeHide && activeHide !== hideImmediate) {
|
|
68
|
-
activeHide();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (hideTimer) {
|
|
72
|
-
clearTimeout(hideTimer);
|
|
73
|
-
hideTimer = null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (visible.value) return;
|
|
77
|
-
|
|
78
|
-
const delay = props.delay ?? 300;
|
|
79
|
-
showTimer = setTimeout(() => {
|
|
80
|
-
showTimer = null;
|
|
81
|
-
if (props.disabled) return;
|
|
82
|
-
doShow();
|
|
83
|
-
}, delay);
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
/** Actually display the tooltip and set up popper */
|
|
87
|
-
const doShow = () => {
|
|
88
68
|
visible.value = true;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
addScrollListeners();
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
/** Initialize popper positioning — called after tooltip DOM is mounted */
|
|
95
|
-
const initPopper = () => {
|
|
69
|
+
// 等待 tooltip DOM 渲染后再计算位置
|
|
70
|
+
await nextTick();
|
|
96
71
|
if (!triggerRef.value || !tooltipRef.value) return;
|
|
97
|
-
|
|
98
|
-
destroyPopper();
|
|
99
|
-
|
|
100
|
-
const { clear } = usePopper(
|
|
101
|
-
triggerRef.value,
|
|
102
|
-
tooltipRef.value,
|
|
103
|
-
(data: PositionStyle) => {
|
|
104
|
-
positionData.value = {
|
|
105
|
-
style: { ...data.style },
|
|
106
|
-
arrowStyle: { ...data.arrowStyle },
|
|
107
|
-
placement: data.placement,
|
|
108
|
-
};
|
|
109
|
-
},
|
|
110
|
-
arrowRef.value ?? undefined,
|
|
111
|
-
{
|
|
112
|
-
placement: props.placement as Placement,
|
|
113
|
-
middleware: [
|
|
114
|
-
offset(8),
|
|
115
|
-
flip(),
|
|
116
|
-
shift({ padding: 8 }),
|
|
117
|
-
],
|
|
118
|
-
},
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
popperCleanup = clear;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
/** Hide tooltip with a short delay (allows cursor to move between trigger and tooltip) */
|
|
125
|
-
const hide = () => {
|
|
126
|
-
if (showTimer) {
|
|
127
|
-
clearTimeout(showTimer);
|
|
128
|
-
showTimer = null;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (!visible.value) return;
|
|
132
|
-
|
|
133
|
-
hideTimer = setTimeout(() => {
|
|
134
|
-
hideTimer = null;
|
|
135
|
-
hideImmediate();
|
|
136
|
-
}, HIDE_DELAY);
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const clearTimers = () => {
|
|
140
|
-
if (showTimer) {
|
|
141
|
-
clearTimeout(showTimer);
|
|
142
|
-
showTimer = null;
|
|
143
|
-
}
|
|
144
|
-
if (hideTimer) {
|
|
145
|
-
clearTimeout(hideTimer);
|
|
146
|
-
hideTimer = null;
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
/* ── Interaction listeners: dismiss on click / keydown ── */
|
|
151
|
-
const onInteraction = () => {
|
|
152
|
-
hideImmediate();
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
const addInteractionListeners = () => {
|
|
156
|
-
document.addEventListener('mousedown', onInteraction, true);
|
|
157
|
-
document.addEventListener('keydown', onInteraction, true);
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const removeInteractionListeners = () => {
|
|
161
|
-
document.removeEventListener('mousedown', onInteraction, true);
|
|
162
|
-
document.removeEventListener('keydown', onInteraction, true);
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
/* ── Scroll listeners: dismiss when trigger scrolls out of view ── */
|
|
166
|
-
const onScroll = () => {
|
|
167
|
-
if (!triggerRef.value) {
|
|
168
|
-
hideImmediate();
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
72
|
const rect = triggerRef.value.getBoundingClientRect();
|
|
172
|
-
|
|
173
|
-
rect.bottom > 0 &&
|
|
174
|
-
rect.top < window.innerHeight &&
|
|
175
|
-
rect.right > 0 &&
|
|
176
|
-
rect.left < window.innerWidth;
|
|
177
|
-
if (!inView) {
|
|
178
|
-
hideImmediate();
|
|
179
|
-
}
|
|
73
|
+
tooltipStyle.value = calcPosition(rect, tooltipRef.value, props.placement);
|
|
180
74
|
};
|
|
181
75
|
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
const removeScrollListeners = () => {
|
|
188
|
-
window.removeEventListener('scroll', onScroll, true);
|
|
189
|
-
window.removeEventListener('resize', onScroll, true);
|
|
76
|
+
const hide = () => {
|
|
77
|
+
visible.value = false;
|
|
78
|
+
tooltipStyle.value = {};
|
|
190
79
|
};
|
|
191
80
|
|
|
192
|
-
onBeforeUnmount(() => {
|
|
193
|
-
hideImmediate();
|
|
194
|
-
});
|
|
195
|
-
|
|
196
81
|
return {
|
|
197
82
|
visible,
|
|
198
|
-
|
|
83
|
+
tooltipStyle,
|
|
199
84
|
triggerRef,
|
|
200
85
|
tooltipRef,
|
|
201
|
-
arrowRef,
|
|
202
|
-
tooltipId,
|
|
203
86
|
show,
|
|
204
87
|
hide,
|
|
205
|
-
hideImmediate,
|
|
206
|
-
initPopper,
|
|
207
88
|
};
|
|
208
89
|
}
|
|
@@ -12,7 +12,7 @@ import { TransferProps, TransferItem } from './props';
|
|
|
12
12
|
export const props: MCOPO<TransferProps> = {
|
|
13
13
|
modelValue: { type: Array as MPropType<(string | number)[]>, default: () => [] },
|
|
14
14
|
data: { type: Array as MPropType<TransferItem[]>, default: () => [] },
|
|
15
|
-
titles: { type: Array as unknown as MPropType<[string, string]>, default:
|
|
15
|
+
titles: { type: Array as unknown as MPropType<[string, string]>, default: undefined },
|
|
16
16
|
filterable: { type: Boolean, default: false },
|
|
17
|
-
filterPlaceholder: { type: String, default:
|
|
17
|
+
filterPlaceholder: { type: String, default: undefined },
|
|
18
18
|
};
|
|
@@ -14,8 +14,8 @@ export const props: MCOPO<ConfirmProps> = {
|
|
|
14
14
|
mask: { type: Object, default: () => ({ show: true, clickClose: false }) },
|
|
15
15
|
teleport: { type: Object, default: () => ({ to: 'body' }) },
|
|
16
16
|
content: { type: String, default: '' },
|
|
17
|
-
confirmText: { type: String, default:
|
|
18
|
-
cancelText: { type: String, default:
|
|
17
|
+
confirmText: { type: String, default: undefined },
|
|
18
|
+
cancelText: { type: String, default: undefined },
|
|
19
19
|
title: { type: String, default: undefined },
|
|
20
20
|
loading: { type: Boolean, default: false },
|
|
21
21
|
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description composable for unified component locale with global injection
|
|
3
|
+
* support — the i18n counterpart of `useComponentSize`. Components call
|
|
4
|
+
* `useLocale()` to get the active message dictionary (a computed ref) and read
|
|
5
|
+
* their user-facing strings from it instead of hardcoding text.
|
|
6
|
+
* @author kine-design
|
|
7
|
+
* @version v1.0.0
|
|
8
|
+
*
|
|
9
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
10
|
+
*/
|
|
11
|
+
import { computed, inject, type ComputedRef, type InjectionKey, type Ref } from 'vue';
|
|
12
|
+
import type { KineLocaleName, KineLocaleMessages } from '../../locale/types';
|
|
13
|
+
import { DEFAULT_LOCALE, locales } from '../../locale';
|
|
14
|
+
|
|
15
|
+
/** Accepted `locale` values: a built-in name, or a full custom dictionary. */
|
|
16
|
+
export type KineLocaleConfig = KineLocaleName | KineLocaleMessages;
|
|
17
|
+
|
|
18
|
+
export const KINE_LOCALE_KEY: InjectionKey<Ref<KineLocaleConfig | undefined>> = Symbol('kine-locale');
|
|
19
|
+
|
|
20
|
+
function resolveMessages(config: KineLocaleConfig | undefined): KineLocaleMessages {
|
|
21
|
+
if (!config) return locales[DEFAULT_LOCALE];
|
|
22
|
+
if (typeof config === 'string') return locales[config] ?? locales[DEFAULT_LOCALE];
|
|
23
|
+
return config;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Resolve the active message dictionary from the nearest `KConfigProvider`.
|
|
28
|
+
* Falls back to the default (zh) pack when no provider is present.
|
|
29
|
+
*/
|
|
30
|
+
export function useLocale(): ComputedRef<KineLocaleMessages> {
|
|
31
|
+
const injected = inject(KINE_LOCALE_KEY, undefined);
|
|
32
|
+
return computed(() => resolveMessages(injected?.value));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ── Global singleton ─────────────────────────────────────────────────────────
|
|
36
|
+
// Components read locale through useLocale() (provide/inject, scoped + reactive).
|
|
37
|
+
// But non-component code — the crud request/error feedback functions — has no
|
|
38
|
+
// component context and cannot inject. Those read this module-level singleton
|
|
39
|
+
// instead. KConfigProvider keeps it in sync inside its setup, so under a single
|
|
40
|
+
// root provider the two are always consistent; with nested providers the global
|
|
41
|
+
// reflects whichever was set last (an acceptable trade-off, since feedback text
|
|
42
|
+
// is app-global by nature).
|
|
43
|
+
let activeLocaleMessages: KineLocaleMessages = locales[DEFAULT_LOCALE];
|
|
44
|
+
|
|
45
|
+
/** Set the global active dictionary. Called by KConfigProvider on locale change. */
|
|
46
|
+
export function setActiveLocaleMessages(config: KineLocaleConfig | undefined): void {
|
|
47
|
+
activeLocaleMessages = resolveMessages(config);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Read the global active dictionary from non-component (pure-function) code. */
|
|
51
|
+
export function getActiveLocaleMessages(): KineLocaleMessages {
|
|
52
|
+
return activeLocaleMessages;
|
|
53
|
+
}
|
|
@@ -4,5 +4,5 @@ export declare const DatePickerCore: {
|
|
|
4
4
|
useDatePicker: typeof useDatePicker;
|
|
5
5
|
};
|
|
6
6
|
export type { DatePickerProps, CalendarType, DateRefType, CalendarItem } from './props';
|
|
7
|
-
export { useDatePicker, toDayjs,
|
|
7
|
+
export { useDatePicker, toDayjs, generateTimeColumn } from './useDatePicker';
|
|
8
8
|
export type { TimeRefType } from './useDatePicker';
|
|
@@ -7,13 +7,6 @@ export type TimeRefType = {
|
|
|
7
7
|
minutes: number;
|
|
8
8
|
seconds: number;
|
|
9
9
|
};
|
|
10
|
-
/** 基础星期头(汉字显示) */
|
|
11
|
-
export declare const BASE_WEEK_NAME: Array<{
|
|
12
|
-
day: string;
|
|
13
|
-
isCurrentMonth: boolean;
|
|
14
|
-
}>;
|
|
15
|
-
/** 月份名称 */
|
|
16
|
-
export declare const BASE_MONTH_NAME: string[];
|
|
17
10
|
/**
|
|
18
11
|
* 将 string | Date 转换为 dayjs 对象。
|
|
19
12
|
* headless 组件需要用此函数更新 currentRef。
|