donar 0.0.1
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/.cspell/custom-dictionary.txt +5 -0
- package/.github/actions/base-check/action.yaml +27 -0
- package/.github/actions/env-setup/action.yaml +74 -0
- package/.github/workflows/pr-check.yaml +33 -0
- package/.github/workflows/release.yaml +112 -0
- package/.gitignore +41 -0
- package/.node-version +1 -0
- package/.npmignore +7 -0
- package/.vscode/extensions.json +10 -0
- package/.vscode/settings.json +44 -0
- package/LICENSE +21 -0
- package/README.md +160 -0
- package/commitlint.config.ts +3 -0
- package/cspell.json +27 -0
- package/dist/components.esm.js +2 -0
- package/dist/css/components.C24nnsjt.css +1 -0
- package/dist/hooks.esm.js +185 -0
- package/dist/index.esm.js +4 -0
- package/dist/js/components.nFDoAkCq.js +198 -0
- package/dist/js/utils.CVb1iSAU.js +330 -0
- package/dist/types/components.d.ts +1 -0
- package/dist/types/hooks.d.ts +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/src/components/async-custom-show/index.d.ts +22 -0
- package/dist/types/src/components/carousel/hooks.d.ts +74 -0
- package/dist/types/src/components/carousel/index.d.ts +88 -0
- package/dist/types/src/components/custom-show/index.d.ts +21 -0
- package/dist/types/src/components/error-boundary/index.d.ts +31 -0
- package/dist/types/src/components/index.d.ts +8 -0
- package/dist/types/src/hooks/async-guard.d.ts +9 -0
- package/dist/types/src/hooks/index.d.ts +5 -0
- package/dist/types/src/hooks/observer.d.ts +70 -0
- package/dist/types/src/hooks/state.d.ts +44 -0
- package/dist/types/src/hooks/storage.d.ts +25 -0
- package/dist/types/src/hooks/timer.d.ts +16 -0
- package/dist/types/src/index.d.ts +3 -0
- package/dist/types/src/test/emiter-test.d.ts +1 -0
- package/dist/types/src/test/index.d.ts +1 -0
- package/dist/types/src/test/retry-async-test.d.ts +1 -0
- package/dist/types/src/utils/class-singleton.d.ts +6 -0
- package/dist/types/src/utils/concurrency.d.ts +17 -0
- package/dist/types/src/utils/debounce.d.ts +8 -0
- package/dist/types/src/utils/deep-copy.d.ts +11 -0
- package/dist/types/src/utils/dev.d.ts +8 -0
- package/dist/types/src/utils/download.d.ts +15 -0
- package/dist/types/src/utils/event-emitter/helpers.d.ts +36 -0
- package/dist/types/src/utils/event-emitter/index.d.ts +65 -0
- package/dist/types/src/utils/fetch-xhr/helpers.d.ts +28 -0
- package/dist/types/src/utils/fetch-xhr/index.d.ts +25 -0
- package/dist/types/src/utils/hash.d.ts +8 -0
- package/dist/types/src/utils/index.d.ts +15 -0
- package/dist/types/src/utils/is-deep-plain-equal.d.ts +15 -0
- package/dist/types/src/utils/json-convert.d.ts +66 -0
- package/dist/types/src/utils/micro-queue-scheduler.d.ts +14 -0
- package/dist/types/src/utils/raf-interval.d.ts +16 -0
- package/dist/types/src/utils/record-typed-map.d.ts +27 -0
- package/dist/types/src/utils/retry-async.d.ts +9 -0
- package/dist/types/src/utils/thenable.d.ts +15 -0
- package/dist/types/utils.d.ts +1 -0
- package/dist/utils.esm.js +2 -0
- package/eslint.config.ts +48 -0
- package/lint-staged.config.ts +13 -0
- package/oxfmt.config.ts +14 -0
- package/package.json +90 -0
- package/pnpm-workspace.yaml +3 -0
- package/scripts/sync-node-version/index.js +31 -0
- package/simple-git-hooks.js +4 -0
- package/src/components/async-custom-show/index.tsx +37 -0
- package/src/components/carousel/hooks.ts +312 -0
- package/src/components/carousel/index.module.scss +163 -0
- package/src/components/carousel/index.tsx +215 -0
- package/src/components/custom-show/index.tsx +31 -0
- package/src/components/error-boundary/index.tsx +48 -0
- package/src/components/index.ts +11 -0
- package/src/hooks/async-guard.ts +53 -0
- package/src/hooks/index.ts +5 -0
- package/src/hooks/observer.ts +236 -0
- package/src/hooks/state.ts +140 -0
- package/src/hooks/storage.ts +103 -0
- package/src/hooks/timer.ts +42 -0
- package/src/index.ts +3 -0
- package/src/test/emiter-test.ts +19 -0
- package/src/test/index.ts +35 -0
- package/src/test/retry-async-test.ts +8 -0
- package/src/utils/class-singleton.ts +23 -0
- package/src/utils/concurrency.ts +49 -0
- package/src/utils/debounce.ts +20 -0
- package/src/utils/deep-copy.ts +132 -0
- package/src/utils/dev.ts +16 -0
- package/src/utils/download.ts +39 -0
- package/src/utils/event-emitter/helpers.ts +80 -0
- package/src/utils/event-emitter/index.ts +171 -0
- package/src/utils/fetch-xhr/helpers.ts +85 -0
- package/src/utils/fetch-xhr/index.ts +103 -0
- package/src/utils/hash.ts +25 -0
- package/src/utils/index.ts +18 -0
- package/src/utils/is-deep-plain-equal.ts +45 -0
- package/src/utils/json-convert.ts +257 -0
- package/src/utils/micro-queue-scheduler.ts +38 -0
- package/src/utils/raf-interval.ts +42 -0
- package/src/utils/record-typed-map.ts +38 -0
- package/src/utils/retry-async.ts +30 -0
- package/src/utils/thenable.ts +30 -0
- package/tsconfig.json +43 -0
- package/types/scss.d.ts +10 -0
- package/vite.config.ts +51 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { SetStateAction } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* @author sonion
|
|
4
|
+
* @description 创建静态的state, 不会触发组件重新渲染
|
|
5
|
+
* @param {T} initialValue - 初始值
|
|
6
|
+
*/
|
|
7
|
+
export declare function useStaticState<T>(initialValue: T): [() => T, (t: T) => void, (t?: T) => T];
|
|
8
|
+
export declare function useStaticState<T>(initialValue?: undefined): [() => T | undefined, (t: T) => void, (t?: T) => T | undefined];
|
|
9
|
+
/**
|
|
10
|
+
* @author sonion
|
|
11
|
+
* @description 创建最新的回调函数,不触发重新执行,同时避免闭包问题。
|
|
12
|
+
* 作用类似19.2的useEffectEvent,但原理和用法不同。
|
|
13
|
+
* @param {T} dep - 依赖函数、依赖函数数组、依赖函数对象
|
|
14
|
+
* @returns {()=>T} - 获取最新回调函数、依赖函数数组、依赖函数对象的方法
|
|
15
|
+
*/
|
|
16
|
+
export declare function useLatestCallback<T extends (...args: never) => unknown>(dep: T): () => T;
|
|
17
|
+
export declare function useLatestCallback<T extends (...args: never) => unknown>(dep?: T | undefined): () => T | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* @author sonion
|
|
20
|
+
* @description 创建相同值不触发组件重新渲染的state。和useCreateSafeRef类似,但useCreateSafeRef更专注于ref
|
|
21
|
+
* @param params - 参数对象
|
|
22
|
+
* @param {T} params.initialValue - 初始值
|
|
23
|
+
* @param {(val: T) => void} [params.onChange] - 变化回调
|
|
24
|
+
* @param {(prev: T, next: T) => boolean} [params.hasDiff] - 对比函数,默认对比引用是否不相同。
|
|
25
|
+
* @param {boolean} [params.onlyEvent] - 是否仅触发事件,不更新值,避免重渲染
|
|
26
|
+
*/
|
|
27
|
+
export declare function useDistinctState<T>(params: {
|
|
28
|
+
initialValue: T | (() => T);
|
|
29
|
+
onChange?: (val: T) => void;
|
|
30
|
+
hasDiff?: (prev?: T, next?: T) => boolean;
|
|
31
|
+
onlyEvent: true;
|
|
32
|
+
}): [undefined, (val: SetStateAction<T>) => void, () => T];
|
|
33
|
+
export declare function useDistinctState<T>(params: {
|
|
34
|
+
initialValue: T | (() => T);
|
|
35
|
+
onChange?: (val: T) => void;
|
|
36
|
+
hasDiff?: (prev?: T, next?: T) => boolean;
|
|
37
|
+
onlyEvent?: false;
|
|
38
|
+
}): [T, (val: SetStateAction<T>) => void, () => T];
|
|
39
|
+
/**
|
|
40
|
+
* @author sonion
|
|
41
|
+
* @description 创建安全的Ref引用
|
|
42
|
+
* @param {(oldNode?: T, newNode?: T) => boolean} [hasDiff] - 对比函数,默认对比引用是否不相同。
|
|
43
|
+
*/
|
|
44
|
+
export declare const useCreateSafeRef: <T extends object = HTMLElement>(hasDiff?: (oldNode?: T, newNode?: T) => boolean) => readonly [T | undefined, (node: T | null) => void, import('react').MutableRefObject<boolean>];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useDistinctState } from './state';
|
|
2
|
+
type StorageParams<T> = Omit<Parameters<typeof useDistinctState<T>>[0], 'onlyEvent'> & {
|
|
3
|
+
/** 储存的key */
|
|
4
|
+
key: string;
|
|
5
|
+
/** 储存类型。 localStorage 或 sessionStorage */
|
|
6
|
+
storage?: typeof localStorage | typeof sessionStorage;
|
|
7
|
+
/** 初始化类型检查函数,检查不通过使用初始值。可避免类型不对引起的错误 */
|
|
8
|
+
checkType?: (val: T) => boolean;
|
|
9
|
+
/** tab关闭前的回调, 相同key的不同回调只有初始生效。 */
|
|
10
|
+
beforeunload?: () => void;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* @author sonion
|
|
14
|
+
* @description 本地储存
|
|
15
|
+
* @param params - 参数对象
|
|
16
|
+
* @param params.key - 储存的key
|
|
17
|
+
* @param params.initialValue - 初始值
|
|
18
|
+
* @param [params.hasDiff] - 对比函数,默认对比引用是否不相同。
|
|
19
|
+
* @param params.onChange - 变化回调
|
|
20
|
+
* @param [params.storage] - 储存类型。 localStorage 或 sessionStorage
|
|
21
|
+
* @param [params.checkType] - 初始化类型检查函数,检查不通过使用初始值。可避免类型不对引起的错误
|
|
22
|
+
* @param [params.beforeunload] - tab关闭前的回调, 相同key的不同回调只有初始生效。
|
|
23
|
+
*/
|
|
24
|
+
export declare const useStorage: <T>({ key, initialValue, hasDiff, onChange, storage, checkType, beforeunload, }: StorageParams<T>) => readonly [T, (value: T | ((val: T) => T)) => void];
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author sonion
|
|
3
|
+
* @description 自管理定时器的interval
|
|
4
|
+
* @param {()=>void} cb - 回调函数
|
|
5
|
+
* @param {number} duration - 时间间隔
|
|
6
|
+
* @returns {[() => void, () => void]} - [启动函数, 清除函数]
|
|
7
|
+
*/
|
|
8
|
+
export declare const useInterval: (cb: () => void, duration: number) => (() => void)[];
|
|
9
|
+
/**
|
|
10
|
+
* @author sonion
|
|
11
|
+
* @description 自管理定时器的rAfInterval
|
|
12
|
+
* @param {()=>void} cb - 回调函数
|
|
13
|
+
* @param {number} duration - 时间间隔
|
|
14
|
+
* @returns {[() => void, () => void]} - [启动函数, 清除函数]
|
|
15
|
+
*/
|
|
16
|
+
export declare const useRAfInterval: (cb: () => void, duration: number) => readonly [() => void, () => void];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author sonion
|
|
3
|
+
* @description 并发控制器
|
|
4
|
+
* @param {number} concurrency - 并发数
|
|
5
|
+
*/
|
|
6
|
+
export declare class ConcurrencyController<T> {
|
|
7
|
+
/** 任务队列 */
|
|
8
|
+
private queue;
|
|
9
|
+
/** 并发数 */
|
|
10
|
+
private concurrency;
|
|
11
|
+
/** 当前运行中的任务数 */
|
|
12
|
+
private running;
|
|
13
|
+
constructor(concurrency?: number);
|
|
14
|
+
push(task: () => Promise<T>): Promise<T>;
|
|
15
|
+
run(): void;
|
|
16
|
+
private next;
|
|
17
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author sonion
|
|
3
|
+
* @description 防抖
|
|
4
|
+
* @param {(...args: unknown[])=>void} fn - 防抖的函数
|
|
5
|
+
* @param {number} delay - 毫秒
|
|
6
|
+
* @returns {(...args: unknown[])=>void} - 防抖后的函数
|
|
7
|
+
*/
|
|
8
|
+
export declare const debounce: <A extends unknown[], R, T = unknown>(fn: (this: T, ...args: A) => R, delay: number) => ((this: T, ...args: A) => void);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type DeepCloneResult = Record<string | symbol, unknown>;
|
|
2
|
+
type DeepCloneParamReturn = DeepCloneResult | Array<unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* @author sonion
|
|
5
|
+
* @description 解决了循环引用、原型一致的深度克隆 // 原生structuredClone 没解决Symbol、原型链,兼容到22年8月
|
|
6
|
+
* @param {DeepCloneParamReturn} value 要克隆的对象
|
|
7
|
+
* @param {boolean} [isCopyProto] 是否拷贝原型链 -默认值:true
|
|
8
|
+
* @returns {DeepCloneParamReturn} - 克隆后的对象
|
|
9
|
+
*/
|
|
10
|
+
export declare const deepClone: <T extends DeepCloneParamReturn, U extends DeepCloneParamReturn>(value: T, isCopyProto?: boolean) => U;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author sonion
|
|
3
|
+
* @description 浏览器原生下载。需要content-disposition: attachment; filename=xxx响应头支持
|
|
4
|
+
* a元素、window.open;target为_self短时间打开多个,后面的会覆盖前面的。为_blank时都会拦截,但window.open可以通过返回值检测是否被拦截
|
|
5
|
+
* @param {string} url - 下载链接
|
|
6
|
+
*/
|
|
7
|
+
export declare const browserNativeDownload: (url: string) => Promise<boolean>;
|
|
8
|
+
/**
|
|
9
|
+
* @author sonion
|
|
10
|
+
* @description blob下载
|
|
11
|
+
* @param {Blob} blob - 下载的blob数据
|
|
12
|
+
* @param {string} fileName - 下载的文件名
|
|
13
|
+
* @param {boolean} [inline] - 是否内联下载(不开新tab) 默认内联
|
|
14
|
+
*/
|
|
15
|
+
export declare const blobDownload: (blob: Blob, fileName: string, inline?: boolean) => void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { RecordTypedMap } from '../record-typed-map';
|
|
2
|
+
/**
|
|
3
|
+
* @author sonion
|
|
4
|
+
* @description 判断对象自身是否有指定属性
|
|
5
|
+
* @param obj 要判断的对象
|
|
6
|
+
* @param property 属性名
|
|
7
|
+
* @returns {boolean} - 是否有指定属性
|
|
8
|
+
*/
|
|
9
|
+
export declare const hasOwnProperty: <T extends Partial<Record<keyof T, unknown>>>(obj: T, property: string) => boolean;
|
|
10
|
+
/** 事件处理函数类型 */
|
|
11
|
+
export type EventHandler<P> = undefined extends P ? (payload?: P) => void : (payload: P) => void;
|
|
12
|
+
/** 事件处理函数配置类型 */
|
|
13
|
+
export type EventHandlerOptions = {
|
|
14
|
+
/** 是否仅触发一次 */
|
|
15
|
+
once?: boolean;
|
|
16
|
+
/** 取消信号 */
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
};
|
|
19
|
+
/** 事件处理函数集合 */
|
|
20
|
+
export type EventCollection<P> = Map<EventHandler<P>, EventHandlerOptions | undefined>;
|
|
21
|
+
/**
|
|
22
|
+
* @author sonion
|
|
23
|
+
* @description 创建事件处理集合,同名事件的集合
|
|
24
|
+
* 泛型 A,事件处理韩式参数类型
|
|
25
|
+
* @returns 事件处理函数集合
|
|
26
|
+
*/
|
|
27
|
+
export declare const createEventCollection: <K extends keyof T, T extends Record<string, unknown>>() => EventCollection<T[K]>;
|
|
28
|
+
/** 事件中心数据类型 `Map<事件名, Map<事件处理函数, 配置参数>>` */
|
|
29
|
+
export type EventCenter<T extends Record<string, unknown>> = RecordTypedMap<{
|
|
30
|
+
[K in keyof T]: EventCollection<T[K]>;
|
|
31
|
+
}>;
|
|
32
|
+
export type EventOptionExecutor<T extends Record<string, unknown>> = Record<keyof EventHandlerOptions, <K extends keyof T>(events: EventCenter<T>, eventName: K, eventExecutorParams: [EventHandler<T[K]>, EventHandlerOptions | undefined]) => void>;
|
|
33
|
+
export declare const createEventOptionExecutor: <T extends Record<string, unknown>>() => {
|
|
34
|
+
once: <K extends keyof T>(events: EventCenter<T>, eventName: K, eventExecutorParams: [EventHandler<T[K]>, EventHandlerOptions | undefined]) => void;
|
|
35
|
+
signal: <K extends keyof T>(events: EventCenter<T>, eventName: K, eventExecutorParams: [EventHandler<T[K]>, EventHandlerOptions | undefined]) => void;
|
|
36
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { EventHandler, EventHandlerOptions } from './helpers';
|
|
2
|
+
type NonFunction = null | undefined | number | string | boolean | symbol | bigint | {
|
|
3
|
+
[key: string]: unknown;
|
|
4
|
+
};
|
|
5
|
+
/** 返回包含 undefined 类型的键 */
|
|
6
|
+
type KeysWithUndefined<T> = {
|
|
7
|
+
[K in keyof T]: undefined extends T[K] ? K : never;
|
|
8
|
+
}[keyof T];
|
|
9
|
+
/** 返回不包含 undefined 类型的键 */
|
|
10
|
+
type KeysWithoutUndefined<T> = {
|
|
11
|
+
[K in keyof T]: undefined extends T[K] ? never : K;
|
|
12
|
+
}[keyof T];
|
|
13
|
+
/**
|
|
14
|
+
* @author sonion
|
|
15
|
+
* @description 自定义事件中心。
|
|
16
|
+
* @example
|
|
17
|
+
* const eventCenter = new EventEmitter();
|
|
18
|
+
* eventCenter.on('onChange', data=>console.log('没有配置的事件。参数:', data));
|
|
19
|
+
* eventCenter.on('onTest', data=>console.log('once 配置为 true 的事件。参数:', data), {once: true});
|
|
20
|
+
* const controller = new AbortController(); // 创建取消信号
|
|
21
|
+
* eventCenter.on('tap', data=>console.log('配置了 signal 的事件。参数:', data), {signal: controller.signal})
|
|
22
|
+
* controller.abort() // 取消
|
|
23
|
+
* eventCenter.emit('onChange', {happy: true});
|
|
24
|
+
*/
|
|
25
|
+
export declare class EventEmitter<T extends Record<string, NonFunction>> {
|
|
26
|
+
/** Map<事件名, Map<事件处理函数, 配置参数>> */
|
|
27
|
+
private events;
|
|
28
|
+
/** 配置对象执行器,不同配置参数的不同处理。在emit中执行 */
|
|
29
|
+
private eventOptionExecutor;
|
|
30
|
+
/** 自定义调度器,怎么执行事件处理函数 */
|
|
31
|
+
private scheduler;
|
|
32
|
+
constructor(scheduler?: (eventHandel: () => void) => void);
|
|
33
|
+
/**
|
|
34
|
+
* @author sonion
|
|
35
|
+
* @description 注册事件
|
|
36
|
+
* @param eventName 事件名
|
|
37
|
+
* @param callback 事件处理函数
|
|
38
|
+
* @param options 配置对象。once:是否只运行一次, signal取消信号
|
|
39
|
+
*/
|
|
40
|
+
addEventListener<K extends keyof T>(eventName: K, callback: EventHandler<T[K]>, options?: EventHandlerOptions): void;
|
|
41
|
+
/**
|
|
42
|
+
* @author sonion
|
|
43
|
+
* @description 移除事件
|
|
44
|
+
* @param eventName 事件名
|
|
45
|
+
* @param callback 事件处理函数
|
|
46
|
+
*/
|
|
47
|
+
removeEventListener<K extends keyof T>(eventName: K, callback: EventHandler<T[K]>): void;
|
|
48
|
+
on<K extends keyof T>(eventName: K, callback: EventHandler<T[K]>, options?: EventHandlerOptions): void;
|
|
49
|
+
off<K extends keyof T>(eventName: K, callback: EventHandler<T[K]>): void;
|
|
50
|
+
/**
|
|
51
|
+
* @author sonion
|
|
52
|
+
* @description 清空事件列表
|
|
53
|
+
* @param {string | void} [eventName] - 要清除的事件名。不传就清空所有事件列表
|
|
54
|
+
*/
|
|
55
|
+
clear(eventName?: keyof T): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* @author sonion
|
|
58
|
+
* @description 发布事件
|
|
59
|
+
* @param eventName 事件名
|
|
60
|
+
* @param data 事件参数
|
|
61
|
+
*/
|
|
62
|
+
emit<K extends KeysWithoutUndefined<T>>(eventName: K, data: T[K]): void;
|
|
63
|
+
emit<K extends KeysWithUndefined<T>>(eventName: K, data?: T[K]): void;
|
|
64
|
+
}
|
|
65
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author sonion
|
|
3
|
+
* @description
|
|
4
|
+
* @param xhr - XMLHttpRequest 实例对象
|
|
5
|
+
* @param headers 请求头参数
|
|
6
|
+
*/
|
|
7
|
+
export declare const setRequestHeaders: (xhr: XMLHttpRequest, headers: RequestInit["headers"]) => void;
|
|
8
|
+
/**
|
|
9
|
+
* @author sonion
|
|
10
|
+
* @description 处理请求体,将 ReadableStream 类型转换为 Blob 类型
|
|
11
|
+
* @param body - 请求体
|
|
12
|
+
* @param signal - 信号量
|
|
13
|
+
*/
|
|
14
|
+
export declare const handleRequestBody: (body: RequestInit["body"], signal?: AbortSignal | null) => Promise<string | ArrayBuffer | ArrayBufferView<ArrayBuffer> | Blob | FormData | URLSearchParams | null | undefined>;
|
|
15
|
+
/**
|
|
16
|
+
* @author sonion
|
|
17
|
+
* @description 获取响应头
|
|
18
|
+
* @param {XMLHttpRequest} xhr XMLHttpRequest对象
|
|
19
|
+
*/
|
|
20
|
+
export declare const getResponseHeaders: (xhr: XMLHttpRequest) => Headers;
|
|
21
|
+
/**
|
|
22
|
+
* @author sonion
|
|
23
|
+
* @description 自定义超时错误类
|
|
24
|
+
*/
|
|
25
|
+
export declare class CustomTimeoutError extends DOMException {
|
|
26
|
+
readonly isTimeout = true;
|
|
27
|
+
constructor(msg?: string);
|
|
28
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CustomTimeoutError } from './helpers';
|
|
2
|
+
export { CustomTimeoutError };
|
|
3
|
+
type RequestInitFields = 'body' | 'method' | 'headers' | 'credentials' | 'signal';
|
|
4
|
+
export interface FetchXHRInit extends Pick<RequestInit, RequestInitFields> {
|
|
5
|
+
/**
|
|
6
|
+
* @description 超时时间,单位毫秒
|
|
7
|
+
*/
|
|
8
|
+
timeout?: number;
|
|
9
|
+
/**
|
|
10
|
+
* @description 上传进度回调
|
|
11
|
+
*/
|
|
12
|
+
onUploadProgress?: (loaded: number, total: number, e: ProgressEvent) => void;
|
|
13
|
+
/**
|
|
14
|
+
* @description 下载进度回调
|
|
15
|
+
*/
|
|
16
|
+
onDownloadProgress?: (loaded: number, total: number, e: ProgressEvent) => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* @author sonion
|
|
20
|
+
* @description 基于 XMLHttpRequest 实现的 fetch 函数。
|
|
21
|
+
* 除增加 timeout、onUploadProgress、onDownloadProgress 外,其他与 fetch 一致。
|
|
22
|
+
* @param url 请求地址
|
|
23
|
+
* @param init 请求配置。
|
|
24
|
+
*/
|
|
25
|
+
export declare const fetchXHR: (url: string, init?: FetchXHRInit) => Promise<Response>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type SupportedHashType = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
|
|
2
|
+
/**
|
|
3
|
+
* @author sonion
|
|
4
|
+
* @description 字符串转哈希
|
|
5
|
+
* @param {string} message - 要转换的字符串
|
|
6
|
+
* @param {SupportedHashType} algorithm - 哈希算法,默认SHA-1
|
|
7
|
+
*/
|
|
8
|
+
export declare function stringToHash(message: string, algorithm?: SupportedHashType): Promise<string>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from './thenable';
|
|
2
|
+
export * from './concurrency';
|
|
3
|
+
export * from './debounce';
|
|
4
|
+
export * from './hash';
|
|
5
|
+
export * from './download';
|
|
6
|
+
export * from './deep-copy';
|
|
7
|
+
export * from './raf-interval';
|
|
8
|
+
export * from './json-convert';
|
|
9
|
+
export * from './fetch-xhr';
|
|
10
|
+
export * from './class-singleton';
|
|
11
|
+
export * from './event-emitter';
|
|
12
|
+
export * from './micro-queue-scheduler';
|
|
13
|
+
export * from './record-typed-map';
|
|
14
|
+
export * from './retry-async';
|
|
15
|
+
export * from './is-deep-plain-equal';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author sonion
|
|
3
|
+
* @param value 要判断的值
|
|
4
|
+
* @description 是否为null或undefined
|
|
5
|
+
*/
|
|
6
|
+
export declare const isNil: (value: unknown) => value is null | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* @author sonion
|
|
9
|
+
* @description 深度比较两个未知类型的值是否相等。支持 Plain Object。
|
|
10
|
+
* 不支持比较函数、Symbol、Date、RegExp等。
|
|
11
|
+
* @param a 要比较的第一个值
|
|
12
|
+
* @param b 要比较的第二个值
|
|
13
|
+
* @returns 如果两个值相等则返回 true,否则返回 false
|
|
14
|
+
*/
|
|
15
|
+
export declare const isDeepPlainEqual: (a: unknown, b: unknown) => boolean;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** 小驼峰命名支持用小划线分割 */
|
|
2
|
+
type CamelToSnakeRaw<S extends string> = S extends `${infer First}${infer Rest}` ? First extends Lowercase<First> ? `${First}${CamelToSnakeRaw<Rest>}` : `_${Lowercase<First>}${CamelToSnakeRaw<Rest>}` : S;
|
|
3
|
+
/** 去掉开头的下划线 */
|
|
4
|
+
type TrimLeadingUnderscore<S extends string> = S extends `_${infer R}` ? R : S;
|
|
5
|
+
/** 小驼峰命名转换为蛇形命名类型 */
|
|
6
|
+
type CamelToSnake<S extends string> = TrimLeadingUnderscore<CamelToSnakeRaw<S>>;
|
|
7
|
+
/** 蛇形命名转换为小驼峰命名类型 */
|
|
8
|
+
type SnakeToCamel<S extends string> = S extends `${infer Head}_${infer Tail}` ? `${Lowercase<Head>}${Capitalize<SnakeToCamel<Tail>>}` : Lowercase<S>;
|
|
9
|
+
/** 小驼峰命名转换为大驼峰命名类型 */
|
|
10
|
+
type CamelToPascal<S extends string> = Capitalize<S>;
|
|
11
|
+
/** 大驼峰命名转换为小驼峰命名类型 */
|
|
12
|
+
type PascalToCamel<S extends string> = Uncapitalize<S>;
|
|
13
|
+
/** 转换模式 */
|
|
14
|
+
export declare const ConvertMode: {
|
|
15
|
+
readonly SnakeToCamel: "snakeToCamel";
|
|
16
|
+
readonly CamelToSnake: "camelToSnake";
|
|
17
|
+
readonly CamelToPascal: "camelToPascal";
|
|
18
|
+
readonly PascalToCamel: "pascalToCamel";
|
|
19
|
+
};
|
|
20
|
+
/** 转换模式类型 */
|
|
21
|
+
export type ConvertMode = (typeof ConvertMode)[keyof typeof ConvertMode];
|
|
22
|
+
type TransformMap<K extends string> = {
|
|
23
|
+
snakeToCamel: SnakeToCamel<K>;
|
|
24
|
+
camelToSnake: CamelToSnake<K>;
|
|
25
|
+
camelToPascal: CamelToPascal<K>;
|
|
26
|
+
pascalToCamel: PascalToCamel<K>;
|
|
27
|
+
};
|
|
28
|
+
/** 通用:深度转换对象所有键名(保留函数与数组)*/
|
|
29
|
+
type ConvertKeys<T, M extends ConvertMode, IGN extends readonly string[] = readonly []> = T extends (...args: never) => unknown ? T : T extends readonly unknown[] ? {
|
|
30
|
+
[I in keyof T]: ConvertKeys<T[I], M, IGN>;
|
|
31
|
+
} : T extends object ? {
|
|
32
|
+
[K in keyof T as K extends string ? K extends IGN[number] ? K : TransformMap<K>[M] : K]: ConvertKeys<T[K], M, IGN>;
|
|
33
|
+
} : T;
|
|
34
|
+
/**
|
|
35
|
+
* @author sonion
|
|
36
|
+
* @description 深度遍历JSON,将所有键名从蛇形转换为小驼峰
|
|
37
|
+
* @param obj 要处理的JSON对象或数组
|
|
38
|
+
* @param ignoreKeys 忽略转换的键名数组。⚠️ ignoreKeys必须是使用 as const断言的数组,否则类型会失效
|
|
39
|
+
* @example convertSnake2Camel({ a_b: 1, c_d: { e_f: 2 } }, ['c_d'] as const)
|
|
40
|
+
*/
|
|
41
|
+
declare const convertSnake2Camel: <T extends Record<keyof T, unknown> | Record<keyof T, unknown>[], K extends readonly string[] = readonly []>(obj: T, ignoreKeys?: K) => ConvertKeys<T, typeof ConvertMode.SnakeToCamel, K>;
|
|
42
|
+
/**
|
|
43
|
+
* @author sonion
|
|
44
|
+
* @description 深度遍历JSON,将所有键名从小驼峰转换为蛇形
|
|
45
|
+
* @param obj 要处理的JSON对象或数组
|
|
46
|
+
* @param ignoreKeys 忽略转换的键名数组。⚠️ ignoreKeys必须是使用 as const断言的数组,否则类型会失效
|
|
47
|
+
* @example convertCamel2Snake({ aB: 1, cD: { eF: 2 } }, ['cD'] as const)
|
|
48
|
+
*/
|
|
49
|
+
declare const convertCamel2Snake: <T extends Record<keyof T, unknown> | Record<keyof T, unknown>[], K extends readonly string[] = readonly []>(obj: T, ignoreKeys?: K) => ConvertKeys<T, typeof ConvertMode.CamelToSnake, K>;
|
|
50
|
+
/**
|
|
51
|
+
* @author sonion
|
|
52
|
+
* @description 深度遍历JSON,将所有键名从小驼峰转换为大驼峰
|
|
53
|
+
* @param obj 要处理的JSON对象或数组
|
|
54
|
+
* @param ignoreKeys 忽略转换的键名数组。⚠️ ignoreKeys必须是使用 as const断言的数组,否则类型会失效
|
|
55
|
+
* @example convertCamel2Pascal({ aB: 1, cD: { eF: 2 } }, ['cD'] as const)
|
|
56
|
+
*/
|
|
57
|
+
declare const convertCamel2Pascal: <T extends Record<keyof T, unknown> | Record<keyof T, unknown>[], K extends readonly string[] = readonly []>(obj: T, ignoreKeys?: K) => ConvertKeys<T, typeof ConvertMode.CamelToPascal, K>;
|
|
58
|
+
/**
|
|
59
|
+
* @author sonion
|
|
60
|
+
* @description 深度遍历JSON,将所有键名从大驼峰转换为小驼峰
|
|
61
|
+
* @param obj 要处理的JSON对象或数组
|
|
62
|
+
* @param ignoreKeys 忽略转换的键名数组。⚠️ ignoreKeys必须是使用 as const断言的数组,否则类型会失效
|
|
63
|
+
* @example convertPascal2Camel({ AB: 1, CD: { EF: 2 } }, ['CD'] as const)
|
|
64
|
+
*/
|
|
65
|
+
declare const convertPascal2Camel: <T extends Record<keyof T, unknown> | Record<keyof T, unknown>[], K extends readonly string[] = readonly []>(obj: T, ignoreKeys?: K) => ConvertKeys<T, typeof ConvertMode.PascalToCamel, K>;
|
|
66
|
+
export { convertSnake2Camel, convertCamel2Snake, convertCamel2Pascal, convertPascal2Camel, };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author sonion
|
|
3
|
+
* @description 创建微队列调度器 - 将同一个同步执行阶段中的所有任务合并到一个微任务中执行。
|
|
4
|
+
* @returns 调度器函数
|
|
5
|
+
*
|
|
6
|
+
* 使用场景:
|
|
7
|
+
* - 批量合并异步任务,保证它们在同一个微任务中执行
|
|
8
|
+
* - 避免频繁创建多个 Promise 微任务,提高性能
|
|
9
|
+
* @example
|
|
10
|
+
* const scheduler = createMicroQueueScheduler();
|
|
11
|
+
* scheduler(() => console.log("task1"));
|
|
12
|
+
* scheduler(() => console.log("task2"));
|
|
13
|
+
*/
|
|
14
|
+
export declare const createMicroQueueScheduler: () => ((fn: () => void) => Promise<void>);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type RAfIntervalReturn = Record<'stop', () => void>;
|
|
2
|
+
/**
|
|
3
|
+
* @author sonion
|
|
4
|
+
* @description rAf版setInterval。可利用rAf页面隐藏暂停的特性,实现页面隐藏时暂停,页面显示时继续
|
|
5
|
+
* @param {() => void} fn - 回调函数
|
|
6
|
+
* @param {number} wait - 间隔时间 毫秒
|
|
7
|
+
* @returns {RAfIntervalReturn} - 返回取消函数
|
|
8
|
+
*/
|
|
9
|
+
export declare const rAfInterval: (fn: () => void, wait: number) => RAfIntervalReturn;
|
|
10
|
+
/**
|
|
11
|
+
* @author sonion
|
|
12
|
+
* @description 清除rAf版setInterval定时器
|
|
13
|
+
* @param {RAfIntervalReturn} intervalId - 手写定时器的返回值
|
|
14
|
+
* @returns {void}
|
|
15
|
+
*/
|
|
16
|
+
export declare const clearRAfInterval: (intervalId: RAfIntervalReturn | (() => void) | undefined) => void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author sonion
|
|
3
|
+
* @description 一个带有精确类型约束的 Map。
|
|
4
|
+
*
|
|
5
|
+
* 与普通 `Map<keyof T, T[keyof T]>` 不同,
|
|
6
|
+
* 它保证键和值的类型一一对应:
|
|
7
|
+
* - 键只能是对象 T 的属性名
|
|
8
|
+
* - 值必须是该属性对应的类型
|
|
9
|
+
* - 因使用 object 约束泛型,键只能是 string|number|symbol
|
|
10
|
+
*
|
|
11
|
+
* 这样可以避免宽泛的联合类型,提供类似对象的强类型体验。
|
|
12
|
+
* @example
|
|
13
|
+
* interface Config {
|
|
14
|
+
* port: number;
|
|
15
|
+
* host: string;
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* const map = new RecordTypedMap<Config>();
|
|
19
|
+
* map.set("port", 3000); // ✅ 正确
|
|
20
|
+
* map.set("host", "localhost"); // ✅ 正确
|
|
21
|
+
* map.set("port", "oops"); // ❌ 类型错误
|
|
22
|
+
*/
|
|
23
|
+
export declare class RecordTypedMap<T extends object> extends Map<keyof T, T[keyof T]> {
|
|
24
|
+
constructor(obj?: T);
|
|
25
|
+
get<K extends keyof T>(key: K): T[K] | undefined;
|
|
26
|
+
set<K extends keyof T>(key: K, value: T[K]): this;
|
|
27
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author sonion
|
|
3
|
+
* @description 重试任务,直到成功或达到最大重试次数
|
|
4
|
+
* @param task - 要重试的任务函数,需返回 Promise
|
|
5
|
+
* @param count - 最大重试次数,默认 5 次
|
|
6
|
+
* @param delay - 每次重试间隔时间,默认 0 毫秒。可传函数,根据重试次数、错误信息动态计算。
|
|
7
|
+
* @returns Promise<R> - 任务成功时的返回值
|
|
8
|
+
*/
|
|
9
|
+
export declare const retryAsync: <R>(task: () => Promise<R>, count?: number, delay?: number | ((attemptIndex?: number, beforeError?: Error) => number)) => Promise<R>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type SafeAwaitResult<T> = [true, null, T] | [false, Error, null];
|
|
2
|
+
/**
|
|
3
|
+
* @author sonion
|
|
4
|
+
* @description 安全的 await 函数。
|
|
5
|
+
* @param {Promise<T>} promise 要执行的 Promise 函数
|
|
6
|
+
* @returns {Promise<SafeAwaitResult<T>>} - 返回一个元组,第一个元素为是否成功,第二个元素为错误信息,第三个元素为数据
|
|
7
|
+
*/
|
|
8
|
+
export declare const safeAwait: <T>(promise: Promise<T>) => Promise<SafeAwaitResult<T>>;
|
|
9
|
+
/**
|
|
10
|
+
* @author sonion
|
|
11
|
+
* @description Promise.try 的polyfill实现
|
|
12
|
+
* @param p - promise 或 一个返回 promise 的函数
|
|
13
|
+
*/
|
|
14
|
+
export declare const promiseTry: <T>(p: PromiseLike<T> | (() => PromiseLike<T>)) => Promise<T>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { S as e, T as t, _ as n, a as r, b as i, c as a, d as o, f as s, g as c, h as l, i as u, l as d, m as f, n as p, o as m, p as h, r as g, s as _, t as v, u as y, v as b, w as x, x as S, y as C } from "./js/utils.CVb1iSAU.js";
|
|
2
|
+
export { e as ConcurrencyController, y as ConvertMode, d as CustomTimeoutError, u as EventEmitter, r as RecordTypedMap, b as blobDownload, C as browserNativeDownload, l as clearRAfInterval, o as convertCamel2Pascal, s as convertCamel2Snake, h as convertPascal2Camel, f as convertSnake2Camel, m as createMicroQueueScheduler, S as debounce, n as deepClone, a as fetchXHR, v as isDeepPlainEqual, p as isNil, x as promiseTry, c as rAfInterval, g as retryAsync, t as safeAwait, _ as singleton, i as stringToHash };
|
package/eslint.config.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { defineConfig, globalIgnores } from 'eslint/config';
|
|
2
|
+
import globals from 'globals';
|
|
3
|
+
import jslint from '@eslint/js';
|
|
4
|
+
import tseslint from 'typescript-eslint';
|
|
5
|
+
import prettier from 'eslint-config-prettier';
|
|
6
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
7
|
+
import reactRefresh from 'eslint-plugin-react-refresh';
|
|
8
|
+
import react from 'eslint-plugin-react';
|
|
9
|
+
import jsdoc from 'eslint-plugin-jsdoc';
|
|
10
|
+
|
|
11
|
+
export default defineConfig([
|
|
12
|
+
globalIgnores(['dist', 'node_modules']), // 忽略 dist 和 node_modules 目录
|
|
13
|
+
{
|
|
14
|
+
files: ['**/*.{ts,tsx,js,jsx}'], // 对所有 TS TSX JS JSX 文件应用规则
|
|
15
|
+
languageOptions: {
|
|
16
|
+
ecmaVersion: 2020, // 语法检查 支持的 ES 版本
|
|
17
|
+
globals: globals.browser, // 浏览器全局变量
|
|
18
|
+
// env: globals.node, // Node.js 环境变量
|
|
19
|
+
},
|
|
20
|
+
settings: {
|
|
21
|
+
react: {
|
|
22
|
+
version: 'detect', // 自动检测 React 版本
|
|
23
|
+
},
|
|
24
|
+
jsdoc: {
|
|
25
|
+
mode: 'typescript',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
extends: [
|
|
29
|
+
prettier, // ✅ 关闭和 Prettier 冲突的规则
|
|
30
|
+
jslint.configs.recommended, // ✅ JavaScript 规则
|
|
31
|
+
...tseslint.configs.recommended, // ✅ TypeScript 规则
|
|
32
|
+
reactHooks.configs.flat.recommended, // ✅ React Hooks 扁平插件配置对象
|
|
33
|
+
reactRefresh.configs.vite, // ✅ React Refresh 插件注册; 扁平插件配置对象, vite 环境下需要配置
|
|
34
|
+
react.configs.flat.recommended, // ✅ React 扁平插件配置对象
|
|
35
|
+
jsdoc.configs['flat/recommended'], // ✅ JSDoc 扁平插件配置对象
|
|
36
|
+
],
|
|
37
|
+
rules: {
|
|
38
|
+
'jsdoc/no-undefined-types': 'off', // JSDoc 里的泛型会报错
|
|
39
|
+
'jsdoc/require-returns': 'off', // 关闭 JSDoc 缺少返回值规则
|
|
40
|
+
'jsdoc/require-returns-type': 'off', // 关闭 JSDoc 缺少返回值类型规则
|
|
41
|
+
'jsdoc/require-param-type': 'off', // 关闭 JSDoc 缺少参数类型规则
|
|
42
|
+
'react/react-in-jsx-scope': 'off', // 关闭 React 17+ ,JSX 可以空标签
|
|
43
|
+
'react-hooks/exhaustive-deps': 'warn', // 不完整的依赖项
|
|
44
|
+
'@typescript-eslint/no-unused-expressions': 'off', // 关闭未使用表达式校验,开启React常用的短路规则可能误判
|
|
45
|
+
'@typescript-eslint/no-unused-vars': ['warn'], // 警告未使用变量 如遇到 与tsconfig.json 冲突,以ts为准
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
// tsc 不用插件只能全局检查。用函数忽略 lint-staged 传入文件,直接全量检查
|
|
3
|
+
'{src,packages,apps}/**/*.{ts,tsx,vue}': () => ['tsc --noEmit'],
|
|
4
|
+
'{src,packages,apps}/**/*.{js,jsx,ts,tsx,vue}': [
|
|
5
|
+
'eslint',
|
|
6
|
+
'oxfmt',
|
|
7
|
+
],
|
|
8
|
+
'{src,packages,apps}/**/*.{css,scss,less,md,mdx,html,json,yml,yaml}': [
|
|
9
|
+
'oxfmt',
|
|
10
|
+
],
|
|
11
|
+
'{src,packages,apps}/**/*.{js,jsx,ts,tsx,vue,css,scss,less,md,mdx,html,json,yml,yaml}':
|
|
12
|
+
['cspell lint'],
|
|
13
|
+
};
|
package/oxfmt.config.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineConfig } from "oxfmt";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
singleQuote: true, // 单引号
|
|
5
|
+
semi: true, // 分号
|
|
6
|
+
trailingComma: "es5", // 允许对象和数组尾随逗号
|
|
7
|
+
arrowParens: "always", // 箭头函数参数是否添加括号
|
|
8
|
+
bracketSpacing: true, // 对象字面量是否添加空格
|
|
9
|
+
useTabs: false, // 是否tab缩进
|
|
10
|
+
tabWidth: 2, // 缩进空格数
|
|
11
|
+
printWidth: 80, // 行宽限制
|
|
12
|
+
sortPackageJson: true, // 是否排序package.json
|
|
13
|
+
ignorePatterns: [], // 忽略的文件模式
|
|
14
|
+
});
|