@sv443-network/userutils 7.0.1 → 7.2.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.
@@ -0,0 +1,104 @@
1
+ import { NanoEmitter } from "./NanoEmitter.js";
2
+ export declare const defaultDialogCss: string;
3
+ /** ID of the last opened (top-most) dialog */
4
+ export declare let currentDialogId: string | null;
5
+ /** IDs of all currently open dialogs, top-most first */
6
+ export declare const openDialogs: string[];
7
+ export declare const defaultStrings: {
8
+ closeDialogTooltip: string;
9
+ };
10
+ /** Options passed to the Dialog constructor */
11
+ export interface DialogOptions {
12
+ /** ID that gets added to child element IDs - has to be unique and conform to HTML ID naming rules! */
13
+ id: string;
14
+ /** Target and max width of the dialog in pixels */
15
+ width: number;
16
+ /** Target and max height of the dialog in pixels */
17
+ height: number;
18
+ /** Whether the dialog should close when the background is clicked - defaults to true */
19
+ closeOnBgClick?: boolean;
20
+ /** Whether the dialog should close when the escape key is pressed - defaults to true */
21
+ closeOnEscPress?: boolean;
22
+ /** Whether the dialog should be destroyed when it's closed - defaults to false */
23
+ destroyOnClose?: boolean;
24
+ /** Whether the dialog should be unmounted when it's closed - defaults to true - superseded by destroyOnClose */
25
+ unmountOnClose?: boolean;
26
+ /** Whether all listeners should be removed when the dialog is destroyed - defaults to true */
27
+ removeListenersOnDestroy?: boolean;
28
+ /** Whether the dialog should have a smaller overall appearance - defaults to false */
29
+ small?: boolean;
30
+ /** Where to align or anchor the dialog vertically - defaults to "center" */
31
+ verticalAlign?: "top" | "center" | "bottom";
32
+ /** Strings used in the dialog (used for translations) - defaults to the default English strings */
33
+ strings?: Partial<typeof defaultStrings>;
34
+ /** CSS to apply to the dialog - defaults to the {@linkcode defaultDialogCss} */
35
+ dialogCss?: string;
36
+ /** Called to render the body of the dialog */
37
+ renderBody: () => HTMLElement | Promise<HTMLElement>;
38
+ /** Called to render the header of the dialog - leave undefined for a blank header */
39
+ renderHeader?: () => HTMLElement | Promise<HTMLElement>;
40
+ /** Called to render the footer of the dialog - leave undefined for no footer */
41
+ renderFooter?: () => HTMLElement | Promise<HTMLElement>;
42
+ /** Called to render the close button of the dialog - leave undefined for no close button */
43
+ renderCloseBtn?: () => HTMLElement | Promise<HTMLElement>;
44
+ }
45
+ /** Creates and manages a modal dialog element */
46
+ export declare class Dialog extends NanoEmitter<{
47
+ /** Emitted just **after** the dialog is closed */
48
+ close: () => void;
49
+ /** Emitted just **after** the dialog is opened */
50
+ open: () => void;
51
+ /** Emitted just **after** the dialog contents are rendered */
52
+ render: () => void;
53
+ /** Emitted just **after** the dialog contents are cleared */
54
+ clear: () => void;
55
+ /** Emitted just **after** the dialog is destroyed and **before** all listeners are removed */
56
+ destroy: () => void;
57
+ }> {
58
+ /** Options passed to the dialog in the constructor */
59
+ readonly options: DialogOptions;
60
+ /** ID that gets added to child element IDs - has to be unique and conform to HTML ID naming rules! */
61
+ readonly id: string;
62
+ /** Strings used in the dialog (used for translations) */
63
+ strings: typeof defaultStrings;
64
+ protected dialogOpen: boolean;
65
+ protected dialogMounted: boolean;
66
+ constructor(options: DialogOptions);
67
+ /** Call after DOMContentLoaded to pre-render the dialog and invisibly mount it in the DOM */
68
+ mount(): Promise<HTMLElement | void>;
69
+ /** Closes the dialog and clears all its contents (unmounts elements from the DOM) in preparation for a new rendering call */
70
+ unmount(): void;
71
+ /** Clears the DOM of the dialog and then renders it again */
72
+ remount(): Promise<void>;
73
+ /**
74
+ * Opens the dialog - also mounts it if it hasn't been mounted yet
75
+ * Prevents default action and immediate propagation of the passed event
76
+ */
77
+ open(e?: MouseEvent | KeyboardEvent): Promise<HTMLElement | void>;
78
+ /** Closes the dialog - prevents default action and immediate propagation of the passed event */
79
+ close(e?: MouseEvent | KeyboardEvent): void;
80
+ /** Returns true if the dialog is currently open */
81
+ isOpen(): boolean;
82
+ /** Returns true if the dialog is currently mounted */
83
+ isMounted(): boolean;
84
+ /** Clears the DOM of the dialog and removes all event listeners */
85
+ destroy(): void;
86
+ /** Returns the ID of the top-most dialog (the dialog that has been opened last) */
87
+ static getCurrentDialogId(): string | null;
88
+ /** Returns the IDs of all currently open dialogs, top-most first */
89
+ static getOpenDialogs(): string[];
90
+ protected getString(key: keyof typeof defaultStrings): string;
91
+ /** Called once to attach all generic event listeners */
92
+ protected attachListeners(bgElem: HTMLElement): void;
93
+ /**
94
+ * Adds generic, accessible interaction listeners to the passed element.
95
+ * All listeners have the default behavior prevented and stop propagation (for keyboard events only as long as the captured key is valid).
96
+ * @param listenerOptions Provide a {@linkcode listenerOptions} object to configure the listeners
97
+ */
98
+ protected onInteraction<TElem extends HTMLElement>(elem: TElem, listener: (evt: MouseEvent | KeyboardEvent) => void, listenerOptions?: AddEventListenerOptions & {
99
+ preventDefault?: boolean;
100
+ stopPropagation?: boolean;
101
+ }): void;
102
+ /** Returns the dialog content element and all its children */
103
+ protected getDialogContent(): Promise<HTMLElement>;
104
+ }
@@ -0,0 +1,20 @@
1
+ import { type DefaultEvents, type Emitter, type EventsMap, type Unsubscribe } from "nanoevents";
2
+ export interface NanoEmitterOptions {
3
+ /** If set to true, allows emitting events through the public method emit() */
4
+ publicEmit: boolean;
5
+ }
6
+ /** Class that can be extended or instantiated by itself to create an event emitter with helper methods and a strongly typed event map */
7
+ export declare class NanoEmitter<TEvtMap extends EventsMap = DefaultEvents> {
8
+ protected readonly events: Emitter<TEvtMap>;
9
+ protected eventUnsubscribes: Unsubscribe[];
10
+ protected emitterOptions: NanoEmitterOptions;
11
+ constructor(options?: Partial<NanoEmitterOptions>);
12
+ /** Subscribes to an event - returns a function that unsubscribes the event listener */
13
+ on<TKey extends keyof TEvtMap>(event: TKey | "_", cb: TEvtMap[TKey]): () => void;
14
+ /** Subscribes to an event and calls the callback or resolves the Promise only once */
15
+ once<TKey extends keyof TEvtMap>(event: TKey | "_", cb?: TEvtMap[TKey]): Promise<Parameters<TEvtMap[TKey]>>;
16
+ /** Emits an event on this instance - Needs `publicEmit` to be set to true in the constructor! */
17
+ emit<TKey extends keyof TEvtMap>(event: TKey, ...args: Parameters<TEvtMap[TKey]>): boolean;
18
+ /** Unsubscribes all event listeners */
19
+ unsubscribeAll(): void;
20
+ }
@@ -0,0 +1,18 @@
1
+ /** Converts a hex color string to a tuple of RGB values */
2
+ export declare function hexToRgb(hex: string): [red: number, green: number, blue: number];
3
+ /** Converts RGB values to a hex color string */
4
+ export declare function rgbToHex(red: number, green: number, blue: number, withHash?: boolean, upperCase?: boolean): string;
5
+ /**
6
+ * Lightens a CSS color value (in hex, RGB or RGBA format) by a given percentage.
7
+ * Will not exceed the maximum range (00-FF or 0-255).
8
+ * @returns Returns the new color value in the same format as the input
9
+ * @throws Throws if the color format is invalid or not supported
10
+ */
11
+ export declare function lightenColor(color: string, percent: number): string;
12
+ /**
13
+ * Darkens a CSS color value (in hex, RGB or RGBA format) by a given percentage.
14
+ * Will not exceed the maximum range (00-FF or 0-255).
15
+ * @returns Returns the new color value in the same format as the input
16
+ * @throws Throws if the color format is invalid or not supported
17
+ */
18
+ export declare function darkenColor(color: string, percent: number): string;
@@ -0,0 +1,24 @@
1
+ /** Compresses a string or an ArrayBuffer using the provided {@linkcode compressionFormat} and returns it as a base64 string */
2
+ export declare function compress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType?: "string"): Promise<string>;
3
+ /** Compresses a string or an ArrayBuffer using the provided {@linkcode compressionFormat} and returns it as an ArrayBuffer */
4
+ export declare function compress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType: "arrayBuffer"): Promise<ArrayBuffer>;
5
+ /** Decompresses a previously compressed base64 string or ArrayBuffer, with the format passed by {@linkcode compressionFormat}, converted to a string */
6
+ export declare function decompress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType?: "string"): Promise<string>;
7
+ /** Decompresses a previously compressed base64 string or ArrayBuffer, with the format passed by {@linkcode compressionFormat}, converted to an ArrayBuffer */
8
+ export declare function decompress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType: "arrayBuffer"): Promise<ArrayBuffer>;
9
+ /**
10
+ * Creates a hash / checksum of the given {@linkcode input} string or ArrayBuffer using the specified {@linkcode algorithm} ("SHA-256" by default).
11
+ *
12
+ * ⚠️ Uses the SubtleCrypto API so it needs to run in a secure context (HTTPS).
13
+ * ⚠️ If you use this for cryptography, make sure to use a secure algorithm (under no circumstances use SHA-1) and to [salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) your input data.
14
+ */
15
+ export declare function computeHash(input: string | ArrayBuffer, algorithm?: string): Promise<string>;
16
+ /**
17
+ * Generates a random ID with the specified length and radix (16 characters and hexadecimal by default)
18
+ *
19
+ * ⚠️ Not suitable for generating anything related to cryptography! Use [SubtleCrypto's `generateKey()`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey) for that instead.
20
+ * @param length The length of the ID to generate (defaults to 16)
21
+ * @param radix The [radix](https://en.wikipedia.org/wiki/Radix) of each digit (defaults to 16 which is hexadecimal. Use 2 for binary, 10 for decimal, 36 for alphanumeric, etc.)
22
+ * @param enhancedEntropy If set to true, uses [`crypto.getRandomValues()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) for better cryptographic randomness (this also makes it take MUCH longer to generate)
23
+ */
24
+ export declare function randomId(length?: number, radix?: number, enhancedEntropy?: boolean): string;
package/dist/lib/dom.d.ts CHANGED
@@ -63,3 +63,11 @@ export declare function observeElementProp<TElem extends Element = HTMLElement,
63
63
  * @returns An array of sibling elements
