@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.
Files changed (88) hide show
  1. package/.vlaude/last-session-id +1 -1
  2. package/components/base/autoComplete/api.ts +1 -1
  3. package/components/base/cascader/api.ts +1 -1
  4. package/components/base/datePicker/__tests__/useDatePicker.test.ts +8 -17
  5. package/components/base/datePicker/api.ts +1 -1
  6. package/components/base/datePicker/index.ts +1 -1
  7. package/components/base/datePicker/useDatePicker.ts +1 -18
  8. package/components/base/empty/api.ts +1 -1
  9. package/components/base/select/api.ts +1 -1
  10. package/components/base/timePicker/__tests__/useTimePicker.test.ts +5 -4
  11. package/components/base/timePicker/api.ts +1 -1
  12. package/components/base/timePicker/useTimePicker.ts +1 -1
  13. package/components/base/tooltip/api.ts +2 -3
  14. package/components/base/tooltip/index.ts +2 -3
  15. package/components/base/tooltip/props.d.ts +6 -12
  16. package/components/base/tooltip/useTooltip.ts +56 -175
  17. package/components/base/transfer/api.ts +2 -2
  18. package/components/message/confirm/api.ts +2 -2
  19. package/compositions/common/useLocale.ts +53 -0
  20. package/dist/components/base/datePicker/index.d.ts +1 -1
  21. package/dist/components/base/datePicker/useDatePicker.d.ts +0 -7
  22. package/dist/components/base/tooltip/index.d.ts +0 -1
  23. package/dist/components/base/tooltip/useTooltip.d.ts +17 -20
  24. package/dist/compositions/common/useLocale.d.ts +14 -0
  25. package/dist/core.js +498 -851
  26. package/dist/index.d.ts +2 -1
  27. package/dist/locale/en.d.ts +3 -0
  28. package/dist/locale/index.d.ts +9 -0
  29. package/dist/locale/types.d.ts +222 -0
  30. package/dist/locale/zh.d.ts +3 -0
  31. package/index.ts +9 -1
  32. package/locale/.vlaude/last-session-id +1 -0
  33. package/locale/en.ts +187 -0
  34. package/locale/index.ts +29 -0
  35. package/locale/types.ts +214 -0
  36. package/locale/zh.ts +190 -0
  37. package/package.json +19 -32
  38. package/.vlaude/session-switch.signal +0 -1
  39. package/compositions/commandPalette/index.ts +0 -11
  40. package/compositions/commandPalette/types.ts +0 -29
  41. package/compositions/commandPalette/useCommandPalette.ts +0 -135
  42. package/compositions/contextMenu/index.ts +0 -10
  43. package/compositions/contextMenu/types.ts +0 -21
  44. package/compositions/contextMenu/useContextMenu.ts +0 -101
  45. package/compositions/editor/index.ts +0 -18
  46. package/compositions/editor/types.ts +0 -147
  47. package/compositions/editor/useEditor.ts +0 -224
  48. package/compositions/index.ts +0 -15
  49. package/compositions/overlay/index.ts +0 -14
  50. package/compositions/overlay/useOverlayStack.ts +0 -146
  51. package/compositions/peekView/index.ts +0 -10
  52. package/compositions/peekView/usePeekView.ts +0 -99
  53. package/compositions/theme/index.ts +0 -17
  54. package/compositions/theme/presets/compact.ts +0 -117
  55. package/compositions/theme/presets/dark.ts +0 -113
  56. package/compositions/theme/presets/index.ts +0 -11
  57. package/compositions/theme/presets/light.ts +0 -113
  58. package/compositions/theme/types.ts +0 -46
  59. package/compositions/theme/useTheme.ts +0 -269
  60. package/compositions/toast/index.ts +0 -10
  61. package/compositions/toast/useToast.ts +0 -176
  62. package/compositions/tooltip/index.ts +0 -9
  63. package/compositions/tooltip/useTooltip.ts +0 -10
  64. package/dist/compositions/commandPalette/index.d.ts +0 -11
  65. package/dist/compositions/commandPalette/types.d.ts +0 -20
  66. package/dist/compositions/commandPalette/useCommandPalette.d.ts +0 -32
  67. package/dist/compositions/contextMenu/index.d.ts +0 -10
  68. package/dist/compositions/contextMenu/types.d.ts +0 -12
  69. package/dist/compositions/contextMenu/useContextMenu.d.ts +0 -52
  70. package/dist/compositions/editor/index.d.ts +0 -10
  71. package/dist/compositions/editor/types.d.ts +0 -132
  72. package/dist/compositions/editor/useEditor.d.ts +0 -13
  73. package/dist/compositions/index.d.ts +0 -15
  74. package/dist/compositions/overlay/index.d.ts +0 -10
  75. package/dist/compositions/overlay/useOverlayStack.d.ts +0 -188
  76. package/dist/compositions/peekView/index.d.ts +0 -10
  77. package/dist/compositions/peekView/usePeekView.d.ts +0 -16
  78. package/dist/compositions/theme/index.d.ts +0 -11
  79. package/dist/compositions/theme/presets/compact.d.ts +0 -6
  80. package/dist/compositions/theme/presets/dark.d.ts +0 -2
  81. package/dist/compositions/theme/presets/index.d.ts +0 -11
  82. package/dist/compositions/theme/presets/light.d.ts +0 -2
  83. package/dist/compositions/theme/types.d.ts +0 -41
  84. package/dist/compositions/theme/useTheme.d.ts +0 -167
  85. package/dist/compositions/toast/index.d.ts +0 -10
  86. package/dist/compositions/toast/useToast.d.ts +0 -71
  87. package/dist/compositions/tooltip/index.d.ts +0 -9
  88. package/dist/compositions/tooltip/useTooltip.d.ts +0 -10
