@sv443-network/userutils 8.3.3 → 9.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.
@@ -1,67 +1,64 @@
1
- /// <reference types="greasemonkey" />
2
1
  import type { Prettify } from "./types.js";
3
- /** Function that takes the data in the old format and returns the data in the new format. Also supports an asynchronous migration. */
4
- type MigrationFunc = (oldData: any) => any | Promise<any>;
5
2
  /** Dictionary of format version numbers and the function that migrates to them from the previous whole integer */
6
- export type DataMigrationsDict = Record<number, MigrationFunc>;
3
+ export type DataMigrationsDict = Record<number, ((oldData: unknown) => unknown | Promise<unknown>)>;
7
4
  /** Options for the DataStore instance */
8
5
  export type DataStoreOptions<TData> = Prettify<{
9
6
  /**
10
- * A unique internal ID for this data store.
11
- * To avoid conflicts with other scripts, it is recommended to use a prefix that is unique to your script.
12
- * If you want to change the ID, you should make use of the {@linkcode DataStore.migrateId()} method.
7
+ * A unique internal ID for this data store.
8
+ * To avoid conflicts with other scripts, it is recommended to use a prefix that is unique to your script.
9
+ * If you want to change the ID, you should make use of the {@linkcode DataStore.migrateId()} method.
13
10
  */
14
11
  id: string;
15
12
  /**
16
- * The default data object to use if no data is saved in persistent storage yet.
17
- * Until the data is loaded from persistent storage with {@linkcode DataStore.loadData()}, this will be the data returned by {@linkcode DataStore.getData()}.
18
- *
19
- * ⚠️ This has to be an object that can be serialized to JSON using `JSON.stringify()`, so no functions or circular references are allowed, they will cause unexpected behavior.
13
+ * The default data object to use if no data is saved in persistent storage yet.
14
+ * Until the data is loaded from persistent storage with {@linkcode DataStore.loadData()}, this will be the data returned by {@linkcode DataStore.getData()}.
15
+ *
16
+ * - ⚠️ This has to be an object that can be serialized to JSON using `JSON.stringify()`, so no functions or circular references are allowed, they will cause unexpected behavior.
20
17
  */
21
18
  defaultData: TData;
22
19
  /**
23
- * An incremental, whole integer version number of the current format of data.
24
- * If the format of the data is changed in any way, this number should be incremented, in which case all necessary functions of the migrations dictionary will be run consecutively.
25
- *
26
- * ⚠️ Never decrement this number and optimally don't skip any numbers either!
20
+ * An incremental, whole integer version number of the current format of data.
21
+ * If the format of the data is changed in any way, this number should be incremented, in which case all necessary functions of the migrations dictionary will be run consecutively.
22
+ *
23
+ * - ⚠️ Never decrement this number and optimally don't skip any numbers either!
27
24
  */
28
25
  formatVersion: number;
29
26
  /**
30
- * A dictionary of functions that can be used to migrate data from older versions to newer ones.
31
- * The keys of the dictionary should be the format version that the functions can migrate to, from the previous whole integer value.
32
- * The values should be functions that take the data in the old format and return the data in the new format.
33
- * The functions will be run in order from the oldest to the newest version.
34
- * If the current format version is not in the dictionary, no migrations will be run.
27
+ * A dictionary of functions that can be used to migrate data from older versions to newer ones.
28
+ * The keys of the dictionary should be the format version that the functions can migrate to, from the previous whole integer value.
29
+ * The values should be functions that take the data in the old format and return the data in the new format.
30
+ * The functions will be run in order from the oldest to the newest version.
31
+ * If the current format version is not in the dictionary, no migrations will be run.
35
32
  */
36
33
  migrations?: DataMigrationsDict;
37
34
  /**
38
- * If an ID or multiple IDs are passed here, the data will be migrated from the old ID(s) to the current ID.
39
- * This will happen once per page load, when {@linkcode DataStore.loadData()} is called.
40
- * All future calls to {@linkcode DataStore.loadData()} in the session will not check for the old ID(s) anymore.
41
- * To migrate IDs manually, use the method {@linkcode DataStore.migrateId()} instead.
35
+ * If an ID or multiple IDs are passed here, the data will be migrated from the old ID(s) to the current ID.
36
+ * This will happen once per page load, when {@linkcode DataStore.loadData()} is called.
37
+ * All future calls to {@linkcode DataStore.loadData()} in the session will not check for the old ID(s) anymore.
38
+ * To migrate IDs manually, use the method {@linkcode DataStore.migrateId()} instead.
42
39
  */
43
40
  migrateIds?: string | string[];
44
41
  /**
45
- * Where the data should be saved (`"GM"` by default).
46
- * The protected methods {@linkcode DataStore.getValue()}, {@linkcode DataStore.setValue()} and {@linkcode DataStore.deleteValue()} are used to interact with the storage.
47
- * `"GM"` storage, `"localStorage"` and `"sessionStorage"` are supported out of the box, but in an extended class you can overwrite those methods to implement any other storage method.
42
+ * Where the data should be saved (`"GM"` by default).
43
+ * The protected methods {@linkcode DataStore.getValue()}, {@linkcode DataStore.setValue()} and {@linkcode DataStore.deleteValue()} are used to interact with the storage.
44
+ * `"GM"` storage, `"localStorage"` and `"sessionStorage"` are supported out of the box, but in an extended class you can overwrite those methods to implement any other storage method.
48
45
  */
49
46
  storageMethod?: "GM" | "localStorage" | "sessionStorage";
50
47
  } & ({
51
48
  /**
52
- * Function to use to encode the data prior to saving it in persistent storage.
53
- * If this is specified, make sure to declare {@linkcode decodeData()} as well.
54
- *
55
- * You can make use of UserUtils' [`compress()`](https://github.com/Sv443-Network/UserUtils?tab=readme-ov-file#compress) function here to make the data use up less space at the cost of a little bit of performance.
56
- * @param data The input data as a serialized object (JSON string)
49
+ * Function to use to encode the data prior to saving it in persistent storage.
50
+ * If this is specified, make sure to declare {@linkcode decodeData()} as well.
51
+ *
52
+ * You can make use of UserUtils' [`compress()`](https://github.com/Sv443-Network/UserUtils?tab=readme-ov-file#compress) function here to make the data use up less space at the cost of a little bit of performance.
53
+ * @param data The input data as a serialized object (JSON string)
57
54
  */
58
55
  encodeData: (data: string) => string | Promise<string>;
59
56
  /**
60
- * Function to use to decode the data after reading it from persistent storage.
61
- * If this is specified, make sure to declare {@linkcode encodeData()} as well.
62
- *
63
- * You can make use of UserUtils' [`decompress()`](https://github.com/Sv443-Network/UserUtils?tab=readme-ov-file#decompress) function here to make the data use up less space at the cost of a little bit of performance.
64
- * @returns The resulting data as a valid serialized object (JSON string)
57
+ * Function to use to decode the data after reading it from persistent storage.
58
+ * If this is specified, make sure to declare {@linkcode encodeData()} as well.
59
+ *
60
+ * You can make use of UserUtils' [`decompress()`](https://github.com/Sv443-Network/UserUtils?tab=readme-ov-file#decompress) function here to make the data use up less space at the cost of a little bit of performance.
61
+ * @returns The resulting data as a valid serialized object (JSON string)
65
62
  */
66
63
  decodeData: (data: string) => string | Promise<string>;
67
64
  } | {
@@ -69,18 +66,18 @@ export type DataStoreOptions<TData> = Prettify<{
69
66
  decodeData?: never;
70
67
  })>;
71
68
  /**
72
- * Manages a hybrid synchronous & asynchronous persistent JSON database that is cached in memory and persistently saved across sessions using [GM storage](https://wiki.greasespot.net/GM.setValue) (default), [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) or [sessionStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage).
73
- * Supports migrating data from older format versions to newer ones and populating the cache with default data if no persistent data is found.
74
- * Can be overridden to implement any other storage method.
75
- *
76
- * All methods are at least `protected`, so you can easily extend this class and overwrite them to use a different storage method or to add additional functionality.
77
- * Remember that you can call `super.methodName()` in the subclass to access the original method.
78
- *
79
- * ⚠️ The stored data has to be **serializable using `JSON.stringify()`**, meaning no undefined, circular references, etc. are allowed.
80
- * ⚠️ If the storageMethod is left as the default of `"GM"` the directives `@grant GM.getValue` and `@grant GM.setValue` are required. If you then also use the method {@linkcode DataStore.deleteData()}, the extra directive `@grant GM.deleteValue` is needed too.
81
- * ⚠️ Make sure to call {@linkcode loadData()} at least once after creating an instance, or the returned data will be the same as `options.defaultData`
82
- *
83
- * @template TData The type of the data that is saved in persistent storage for the currently set format version (will be automatically inferred from `defaultData` if not provided)
69
+ * Manages a hybrid synchronous & asynchronous persistent JSON database that is cached in memory and persistently saved across sessions using [GM storage](https://wiki.greasespot.net/GM.setValue) (default), [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) or [sessionStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage).
70
+ * Supports migrating data from older format versions to newer ones and populating the cache with default data if no persistent data is found.
71
+ * Can be overridden to implement any other storage method.
72
+ *
73
+ * All methods are `protected` or `public`, so you can easily extend this class and overwrite them to use a different storage method or to add other functionality.
74
+ * Remember that you can use `super.methodName()` in the subclass to call the original method if needed.
75
+ *
76
+ * - ⚠️ The data is stored as a JSON string, so only data compatible with [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) can be used. Circular structures and complex objects (containing functions, symbols, etc.) will either throw an error on load and save or cause otherwise unexpected behavior. Properties with a value of `undefined` will be removed from the data prior to saving it, so use `null` instead.
77
+ * - ⚠️ If the storageMethod is left as the default of `"GM"`, the directives `@grant GM.getValue` and `@grant GM.setValue` are required. If you then also use the method {@linkcode DataStore.deleteData()}, the extra directive `@grant GM.deleteValue` is needed too.
78
+ * - ⚠️ Make sure to call {@linkcode loadData()} at least once after creating an instance, or the returned data will be the same as `options.defaultData`
79
+ *
80
+ * @template TData The type of the data that is saved in persistent storage for the currently set format version (will be automatically inferred from `defaultData` if not provided)
84
81
  */
85
82
  export declare class DataStore<TData extends object = object> {
86
83
  readonly id: string;
@@ -93,26 +90,26 @@ export declare class DataStore<TData extends object = object> {
93
90
  private migrations?;
94
91
  private migrateIds;
95
92
  /**
96
- * Creates an instance of DataStore to manage a sync & async database that is cached in memory and persistently saved across sessions.
97
- * Supports migrating data from older versions to newer ones and populating the cache with default data if no persistent data is found.
98
- *
99
- * ⚠️ Requires the directives `@grant GM.getValue` and `@grant GM.setValue` if the storageMethod is left as the default of `"GM"`
100
- * ⚠️ Make sure to call {@linkcode loadData()} at least once after creating an instance, or the returned data will be the same as `options.defaultData`
101
- *
102
- * @template TData The type of the data that is saved in persistent storage for the currently set format version (will be automatically inferred from `defaultData` if not provided) - **This has to be a JSON-compatible object!** (no undefined, circular references, etc.)
103
- * @param options The options for this DataStore instance
93
+ * Creates an instance of DataStore to manage a sync & async database that is cached in memory and persistently saved across sessions.
94
+ * Supports migrating data from older versions to newer ones and populating the cache with default data if no persistent data is found.
95
+ *
96
+ * - ⚠️ Requires the directives `@grant GM.getValue` and `@grant GM.setValue` if the storageMethod is left as the default of `"GM"`
97
+ * - ⚠️ Make sure to call {@linkcode loadData()} at least once after creating an instance, or the returned data will be the same as `options.defaultData`
98
+ *
99
+ * @template TData The type of the data that is saved in persistent storage for the currently set format version (will be automatically inferred from `defaultData` if not provided) - **This has to be a JSON-compatible object!** (no undefined, circular references, etc.)
100
+ * @param options The options for this DataStore instance
104
101
  */
105
102
  constructor(options: DataStoreOptions<TData>);
106
103
  /**
107
- * Loads the data saved in persistent storage into the in-memory cache and also returns it.
108
- * Automatically populates persistent storage with default data if it doesn't contain any data yet.
109
- * Also runs all necessary migration functions if the data format has changed since the last time the data was saved.
104
+ * Loads the data saved in persistent storage into the in-memory cache and also returns it.
105
+ * Automatically populates persistent storage with default data if it doesn't contain any data yet.
106
+ * Also runs all necessary migration functions if the data format has changed since the last time the data was saved.
110
107
  */
111
108
  loadData(): Promise<TData>;
112
109
  /**
113
- * Returns a copy of the data from the in-memory cache.
114
- * Use {@linkcode loadData()} to get fresh data from persistent storage (usually not necessary since the cache should always exactly reflect persistent storage).
115
- * @param deepCopy Whether to return a deep copy of the data (default: `false`) - only necessary if your data object is nested and may have a bigger performance impact if enabled
110
+ * Returns a copy of the data from the in-memory cache.
111
+ * Use {@linkcode loadData()} to get fresh data from persistent storage (usually not necessary since the cache should always exactly reflect persistent storage).
112
+ * @param deepCopy Whether to return a deep copy of the data (default: `false`) - only necessary if your data object is nested and may have a bigger performance impact if enabled
116
113
  */
117
114
  getData(deepCopy?: boolean): TData;
118
115
  /** Saves the data synchronously to the in-memory cache and asynchronously to the persistent storage */
@@ -120,26 +117,26 @@ export declare class DataStore<TData extends object = object> {
120
117
  /** Saves the default data passed in the constructor synchronously to the in-memory cache and asynchronously to persistent storage */
121
118
  saveDefaultData(): Promise<void>;
122
119
  /**
123
- * Call this method to clear all persistently stored data associated with this DataStore instance.
124
- * The in-memory cache will be left untouched, so you may still access the data with {@linkcode getData()}
125
- * Calling {@linkcode loadData()} or {@linkcode setData()} after this method was called will recreate persistent storage with the cached or default data.
126
- *
127
- * ⚠️ This requires the additional directive `@grant GM.deleteValue` if the storageMethod is left as the default of `"GM"`
120
+ * Call this method to clear all persistently stored data associated with this DataStore instance.
121
+ * The in-memory cache will be left untouched, so you may still access the data with {@linkcode getData()}
122
+ * Calling {@linkcode loadData()} or {@linkcode setData()} after this method was called will recreate persistent storage with the cached or default data.
123
+ *
124
+ * - ⚠️ This requires the additional directive `@grant GM.deleteValue` if the storageMethod is left as the default of `"GM"`
128
125
  */
129
126
  deleteData(): Promise<void>;
130
127
  /** Returns whether encoding and decoding are enabled for this DataStore instance */
131
128
  encodingEnabled(): this is Required<Pick<DataStoreOptions<TData>, "encodeData" | "decodeData">>;
132
129
  /**
133
- * Runs all necessary migration functions consecutively and saves the result to the in-memory cache and persistent storage and also returns it.
134
- * This method is automatically called by {@linkcode loadData()} if the data format has changed since the last time the data was saved.
135
- * Though calling this method manually is not necessary, it can be useful if you want to run migrations for special occasions like a user importing potentially outdated data that has been previously exported.
136
- *
137
- * If one of the migrations fails, the data will be reset to the default value if `resetOnError` is set to `true` (default). Otherwise, an error will be thrown and no data will be saved.
130
+ * Runs all necessary migration functions consecutively and saves the result to the in-memory cache and persistent storage and also returns it.
131
+ * This method is automatically called by {@linkcode loadData()} if the data format has changed since the last time the data was saved.
132
+ * Though calling this method manually is not necessary, it can be useful if you want to run migrations for special occasions like a user importing potentially outdated data that has been previously exported.
133
+ *
134
+ * If one of the migrations fails, the data will be reset to the default value if `resetOnError` is set to `true` (default). Otherwise, an error will be thrown and no data will be saved.
138
135
  */
139
- runMigrations(oldData: any, oldFmtVer: number, resetOnError?: boolean): Promise<TData>;
136
+ runMigrations(oldData: unknown, oldFmtVer: number, resetOnError?: boolean): Promise<TData>;
140
137
  /**
141
- * Tries to migrate the currently saved persistent data from one or more old IDs to the ID set in the constructor.
142
- * If no data exist for the old ID(s), nothing will be done, but some time may still pass trying to fetch the non-existent data.
138
+ * Tries to migrate the currently saved persistent data from one or more old IDs to the ID set in the constructor.
139
+ * If no data exist for the old ID(s), nothing will be done, but some time may still pass trying to fetch the non-existent data.
143
140
  */
144
141
  migrateId(oldIds: string | string[]): Promise<void>;
145
142
  /** Serializes the data using the optional this.encodeData() and returns it as a string */
@@ -148,14 +145,13 @@ export declare class DataStore<TData extends object = object> {
148
145
  protected deserializeData(data: string, useEncoding?: boolean): Promise<TData>;
149
146
  /** Copies a JSON-compatible object and loses all its internal references in the process */
150
147
  protected deepCopy<T>(obj: T): T;
151
- /** Gets a value from persistent storage - can be overwritten in a subclass if you want to use something other than GM storage */
148
+ /** Gets a value from persistent storage - can be overwritten in a subclass if you want to use something other than the default storage methods */
152
149
  protected getValue<TValue extends GM.Value = string>(name: string, defaultValue: TValue): Promise<string | TValue>;
153
150
  /**
154
- * Sets a value in persistent storage - can be overwritten in a subclass if you want to use something other than GM storage.
155
- * The default storage engines will stringify all passed values like numbers or booleans, so be aware of that.
151
+ * Sets a value in persistent storage - can be overwritten in a subclass if you want to use something other than the default storage methods.
152
+ * The default storage engines will stringify all passed values like numbers or booleans, so be aware of that.
156
153
  */
157
154
  protected setValue(name: string, value: GM.Value): Promise<void>;
158
- /** Deletes a value from persistent storage - can be overwritten in a subclass if you want to use something other than GM storage */
155
+ /** Deletes a value from persistent storage - can be overwritten in a subclass if you want to use something other than the default storage methods */
159
156
  protected deleteValue(name: string): Promise<void>;
160
157
  }
161
- export {};
@@ -26,12 +26,12 @@ export type LoadStoresDataResult = {
26
26
  data: object;
27
27
  };
28
28
  /**
29
- * Allows for easy serialization and deserialization of multiple DataStore instances.
30
- *
31
- * All methods are at least `protected`, so you can easily extend this class and overwrite them to use a different storage method or to add additional functionality.
32
- * Remember that you can call `super.methodName()` in the subclass to access the original method.
33
- *
34
- * ⚠️ Needs to run in a secure context (HTTPS) due to the use of the SubtleCrypto API if checksumming is enabled.
29
+ * Allows for easy serialization and deserialization of multiple DataStore instances.
30
+ *
31
+ * All methods are at least `protected`, so you can easily extend this class and overwrite them to use a different storage method or to add additional functionality.
32
+ * Remember that you can call `super.methodName()` in the subclass to access the original method.
33
+ *
34
+ * - ⚠️ Needs to run in a secure context (HTTPS) due to the use of the SubtleCrypto API if checksumming is enabled.
35
35
  */
36
36
  export declare class DataStoreSerializer {
37
37
  protected stores: DataStore[];
@@ -44,21 +44,21 @@ export declare class DataStoreSerializer {
44
44
  /** Serializes the data stores into a string */
45
45
  serialize(): Promise<string>;
46
46
  /**
47
- * Deserializes the data exported via {@linkcode serialize()} and imports it into the DataStore instances.
48
- * Also triggers the migration process if the data format has changed.
47
+ * Deserializes the data exported via {@linkcode serialize()} and imports it into the DataStore instances.
48
+ * Also triggers the migration process if the data format has changed.
49
49
  */
50
50
  deserialize(serializedData: string): Promise<void>;
51
51
  /**
52
- * Loads the persistent data of the DataStore instances into the in-memory cache.
53
- * Also triggers the migration process if the data format has changed.
54
- * @returns Returns a PromiseSettledResult array with the results of each DataStore instance in the format `{ id: string, data: object }`
52
+ * Loads the persistent data of the DataStore instances into the in-memory cache.
53
+ * Also triggers the migration process if the data format has changed.
54
+ * @returns Returns a PromiseSettledResult array with the results of each DataStore instance in the format `{ id: string, data: object }`
55
55
  */
56
56
  loadStoresData(): Promise<PromiseSettledResult<LoadStoresDataResult>[]>;
57
57
  /** Resets the persistent data of the DataStore instances to their default values. */
58
58
  resetStoresData(): Promise<PromiseSettledResult<void>[]>;
59
59
  /**
60
- * Deletes the persistent data of the DataStore instances.
61
- * Leaves the in-memory data untouched.
60
+ * Deletes the persistent data of the DataStore instances.
61
+ * Leaves the in-memory data untouched.
62
62
  */
63
63
  deleteStoresData(): Promise<PromiseSettledResult<void>[]>;
64
64
  }
@@ -0,0 +1,77 @@
1
+ import { NanoEmitter } from "./NanoEmitter.js";
2
+ /**
3
+ * The type of edge to use for the debouncer - [see the docs for a diagram and explanation.](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#debouncer)
4
+ * - `immediate` - (default & recommended) - calls the listeners at the very first call ("rising" edge) and queues the latest call until the timeout expires
5
+ * - Pros:
6
+ * - First call is let through immediately
7
+ * - Cons:
8
+ * - After all calls stop, the JS engine's event loop will continue to run until the last timeout expires (doesn't really matter on the web, but could cause a process exit delay in Node.js)
9
+ * - `idle` - queues all calls until there are no more calls in the given timeout duration ("falling" edge), and only then executes the very last call
10
+ * - Pros:
11
+ * - Makes sure there are zero calls in the given `timeoutDuration` before executing the last call
12
+ * - Cons:
13
+ * - Calls are always delayed by at least `1 * timeoutDuration`
14
+ * - Calls could get stuck in the queue indefinitely if there is no downtime between calls that is greater than the `timeoutDuration`
15
+ */
16
+ export type DebouncerType = "immediate" | "idle";
17
+ export type DebouncerFunc<TArgs> = (...args: TArgs[]) => void | unknown;
18
+ /** Event map for the {@linkcode Debouncer} */
19
+ export type DebouncerEventMap<TArgs> = {
20
+ /** Emitted when the debouncer calls all registered listeners, as a pub-sub alternative */
21
+ call: DebouncerFunc<TArgs>;
22
+ /** Emitted when the timeout or edge type is changed after the instance was created */
23
+ change: (timeout: number, type: DebouncerType) => void;
24
+ };
25
+ /**
26
+ * A debouncer that calls all listeners after a specified timeout, discarding all calls in-between.
27
+ * It is very useful for event listeners that fire quickly, like `input` or `mousemove`, to prevent the listeners from being called too often and hogging resources.
28
+ * The exact behavior can be customized with the `type` parameter.
29
+ *
30
+ * The instance inherits from {@linkcode NanoEmitter} and emits the following events:
31
+ * - `call` - emitted when the debouncer calls all listeners - use this as a pub-sub alternative to the default callback-style listeners
32
+ * - `change` - emitted when the timeout or edge type is changed after the instance was created
33
+ */
34
+ export declare class Debouncer<TArgs> extends NanoEmitter<DebouncerEventMap<TArgs>> {
35
+ protected timeout: number;
36
+ protected type: DebouncerType;
37
+ /** All registered listener functions and the time they were attached */
38
+ protected listeners: DebouncerFunc<TArgs>[];
39
+ /** The currently active timeout */
40
+ protected activeTimeout: ReturnType<typeof setTimeout> | undefined;
41
+ /** The latest queued call */
42
+ protected queuedCall: DebouncerFunc<TArgs> | undefined;
43
+ /**
44
+ * Creates a new debouncer with the specified timeout and edge type.
45
+ * @param timeout Timeout in milliseconds between letting through calls - defaults to 200
46
+ * @param type The edge type to use for the debouncer - see {@linkcode DebouncerType} for details or [the documentation for an explanation and diagram](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#debouncer) - defaults to "immediate"
47
+ */
48
+ constructor(timeout?: number, type?: DebouncerType);
49
+ /** Adds a listener function that will be called on timeout */
50
+ addListener(fn: DebouncerFunc<TArgs>): void;
51
+ /** Removes the listener with the specified function reference */
52
+ removeListener(fn: DebouncerFunc<TArgs>): void;
53
+ /** Removes all listeners */
54
+ removeAllListeners(): void;
55
+ /** Sets the timeout for the debouncer */
56
+ setTimeout(timeout: number): void;
57
+ /** Returns the current timeout */
58
+ getTimeout(): number;
59
+ /** Whether the timeout is currently active, meaning any latest call to the {@linkcode call()} method will be queued */
60
+ isTimeoutActive(): boolean;
61
+ /** Sets the edge type for the debouncer */
62
+ setType(type: DebouncerType): void;
63
+ /** Returns the current edge type */
64
+ getType(): DebouncerType;
65
+ /** Use this to call the debouncer with the specified arguments that will be passed to all listener functions registered with {@linkcode addListener()} */
66
+ call(...args: TArgs[]): void;
67
+ }
68
+ /**
69
+ * Creates a {@linkcode Debouncer} instance with the specified timeout and edge type and attaches the passed function as a listener.
70
+ * The returned function can be called with any arguments and will execute the `call()` method of the debouncer.
71
+ * The debouncer instance is accessible via the `debouncer` property of the returned function.
72
+ *
73
+ * Refer to the {@linkcode Debouncer} class definition or the [Debouncer documentation](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#debouncer) for more information.
74
+ */
75
+ export declare function debounce<TFunc extends DebouncerFunc<TArgs>, TArgs>(fn: TFunc, timeout?: number, type?: DebouncerType): DebouncerFunc<TArgs> & {
76
+ debouncer: Debouncer<TArgs>;
77
+ };
@@ -71,8 +71,8 @@ export declare class Dialog extends NanoEmitter<{
71
71
  /** Clears the DOM of the dialog and then renders it again */
72
72
  remount(): Promise<void>;
73
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
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
76
  */
77
77
  open(e?: MouseEvent | KeyboardEvent): Promise<HTMLElement | void>;
78
78
  /** Closes the dialog - prevents default action and immediate propagation of the passed event */
@@ -91,9 +91,9 @@ export declare class Dialog extends NanoEmitter<{
91
91
  /** Called once to attach all generic event listeners */
92
92
  protected attachListeners(bgElem: HTMLElement): void;
93
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
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
97
  */
98
98
  protected onInteraction<TElem extends HTMLElement>(elem: TElem, listener: (evt: MouseEvent | KeyboardEvent) => void, listenerOptions?: AddEventListenerOptions & {
99
99
  preventDefault?: boolean;
@@ -1,35 +1,33 @@
1
+ import { type DebouncerType } from "./Debouncer.js";
1
2
  import type { Prettify } from "./types.js";
2
3
  /** Options for the `onSelector()` method of {@linkcode SelectorObserver} */
3
4
  export type SelectorListenerOptions<TElem extends Element = HTMLElement> = Prettify<SelectorOptionsOne<TElem> | SelectorOptionsAll<TElem>>;
4
- type SelectorOptionsOne<TElem extends Element> = SelectorOptionsCommon & {
5
+ export type SelectorOptionsOne<TElem extends Element> = SelectorOptionsCommon & {
5
6
  /** Whether to use `querySelectorAll()` instead - default is false */
6
7
  all?: false;
7
8
  /** Gets called whenever the selector was found in the DOM */
8
9
  listener: (element: TElem) => void;
9
10
  };
10
- type SelectorOptionsAll<TElem extends Element> = SelectorOptionsCommon & {
11
+ export type SelectorOptionsAll<TElem extends Element> = SelectorOptionsCommon & {
11
12
  /** Whether to use `querySelectorAll()` instead - default is false */
12
13
  all: true;
13
14
  /** Gets called whenever the selector was found in the DOM */
14
15
  listener: (elements: NodeListOf<TElem>) => void;
15
16
  };
16
- type SelectorOptionsCommon = {
17
+ export type SelectorOptionsCommon = {
17
18
  /** Whether to call the listener continuously instead of once - default is false */
18
19
  continuous?: boolean;
19
20
  /** Whether to debounce the listener to reduce calls to `querySelector` or `querySelectorAll` - set undefined or <=0 to disable (default) */
20
21
  debounce?: number;
21
- /** Whether to call the function at the very first call ("rising" edge) or the very last call ("falling" edge, default) */
22
- debounceEdge?: "rising" | "falling";
22
+ /** The edge type of the debouncer - default is "immediate" - refer to {@linkcode Debouncer} for more info */
23
+ debounceType?: DebouncerType;
23
24
  };
24
- type UnsubscribeFunction = () => void;
25
+ export type UnsubscribeFunction = () => void;
25
26
  export type SelectorObserverOptions = {
26
27
  /** If set, applies this debounce in milliseconds to all listeners that don't have their own debounce set */
27
28
  defaultDebounce?: number;
28
- /**
29
- * If set, applies this debounce edge to all listeners that don't have their own set.
30
- * Edge = Whether to call the function at the very first call ("rising" edge) or the very last call ("falling" edge, default)
31
- */
32
- defaultDebounceEdge?: "rising" | "falling";
29
+ /** If set, applies this debounce edge type to all listeners that don't have their own set - refer to {@linkcode Debouncer} for more info */
30
+ defaultDebounceType?: DebouncerType;
33
31
  /** Whether to disable the observer when no listeners are present - default is true */
34
32
  disableOnNoListeners?: boolean;
35
33
  /** Whether to ensure the observer is enabled when a new listener is added - default is true */
@@ -47,15 +45,15 @@ export declare class SelectorObserver {
47
45
  private customOptions;
48
46
  private listenerMap;
49
47
  /**
50
- * Creates a new SelectorObserver that will observe the children of the given base element selector for changes (only creation and deletion of elements by default)
51
- * @param baseElementSelector The selector of the element to observe
52
- * @param options Fine-tune what triggers the MutationObserver's checking function - `subtree` and `childList` are set to true by default
48
+ * Creates a new SelectorObserver that will observe the children of the given base element selector for changes (only creation and deletion of elements by default)
49
+ * @param baseElementSelector The selector of the element to observe
50
+ * @param options Fine-tune what triggers the MutationObserver's checking function - `subtree` and `childList` are set to true by default
53
51
  */
54
52
  constructor(baseElementSelector: string, options?: SelectorObserverConstructorOptions);
55
53
  /**
56
- * Creates a new SelectorObserver that will observe the children of the given base element for changes (only creation and deletion of elements by default)
57
- * @param baseElement The element to observe
58
- * @param options Fine-tune what triggers the MutationObserver's checking function - `subtree` and `childList` are set to true by default
54
+ * Creates a new SelectorObserver that will observe the children of the given base element for changes (only creation and deletion of elements by default)
55
+ * @param baseElement The element to observe
56
+ * @param options Fine-tune what triggers the MutationObserver's checking function - `subtree` and `childList` are set to true by default
59
57
  */
60
58
  constructor(baseElement: Element, options?: SelectorObserverConstructorOptions);
61
59
  /** Call to check all selectors in the {@linkcode listenerMap} using {@linkcode checkSelector()} */
@@ -63,22 +61,22 @@ export declare class SelectorObserver {
63
61
  /** Checks if the element(s) with the given {@linkcode selector} exist in the DOM and calls the respective {@linkcode listeners} accordingly */
64
62
  protected checkSelector(selector: string, listeners: SelectorListenerOptions[]): void;
65
63
  /**
66
- * Starts observing the children of the base element for changes to the given {@linkcode selector} according to the set {@linkcode options}
67
- * @param selector The selector to observe
68
- * @param options Options for the selector observation
69
- * @param options.listener Gets called whenever the selector was found in the DOM
70
- * @param [options.all] Whether to use `querySelectorAll()` instead - default is false
71
- * @param [options.continuous] Whether to call the listener continuously instead of just once - default is false
72
- * @param [options.debounce] Whether to debounce the listener to reduce calls to `querySelector` or `querySelectorAll` - set undefined or <=0 to disable (default)
73
- * @returns Returns a function that can be called to remove this listener more easily
64
+ * Starts observing the children of the base element for changes to the given {@linkcode selector} according to the set {@linkcode options}
65
+ * @param selector The selector to observe
66
+ * @param options Options for the selector observation
67
+ * @param options.listener Gets called whenever the selector was found in the DOM
68
+ * @param [options.all] Whether to use `querySelectorAll()` instead - default is false
69
+ * @param [options.continuous] Whether to call the listener continuously instead of just once - default is false
70
+ * @param [options.debounce] Whether to debounce the listener to reduce calls to `querySelector` or `querySelectorAll` - set undefined or <=0 to disable (default)
71
+ * @returns Returns a function that can be called to remove this listener more easily
74
72
  */
75
73
  addListener<TElem extends Element = HTMLElement>(selector: string, options: SelectorListenerOptions<TElem>): UnsubscribeFunction;
76
74
  /** Disables the observation of the child elements */
77
75
  disable(): void;
78
76
  /**
79
- * Enables or reenables the observation of the child elements.
80
- * @param immediatelyCheckSelectors Whether to immediately check if all previously registered selectors exist (default is true)
81
- * @returns Returns true when the observation was enabled, false otherwise (e.g. when the base element wasn't found)
77
+ * Enables or reenables the observation of the child elements.
78
+ * @param immediatelyCheckSelectors Whether to immediately check if all previously registered selectors exist (default is true)
79
+ * @returns Returns true when the observation was enabled, false otherwise (e.g. when the base element wasn't found)
82
80
  */
83
81
  enable(immediatelyCheckSelectors?: boolean): boolean;
84
82
  /** Returns whether the observation of the child elements is currently enabled */
@@ -86,13 +84,13 @@ export declare class SelectorObserver {
86
84
  /** Removes all listeners that have been registered with {@linkcode addListener()} */
87
85
  clearListeners(): void;
88
86
  /**
89
- * Removes all listeners for the given {@linkcode selector} that have been registered with {@linkcode addListener()}
90
- * @returns Returns true when all listeners for the associated selector were found and removed, false otherwise
87
+ * Removes all listeners for the given {@linkcode selector} that have been registered with {@linkcode addListener()}
88
+ * @returns Returns true when all listeners for the associated selector were found and removed, false otherwise
91
89
  */
92
90
  removeAllListeners(selector: string): boolean;
93
91
  /**
94
- * Removes a single listener for the given {@linkcode selector} and {@linkcode options} that has been registered with {@linkcode addListener()}
95
- * @returns Returns true when the listener was found and removed, false otherwise
92
+ * Removes a single listener for the given {@linkcode selector} and {@linkcode options} that has been registered with {@linkcode addListener()}
93
+ * @returns Returns true when the listener was found and removed, false otherwise
96
94
  */
97
95
  removeListener(selector: string, options: SelectorListenerOptions): boolean;
98
96
  /** Returns all listeners that have been registered with {@linkcode addListener()} */
@@ -100,4 +98,3 @@ export declare class SelectorObserver {
100
98
  /** Returns all listeners for the given {@linkcode selector} that have been registered with {@linkcode addListener()} */
101
99
  getListeners(selector: string): SelectorListenerOptions<HTMLElement>[] | undefined;
102
100
  }
103
- export {};
@@ -3,8 +3,8 @@ export type NonEmptyArray<TArray = unknown> = [TArray, ...TArray[]];
3
3
  /** Returns a random item from the passed array */
4
4
  export declare function randomItem<TItem = unknown>(array: TItem[]): TItem | undefined;
5
5
  /**
6
- * Returns a tuple of a random item and its index from the passed array
7
- * Returns `[undefined, undefined]` if the passed array is empty
6
+ * Returns a tuple of a random item and its index from the passed array
7
+ * Returns `[undefined, undefined]` if the passed array is empty
8
8
  */
9
9
  export declare function randomItemIndex<TItem = unknown>(array: TItem[]): [item?: TItem, index?: number];
10
10
  /** Returns a random item from the passed array and mutates the array to remove the item */
@@ -1,21 +1,21 @@
1
1
  /**
2
- * Converts a hex color string in the format `#RRGGBB`, `#RRGGBBAA` (or even `RRGGBB` and `RGB`) to a tuple.
3
- * @returns Returns a tuple array where R, G and B are an integer from 0-255 and alpha is a float from 0 to 1, or undefined if no alpha channel exists.
2
+ * Converts a hex color string in the format `#RRGGBB`, `#RRGGBBAA` (or even `RRGGBB` and `RGB`) to a tuple.
3
+ * @returns Returns a tuple array where R, G and B are an integer from 0-255 and alpha is a float from 0 to 1, or undefined if no alpha channel exists.
4
4
  */
5
5
  export declare function hexToRgb(hex: string): [red: number, green: number, blue: number, alpha?: number];
6
6
  /** Converts RGB or RGBA number values to a hex color string in the format `#RRGGBB` or `#RRGGBBAA` */
7
7
  export declare function rgbToHex(red: number, green: number, blue: number, alpha?: number, withHash?: boolean, upperCase?: boolean): string;
8
8
  /**
9
- * Lightens a CSS color value (in #HEX, rgb() or rgba() format) by a given percentage.
10
- * Will not exceed the maximum range (00-FF or 0-255).
11
- * @returns Returns the new color value in the same format as the input
12
- * @throws Throws if the color format is invalid or not supported
9
+ * Lightens a CSS color value (in #HEX, rgb() or rgba() format) by a given percentage.
10
+ * Will not exceed the maximum range (00-FF or 0-255).
11
+ * @returns Returns the new color value in the same format as the input
12
+ * @throws Throws if the color format is invalid or not supported
13
13
  */
14
14
  export declare function lightenColor(color: string, percent: number, upperCase?: boolean): string;
15
15
  /**
16
- * Darkens a CSS color value (in #HEX, rgb() or rgba() format) by a given percentage.
17
- * Will not exceed the maximum range (00-FF or 0-255).
18
- * @returns Returns the new color value in the same format as the input
19
- * @throws Throws if the color format is invalid or not supported
16
+ * Darkens a CSS color value (in #HEX, rgb() or rgba() format) by a given percentage.
17
+ * Will not exceed the maximum range (00-FF or 0-255).
18
+ * @returns Returns the new color value in the same format as the input
19
+ * @throws Throws if the color format is invalid or not supported
20
20
  */
21
21
  export declare function darkenColor(color: string, percent: number, upperCase?: boolean): string;
@@ -7,19 +7,19 @@ export declare function decompress(input: string | ArrayBuffer, compressionForma
7
7
  /** Decompresses a previously compressed base64 string or ArrayBuffer, with the format passed by {@linkcode compressionFormat}, converted to an ArrayBuffer */
8
8
  export declare function decompress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType: "arrayBuffer"): Promise<ArrayBuffer>;
9
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.
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
14
  */
15
15
  export declare function computeHash(input: string | ArrayBuffer, algorithm?: string): Promise<string>;
16
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 longer to generate)
23
- * @param randomCase If set to false, the generated ID will be lowercase only - also makes use of the `enhancedEntropy` parameter unless the output doesn't contain letters
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 longer to generate)
23
+ * @param randomCase If set to false, the generated ID will be lowercase only - also makes use of the `enhancedEntropy` parameter unless the output doesn't contain letters
24
24
  */
25
25
  export declare function randomId(length?: number, radix?: number, enhancedEntropy?: boolean, randomCase?: boolean): string;