@d-matrix/utils 1.27.1 → 1.28.0

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 (72) hide show
  1. package/dist/algorithm/binary.d.ts +8 -8
  2. package/dist/algorithm/binary.js +38 -38
  3. package/dist/algorithm/index.d.ts +2 -2
  4. package/dist/algorithm/index.js +2 -2
  5. package/dist/algorithm/tree.d.ts +34 -34
  6. package/dist/algorithm/tree.js +124 -124
  7. package/dist/array.d.ts +46 -5
  8. package/dist/array.js +129 -37
  9. package/dist/clipboard.d.ts +12 -12
  10. package/dist/clipboard.js +107 -107
  11. package/dist/color.d.ts +7 -7
  12. package/dist/color.js +41 -41
  13. package/dist/date.d.ts +34 -34
  14. package/dist/date.js +62 -62
  15. package/dist/decimal.d.ts +17 -17
  16. package/dist/decimal.js +23 -23
  17. package/dist/dom.d.ts +11 -11
  18. package/dist/dom.js +27 -27
  19. package/dist/echarts.d.ts +36 -36
  20. package/dist/echarts.js +112 -112
  21. package/dist/file.d.ts +49 -49
  22. package/dist/file.js +154 -154
  23. package/dist/i18n.d.ts +10 -10
  24. package/dist/i18n.js +12 -12
  25. package/dist/index.d.ts +16 -16
  26. package/dist/index.js +16 -16
  27. package/dist/number.d.ts +2 -2
  28. package/dist/number.js +4 -4
  29. package/dist/object.d.ts +13 -13
  30. package/dist/object.js +28 -28
  31. package/dist/operator.d.ts +6 -6
  32. package/dist/operator.js +6 -6
  33. package/dist/react/enhancedComponent.d.ts +12 -12
  34. package/dist/react/enhancedComponent.js +16 -16
  35. package/dist/react/index.d.ts +15 -12
  36. package/dist/react/index.js +15 -12
  37. package/dist/react/renderToString.d.ts +3 -3
  38. package/dist/react/renderToString.js +30 -30
  39. package/dist/react/types.d.ts +9 -9
  40. package/dist/react/types.js +1 -1
  41. package/dist/react/useCopyToClipboard.d.ts +21 -21
  42. package/dist/react/useCopyToClipboard.js +44 -44
  43. package/dist/react/useDeepCompareRef.d.ts +2 -2
  44. package/dist/react/useDeepCompareRef.js +11 -11
  45. package/dist/react/useDisableContextMenu.d.ts +7 -7
  46. package/dist/react/useDisableContextMenu.js +24 -24
  47. package/dist/react/useEventCallback.d.ts +7 -0
  48. package/dist/react/useEventCallback.js +19 -0
  49. package/dist/react/useForwardRef.d.ts +9 -9
  50. package/dist/react/useForwardRef.js +22 -22
  51. package/dist/react/useId.d.ts +1 -0
  52. package/dist/react/useId.js +12 -0
  53. package/dist/react/useIsFirstRender.d.ts +6 -6
  54. package/dist/react/useIsFirstRender.js +14 -14
  55. package/dist/react/useIsMounted.d.ts +2 -2
  56. package/dist/react/useIsMounted.js +13 -13
  57. package/dist/react/useIsomorphicLayoutEffect.d.ts +2 -2
  58. package/dist/react/useIsomorphicLayoutEffect.js +2 -2
  59. package/dist/react/useMediaQuery.d.ts +14 -14
  60. package/dist/react/useMediaQuery.js +42 -42
  61. package/dist/react/useSafeTimeout.d.ts +12 -0
  62. package/dist/react/useSafeTimeout.js +28 -0
  63. package/dist/react/useStateCallback.d.ts +2 -2
  64. package/dist/react/useStateCallback.js +17 -17
  65. package/dist/support.d.ts +12 -12
  66. package/dist/support.js +12 -12
  67. package/dist/timer.d.ts +5 -5
  68. package/dist/timer.js +5 -5
  69. package/dist/types.d.ts +128 -21
  70. package/dist/types.js +1 -1
  71. package/package.json +1 -1
  72. package/readme.md +5 -1
