ph-utils 0.11.2 → 0.11.4

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.d.ts CHANGED
@@ -59,14 +59,14 @@ export declare function symmetricDifference<T>(...arrs: T[][]): T[];
59
59
  * @param a2
60
60
  * @returns
61
61
  */
62
- export declare function isSubsetOf<T>(a1: T[] | Set<T>, a2: T[] | Set<T>): any;
62
+ export declare function isSubsetOf<T>(a1: T[] | Set<T>, a2: T[] | Set<T>): boolean;
63
63
  /**
64
64
  * 返回一个布尔值,指示给定集合中的所有元素是否都在此集合中。
65
65
  * @param arr1
66
66
  * @param arr2
67
67
  * @returns
68
68
  */
69
- export declare function isSupersetOf<T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>): any;
69
+ export declare function isSupersetOf<T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>): boolean;
70
70
  /**
71
71
  * 返回一个布尔值,指示此集合是否与给定集合没有公共元素。
72
72
  *
@@ -76,4 +76,4 @@ export declare function isSupersetOf<T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>):
76
76
  * @param arr2
77
77
  * @returns
78
78
  */
79
- export declare function isDisjointFrom<T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>): any;
79
+ export declare function isDisjointFrom<T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>): boolean;
@@ -0,0 +1,11 @@
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>;
@@ -0,0 +1,101 @@
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
+ }
package/lib/dom.d.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * web(浏览器端) DOM 文件操作
3
+ * 现今不推荐在使用这种方式,现在开发前端的时候,推荐使用一些成熟的框架例如:React、Preact、Vue、Angular、Svelte、Ember、Knockout等
4
+ * 在使用这些框架的时候额外的一些不可避免的 dom 操作时才使用这个工具;如果确实需要使用原生开发推荐使用 jquery 或者想要更精简的话可以使用 https://github.com/finom/bala 封装
5
+ */
1
6
  /**
2
7
  * 根据选择器获取节点
3
8
  * @param {string} selector 选择器
@@ -37,17 +42,12 @@ export declare function removeClass(elem: HTMLElement, clazz: string): void;
37
42
  */
38
43
  export declare function hasClass(elem: HTMLElement, clazz: string): boolean;
39
44
  /**
40
- * 为节点添加 transition 属性,包括浏览器前缀
41
- * @param {HTMLElement} element 需要添加 css Transition 属性的节点
42
- * @param {string} value css transition
43
- */
44
- export declare function transition(element: HTMLElement, value: string): void;
45
- /**
46
- * 为节点添加 transform 属性,包括浏览器前缀
47
- * @param {HTMLElement} element 需要添加 css transform 属性的节点
48
- * @param {string} value css transform 值
45
+ * 切换指定元素的类名。
46
+ * 如果元素已包含该类名,则移除它;否则添加它。
47
+ * @param el - 要操作的 HTML 元素。
48
+ * @param clazz - 要切换的类名。
49
49
  */
50
- export declare function transform(element: HTMLElement, value: string): void;
50
+ export declare function toggleClass(el: HTMLElement, clazz: string): void;
51
51
  /**
52
52
  * 为节点添加事件处理
53
53
  * @param {HTMLElement} element 添加事件的节点
@@ -173,7 +173,7 @@ export declare function formatStyle(styleObj: (string | undefined | null | "")[]
173
173
  ]);
174
174
  * ```
175
175
  */
176
- export declare function startTransition(target: HTMLElement, properties: [string, string][], duration?: string): void;
176
+ export declare function startTransition(target: HTMLElement, properties: [string, string][], duration?: string | undefined | null): void;
177
177
  /**
178
178
  * 结束元素的过渡效果,并在过渡结束后隐藏元素。
179
179
  * @param target - 要操作的 HTML 元素。
package/lib/dom.js CHANGED
@@ -3,7 +3,6 @@
3
3
  * 现今不推荐在使用这种方式,现在开发前端的时候,推荐使用一些成熟的框架例如:React、Preact、Vue、Angular、Svelte、Ember、Knockout等
4
4
  * 在使用这些框架的时候额外的一些不可避免的 dom 操作时才使用这个工具;如果确实需要使用原生开发推荐使用 jquery 或者想要更精简的话可以使用 https://github.com/finom/bala 封装
5
5
  */
6
- const vendorPrefix = ["", "-webkit", "-moz-"];
7
6
  /**
8
7
  * 根据选择器获取节点
9
8
  * @param {string} selector 选择器
@@ -60,26 +59,18 @@ export function hasClass(elem, clazz) {
60
59
  return elem.classList.contains(clazz);
61
60
  }
62
61
  /**
63
- * 为节点添加 transition 属性,包括浏览器前缀
64
- * @param {HTMLElement} element 需要添加 css Transition 属性的节点
65
- * @param {string} value css transition
62
+ * 切换指定元素的类名。
63
+ * 如果元素已包含该类名,则移除它;否则添加它。
64
+ * @param el - 要操作的 HTML 元素。
65
+ * @param clazz - 要切换的类名。
66
66
  */