64
64
  */
65
65
  export declare function getSiblingsFrame<TSibling extends Element = HTMLElement>(refElement: Element, siblingAmount: number, refElementAlignment?: "center-top" | "center-bottom" | "top" | "bottom", includeRef?: boolean): TSibling[];
66
+ /**
67
+ * Sets the innerHTML property of the provided element without any sanitation or validation.
68
+ * Uses a [Trusted Types policy](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API) on Chromium-based browsers to trick the browser into thinking the HTML is safe.
69
+ * Use this if the page makes use of the CSP directive `require-trusted-types-for 'script'` and throws a "This document requires 'TrustedHTML' assignment" error on Chromium-based browsers.
70
+ *
71
+ * ⚠️ This function does not perform any sanitization and should thus be used with utmost caution, as it can easily lead to XSS vulnerabilities!
72
+ */
73
+ export declare function setInnerHtmlUnsafe<TElement extends Element = HTMLElement>(element: TElement, html: string): TElement;
@@ -1,9 +1,12 @@
1
1
  export * from "./array.js";
2
+ export * from "./crypto.js";
2
3
  export * from "./DataStore.js";
3
4
  export * from "./DataStoreSerializer.js";
5
+ export * from "./Dialog.js";
4
6
  export * from "./dom.js";
5
7
  export * from "./math.js";