@@ -1,42 +1,42 @@
1
- import { useState } from 'react';
2
- import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';
3
- const IS_SERVER = typeof window === 'undefined';
4
- export function useMediaQuery(query, { defaultValue = false, initializeWithValue = true } = {}) {
5
- const getMatches = (query) => {
6
- if (IS_SERVER) {
7
- return defaultValue;
8
- }
9
- return window.matchMedia(query).matches;
10
- };
11
- const [matches, setMatches] = useState(() => {
12
- if (initializeWithValue) {
13
- return getMatches(query);
14
- }
15
- return defaultValue;
16
- });
17
- // Handles the change event of the media query.
18
- function handleChange() {
19
- setMatches(getMatches(query));
20
- }
21
- useIsomorphicLayoutEffect(() => {
22
- const matchMedia = window.matchMedia(query);
23
- // Triggered at the first client-side load and if query changes
24
- handleChange();
25
- // Use deprecated `addListener` and `removeListener` to support Safari < 14 (#135)
26
- if (matchMedia.addListener) {
27
- matchMedia.addListener(handleChange);
28
- }
29
- else {
30
- matchMedia.addEventListener('change', handleChange);
31
- }
32
- return () => {
33
- if (matchMedia.removeListener) {
34
- matchMedia.removeListener(handleChange);
35
- }
36
- else {
37
- matchMedia.removeEventListener('change', handleChange);
38
- }
39
- };
40
- }, [query]);
41
- return matches;
42
- }
1
+ import { useState } from 'react';
2
+ import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';
3
+ const IS_SERVER = typeof window === 'undefined';
4
+ export function useMediaQuery(query, { defaultValue = false, initializeWithValue = true } = {}) {
5
+ const getMatches = (query) => {
6
+ if (IS_SERVER) {
7
+ return defaultValue;
8
+ }
9
+ return window.matchMedia(query).matches;
10
+ };
11
+ const [matches, setMatches] = useState(() => {
12
+ if (initializeWithValue) {
13
+ return getMatches(query);
14
+ }
15
+ return defaultValue;
16
+ });
17
+ // Handles the change event of the media query.
18
+ function handleChange() {
19
+ setMatches(getMatches(query));
20
+ }
21
+ useIsomorphicLayoutEffect(() => {
22
+ const matchMedia = window.matchMedia(query);
23
+ // Triggered at the first client-side load and if query changes
24
+ handleChange();
25
+ // Use deprecated `addListener` and `removeListener` to support Safari < 14 (#135)
26
+ if (matchMedia.addListener) {
27
+ matchMedia.addListener(handleChange);
28
+ }
29
+ else {
30
+ matchMedia.addEventListener('change', handleChange);
31
+ }
32
+ return () => {
33
+ if (matchMedia.removeListener) {
34
+ matchMedia.removeListener(handleChange);
35
+ }
36
+ else {
37
+ matchMedia.removeEventListener('change', handleChange);
38
+ }
39
+ };
40
+ }, [query]);
41
+ return matches;
42
+ }
@@ -0,0 +1,12 @@
1
+ declare type SetTimeout = (handler: TimerHandler, timeout?: number, ...args: unknown[]) => number;
2
+ declare type ClearTimeout = (id: number) => void;
3
+ /**
4
+ * Safely call `setTimeout` and `clearTimeout` within a component.
5
+ *
6
+ * This hook ensures that all timeouts are cleared when the component unmounts.
7
+ */
8
+ export declare function useSafeTimeout(): {
9
+ safeSetTimeout: SetTimeout;
10
+ safeClearTimeout: ClearTimeout;
11
+ };
12
+ export {};
@@ -0,0 +1,28 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+ /**
3
+ * Safely call `setTimeout` and `clearTimeout` within a component.
4
+ *
5
+ * This hook ensures that all timeouts are cleared when the component unmounts.
6
+ */
7
+ export function useSafeTimeout() {
8
+ const timers = useRef(new Set());
9
+ const safeSetTimeout = useCallback((handler, timeout, ...args) => {
10
+ const id = window.setTimeout(handler, timeout, ...args);
11
+ timers.current.add(id);
12
+ return id;
13
+ }, []);
14
+ const safeClearTimeout = useCallback((id) => {
15
+ clearTimeout(id);
16
+ timers.current.delete(id);
17
+ }, []);
18
+ useEffect(() => {
19
+ return () => {
20
+ // eslint-disable-next-line react-compiler/react-compiler
21
+ // eslint-disable-next-line react-hooks/exhaustive-deps
22
+ for (const id of timers.current) {
23
+ clearTimeout(id);
24
+ }
25
+ };
26
+ }, []);
27
+ return { safeSetTimeout, safeClearTimeout };
28
+ }
@@ -1,2 +1,2 @@
1
- /** 等价与类组件 setState(updater[, callback]) */
2
- export declare function useStateCallback<T>(initialState: T): [T, (state: T, cb?: (state: T) => void) => void];
1
+ /** 等价与类组件 setState(updater[, callback]) */
2
+ export declare function useStateCallback<T>(initialState: T): [T, (state: T, cb?: (state: T) => void) => void];
@@ -1,17 +1,17 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react';
2
- /** 等价与类组件 setState(updater[, callback]) */
3
- export function useStateCallback(initialState) {
4
- const [state, setState] = useState(initialState);
5
- const cbRef = useRef(undefined);
6
- const setStateCallback = useCallback((state, cb) => {
7
- cbRef.current = cb;
8
- setState(state);
9
- }, []);
10
- useEffect(() => {
11
- if (cbRef.current) {
12
- cbRef.current(state);
13
- cbRef.current = undefined;
14
- }
15
- }, [state]);
16
- return [state, setStateCallback];
17
- }
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ /** 等价与类组件 setState(updater[, callback]) */
3
+ export function useStateCallback(initialState) {
4
+ const [state, setState] = useState(initialState);
5
+ const cbRef = useRef(undefined);
6
+ const setStateCallback = useCallback((state, cb) => {
7
+ cbRef.current = cb;
8
+ setState(state);
9
+ }, []);
10
+ useEffect(() => {
11
+ if (cbRef.current) {
12
+ cbRef.current(state);
13
+ cbRef.current = undefined;
14
+ }
15
+ }, [state]);
16
+ return [state, setStateCallback];
17
+ }
package/dist/support.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- /**
2
- * 是否是浏览器环境
3
- */
4
- export declare const isBrowserEnv: () => boolean;
5
- /**
6
- * 是否支持WebSocket
7
- */
8
- export declare const isWebSocket: () => boolean;
9
- /**
10
- * 是否支持SharedWorker
11
- */
12
- export declare const isSharedWorker: () => boolean;
1
+ /**
2
+ * 是否是浏览器环境
3
+ */
4
+ export declare const isBrowserEnv: () => boolean;
5
+ /**
6
+ * 是否支持WebSocket
7
+ */
8
+ export declare const isWebSocket: () => boolean;
9
+ /**
10
+ * 是否支持SharedWorker
11
+ */
12
+ export declare const isSharedWorker: () => boolean;
package/dist/support.js CHANGED
@@ -1,12 +1,12 @@
1
- /**
2
- * 是否是浏览器环境
3
- */
4
- export const isBrowserEnv = () => typeof window !== 'undefined';
5
- /**
6
- * 是否支持WebSocket
7
- */
8
- export const isWebSocket = () => typeof WebSocket !== 'undefined';
9
- /**
10
- * 是否支持SharedWorker
11
- */
12
- export const isSharedWorker = () => typeof SharedWorker !== 'undefined';
1
+ /**
2
+ * 是否是浏览器环境
3
+ */
4
+ export const isBrowserEnv = () => typeof window !== 'undefined';
5
+ /**
6
+ * 是否支持WebSocket
7
+ */
8
+ export const isWebSocket = () => typeof WebSocket !== 'undefined';
9
+ /**
10
+ * 是否支持SharedWorker
11
+ */
12
+ export const isSharedWorker = () => typeof SharedWorker !== 'undefined';
package/dist/timer.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- /**
2
- * 睡眠
3
- * @param time 睡眠时间
4
- */
5
- export declare const sleep: (ms?: number) => Promise<unknown>;
1
+ /**
2
+ * 睡眠
3
+ * @param time 睡眠时间
4
+ */
5
+ export declare const sleep: (ms?: number) => Promise<unknown>;
package/dist/timer.js CHANGED
@@ -1,5 +1,5 @@
1
- /**
2
- * 睡眠
3
- * @param time 睡眠时间
4
- */
5
- export const sleep = (ms = 0) => new Promise((resolve) => setTimeout(resolve, ms));
1
+ /**
2
+ * 睡眠
3
+ * @param time 睡眠时间
4
+ */
5
+ export const sleep = (ms = 0) => new Promise((resolve) => setTimeout(resolve, ms));
package/dist/types.d.ts CHANGED
@@ -1,21 +1,128 @@
1
- /** 指定的属性变为可选 */
2
- export declare type WithOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
3
- /** 除了 K 的其他属性变成可选 */
4
- export declare type ExcludePickPartial<T, K extends keyof T> = Partial<Omit<T, K>> & Pick<T, K>;
5
- export declare type Undefinable<T> = {
6
- [K in keyof T]: T[K] | undefined;
7
- };
8
- /** 获取对象中的方法名称,返回union type */
9
- export declare type FunctionPropertyNames<T> = {
10
- [P in keyof T]-?: T[P] extends Function ? P : never;
11
- }[keyof T];
12
- /** 获取对象中非函数属性名称,返回union type */
13
- export declare type NonFunctionPropertyNames<T> = {
14
- [P in keyof T]-?: T[P] extends Function ? never : P;
15
- }[keyof T];
16
- /** 获取对象中key的值,返回由这些值组成的union type */
17
- export declare type ValueOf<T> = T[keyof T];
18
- /** 指定属性变为必选 */
19
- export declare type WithRequired<T, K extends keyof T> = T & {
20
- [P in K]-?: T[P];
21
- };
1
+ /**
2
+ * 创建一个新类型,将指定属性设为可选
3
+ *
4
+ * @template T - 原始对象类型
5
+ * @template K - 要设为可选的属性键名联合类型,必须是T的键的子集
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * type User = {
10
+ * id: number;
11
+ * name: string;
12
+ * email: string;
13
+ * };
14
+ *
15
+ * // 将email属性设为可选
16
+ * type UserWithOptionalEmail = WithOptional<User, 'email'>;
17
+ * // 等价于: { id: number; name: string; email?: string | undefined; }
18
+ * ```
19
+ */
20
+ export declare type WithOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
21
+ /**
22
+ * 创建一个新类型,该类型包含原类型T的部分属性和指定属性K的完整属性
23
+ *
24
+ * @template T - 原始对象类型
25
+ * @template K - 需要保持完整的属性键名,必须是T的键名的子集
26
+ *
27
+ * @description
28
+ * 该类型工具首先使用Omit排除类型T中的属性K,然后对剩余属性应用Partial使其变为可选,
29
+ * 同时使用Pick提取属性K并保持其完整性,最后将两部分进行交叉合并。
30
+ * 结果类型中,除了K指定的属性保持必需外,其他所有属性都变为可选。
31
+ */
32
+ export declare type ExcludePickPartial<T, K extends keyof T> = Partial<Omit<T, K>> & Pick<T, K>;
33
+ /**
34
+ * 定义一个工具类型Undefinable,用于将传入类型的每个属性都变为可选(即允许undefined)
35
+ *
36
+ * @template T - 需要处理的原始类型
37
+ * @returns 返回一个新的类型,该类型的每个属性都是原类型对应属性的联合类型加上undefined
38
+ */
39
+ export declare type Undefinable<T> = {
40
+ [K in keyof T]: T[K] | undefined;
41
+ };
42
+ /**
43
+ * 获取对象类型中所有函数类型的属性名
44
+ *
45
+ * @template T - 要检查的对象类型
46
+ * @returns 返回T类型中所有值为函数的属性名组成的联合类型
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * type Example = {
51
+ * name: string;
52
+ * age: number;
53
+ * getName(): string;
54
+ * getAge: () => number;
55
+ * };
56
+ *
57
+ * // 结果为 "getName" | "getAge"
58
+ * type FunctionProps = FunctionPropertyNames<Example>;
59
+ * ```
60
+ */
61
+ export declare type FunctionPropertyNames<T> = {
62
+ [P in keyof T]-?: T[P] extends Function ? P : never;
63
+ }[keyof T];
64
+ /**
65
+ * 获取对象类型中所有非函数属性的属性名联合类型
66
+ *
67
+ * @template T - 要处理的对象类型
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * type Example = {
72
+ * name: string;
73
+ * age: number;
74
+ * getName(): string;
75
+ * };
76
+ *
77
+ * // 结果为 "name" | "age"
78
+ * type Result = NonFunctionPropertyNames<Example>;
79
+ * ```
80
+ *
81
+ * @returns 返回T类型中所有非函数属性的属性名组成的联合类型
82
+ */
83
+ export declare type NonFunctionPropertyNames<T> = {
84
+ [P in keyof T]-?: T[P] extends Function ? never : P;
85
+ }[keyof T];
86
+ /**
87
+ * 获取对象类型T的所有值类型的联合类型
88
+ *
89
+ * 该工具类型通过 keyof T 获取对象T的所有键名,然后使用索引访问操作符 [keyof T]
90
+ * 来获取所有键对应的值类型,最终得到一个联合类型包含所有可能的值类型
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * type Person = {
95
+ * name: string;
96
+ * age: number;
97
+ * active: boolean;
98
+ * };
99
+ *
100
+ * // 结果类型为 string | number | boolean
101
+ * type PersonValues = ValueOf<Person>;
102
+ * ```
103
+ */
104
+ export declare type ValueOf<T> = T[keyof T];
105
+ /**
106
+ * 创建一个新类型,将指定属性设为必需
107
+ *
108
+ * @template T 原始对象类型
109
+ * @template K 需要设为必需的属性名联合类型,必须是T的键的子集
110
+ * @returns 返回一个新的交叉类型,包含原始类型T和将K中属性设为必需后的类型
111
+ *
112
+ * @example
113
+ * type User = { name?: string; age?: number; email?: string };
114
+ * type UserWithRequiredName = WithRequired<User, 'name'>;
115
+ * // 结果: { name: string; age?: number; email?: string }
116
+ */
117
+ export declare type WithRequired<T, K extends keyof T> = T & {
118
+ [P in K]-?: T[P];
119
+ };
120
+ /**
121
+ * 定义一个工具类型 Nullable,用于将传入类型的每个属性都变为可为空的联合类型
122
+ *
123
+ * @template T - 需要处理的原始类型
124
+ * @returns 返回一个新的类型,该类型的所有属性都与原始类型相同,但每个属性的值类型都扩展了 null 类型
125
+ */
126
+ export declare type Nullable<T> = {
127
+ [K in keyof T]: T[K] | null;
128
+ };
package/dist/types.js CHANGED
@@ -1 +1 @@
1
- export {};
1
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@d-matrix/utils",
3
3
  "sideEffects": false,