67
- export function transition(element, value) {
68
- vendorPrefix.forEach((prefix) => {
69
- let t = prefix === "" ? "transition" : prefix + "Transition";
70
- element.style[t] = value;
71
- });
72
- }
73
- /**
74
- * 为节点添加 transform 属性,包括浏览器前缀
75
- * @param {HTMLElement} element 需要添加 css transform 属性的节点
76
- * @param {string} value css transform 值
77
- */
78
- export function transform(element, value) {
79
- vendorPrefix.forEach((prefix) => {
80
- let t = prefix === "" ? "transform" : prefix + "Transform";
81
- element.style[t] = value;
82
- });
67
+ export function toggleClass(el, clazz) {
68
+ if (hasClass(el, clazz)) {
69
+ removeClass(el, clazz);
70
+ }
71
+ else {
72
+ addClass(el, clazz);
73
+ }
83
74
  }
84
75
  /**
85
76
  * 为节点添加事件处理
@@ -356,7 +347,7 @@ export function formatStyle(styleObj) {
356
347
  ]);
357
348
  * ```
358
349
  */
359
- export function startTransition(target, properties, duration) {
350
+ export function startTransition(target, properties, duration = "0.3s") {
360
351
  target.style.setProperty("display", "none");
361
352
  const trans = [];
362
353
  for (let i = 0, len = properties.length; i < len; i++) {
@@ -367,14 +358,12 @@ export function startTransition(target, properties, duration) {
367
358
  if (duration) {
368
359
  target.style.setProperty("transition", trans.join(", "));
369
360
  }
370
- queueMicrotask(() => {
371
- target.style.removeProperty("display");
372
- queueMicrotask(() => {
373
- for (let i = 0, len = properties.length; i < len; i++) {
374
- const rec = properties[i];
375
- target.style.removeProperty(rec[0]);
376
- }
377
- });
361
+ target.style.removeProperty("display");
362
+ requestAnimationFrame(() => {
363
+ for (let i = 0, len = properties.length; i < len; i++) {
364
+ const rec = properties[i];
365
+ target.style.removeProperty(rec[0]);
366
+ }
378
367
  });
379
368
  }
380
369
  /**
package/lib/server.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { SpawnOptions } from "node:child_process";
3
2
  /**
4
3
  * 执行命令
package/lib/theme.js CHANGED
@@ -19,10 +19,10 @@ export async function initTheme() {
19
19
  if ($themeStyle == null) {
20
20
  $themeStyle = document.createElement("style");
21
21
  $themeStyle.id = "theme-style";
22
- $themeStyle.innerHTML = `
23
- :root{color-scheme:light dark;}
24
- html.light{color-scheme: light;}
25
- html.dark {color-scheme: dark;}
22
+ $themeStyle.innerHTML = `
23
+ :root{color-scheme:light dark;}
24
+ html.light{color-scheme: light;}
25
+ html.dark {color-scheme: dark;}
26
26
  `;
27
27
  document.head.appendChild($themeStyle);
28
28
  }
@@ -60,7 +60,10 @@ declare class Validator {
60
60
  * @param value 待验证的数据
61
61
  * @param data 原始数据,当验证确认密码时需要使用
62
62
  */
63
- validateKey(key: string, value: any, data?: any): Promise<boolean>;
63
+ validateKey(key: string, value: any, data?: any): Promise<{
64
+ key: string;
65
+ value: any;
66
+ }>;
64
67
  private _validateRule;
65
68
  private _parseSchemaRules;
66
69
  private _parseStringRule;
package/lib/validator.js CHANGED
@@ -112,7 +112,7 @@ class Validator {
112
112
  return new Promise((resolve, reject) => {
113
113
  let keyRules = this.rules[key];
114
114
  if (keyRules == null) {
115
- resolve(true);
115
+ resolve({ key, value });
116
116
  return;
117
117
  }
118
118
  let errMsg = this._validateRule(keyRules, value, data);
@@ -121,7 +121,7 @@ class Validator {
121
121
  reject(new ValidateError({ [key]: errMsg }, key, errMsg));
122
122
  }
123
123
  else {
124
- resolve(true);
124
+ resolve({ key, value });
125
125
  }
126
126
  });
127
127
  }
package/package.json CHANGED
@@ -68,7 +68,7 @@
68
68
  },
69
69
  "./*": "./lib/*"
70
70
  },
71
- "version": "0.11.2",
71
+ "version": "0.11.4",
72
72
  "type": "module",
73
73
  "repository": {
74
74
  "type": "git",