@@ -1 +1 @@
1
- dd5e7d65-f4f9-4e97-acdf-d3bb42303812
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, BASE_WEEK_NAME, BASE_MONTH_NAME } from '../useDatePicker';
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('初始化空值显示 placeholder', () => {
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('自定义 placeholder', () => {
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 空值恢复 placeholder', () => {
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, BASE_WEEK_NAME, BASE_MONTH_NAME, generateTimeColumn } from './useDatePicker';
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 = props.placeholder ?? '请选择日期...';
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('初始化空值显示 placeholder', () => {
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 空值恢复 placeholder', () => {
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 = resolvedProps.placeholder ?? '请选择时间...';
71
+ displayValue.value = '';
72
72
  needPlaceholder = true;
73
73
  } else {
74
74
  needPlaceholder = false;
@@ -1,8 +1,8 @@
1
1
  /**
2
- * @description tooltip runtime props
2
+ * @description tooltip 运行时 props
3
3
  * @author 阿怪
4
4
  * @date 2026/2/25
5
- * @version v2.0.0
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 barrel export
2
+ * @description tooltip core 导出
3
3
  * @author 阿怪
4
4
  * @date 2026/2/25
5
- * @version v2.0.0
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 type definitions
2
+ * @description tooltip 类型定义
3
3
  * @author 阿怪
4
4
  * @date 2026/2/25
5
- * @version v2.0.0
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 tooltip text content
17
+ * @description 提示内容,简单文本可直接通过 prop 传入
18
18
  * @type string
19
19
  * @default ''
20
20
  */
21
21
  content?: string;
22
22
  /**
23
- * @description preferred placement direction
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 show delay in milliseconds
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 manages show/hide with delay, positioning via usePopper, singleton, scroll/interaction dismissal
2
+ * @description tooltip composable,管理 hover 显示/隐藏及定位
3
3
  * @author 阿怪
4
4
  * @date 2026/2/25
5
- * @version v2.0.0
5
+ * @version v1.0.0
6
6
  *
7
7
  * 江湖的业务千篇一律,复杂的代码好几百行。
8
8
  */
9
- import { ref, onBeforeUnmount } from 'vue';
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
- const HIDE_DELAY = 100;
15
-
16
- /** Singleton: only one tooltip visible at a time */
17
- let activeHide: (() => void) | null = null;
12
+ export type TooltipStyle = {
13
+ position: string;
14
+ left: string;
15
+ top: string;
16
+ zIndex: string;
17
+ };
18
18
 
19
- export type TooltipPlacement = Placement;
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
- export type TooltipPositionData = {
22
- style: Record<string, string>;
23
- arrowStyle: Record<string, string>;
24
- placement: Placement;
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 positionData = ref<TooltipPositionData | null>(null);
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
- /** Immediately hide no delay */
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
- activeHide = hideImmediate;
90
- addInteractionListeners();
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
- const inView =
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 addScrollListeners = () => {
183
- window.addEventListener('scroll', onScroll, true);
184
- window.addEventListener('resize', onScroll, true);
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
- positionData,
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, BASE_WEEK_NAME, BASE_MONTH_NAME, generateTimeColumn } from './useDatePicker';
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。
@@ -4,4 +4,3 @@ export declare const TooltipCore: {
4
4
  useTooltip: typeof useTooltip;
5
5
  };
6
6
  export type { TooltipProps } from './props';
7
- export type { TooltipPlacement, TooltipPositionData } from './useTooltip';