ph-utils 0.20.0 → 1.0.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/lib/storage.js DELETED
@@ -1,73 +0,0 @@
1
- function getStorage(storage = "session") {
2
- return storage === "session" ? sessionStorage : localStorage;
3
- }
4
- /**
5
- * 存储值到 Storage 中
6
- * @param key 设置的 key
7
- * @param value 设置的值
8
- * @param [option.storage] session 或 local, 默认: session
9
- * @param [option.expire] 数据有效期, 单位秒, 默认: -1 - 永久存储
10
- *
11
- * @example <caption>1. 存储到 SessionStorage</caption>
12
- * set("key", "value");
13
- *
14
- * @example <caption>2. 存储到 LocalStorage</caption>
15
- * set("key", "value", { storage: "local" });
16
- */
17
- export function set(key, value, option) {
18
- const opts = {
19
- expire: -1,
20
- storage: "session",
21
- ...option,
22
- };
23
- const saveData = JSON.stringify({
24
- value,
25
- time: Date.now(),
26
- expire: opts.expire === -1 ? -1 : Math.floor(Date.now() / 1000) + opts.expire,
27
- });
28
- getStorage(opts.storage).setItem(key, saveData);
29
- }
30
- /**
31
- * 清空所有的缓存内容
32
- * @param storage 待清空的缓存对象
33
- */
34
- export function clear(storage) {
35
- getStorage(storage).clear();
36
- }
37
- /**
38
- * 删除存储到 Storage 中的数据
39
- * @param key
40
- * @param storage
41
- */
42
- export function remove(key, storage) {
43
- getStorage(storage).removeItem(key);
44
- }
45
- /**
46
- * 从 Storage 中取出数据
47
- * @param key 保存时的 key
48
- * @param defaultValue 没有数据时的默认值
49
- * @param [option.delete] 是否在取出后,删除数据,默认:false - 取出后删除数据
50
- * @param [option.storage] 使用的 Storage ,可以是 localStorage、sessionStorage, 默认: localStorage、sessionStorage
51
- * @returns Storage 中 key 对应的数据
52
- */
53
- export function get(key, defaultValue, option) {
54
- const opts = (option || { delete: false });
55
- const storage = getStorage(opts.storage);
56
- let data = storage.getItem(key);
57
- if (data == null) {
58
- return defaultValue || null;
59
- }
60
- data = JSON.parse(data);
61
- let d = data.value;
62
- if (data.expire !== -1) {
63
- // 数据过期
64
- if (Math.floor(Date.now() / 1000) > data.expire) {
65
- d = null;
66
- storage.removeItem(key);
67
- }
68
- }
69
- if (opts.delete) {
70
- storage.removeItem(key);
71
- }
72
- return d || defaultValue;
73
- }
package/lib/theme.d.ts DELETED
@@ -1,44 +0,0 @@
1
- /** 获取当前系统的主题 */
2
- export declare function getSystemTheme(): "light" | "dark" | "auto";
3
- /**
4
- * 初始化主题, 让网页能够适应系统主题, 同时根据缓存的主题切换主题
5
- * @returns 当前应用的主题
6
- */
7
- export declare function initTheme(): Promise<"light" | "dark" | "auto">;
8
- /**
9
- * 切换主题, 通常用于预览
10
- * @param theme 切换的主题
11
- * @param transition 是否使用过渡动画, 注意浏览器必须支持 document.startViewTransition, 默认: true
12
- * @returns 切换后的主题
13
- */
14
- export declare function toggleTheme(theme?: "light" | "dark" | "auto", transition?: boolean): Promise<"light" | "dark" | "auto">;
15
- /** 获取当前主题 */
16
- export declare function getTheme(): string;
17
- /**
18
- * 应用主题
19
- * @param theme 待应用的主题
20
- * @param cache 是否缓存应用的主题, 让应用下一次启动的时候, 可以应用主题, 默认: true
21
- * @param transition 是否使用过渡动画, 注意浏览器必须支持 document.startViewTransition, 默认: true
22
- * @returns 应用的主题
23
- */
24
- export declare function applyTheme(theme?: "light" | "dark" | "auto", cache?: boolean, transition?: boolean): Promise<"light" | "dark" | "auto">;
25
- /** 获取当前主题色 */
26
- export declare function getColorTheme(defaultValue?: string): string | undefined;
27
- /**
28
- * 初始化主题色, 让网页能够适应系统主题色, 同时根据缓存的主题色切换主题色
29
- * @returns 当前应用的主题色
30
- */
31
- export declare function initColorTheme(): Promise<string> | null;
32
- /**
33
- * 切换主题色, 通常用于预览
34
- * @param color 待切换的主题色
35
- * @returns 切换后的主题色
36
- */
37
- export declare function toggleColorTheme(color: string): Promise<string>;
38
- /**
39
- * 应用主题色
40
- * @param color 主题色
41
- * @param cache 是否缓存主题色, 让应用下一次启动的时候, 可以应用主题色, 默认: true
42
- * @returns 切换后的主题色
43
- */
44
- export declare function applyColorTheme(color: string, cache?: boolean): Promise<string>;
package/lib/theme.js DELETED
@@ -1,156 +0,0 @@
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
- else if (window.matchMedia("(prefers-color-scheme: light)").matches) {
8
- return "light";
9
- }
10
- return "auto";
11
- }
12
- /**
13
- * 初始化主题, 让网页能够适应系统主题, 同时根据缓存的主题切换主题
14
- * @returns 当前应用的主题
15
- */
16
- export async function initTheme() {
17
- // 让网页能够适应系统主题
18
- let $themeStyle = document.getElementById("theme-style");
19
- if ($themeStyle == null) {
20
- $themeStyle = document.createElement("style");
21
- $themeStyle.id = "theme-style";
22
- $themeStyle.innerHTML =
23
- ":root{color-scheme:light dark;}html.light{color-scheme: light;}html.dark {color-scheme: dark;}";
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
- * @param transition 是否使用过渡动画, 注意浏览器必须支持 document.startViewTransition, 默认: true
34
- * @returns 切换后的主题
35
- */
36
- export async function toggleTheme(theme, transition = true) {
37
- return new Promise((resolve) => {
38
- const classList = document.documentElement.classList;
39
- if (theme == null) {
40
- theme = getSystemTheme();
41
- }
42
- function updateThemeClass() {
43
- if (theme === "light") {
44
- classList.add("light");
45
- classList.remove("dark");
46
- }
47
- else if (theme === "dark") {
48
- classList.add("dark");
49
- classList.remove("light");
50
- }
51
- else {
52
- classList.remove("light", "dark");
53
- }
54
- }
55
- // @ts-ignore
56
- if (transition && document.startViewTransition) {
57
- // @ts-ignore
58
- document.startViewTransition(() => {
59
- updateThemeClass();
60
- resolve(theme);
61
- });
62
- }
63
- else {
64
- updateThemeClass();
65
- resolve(theme);
66
- }
67
- });
68
- }
69
- /** 获取当前主题 */
70
- export function getTheme() {
71
- // 1. 从根节点获取
72
- let theme = document.documentElement.className.match(/light|dark/);
73
- if (theme != null) {
74
- theme = theme[0];
75
- }
76
- if (theme == null) {
77
- theme = localStorage.getItem("web-theme-appearance");
78
- }
79
- if (theme == null) {
80
- theme = getSystemTheme();
81
- }
82
- return theme;
83
- }
84
- /**
85
- * 应用主题
86
- * @param theme 待应用的主题
87
- * @param cache 是否缓存应用的主题, 让应用下一次启动的时候, 可以应用主题, 默认: true
88
- * @param transition 是否使用过渡动画, 注意浏览器必须支持 document.startViewTransition, 默认: true
89
- * @returns 应用的主题
90
- */
91
- export async function applyTheme(theme, cache = true, transition = true) {
92
- if (cache === true) {
93
- localStorage.setItem("web-theme-appearance", theme == null ? "auto" : theme);
94
- }
95
- return toggleTheme(theme, transition);
96
- }
97
- /** 获取当前主题色 */
98
- export function getColorTheme(defaultValue) {
99
- const root = document.documentElement;
100
- const match = root.className.match(/color-([0-9a-fA-F]{6})/);
101
- if (match == null) {
102
- // 获取 --nt-primary-color 的值
103
- let color = getComputedStyle(root).getPropertyValue("--l-primary-color");
104
- if (color === "") {
105
- color = localStorage.getItem("web-theme-color");
106
- }
107
- return color ? color : defaultValue;
108
- }
109
- return `#${match[1]}`;
110
- }
111
- /**
112
- * 初始化主题色, 让网页能够适应系统主题色, 同时根据缓存的主题色切换主题色
113
- * @returns 当前应用的主题色
114
- */
115
- export function initColorTheme() {
116
- // 获取缓存主题色
117
- const color = localStorage.getItem("web-theme-color");
118
- if (color != null) {
119
- return toggleColorTheme(color);
120
- }
121
- return color;
122
- }
123
- /**
124
- * 切换主题色, 通常用于预览
125
- * @param color 待切换的主题色
126
- * @returns 切换后的主题色
127
- */
128
- export async function toggleColorTheme(color) {
129
- const vars = [
130
- `--l-primary-color: ${color};`,
131
- `--l-primary-color-dark1: ${adjust(color, 1, false)};`,
132
- ];
133
- for (let i = 1; i <= 5; i++) {
134
- vars.push(`--l-primary-color-light${i}: ${adjust(color, i)};`);
135
- }
136
- let $style = document.getElementById("color-theme-style");
137
- if ($style == null) {
138
- $style = document.createElement("style");
139
- $style.id = "color-theme-style";
140
- document.head.appendChild($style);
141
- }
142
- $style.innerHTML = `:root{${vars.join("")}}`;
143
- return color;
144
- }
145
- /**
146
- * 应用主题色
147
- * @param color 主题色
148
- * @param cache 是否缓存主题色, 让应用下一次启动的时候, 可以应用主题色, 默认: true
149
- * @returns 切换后的主题色
150
- */
151
- export function applyColorTheme(color, cache = true) {
152
- if (cache === true) {
153
- localStorage.setItem("web-theme-color", color);
154
- }
155
- return toggleColorTheme(color);
156
- }
@@ -1,71 +0,0 @@
1
- /**
2
- * 数据验证器
3
- */
4
- interface RuleItem {
5
- rule: RegExp | ((v: any) => boolean) | "required";
6
- message: string;
7
- sameKey?: string;
8
- }
9
- export type RuleType = string | RegExp | ((v: any) => boolean) | (RegExp | string | ((v: any) => boolean) | {
10
- rule: string | RegExp | ((v: any) => boolean);
11
- message?: string;
12
- });
13
- export interface SchemaType {
14
- /** 数据字段 */
15
- key: string;
16
- /** 是否必须 */
17
- required?: boolean;
18
- /** 验证规则列表 */
19
- rules?: RuleType[];
20
- /** 错误信息 */
21
- message?: string;
22
- }
23
- /**
24
- * 数据验证器
25
- */
26
- declare class Validator {
27
- rules: Record<string, RuleItem[]>;
28
- /**
29
- * 构造数据验证转换器
30
- *
31
- * See {@link https://gitee.com/towardly/ph/wikis/utils/validator|Validator文档}.
32
- *
33
- * @param schemas 配置验证转换规则
34
- *
35
- * @example
36
- *
37
- * const validator = new Validator([
38
- * { key: 'mobile', rules: ['required', 'mobile'] },
39
- * { key: 'code': rules: /^\d{6}$/, message: '请输入正确的验证码' },
40
- * { key: 'confirmPassword', rules: ['required', 'same:password'] }
41
- * ])
42
- * // 验证某一个字段
43
- * validator.validateKey().then(res => {})
44
- */
45
- constructor(schemas: SchemaType[]);
46
- addSchemas(schemas: SchemaType[]): void;
47
- addSchema(schema: SchemaType): void;
48
- setSchema(schema: SchemaType): void;
49
- setSchemas(schemas: SchemaType[]): void;
50
- /**
51
- * 进行数据验证
52
- * @param data 待验证的数据
53
- * @param all 是否全部验证, false - 只要验证错误一个则停止验证
54
- * @returns
55
- */
56
- validate(data: any, all?: boolean): Promise<boolean>;
57
- /**
58
- * 只验证指定 key 的数据格式
59
- * @param key 指定待验证的 key
60
- * @param value 待验证的数据
61
- * @param data 原始数据,当验证确认密码时需要使用
62
- */
63
- validateKey(key: string, value: any, data?: any): Promise<{
64
- key: string;
65
- value: any;
66
- }>;
67
- private _validateRule;
68
- private _parseSchemaRules;
69
- private _parseStringRule;
70
- }
71
- export default Validator;
package/lib/validator.js DELETED
@@ -1,248 +0,0 @@
1
- /**
2
- * 数据验证器
3
- */
4
- // 默认的错误提示信息
5
- const defaultMsgs = {
6
- mobile: "请输入正确的手机号",
7
- same: "两次输入不一致",
8
- required: "%s为必填字段",
9
- };
10
- const defaultMsg = "请输入正确的数据";
11
- // 一些常用的验证正则
12
- const ruleRegexs = {
13
- /** 验证跟其余数据相等的正则,一般用于验证再次输入密码 */
14
- same: /^same:(.+)$/i,
15
- /** 验证手机号的正则表达式 */
16
- mobile: /^1[3456789]\d{9}$/,
17
- /** 非空验证的正则表达式 */
18
- required: /^\S{1}.*/,
19
- };
20
- // 规则比对函数
21
- const ruleFns = {
22
- /** 验证相等 */
23
- same(val1, val2) {
24
- return val2 === val1;
25
- },
26
- /** 正则匹配 */
27
- pattern(regex, val) {
28
- if (val == null) {
29
- return false;
30
- }
31
- return regex.test(String(val));
32
- },
33
- };
34
- class ValidateError extends Error {
35
- constructor(detail, key, message) {
36
- super(message);
37
- this.name = "ValidateError";
38
- this.key = key;
39
- this.detail = detail;
40
- }
41
- }
42
- /**
43
- * 数据验证器
44
- */
45
- class Validator {
46
- /**
47
- * 构造数据验证转换器
48
- *
49
- * See {@link https://gitee.com/towardly/ph/wikis/utils/validator|Validator文档}.
50
- *
51
- * @param schemas 配置验证转换规则
52
- *
53
- * @example
54
- *
55
- * const validator = new Validator([
56
- * { key: 'mobile', rules: ['required', 'mobile'] },
57
- * { key: 'code': rules: /^\d{6}$/, message: '请输入正确的验证码' },
58
- * { key: 'confirmPassword', rules: ['required', 'same:password'] }
59
- * ])
60
- * // 验证某一个字段
61
- * validator.validateKey().then(res => {})
62
- */
63
- constructor(schemas) {
64
- this.setSchemas(schemas);
65
- }
66
- addSchemas(schemas) {
67
- for (let schema of schemas) {
68
- this.addSchema(schema);
69
- }
70
- }
71
- addSchema(schema) {
72
- if (schema.key in this.rules) {
73
- this.rules[schema.key] = [...this.rules[schema.key], ...this._parseSchemaRules(schema)];
74
- }
75
- else {
76
- this.rules[schema.key] = this._parseSchemaRules(schema);
77
- }
78
- }
79
- setSchema(schema) {
80
- this.rules[schema.key] = this._parseSchemaRules(schema);
81
- }
82
- setSchemas(schemas) {
83
- this.rules = {};
84
- this.addSchemas(schemas);
85
- }
86
- /**
87
- * 进行数据验证
88
- * @param data 待验证的数据
89
- * @param all 是否全部验证, false - 只要验证错误一个则停止验证
90
- * @returns
91
- */
92
- async validate(data, all = false) {
93
- return new Promise((resolve, reject) => {
94
- const detail = {};
95
- let currentKey = undefined;
96
- let currentMessage = undefined;
97
- for (let key in this.rules) {
98
- let errMsg = this._validateRule(this.rules[key], data[key], data);
99
- if (errMsg !== "") {
100
- errMsg = errMsg.replace("%s", key);
101
- detail[key] = errMsg;
102
- currentKey = key;
103
- currentMessage = errMsg;
104
- if (all)
105
- break;
106
- }
107
- }
108
- if (currentKey == null) {
109
- resolve(true);
110
- }
111
- else {
112
- reject(new ValidateError(detail, currentKey, currentMessage));
113
- }
114
- });
115
- }
116
- /**
117
- * 只验证指定 key 的数据格式
118
- * @param key 指定待验证的 key
119
- * @param value 待验证的数据
120
- * @param data 原始数据,当验证确认密码时需要使用
121
- */
122
- async validateKey(key, value, data) {
123
- return new Promise((resolve, reject) => {
124
- let keyRules = this.rules[key];
125
- if (keyRules == null) {
126
- resolve({ key, value });
127
- return;
128
- }
129
- let errMsg = this._validateRule(keyRules, value, data);
130
- if (errMsg !== "") {
131
- errMsg = errMsg.replace("%s", key);
132
- reject(new ValidateError({ [key]: errMsg }, key, errMsg));
133
- }
134
- else {
135
- resolve({ key, value });
136
- }
137
- });
138
- }
139
- _validateRule(rules, value, data) {
140
- let errMsg = "";
141
- for (let rule of rules) {
142
- if (!rule)
143
- continue;
144
- // 如果数据为空,则判断是否是必填
145
- if (rule.rule === "required") {
146
- if (value == null || !ruleFns.pattern(ruleRegexs.required, value)) {
147
- errMsg = rule.message;
148
- }
149
- }
150
- else if (typeof rule.rule === "function") {
151
- if (!rule.rule(value)) {
152
- errMsg = rule.message;
153
- }
154
- }
155
- else if (rule.sameKey != null) {
156
- if (data != null) {
157
- if (!ruleFns.same(value, data[rule.sameKey])) {
158
- errMsg = rule.message;
159
- }
160
- }
161
- }
162
- else {
163
- if (rule && !ruleFns.pattern(rule.rule, value)) {
164
- errMsg = rule.message;
165
- }
166
- }
167
- if (errMsg !== "") {
168
- break;
169
- }
170
- }
171
- return errMsg;
172
- }
173
- _parseSchemaRules(schema) {
174
- // 解析规则
175
- let rules = [];
176
- let rule = schema.rules;
177
- if (schema.required === true) {
178
- rules.push(...this._parseStringRule("required", schema.message));
179
- }
180
- if (rule != null) {
181
- if (typeof rule === "string") {
182
- rules.push(...this._parseStringRule(rule, schema.message));
183
- }
184
- else if (rule instanceof Array) {
185
- for (let ruleItem of rule) {
186
- if (typeof ruleItem === "string") {
187
- rules.push(...this._parseStringRule(ruleItem, schema.message));
188
- }
189
- else if (ruleItem instanceof RegExp || typeof ruleItem === "function") {
190
- rules.push({
191
- rule: ruleItem,
192
- message: schema.message || defaultMsg,
193
- });
194
- }
195
- else {
196
- const emessage = ruleItem.message || schema.message || defaultMsg;
197
- if (typeof ruleItem.rule === "string") {
198
- rules.push(...this._parseStringRule(ruleItem.rule, emessage));
199
- }
200
- else {
201
- rules.push({
202
- rule: ruleItem.rule,
203
- message: emessage,
204
- });
205
- }
206
- }
207
- }
208
- }
209
- else {
210
- rules.push({ rule, message: defaultMsg });
211
- }
212
- }
213
- return rules;
214
- }
215
- _parseStringRule(rule, ruleErrMsg) {
216
- let rules = [];
217
- let trule = rule.split("|");
218
- for (let r of trule) {
219
- let message = ruleErrMsg;
220
- let rrule = null;
221
- let sameKey;
222
- if (rule === "required") {
223
- rrule = "required";
224
- message = message || ruleErrMsg || defaultMsgs.required;
225
- }
226
- else if (ruleRegexs.same.test(r)) {
227
- let m = r.match(ruleRegexs.same);
228
- if (m != null) {
229
- rrule = ruleRegexs.same;
230
- let m = r.match(ruleRegexs.same);
231
- if (m != null) {
232
- sameKey = m[1];
233
- }
234
- message = message || defaultMsgs["same"];
235
- }
236
- }
237
- else if (Object.hasOwn(ruleRegexs, r)) {
238
- rrule = ruleRegexs[r];
239
- message = message || defaultMsgs[r];
240
- }
241
- if (rrule) {
242
- rules.push({ rule: rrule, message: message, sameKey });
243
- }
244
- }
245
- return rules;
246
- }
247
- }
248
- export default Validator;
package/lib/web.d.ts DELETED
@@ -1,30 +0,0 @@
1
- /**
2
- * 解析 Form 表单中的 input 元素的数据为 JSON 格式,key: input-name;value: input-value
3
- * @param form {object} Form 节点对象
4
- */
5
- export declare const formJson: <T>(form: HTMLFormElement) => T;
6
- /**
7
- * 获取 url query 参数 (get 请求的参数)
8
- * @param search 如果是 React 应用就需要传递 useLocation().search
9
- * @returns
10
- */
11
- export declare function query(search?: string): {
12
- [index: string]: string;
13
- };
14
- /**
15
- * 函数节流 - 每隔单位时间,只执行一次
16
- * @param cb 待节流的函数
17
- * @param wait 间隔时间
18
- * @returns
19
- */
20
- export declare function throttle<R extends any[], T>(fn: (...args: R) => T, wait?: number): (...args: R) => void;
21
- /**
22
- * 函数防抖 - 当重复触发某一个行为(事件时),只执行最后一次触发
23
- * @param fn 防抖函数
24
- * @param interval 间隔时间段
25
- * @returns
26
- */
27
- export declare function debounce<R extends any[], T>(fn: (...args: R) => T, interval?: number): {
28
- (...args: R): void;
29
- cancel(): void;
30
- };