6
8
  export * from "./misc.js";
9
+ export * from "./NanoEmitter.js";
7
10
  export * from "./SelectorObserver.js";
8
11
  export * from "./translation.js";
9
12
  export * from "./types.js";
@@ -5,6 +5,13 @@ import type { Stringifiable } from "./types.js";
5
5
  * @param num If this is an array or NodeList, the amount of items is used
6
6
  */
7
7
  export declare function autoPlural(word: Stringifiable, num: number | unknown[] | NodeList): string;
8
+ /**
9
+ * Inserts the passed values into a string at the respective placeholders.
10
+ * The placeholder format is `%n`, where `n` is the 1-indexed argument number.
11
+ * @param input The string to insert the values into
12
+ * @param values The values to insert, in order, starting at `%1`
13
+ */
14
+ export declare function insertValues(input: string, ...values: Stringifiable[]): string;
8
15
  /** Pauses async execution for the specified time in ms */
9
16
  export declare function pauseFor(time: number): Promise<void>;
10
17
  /**
@@ -23,34 +30,3 @@ export type FetchAdvancedOpts = Omit<RequestInit & Partial<{
23
30
  }>, "signal">;
24
31
  /** Calls the fetch API with special options like a timeout */
25
32
  export declare function fetchAdvanced(input: RequestInfo | URL, options?: FetchAdvancedOpts): Promise<Response>;
