@yh-ui/utils 0.1.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/LICENSE +21 -0
- package/dist/common.cjs +150 -0
- package/dist/common.d.ts +62 -0
- package/dist/common.mjs +135 -0
- package/dist/dom.cjs +75 -0
- package/dist/dom.d.ts +43 -0
- package/dist/dom.mjs +61 -0
- package/dist/index.cjs +378 -0
- package/dist/index.d.cts +236 -0
- package/dist/index.d.mts +236 -0
- package/dist/index.d.ts +236 -0
- package/dist/index.mjs +329 -0
- package/dist/style.cjs +71 -0
- package/dist/style.d.ts +40 -0
- package/dist/style.mjs +60 -0
- package/dist/types.cjs +33 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.mjs +17 -0
- package/dist/vue.cjs +65 -0
- package/dist/vue.d.ts +33 -0
- package/dist/vue.mjs +55 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-present YH-UI Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/common.cjs
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.toArray = exports.throttle = exports.sleep = exports.set = exports.retry = exports.kebabCase = exports.get = exports.generateId = exports.deepMerge = exports.deepClone = exports.debounce = exports.capitalize = exports.camelCase = void 0;
|
|
7
|
+
let idCounter = 0;
|
|
8
|
+
const generateId = (prefix = "yh") => {
|
|
9
|
+
return `${prefix}-${Date.now()}-${++idCounter}`;
|
|
10
|
+
};
|
|
11
|
+
exports.generateId = generateId;
|
|
12
|
+
const debounce = (fn, delay) => {
|
|
13
|
+
let timer = null;
|
|
14
|
+
const debounced = (...args) => {
|
|
15
|
+
if (timer) clearTimeout(timer);
|
|
16
|
+
timer = setTimeout(() => {
|
|
17
|
+
fn(...args);
|
|
18
|
+
timer = null;
|
|
19
|
+
}, delay);
|
|
20
|
+
};
|
|
21
|
+
debounced.cancel = () => {
|
|
22
|
+
if (timer) {
|
|
23
|
+
clearTimeout(timer);
|
|
24
|
+
timer = null;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
return debounced;
|
|
28
|
+
};
|
|
29
|
+
exports.debounce = debounce;
|
|
30
|
+
const throttle = (fn, delay) => {
|
|
31
|
+
let lastTime = 0;
|
|
32
|
+
let timer = null;
|
|
33
|
+
const throttled = (...args) => {
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
const remaining = delay - (now - lastTime);
|
|
36
|
+
if (remaining <= 0) {
|
|
37
|
+
if (timer) {
|
|
38
|
+
clearTimeout(timer);
|
|
39
|
+
timer = null;
|
|
40
|
+
}
|
|
41
|
+
fn(...args);
|
|
42
|
+
lastTime = now;
|
|
43
|
+
} else if (!timer) {
|
|
44
|
+
timer = setTimeout(() => {
|
|
45
|
+
fn(...args);
|
|
46
|
+
lastTime = Date.now();
|
|
47
|
+
timer = null;
|
|
48
|
+
}, remaining);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
throttled.cancel = () => {
|
|
52
|
+
if (timer) {
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
timer = null;
|
|
55
|
+
}
|
|
56
|
+
lastTime = 0;
|
|
57
|
+
};
|
|
58
|
+
return throttled;
|
|
59
|
+
};
|
|
60
|
+
exports.throttle = throttle;
|
|
61
|
+
const deepClone = obj => {
|
|
62
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
63
|
+
if (obj instanceof Date) return new Date(obj.getTime());
|
|
64
|
+
if (obj instanceof Array) {
|
|
65
|
+
return obj.map(item => deepClone(item));
|
|
66
|
+
}
|
|
67
|
+
if (obj instanceof Object) {
|
|
68
|
+
const copy = {};
|
|
69
|
+
Object.keys(obj).forEach(key => {
|
|
70
|
+
copy[key] = deepClone(obj[key]);
|
|
71
|
+
});
|
|
72
|
+
return copy;
|
|
73
|
+
}
|
|
74
|
+
return obj;
|
|
75
|
+
};
|
|
76
|
+
exports.deepClone = deepClone;
|
|
77
|
+
const deepMerge = (target, ...sources) => {
|
|
78
|
+
if (!sources.length) return target;
|
|
79
|
+
const source = sources.shift();
|
|
80
|
+
if (source === void 0) return target;
|
|
81
|
+
for (const key in source) {
|
|
82
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
83
|
+
const targetValue = target[key];
|
|
84
|
+
const sourceValue = source[key];
|
|
85
|
+
if (typeof targetValue === "object" && targetValue !== null && typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(targetValue) && !Array.isArray(sourceValue)) {
|
|
86
|
+
target[key] = deepMerge({
|
|
87
|
+
...targetValue
|
|
88
|
+
}, sourceValue);
|
|
89
|
+
} else {
|
|
90
|
+
target[key] = sourceValue;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return deepMerge(target, ...sources);
|
|
95
|
+
};
|
|
96
|
+
exports.deepMerge = deepMerge;
|
|
97
|
+
const toArray = val => {
|
|
98
|
+
return Array.isArray(val) ? val : [val];
|
|
99
|
+
};
|
|
100
|
+
exports.toArray = toArray;
|
|
101
|
+
const capitalize = str => {
|
|
102
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
103
|
+
};
|
|
104
|
+
exports.capitalize = capitalize;
|
|
105
|
+
const kebabCase = str => {
|
|
106
|
+
return str.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
|
|
107
|
+
};
|
|
108
|
+
exports.kebabCase = kebabCase;
|
|
109
|
+
const camelCase = str => {
|
|
110
|
+
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
111
|
+
};
|
|
112
|
+
exports.camelCase = camelCase;
|
|
113
|
+
const sleep = ms => {
|
|
114
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
115
|
+
};
|
|
116
|
+
exports.sleep = sleep;
|
|
117
|
+
const get = (obj, path, defaultValue) => {
|
|
118
|
+
const result = path.split(".").reduce((res, key) => {
|
|
119
|
+
if (res !== null && res !== void 0 && typeof res === "object") {
|
|
120
|
+
return res[key];
|
|
121
|
+
}
|
|
122
|
+
return void 0;
|
|
123
|
+
}, obj);
|
|
124
|
+
return result === void 0 ? defaultValue : result;
|
|
125
|
+
};
|
|
126
|
+
exports.get = get;
|
|
127
|
+
const set = (obj, path, value) => {
|
|
128
|
+
if (Object(obj) !== obj) return obj;
|
|
129
|
+
const keys = path.split(".");
|
|
130
|
+
const lastKey = keys.pop();
|
|
131
|
+
const node = keys.reduce((res, key) => {
|
|
132
|
+
if (res[key] === void 0) res[key] = {};
|
|
133
|
+
return res[key];
|
|
134
|
+
}, obj);
|
|
135
|
+
node[lastKey] = value;
|
|
136
|
+
return obj;
|
|
137
|
+
};
|
|
138
|
+
exports.set = set;
|
|
139
|
+
const retry = async (fn, retries = 3, delay = 1e3) => {
|
|
140
|
+
try {
|
|
141
|
+
return await fn();
|
|
142
|
+
} catch (error) {
|
|
143
|
+
if (retries > 0) {
|
|
144
|
+
await sleep(delay);
|
|
145
|
+
return retry(fn, retries - 1, delay);
|
|
146
|
+
}
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
exports.retry = retry;
|
package/dist/common.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common utilities
|
|
3
|
+
* @description 通用工具函数库,严格类型化
|
|
4
|
+
*/
|
|
5
|
+
export declare const generateId: (prefix?: string) => string;
|
|
6
|
+
/**
|
|
7
|
+
* 函数类型定义
|
|
8
|
+
*/
|
|
9
|
+
type AnyFunction = (...args: unknown[]) => unknown;
|
|
10
|
+
/**
|
|
11
|
+
* 防抖函数
|
|
12
|
+
*/
|
|
13
|
+
export declare const debounce: <T extends AnyFunction>(fn: T, delay: number) => ((...args: Parameters<T>) => void) & {
|
|
14
|
+
cancel: () => void;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* 节流函数
|
|
18
|
+
*/
|
|
19
|
+
export declare const throttle: <T extends AnyFunction>(fn: T, delay: number) => ((...args: Parameters<T>) => void) & {
|
|
20
|
+
cancel: () => void;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* 深拷贝
|
|
24
|
+
*/
|
|
25
|
+
export declare const deepClone: <T>(obj: T) => T;
|
|
26
|
+
/**
|
|
27
|
+
* 深度合并对象
|
|
28
|
+
*/
|
|
29
|
+
export declare const deepMerge: <T extends Record<string, unknown>>(target: T, ...sources: Partial<T>[]) => T;
|
|
30
|
+
/**
|
|
31
|
+
* 将值转换为数组
|
|
32
|
+
*/
|
|
33
|
+
export declare const toArray: <T>(val: T | T[]) => T[];
|
|
34
|
+
/**
|
|
35
|
+
* 首字母大写
|
|
36
|
+
*/
|
|
37
|
+
export declare const capitalize: (str: string) => string;
|
|
38
|
+
/**
|
|
39
|
+
* 转换为 kebab-case
|
|
40
|
+
*/
|
|
41
|
+
export declare const kebabCase: (str: string) => string;
|
|
42
|
+
/**
|
|
43
|
+
* 转换为 camelCase
|
|
44
|
+
*/
|
|
45
|
+
export declare const camelCase: (str: string) => string;
|
|
46
|
+
/**
|
|
47
|
+
* 休眠函数
|
|
48
|
+
*/
|
|
49
|
+
export declare const sleep: (ms: number) => Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* 访问对象嵌套路径的值
|
|
52
|
+
*/
|
|
53
|
+
export declare const get: <T = unknown>(obj: Record<string, unknown>, path: string, defaultValue?: T) => T;
|
|
54
|
+
/**
|
|
55
|
+
* 设置对象嵌套路径的值
|
|
56
|
+
*/
|
|
57
|
+
export declare const set: <T extends Record<string, unknown>>(obj: T, path: string, value: unknown) => T;
|
|
58
|
+
/**
|
|
59
|
+
* 异步函数重试
|
|
60
|
+
*/
|
|
61
|
+
export declare const retry: <T>(fn: () => Promise<T>, retries?: number, delay?: number) => Promise<T>;
|
|
62
|
+
export {};
|
package/dist/common.mjs
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
let idCounter = 0;
|
|
2
|
+
export const generateId = (prefix = "yh") => {
|
|
3
|
+
return `${prefix}-${Date.now()}-${++idCounter}`;
|
|
4
|
+
};
|
|
5
|
+
export const debounce = (fn, delay) => {
|
|
6
|
+
let timer = null;
|
|
7
|
+
const debounced = (...args) => {
|
|
8
|
+
if (timer) clearTimeout(timer);
|
|
9
|
+
timer = setTimeout(() => {
|
|
10
|
+
fn(...args);
|
|
11
|
+
timer = null;
|
|
12
|
+
}, delay);
|
|
13
|
+
};
|
|
14
|
+
debounced.cancel = () => {
|
|
15
|
+
if (timer) {
|
|
16
|
+
clearTimeout(timer);
|
|
17
|
+
timer = null;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
return debounced;
|
|
21
|
+
};
|
|
22
|
+
export const throttle = (fn, delay) => {
|
|
23
|
+
let lastTime = 0;
|
|
24
|
+
let timer = null;
|
|
25
|
+
const throttled = (...args) => {
|
|
26
|
+
const now = Date.now();
|
|
27
|
+
const remaining = delay - (now - lastTime);
|
|
28
|
+
if (remaining <= 0) {
|
|
29
|
+
if (timer) {
|
|
30
|
+
clearTimeout(timer);
|
|
31
|
+
timer = null;
|
|
32
|
+
}
|
|
33
|
+
fn(...args);
|
|
34
|
+
lastTime = now;
|
|
35
|
+
} else if (!timer) {
|
|
36
|
+
timer = setTimeout(() => {
|
|
37
|
+
fn(...args);
|
|
38
|
+
lastTime = Date.now();
|
|
39
|
+
timer = null;
|
|
40
|
+
}, remaining);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
throttled.cancel = () => {
|
|
44
|
+
if (timer) {
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
timer = null;
|
|
47
|
+
}
|
|
48
|
+
lastTime = 0;
|
|
49
|
+
};
|
|
50
|
+
return throttled;
|
|
51
|
+
};
|
|
52
|
+
export const deepClone = (obj) => {
|
|
53
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
54
|
+
if (obj instanceof Date) return new Date(obj.getTime());
|
|
55
|
+
if (obj instanceof Array) {
|
|
56
|
+
return obj.map((item) => deepClone(item));
|
|
57
|
+
}
|
|
58
|
+
if (obj instanceof Object) {
|
|
59
|
+
const copy = {};
|
|
60
|
+
Object.keys(obj).forEach((key) => {
|
|
61
|
+
copy[key] = deepClone(obj[key]);
|
|
62
|
+
});
|
|
63
|
+
return copy;
|
|
64
|
+
}
|
|
65
|
+
return obj;
|
|
66
|
+
};
|
|
67
|
+
export const deepMerge = (target, ...sources) => {
|
|
68
|
+
if (!sources.length) return target;
|
|
69
|
+
const source = sources.shift();
|
|
70
|
+
if (source === void 0) return target;
|
|
71
|
+
for (const key in source) {
|
|
72
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
73
|
+
const targetValue = target[key];
|
|
74
|
+
const sourceValue = source[key];
|
|
75
|
+
if (typeof targetValue === "object" && targetValue !== null && typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(targetValue) && !Array.isArray(sourceValue)) {
|
|
76
|
+
target[key] = deepMerge(
|
|
77
|
+
{ ...targetValue },
|
|
78
|
+
sourceValue
|
|
79
|
+
);
|
|
80
|
+
} else {
|
|
81
|
+
target[key] = sourceValue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return deepMerge(target, ...sources);
|
|
86
|
+
};
|
|
87
|
+
export const toArray = (val) => {
|
|
88
|
+
return Array.isArray(val) ? val : [val];
|
|
89
|
+
};
|
|
90
|
+
export const capitalize = (str) => {
|
|
91
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
92
|
+
};
|
|
93
|
+
export const kebabCase = (str) => {
|
|
94
|
+
return str.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
|
|
95
|
+
};
|
|
96
|
+
export const camelCase = (str) => {
|
|
97
|
+
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
98
|
+
};
|
|
99
|
+
export const sleep = (ms) => {
|
|
100
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
101
|
+
};
|
|
102
|
+
export const get = (obj, path, defaultValue) => {
|
|
103
|
+
const result = path.split(".").reduce((res, key) => {
|
|
104
|
+
if (res !== null && res !== void 0 && typeof res === "object") {
|
|
105
|
+
return res[key];
|
|
106
|
+
}
|
|
107
|
+
return void 0;
|
|
108
|
+
}, obj);
|
|
109
|
+
return result === void 0 ? defaultValue : result;
|
|
110
|
+
};
|
|
111
|
+
export const set = (obj, path, value) => {
|
|
112
|
+
if (Object(obj) !== obj) return obj;
|
|
113
|
+
const keys = path.split(".");
|
|
114
|
+
const lastKey = keys.pop();
|
|
115
|
+
const node = keys.reduce(
|
|
116
|
+
(res, key) => {
|
|
117
|
+
if (res[key] === void 0) res[key] = {};
|
|
118
|
+
return res[key];
|
|
119
|
+
},
|
|
120
|
+
obj
|
|
121
|
+
);
|
|
122
|
+
node[lastKey] = value;
|
|
123
|
+
return obj;
|
|
124
|
+
};
|
|
125
|
+
export const retry = async (fn, retries = 3, delay = 1e3) => {
|
|
126
|
+
try {
|
|
127
|
+
return await fn();
|
|
128
|
+
} catch (error) {
|
|
129
|
+
if (retries > 0) {
|
|
130
|
+
await sleep(delay);
|
|
131
|
+
return retry(fn, retries - 1, delay);
|
|
132
|
+
}
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
};
|
package/dist/dom.cjs
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.toggleClass = exports.setStyle = exports.removeClass = exports.isServer = exports.isInViewport = exports.isClient = exports.hasClass = exports.getStyle = exports.getScrollContainer = exports.addClass = void 0;
|
|
7
|
+
const isClient = exports.isClient = typeof window !== "undefined";
|
|
8
|
+
const isServer = exports.isServer = !isClient;
|
|
9
|
+
const getStyle = (element, styleName) => {
|
|
10
|
+
if (!isClient || !element || !styleName) return "";
|
|
11
|
+
try {
|
|
12
|
+
const style = element.style[styleName];
|
|
13
|
+
if (style) return style;
|
|
14
|
+
const computed = document.defaultView?.getComputedStyle(element, "");
|
|
15
|
+
return computed ? computed[styleName] : "";
|
|
16
|
+
} catch {
|
|
17
|
+
return element.style[styleName];
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
exports.getStyle = getStyle;
|
|
21
|
+
const setStyle = (element, styleName, value) => {
|
|
22
|
+
if (!element || !styleName) return;
|
|
23
|
+
if (typeof styleName === "object") {
|
|
24
|
+
Object.entries(styleName).forEach(([key, val]) => {
|
|
25
|
+
setStyle(element, key, val);
|
|
26
|
+
});
|
|
27
|
+
} else {
|
|
28
|
+
;
|
|
29
|
+
element.style[styleName] = value ?? "";
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
exports.setStyle = setStyle;
|
|
33
|
+
const hasClass = (el, cls) => {
|
|
34
|
+
if (!el || !cls) return false;
|
|
35
|
+
if (cls.includes(" ")) throw new Error("className should not contain space.");
|
|
36
|
+
return el.classList.contains(cls);
|
|
37
|
+
};
|
|
38
|
+
exports.hasClass = hasClass;
|
|
39
|
+
const addClass = (el, cls) => {
|
|
40
|
+
if (!el || !cls.trim()) return;
|
|
41
|
+
el.classList.add(...cls.split(" ").filter(Boolean));
|
|
42
|
+
};
|
|
43
|
+
exports.addClass = addClass;
|
|
44
|
+
const removeClass = (el, cls) => {
|
|
45
|
+
if (!el || !cls.trim()) return;
|
|
46
|
+
el.classList.remove(...cls.split(" ").filter(Boolean));
|
|
47
|
+
};
|
|
48
|
+
exports.removeClass = removeClass;
|
|
49
|
+
const toggleClass = (el, cls, force) => {
|
|
50
|
+
if (!el || !cls.trim()) return;
|
|
51
|
+
el.classList.toggle(cls, force);
|
|
52
|
+
};
|
|
53
|
+
exports.toggleClass = toggleClass;
|
|
54
|
+
const getScrollContainer = (el, isVertical) => {
|
|
55
|
+
if (!isClient) return void 0;
|
|
56
|
+
let parent = el;
|
|
57
|
+
while (parent) {
|
|
58
|
+
if ([document.documentElement, document.body].includes(parent)) {
|
|
59
|
+
return window;
|
|
60
|
+
}
|
|
61
|
+
const overflow = isVertical ? getStyle(parent, "overflowY") : getStyle(parent, "overflow");
|
|
62
|
+
if (/(scroll|auto)/.test(overflow)) {
|
|
63
|
+
return parent;
|
|
64
|
+
}
|
|
65
|
+
parent = parent.parentNode;
|
|
66
|
+
}
|
|
67
|
+
return void 0;
|
|
68
|
+
};
|
|
69
|
+
exports.getScrollContainer = getScrollContainer;
|
|
70
|
+
const isInViewport = el => {
|
|
71
|
+
if (!isClient || !el) return false;
|
|
72
|
+
const rect = el.getBoundingClientRect();
|
|
73
|
+
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
|
|
74
|
+
};
|
|
75
|
+
exports.isInViewport = isInViewport;
|
package/dist/dom.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 判断是否在浏览器环境
|
|
6
|
+
*/
|
|
7
|
+
export declare const isClient: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* 判断是否在服务端环境
|
|
10
|
+
*/
|
|
11
|
+
export declare const isServer: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* 获取元素的样式
|
|
14
|
+
*/
|
|
15
|
+
export declare const getStyle: (element: HTMLElement, styleName: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* 设置元素的样式
|
|
18
|
+
*/
|
|
19
|
+
export declare const setStyle: (element: HTMLElement, styleName: string | Record<string, string>, value?: string) => void;
|
|
20
|
+
/**
|
|
21
|
+
* 检查元素是否包含某个类名
|
|
22
|
+
*/
|
|
23
|
+
export declare const hasClass: (el: HTMLElement, cls: string) => boolean;
|
|
24
|
+
/**
|
|
25
|
+
* 添加类名
|
|
26
|
+
*/
|
|
27
|
+
export declare const addClass: (el: HTMLElement, cls: string) => void;
|
|
28
|
+
/**
|
|
29
|
+
* 移除类名
|
|
30
|
+
*/
|
|
31
|
+
export declare const removeClass: (el: HTMLElement, cls: string) => void;
|
|
32
|
+
/**
|
|
33
|
+
* 切换类名
|
|
34
|
+
*/
|
|
35
|
+
export declare const toggleClass: (el: HTMLElement, cls: string, force?: boolean) => void;
|
|
36
|
+
/**
|
|
37
|
+
* 获取滚动容器
|
|
38
|
+
*/
|
|
39
|
+
export declare const getScrollContainer: (el: HTMLElement, isVertical?: boolean) => HTMLElement | Window | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* 检查元素是否在视口中
|
|
42
|
+
*/
|
|
43
|
+
export declare const isInViewport: (el: HTMLElement) => boolean;
|
package/dist/dom.mjs
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export const isClient = typeof window !== "undefined";
|
|
2
|
+
export const isServer = !isClient;
|
|
3
|
+
export const getStyle = (element, styleName) => {
|
|
4
|
+
if (!isClient || !element || !styleName) return "";
|
|
5
|
+
try {
|
|
6
|
+
const style = element.style[styleName];
|
|
7
|
+
if (style) return style;
|
|
8
|
+
const computed = document.defaultView?.getComputedStyle(element, "");
|
|
9
|
+
return computed ? computed[styleName] : "";
|
|
10
|
+
} catch {
|
|
11
|
+
return element.style[styleName];
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
export const setStyle = (element, styleName, value) => {
|
|
15
|
+
if (!element || !styleName) return;
|
|
16
|
+
if (typeof styleName === "object") {
|
|
17
|
+
Object.entries(styleName).forEach(([key, val]) => {
|
|
18
|
+
setStyle(element, key, val);
|
|
19
|
+
});
|
|
20
|
+
} else {
|
|
21
|
+
;
|
|
22
|
+
element.style[styleName] = value ?? "";
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
export const hasClass = (el, cls) => {
|
|
26
|
+
if (!el || !cls) return false;
|
|
27
|
+
if (cls.includes(" ")) throw new Error("className should not contain space.");
|
|
28
|
+
return el.classList.contains(cls);
|
|
29
|
+
};
|
|
30
|
+
export const addClass = (el, cls) => {
|
|
31
|
+
if (!el || !cls.trim()) return;
|
|
32
|
+
el.classList.add(...cls.split(" ").filter(Boolean));
|
|
33
|
+
};
|
|
34
|
+
export const removeClass = (el, cls) => {
|
|
35
|
+
if (!el || !cls.trim()) return;
|
|
36
|
+
el.classList.remove(...cls.split(" ").filter(Boolean));
|
|
37
|
+
};
|
|
38
|
+
export const toggleClass = (el, cls, force) => {
|
|
39
|
+
if (!el || !cls.trim()) return;
|
|
40
|
+
el.classList.toggle(cls, force);
|
|
41
|
+
};
|
|
42
|
+
export const getScrollContainer = (el, isVertical) => {
|
|
43
|
+
if (!isClient) return void 0;
|
|
44
|
+
let parent = el;
|
|
45
|
+
while (parent) {
|
|
46
|
+
if ([document.documentElement, document.body].includes(parent)) {
|
|
47
|
+
return window;
|
|
48
|
+
}
|
|
49
|
+
const overflow = isVertical ? getStyle(parent, "overflowY") : getStyle(parent, "overflow");
|
|
50
|
+
if (/(scroll|auto)/.test(overflow)) {
|
|
51
|
+
return parent;
|
|
52
|
+
}
|
|
53
|
+
parent = parent.parentNode;
|
|
54
|
+
}
|
|
55
|
+
return void 0;
|
|
56
|
+
};
|
|
57
|
+
export const isInViewport = (el) => {
|
|
58
|
+
if (!isClient || !el) return false;
|
|
59
|
+
const rect = el.getBoundingClientRect();
|
|
60
|
+
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
|
|
61
|
+
};
|