ph-utils 0.8.3 → 0.9.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.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
- ## ph-utils
2
-
3
- 整理了 js 前后端开发(web + nodejs)时常用的一些工具;[详细文档](https://gitee.com/towardly/ph/wikis/Home?sort_id=4035190)
4
-
5
- ### 包含如下工具文件
6
-
7
- `index` 基础工具类、`date` 跟日期相关的工具类、`file` 文件操作相关工具类[**服务端**]、`server` 服务端工具类、`validator` 数据验证、`dom` 浏览器节点操作相关[**前端**]、`web` 一些只适用于前端相关的工具、`color` 颜色相关工具
1
+ ## ph-utils
2
+
3
+ 整理了 js 前后端开发(web + nodejs)时常用的一些工具;[详细文档](https://gitee.com/towardly/ph/wikis/Home?sort_id=4035190)
4
+
5
+ ### 包含如下工具文件
6
+
7
+ `index` 基础工具类、`date` 跟日期相关的工具类、`file` 文件操作相关工具类[**服务端**]、`server` 服务端工具类、`validator` 数据验证、`dom` 浏览器节点操作相关[**前端**]、`web` 一些只适用于前端相关的工具、`color` 颜色相关工具
package/lib/array.js CHANGED
@@ -6,9 +6,10 @@
6
6
  * @returns
7
7
  */
8
8
  export function order(arr, order = "asc", orderKey = null) {
9
- const collator = new Intl.Collator();
9
+ const collator = new Intl.Collator(undefined, { numeric: true });
10
10
  return arr.sort((a, b) => {
11
- let aValue = a, bValue = b;
11
+ let aValue = a;
12
+ let bValue = b;
12
13
  if (typeof a === "object" && orderKey != null) {
13
14
  // @ts-ignore
14
15
  aValue = a[orderKey];
package/lib/date.js CHANGED
@@ -116,8 +116,6 @@ export function format(date, pattern = "yyyy-mm-dd HH:MM:ss") {
116
116
  export function parse(date) {
117
117
  if (date == null)
118
118
  return new Date();
119
- if (date instanceof Date)
120
- return date;
121
119
  if (typeof date === "string" && !/Z$/i.test(date)) {
122
120
  const d = date.match(REGEX_PARSE);
123
121
  if (d) {
@@ -127,7 +125,7 @@ export function parse(date) {
127
125
  if (typeof date === "number") {
128
126
  return new Date(date <= 9999999999 ? date * 1000 : date);
129
127
  }
130
- return new Date();
128
+ return new Date(date);
131
129
  }
132
130
  /**
133
131
  * 设置日期的开始或者结束的点
package/lib/index.d.ts CHANGED
@@ -29,37 +29,55 @@ export declare function isNumeric(str: string, numericParam?: {
29
29
  */
30
30
  export declare function isBoolean(str: string): boolean;
31
31
  /** 生成随机数的选项 */
32
- interface RandomConfig {
32
+ interface RandomStringOption {
33
33
  /** 生成指定长度的随机字符串 */
34
- length?: number;
34
+ length: number;
35
35
  /** 是否包含英文字母, 默认为: true */
36
36
  hasLetter?: boolean;
37
37
  /** 生成纯数字的随机数时, 首位是否允许为 0, 默认为: true */
38
38
  firstIsZero?: boolean;
39
+ }
40
+ interface RangeRandomOption {
39
41
  /** 配合 max 生成 [min~max] 之间的随机数 */
40
- min?: number;
42
+ min: number;
41
43
  /** 配合 min 生成 [min~max] 之间的随机数 */
42
- max?: number;
44
+ max: number;
43
45
  /** 生成的随机数,是否包含 max, 默认: false */
44
46
  hasEnd?: boolean;
45
47
  /** 生成的随机数是否是整数, 默认: true */
46
48
  isInteger?: boolean;
47
49
  }
48
50
  /**
49
- * 生成随机数
50
- * 1. 生成指定长度的随机数
51
- * 2. 生成介于 [min, max] 之间的随机数
52
- * @param opts 生成随机数的配置
51
+ * 生成指定长度的随机数
52
+ *
53
+ * @param len - 生成的随机数长度
53
54
  *
54
55
  * @example <caption>1. 生成指定长度的随机字符串</caption>
55
56
  * random(1); // 长度为 1 的随机字符串
57
+ */
58
+ export declare function random(len: number): string;
59
+ /**
60
+ * 生成介于 [min, max] 之间的随机数
56
61
  *
57
- * @example <caption>2. 生成纯数字且不能为0长度为1的随机字符</caption>
58
- * random({ length: 1, hasLetter: false, firstIsZero: false })
62
+ * @param option 配置项
63
+ * @param option.min 生成介于 [min, max] 之间的随机数
64
+ * @param option.max 生成介于 [min, max] 之间的随机数
65
+ * @param option.hasEnd 生成的随机数,是否包含 max, 默认: false
66
+ * @param option.isInteger 生成的随机数是否是整数, 默认: true
67
+ */
68
+ export declare function random(option: RangeRandomOption): number;
69
+ /**
70
+ * 生成指定长度随机数
59
71
  *
60
- * @returns
72
+ * @param option 配置项
73
+ * @param option.length 生成的随机数长度
74
+ * @param option.hasLetter 是否包含英文字母, 默认为: true
75
+ * @param option.firstIsZero 生成纯数字的随机数时, 首位是否允许为 0, 默认为: true
76
+ *
77
+ * @example <caption>2. 生成纯数字且首位不能为0长度为1的随机字符</caption>
78
+ * random({ length: 1, hasLetter: false, firstIsZero: false })
61
79
  */
62
- export declare function random(opts: number | RandomConfig): string | number;
80
+ export declare function random(option: RandomStringOption): string;
63
81
  /**
64
82
  * 带有错误名称标记的错误类型
65
83
  */
package/lib/index.js CHANGED
@@ -53,20 +53,6 @@ export function isNumeric(str, numericParam) {
53
53
  export function isBoolean(str) {
54
54
  return ["true", "false"].indexOf(str) >= 0;
55
55
  }
56
- /**
57
- * 生成随机数
58
- * 1. 生成指定长度的随机数
59
- * 2. 生成介于 [min, max] 之间的随机数
60
- * @param opts 生成随机数的配置
61
- *
62
- * @example <caption>1. 生成指定长度的随机字符串</caption>
63
- * random(1); // 长度为 1 的随机字符串
64
- *
65
- * @example <caption>2. 生成纯数字且不能为0长度为1的随机字符</caption>
66
- * random({ length: 1, hasLetter: false, firstIsZero: false })
67
- *
68
- * @returns
69
- */
70
56
  export function random(opts) {
71
57
  if (typeof opts === "object" && opts.min != null && opts.max != null) {
72
58
  const randomNum = Math.random();
@@ -79,13 +65,13 @@ export function random(opts) {
79
65
  if (typeof opts === "object" && opts.length == null) {
80
66
  throw new Error("random_length_cannot_null");
81
67
  }
82
- const len = typeof opts === "object" ? opts.length : opts;
68
+ let len = typeof opts === "object" ? opts.length : opts;
83
69
  /* 生成指定长度的随机数 */
84
70
  let chars = RANDOM_CHARS;
85
71
  if (typeof opts === "object" && opts.hasLetter === false) {
86
72
  chars = NUMBER_RANDOM_CHARTS;
87
73
  }
88
- const resRandom = Array.from({ length: len }, () => chars.charAt(random({ min: 0, max: 9, hasEnd: true }))).join("");
74
+ const resRandom = Array.from({ length: len }, () => chars.charAt(random({ min: 0, max: chars.length - 1, hasEnd: true }))).join("");
89
75
  if (typeof opts === "object" &&
90
76
  opts.firstIsZero === false &&
91
77
  resRandom.indexOf("0") === 0) {
package/lib/storage.d.ts CHANGED
@@ -11,8 +11,8 @@ interface StorageSetOption {
11
11
  * 存储值到 Storage 中
12
12
  * @param key 设置的 key
13
13
  * @param value 设置的值
14
- * @param storage session 或 local
15
- * @param expire 数据有效期, 单位秒, 默认: -1 - 永久存储
14
+ * @param [option.storage] session 或 local, 默认: session
15
+ * @param [option.expire] 数据有效期, 单位秒, 默认: -1 - 永久存储
16
16
  */
17
17
  export declare function set(key: string, value: any, option?: StorageSetOption): void;
18
18
  /**
@@ -37,8 +37,8 @@ interface StorageQueryOption {
37
37
  * 从 Storage 中取出数据
38
38
  * @param key 保存时的 key
39
39
  * @param defaultValue 没有数据时的默认值
40
- * @param delete 是否在取出后,删除数据,默认:false - 取出后删除数据
41
- * @param storage 使用的 Storage ,可以是 localStorage、sessionStorage
40
+ * @param [option.delete] 是否在取出后,删除数据,默认:false - 取出后删除数据
41
+ * @param [option.storage] 使用的 Storage ,可以是 localStorage、sessionStorage, 默认: localStorage、sessionStorage
42
42
  * @returns Storage 中 key 对应的数据
43
43
  */
44
44
  export declare function get<T>(key: string, defaultValue?: T, option?: StorageQueryOption): T;
package/lib/storage.js CHANGED
@@ -5,8 +5,8 @@ function getStorage(storage = "session") {
5
5
  * 存储值到 Storage 中
6
6
  * @param key 设置的 key
7
7
  * @param value 设置的值
8
- * @param storage session 或 local
9
- * @param expire 数据有效期, 单位秒, 默认: -1 - 永久存储
8
+ * @param [option.storage] session 或 local, 默认: session
9
+ * @param [option.expire] 数据有效期, 单位秒, 默认: -1 - 永久存储
10
10
  */
11
11
  export function set(key, value, option) {
12
12
  const opts = {
@@ -40,8 +40,8 @@ export function remove(key, storage) {
40
40
  * 从 Storage 中取出数据
41
41
  * @param key 保存时的 key
42
42
  * @param defaultValue 没有数据时的默认值
43
- * @param delete 是否在取出后,删除数据,默认:false - 取出后删除数据
44
- * @param storage 使用的 Storage ,可以是 localStorage、sessionStorage
43
+ * @param [option.delete] 是否在取出后,删除数据,默认:false - 取出后删除数据
44
+ * @param [option.storage] 使用的 Storage ,可以是 localStorage、sessionStorage, 默认: localStorage、sessionStorage
45
45
  * @returns Storage 中 key 对应的数据
46
46
  */
47
47
  export function get(key, defaultValue, option) {
package/lib/theme.d.ts ADDED
@@ -0,0 +1,42 @@
1
+ /** 获取当前系统的主题 */
2
+ export declare function getSystemTheme(): "dark" | "light";
3
+ /**
4
+ * 初始化主题, 让网页能够适应系统主题, 同时根据缓存的主题切换主题
5
+ * @returns 当前应用的主题
6
+ */
7
+ export declare function initTheme(): Promise<"dark" | "light">;
8
+ /**
9
+ * 切换主题, 通常用于预览
10
+ * @param theme 切换的主题
11
+ * @returns 切换后的主题
12
+ */
13
+ export declare function toggleTheme(theme?: "light" | "dark" | "auto"): Promise<"dark" | "light">;
14
+ /** 获取当前主题 */
15
+ export declare function getTheme(): string;
16
+ /**
17
+ * 应用主题
18
+ * @param theme 待应用的主题
19
+ * @param cache 是否缓存应用的主题, 让应用下一次启动的时候, 可以应用主题, 默认: true
20
+ * @returns 应用的主题
21
+ */
22
+ export declare function applyTheme(theme?: "light" | "dark" | "auto", cache?: boolean): Promise<"dark" | "light">;
23
+ /** 获取当前主题色 */
24
+ export declare function getColorTheme(defaultValue?: string): string | undefined;
25
+ /**
26
+ * 初始化主题色, 让网页能够适应系统主题色, 同时根据缓存的主题色切换主题色
27
+ * @returns 当前应用的主题色
28
+ */
29
+ export declare function initColorTheme(): Promise<string> | null;
30
+ /**
31
+ * 切换主题色, 通常用于预览
32
+ * @param color 待切换的主题色
33
+ * @returns 切换后的主题色
34
+ */
35
+ export declare function toggleColorTheme(color: string): Promise<string>;
36
+ /**
37
+ * 应用主题色
38
+ * @param color 主题色
39
+ * @param cache 是否缓存主题色, 让应用下一次启动的时候, 可以应用主题色, 默认: true
40
+ * @returns 切换后的主题色
41
+ */
42
+ export declare function applyColorTheme(color: string, cache?: boolean): Promise<string>;
package/lib/theme.js ADDED
@@ -0,0 +1,136 @@
1
+ import { adjust } from "./color.js";
2
+ /** 获取当前系统的主题 */
3
+ export function getSystemTheme() {
4
+ if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
5
+ return "dark";
6
+ }
7
+ return "light";
8
+ }
9
+ /**
10
+ * 初始化主题, 让网页能够适应系统主题, 同时根据缓存的主题切换主题
11
+ * @returns 当前应用的主题
12
+ */
13
+ export async function initTheme() {
14
+ // 让网页能够适应系统主题
15
+ let $themeStyle = document.getElementById("theme-style");
16
+ if ($themeStyle == null) {
17
+ $themeStyle = document.createElement("style");
18
+ $themeStyle.id = "theme-style";
19
+ $themeStyle.innerHTML = `
20
+ :root{color-scheme:light dark;}
21
+ html.light{color-scheme: light;}
22
+ html.dark {color-scheme: dark;}
23
+ `;
24
+ document.head.appendChild($themeStyle);
25
+ }
26
+ // 获取已经应用的主题设置
27
+ const cacheTheme = localStorage.getItem("web-theme-appearance");
28
+ return toggleTheme(cacheTheme);
29
+ }
30
+ /**
31
+ * 切换主题, 通常用于预览
32
+ * @param theme 切换的主题
33
+ * @returns 切换后的主题
34
+ */
35
+ export async function toggleTheme(theme) {
36
+ if (theme !== "light" && theme !== "dark") {
37
+ theme = getSystemTheme();
38
+ }
39
+ const classList = document.documentElement.classList;
40
+ if (theme === "light") {
41
+ classList.add("light");
42
+ classList.remove("dark");
43
+ }
44
+ else if (theme === "dark") {
45
+ classList.add("dark");
46
+ classList.remove("light");
47
+ }
48
+ return theme;
49
+ }
50
+ /** 获取当前主题 */
51
+ export function getTheme() {
52
+ // 1. 从根节点获取
53
+ let theme = document.documentElement.className.match(/light|dark/);
54
+ if (theme != null) {
55
+ theme = theme[0];
56
+ }
57
+ if (theme == null) {
58
+ theme = localStorage.getItem("web-theme-appearance");
59
+ }
60
+ if (theme == null) {
61
+ theme = getSystemTheme();
62
+ }
63
+ return theme;
64
+ }
65
+ /**
66
+ * 应用主题
67
+ * @param theme 待应用的主题
68
+ * @param cache 是否缓存应用的主题, 让应用下一次启动的时候, 可以应用主题, 默认: true
69
+ * @returns 应用的主题
70
+ */
71
+ export async function applyTheme(theme, cache = true) {
72
+ if (cache === true) {
73
+ localStorage.setItem("web-theme-appearance", theme == null ? "auto" : theme);
74
+ }
75
+ return toggleTheme(theme);
76
+ }
77
+ /** 获取当前主题色 */
78
+ export function getColorTheme(defaultValue) {
79
+ const root = document.documentElement;
80
+ const match = root.className.match(/color-([0-9a-fA-F]{6})/);
81
+ if (match == null) {
82
+ // 获取 --nt-primary-color 的值
83
+ let color = getComputedStyle(root).getPropertyValue("--nt-primary-color");
84
+ if (color === "") {
85
+ color = localStorage.getItem("web-theme-color");
86
+ }
87
+ return color ? color : defaultValue;
88
+ }
89
+ return `#${match[1]}`;
90
+ }
91
+ /**
92
+ * 初始化主题色, 让网页能够适应系统主题色, 同时根据缓存的主题色切换主题色
93
+ * @returns 当前应用的主题色
94
+ */
95
+ export function initColorTheme() {
96
+ // 获取缓存主题色
97
+ const color = localStorage.getItem("web-theme-color");
98
+ if (color != null) {
99
+ return toggleColorTheme(color);
100
+ }
101
+ return color;
102
+ }
103
+ /**
104
+ * 切换主题色, 通常用于预览
105
+ * @param color 待切换的主题色
106
+ * @returns 切换后的主题色
107
+ */
108
+ export async function toggleColorTheme(color) {
109
+ const vars = [
110
+ `--nt-primary-color: ${color};`,
111
+ `--nt-primary-color-dark1: ${adjust(color, 1, false)};`,
112
+ ];
113
+ for (let i = 1; i <= 5; i++) {
114
+ vars.push(`--nt-primary-color-light${i}: ${adjust(color, i)};`);
115
+ }
116
+ let $style = document.getElementById("color-theme-style");
117
+ if ($style == null) {
118
+ $style = document.createElement("style");
119
+ $style.id = "color-theme-style";
120
+ document.head.appendChild($style);
121
+ }
122
+ $style.innerHTML = `:root{${vars.join("")}}`;
123
+ return color;
124
+ }
125
+ /**
126
+ * 应用主题色
127
+ * @param color 主题色
128
+ * @param cache 是否缓存主题色, 让应用下一次启动的时候, 可以应用主题色, 默认: true
129
+ * @returns 切换后的主题色
130
+ */
131
+ export function applyColorTheme(color, cache = true) {
132
+ if (cache === true) {
133
+ localStorage.setItem("web-theme-color", color.substring(1));
134
+ }
135
+ return toggleColorTheme(color);
136
+ }
package/package.json CHANGED
@@ -58,9 +58,13 @@
58
58
  "types": "./lib/array.d.ts",
59
59
  "import": "./lib/array.js"
60
60
  },
61
+ "./theme": {
62
+ "types": "./lib/theme.d.ts",
63
+ "import": "./lib/theme.js"
64
+ },
61
65
  "./*": "./lib/*"
62
66
  },
63
- "version": "0.8.3",
67
+ "version": "0.9.0",
64
68
  "type": "module",
65
69
  "repository": {
66
70
  "type": "git",
@@ -1,11 +0,0 @@
1
- /**
2
- * 复制数据, 可以从多种类型的数据
3
- * 1. 直接复制文本: await copy("待复制的文本")
4
- * 2. 复制节点上的 data-copy-text:
5
- * <button data-copy-text="这是待复制的文本">复制</button>
6
- * await copy(e.target) // or await copy("#a") or await copy(document.querySelector('#a'))
7
- * 3. 直接复制节点本身数据: await copy('#a')
8
- * @param {string | HTMLElement} source 复制源, 从中解析待复制的数据
9
- * @returns {Promise<boolean>} 是否复制成功
10
- */
11
- export declare function copy(source: string | HTMLElement): Promise<boolean>;
package/lib/clipboard.js DELETED
@@ -1,101 +0,0 @@
1
- /**
2
- * 创建一个临时节点缓存待复制数据
3
- * @param {String} value - 待复制文本
4
- * @return {HTMLElement}
5
- */
6
- function createFakeElement(value) {
7
- const fakeElement = document.createElement("textarea");
8
- fakeElement.style.border = "0";
9
- fakeElement.style.padding = "0";
10
- fakeElement.style.margin = "0";
11
- fakeElement.style.position = "absolute";
12
- fakeElement.style.left = "-9999px";
13
- fakeElement.style.top = "-9999";
14
- fakeElement.setAttribute("readonly", "");
15
- fakeElement.value = value;
16
- return fakeElement;
17
- }
18
- /** 通过执行 execCommand 来执行复制 */
19
- function copyFromCommand(text) {
20
- // 添加节点
21
- const fakeEl = createFakeElement(text);
22
- document.body.append(fakeEl);
23
- fakeEl.focus();
24
- fakeEl.select();
25
- // 执行复制
26
- const res = document.execCommand("copy");
27
- fakeEl.remove(); // 删除节点
28
- return Promise.resolve(res);
29
- }
30
- /** 使用 navigator.clipboard 复制 */
31
- function copyFromClipboard(text) {
32
- const theClipboard = navigator.clipboard;
33
- if (theClipboard != null) {
34
- return theClipboard
35
- .writeText(text)
36
- .then(() => {
37
- Promise.resolve(true);
38
- })
39
- .catch(() => Promise.resolve(false));
40
- }
41
- return Promise.resolve(false);
42
- }
43
- /** 解析待复制的文本 */
44
- function parseCopyText(source) {
45
- let copyText = null; // 待复制文本
46
- let sourceEl = null;
47
- // 获取待复制数据
48
- if (typeof source === "string") {
49
- // 从节点拿数据
50
- if (source.startsWith("#") || source.startsWith(".")) {
51
- sourceEl = document.querySelector(source);
52
- if (sourceEl == null) {
53
- copyText = source;
54
- }
55
- }
56
- else {
57
- copyText = source;
58
- }
59
- }
60
- if (source instanceof HTMLElement) {
61
- sourceEl = source;
62
- }
63
- // 从节点获取待复制数据
64
- if (sourceEl != null) {
65
- if (sourceEl.hasAttribute("data-copy-text")) {
66
- copyText = sourceEl.getAttribute("data-copy-text");
67
- }
68
- else {
69
- const tagName = sourceEl.tagName;
70
- if (tagName === "INPUT" || tagName === "TEXTAREA") {
71
- copyText = sourceEl.value;
72
- }
73
- else {
74
- copyText = sourceEl.textContent;
75
- }
76
- }
77
- }
78
- return copyText;
79
- }
80
- /**
81
- * 复制数据, 可以从多种类型的数据
82
- * 1. 直接复制文本: await copy("待复制的文本")
83
- * 2. 复制节点上的 data-copy-text:
84
- * <button data-copy-text="这是待复制的文本">复制</button>
85
- * await copy(e.target) // or await copy("#a") or await copy(document.querySelector('#a'))
86
- * 3. 直接复制节点本身数据: await copy('#a')
87
- * @param {string | HTMLElement} source 复制源, 从中解析待复制的数据
88
- * @returns {Promise<boolean>} 是否复制成功
89
- */
90
- export async function copy(source) {
91
- // 待复制文本
92
- const copyText = parseCopyText(source);
93
- if (copyText == null) {
94
- return Promise.resolve(false);
95
- }
96
- const v = await copyFromClipboard(copyText);
97
- if (v === false) {
98
- return copyFromCommand(copyText);
99
- }
100
- return Promise.resolve(true);
101
- }