@kine-design/core 0.0.1-beta.5 → 0.0.1-beta.6
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/components/base/affix/useAffix.ts +2 -1
- package/components/base/anchor/useAnchor.ts +2 -1
- package/components/base/autoComplete/useAutoComplete.ts +2 -1
- package/components/base/carousel/useCarousel.ts +2 -1
- package/components/base/cascader/useCascader.ts +2 -1
- package/components/base/checkbox/useCheckbox.ts +2 -1
- package/components/base/collapse/useCollapse.ts +2 -1
- package/components/base/datePicker/__tests__/useDatePicker.test.ts +239 -0
- package/components/base/dropdown/useDropdown.ts +2 -1
- package/components/base/image/__tests__/useImage.test.ts +174 -0
- package/components/base/input/useInput.ts +3 -1
- package/components/base/inputNumber/__tests__/useInputNumber.test.ts +153 -0
- package/components/base/inputNumber/useInputNumber.ts +53 -11
- package/components/base/popover/usePopover.ts +4 -3
- package/components/base/rate/useRate.ts +2 -1
- package/components/base/select/useSelect.ts +2 -1
- package/components/base/slider/useSlider.ts +2 -1
- package/components/base/steps/__tests__/useSteps.test.ts +46 -0
- package/components/base/switch/useSwitch.tsx +2 -1
- package/components/base/tabs/useTabs.ts +2 -1
- package/components/base/timePicker/__tests__/useTimePicker.test.ts +118 -0
- package/components/base/transfer/useTransfer.ts +2 -1
- package/components/base/tree/__tests__/tree.test.ts +214 -0
- package/components/message/notification/__tests__/useNotification.test.ts +129 -0
- package/components/message/popover/usePopover.ts +4 -4
- package/components/other/darkMode/useDarkMode.ts +2 -2
- package/components/template/menu/__tests__/useMenu.test.ts +157 -0
- package/components/template/pagination/__tests__/usePagination.test.ts +138 -0
- package/components/template/table/__tests__/useTable.test.ts +139 -0
- package/components/template/table/useTable.ts +2 -4
- package/components/types/hook.d.ts +11 -0
- package/compositions/common/__tests__/useDebounceFn.test.ts +62 -0
- package/compositions/common/__tests__/useEventListener.test.ts +71 -0
- package/compositions/common/__tests__/usePopover.test.ts +38 -0
- package/compositions/common/__tests__/useTeleport.test.ts +25 -0
- package/compositions/common/useEventListener.ts +3 -3
- package/compositions/common/useResizeObserver.ts +6 -2
- package/compositions/input/__tests__/useBooleanInput.test.ts +73 -0
- package/compositions/modal/__tests__/useModal.test.ts +92 -0
- package/compositions/modal/useModal.ts +2 -2
- package/compositions/popper/useClickAway.ts +4 -4
- package/compositions/utils/__tests__/filters.test.ts +136 -0
- package/compositions/virtualList/__tests__/useHeightCache.test.ts +97 -0
- package/dist/components/base/affix/useAffix.d.ts +2 -1
- package/dist/components/base/anchor/useAnchor.d.ts +2 -1
- package/dist/components/base/autoComplete/useAutoComplete.d.ts +2 -1
- package/dist/components/base/carousel/useCarousel.d.ts +2 -1
- package/dist/components/base/cascader/useCascader.d.ts +2 -1
- package/dist/components/base/checkbox/useCheckbox.d.ts +2 -1
- package/dist/components/base/collapse/useCollapse.d.ts +2 -1
- package/dist/components/base/datePicker/__tests__/useDatePicker.test.d.ts +1 -0
- package/dist/components/base/dropdown/useDropdown.d.ts +2 -1
- package/dist/components/base/image/__tests__/useImage.test.d.ts +1 -0
- package/dist/components/base/input/useInput.d.ts +2 -1
- package/dist/components/base/inputNumber/__tests__/useInputNumber.test.d.ts +1 -0
- package/dist/components/base/inputNumber/useInputNumber.d.ts +2 -1
- package/dist/components/base/popover/usePopover.d.ts +2 -1
- package/dist/components/base/rate/useRate.d.ts +2 -1
- package/dist/components/base/select/useSelect.d.ts +2 -1
- package/dist/components/base/slider/useSlider.d.ts +2 -1
- package/dist/components/base/steps/__tests__/useSteps.test.d.ts +1 -0
- package/dist/components/base/switch/useSwitch.d.ts +2 -1
- package/dist/components/base/tabs/useTabs.d.ts +2 -1
- package/dist/components/base/timePicker/__tests__/useTimePicker.test.d.ts +1 -0
- package/dist/components/base/transfer/useTransfer.d.ts +2 -1
- package/dist/components/base/tree/__tests__/tree.test.d.ts +1 -0
- package/dist/components/message/notification/__tests__/useNotification.test.d.ts +1 -0
- package/dist/components/message/popover/usePopover.d.ts +1 -1
- package/dist/components/other/darkMode/useDarkMode.d.ts +2 -3
- package/dist/components/template/menu/__tests__/useMenu.test.d.ts +1 -0
- package/dist/components/template/pagination/__tests__/usePagination.test.d.ts +1 -0
- package/dist/components/template/table/__tests__/useTable.test.d.ts +1 -0
- package/dist/compositions/common/__tests__/useDebounceFn.test.d.ts +1 -0
- package/dist/compositions/common/__tests__/useEventListener.test.d.ts +1 -0
- package/dist/compositions/common/__tests__/usePopover.test.d.ts +1 -0
- package/dist/compositions/common/__tests__/useTeleport.test.d.ts +1 -0
- package/dist/compositions/common/useEventListener.d.ts +2 -2
- package/dist/compositions/input/__tests__/useBooleanInput.test.d.ts +1 -0
- package/dist/compositions/modal/__tests__/useModal.test.d.ts +1 -0
- package/dist/compositions/modal/useModal.d.ts +2 -1
- package/dist/compositions/popper/useClickAway.d.ts +3 -3
- package/dist/compositions/utils/__tests__/filters.test.d.ts +1 -0
- package/dist/compositions/virtualList/__tests__/useHeightCache.test.d.ts +1 -0
- package/dist/core.js +64 -18
- package/dist/tools/__tests__/empty.test.d.ts +1 -0
- package/dist/tools/empty.d.ts +2 -2
- package/dist/tools/types.d.ts +1 -1
- package/dist/vitest.config.d.ts +10 -0
- package/package.json +6 -2
- package/tools/__tests__/empty.test.ts +72 -0
- package/tools/empty.ts +2 -2
- package/tools/types.ts +1 -1
- package/vitest.config.ts +17 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { HookContext } from '../../types/hook';
|
|
1
2
|
import { AffixProps } from './props';
|
|
2
|
-
export declare function useAffix(props: Required<AffixProps>, emit:
|
|
3
|
+
export declare function useAffix(props: Required<AffixProps>, emit: HookContext['emit']): {
|
|
3
4
|
wrapperRef: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
|
|
4
5
|
wrapRef: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
|
|
5
6
|
affixed: import('vue').Ref<boolean, boolean>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { HookContext } from '../../types/hook';
|
|
1
2
|
import { AnchorProps } from './props';
|
|
2
|
-
export declare function useAnchor(props: Required<AnchorProps>, emit:
|
|
3
|
+
export declare function useAnchor(props: Required<AnchorProps>, emit: HookContext['emit']): {
|
|
3
4
|
currentLink: import('vue').Ref<string, string>;
|
|
4
5
|
registerLink: (href: string) => void;
|
|
5
6
|
unregisterLink: (href: string) => void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AutoCompleteProps, AutoCompleteOption } from './props';
|
|
2
|
-
|
|
2
|
+
import { HookContext } from '../../types/hook';
|
|
3
|
+
export declare function useAutoComplete(props: AutoCompleteProps, ctx: HookContext): {
|
|
3
4
|
inputValue: import('vue').Ref<string, string>;
|
|
4
5
|
isOpen: import('vue').Ref<boolean, boolean>;
|
|
5
6
|
loading: import('vue').Ref<boolean, boolean>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { HookContext } from '../../types/hook';
|
|
1
2
|
import { CarouselProps } from './props';
|
|
2
|
-
export declare function useCarousel(props: Required<CarouselProps>, emit:
|
|
3
|
+
export declare function useCarousel(props: Required<CarouselProps>, emit: HookContext['emit'], count: () => number): {
|
|
3
4
|
activeIndex: import('vue').Ref<number, number>;
|
|
4
5
|
trackIndex: import('vue').Ref<number, number>;
|
|
5
6
|
disableTransition: import('vue').Ref<boolean, boolean>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CascaderOption, CascaderProps } from './props';
|
|
2
|
+
import { HookContext } from '../../types/hook';
|
|
2
3
|
/** 扁平化后的叶子路径,用于搜索 */
|
|
3
4
|
export interface FlatCascaderOption {
|
|
4
5
|
/** 从根到当前节点的完整路径节点列表 */
|
|
@@ -6,7 +7,7 @@ export interface FlatCascaderOption {
|
|
|
6
7
|
/** 路径标签拼接(用于搜索匹配) */
|
|
7
8
|
pathLabel: string;
|
|
8
9
|
}
|
|
9
|
-
export declare function useCascader(props: CascaderProps, ctx:
|
|
10
|
+
export declare function useCascader(props: CascaderProps, ctx: HookContext): {
|
|
10
11
|
isOpen: import('vue').Ref<boolean, boolean>;
|
|
11
12
|
searchQuery: import('vue').Ref<string, string>;
|
|
12
13
|
activePath: import('vue').Ref<{
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CheckboxProps } from './props';
|
|
2
|
-
|
|
2
|
+
import { HookContext } from '../../types/hook';
|
|
3
|
+
export declare function useCheckbox<Props extends Required<CheckboxProps>>(props: Props, ctx: HookContext): {
|
|
3
4
|
checkboxClass: (string | {
|
|
4
5
|
'm-disabled': boolean;
|
|
5
6
|
'm-indeterminate': boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CollapseProps } from './props';
|
|
2
|
-
|
|
2
|
+
import { HookContext } from '../../types/hook';
|
|
3
|
+
export declare function useCollapse(props: Required<CollapseProps>, ctx: HookContext): {
|
|
3
4
|
activeNames: import('vue').ComputedRef<(string | number)[]>;
|
|
4
5
|
isActive: (name: string | number) => boolean;
|
|
5
6
|
toggle: (name: string | number, disabled: boolean) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DropdownItemProps, DropdownProps } from './props';
|
|
2
|
-
|
|
2
|
+
import { HookContext } from '../../types/hook';
|
|
3
|
+
export declare function useDropdown(props: Required<DropdownProps>, ctx: HookContext): {
|
|
3
4
|
visible: import('vue').Ref<boolean, boolean>;
|
|
4
5
|
triggerRef: import('vue').Ref<HTMLElement | undefined, HTMLElement | undefined>;
|
|
5
6
|
menuRef: import('vue').Ref<HTMLElement | undefined, HTMLElement | undefined>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HTMLElementEvent } from '../../types/template';
|
|
2
|
-
|
|
2
|
+
import { HookContext } from '../../types/hook';
|
|
3
|
+
export declare function useInput<Props extends Record<string, any>>(props: Props, ctx: HookContext): {
|
|
3
4
|
baseProps: {
|
|
4
5
|
autofocus: any;
|
|
5
6
|
value: any;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { InputNumberProps } from './props';
|
|
2
2
|
import { HTMLElementEvent } from '../../types/template';
|
|
3
|
+
import { HookContext } from '../../types/hook';
|
|
3
4
|
export type InputNumber = string | number | null;
|
|
4
|
-
export declare function useInputNumber(props: Required<InputNumberProps>, ctx:
|
|
5
|
+
export declare function useInputNumber(props: Required<InputNumberProps>, ctx: HookContext): {
|
|
5
6
|
currentValue: import('vue').Ref<string | number, string | number>;
|
|
6
7
|
handleInputChange: (e: HTMLElementEvent<HTMLInputElement>) => void;
|
|
7
8
|
handleInputBlur: () => void;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Placement, PopperConfig, PositionStyle, usePopper } from '../../../compositions/popper/usePopper.ts';
|
|
2
2
|
import { PopoverProps } from './props';
|
|
3
3
|
import { Ref } from 'vue';
|
|
4
|
+
import { HookContext } from '../../types/hook';
|
|
4
5
|
export type IPopper = ReturnType<typeof usePopper>;
|
|
5
6
|
/**
|
|
6
7
|
* Popover 实例,管理定位、显示/隐藏状态
|
|
@@ -32,7 +33,7 @@ export declare class PopoverImpl {
|
|
|
32
33
|
toggle(): Promise<void>;
|
|
33
34
|
destroy(): void;
|
|
34
35
|
}
|
|
35
|
-
export declare function usePopover(props: Required<PopoverProps>, ctx:
|
|
36
|
+
export declare function usePopover(props: Required<PopoverProps>, ctx: HookContext): {
|
|
36
37
|
popoverEnter: () => void;
|
|
37
38
|
popoverLeave: () => void;
|
|
38
39
|
popoverRef: Ref<HTMLElement | undefined, HTMLElement | undefined>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { HookContext } from '../../types/hook';
|
|
1
2
|
import { RateProps } from './props';
|
|
2
|
-
export declare function useRate(props: Required<RateProps>, emit:
|
|
3
|
+
export declare function useRate(props: Required<RateProps>, emit: HookContext['emit']): {
|
|
3
4
|
hoverValue: import('vue').Ref<number | null, number | null>;
|
|
4
5
|
getStarState: (index: number) => "full" | "half" | "empty";
|
|
5
6
|
onMouseEnter: (e: MouseEvent, index: number) => void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SelectProps } from './props';
|
|
2
|
+
import { HookContext } from '../../types/hook';
|
|
2
3
|
export interface SelectOptionItem {
|
|
3
4
|
/** 原始值 */
|
|
4
5
|
value: any;
|
|
@@ -7,7 +8,7 @@ export interface SelectOptionItem {
|
|
|
7
8
|
/** 是否选中 */
|
|
8
9
|
isSelected: boolean;
|
|
9
10
|
}
|
|
10
|
-
export declare function useSelect(props: SelectProps, ctx:
|
|
11
|
+
export declare function useSelect(props: SelectProps, ctx: HookContext): {
|
|
11
12
|
inputValue: import('vue').Ref<string, string>;
|
|
12
13
|
isOpen: import('vue').Ref<boolean, boolean>;
|
|
13
14
|
fetchLoading: import('vue').Ref<boolean, boolean>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SliderProps } from './props';
|
|
2
|
-
|
|
2
|
+
import { HookContext } from '../../types/hook';
|
|
3
|
+
export declare function useSlider(props: Required<SliderProps>, ctx: HookContext): {
|
|
3
4
|
btnRef: import('vue').Ref<HTMLElement | null | undefined, HTMLElement | null | undefined>;
|
|
4
5
|
sliderRef: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
|
|
5
6
|
perRef: import('vue').Ref<number, number>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { SwitchProps } from './props';
|
|
2
|
+
import { HookContext } from '../../types/hook';
|
|
2
3
|
export declare const switchIsBoolean: (value: SwitchProps["modelValue"]) => value is boolean;
|
|
3
4
|
export declare const getIsActive: (value: SwitchProps["modelValue"], activeValue: SwitchProps["activeValue"]) => boolean;
|
|
4
|
-
export declare function useSwitch<Props extends Record<string, any>>(props: Props, ctx:
|
|
5
|
+
export declare function useSwitch<Props extends Record<string, any>>(props: Props, ctx: HookContext): {
|
|
5
6
|
getInfo: (key: keyof Pick<SwitchProps, "activeInfo" | "inactiveInfo">) => any;
|
|
6
7
|
changeSwitch: () => void;
|
|
7
8
|
switchClass: import('vue').ComputedRef<(string | {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { HookContext } from '../../types/hook';
|
|
2
|
+
export declare function useTabs<Props extends Record<string, unknown>>(props: Props, ctx: HookContext): {
|
|
2
3
|
activeTab: import('vue').ComputedRef<string | number>;
|
|
3
4
|
isActive: (name: string | number) => boolean;
|
|
4
5
|
switchTab: (name: string | number, disabled?: boolean) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TransferItem, TransferProps } from './props';
|
|
2
|
-
|
|
2
|
+
import { HookContext } from '../../types/hook';
|
|
3
|
+
export declare function useTransfer(props: TransferProps, ctx: HookContext): {
|
|
3
4
|
leftSearch: import('vue').Ref<string, string>;
|
|
4
5
|
rightSearch: import('vue').Ref<string, string>;
|
|
5
6
|
leftData: import('vue').ComputedRef<TransferItem[]>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import { HookContext } from '../../types/hook';
|
|
1
2
|
import { DarkModeProps } from './props';
|
|
2
3
|
/** 将暗色状态同步到 html[dark] attribute */
|
|
3
4
|
declare function applyDarkAttr(isDark: boolean): void;
|
|
4
|
-
export declare function useDarkMode(props: DarkModeProps, ctx: {
|
|
5
|
-
emit: (event: string, ...args: any[]) => void;
|
|
6
|
-
}): {
|
|
5
|
+
export declare function useDarkMode(props: DarkModeProps, ctx: Pick<HookContext, 'emit'>): {
|
|
7
6
|
isDark: import('vue').Ref<boolean, boolean>;
|
|
8
7
|
toggle: () => void;
|
|
9
8
|
applyDarkAttr: typeof applyDarkAttr;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
8
|
*/
|
|
9
9
|
export type EventListenerOptions = {
|
|
10
|
-
target:
|
|
10
|
+
target: EventTarget | (() => EventTarget);
|
|
11
11
|
event: string;
|
|
12
12
|
handler: EventListenerOrEventListenerObject;
|
|
13
13
|
};
|
|
@@ -15,5 +15,5 @@ export default function useEventListener(options: EventListenerOptions): {
|
|
|
15
15
|
add: () => void;
|
|
16
16
|
remove: () => void;
|
|
17
17
|
onMounted: () => void;
|
|
18
|
-
|
|
18
|
+
onBeforeUnmount: () => void;
|
|
19
19
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { HookContext } from '../../components/types/hook';
|
|
1
2
|
import { ModelMask } from '../../types/common/model';
|
|
2
3
|
export interface UseModalProps {
|
|
3
4
|
visible?: boolean;
|
|
4
5
|
mask?: ModelMask;
|
|
5
6
|
}
|
|
6
|
-
export declare function useModal(props: UseModalProps, emit:
|
|
7
|
+
export declare function useModal(props: UseModalProps, emit: HookContext['emit']): {
|
|
7
8
|
visible: import('vue').Ref<boolean, boolean>;
|
|
8
9
|
open: () => void;
|
|
9
10
|
close: () => void;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export default function useClickAway(options: {
|
|
2
|
-
target:
|
|
3
|
-
handler: (event:
|
|
2
|
+
target: EventTarget | (() => EventTarget | null | undefined);
|
|
3
|
+
handler: (event: PointerEvent) => void;
|
|
4
4
|
}): {
|
|
5
5
|
add: () => void;
|
|
6
6
|
remove: () => void;
|
|
7
7
|
onMounted: () => void;
|
|
8
|
-
|
|
8
|
+
onBeforeUnmount: () => void;
|
|
9
9
|
} | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/core.js
CHANGED
|
@@ -1091,20 +1091,58 @@ var props$39 = {
|
|
|
1091
1091
|
* @description inputNumber composable
|
|
1092
1092
|
* @author 阿怪
|
|
1093
1093
|
* @date 2026/2/25 00:00
|
|
1094
|
-
* @version v1.
|
|
1094
|
+
* @version v1.2.0
|
|
1095
1095
|
*
|
|
1096
1096
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
1097
|
+
*
|
|
1098
|
+
* v1.2.0 changelog:
|
|
1099
|
+
* - emit 类型保真:string 入 string 出,number 入 number 出;空值一律 emit null
|
|
1100
|
+
* - 内部 currentValue 保留中间态('-' / '0.' / ''),仅在 emit 时归一
|
|
1101
|
+
*/
|
|
1102
|
+
/** 用户输入中间态:不构成可 emit 的数字,emit null */
|
|
1103
|
+
var MID_STATES = new Set([
|
|
1104
|
+
"",
|
|
1105
|
+
"-",
|
|
1106
|
+
".",
|
|
1107
|
+
"-."
|
|
1108
|
+
]);
|
|
1109
|
+
/**
|
|
1110
|
+
* 把任意内部值归一为 number | null。
|
|
1111
|
+
* 规则:
|
|
1112
|
+
* - null/undefined/中间态 → null
|
|
1113
|
+
* - 末尾小数点去掉('1.' → '1')
|
|
1114
|
+
* - 非法 NaN → null
|
|
1115
|
+
* - 其他 → Number(v)
|
|
1097
1116
|
*/
|
|
1117
|
+
var normalize = (v) => {
|
|
1118
|
+
if (v === null || v === void 0) return null;
|
|
1119
|
+
const s = String(v);
|
|
1120
|
+
if (MID_STATES.has(s)) return null;
|
|
1121
|
+
const cleaned = s.endsWith(".") ? s.slice(0, -1) : s;
|
|
1122
|
+
const n = Number(cleaned);
|
|
1123
|
+
return Number.isNaN(n) ? null : n;
|
|
1124
|
+
};
|
|
1098
1125
|
function useInputNumber(props, ctx) {
|
|
1099
1126
|
const currentValue = ref(props.modelValue ?? "");
|
|
1127
|
+
/**
|
|
1128
|
+
* 按外部 modelValue 的当前 typeof 决定出参类型,保真 v-model 声明。
|
|
1129
|
+
* - null/undefined → null
|
|
1130
|
+
* - 外部当前是 string → emit String(n)
|
|
1131
|
+
* - 否则 → emit n(默认 number)
|
|
1132
|
+
*/
|
|
1133
|
+
const toEmitValue = (n) => {
|
|
1134
|
+
if (n === null) return null;
|
|
1135
|
+
return typeof props.modelValue === "string" ? String(n) : n;
|
|
1136
|
+
};
|
|
1100
1137
|
const updateInput = (oldVal) => {
|
|
1101
|
-
|
|
1102
|
-
ctx.emit("
|
|
1138
|
+
const out = toEmitValue(normalize(currentValue.value));
|
|
1139
|
+
ctx.emit("update:modelValue", out);
|
|
1140
|
+
ctx.emit("change", out, oldVal);
|
|
1103
1141
|
};
|
|
1104
1142
|
const setCurrentValue = (newVal, e) => {
|
|
1105
1143
|
const oldVal = currentValue.value;
|
|
1106
1144
|
const { min, max, precision } = props;
|
|
1107
|
-
if (oldVal === newVal) return;
|
|
1145
|
+
if (String(oldVal) === String(newVal)) return;
|
|
1108
1146
|
else if (+newVal >= +max) newVal = max;
|
|
1109
1147
|
else if (+newVal <= +min) newVal = min;
|
|
1110
1148
|
else if (precision !== 0 && String(newVal).includes(".") && `${newVal}`.length - (`${newVal}`.indexOf(".") + 1) >= precision) newVal = Number(`${newVal}`.substring(0, `${newVal}`.indexOf(".") + (precision + 1)));
|
|
@@ -1132,11 +1170,15 @@ function useInputNumber(props, ctx) {
|
|
|
1132
1170
|
validate(val, e);
|
|
1133
1171
|
};
|
|
1134
1172
|
const handleInputBlur = () => {
|
|
1173
|
+
const oldVal = currentValue.value;
|
|
1135
1174
|
if (currentValue.value === "-") currentValue.value = "";
|
|
1136
1175
|
else if (currentValue.value === "-0") currentValue.value = 0;
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1176
|
+
else {
|
|
1177
|
+
const str = String(currentValue.value);
|
|
1178
|
+
if (str.indexOf(".") === str.length - 1 && str.length > 0) currentValue.value = str.replace(/\.$/g, "");
|
|
1179
|
+
}
|
|
1180
|
+
const n = normalize(currentValue.value);
|
|
1181
|
+
currentValue.value = n === null ? "" : n;
|
|
1140
1182
|
updateInput(oldVal);
|
|
1141
1183
|
};
|
|
1142
1184
|
/**
|
|
@@ -1252,13 +1294,17 @@ function useResizeObserver(target, callback, options = {}) {
|
|
|
1252
1294
|
observer = void 0;
|
|
1253
1295
|
}
|
|
1254
1296
|
};
|
|
1255
|
-
watch(target, () => {
|
|
1297
|
+
const stopWatch = watch(target, () => {
|
|
1256
1298
|
if (target.value) {
|
|
1257
1299
|
cleanup();
|
|
1258
1300
|
observer = new ResizeObserver(callback);
|
|
1259
1301
|
observer.observe(target.value, options);
|
|
1260
1302
|
}
|
|
1261
1303
|
});
|
|
1304
|
+
onBeforeUnmount(() => {
|
|
1305
|
+
cleanup();
|
|
1306
|
+
stopWatch();
|
|
1307
|
+
});
|
|
1262
1308
|
return { cleanup };
|
|
1263
1309
|
}
|
|
1264
1310
|
//#endregion
|
|
@@ -1642,14 +1688,14 @@ function useEventListener(options) {
|
|
|
1642
1688
|
const onMounted = () => {
|
|
1643
1689
|
add();
|
|
1644
1690
|
};
|
|
1645
|
-
const
|
|
1691
|
+
const onBeforeUnmount = () => {
|
|
1646
1692
|
remove();
|
|
1647
1693
|
};
|
|
1648
1694
|
return {
|
|
1649
1695
|
add,
|
|
1650
1696
|
remove,
|
|
1651
1697
|
onMounted,
|
|
1652
|
-
|
|
1698
|
+
onBeforeUnmount
|
|
1653
1699
|
};
|
|
1654
1700
|
}
|
|
1655
1701
|
//#endregion
|
|
@@ -1807,8 +1853,8 @@ function usePopover$1(props, ctx) {
|
|
|
1807
1853
|
});
|
|
1808
1854
|
onBeforeUnmount(() => {
|
|
1809
1855
|
if (clickAwayInstance) {
|
|
1810
|
-
const {
|
|
1811
|
-
|
|
1856
|
+
const { onBeforeUnmount } = clickAwayInstance;
|
|
1857
|
+
onBeforeUnmount();
|
|
1812
1858
|
}
|
|
1813
1859
|
instance?.destroy();
|
|
1814
1860
|
});
|
|
@@ -3418,8 +3464,8 @@ function useTable() {
|
|
|
3418
3464
|
});
|
|
3419
3465
|
/** 从 data[i] 中安全取值 */
|
|
3420
3466
|
const getData = (i, param) => {
|
|
3421
|
-
if (data[i]
|
|
3422
|
-
return "";
|
|
3467
|
+
if (data[i] == null) return "";
|
|
3468
|
+
return data[i][param] ?? "";
|
|
3423
3469
|
};
|
|
3424
3470
|
/** 向每行的 td 列表中追加一列 */
|
|
3425
3471
|
const pushTd = (param, bodySlot, style) => {
|
|
@@ -4009,7 +4055,7 @@ function usePopover(options, lifecycle) {
|
|
|
4009
4055
|
const popoverLeave = () => {
|
|
4010
4056
|
if (props.hover) instance?.hide();
|
|
4011
4057
|
};
|
|
4012
|
-
const
|
|
4058
|
+
const onBeforeUnmountEvents = [];
|
|
4013
4059
|
onMounted(() => {
|
|
4014
4060
|
if (!popoverRef.value || !contentRef.value) return;
|
|
4015
4061
|
popperInstance.value = createPopover(popoverRef.value, contentRef.value, arrowRef.value, {
|
|
@@ -4026,8 +4072,8 @@ function usePopover(options, lifecycle) {
|
|
|
4026
4072
|
});
|
|
4027
4073
|
onBeforeUnmount(() => {
|
|
4028
4074
|
if (clickAwayInstance) {
|
|
4029
|
-
const {
|
|
4030
|
-
|
|
4075
|
+
const { onBeforeUnmount } = clickAwayInstance;
|
|
4076
|
+
onBeforeUnmount();
|
|
4031
4077
|
}
|
|
4032
4078
|
instance?.destroy();
|
|
4033
4079
|
});
|
|
@@ -4053,7 +4099,7 @@ function usePopover(options, lifecycle) {
|
|
|
4053
4099
|
popperInstance,
|
|
4054
4100
|
style,
|
|
4055
4101
|
arrowStyle,
|
|
4056
|
-
lifecycle: {
|
|
4102
|
+
lifecycle: { onBeforeUnmountEvents }
|
|
4057
4103
|
};
|
|
4058
4104
|
}
|
|
4059
4105
|
//#endregion
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/tools/empty.d.ts
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
* 支持稍多类型的判断非空的方法
|
|
11
11
|
* @param value
|
|
12
12
|
*/
|
|
13
|
-
export declare const notEmpty: (value:
|
|
13
|
+
export declare const notEmpty: (value: unknown) => number | boolean | undefined;
|
|
14
14
|
/**
|
|
15
15
|
* 判断为空的方法,即notEmpty的取反
|
|
16
16
|
* @param value
|
|
17
17
|
*/
|
|
18
|
-
export declare const isEmpty: (value:
|
|
18
|
+
export declare const isEmpty: (value: unknown) => boolean;
|
package/dist/tools/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kine-design/core",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.6",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/core.js",
|
|
@@ -19,8 +19,12 @@
|
|
|
19
19
|
"dist"
|
|
20
20
|
]
|
|
21
21
|
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"vitest": "^4.1.0"
|
|
24
|
+
},
|
|
22
25
|
"scripts": {
|
|
23
|
-
"build": "vite build --config vite.config.build.ts"
|
|
26
|
+
"build": "vite build --config vite.config.build.ts",
|
|
27
|
+
"test": "vitest --config vitest.config.ts --run"
|
|
24
28
|
},
|
|
25
29
|
"module": "./dist/core.js",
|
|
26
30
|
"exports": {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description notEmpty / isEmpty 工具函数测试
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2026/3/23
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import { describe, expect, it } from 'vitest';
|
|
10
|
+
import { notEmpty, isEmpty } from '../empty';
|
|
11
|
+
|
|
12
|
+
describe('notEmpty', () => {
|
|
13
|
+
// 基本空值
|
|
14
|
+
it('null 为空', () => expect(notEmpty(null)).toBe(false));
|
|
15
|
+
it('undefined 为空', () => expect(notEmpty(undefined)).toBe(false));
|
|
16
|
+
|
|
17
|
+
// 字符串
|
|
18
|
+
it('空字符串为空', () => expect(notEmpty('')).toBe(false));
|
|
19
|
+
it('非空字符串非空', () => expect(notEmpty('hello')).toBe(true));
|
|
20
|
+
|
|
21
|
+
// 数字
|
|
22
|
+
it('0 非空', () => expect(notEmpty(0)).toBe(true));
|
|
23
|
+
it('正数非空', () => expect(notEmpty(42)).toBe(true));
|
|
24
|
+
it('NaN 非空(数字类型)', () => expect(notEmpty(NaN)).toBe(true));
|
|
25
|
+
|
|
26
|
+
// 布尔
|
|
27
|
+
it('false 非空', () => expect(notEmpty(false)).toBe(true));
|
|
28
|
+
it('true 非空', () => expect(notEmpty(true)).toBe(true));
|
|
29
|
+
|
|
30
|
+
// 函数
|
|
31
|
+
it('函数非空', () => expect(notEmpty(() => {})).toBe(true));
|
|
32
|
+
|
|
33
|
+
// Symbol
|
|
34
|
+
it('空 Symbol 为空', () => expect(notEmpty(Symbol())).toBe(false));
|
|
35
|
+
it('有描述的 Symbol 非空', () => expect(notEmpty(Symbol('desc'))).toBe(true));
|
|
36
|
+
|
|
37
|
+
// 数组
|
|
38
|
+
it('空数组为空', () => expect(notEmpty([])).toBe(false));
|
|
39
|
+
it('非空数组非空', () => expect(notEmpty([1])).toBe(true));
|
|
40
|
+
|
|
41
|
+
// 对象
|
|
42
|
+
it('空对象为空', () => expect(notEmpty({})).toBe(false));
|
|
43
|
+
it('非空对象非空', () => expect(notEmpty({ a: 1 })).toBe(true));
|
|
44
|
+
|
|
45
|
+
// Map / Set
|
|
46
|
+
it('空 Map 为空', () => expect(notEmpty(new Map())).toBe(false));
|
|
47
|
+
it('非空 Map 非空', () => expect(notEmpty(new Map([['a', 1]]))).toBe(true));
|
|
48
|
+
it('空 Set 为空', () => expect(notEmpty(new Set())).toBe(false));
|
|
49
|
+
it('非空 Set 非空', () => expect(notEmpty(new Set([1]))).toBe(true));
|
|
50
|
+
|
|
51
|
+
// Date
|
|
52
|
+
it('有效 Date 非空', () => expect(notEmpty(new Date())).toBe(true));
|
|
53
|
+
it('Invalid Date 为空', () => expect(notEmpty(new Date('invalid'))).toBe(false));
|
|
54
|
+
|
|
55
|
+
// RegExp
|
|
56
|
+
it('空正则为空', () => expect(notEmpty(new RegExp(''))).toBe(false));
|
|
57
|
+
it('非空正则非空', () => expect(notEmpty(/abc/)).toBe(true));
|
|
58
|
+
|
|
59
|
+
// TypedArray
|
|
60
|
+
it('空 Uint8Array 为空', () => expect(notEmpty(new Uint8Array(0))).toBe(0));
|
|
61
|
+
it('非空 Float64Array 非空', () => expect(notEmpty(new Float64Array([1.5]))).toBe(1));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('isEmpty', () => {
|
|
65
|
+
it('是 notEmpty 的取反', () => {
|
|
66
|
+
expect(isEmpty(null)).toBe(true);
|
|
67
|
+
expect(isEmpty('hello')).toBe(false);
|
|
68
|
+
expect(isEmpty(0)).toBe(false);
|
|
69
|
+
expect(isEmpty([])).toBe(true);
|
|
70
|
+
expect(isEmpty({})).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
});
|
package/tools/empty.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* 支持稍多类型的判断非空的方法
|
|
12
12
|
* @param value
|
|
13
13
|
*/
|
|
14
|
-
export const notEmpty = (value:
|
|
14
|
+
export const notEmpty = (value: unknown) => {
|
|
15
15
|
// 先处理基本类型
|
|
16
16
|
// null
|
|
17
17
|
// undefined
|
|
@@ -78,4 +78,4 @@ export const notEmpty = (value: any) => {
|
|
|
78
78
|
* 判断为空的方法,即notEmpty的取反
|
|
79
79
|
* @param value
|
|
80
80
|
*/
|
|
81
|
-
export const isEmpty = (value:
|
|
81
|
+
export const isEmpty = (value: unknown) => !notEmpty(value);
|
package/tools/types.ts
CHANGED