@js-toolkit/web-utils 1.63.0 → 1.64.1

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.
@@ -5,6 +5,7 @@ type GetOffOptions<T extends EmitterTarget> = T extends DomEventTarget ? boolean
5
5
  interface GetListenersOptions {
6
6
  event?: string | undefined;
7
7
  type?: 'normal' | 'capture' | undefined;
8
+ wrapper?: boolean | undefined;
8
9
  }
9
10
  export declare class EventEmitterListener<T extends EmitterTarget, M extends AnyObject = GetEventMap<T>> {
10
11
  readonly target: T;
@@ -14,8 +15,8 @@ export declare class EventEmitterListener<T extends EmitterTarget, M extends Any
14
15
  readonly passiveSupported: boolean;
15
16
  constructor(target: T, interceptor?: ((...args: any[]) => [...args: unknown[]] | undefined) | undefined);
16
17
  private createWrapper;
17
- getListenerList<L = unknown>({ event, type }?: GetListenersOptions): L[];
18
- getListeners<L = unknown>({ event, type }?: GetListenersOptions): Record<string, L[]>;
18
+ getListenerList<L = unknown>({ event, type, wrapper }?: GetListenersOptions): L[];
19
+ getListeners<L = unknown>({ event, type, wrapper }?: GetListenersOptions): Record<string, L[]>;
19
20
  has<K extends GetEventType<T>>(type: K, listener?: GetEventListener<T, K, M>, ...rest: [
20
21
  ...(T extends DomEventTarget ? [options?: GetOffOptions<T> | undefined] : []),
21
22
  ...unknown[]
@@ -1 +1 @@
1
- import{isPassiveSupported,isDomEventTarget,isEventTargetLike,normalizeOptions}from"./EventEmitterListener.utils";export class EventEmitterListener{target;interceptor;normalListeners={};captureListeners={};passiveSupported=isPassiveSupported();constructor(t,e){this.target=t,this.interceptor=e,this.target=t}createWrapper(t,e,s,...r){return(...i)=>{s&&this.off(t,e,...r);const n=this.interceptor&&this.interceptor(...i)||i;e(...n)}}getListenerList({event:t,type:e}={}){const s="normal"===e&&this.normalListeners||"capture"===e&&this.captureListeners||void 0;if(s){const e=t?s[t]&&{[t]:s[t]}:s;return e?Object.values(e).flatMap((t=>t?Array.from(t.keys()):[])):[]}return this.getListenerList({event:t,type:"normal"}).concat(this.getListenerList({event:t,type:"capture"}))}getListeners({event:t,type:e}={}){const s="normal"===e&&this.normalListeners||"capture"===e&&this.captureListeners||void 0;if(!s){const e=this.getListeners({event:t,type:"normal"}),s=this.getListeners({event:t,type:"capture"}),r={},i=([t,e])=>{const s=r[t];r[t]=s?s.concat(e):e};return Object.entries(e).forEach(i),Object.entries(s).forEach(i),r}const r=t?s[t]&&{[t]:s[t]}:s;return r?Object.entries(r).reduce(((t,[e,s])=>{const r=s?Array.from(s.keys()):[];return r.length>0&&(t[e]=r),t}),{}):{}}has(t,e,...s){if(!isDomEventTarget(this.target)){const s=this.normalListeners[t];return!!s&&(e?s.has(e):s.size>0)}const r=s[0],i=!0===r||r&&"object"==typeof r&&(r.capture??!1)?this.captureListeners[t]:this.normalListeners[t];return!!i&&(e?i.has(e):i.size>0)}on(t,e,...s){if(!isDomEventTarget(this.target)){const r=this.normalListeners[t]??new Map;this.normalListeners[t]=r;const i=r.get(e)??(this.interceptor?this.createWrapper(t,e,!1):e);return!r.has(e)&&r.set(e,i),isEventTargetLike(this.target)?this.target.addEventListener(t,i,...s):this.target.on(t,i,...s),this}const r=s[0],i=!0===r||r&&"object"==typeof r&&(r.capture??!1),n=(r&&"object"==typeof r&&r.once)??!1;if(i){const s=this.captureListeners[t]??new Map;this.captureListeners[t]=s;const i=s.get(e)??this.createWrapper(t,e,n,r);!s.has(e)&&s.set(e,i),this.target.addEventListener(t,i,normalizeOptions(r))}else{const s=this.normalListeners[t]??new Map;this.normalListeners[t]=s;const i=s.get(e)??this.createWrapper(t,e,n,r);!s.has(e)&&s.set(e,i),this.target.addEventListener(t,i,normalizeOptions(r))}return this}once(t,e,...s){if(!isDomEventTarget(this.target)){const r=this.normalListeners[t]??new Map;this.normalListeners[t]=r;const i=r.get(e)??this.createWrapper(t,e,!0,...s);return!r.has(e)&&r.set(e,i),isEventTargetLike(this.target)?this.target.addEventListener(t,i,...s):this.target.once?this.target.once(t,i,...s):this.target.on(t,i,...s),this}const r=s[0];return this.on(t,e,{..."object"==typeof r?r:null!=r&&{capture:r},once:!0})}off(t,e,...s){if(!isDomEventTarget(this.target)){const r=this.normalListeners[t],i=r?.get(e);return r&&i&&r.delete(e),0===r?.size&&delete this.normalListeners[t],isEventTargetLike(this.target)?this.target.removeEventListener(t,i??e,...s):this.target.off(t,i??e,...s),this}const r=s[0],i=!0===r||r&&"object"==typeof r&&(r.capture??!1),n=i?this.captureListeners[t]:this.normalListeners[t],o=n?.get(e);return n&&o&&n.delete(e),0===n?.size&&(i?delete this.captureListeners[t]:delete this.normalListeners[t]),this.target.removeEventListener(t,o??e,normalizeOptions(r)),this}removeAllListeners(t){if(t){const e=this.normalListeners[t];e&&e.forEach(((e,s)=>this.off(t,s)));const s=this.captureListeners[t];s&&s.forEach(((e,s)=>this.off(t,s,!0)))}else Object.keys(this.normalListeners).forEach((t=>this.removeAllListeners(t))),Object.keys(this.captureListeners).forEach((t=>this.removeAllListeners(t)));return this}removeAllListenersBut(...t){return 0===t.length?this.removeAllListeners():(Object.keys(this.normalListeners).forEach((e=>!t.includes(e)&&this.removeAllListeners(e))),Object.keys(this.captureListeners).forEach((e=>!t.includes(e)&&this.removeAllListeners(e))),this)}emit(t,...e){const[s,...r]=e;return this.getListenerList({event:t}).forEach((t=>{t(s,...r)})),this}}
1
+ import{isPassiveSupported,isDomEventTarget,isEventTargetLike,normalizeOptions}from"./EventEmitterListener.utils";function getEventTypeError(){return new Error("Event type can not be null.")}function getEventListenerError(){return new Error("Event listener can not be null.")}export class EventEmitterListener{target;interceptor;normalListeners={};captureListeners={};passiveSupported=isPassiveSupported();constructor(e,t){this.target=e,this.interceptor=t,this.target=e}createWrapper(e,t,r,...s){return(...n)=>{r&&this.off(e,t,...s);const i=this.interceptor&&this.interceptor(...n)||n;t(...i)}}getListenerList({event:e,type:t,wrapper:r}={}){const s="normal"===t&&this.normalListeners||"capture"===t&&this.captureListeners||void 0;if(s){const t=e?s[e]&&{[e]:s[e]}:s;return t?Object.values(t).flatMap((e=>e?Array.from(r?e.values():e.keys()):[])):[]}return this.getListenerList({event:e,type:"normal",wrapper:r}).concat(this.getListenerList({event:e,type:"capture",wrapper:r}))}getListeners({event:e,type:t,wrapper:r}={}){const s="normal"===t&&this.normalListeners||"capture"===t&&this.captureListeners||void 0;if(!s){const t=this.getListeners({event:e,type:"normal",wrapper:r}),s=this.getListeners({event:e,type:"capture",wrapper:r}),n={},i=([e,t])=>{const r=n[e];n[e]=r?r.concat(t):t};return Object.entries(t).forEach(i),Object.entries(s).forEach(i),n}const n=e?s[e]&&{[e]:s[e]}:s;return n?Object.entries(n).reduce(((e,[t,s])=>{const n=s?Array.from(r?s.values():s.keys()):[];return n.length>0&&(e[t]=n),e}),{}):{}}has(e,t,...r){if(!isDomEventTarget(this.target)){const r=this.normalListeners[e];return!!r&&(t?r.has(t):r.size>0)}const s=r[0],n=!0===s||s&&"object"==typeof s&&(s.capture??!1)?this.captureListeners[e]:this.normalListeners[e];return!!n&&(t?n.has(t):n.size>0)}on(e,t,...r){if(null==e)throw getEventTypeError();if(null==t)throw getEventListenerError();if(!isDomEventTarget(this.target)){const s=this.normalListeners[e]??new Map;this.normalListeners[e]=s;const n=s.get(t)??(this.interceptor?this.createWrapper(e,t,!1,...r):t);return!s.has(t)&&s.set(t,n),isEventTargetLike(this.target)?this.target.addEventListener(e,n,...r):this.target.on(e,n,...r),this}const s=r[0],n=!0===s||s&&"object"==typeof s&&(s.capture??!1),i=(s&&"object"==typeof s&&s.once)??!1;if(n){const n=this.captureListeners[e]??new Map;this.captureListeners[e]=n;const o=n.get(t)??this.createWrapper(e,t,i,...r);!n.has(t)&&n.set(t,o),this.target.addEventListener(e,o,normalizeOptions(s))}else{const n=this.normalListeners[e]??new Map;this.normalListeners[e]=n;const o=n.get(t)??this.createWrapper(e,t,i,...r);!n.has(t)&&n.set(t,o),this.target.addEventListener(e,o,normalizeOptions(s))}return this}once(e,t,...r){if(null==e)throw getEventTypeError();if(null==t)throw getEventListenerError();if(!isDomEventTarget(this.target)){const s=this.normalListeners[e]??new Map;this.normalListeners[e]=s;const n=s.get(t)??this.createWrapper(e,t,!0,...r);return!s.has(t)&&s.set(t,n),isEventTargetLike(this.target)?this.target.addEventListener(e,n,...r):this.target.once?this.target.once(e,n,...r):this.target.on(e,n,...r),this}const s=r[0];return this.on(e,t,{..."object"==typeof s?s:null!=s&&{capture:s},once:!0})}off(e,t,...r){if(!isDomEventTarget(this.target)){const s=this.normalListeners[e],n=s?.get(t);return s&&n&&s.delete(t),0===s?.size&&delete this.normalListeners[e],isEventTargetLike(this.target)?this.target.removeEventListener(e,n??t,...r):this.target.off(e,n??t,...r),this}const s=r[0],n=!0===s||s&&"object"==typeof s&&(s.capture??!1),i=n?this.captureListeners[e]:this.normalListeners[e],o=i?.get(t);return i&&o&&i.delete(t),0===i?.size&&(n?delete this.captureListeners[e]:delete this.normalListeners[e]),this.target.removeEventListener(e,o??t,normalizeOptions(s)),this}removeAllListeners(e){if(e){const t=this.normalListeners[e];t&&t.forEach(((t,r)=>this.off(e,r)));const r=this.captureListeners[e];r&&r.forEach(((t,r)=>this.off(e,r,!0)))}else Object.keys(this.normalListeners).forEach((e=>this.removeAllListeners(e))),Object.keys(this.captureListeners).forEach((e=>this.removeAllListeners(e)));return this}removeAllListenersBut(...e){return 0===e.length?this.removeAllListeners():(Object.keys(this.normalListeners).forEach((t=>!e.includes(t)&&this.removeAllListeners(t))),Object.keys(this.captureListeners).forEach((t=>!e.includes(t)&&this.removeAllListeners(t))),this)}emit(e,...t){if(null==e)throw getEventTypeError();const[r,...s]=t;return this.getListenerList({event:e,wrapper:!0}).forEach((e=>{e(r,...s)})),this}}
@@ -23,7 +23,7 @@ export type GetEventListener<T extends EmitterTarget, E, EM extends AnyObject =
23
23
  type ListenersMapToEventMap<T extends Record<string, AnyFunction[]>> = {
24
24
  [P in keyof T]: Parameters<T[P][number]>[0];
25
25
  };
26
- export type GetEventMap<T> = T extends Document ? DocumentEventMap : T extends HTMLBodyElement ? HTMLBodyElementEventMap : T extends HTMLVideoElement ? HTMLVideoElementEventMap : T extends HTMLMediaElement ? HTMLMediaElementEventMap : T extends TextTrackList ? TextTrackListEventMap : T extends HTMLElement ? HTMLElementEventMap : T extends Element ? ElementEventMap : T extends Animation ? AnimationEventMap : T extends AbortSignal ? AbortSignalEventMap : T extends BroadcastChannel ? BroadcastChannelEventMap : T extends WebSocket ? WebSocketEventMap : T extends MediaStreamTrack ? MediaStreamTrackEventMap : T extends MediaStream ? MediaStreamEventMap : T extends EventSource ? EventSourceEventMap : T extends SourceBuffer ? SourceBufferEventMap : T extends SourceBufferList ? SourceBufferListEventMap : T extends EventEmitter<any, any> ? ListenersMapToEventMap<ReturnType<T['getEventListeners']>> : EmptyObject;
26
+ export type GetEventMap<T> = T extends Window ? WindowEventMap : T extends ServiceWorker ? ServiceWorkerEventMap : T extends Worker ? WorkerEventMap : T extends ShadowRoot ? ShadowRootEventMap : T extends Document ? DocumentEventMap : T extends HTMLBodyElement ? HTMLBodyElementEventMap : T extends HTMLVideoElement ? HTMLVideoElementEventMap : T extends HTMLMediaElement ? HTMLMediaElementEventMap : T extends TextTrackList ? TextTrackListEventMap : T extends HTMLElement ? HTMLElementEventMap : T extends Element ? ElementEventMap : T extends TextTrackList ? TextTrackListEventMap : T extends TextTrackCue ? TextTrackCueEventMap : T extends Animation ? AnimationEventMap : T extends AbortSignal ? AbortSignalEventMap : T extends BroadcastChannel ? BroadcastChannelEventMap : T extends WebSocket ? WebSocketEventMap : T extends MediaStreamTrack ? MediaStreamTrackEventMap : T extends MediaStream ? MediaStreamEventMap : T extends EventSource ? EventSourceEventMap : T extends SourceBuffer ? SourceBufferEventMap : T extends SourceBufferList ? SourceBufferListEventMap : T extends RemotePlayback ? RemotePlaybackEventMap : T extends EventEmitter<any, any> ? ListenersMapToEventMap<ReturnType<T['getEventListeners']>> : EmptyObject;
27
27
  export declare function isEventTargetLike(target: EmitterTarget): target is EventTargetLike;
28
28
  export declare function isDomEventTarget(target: EmitterTarget): target is DomEventTarget;
29
29
  export declare function isEventEmitterLike(target: EmitterTarget): target is EventEmitterLike;
@@ -44,7 +44,7 @@ export declare namespace FullscreenController {
44
44
  Change = "change",
45
45
  Error = "error"
46
46
  }
47
- type EventMap = DefineAll<Events, {
47
+ type EventMap = EventEmitter.EventMap<DefineAll<Events, {
48
48
  [Events.Change]: [{
49
49
  fullscreen: boolean;
50
50
  type: FullscreenType;
@@ -53,7 +53,7 @@ export declare namespace FullscreenController {
53
53
  error: unknown;
54
54
  type: FullscreenType;
55
55
  }];
56
- }>;
56
+ }>, FullscreenController>;
57
57
  type EventHandler<T extends Events = Events> = EventEmitter.EventListener<EventMap, T, FullscreenController>;
58
58
  type EventHandlerMap<T extends Events = Events> = {
59
59
  [P in T]: EventHandler<P>;
package/README.md CHANGED
@@ -2,4 +2,40 @@
2
2
 
3
3
  [![npm package](https://img.shields.io/npm/v/@js-toolkit/web-utils.svg?style=flat-square)](https://www.npmjs.org/package/@js-toolkit/web-utils)
4
4
 
5
- Useful utils for browser environment.
5
+ A lightweight utility library for common operations in the browser environment. This package simplifies tasks such as DOM manipulation, event handling, and other browser-related utilities.
6
+
7
+ ## Installation
8
+
9
+ Install the library via npm:
10
+
11
+ ```bash
12
+ yarn add @js-toolkit/web-utils
13
+ # or
14
+ npm install @js-toolkit/web-utils
15
+ ```
16
+
17
+ # Usage
18
+
19
+ Here’s an example of how to use the library:
20
+
21
+ ```ts
22
+ import { getRandomID } from '@js-toolkit/web-utils/getRandomID';
23
+
24
+ const id = getRandomID();
25
+ ```
26
+
27
+ # Features
28
+
29
+ - Simplifies common browser tasks
30
+ - Lightweight and fast
31
+ - Easy to integrate with other JavaScript projects
32
+
33
+ # Contributing
34
+
35
+ Contributions are welcome! Please follow these steps:
36
+
37
+ 1. Fork the repository.
38
+ 1. Create a new branch (git checkout -b feature/my-feature-name).
39
+ 1. Commit your changes (git commit -m 'Add some feature').
40
+ 1. Push the branch (git push origin feature/my-feature-name).
41
+ 1. Open a pull request.
@@ -0,0 +1,9 @@
1
+ declare global {
2
+ interface PermissionDescriptorNew {
3
+ name: PermissionName | 'clipboard-write';
4
+ }
5
+ interface Permissions {
6
+ query(permissionDesc: PermissionDescriptorNew): Promise<PermissionStatus>;
7
+ }
8
+ }
9
+ export declare function checkPermission(name: PermissionDescriptorNew['name']): Promise<PermissionState | undefined>;
@@ -0,0 +1 @@
1
+ export async function checkPermission(t){try{return(await(navigator.permissions?.query?.({name:t}))).state}catch{}}
@@ -1 +1 @@
1
- import{getAwaiter}from"@js-toolkit/utils/getAwaiter";import{EventEmitterListener}from"./EventEmitterListener";import{isEventEmitterLike}from"./EventEmitterListener.utils";export function getEventAwaiter(e,t,r,{ignoreResolve:i,eventToError:o,lazy:n=!0,...s}={}){const E=getAwaiter({lazy:n,...s}),a=Array.isArray(t)?t:[t],f=Array.isArray(r)?r:[r],m=isEventEmitterLike(e)?e:new EventEmitterListener(e),v=e=>{!(!!i&&i(e))&&E.resolve(e)},c=e=>{const t=o?o(e):e;null!=t&&E.reject(t)},l=()=>{a.forEach((e=>m.off(e,v))),f.forEach((e=>m.off(e,c)))},A=E.resolve;E.resolve=(...e)=>(l(),A(...e));const y=E.reject;return E.reject=(...e)=>{y(...e),l()},a.forEach((e=>m.on(e,v))),f.forEach((e=>m.on(e,c))),E}
1
+ import{getAwaiter}from"@js-toolkit/utils/getAwaiter";import{EventEmitterListener}from"./EventEmitterListener";import{isEventEmitterLike}from"./EventEmitterListener.utils";export function getEventAwaiter(e,t,r,{ignoreResolve:i,eventToError:o,lazy:n=!0,...s}={}){const E=getAwaiter({lazy:n,...s}),a=Array.isArray(t)?t:[t],f=Array.isArray(r)&&r||r&&[r]||[],m=isEventEmitterLike(e)?e:new EventEmitterListener(e),v=e=>{!(!!i&&i(e))&&E.resolve(e)},c=e=>{const t=o?o(e):e;null!=t&&E.reject(t)},l=()=>{a.forEach((e=>m.off(e,v))),f.forEach((e=>m.off(e,c)))},A=E.resolve;E.resolve=(...e)=>(l(),A(...e));const y=E.reject;return E.reject=(...e)=>{y(...e),l()},a.forEach((e=>m.on(e,v))),f.forEach((e=>m.on(e,c))),E}
@@ -1 +1 @@
1
- import{isIOS}from"../../platform/isIOS";const DETACHED_GROUP_ID="__detached__";export function fakeDetachTextTracks(e){Array.prototype.forEach.call(e.textTracks,(e=>{const t=e;t.customGroupId&&(t.customGroupId="__detached__")}))}export function parseTextTracks(e){return 0===e.textTracks.length?[]:Array.prototype.reduce.call(e.textTracks,((e,{customGroupId:t,id:n,kind:r,language:l,label:a})=>("__detached__"!==t&&l&&e.push({id:n,kind:r,language:l,label:a??""}),e)),[])}export function isIOSFullscreen(e){return isIOS()&&!!e.webkitDisplayingFullscreen}export function findTextTrack(e,t){return Array.prototype.find.call(e.textTracks,(({mode:e,language:n})=>t.some((t=>!(null!=t.mode&&t.mode!==e||null!=t.language&&t.language!==n)))))}export function setActiveTextTrack(e,t,n){const{textTracks:r}=e;if(0===r.length)return!1;let l=!1,a=!1;for(let e=0;e<r.length;e+=1){const o=r[e];if(a||o.language!==t?.language||t.kind&&o.kind!==t.kind)"disabled"!==o.mode&&(o.mode="disabled",l=!0);else{const e=n?"hidden":"showing";o.mode=e,a=!0,l=!0}}return l}export function addTextTracks(e,t,n){const r=Array.prototype.reduce.call(e.textTracks,((e,t)=>(t.language&&(e[t.language]=t),e)),{});t.forEach((t=>{if(!r[t.language]){const r=document.createElement("track");r.src=t.src,r.srclang=t.language,r.label=t.label,r.kind=t.kind??"captions",r.default=!1,n(e.appendChild(r))}}))}export function buildCueId(e,t){return`${e.startTime}-${t}`}export function splitRows(e,t){if(t<=0)return e.split(/\r?\n/);const n=[];let r=0,l=r,a="";for(let o=0;o<=e.length;o+=1){const c=e[o];a.length>0&&r<l&&(n[l]=null==c?a.trim():a.trimStart(),a=""),r=l;let i=n[r]??"";if("\n"===c||"\r\n"===c)a.length>0&&i.length+a.length<=t&&(i+=i.length>0?a:a.trimStart(),a=""),l+=1;else if(" "===c){if(a.length>0){i.length+a.length>t&&i.length>0?(l+=1,i=i.trimEnd()):(i+=0===i.length?a.trimStart():a,a="")}a+=c}else if(null==c&&a.length>0){i.length+a.length>t&&0!==i.length?(r+=1,i=a.trim()):i+=a}else c&&(a+=c);n[r]=i}return n}
1
+ import{isIOS}from"../../platform/isIOS";const DETACHED_GROUP_ID="__detached__";export function fakeDetachTextTracks(t){Array.prototype.forEach.call(t.textTracks,(t=>{const e=t;e.customGroupId&&(e.customGroupId="__detached__")}))}export function parseTextTracks(t){return 0===t.textTracks.length?[]:Array.prototype.reduce.call(t.textTracks,((t,{customGroupId:e,id:n,kind:r,language:l,label:a})=>("__detached__"!==e&&l&&t.push({id:n,kind:r,language:l,label:a??""}),t)),[])}export function isIOSFullscreen(t){return isIOS()&&!!t.webkitDisplayingFullscreen}export function findTextTrack(t,e){return Array.prototype.find.call(t.textTracks,(({mode:t,language:n})=>e.some((e=>!(null!=e.mode&&e.mode!==t||null!=e.language&&e.language!==n)))))}export function setActiveTextTrack(t,e,n){const{textTracks:r}=t;if(0===r.length)return!1;let l=!1,a=!1;for(let t=0;t<r.length;t+=1){const o=r[t];if(a||o.language!==e?.language||e.kind&&o.kind!==e.kind)"disabled"!==o.mode&&(o.mode="disabled",l=!0);else{const t=n?"hidden":"showing";o.mode=t,a=!0,l=!0}}return l}export function addTextTracks(t,e,n){const r=new Set;for(const{language:e,kind:n}of t.textTracks)r.add(`${e} ${n}`);e.forEach((e=>{const l=e.kind??"subtitles";if(!r.has(`${e.language} ${l}`)){const r=document.createElement("track");r.src=e.src,r.srclang=e.language,r.label=e.label,r.kind=l,r.default=!1,n(t.appendChild(r))}}))}export function buildCueId(t,e){return`${t.startTime}-${e}`}export function splitRows(t,e){if(e<=0)return t.split(/\r?\n/);const n=[];let r=0,l=r,a="";for(let o=0;o<=t.length;o+=1){const i=t[o];a.length>0&&r<l&&(n[l]=null==i?a.trim():a.trimStart(),a=""),r=l;let c=n[r]??"";if("\n"===i||"\r\n"===i)a.length>0&&c.length+a.length<=e&&(c+=c.length>0?a:a.trimStart(),a=""),l+=1;else if(" "===i){if(a.length>0){c.length+a.length>e&&c.length>0?(l+=1,c=c.trimEnd()):(c+=0===c.length?a.trimStart():a,a="")}a+=i}else if(null==i&&a.length>0){c.length+a.length>e&&0!==c.length?(r+=1,c=a.trim()):c+=a}else i&&(a+=i);n[r]=c}return n}
@@ -1 +1 @@
1
- export function resetMedia(e){(e.src||e.srcObject||e.childElementCount>0)&&(URL.revokeObjectURL(e.src),e.removeAttribute("src"),e.srcObject=null,e.childElementCount>0&&Array.prototype.filter.call(e.children,(e=>e instanceof HTMLSourceElement)).forEach((r=>e.removeChild(r))),e.load())}
1
+ export function resetMedia(e){(e.src||e.srcObject||e.childElementCount>0)&&(URL.revokeObjectURL(e.src),e.removeAttribute("src"),e.srcObject=null,e.childElementCount>0&&Array.prototype.filter.call(e.children,(e=>e instanceof HTMLSourceElement)).forEach((r=>{URL.revokeObjectURL(r.src),e.removeChild(r)})),e.load())}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@js-toolkit/web-utils",
3
- "version": "1.63.0",
3
+ "version": "1.64.1",
4
4
  "description": "Web utils",
5
5
  "author": "VZH",
6
6
  "license": "MIT",
@@ -20,31 +20,30 @@
20
20
  "@js-toolkit/node-utils": "^1.2.1"
21
21
  },
22
22
  "devDependencies": {
23
- "@eslint/compat": "^1.2.6",
24
- "@eslint/eslintrc": "^3.2.0",
25
- "@eslint/js": "^9.20.0",
26
- "@js-toolkit/configs": "^3.94.0",
27
- "@js-toolkit/utils": "^1.59.1",
23
+ "@eslint/compat": "^1.2.9",
24
+ "@eslint/eslintrc": "^3.3.1",
25
+ "@eslint/js": "^9.27.0",
26
+ "@js-toolkit/configs": "^3.94.3",
27
+ "@js-toolkit/utils": "^1.59.2",
28
28
  "@types/eslint": "^9.6.1",
29
- "@types/eslint__eslintrc": "^2.1.2",
30
- "@types/eslint__js": "^8.42.3",
31
29
  "@types/lodash.throttle": "^4.1.9",
32
30
  "@types/uuid": "^10.0.0",
33
31
  "copyfiles": "^2.4.1",
34
- "eslint": "^9.20.1",
35
- "eslint-config-prettier": "^10.0.1",
32
+ "eslint": "^9.27.0",
33
+ "eslint-config-prettier": "^10.1.5",
34
+ "eslint-import-resolver-typescript": "^4.3.5",
36
35
  "eslint-plugin-import": "^2.31.0",
37
- "eslint-plugin-prettier": "^5.2.3",
36
+ "eslint-plugin-prettier": "^5.4.0",
38
37
  "lodash.throttle": "^4.1.1",
39
- "prettier": "^3.5.1",
38
+ "prettier": "^3.5.3",
40
39
  "reconnecting-websocket": "^4.4.0",
41
40
  "rimraf": "^6.0.1",
42
- "terser": "^5.39.0",
43
- "typescript": "^5.7.3",
44
- "typescript-eslint": "^8.24.1",
45
- "ua-parser-js": "^2.0.2",
41
+ "terser": "^5.39.2",
42
+ "typescript": "^5.8.3",
43
+ "typescript-eslint": "^8.32.1",
44
+ "ua-parser-js": "^2.0.3",
46
45
  "uuid": "^11.1.0",
47
- "webpack": "^5.98.0",
46
+ "webpack": "^5.99.8",
48
47
  "yargs": "^17.7.2"
49
48
  }
50
49
  }
@@ -0,0 +1,9 @@
1
+ type Methods = Pick<Console, 'debug' | 'error' | 'info' | 'log' | 'trace' | 'warn'>;
2
+ interface PatchConsoleLoggingOptions {
3
+ /** Defaults to 'replace'. */
4
+ readonly mode?: 'replace' | 'prepend' | 'append';
5
+ }
6
+ type CustomMethod = (level: keyof Methods, ...data: unknown[]) => void;
7
+ export declare function restoreConsoleLogging(): void;
8
+ export declare function patchConsoleLogging(customMethod: CustomMethod, { mode }?: PatchConsoleLoggingOptions): void;
9
+ export {};
@@ -0,0 +1 @@
1
+ const methods={debug:console.debug.bind(console),error:console.error.bind(console),info:console.info.bind(console),log:console.log.bind(console),trace:console.trace.bind(console),warn:console.warn.bind(console)};export function restoreConsoleLogging(){Object.entries(methods).forEach((([o,e])=>{console[o]=e}))}export function patchConsoleLogging(o,{mode:e="replace"}={}){restoreConsoleLogging(),Object.getOwnPropertyNames(methods).forEach((n=>{const s=n;console[s]=(...n)=>{"append"===e&&methods[s](...n),o(s,...n),"prepend"===e&&methods[s](...n)}}))}
@@ -0,0 +1,8 @@
1
+ export declare class Semver {
2
+ readonly major: number;
3
+ readonly minor: number;
4
+ readonly patch: number;
5
+ static parse(version: string): Semver | undefined;
6
+ constructor(major: number, minor: number, patch: number);
7
+ toString(): string;
8
+ }
@@ -0,0 +1 @@
1
+ export class Semver{major;minor;patch;static parse(t){const r=/(\d+)\.(\d+)(?:\.(\d+))?/.exec(t);if(!r)return;const s=parseInt(r[1],10)||0,e=parseInt(r[2],10)||0,n=parseInt(r[3],10)||0;return new Semver(s,e,n)}constructor(t,r,s){this.major=t,this.minor=r,this.patch=s}toString(){return`${this.major}_${this.minor}_${this.patch}`}}
@@ -1,8 +1,2 @@
1
- interface Semver {
2
- readonly major: number;
3
- readonly minor: number;
4
- readonly patch: number;
5
- toString(): string;
6
- }
1
+ import { Semver } from './Semver';
7
2
  export declare function getIOSVersion(): Semver | undefined;
8
- export {};
@@ -1 +1 @@
1
- import{getCachedPlatformInfo}from"./getPlatformInfo";import{isIOS}from"./isIOS";let memo;export function getIOSVersion(){if(void 0===memo){const o=getCachedPlatformInfo();if(!o)return;const{os:t}=o,r=isIOS()&&t.version&&/(\d+)\.(\d+)(?:\.(\d+))?/.exec(t.version);memo=r?{major:parseInt(r[1],10)||0,minor:parseInt(r[2],10)||0,patch:parseInt(r[3],10)||0,toString(){return`${this.major}_${this.minor}_${this.patch}`}}:null}return memo??void 0}
1
+ import{getCachedPlatformInfo}from"./getPlatformInfo";import{isIOS}from"./isIOS";import{Semver}from"./Semver";let memo;export function getIOSVersion(){if(void 0===memo){const o=getCachedPlatformInfo();if(!o)return;const{os:e}=o;memo=isIOS()&&e.version?Semver.parse(e.version):null}return memo??void 0}
@@ -1,8 +1,7 @@
1
1
  /// <reference types="ua-parser-js" preserve="true" />
2
- type PlatformInfo = DeepReadonly<OmitStrict<UAParser.IResult, 'withClientHints' | 'withFeatureCheck'>> & {
2
+ export type PlatformInfo = DeepReadonly<DeepExcludeKeysOfType<UAParser.IResult, AnyFunction>> & {
3
3
  toStringObject(): Record<Keys<ExcludeKeysOfType<UAParser.IResult, AnyFunction>>, string>;
4
4
  };
5
5
  export declare function getPlatformInfoSync(): PlatformInfo;
6
6
  export declare function getPlatformInfo(): Promise<PlatformInfo>;
7
7
  export declare function getCachedPlatformInfo(): PlatformInfo | undefined;
8
- export {};
@@ -4,7 +4,7 @@ import * as sdpUtils from './sdputils';
4
4
  export declare class PeerConnection extends EventEmitter<PeerConnection.EventMap, PeerConnection> implements Disposable {
5
5
  readonly options: PeerConnection.Options;
6
6
  get Events(): typeof PeerConnection.Events;
7
- readonly logger: Pick<log.Logger, "warn" | "debug">;
7
+ readonly logger: Pick<log.Logger, "debug" | "warn">;
8
8
  private pc;
9
9
  constructor(options?: PeerConnection.Options);
10
10
  private clear;
@@ -1 +1 @@
1
- import{EventEmitter}from"@js-toolkit/utils/EventEmitter";import{getErrorMessage}from"@js-toolkit/utils/getErrorMessage";import{hasIn}from"@js-toolkit/utils/hasIn";import log from"@js-toolkit/utils/log";import*as sdpUtils from"./sdputils";export class PeerConnection extends EventEmitter{options;get Events(){return PeerConnection.Events}logger;pc;constructor(e={}){super(),this.options=e,this.logger=e.logger??log.getLogger("PeerConnection"),this.pc=this.createPC()}clear(){this.pc.onsignalingstatechange=null,this.pc.onconnectionstatechange=null,this.pc.oniceconnectionstatechange=null,this.pc.ontrack=null,this.pc.onnegotiationneeded=null,this.pc.onicecandidate=null,this.pc.onicecandidateerror=null}createPC(){const e=new RTCPeerConnection(this.options.rtc);return e.onsignalingstatechange=()=>{this.logger.debug(`Signaling state changed to: ${e.signalingState}`),"closed"===e.signalingState&&(this.emit(this.Events.Closed),this.clear())},hasIn(RTCPeerConnection.prototype,"onconnectionstatechange")?e.onconnectionstatechange=()=>{this.logger.debug(`Connection state changed to: ${e.connectionState}`),"connected"===e.connectionState?this.emit(this.Events.Connected):"disconnected"===e.connectionState&&this.emit(this.Events.Disconnected)}:e.oniceconnectionstatechange=()=>{this.logger.debug(`ICE connection state changed to: ${e.iceConnectionState}`),"connected"===e.iceConnectionState?this.emit(this.Events.Connected):"disconnected"===e.iceConnectionState&&this.emit(this.Events.Disconnected)},e.ontrack=({streams:e,track:t})=>{if(this.logger.debug("Remote stream received.",e.length,t.kind),0===e.length)return;const[n]=e;n.onremovetrack=()=>{this.logger.debug("onremovetrack"),this.emit(this.Events.RemoteStreamChanged,n)},n.onaddtrack=()=>{this.logger.debug("onaddtrack"),this.emit(this.Events.RemoteStreamChanged,n)},this.emit(this.Events.RemoteStreamChanged,n)},e.onnegotiationneeded=()=>{const{iceConnectionState:t}=e;"connected"!==t&&"completed"!==t||(this.logger.debug("Reinitializing connection..."),this.emit(this.Events.ReinitializingConnectionRequired))},e.onicecandidate=({candidate:e})=>{e?sdpUtils.isValidIceCandidate(e)&&this.emit(this.Events.LocalIceCandidate,e):this.emit(this.Events.EndOfIceCandidates)},e.onicecandidateerror=e=>{if(e instanceof RTCPeerConnectionIceErrorEvent){const{errorCode:t,errorText:n,hostCandidate:i,url:o}=e;this.logger.warn(`ICE candidate error: errorCode=${t}, errorText=${n}, hostCandidate=${i}, url=${o}`)}else this.logger.warn(`ICE candidate error: ${getErrorMessage(e)}`)},e}async setLocalDescription(e,t){const n=sdpUtils.prepareLocalDescription(t,this.options.codecs);return await e.setLocalDescription(n),n}async setRemoteDescription(e,t){const n=sdpUtils.prepareRemoteDescription(t,this.options.codecs);return await e.setRemoteDescription(n),n}isConnected(){return"connected"===this.pc.iceConnectionState||"completed"===this.pc.iceConnectionState}isClosed(){return"closed"===this.pc.signalingState}addIceCandidate(e){return this.pc.addIceCandidate(e)}attachStream(e){const t=this.pc.getSenders(),n=t.length?e.getTracks().filter((e=>!t.find((({track:t})=>!!t&&t.id===e.id)))):e.getTracks();n.length?(n.forEach((t=>this.pc.addTrack(t,e))),this.logger.debug(`Attached ${n.length} track(s) to a peer connection.`)):this.logger.debug("No tracks to attach to a peer connection.")}reattachStream(e){const t=this.pc.iceConnectionState;if("new"!==t&&"connected"!==t&&"completed"!==t)return;const n=e?e.getTracks():[];this.pc.getSenders().forEach((e=>{const{track:t}=e;!t||"ended"!==t.readyState&&n.find((e=>e.id===t.id))||(this.pc.removeTrack(e),this.logger.debug(`'${t&&t.kind}' track is removed from a peer connection.`))})),e&&this.attachStream(e)}async createOffer(){const e=await this.pc.createOffer(this.options.offerOptions);return this.setLocalDescription(this.pc,e)}async createAnswer(e){await this.setRemoteDescription(this.pc,e);const t=await this.pc.createAnswer(this.options.offerOptions);return this.setLocalDescription(this.pc,t)}applyAnswer(e){return this.setRemoteDescription(this.pc,e)}reconnect(){this.close(),this.pc=this.createPC()}close(){this.pc.close(),this.pc.onsignalingstatechange&&(this.emit(this.Events.Closed),this.clear())}destroy(){this.close(),this.removeAllListeners()}[Symbol.dispose](){this.destroy()}}!function(e){let t;!function(e){e.LocalIceCandidate="LocalIceCandidate",e.EndOfIceCandidates="EndOfIceCandidates",e.Connected="Connected",e.Disconnected="Disconnected",e.RemoteStreamChanged="RemoteStreamChanged",e.ReinitializingConnectionRequired="ReinitializingConnectionRequired",e.Closed="Closed"}(t=e.Events||(e.Events={}))}(PeerConnection||(PeerConnection={}));
1
+ import{EventEmitter}from"@js-toolkit/utils/EventEmitter";import{getErrorMessage}from"@js-toolkit/utils/getErrorMessage";import{hasIn}from"@js-toolkit/utils/hasIn";import log from"@js-toolkit/utils/log";import*as sdpUtils from"./sdputils";export class PeerConnection extends EventEmitter{options;get Events(){return PeerConnection.Events}logger;pc;constructor(e={}){super(),this.options=e,this.logger=e.logger??log.getLogger("PeerConnection"),this.pc=this.createPC()}clear(){this.pc.onsignalingstatechange=null,this.pc.onconnectionstatechange=null,this.pc.oniceconnectionstatechange=null,this.pc.ontrack=null,this.pc.onnegotiationneeded=null,this.pc.onicecandidate=null,this.pc.onicecandidateerror=null}createPC(){const e=new RTCPeerConnection(this.options.rtc);e.onsignalingstatechange=()=>{this.logger.debug(`Signaling state changed to: ${e.signalingState}`),"closed"===e.signalingState&&(this.emit(this.Events.Closed),this.clear())};const t=e=>{this.logger.debug(`Connection state changed to: ${e}`),"connected"===e?this.emit(this.Events.Connected):"disconnected"===e&&this.emit(this.Events.Disconnected)};return hasIn(RTCPeerConnection.prototype,"onconnectionstatechange")?e.onconnectionstatechange=()=>t(e.connectionState):e.oniceconnectionstatechange=()=>t(e.iceConnectionState),e.ontrack=({streams:e,track:t})=>{if(this.logger.debug("Remote stream received.",e.length,t.kind),0===e.length)return;const[n]=e;n.onremovetrack=()=>{this.logger.debug("onremovetrack"),this.emit(this.Events.RemoteStreamChanged,n)},n.onaddtrack=()=>{this.logger.debug("onaddtrack"),this.emit(this.Events.RemoteStreamChanged,n)},this.emit(this.Events.RemoteStreamChanged,n)},e.onnegotiationneeded=()=>{const{iceConnectionState:t}=e;"connected"!==t&&"completed"!==t||(this.logger.debug("Reinitializing connection..."),this.emit(this.Events.ReinitializingConnectionRequired))},e.onicecandidate=({candidate:e})=>{e?sdpUtils.isValidIceCandidate(e)&&this.emit(this.Events.LocalIceCandidate,e):this.emit(this.Events.EndOfIceCandidates)},e.onicecandidateerror=e=>{if(e instanceof RTCPeerConnectionIceErrorEvent){const{errorCode:t,errorText:n,hostCandidate:i,url:o}=e;this.logger.warn(`ICE candidate error: errorCode=${t}, errorText=${n}, hostCandidate=${i}, url=${o}`)}else this.logger.warn(`ICE candidate error: ${getErrorMessage(e)}`)},e}async setLocalDescription(e,t){const n=sdpUtils.prepareLocalDescription(t,this.options.codecs);return await e.setLocalDescription(n),n}async setRemoteDescription(e,t){const n=sdpUtils.prepareRemoteDescription(t,this.options.codecs);return await e.setRemoteDescription(n),n}isConnected(){return"connected"===this.pc.iceConnectionState||"completed"===this.pc.iceConnectionState}isClosed(){return"closed"===this.pc.signalingState}addIceCandidate(e){return this.pc.addIceCandidate(e)}attachStream(e){const t=this.pc.getSenders(),n=t.length?e.getTracks().filter((e=>!t.find((({track:t})=>!!t&&t.id===e.id)))):e.getTracks();n.length?(n.forEach((t=>this.pc.addTrack(t,e))),this.logger.debug(`Attached ${n.length} track(s) to a peer connection.`)):this.logger.debug("No tracks to attach to a peer connection.")}reattachStream(e){const t=this.pc.iceConnectionState;if("new"!==t&&"connected"!==t&&"completed"!==t)return;const n=e?e.getTracks():[];this.pc.getSenders().forEach((e=>{const{track:t}=e;!t||"ended"!==t.readyState&&n.find((e=>e.id===t.id))||(this.pc.removeTrack(e),this.logger.debug(`'${t&&t.kind}' track is removed from a peer connection.`))})),e&&this.attachStream(e)}async createOffer(){const e=await this.pc.createOffer(this.options.offerOptions);return this.setLocalDescription(this.pc,e)}async createAnswer(e){await this.setRemoteDescription(this.pc,e);const t=await this.pc.createAnswer(this.options.offerOptions);return this.setLocalDescription(this.pc,t)}applyAnswer(e){return this.setRemoteDescription(this.pc,e)}reconnect(){this.close(),this.pc=this.createPC()}close(){this.pc.close(),this.pc.onsignalingstatechange&&(this.emit(this.Events.Closed),this.clear())}destroy(){this.close(),this.removeAllListeners()}[Symbol.dispose](){this.destroy()}}!function(e){let t;!function(e){e.LocalIceCandidate="LocalIceCandidate",e.EndOfIceCandidates="EndOfIceCandidates",e.Connected="Connected",e.Disconnected="Disconnected",e.RemoteStreamChanged="RemoteStreamChanged",e.ReinitializingConnectionRequired="ReinitializingConnectionRequired",e.Closed="Closed"}(t=e.Events||(e.Events={}))}(PeerConnection||(PeerConnection={}));