26
- /**
27
- * Inserts the passed values into a string at the respective placeholders.
28
- * The placeholder format is `%n`, where `n` is the 1-indexed argument number.
29
- * @param input The string to insert the values into
30
- * @param values The values to insert, in order, starting at `%1`
31
- */
32
- export declare function insertValues(input: string, ...values: Stringifiable[]): string;
33
- /** Compresses a string or an ArrayBuffer using the provided {@linkcode compressionFormat} and returns it as a base64 string */
34
- export declare function compress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType?: "string"): Promise<string>;
35
- /** Compresses a string or an ArrayBuffer using the provided {@linkcode compressionFormat} and returns it as an ArrayBuffer */
36
- export declare function compress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType: "arrayBuffer"): Promise<ArrayBuffer>;
37
- /** Decompresses a previously compressed base64 string or ArrayBuffer, with the format passed by {@linkcode compressionFormat}, converted to a string */
38
- export declare function decompress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType?: "string"): Promise<string>;
39
- /** Decompresses a previously compressed base64 string or ArrayBuffer, with the format passed by {@linkcode compressionFormat}, converted to an ArrayBuffer */
40
- export declare function decompress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType: "arrayBuffer"): Promise<ArrayBuffer>;
41
- /**
42
- * Creates a hash / checksum of the given {@linkcode input} string or ArrayBuffer using the specified {@linkcode algorithm} ("SHA-256" by default).
43
- *
44
- * ⚠️ Uses the SubtleCrypto API so it needs to run in a secure context (HTTPS).
45
- * ⚠️ If you use this for cryptography, make sure to use a secure algorithm (under no circumstances use SHA-1) and to [salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) your input data.
46
- */
47
- export declare function computeHash(input: string | ArrayBuffer, algorithm?: string): Promise<string>;
48
- /**
49
- * Generates a random ID with the specified length and radix (16 characters and hexadecimal by default)
50
- *
51
- * ⚠️ Not suitable for generating anything related to cryptography! Use [SubtleCrypto's `generateKey()`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey) for that instead.
52
- * @param length The length of the ID to generate (defaults to 16)
53
- * @param radix The [radix](https://en.wikipedia.org/wiki/Radix) of each digit (defaults to 16 which is hexadecimal. Use 2 for binary, 10 for decimal, 36 for alphanumeric, etc.)
54
- * @param enhancedEntropy If set to true, uses [`crypto.getRandomValues()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) for better cryptographic randomness (this also makes it take MUCH longer to generate)
55
- */
56
- export declare function randomId(length?: number, radix?: number, enhancedEntropy?: boolean): string;
@@ -1,3 +1,13 @@
1
+ export type TrustedTypesPolicy = {
2
+ createHTML?: (dirty: string) => string;
3
+ };
4
+ declare global {
5
+ interface Window {
6
+ trustedTypes: {
7
+ createPolicy(name: string, policy: TrustedTypesPolicy): TrustedTypesPolicy;
8
+ };
9
+ }
10
+ }
1
11
  /** Represents any value that is either a string itself or can be converted to one (implicitly and explicitly) because it has a toString() method */
