@d-matrix/utils 1.25.0 → 1.27.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.
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 二分查找target 在arr中的索引
3
+ * @param arr
4
+ * @param target
5
+ * @param forward true 向前取值,false
6
+ * @param backward true 向后取值,false
7
+ */
8
+ export declare const binarySearchIndex: <T>(arr: T[], target: T, forward?: boolean, backward?: boolean) => number;
@@ -0,0 +1,38 @@
1
+ // 二分
2
+ /**
3
+ * 二分查找target 在arr中的索引
4
+ * @param arr
5
+ * @param target
6
+ * @param forward true 向前取值,false
7
+ * @param backward true 向后取值,false
8
+ */
9
+ export const binarySearchIndex = (arr, target, forward = false, backward = false) => {
10
+ let low = 0;
11
+ let high = arr.length - 1;
12
+ let result = -1; // 如果找不到,返回-1
13
+ while (low <= high) {
14
+ const mid = Math.floor((low + high) / 2);
15
+ if (arr[mid] === target) {
16
+ return mid; // 找到目标值,返回索引
17
+ }
18
+ else if (arr[mid] < target) {
19
+ low = mid + 1;
20
+ }
21
+ else {
22
+ high = mid - 1;
23
+ }
24
+ if (forward) {
25
+ // 向前取值
26
+ if (arr[mid] < target) {
27
+ result = mid;
28
+ }
29
+ }
30
+ else if (backward) {
31
+ // 向后取值
32
+ if (arr[mid] > target) {
33
+ result = mid;
34
+ }
35
+ }
36
+ }
37
+ return result;
38
+ };
@@ -1 +1,2 @@
1
1
  export * as tree from './tree';
2
+ export * as binary from './binary';
@@ -1 +1,2 @@
1
1
  export * as tree from './tree';
