@kine-design/core 0.0.1-beta.10 → 0.0.1-beta.12

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.
@@ -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;
@@ -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。
@@ -0,0 +1,14 @@
1
+ import { ComputedRef, InjectionKey, Ref } from 'vue';
2
+ import { KineLocaleName, KineLocaleMessages } from '../../locale/types';
3
+ /** Accepted `locale` values: a built-in name, or a full custom dictionary. */
4
+ export type KineLocaleConfig = KineLocaleName | KineLocaleMessages;
5
+ export declare const KINE_LOCALE_KEY: InjectionKey<Ref<KineLocaleConfig | undefined>>;
6
+ /**
7
+ * Resolve the active message dictionary from the nearest `KConfigProvider`.
8
+ * Falls back to the default (zh) pack when no provider is present.
9
+ */
10
+ export declare function useLocale(): ComputedRef<KineLocaleMessages>;
11
+ /** Set the global active dictionary. Called by KConfigProvider on locale change. */
12
+ export declare function setActiveLocaleMessages(config: KineLocaleConfig | undefined): void;
13
+ /** Read the global active dictionary from non-component (pure-function) code. */
14
+ export declare function getActiveLocaleMessages(): KineLocaleMessages;