2
12
  export type Stringifiable = string | {
3
13
  toString(): string;
package/package.json CHANGED
@@ -1,20 +1,24 @@
1
1
  {
2
2
  "name": "@sv443-network/userutils",
3
3
  "libName": "UserUtils",
4
- "version": "7.0.1",
4
+ "version": "7.2.0",
5
5
  "description": "Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, create persistent & synchronous data stores, modify the DOM more easily and more",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
8
8
  "types": "dist/lib/index.d.ts",
9
+ "type": "module",
9
10
  "scripts": {
10
11
  "lint": "tsc --noEmit && eslint .",
11
12
  "build-types": "tsc --emitDeclarationOnly --declaration --outDir dist",
12
13
  "build-common": "tsup lib/index.ts --format cjs,esm --clean --treeshake",
13
- "build-all": "tsup lib/index.ts --format cjs,esm,iife --treeshake --onSuccess \"npm run post-build-global && echo Finished building.\"",
14
+ "build-all": "tsup lib/index.ts --format cjs,esm,iife --treeshake --onSuccess \"npm run build-types && npm run post-build-global && echo Finished building.\"",
14
15
  "build": "npm run build-common -- && npm run build-types",
15
16
  "post-build-global": "npm run node-ts -- ./tools/post-build-global.mts",
16
17
  "dev": "npm run build-common -- --sourcemap --watch --onSuccess \"npm run build-types && echo Finished building.\"",
18
+ "dev-all": "npm run build-all -- --watch",
19
+ "update-jsr-version": "npm run node-ts -- ./tools/update-jsr-version.mts",
17
20
  "publish-package": "changeset publish",
21
+ "publish-package-jsr": "npm run update-jsr-version && npx jsr publish",
18
22
  "node-ts": "node --no-warnings=ExperimentalWarning --enable-source-maps --loader ts-node/esm",
19
23
  "test-serve": "npm run node-ts -- ./test/TestPage/server.mts",
20
24
  "test-dev": "cd test/TestScript && npm run dev",
@@ -37,6 +41,9 @@
37
41
  "url": "https://github.com/Sv443-Network/UserUtils/issues"
38
42
  },
39
43
  "homepage": "https://github.com/Sv443-Network/UserUtils",
44
+ "dependencies": {
45
+ "nanoevents": "^9.0.0"
46
+ },
40
47
  "devDependencies": {
41
48
  "@changesets/cli": "^2.26.2",
42
49
  "@types/express": "^4.17.19",