2
+ export * as binary from './binary';
@@ -31,3 +31,4 @@ export declare const findParent: <T extends Record<string, any>>(tree: T | undef
31
31
  * @returns 节点路径
32
32
  */
33
33
  export declare function findPath<T extends Record<string, any>>(tree: T[], func: (node: T) => boolean, childrenKey?: string): T[] | null;
34
+ export declare function flatten<T extends Record<string, any>>(tree: T[], childrenKey?: string): Record<string, any>[];
@@ -1,3 +1,14 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
1
12
  /**
2
13
  * 计算指定层级的节点数量
3
14
  * @param root tree data 对象
@@ -95,3 +106,19 @@ export function findPath(tree, func, childrenKey = 'children') {
95
106
  }
96
107
  return null;
97
108
  }
109
+ export function flatten(tree, childrenKey = 'children') {
110
+ const result = [];
111
+ function traverse(node) {
112
+ // 将当前节点添加到结果数组
113
+ const _a = node, _b = childrenKey, __ = _a[_b], nodePropsOmitChildren = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
114
+ result.push(nodePropsOmitChildren);
115
+ const children = node[childrenKey];
116
+ // 如果节点有子节点,则递归处理每个子节点
117
+ if (children && Array.isArray(children) && children.length > 0) {
118
+ children.forEach((child) => traverse(child));
119
+ }
120
+ }
121
+ // 遍历树的每个根节点
122
+ tree.forEach((root) => traverse(root));
123
+ return result;
124
+ }
package/dist/array.d.ts CHANGED
@@ -2,3 +2,4 @@ export declare function moveMutable<T>(array: T[], fromIndex: number, toIndex: n
2
2
  export declare function moveImmutable<T>(array: T[], fromIndex: number, toIndex: number): T[];
3
3
  export declare function moveToStart<T>(array: T[], predicate: (item: T) => boolean): T[];
4
4
  export declare const moveMulti: <T extends unknown>(arr: T[], indexes: number[], start: number) => T[];
5
+ export declare const getArrayOrUndefined: <T>(array?: T[] | null | undefined) => T[] | undefined;
package/dist/array.js CHANGED
@@ -31,3 +31,7 @@ export const moveMulti = (arr, indexes, start) => {
31
31
  cloned.splice(start, 0, ...els);
32
32
  return cloned.filter((v) => v !== removeSymbol);
33
33
  };
34
+ export const getArrayOrUndefined = (array) => {
35
+ if (Array.isArray(array) && array.length > 0)
36
+ return array;
37
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * 将十六进制颜色转换为 RGBA 颜色
3
+ * @param hex 十六进制颜色
4
+ * @param alpha 透明度,默认值为 1
5
+ * @returns RGBA 颜色
6
+ */
7
+ export declare function hexToRGBA(hex: string, alpha?: number | string): string;
package/dist/color.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * 将十六进制颜色转换为 RGBA 颜色
3
+ * @param hex 十六进制颜色
4
+ * @param alpha 透明度,默认值为 1
5
+ * @returns RGBA 颜色
6
+ */
7
+ export function hexToRGBA(hex, alpha = 1) {
8
+ // 移除井号并转为小写
9
+ const processedHex = hex.replace(/^#/, '').toLowerCase();
10
+ // 验证十六进制字符合法性
11
+ if (!/^[0-9a-f]+$/.test(processedHex)) {
12
+ throw new Error('Invalid hex character(s)');
13
+ }
14
+ // 验证长度合法性
15
+ if (![3, 6].includes(processedHex.length)) {
16
+ throw new Error('Hex must be 3 or 6 characters long');
17
+ }
18
+ // 扩展三位缩写为六位
19
+ const fullHex = processedHex.length === 3
20
+ ? processedHex
21
+ .split('')
22
+ .map((c) => c + c)
23
+ .join('')
24
+ : processedHex;
25
+ // 解析颜色通道
26
+ const parseChannel = (start, end) => parseInt(fullHex.substring(start, end), 16);
27
+ const r = parseChannel(0, 2);
28
+ const g = parseChannel(2, 4);
29
+ const b = parseChannel(4, 6);
30
+ // 处理透明度
31
+ const numericAlpha = Number(alpha);
32
+ if (isNaN(numericAlpha)) {
33
+ throw new Error('Alpha must be a valid number');
34
+ }
35
+ if (numericAlpha < 0 || numericAlpha > 1) {
36
+ throw new Error('Alpha must be between 0 and 1');
37
+ }
38
+ // 标准化输出格式
39
+ const formattedAlpha = numericAlpha % 1 === 0 ? numericAlpha.toFixed(0) : numericAlpha.toFixed(2).replace(/0+$/, '').replace(/\.$/, '');
40
+ return `rgba(${r}, ${g}, ${b}, ${formattedAlpha})`;
41
+ }
package/dist/file.js CHANGED
@@ -109,6 +109,8 @@ export function download(source, fileName = '', target) {
109
109
  link.target = target;
110
110
  }
111
111
  else {
112
+ // https://stackoverflow.com/questions/33909763/download-attribute-with-a-file-name-not-working
113
+ // download 只在同源 URL 或 blob:、data: 协议起作用, 如果下载不同源的oss文件,download属性无效
112
114
  link.download = fileName;
113
115
  }
114
116
  link.href = source;
package/dist/index.d.ts CHANGED
@@ -13,3 +13,4 @@ export * as object from './object';
13
13
  export * as echarts from './echarts';
14
14
  export * as array from './array';
15
15
  export * as number from './number';
16
+ export * as color from './color';
package/dist/index.js CHANGED
@@ -13,3 +13,4 @@ export * as object from './object';
13
13
  export * as echarts from './echarts';
14
14
  export * as array from './array';
15
15
  export * as number from './number';
16
+ export * as color from './color';
@@ -9,3 +9,4 @@ export * from './types';
9
9
  export * from './useForwardRef';
10
10
  export * from './useIsomorphicLayoutEffect';
11
11
  export * from './useMediaQuery';
12
+ export * from './useIsFirstRender';
@@ -9,3 +9,4 @@ export * from './types';
9
9
  export * from './useForwardRef';
10
10
  export * from './useIsomorphicLayoutEffect';
11
11
  export * from './useMediaQuery';
12
+ export * from './useIsFirstRender';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 使用 useIsFirstRender 区分第一次和后续渲染
3
+ * useIsFirstRender 对于确定当前渲染是否是组件的第一个渲染很有用。当你想在初始渲染时有条件地执行某些逻辑或渲染特定组件时,这个钩子特别有价值,提供了一种有效的方法来区分第一次和后续渲染。
4
+ * @returns boolean true 表示第一次渲染,false 表示其他渲染
5
+ */
6
+ export declare function useIsFirstRender(): boolean;
@@ -0,0 +1,14 @@
1
+ import { useRef } from 'react';
2
+ /**
3
+ * 使用 useIsFirstRender 区分第一次和后续渲染
4
+ * useIsFirstRender 对于确定当前渲染是否是组件的第一个渲染很有用。当你想在初始渲染时有条件地执行某些逻辑或渲染特定组件时,这个钩子特别有价值,提供了一种有效的方法来区分第一次和后续渲染。
5
+ * @returns boolean true 表示第一次渲染,false 表示其他渲染
6
+ */
7
+ export function useIsFirstRender() {
8
+ const renderRef = useRef(true);
9
+ if (renderRef.current === true) {
10
+ renderRef.current = false;
11
+ return true;
12
+ }
13
+ return renderRef.current;
14
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@d-matrix/utils",
3
3
  "sideEffects": false,
4
- "version": "1.25.0",
4
+ "version": "1.27.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
@@ -22,6 +22,7 @@ A dozen of utils for Front-End Development
22
22
  - [array](#array)
23
23
  - [number](#number)
24
24
  - [echarts](#echarts)
25
+ - [color](#color)
25
26
 
26
27
  ### clipboard
27
28
 
@@ -198,6 +199,10 @@ export default function Component() {
198
199
  }
199
200
  ```
200
201
 
202
+ - `useIsFirstRender(): boolean`
203
+
204
+ 对于确定当前渲染是否是组件的第一个渲染很有用。当你想在初始渲染时有条件地执行某些逻辑或渲染特定组件时,这个 hook 特别有价值,提供了一种有效的方法来区分第一次和后续渲染。
205
+
201
206
  ### dom
202
207
 
203
208
  - `scrollToTop(element: Element | null | undefined): void`
@@ -424,6 +429,10 @@ const actual = tree.findPath([root], (node) => node.id === 33);
424
429
  expect(actual).to.be.deep.equal([root, root.children[1], root.children[1].children[2]]);
425
430
  ```
426
431
 
432
+ - `tree.flatten(tree, T[], childrenKey = 'children')`
433
+
434
+ 扁平化树结构, 返回的每个节点没有`children`属性
435
+
427
436
  ### file
428
437
 
429
438
  - `toImage(file: BlobPart | FileURL, options?: BlobPropertyBag): Promise<HTMLImageElement>`
@@ -615,6 +624,10 @@ const newList = array.moveToStart(list, (item) => item.id === 4);
615
624
 
616
625
  移动多个元素到数组中指定的位置,用法,见[测试用例](tests/algorithm.cy.ts)
617
626
 
627
+ - `getArrayOrUndefined<T>(array?: T[] | undefined | null): T[] | undefined`
628
+
629
+ 如果`array`是数组且不为空,返回该数组,否则返回`undefined`,见[测试用例](tests/array.cy.ts)
630
+
618
631
  ## number
619
632
 
620
633
  - `randomInt(min: number, max: number): number`
@@ -637,6 +650,12 @@ deep merge Echarts配置,用法见[测试用例](./tests//echarts/echarts.cy.t
637
650
 
638
651
  计算echarts YAxis的max和min属性,以达到根据实际数据动态调整,使折线图的波动明显。且第一个点始终在Y轴中间位置,[效果图](https://raw.githubusercontent.com/mrdulin/pic-bucket-01/master/Dingtalk_20240724140535.jpg)
639
652
 
653
+ ## color
654
+
655
+ - `hexToRGBA(hex: string, alpha: number | string = 1): string`
656
+
657
+ 将十六进制颜色转换为 RGBA 颜色, 见[测试用例](./tests/color.cy.ts)
658
+
640
659
  ## 测试
641
660
 
642
661
  运行全部组件测试