@longmo-utils/browser 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/dist/index.d.mts +123 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +41 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
//#region src/storage/index.d.ts
|
|
2
|
+
declare function getLocalStorage<T = any>(key: string): T | null;
|
|
3
|
+
declare function setLocalStorage<T>(key: string, value: T): boolean;
|
|
4
|
+
declare function removeLocalStorage(key: string): boolean;
|
|
5
|
+
declare function clearLocalStorage(): boolean;
|
|
6
|
+
declare function getSessionStorage<T = any>(key: string): T | null;
|
|
7
|
+
declare function setSessionStorage<T>(key: string, value: T): boolean;
|
|
8
|
+
declare function removeSessionStorage(key: string): boolean;
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/dom/selector.d.ts
|
|
11
|
+
declare function $(selector: string): HTMLElement | null;
|
|
12
|
+
declare function $$(selector: string): HTMLElement[];
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/dom/creation.d.ts
|
|
15
|
+
declare function createElement<K extends keyof HTMLElementTagNameMap>(tag: K, attributes?: Record<string, string>, children?: (string | Node)[]): HTMLElementTagNameMap[K];
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/dom/class.d.ts
|
|
18
|
+
declare function addClass(element: HTMLElement, ...classNames: string[]): void;
|
|
19
|
+
declare function removeClass(element: HTMLElement, ...classNames: string[]): void;
|
|
20
|
+
declare function toggleClass(element: HTMLElement, className: string): boolean;
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/dom/style.d.ts
|
|
23
|
+
declare function getStyle(element: HTMLElement, property: string): string;
|
|
24
|
+
declare function setStyle(element: HTMLElement, styles: Record<string, string>): void;
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/dom/viewport.d.ts
|
|
27
|
+
declare function isInViewport(element: HTMLElement): boolean;
|
|
28
|
+
declare function scrollIntoView(element: HTMLElement, options?: ScrollIntoViewOptions): void;
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/dom/event.d.ts
|
|
31
|
+
declare function on(element: HTMLElement | Document | Window, event: string, handler: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
|
32
|
+
declare function off(element: HTMLElement | Document | Window, event: string, handler: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
|
33
|
+
declare function once(element: HTMLElement | Document | Window, event: string, handler: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/clipboard/index.d.ts
|
|
36
|
+
interface optionsType {
|
|
37
|
+
target: HTMLElement;
|
|
38
|
+
}
|
|
39
|
+
declare function copyToClipboard(text: string, options?: optionsType): boolean;
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/cache/storage-manager.d.ts
|
|
42
|
+
type StorageType = 'localStorage' | 'sessionStorage';
|
|
43
|
+
interface StorageManagerOptions {
|
|
44
|
+
prefix?: string;
|
|
45
|
+
storageType?: StorageType;
|
|
46
|
+
}
|
|
47
|
+
declare class StorageManager {
|
|
48
|
+
private prefix;
|
|
49
|
+
private storage;
|
|
50
|
+
constructor({
|
|
51
|
+
prefix,
|
|
52
|
+
storageType
|
|
53
|
+
}?: StorageManagerOptions);
|
|
54
|
+
clear(): void;
|
|
55
|
+
clearExpiredItems(): void;
|
|
56
|
+
getItem<T>(key: string, defaultValue?: null | T): null | T;
|
|
57
|
+
removeItem(key: string): void;
|
|
58
|
+
setItem<T>(key: string, value: T, ttl?: number): void;
|
|
59
|
+
private getFullKey;
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/window/types.d.ts
|
|
63
|
+
interface OpenWindowOptions {
|
|
64
|
+
noopener?: boolean;
|
|
65
|
+
noreferrer?: boolean;
|
|
66
|
+
target?: '_blank' | '_parent' | '_self' | '_top' | string;
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/window/openWindow.d.ts
|
|
70
|
+
declare function openWindow(url: string, options?: OpenWindowOptions): void;
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region src/window/openRouteInNewWindow.d.ts
|
|
73
|
+
declare function openRouteInNewWindow(path: string): void;
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/download/types.d.ts
|
|
76
|
+
interface DownloadOptions<T = string> {
|
|
77
|
+
fileName?: string;
|
|
78
|
+
source: T;
|
|
79
|
+
target?: string;
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/download/constants.d.ts
|
|
83
|
+
declare const DEFAULT_FILENAME = "downloaded_file";
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/download/downloadFileFromUrl.d.ts
|
|
86
|
+
declare function downloadFileFromUrl({
|
|
87
|
+
fileName,
|
|
88
|
+
source,
|
|
89
|
+
target
|
|
90
|
+
}: DownloadOptions): Promise<void>;
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/download/downloadFileFromBase64.d.ts
|
|
93
|
+
declare function downloadFileFromBase64({
|
|
94
|
+
fileName,
|
|
95
|
+
source
|
|
96
|
+
}: DownloadOptions): void;
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/download/downloadFileFromImageUrl.d.ts
|
|
99
|
+
declare function downloadFileFromImageUrl({
|
|
100
|
+
fileName,
|
|
101
|
+
source
|
|
102
|
+
}: DownloadOptions): Promise<void>;
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/download/downloadFileFromBlob.d.ts
|
|
105
|
+
declare function downloadFileFromBlob({
|
|
106
|
+
fileName,
|
|
107
|
+
source
|
|
108
|
+
}: DownloadOptions<Blob>): void;
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/download/downloadFileFromBlobPart.d.ts
|
|
111
|
+
declare function downloadFileFromBlobPart({
|
|
112
|
+
fileName,
|
|
113
|
+
source
|
|
114
|
+
}: DownloadOptions<BlobPart>): void;
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/download/urlToBase64.d.ts
|
|
117
|
+
declare function urlToBase64(url: string, mineType?: string): Promise<string>;
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region src/download/triggerDownload.d.ts
|
|
120
|
+
declare function triggerDownload(href: string, fileName: string | undefined, revokeDelay?: number): void;
|
|
121
|
+
//#endregion
|
|
122
|
+
export { $, $$, DEFAULT_FILENAME, DownloadOptions, OpenWindowOptions, StorageManager, addClass, clearLocalStorage, copyToClipboard, createElement, downloadFileFromBase64, downloadFileFromBlob, downloadFileFromBlobPart, downloadFileFromImageUrl, downloadFileFromUrl, getLocalStorage, getSessionStorage, getStyle, isInViewport, off, on, once, openRouteInNewWindow, openWindow, removeClass, removeLocalStorage, removeSessionStorage, scrollIntoView, setLocalStorage, setSessionStorage, setStyle, toggleClass, triggerDownload, urlToBase64 };
|
|
123
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/storage/index.ts","../src/dom/selector.ts","../src/dom/creation.ts","../src/dom/class.ts","../src/dom/style.ts","../src/dom/viewport.ts","../src/dom/event.ts","../src/clipboard/index.ts","../src/cache/storage-manager.ts","../src/window/types.ts","../src/window/openWindow.ts","../src/window/openRouteInNewWindow.ts","../src/download/types.ts","../src/download/constants.ts","../src/download/downloadFileFromUrl.ts","../src/download/downloadFileFromBase64.ts","../src/download/downloadFileFromImageUrl.ts","../src/download/downloadFileFromBlob.ts","../src/download/downloadFileFromBlobPart.ts","../src/download/urlToBase64.ts","../src/download/triggerDownload.ts"],"mappings":"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"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"copy-text-to-clipboard";function t(e){try{let t=window.localStorage.getItem(e);return t?JSON.parse(t):null}catch(e){return console.error(`Error reading from localStorage: ${e}`),null}}function n(e,t){try{return window.localStorage.setItem(e,JSON.stringify(t)),!0}catch(e){return console.error(`Error writing to localStorage: ${e}`),!1}}function r(e){try{return window.localStorage.removeItem(e),!0}catch(e){return console.error(`Error removing from localStorage: ${e}`),!1}}function i(){try{return window.localStorage.clear(),!0}catch(e){return console.error(`Error clearing localStorage: ${e}`),!1}}function a(e){try{let t=window.sessionStorage.getItem(e);return t?JSON.parse(t):null}catch(e){return console.error(`Error reading from sessionStorage: ${e}`),null}}function o(e,t){try{return window.sessionStorage.setItem(e,JSON.stringify(t)),!0}catch(e){return console.error(`Error writing to sessionStorage: ${e}`),!1}}function s(e){try{return window.sessionStorage.removeItem(e),!0}catch(e){return console.error(`Error removing from sessionStorage: ${e}`),!1}}function c(e){return document.querySelector(e)}function l(e){return Array.from(document.querySelectorAll(e))}function u(e,t,n){let r=document.createElement(e);if(t)for(let[e,n]of Object.entries(t))r.setAttribute(e,n);if(n)for(let e of n)typeof e==`string`?r.appendChild(document.createTextNode(e)):r.appendChild(e);return r}function d(e,...t){e.classList.add(...t)}function f(e,...t){e.classList.remove(...t)}function p(e,t){return e.classList.toggle(t)}function m(e,t){return window.getComputedStyle(e).getPropertyValue(t)}function h(e,t){for(let[n,r]of Object.entries(t))e.style.setProperty(n,r)}function g(e){let t=e.getBoundingClientRect();return t.top>=0&&t.left>=0&&t.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&t.right<=(window.innerWidth||document.documentElement.clientWidth)}function _(e,t){e.scrollIntoView({behavior:`smooth`,...t})}function v(e,t,n,r=!1){e&&t&&n&&e.addEventListener(t,n,r)}function y(e,t,n,r=!1){e&&t&&n&&e.removeEventListener(t,n,r)}function b(e,t,n,r=!1){if(!e||!t||!n)return;let i=a=>{typeof n==`function`?n(a):n.handleEvent&&n.handleEvent(a),e.removeEventListener(t,i,r)};e.addEventListener(t,i,r)}function x(t,n){return e(t,n)}var S=class{constructor({prefix:e=``,storageType:t=`localStorage`}={}){this.prefix=e,this.storage=t===`localStorage`?window.localStorage:window.sessionStorage}clear(){let e=[];for(let t=0;t<this.storage.length;t++){let n=this.storage.key(t);n&&n.startsWith(this.prefix)&&e.push(n)}e.forEach(e=>this.storage.removeItem(e))}clearExpiredItems(){for(let e=0;e<this.storage.length;e++){let t=this.storage.key(e);if(t&&t.startsWith(this.prefix)){let e=t.replace(this.prefix,``);this.getItem(e)}}}getItem(e,t=null){let n=this.getFullKey(e),r=this.storage.getItem(n);if(!r)return t;try{let e=JSON.parse(r);return e.expiry&&Date.now()>e.expiry?(this.storage.removeItem(n),t):e.value}catch(e){return console.error(`Error parsing item with key "${n}":`,e),this.storage.removeItem(n),t}}removeItem(e){let t=this.getFullKey(e);this.storage.removeItem(t)}setItem(e,t,n){let r=this.getFullKey(e),i={expiry:n?Date.now()+n:void 0,value:t};try{this.storage.setItem(r,JSON.stringify(i))}catch(e){console.error(`Error setting item with key "${r}":`,e)}}getFullKey(e){return`${this.prefix}-${e}`}};function C(e,t={}){let{noopener:n=!0,noreferrer:r=!0,target:i=`_blank`}=t,a=[n&&`noopener=yes`,r&&`noreferrer=yes`].filter(Boolean).join(`,`);window.open(e,i,a)}function w(e){let{hash:t,origin:n}=location,r=e.startsWith(`/`)?e:`/${e}`;C(`${n}${t&&!r.startsWith(`/#`)?`/#`:``}${r}`,{target:`_blank`})}const T=`downloaded_file`;function E(e,t,n=100){let r=t||`downloaded_file`,i=document.createElement(`a`);i.href=e,i.download=r,i.style.display=`none`,i.download===void 0&&i.setAttribute(`target`,`_blank`),document.body.append(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(e),n)}function D(e,t){return t||e.slice(e.lastIndexOf(`/`)+1)||T}async function O({fileName:e,source:t,target:n=`_blank`}){if(!t||typeof t!=`string`)throw Error(`Invalid URL.`);let r=window.navigator.userAgent.toLowerCase().includes(`chrome`),i=window.navigator.userAgent.toLowerCase().includes(`safari`);if(/iP/.test(window.navigator.userAgent)){console.error(`Your browser does not support download!`);return}if(r||i){E(t,D(t,e));return}t.includes(`?`)||(t+=`?download`),C(t,{target:n})}function k({fileName:e,source:t}){if(!t||typeof t!=`string`)throw Error(`Invalid Base64 data.`);E(t,e||T)}function A(e,t){return new Promise((n,r)=>{let i=document.createElement(`CANVAS`),a=i?.getContext(`2d`),o=new Image;o.crossOrigin=``,o.addEventListener(`load`,()=>{if(!i||!a)return r(Error(`Failed to create canvas.`));i.height=o.height,i.width=o.width,a.drawImage(o,0,0);let e=i.toDataURL(t||`image/png`);i=null,n(e)}),o.src=e})}async function j({fileName:e,source:t}){k({fileName:e,source:await A(t)})}function M({fileName:e=T,source:t}){if(!(t instanceof Blob))throw TypeError(`Invalid Blob data.`);E(URL.createObjectURL(t),e)}function N({fileName:e=T,source:t}){let n=t instanceof Blob?t:new Blob([t],{type:`application/octet-stream`});E(URL.createObjectURL(n),e)}export{c as $,l as $$,T as DEFAULT_FILENAME,S as StorageManager,d as addClass,i as clearLocalStorage,x as copyToClipboard,u as createElement,k as downloadFileFromBase64,M as downloadFileFromBlob,N as downloadFileFromBlobPart,j as downloadFileFromImageUrl,O as downloadFileFromUrl,t as getLocalStorage,a as getSessionStorage,m as getStyle,g as isInViewport,y as off,v as on,b as once,w as openRouteInNewWindow,C as openWindow,f as removeClass,r as removeLocalStorage,s as removeSessionStorage,_ as scrollIntoView,n as setLocalStorage,o as setSessionStorage,h as setStyle,p as toggleClass,E as triggerDownload,A as urlToBase64};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/storage/index.ts","../src/dom/selector.ts","../src/dom/creation.ts","../src/dom/class.ts","../src/dom/style.ts","../src/dom/viewport.ts","../src/dom/event.ts","../src/clipboard/index.ts","../src/cache/storage-manager.ts","../src/window/openWindow.ts","../src/window/openRouteInNewWindow.ts","../src/download/constants.ts","../src/download/triggerDownload.ts","../src/download/utils.ts","../src/download/downloadFileFromUrl.ts","../src/download/downloadFileFromBase64.ts","../src/download/urlToBase64.ts","../src/download/downloadFileFromImageUrl.ts","../src/download/downloadFileFromBlob.ts","../src/download/downloadFileFromBlobPart.ts"],"sourcesContent":["/**\n * Storage utilities using localStorage and sessionStorage\n */\n\n/**\n * Gets an item from localStorage\n */\nexport function getLocalStorage<T = any>(key: string): T | null {\n try {\n const item = window.localStorage.getItem(key)\n return item ? JSON.parse(item) : null\n } catch (error) {\n console.error(`Error reading from localStorage: ${error}`)\n return null\n }\n}\n\n/**\n * Sets an item in localStorage\n */\nexport function setLocalStorage<T>(key: string, value: T): boolean {\n try {\n window.localStorage.setItem(key, JSON.stringify(value))\n return true\n } catch (error) {\n console.error(`Error writing to localStorage: ${error}`)\n return false\n }\n}\n\n/**\n * Removes an item from localStorage\n */\nexport function removeLocalStorage(key: string): boolean {\n try {\n window.localStorage.removeItem(key)\n return true\n } catch (error) {\n console.error(`Error removing from localStorage: ${error}`)\n return false\n }\n}\n\n/**\n * Clears all items from localStorage\n */\nexport function clearLocalStorage(): boolean {\n try {\n window.localStorage.clear()\n return true\n } catch (error) {\n console.error(`Error clearing localStorage: ${error}`)\n return false\n }\n}\n\n/**\n * Gets an item from sessionStorage\n */\nexport function getSessionStorage<T = any>(key: string): T | null {\n try {\n const item = window.sessionStorage.getItem(key)\n return item ? JSON.parse(item) : null\n } catch (error) {\n console.error(`Error reading from sessionStorage: ${error}`)\n return null\n }\n}\n\n/**\n * Sets an item in sessionStorage\n */\nexport function setSessionStorage<T>(key: string, value: T): boolean {\n try {\n window.sessionStorage.setItem(key, JSON.stringify(value))\n return true\n } catch (error) {\n console.error(`Error writing to sessionStorage: ${error}`)\n return false\n }\n}\n\n/**\n * Removes an item from sessionStorage\n */\nexport function removeSessionStorage(key: string): boolean {\n try {\n window.sessionStorage.removeItem(key)\n return true\n } catch (error) {\n console.error(`Error removing from sessionStorage: ${error}`)\n return false\n }\n}\n","/**\n * 选择器工具模块\n * 提供 DOM 元素选择功能\n */\n\n/**\n * 通过 CSS 选择器获取单个 DOM 元素\n *\n * @param selector - CSS 选择器字符串 (例如 '.class', '#id', 'div > p')\n * @returns 第一个匹配的 DOM 元素,如果未找到则返回 null\n *\n * @example 基础选择器\n * ```typescript\n * const header = $('header');\n * const nav = $('nav');\n * const footer = $('footer');\n * ```\n *\n * @example 类选择器和 ID 选择器\n * ```typescript\n * const activeItem = $('.menu-item.active');\n * const submitButton = $('#submit-btn');\n * const firstCard = $('.card:first-child');\n * ```\n *\n * @example 属性选择器和后代选择器\n * ```typescript\n * const inputText = $('input[type=\"text\"]');\n * const navLink = $('nav a.external');\n * const checkedCheckbox = $('input[type=\"checkbox\"]:checked');\n * ```\n *\n * @example 空值检查\n * ```typescript\n * const element = $('header');\n * if (element) {\n * console.log(element.textContent);\n * }\n * ```\n */\nexport function $(selector: string): HTMLElement | null {\n return document.querySelector(selector)\n}\n\n/**\n * 通过 CSS 选择器获取所有匹配的 DOM 元素\n *\n * @param selector - CSS 选择器字符串 (例如 '.class', '#id', 'div > p')\n * @returns 匹配的 DOM 元素数组\n *\n * @example 收集元素\n * ```typescript\n * const buttons = $$('button');\n * const links = $$('.nav a');\n * const inputs = $$('input');\n * ```\n *\n * @example 遍历元素\n * ```typescript\n * const cards = $$('.card');\n * cards.forEach(card => {\n * card.style.opacity = '0.8';\n * });\n * ```\n *\n * @example 过滤和处理元素\n * ```typescript\n * const images = $$('img');\n * const largeImages = images.filter(img => {\n * const width = parseInt(img.getAttribute('width') || '0');\n * return width > 300;\n * });\n * ```\n *\n * @example 多选择器组合\n * ```typescript\n * const focusableElements = $$('button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])');\n * ```\n */\nexport function $$(selector: string): HTMLElement[] {\n return Array.from(document.querySelectorAll(selector))\n}\n","/**\n * 元素创建工具模块\n * 提供 DOM 元素创建功能\n */\n\n/**\n * 创建 DOM 元素,可指定属性和子元素\n *\n * @param tag - HTML 标签名 (例如 'div', 'span', 'a')\n * @param attributes - 可选的属性键值对对象\n * @param children - 可选的子元素或文本节点数组\n * @returns 创建的 DOM 元素\n *\n * @example 基础元素创建\n * ```typescript\n * // 创建一个简单的 div\n * const div = createElement('div');\n *\n * // 创建带文本的 span\n * const span = createElement('span', {}, ['Hello, World!']);\n *\n * // 创建图片元素\n * const img = createElement('img', {\n * src: 'image.jpg',\n * alt: 'Image description',\n * width: '200'\n * });\n * ```\n *\n * @example 表单元素\n * ```typescript\n * // 创建输入框\n * const input = createElement('input', {\n * type: 'text',\n * placeholder: 'Enter your name',\n * name: 'username'\n * });\n *\n * // 创建带多个属性的按钮\n * const button = createElement('button', {\n * id: 'submit',\n * type: 'submit',\n * class: 'btn btn-primary',\n * 'data-action': 'submit-form'\n * }, ['Submit']);\n * ```\n *\n * @example 复杂的嵌套结构\n * ```typescript\n * // 创建带头部、主体和底部的卡片\n * const card = createElement('div', { class: 'card' }, [\n * createElement('div', { class: 'card-header' }, [\n * createElement('h3', {}, ['Card Title']),\n * createElement('button', { class: 'close' }, ['×'])\n * ]),\n * createElement('div', { class: 'card-body' }, [\n * createElement('p', {}, ['This is the card content'])\n * ]),\n * createElement('div', { class: 'card-footer' }, [\n * createElement('button', {}, ['Cancel']),\n * createElement('button', { class: 'primary' }, ['Save'])\n * ])\n * ]);\n * ```\n *\n * @example 列表和表格\n * ```typescript\n * // 创建无序列表\n * const ul = createElement('ul', {}, [\n * createElement('li', {}, ['First item']),\n * createElement('li', {}, ['Second item']),\n * createElement('li', {}, ['Third item'])\n * ]);\n *\n * // 创建表格行\n * const tr = createElement('tr', {}, [\n * createElement('td', {}, ['John']),\n * createElement('td', {}, ['30']),\n * createElement('td', {}, ['john@example.com'])\n * ]);\n * ```\n */\nexport function createElement<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n attributes?: Record<string, string>,\n children?: (string | Node)[]\n): HTMLElementTagNameMap[K] {\n const element = document.createElement(tag)\n\n if (attributes) {\n for (const [key, value] of Object.entries(attributes)) {\n element.setAttribute(key, value)\n }\n }\n\n if (children) {\n for (const child of children) {\n if (typeof child === 'string') {\n element.appendChild(document.createTextNode(child))\n } else {\n element.appendChild(child)\n }\n }\n }\n\n return element\n}\n","/**\n * 类名操作工具模块\n * 提供 DOM 元素的类名增删改功能\n * 底层的 classList.add() 方法原生支持两种方式:\n * 接受多个独立的字符串参数\n * 接受一个包含空格分隔的字符串(会自动拆分)\n *\n * 虽然当前实现两种方式都能工作,但从代码清晰度和TypeScript 类型安全的角度考虑:\n * 推荐的用法是使用多个独立参数:\n * ```typescript\n * addClass(element, 'class1', 'class2');\n * ```\n * 原因是:\n *\n * 当前函数签名使用的是剩余参数 ...classNames: string[],设计意图就是接收多个独立字符串\n * 独立参数的方式在 TypeScript 中有更好的类型提示和智能感知\n * 代码意图更明确,便于阅读和维护\n *\n * 因为底层调用的是浏览器原生的 classList.add() 方法,该方法具有以下特性:\n * 如果类名已存在,不会重复添加\n * 即使你多次传入相同的类名,DOM 中最终只会保留一个\n *\n * 说明哪些情况下的元素/对象没有 classList 属性\n * 1. 基本节点类型(Node 的子类): 例如 Text、Comment、Document、Fragment 等\n * 2. SVG 元素 : SVG 元素不是 HTMLElement,而是 SVGElement,早期浏览器可能不支持 classList\n * 3. 非元素节点: 例如 Text、Comment、Document、DocumentFragment 等\n * 4. 全局对象: 例如 window、document 等\n * 5. 自定义或非标准对象\n *\n * 完整的继承关系图\n * Node (没有 classList)\n * ├── Document (没有 classList)\n * ├── DocumentFragment (没有 classList)\n * ├── CharacterData (没有 classList)\n * │ ├── Text (没有 classList)\n * │ └── Comment (没有 classList)\n * └── Element (有 classList - 在现代浏览器中)\n * ├── HTMLElement (有 classList)\n * │ ├── HTMLDivElement\n * │ ├── HTMLButtonElement\n * │ └── ...\n * └── SVGElement (有 classList - 现代浏览器)\n */\n\n/**\n * 向元素添加一个或多个 CSS 类\n *\n * @param element - 要添加类的 DOM 元素\n * @param classNames - 一个或多个要添加的类名\n *\n * @example 添加单个或多个类\n * ```typescript\n * const button = $('button');\n * addClass(button, 'active');\n * addClass(button, 'highlight', 'primary');\n * ```\n *\n * @example 动态添加类\n * ```typescript\n * const card = $('.card');\n * if (card) {\n * const isFeatured = card.dataset.featured === 'true';\n * if (isFeatured) {\n * addClass(card, 'featured', 'highlight');\n * }\n * }\n * ```\n *\n * @example 批量处理元素\n * ```typescript\n * const buttons = $$('button');\n * buttons.forEach(button => {\n * addClass(button, 'btn', 'btn-primary');\n * });\n * ```\n *\n * @example 条件样式\n * ```typescript\n * const alerts = $$('.alert');\n * alerts.forEach(alert => {\n * const type = alert.dataset.type;\n * if (type === 'error') addClass(alert, 'alert-error');\n * if (type === 'warning') addClass(alert, 'alert-warning');\n * if (type === 'success') addClass(alert, 'alert-success');\n * });\n * ```\n */\nexport function addClass(element: HTMLElement, ...classNames: string[]): void {\n element.classList.add(...classNames)\n}\n\n/**\n * 从元素中移除一个或多个 CSS 类\n *\n * @param element - 要移除类的 DOM 元素\n * @param classNames - 一个或多个要移除的类名\n *\n * @example 移除单个或多个类\n * ```typescript\n * const button = $('button');\n * removeClass(button, 'active');\n * removeClass(button, 'highlight', 'primary');\n * ```\n *\n * @example 重置元素状态\n * ```typescript\n * const modal = $('.modal');\n * if (modal) {\n * removeClass(modal, 'open', 'visible');\n * addClass(modal, 'closed');\n * }\n * ```\n *\n * @example 基于切换的移除\n * ```typescript\n * const menu = $('.menu');\n * if (menu) {\n * if (menu.classList.contains('active')) {\n * removeClass(menu, 'active');\n * }\n * }\n * ```\n *\n * @example 清理动态类\n * ```typescript\n * const container = $('.container');\n * if (container) {\n * // 移除所有工具类\n * removeClass(container, 'mt-2', 'mb-4', 'p-4', 'bg-gray-100');\n * // 保留基础类\n * addClass(container, 'base-style');\n * }\n * ```\n */\nexport function removeClass(element: HTMLElement, ...classNames: string[]): void {\n element.classList.remove(...classNames)\n}\n\n/**\n * 切换元素的 CSS 类(存在则移除,不存在则添加)\n *\n * @param element - 要切换类的 DOM 元素\n * @param className - 要切换的类名\n * @returns 如果类被添加则返回 true,如果被移除则返回 false\n *\n * @example 简单切换\n * ```typescript\n * const button = $('button');\n * const isActive = toggleClass(button, 'active');\n * console.log('Active:', isActive); // 添加时为 true,移除时为 false\n * ```\n *\n * @example 事件处理器切换\n * ```typescript\n * const menuToggle = $('#menu-toggle');\n * const menu = $('#menu');\n *\n * menuToggle?.addEventListener('click', () => {\n * if (menu) {\n * const isOpen = toggleClass(menu, 'open');\n * if (isOpen) {\n * addClass(menuToggle, 'active');\n * } else {\n * removeClass(menuToggle, 'active');\n * }\n * }\n * });\n * ```\n *\n * @example 表单验证反馈\n * ```typescript\n * const emailInput = $('input[type=\"email\"]');\n *\n * emailInput?.addEventListener('input', () => {\n * const isValid = emailInput.value.includes('@');\n * toggleClass(emailInput, 'valid', isValid);\n * toggleClass(emailInput, 'invalid', !isValid);\n * });\n * ```\n *\n * @example 多元素切换\n * ```typescript\n * const buttons = $$('.tab-button');\n * const panels = $$('.tab-panel');\n *\n * buttons.forEach((button, index) => {\n * button.addEventListener('click', () => {\n * // 切换按钮的激活状态\n * buttons.forEach(btn => removeClass(btn, 'active'));\n * addClass(button, 'active');\n *\n * // 切换面板的可见性\n * panels.forEach((panel, i) => {\n * toggleClass(panel, 'active', i === index);\n * });\n * });\n * });\n * ```\n */\nexport function toggleClass(element: HTMLElement, className: string): boolean {\n return element.classList.toggle(className)\n}\n","/**\n * 样式操作工具模块\n * 提供 DOM 元素的样式读写功能\n */\n\n/**\n * 获取元素指定 CSS 属性的计算值\n *\n * @param element - 要获取样式的 DOM 元素\n * @param property - CSS 属性名 (例如 'color', 'font-size')\n * @returns CSS 属性的计算值\n *\n * @example 基础样式获取\n * ```typescript\n * const header = $('header');\n * const bgColor = getStyle(header, 'background-color');\n * const fontSize = getStyle(header, 'font-size');\n * const color = getStyle(header, 'color');\n * ```\n *\n * @example 响应式设计检查\n * ```typescript\n * const element = $('.responsive-element');\n * if (element) {\n * const display = getStyle(element, 'display');\n * const isVisible = display !== 'none';\n *\n * if (isVisible) {\n * const width = getStyle(element, 'width');\n * console.log('Element width:', width);\n * }\n * }\n * ```\n *\n * @example 比较和逻辑判断\n * ```typescript\n * const header = $('header');\n * const footer = $('footer');\n *\n * if (header && footer) {\n * const headerHeight = parseInt(getStyle(header, 'height'));\n * const footerHeight = parseInt(getStyle(footer, 'height'));\n *\n * if (headerHeight > footerHeight) {\n * console.log('Header is taller than footer');\n * }\n * }\n * ```\n *\n * @example 颜色处理\n * ```typescript\n * const button = $('button');\n * if (button) {\n * const bgColor = getStyle(button, 'background-color');\n * const textColor = getStyle(button, 'color');\n *\n * // 转换为 RGB 并调整亮度\n * const rgb = bgColor.match(/\\d+/g);\n * if (rgb) {\n * const brightness = (parseInt(rgb[0]) * 299 + parseInt(rgb[1]) * 587 + parseInt(rgb[2]) * 114) / 1000;\n * const shouldUseLightText = brightness < 128;\n * }\n * }\n * ```\n */\nexport function getStyle(element: HTMLElement, property: string): string {\n return window.getComputedStyle(element).getPropertyValue(property)\n}\n\n/**\n * 为元素设置多个 CSS 属性\n *\n * @param element - 要应用样式的 DOM 元素\n * @param styles - CSS 属性键值对对象\n *\n * @example 基础样式设置\n * ```typescript\n * const header = $('header');\n * setStyle(header, {\n * 'color': '#333',\n * 'font-size': '16px',\n * 'background-color': '#f5f5f5'\n * });\n * ```\n *\n * @example 动画和过渡效果\n * ```typescript\n * const modal = $('.modal');\n * if (modal) {\n * setStyle(modal, {\n * 'opacity': '0',\n * 'transform': 'translateY(-20px)',\n * 'transition': 'opacity 0.3s ease, transform 0.3s ease'\n * });\n *\n * setTimeout(() => {\n * setStyle(modal, {\n * 'opacity': '1',\n * 'transform': 'translateY(0)'\n * });\n * }, 100);\n * }\n * ```\n *\n * @example 响应式和动态样式\n * ```typescript\n * const card = $('.card');\n * if (card) {\n * const isDark = document.documentElement.classList.contains('dark');\n * setStyle(card, {\n * 'background-color': isDark ? '#1f2937' : '#ffffff',\n * 'color': isDark ? '#f9fafb' : '#111827',\n * 'box-shadow': isDark ? '0 4px 6px rgba(0, 0, 0, 0.5)' : '0 4px 6px rgba(0, 0, 0, 0.1)'\n * });\n * }\n * ```\n *\n * @example 动态定位\n * ```typescript\n * const tooltip = $('.tooltip');\n * const trigger = $('.trigger');\n *\n * if (tooltip && trigger) {\n * const triggerRect = trigger.getBoundingClientRect();\n * setStyle(tooltip, {\n * 'position': 'absolute',\n * 'top': `${triggerRect.bottom + 10}px`,\n * 'left': `${triggerRect.left}px`,\n * 'z-index': '1000'\n * });\n * }\n * ```\n */\nexport function setStyle(element: HTMLElement, styles: Record<string, string>): void {\n for (const [property, value] of Object.entries(styles)) {\n element.style.setProperty(property, value)\n }\n}\n","/**\n * 视口和滚动工具模块\n * 提供元素可视性检查和滚动控制功能\n */\n\n/**\n * 检查元素是否完全可见于视口中\n *\n * @param element - 要检查的 DOM 元素\n * @returns 如果元素在视口中完全可见则返回 true,否则返回 false\n *\n * @example 基础可见性检查\n * ```typescript\n * const footer = $('footer');\n * if (isInViewport(footer)) {\n * console.log('Footer is visible');\n * }\n * ```\n *\n * @example 懒加载内容\n * ```typescript\n * const images = $$('img[data-src]');\n *\n * function loadVisibleImages() {\n * images.forEach(img => {\n * if (isInViewport(img) && !img.src) {\n * img.src = img.dataset.src;\n * delete img.dataset.src;\n * }\n * });\n * }\n *\n * window.addEventListener('scroll', loadVisibleImages);\n * window.addEventListener('load', loadVisibleImages);\n * ```\n *\n * @example 无限滚动\n * ```typescript\n * const sentinel = $('.sentinel');\n *\n * function loadMoreContent() {\n * if (sentinel && isInViewport(sentinel)) {\n * console.log('Load more content...');\n * // 获取并追加新内容\n * }\n * }\n *\n * window.addEventListener('scroll', () => {\n * requestAnimationFrame(loadMoreContent);\n * });\n * ```\n *\n * @example 统计和跟踪\n * ```typescript\n * const sections = $$('section[data-track]');\n *\n * const observer = new IntersectionObserver((entries) => {\n * entries.forEach(entry => {\n * if (entry.isIntersecting) {\n * const section = entry.target;\n * const trackId = section.dataset.track;\n * console.log('Section viewed:', trackId);\n * // 发送统计事件\n * }\n * });\n * }, { threshold: 0.5 });\n *\n * sections.forEach(section => {\n * if (isInViewport(section)) {\n * const trackId = section.dataset.track;\n * console.log('Initial view:', trackId);\n * }\n * observer.observe(section);\n * });\n * ```\n */\nexport function isInViewport(element: HTMLElement): boolean {\n const rect = element.getBoundingClientRect()\n return (\n rect.top >= 0 &&\n rect.left >= 0 &&\n rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&\n rect.right <= (window.innerWidth || document.documentElement.clientWidth)\n )\n}\n\n/**\n * 将指定元素滚动到浏览器窗口的可见区域\n *\n * @param element - 要滚动到可见区域的 DOM 元素\n * @param options - 可选的滚动行为选项 (默认为平滑滚动)\n *\n * @example 基础滚动\n * ```typescript\n * const section = $('section');\n * scrollIntoView(section);\n * ```\n *\n * @example 不同的滚动位置\n * ```typescript\n * const section = $('section');\n * scrollIntoView(section);\n *\n * // 滚动到顶部\n * scrollIntoView(section, { block: 'start' });\n *\n * // 滚动到中间\n * scrollIntoView(section, { block: 'center' });\n *\n * // 滚动到底部\n * scrollIntoView(section, { block: 'end' });\n * ```\n *\n * @example 导航和锚点链接\n * ```typescript\n * const navLinks = $$('.nav a');\n *\n * navLinks.forEach(link => {\n * link.addEventListener('click', (e) => {\n * e.preventDefault();\n * const targetId = link.getAttribute('href');\n * const target = $(targetId);\n * if (target) {\n * scrollIntoView(target, { block: 'start' });\n * }\n * });\n * });\n * ```\n *\n * @example 表单验证反馈\n * ```typescript\n * const form = $('form');\n * const submitButton = $('button[type=\"submit\"]');\n *\n * form?.addEventListener('submit', (e) => {\n * e.preventDefault();\n *\n * const invalidInputs = $$('input:invalid');\n * if (invalidInputs.length > 0) {\n * // 滚动到第一个无效输入框\n * scrollIntoView(invalidInputs[0], { block: 'center' });\n *\n * // 添加错误高亮\n * invalidInputs.forEach(input => {\n * addClass(input, 'error');\n * });\n * }\n * });\n * ```\n *\n * @example 目录导航\n * ```typescript\n * const tocLinks = $$('.toc a');\n *\n * tocLinks.forEach(link => {\n * link.addEventListener('click', (e) => {\n * e.preventDefault();\n *\n * const targetId = link.getAttribute('href');\n * const target = $(targetId);\n * if (target) {\n * scrollIntoView(target, {\n * block: 'start',\n * inline: 'nearest',\n * behavior: 'smooth'\n * });\n * }\n * });\n * });\n * ```\n */\nexport function scrollIntoView(element: HTMLElement, options?: ScrollIntoViewOptions): void {\n element.scrollIntoView({ behavior: 'smooth', ...options })\n}\n","/**\n * 事件监听工具模块\n * 提供 DOM 元素的事件绑定、解绑和一次性监听功能\n *\n * 支持的事件目标类型:\n * - HTMLElement: DOM 元素节点\n * - Document: 文档对象\n * - Window: 窗口对象\n *\n * 注意事项:\n * - 使用相同参数多次调用 on() 会添加多个监听器,而不是覆盖\n * - 移除监听器时,参数必须与添加时完全一致(包括 useCapture)\n * - once() 监听器在触发后会自动移除,无需手动解绑\n * - 使用事件对象处理函数时,需要确保 handleEvent 方法正确实现\n */\n\n/**\n * 事件绑定\n * 在指定的元素上绑定事件监听器\n *\n * @param element - 目标元素\n * @param event - 事件名称(如 'click', 'mousedown' 等)\n * @param handler - 事件处理函数\n * @param useCapture - 是否在捕获阶段触发事件,默认为 false(冒泡阶段)\n *\n * @example 基础点击事件\n * ```typescript\n * on(document.body, 'click', () => {\n * console.log('Body clicked');\n * }, false);\n * ```\n *\n * @example 元素悬停效果\n * ```typescript\n * const button = $('button');\n * on(button, 'mouseenter', () => {\n * addClass(button, 'hover');\n * });\n * on(button, 'mouseleave', () => {\n * removeClass(button, 'hover');\n * });\n * ```\n *\n * @example 表单输入监听\n * ```typescript\n * const input = $('input[type=\"text\"]');\n * on(input, 'input', (e) => {\n * console.log('Input value:', (e.target as HTMLInputElement).value);\n * });\n * ```\n *\n * @example 使用事件对象处理函数\n * ```typescript\n * const handler = {\n * count: 0,\n * handleEvent(e: Event) {\n * this.count++;\n * console.log(`Event fired ${this.count} times`);\n * }\n * };\n * on(button, 'click', handler);\n * ```\n *\n * @example 捕获阶段监听\n * ```typescript\n * // 在父元素上使用捕获阶段拦截子元素事件\n * on(container, 'click', (e) => {\n * console.log('Click captured at container');\n * }, true);\n * ```\n */\nexport function on(\n element: HTMLElement | Document | Window,\n event: string,\n handler: EventListenerOrEventListenerObject,\n useCapture = false\n): void {\n if (element && event && handler) {\n element.addEventListener(event, handler, useCapture);\n }\n}\n\n/**\n * 事件解绑\n * 移除元素上的事件监听器\n *\n * @param element - 目标元素\n * @param event - 事件名称\n * @param handler - 事件处理函数\n * @param useCapture - 是否为捕获阶段的事件,必须与绑定时一致\n *\n * @example 基础解绑\n * ```typescript\n * const handler = () => console.log('Clicked');\n * on(button, 'click', handler);\n * // ... 某些条件下\n * off(button, 'click', handler);\n * ```\n *\n * @example 组件卸载时清理\n * ```typescript\n * // 在组件挂载时绑定\n * const resizeHandler = () => console.log('Window resized');\n * on(window, 'resize', resizeHandler);\n *\n * // 在组件卸载时清理\n * function cleanup() {\n * off(window, 'resize', resizeHandler);\n * }\n * ```\n *\n * @example 动态清理多个监听器\n * ```typescript\n * const handlers = {\n * click: null as (() => void) | null,\n * scroll: null as (() => void) | null\n * };\n *\n * // 绑定\n * handlers.click = () => console.log('Clicked');\n * handlers.scroll = () => console.log('Scrolled');\n * on(button, 'click', handlers.click);\n * on(window, 'scroll', handlers.scroll);\n *\n * // 清理\n * if (handlers.click) off(button, 'click', handlers.click);\n * if (handlers.scroll) off(window, 'scroll', handlers.scroll);\n * ```\n *\n * @example 捕获阶段事件解绑\n * ```typescript\n * const handler = () => console.log('Captured');\n * on(container, 'click', handler, true);\n * // 移除时必须也传入 true\n * off(container, 'click', handler, true);\n * ```\n */\nexport function off(\n element: HTMLElement | Document | Window,\n event: string,\n handler: EventListenerOrEventListenerObject,\n useCapture = false\n): void {\n if (element && event && handler) {\n element.removeEventListener(event, handler, useCapture);\n }\n}\n\n/**\n * 一次性事件监听\n * 绑定一个只触发一次的事件监听器,触发后自动移除\n *\n * @param element - 目标元素\n * @param event - 事件名称\n * @param handler - 事件处理函数\n * @param useCapture - 是否在捕获阶段触发事件,默认为 false\n *\n * @example 只执行一次的操作\n * ```typescript\n * once(button, 'click', () => {\n * console.log('This will only log once');\n * });\n * ```\n *\n * @example 页面加载初始化\n * ```typescript\n * once(document, 'DOMContentLoaded', () => {\n * console.log('DOM fully loaded');\n * // 执行初始化逻辑\n * });\n * ```\n *\n * @example 首次滚动触发\n * ```typescript\n * once(window, 'scroll', () => {\n * console.log('User scrolled for the first time');\n * // 显示提示或记录数据\n * });\n * ```\n *\n * @example 表单首次提交\n * ```typescript\n * once(form, 'submit', (e) => {\n * e.preventDefault();\n * console.log('First form submission');\n * // 特殊处理首次提交\n * });\n * ```\n *\n * @example 资源加载完成后清理\n * ```typescript\n * const image = new Image();\n * once(image, 'load', () => {\n * console.log('Image loaded successfully');\n * // 显示图片或触发其他逻辑\n * });\n * image.src = 'path/to/image.jpg';\n * ```\n *\n * @example 与事件对象结合\n * ```typescript\n * const counter = { clicks: 0 };\n * once(button, 'click', (e) => {\n * counter.clicks++;\n * console.log(`Clicked at: ${e.timeStamp}`);\n * });\n * ```\n */\nexport function once(\n element: HTMLElement | Document | Window,\n event: string,\n handler: EventListenerOrEventListenerObject,\n useCapture = false\n): void {\n if (!element || !event || !handler) return;\n\n const onceHandler: EventListenerOrEventListenerObject = (e: Event) => {\n if (typeof handler === 'function') {\n handler(e);\n } else if (handler.handleEvent) {\n handler.handleEvent(e);\n }\n element.removeEventListener(event, onceHandler, useCapture);\n };\n\n element.addEventListener(event, onceHandler, useCapture);\n}\n","import copy from 'copy-text-to-clipboard'\n\ninterface optionsType {\n target: HTMLElement\n}\n\n/**\n * 复制文本到剪贴板\n * @param text - 需要复制到剪贴板的文本\n * @param options - target: HTMLElement\n * @returns 是否复制成功(Boolean)\n * @example\n * ```ts\n * copyToClipboard('复制') // true\n * copyToClipboard('指定临时创建的 dom 存放处', { target: document.querySelector('#text') }) // true\n * ```\n * @public\n */\nexport function copyToClipboard(text: string, options?: optionsType): boolean {\n return copy(text, options)\n}\n","type StorageType = 'localStorage' | 'sessionStorage';\n\ninterface StorageManagerOptions {\n prefix?: string;\n storageType?: StorageType;\n}\n\ninterface StorageItem<T> {\n expiry?: number;\n value: T;\n}\n\nclass StorageManager {\n private prefix: string;\n private storage: Storage;\n\n constructor({\n prefix = '',\n storageType = 'localStorage',\n }: StorageManagerOptions = {}) {\n this.prefix = prefix;\n this.storage =\n storageType === 'localStorage'\n ? window.localStorage\n : window.sessionStorage;\n }\n\n /**\n * 清除所有带前缀的存储项\n */\n clear(): void {\n const keysToRemove: string[] = [];\n for (let i = 0; i < this.storage.length; i++) {\n const key = this.storage.key(i);\n if (key && key.startsWith(this.prefix)) {\n keysToRemove.push(key);\n }\n }\n keysToRemove.forEach((key) => this.storage.removeItem(key));\n }\n\n /**\n * 清除所有过期的存储项\n */\n clearExpiredItems(): void {\n for (let i = 0; i < this.storage.length; i++) {\n const key = this.storage.key(i);\n if (key && key.startsWith(this.prefix)) {\n const shortKey = key.replace(this.prefix, '');\n this.getItem(shortKey); // 调用 getItem 方法检查并移除过期项\n }\n }\n }\n\n /**\n * 获取存储项\n * @param key 键\n * @param defaultValue 当项不存在或已过期时返回的默认值\n * @returns 值,如果项已过期或解析错误则返回默认值\n */\n getItem<T>(key: string, defaultValue: null | T = null): null | T {\n const fullKey = this.getFullKey(key);\n const itemStr = this.storage.getItem(fullKey);\n if (!itemStr) {\n return defaultValue;\n }\n\n try {\n const item: StorageItem<T> = JSON.parse(itemStr);\n if (item.expiry && Date.now() > item.expiry) {\n this.storage.removeItem(fullKey);\n return defaultValue;\n }\n return item.value;\n } catch (error) {\n console.error(`Error parsing item with key \"${fullKey}\":`, error);\n this.storage.removeItem(fullKey); // 如果解析失败,删除该项\n return defaultValue;\n }\n }\n\n /**\n * 移除存储项\n * @param key 键\n */\n removeItem(key: string): void {\n const fullKey = this.getFullKey(key);\n this.storage.removeItem(fullKey);\n }\n\n /**\n * 设置存储项\n * @param key 键\n * @param value 值\n * @param ttl 存活时间(毫秒)\n */\n setItem<T>(key: string, value: T, ttl?: number): void {\n const fullKey = this.getFullKey(key);\n const expiry = ttl ? Date.now() + ttl : undefined;\n const item: StorageItem<T> = { expiry, value };\n try {\n this.storage.setItem(fullKey, JSON.stringify(item));\n } catch (error) {\n console.error(`Error setting item with key \"${fullKey}\":`, error);\n }\n }\n\n /**\n * 获取完整的存储键\n * @param key 原始键\n * @returns 带前缀的完整键\n */\n private getFullKey(key: string): string {\n return `${this.prefix}-${key}`;\n }\n}\n\nexport { StorageManager };\n","import type { OpenWindowOptions } from './types';\n\n/**\n * 在新窗口中打开 URL\n *\n * 使用 window.open 方法打开指定 URL,支持配置窗口行为和安全特性\n *\n * @param url - 需要打开的网址\n * @param options - 打开窗口的选项\n * @param options.noopener - 是否启用 noopener,默认为 true\n * @param options.noreferrer - 是否启用 noreferrer,默认为 true\n * @param options.target - 打开目标窗口,默认为 '_blank'\n *\n * @example 打开新窗口\n * ```typescript\n * openWindow('https://example.com');\n * ```\n *\n * @example 在当前窗口打开\n * ```typescript\n * openWindow('https://example.com', { target: '_self' });\n * ```\n *\n * @example 禁用安全特性\n * ```typescript\n * openWindow('https://example.com', {\n * noopener: false,\n * noreferrer: false\n * });\n * ```\n *\n * @example 在父窗口打开\n * ```typescript\n * openWindow('https://example.com', { target: '_parent' });\n * ```\n */\nexport function openWindow(\n url: string,\n options: OpenWindowOptions = {}\n): void {\n // 解构并设置默认值\n const {\n noopener = true,\n noreferrer = true,\n target = '_blank'\n } = options;\n\n // 基于选项创建特性字符串\n const features = [\n noopener && 'noopener=yes',\n noreferrer && 'noreferrer=yes'\n ]\n .filter(Boolean)\n .join(',');\n\n // 打开窗口\n window.open(url, target, features);\n}\n","import { openWindow } from './openWindow';\n\n/**\n * 在新窗口中打开当前应用的路由\n *\n * 基于当前页面的 origin 和 hash 构建完整的路由地址,然后在新窗口中打开\n *\n * @param path - 路由路径\n *\n * @example 打开路由\n * ```typescript\n * openRouteInNewWindow('/dashboard');\n * ```\n *\n * @example 打开带参数的路由\n * ```typescript\n * openRouteInNewWindow('/user/profile?id=123');\n * ```\n *\n * @example 不带前导斜杠\n * ```typescript\n * openRouteInNewWindow('settings');\n * // 等同于 '/settings'\n * ```\n *\n * @example 在 Hash 路由模式下\n * ```typescript\n * // 当前 URL: https://example.com/#/home\n * openRouteInNewWindow('/about');\n * // 将打开: https://example.com/#/about\n * ```\n */\nexport function openRouteInNewWindow(path: string): void {\n const { hash, origin } = location;\n const fullPath = path.startsWith('/') ? path : `/${path}`;\n const url = `${origin}${hash && !fullPath.startsWith('/#') ? '/#' : ''}${fullPath}`;\n openWindow(url, { target: '_blank' });\n}\n","/**\n * 下载功能常量\n */\n\n/**\n * 默认下载文件名\n */\nexport const DEFAULT_FILENAME = 'downloaded_file';\n","/**\n * 通用下载触发函数\n *\n * 通过创建临时 `<a>` 标签并触发点击事件来下载文件,支持自动清理内存\n *\n * @param href - 文件下载的 URL 或 Blob URL\n * @param fileName - 下载文件的名称,如果未提供则使用默认值\n * @param revokeDelay - 清理 URL 的延迟时间(毫秒),默认为 100ms\n *\n * @example 下载文件\n * ```typescript\n * triggerDownload('https://example.com/file.pdf', 'document.pdf');\n * ```\n *\n * @example 使用 Blob URL\n * ```typescript\n * const blob = new Blob(['content'], { type: 'text/plain' });\n * const blobUrl = URL.createObjectURL(blob);\n * triggerDownload(blobUrl, 'file.txt', 200);\n * ```\n *\n * @example 使用默认文件名\n * ```typescript\n * triggerDownload('https://example.com/data.json', undefined);\n * ```\n */\nexport function triggerDownload(\n href: string,\n fileName: string | undefined,\n revokeDelay: number = 100,\n): void {\n const defaultFileName = 'downloaded_file';\n const finalFileName = fileName || defaultFileName;\n\n const link = document.createElement('a');\n link.href = href;\n link.download = finalFileName;\n link.style.display = 'none';\n\n if (link.download === undefined) {\n link.setAttribute('target', '_blank');\n }\n\n document.body.append(link);\n link.click();\n link.remove();\n\n // 清理临时 URL 以释放内存\n setTimeout(() => URL.revokeObjectURL(href), revokeDelay);\n}\n","/**\n * 下载功能工具函数\n */\n\nimport { DEFAULT_FILENAME } from './constants';\n\n/**\n * 解析文件名\n *\n * 从 URL 中提取文件名,如果未提供文件名或 URL 中没有文件名,则使用默认文件名\n *\n * @param url - 文件 URL 地址\n * @param fileName - 指定的文件名(可选)\n *\n * @returns string - 解析后的文件名\n *\n * @example 使用指定文件名\n * ```typescript\n * const name = resolveFileName('https://example.com/file.pdf', 'custom.pdf');\n * console.log(name); // 'custom.pdf'\n * ```\n *\n * @example 从 URL 提取文件名\n * ```typescript\n * const name = resolveFileName('https://example.com/path/to/document.pdf');\n * console.log(name); // 'document.pdf'\n * ```\n *\n * @example 使用默认文件名\n * ```typescript\n * const name = resolveFileName('https://example.com/path/');\n * console.log(name); // 'downloaded_file'\n * ```\n */\nexport function resolveFileName(\n url: string,\n fileName?: string,\n): string {\n return fileName || url.slice(url.lastIndexOf('/') + 1) || DEFAULT_FILENAME;\n}\n\n","import { openWindow } from '../window';\nimport { DownloadOptions } from './types';\nimport { triggerDownload } from './triggerDownload';\nimport { resolveFileName } from './utils';\n\n/**\n * 通过 URL 下载文件,支持跨域\n *\n * @param options - 下载选项\n * @param options.fileName - 下载文件名\n * @param options.source - 文件 URL\n * @param options.target - 打开目标,默认为 '_blank'\n *\n * @throws {Error} - 当下载失败时抛出错误\n *\n * @example 下载 URL 文件\n * ```typescript\n * await downloadFileFromUrl({\n * source: 'https://example.com/file.pdf',\n * fileName: 'document.pdf'\n * });\n * ```\n *\n * @example 跨域下载\n * ```typescript\n * await downloadFileFromUrl({\n * source: 'https://cdn.example.com/image.jpg',\n * fileName: 'image.jpg'\n * });\n * ```\n */\nexport async function downloadFileFromUrl({\n fileName,\n source,\n target = '_blank',\n}: DownloadOptions): Promise<void> {\n if (!source || typeof source !== 'string') {\n throw new Error('Invalid URL.');\n }\n\n const isChrome = window.navigator.userAgent.toLowerCase().includes('chrome');\n const isSafari = window.navigator.userAgent.toLowerCase().includes('safari');\n\n if (/iP/.test(window.navigator.userAgent)) {\n console.error('Your browser does not support download!');\n return;\n }\n\n if (isChrome || isSafari) {\n triggerDownload(source, resolveFileName(source, fileName));\n return;\n }\n if (!source.includes('?')) {\n source += '?download';\n }\n\n openWindow(source, { target });\n}\n","import { DownloadOptions } from './types';\nimport { triggerDownload } from './triggerDownload';\nimport { DEFAULT_FILENAME } from './constants';\n\n/**\n * 通过 Base64 数据下载文件\n *\n * @param options - 下载选项\n * @param options.fileName - 下载文件名\n * @param options.source - Base64 编码的文件数据\n *\n * @throws {Error} - 当 Base64 数据无效时抛出错误\n *\n * @example 下载 Base64 图片\n * ```typescript\n * downloadFileFromBase64({\n * source: 'data:image/png;base64,iVBORw0KGgoAAAANS...',\n * fileName: 'image.png'\n * });\n * ```\n *\n * @example 使用默认文件名\n * ```typescript\n * downloadFileFromBase64({\n * source: 'data:text/plain;base64,SGVsbG8gV29ybGQ='\n * });\n * ```\n */\nexport function downloadFileFromBase64({ fileName, source }: DownloadOptions) {\n if (!source || typeof source !== 'string') {\n throw new Error('Invalid Base64 data.');\n }\n\n const resolvedFileName = fileName || DEFAULT_FILENAME;\n triggerDownload(source, resolvedFileName);\n}\n","/**\n * 将图片 URL 转换为 Base64 编码\n *\n * @param url - 图片 URL 地址\n * @param mineType - 指定输出的 MIME 类型,默认为 'image/png'\n *\n * @returns 返回 Base64 编码的图片数据\n *\n * @example 转换为 PNG\n * ```typescript\n * const base64 = await urlToBase64('https://example.com/image.jpg');\n * console.log(base64); // 'data:image/png;base64,...'\n * ```\n *\n * @example 指定 MIME 类型\n * ```typescript\n * const jpegBase64 = await urlToBase64(\n * 'https://example.com/image.png',\n * 'image/jpeg'\n * );\n * ```\n *\n * @example 下载图片\n * ```typescript\n * const base64Data = await urlToBase64('https://example.com/photo.jpg');\n * downloadFileFromBase64({\n * source: base64Data,\n * fileName: 'photo.jpg'\n * });\n * ```\n */\nexport function urlToBase64(url: string, mineType?: string): Promise<string> {\n return new Promise((resolve, reject) => {\n let canvas = document.createElement('CANVAS') as HTMLCanvasElement | null;\n const ctx = canvas?.getContext('2d');\n const img = new Image();\n img.crossOrigin = '';\n img.addEventListener('load', () => {\n if (!canvas || !ctx) {\n return reject(new Error('Failed to create canvas.'));\n }\n canvas.height = img.height;\n canvas.width = img.width;\n ctx.drawImage(img, 0, 0);\n const dataURL = canvas.toDataURL(mineType || 'image/png');\n canvas = null;\n resolve(dataURL);\n });\n img.src = url;\n });\n}\n","import { DownloadOptions } from './types';\nimport { urlToBase64 } from './urlToBase64';\nimport { downloadFileFromBase64 } from './downloadFileFromBase64';\n\n/**\n * 通过图片 URL 下载图片文件\n *\n * @param options - 下载选项\n * @param options.fileName - 下载文件名\n * @param options.source - 图片 URL\n *\n * @example 下载网络图片\n * ```typescript\n * await downloadFileFromImageUrl({\n * source: 'https://example.com/image.jpg',\n * fileName: 'downloaded-image.jpg'\n * });\n * ```\n *\n * @example 下载 SVG 图片\n * ```typescript\n * await downloadFileFromImageUrl({\n * source: 'https://example.com/icon.svg',\n * fileName: 'icon.svg'\n * });\n * ```\n */\nexport async function downloadFileFromImageUrl({\n fileName,\n source,\n}: DownloadOptions) {\n const base64 = await urlToBase64(source);\n downloadFileFromBase64({ fileName, source: base64 });\n}\n","import { DownloadOptions } from './types';\nimport { triggerDownload } from './triggerDownload';\nimport { DEFAULT_FILENAME } from './constants';\n\n/**\n * 通过 Blob 对象下载文件\n *\n * @param options - 下载选项\n * @param options.fileName - 下载文件名,默认为 'downloaded_file'\n * @param options.source - Blob 对象\n *\n * @throws {TypeError} - 当源数据不是 Blob 对象时抛出错误\n *\n * @example 下载文本 Blob\n * ```typescript\n * const textBlob = new Blob(['Hello World'], { type: 'text/plain' });\n * downloadFileFromBlob({\n * source: textBlob,\n * fileName: 'hello.txt'\n * });\n * ```\n *\n * @example 下载 JSON Blob\n * ```typescript\n * const jsonData = { name: 'test', value: 123 };\n * const jsonBlob = new Blob([JSON.stringify(jsonData)], { type: 'application/json' });\n * downloadFileFromBlob({\n * source: jsonBlob,\n * fileName: 'data.json'\n * });\n * ```\n */\nexport function downloadFileFromBlob({\n fileName = DEFAULT_FILENAME,\n source,\n}: DownloadOptions<Blob>): void {\n if (!(source instanceof Blob)) {\n throw new TypeError('Invalid Blob data.');\n }\n\n const url = URL.createObjectURL(source);\n triggerDownload(url, fileName);\n}\n","import { DownloadOptions } from './types';\nimport { triggerDownload } from './triggerDownload';\nimport { DEFAULT_FILENAME } from './constants';\n\n/**\n * 通过 BlobPart 数据下载文件\n *\n * 支持 Blob、字符串和其他 BlobPart 类型,如果不是 Blob 会自动转换\n *\n * @param options - 下载选项\n * @param options.fileName - 下载文件名,默认为 'downloaded_file'\n * @param options.source - BlobPart 数据 (Blob、字符串、ArrayBuffer 等)\n *\n * @example 下载字符串\n * ```typescript\n * downloadFileFromBlobPart({\n * source: 'Hello World',\n * fileName: 'text.txt'\n * });\n * ```\n *\n * @example 下载 ArrayBuffer\n * ```typescript\n * const arrayBuffer = new Uint8Array([72, 101, 108, 108, 111]);\n * downloadFileFromBlobPart({\n * source: arrayBuffer,\n * fileName: 'data.bin'\n * });\n * ```\n *\n * @example 下载 Blob 对象\n * ```typescript\n * const blob = new Blob(['content'], { type: 'text/plain' });\n * downloadFileFromBlobPart({\n * source: blob,\n * fileName: 'file.txt'\n * });\n * ```\n */\nexport function downloadFileFromBlobPart({\n fileName = DEFAULT_FILENAME,\n source,\n}: DownloadOptions<BlobPart>): void {\n // 如果 data 不是 Blob,则转换为 Blob\n const blob =\n source instanceof Blob\n ? source\n : new Blob([source], { type: 'application/octet-stream' });\n\n // 创建对象 URL 并触发下载\n const url = URL.createObjectURL(blob);\n triggerDownload(url, fileName);\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@longmo-utils/browser",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Browser-specific utility functions with DOM/BOM dependencies",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.mjs",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.mts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"import": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"browser": "./dist/index.js",
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"keywords": [
|
|
22
|
+
"utils",
|
|
23
|
+
"typescript",
|
|
24
|
+
"browser",
|
|
25
|
+
"dom",
|
|
26
|
+
"bom"
|
|
27
|
+
],
|
|
28
|
+
"author": "",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"copy-text-to-clipboard": "^3.2.2"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsdown",
|
|
38
|
+
"dev": "tsdown --watch",
|
|
39
|
+
"clean": "rm -rf dist"
|
|
40
|
+
}
|
|
41
|
+
}
|