4
- "version": "1.27.1",
4
+ "version": "1.28.0",
5
5
  "description": "A dozen of utils for Front-End Development",
6
6
  "main": "dist/index.js",
7
7
  "scripts": {
package/readme.md CHANGED
@@ -622,12 +622,16 @@ const newList = array.moveToStart(list, (item) => item.id === 4);
622
622
 
623
623
  - `moveMulti<T extends unknown>(arr: T[], indexes: number[], start: number): T[]`
624
624
 
625
- 移动多个元素到数组中指定的位置,用法,见[测试用例](tests/algorithm.cy.ts)
625
+ 移动多个元素到数组中指定的位置,用法,见[测试用例](tests/array.cy.ts)
626
626
 
627
627
  - `getArrayOrUndefined<T>(array?: T[] | undefined | null): T[] | undefined`
628
628
 
629
629
  如果`array`是数组且不为空,返回该数组,否则返回`undefined`,见[测试用例](tests/array.cy.ts)
630
630
 
631
+ - `calcUnusedMinSerialNumber = <T extends Record<string, unknown>>(list: T[],options: { fieldName: keyof T; prefix: string; defaultNo?: number }): number`
632
+
633
+ 通用序号计算工具:从指定列表中提取「前缀+数字」格式的值,找到未被使用的最小正整数序号,用法见[测试用例](tests/array.cy.ts)
634
+
631
635
  ## number
632
636
 
633
637
  - `randomInt(min: number, max: number): number`