@studiometa/js-toolkit 3.5.0 → 3.6.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Base/Base.d.ts +2 -2
- package/Base/managers/AbstractManager.d.ts +2 -2
- package/Base/utils.d.ts +1 -1
- package/Base/utils.js +1 -2
- package/Base/utils.js.map +2 -2
- package/helpers/createApp.js +5 -0
- package/helpers/createApp.js.map +2 -2
- package/helpers/index.d.ts +1 -0
- package/helpers/index.js +1 -0
- package/helpers/index.js.map +2 -2
- package/helpers/logTree.d.ts +17 -0
- package/helpers/logTree.js +59 -0
- package/helpers/logTree.js.map +7 -0
- package/helpers/queryComponent.js +9 -10
- package/helpers/queryComponent.js.map +2 -2
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/services/AbstractService.d.ts +1 -1
- package/services/AbstractService.js +1 -1
- package/services/AbstractService.js.map +2 -2
- package/services/DragService.d.ts +5 -5
- package/services/RafService.d.ts +1 -1
- package/services/RafService.js +13 -7
- package/services/RafService.js.map +2 -2
- package/services/ScrollService.d.ts +21 -3
- package/services/ScrollService.js +55 -7
- package/services/ScrollService.js.map +2 -2
- package/utils/collide/boundingRectToCircle.d.ts +2 -2
- package/utils/css/animate.js +166 -96
- package/utils/css/animate.js.map +2 -2
- package/utils/css/transform.js +12 -13
- package/utils/css/transform.js.map +2 -2
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/index.js.map +2 -2
- package/utils/math/smoothTo.d.ts +24 -6
- package/utils/memoize.d.ts +1 -1
- package/utils/object/getAllProperties.js +4 -2
- package/utils/object/getAllProperties.js.map +2 -2
- package/utils/scheduler.d.ts +1 -1
- package/utils/storage/createLocalStorageProvider.d.ts +2 -0
- package/utils/storage/createLocalStorageProvider.js +32 -0
- package/utils/storage/createLocalStorageProvider.js.map +7 -0
- package/utils/storage/createMemoryStorageProvider.d.ts +2 -0
- package/utils/storage/createMemoryStorageProvider.js +27 -0
- package/utils/storage/createMemoryStorageProvider.js.map +7 -0
- package/utils/storage/createNoopProvider.d.ts +2 -0
- package/utils/storage/createNoopProvider.js +23 -0
- package/utils/storage/createNoopProvider.js.map +7 -0
- package/utils/storage/createSessionStorageProvider.d.ts +2 -0
- package/utils/storage/createSessionStorageProvider.js +31 -0
- package/utils/storage/createSessionStorageProvider.js.map +7 -0
- package/utils/storage/createStorage.d.ts +2 -0
- package/utils/storage/createStorage.js +100 -0
- package/utils/storage/createStorage.js.map +7 -0
- package/utils/storage/createUrlSearchParamsInHashProvider.d.ts +2 -0
- package/utils/storage/createUrlSearchParamsInHashProvider.js +57 -0
- package/utils/storage/createUrlSearchParamsInHashProvider.js.map +7 -0
- package/utils/storage/createUrlSearchParamsProvider.d.ts +2 -0
- package/utils/storage/createUrlSearchParamsProvider.js +41 -0
- package/utils/storage/createUrlSearchParamsProvider.js.map +7 -0
- package/utils/storage/getBrowserContext.d.ts +1 -0
- package/utils/storage/getBrowserContext.js +17 -0
- package/utils/storage/getBrowserContext.js.map +7 -0
- package/utils/storage/getGlobalStorage.d.ts +1 -0
- package/utils/storage/getGlobalStorage.js +7 -0
- package/utils/storage/getGlobalStorage.js.map +7 -0
- package/utils/storage/getStorageKeys.d.ts +1 -0
- package/utils/storage/getStorageKeys.js +12 -0
- package/utils/storage/getStorageKeys.js.map +7 -0
- package/utils/storage/index.d.ts +8 -0
- package/utils/storage/index.js +62 -0
- package/utils/storage/index.js.map +7 -0
- package/utils/storage/providers.d.ts +11 -0
- package/utils/storage/providers.js +30 -0
- package/utils/storage/providers.js.map +7 -0
- package/utils/storage/serializers.d.ts +2 -0
- package/utils/storage/serializers.js +14 -0
- package/utils/storage/serializers.js.map +7 -0
- package/utils/storage/types.d.ts +33 -0
- package/utils/storage/types.js +1 -0
- package/utils/storage/types.js.map +7 -0
- package/utils/storage.d.ts +1 -0
- package/utils/storage.js +2 -0
- package/utils/storage.js.map +7 -0
- package/utils/string/changeCase.js +1 -1
- package/utils/string/changeCase.js.map +2 -2
- package/utils/tween.js +5 -5
- package/utils/tween.js.map +2 -2
- package/tsconfig.build.tsbuildinfo +0 -1
package/Base/Base.d.ts
CHANGED
|
@@ -100,12 +100,12 @@ export declare class Base<T extends BaseProps = BaseProps> {
|
|
|
100
100
|
* @deprecated Use `$closest(name)` instead. Will be removed in v4.
|
|
101
101
|
* @link https://js-toolkit.studiometa.dev/api/instance-properties.html#parent
|
|
102
102
|
*/
|
|
103
|
-
get $parent(): T['$parent'] & Base | null;
|
|
103
|
+
get $parent(): (T['$parent'] & Base) | null;
|
|
104
104
|
/**
|
|
105
105
|
* Internal parent resolution without deprecation warning.
|
|
106
106
|
* @internal
|
|
107
107
|
*/
|
|
108
|
-
get __parent(): T['$parent'] & Base | null;
|
|
108
|
+
get __parent(): (T['$parent'] & Base) | null;
|
|
109
109
|
/**
|
|
110
110
|
* Merge configuration with the parents' configurations.
|
|
111
111
|
* @private
|
|
@@ -11,12 +11,12 @@ export declare class AbstractManager<T extends any = any> {
|
|
|
11
11
|
* Get the base instance root element.
|
|
12
12
|
*/
|
|
13
13
|
get __element(): HTMLElement & {
|
|
14
|
-
__base__?: Map<string, Base |
|
|
14
|
+
__base__?: Map<string, Base | 'terminated'>;
|
|
15
15
|
};
|
|
16
16
|
/**
|
|
17
17
|
* Get the base instance config.
|
|
18
18
|
*/
|
|
19
|
-
get __config(): import("
|
|
19
|
+
get __config(): import("#private/index.js").BaseConfig;
|
|
20
20
|
/**
|
|
21
21
|
* Get the events manager.
|
|
22
22
|
*/
|
package/Base/utils.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export declare function getEventTarget(instance: Base, event: string, config: Ba
|
|
|
34
34
|
* Get all mounted instances or the ones from a given component.
|
|
35
35
|
* @link https://js-toolkit.studiometa.dev/api/helpers/getInstances.html
|
|
36
36
|
*/
|
|
37
|
-
export declare function getInstances():
|
|
37
|
+
export declare function getInstances(): ReadonlySet<Base>;
|
|
38
38
|
export declare function getInstances<T extends BaseConstructor = BaseConstructor>(ctor: T): Set<InstanceType<T>>;
|
|
39
39
|
export declare function getElements(): Set<HTMLElement & {
|
|
40
40
|
__base__: Map<string, Base>;
|
package/Base/utils.js
CHANGED
package/Base/utils.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../packages/js-toolkit/Base/utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { isArray, isDefined, SmartQueue, dashCase } from '../utils/index.js';\nimport type { Base, BaseConfig, BaseConstructor } from './index.js';\nimport { features } from './features.js';\nimport { useMutation } from '../services/MutationService.js';\nimport { getInstanceFromElement } from '../helpers/getInstanceFromElement.js';\n\nlet queue: SmartQueue;\n\n/**\n * Add a task to the main queue.\n */\nexport function addToQueue(fn: () => unknown) {\n if (features.get('blocking')) {\n fn();\n return;\n }\n\n if (!queue) {\n queue = new SmartQueue();\n }\n\n return queue.add(fn);\n}\n\nconst selectors = new Map();\n\n// Separator used for multi-component declaration in `data-component` attributeS.\nconst separator = ' ';\n\n/**\n * Get the selector for a given component.\n */\nexport function getSelector(nameOrSelector: string): string {\n const { component } = features.get('attributes');\n const prefix = features.get('prefix');\n const key = prefix + component + nameOrSelector;\n\n if (!selectors.has(key)) {\n const parts = [\n // Tag select\n `${prefix}-${dashCase(nameOrSelector)}`,\n // Single selector\n `[${component}=\"${nameOrSelector}\"]`,\n // Selector in the middle of a list of selectors\n `[${component}*=\"${separator}${nameOrSelector}${separator}\"]`,\n // Selector at the end of a list of selectors\n `[${component}$=\"${separator}${nameOrSelector}\"]`,\n // Selector at the beginning of a list of selectors\n `[${component}^=\"${nameOrSelector}${separator}\"]`,\n ];\n selectors.set(key, parts.join(','));\n }\n\n return selectors.get(key);\n}\n\n/**\n * Get a list of elements based on the name of a component.\n *\n * @param {string} nameOrSelector\n * The name or selector to used for this component.\n * @param {HTMLElement|Document} element\n * The root element on which to query the selector, defaults to `document`.\n * @return {Array<HTMLElement>}\n * A list of elements on which the component should be mounted.\n */\nexport function getComponentElements(\n nameOrSelector: string,\n element: HTMLElement | Document = document,\n): HTMLElement[] {\n const selector = getSelector(nameOrSelector);\n let elements = [];\n\n try {\n elements = Array.from(element.querySelectorAll(selector));\n // eslint-disable-next-line no-empty\n } catch {}\n\n // If no child component found with the default selector, and if the selector does not\n // start with an uppercase letter, matching a component's name, try a classic DOM selector.\n if (elements.length === 0 && nameOrSelector[0] === nameOrSelector[0].toLowerCase()) {\n elements = Array.from(element.querySelectorAll(nameOrSelector));\n }\n\n return elements;\n}\n\n/**\n * Test if an event is defined in the given config.\n */\nexport function eventIsDefinedInConfig(event: string, config: BaseConfig): boolean {\n return isArray(config.emits) && config.emits.includes(event);\n}\n\n/**\n * Test if an event can be used on the given element.\n */\nexport function eventIsNative(event: string, element: HTMLElement): boolean {\n return isDefined(element[`on${event}`]);\n}\n\n/**\n * Get the target of a given event.\n */\nexport function getEventTarget(instance: Base, event: string, config: BaseConfig): Base['$el'] {\n if (eventIsDefinedInConfig(event, config) || eventIsNative(event, instance.$el)) {\n return instance.$el;\n }\n}\n\n/**\n * Get the global instance storage.\n * We attach it to `globalThis` so it can be shared between different\n * instances of the framework.\n */\nfunction getInstancesStorage(): Set<Base> {\n return (globalThis.__JS_TOOLKIT_INSTANCES__ ??= new Set<Base>());\n}\n\n/**\n * Get the global elements storage.\n * It will hold reference to all elements with at least one component attached to it.\n */\nfunction getElementsStorage(): Set<HTMLElement & { __base__: Map<string, Base>}> {\n return (globalThis.__JS_TOOLKIT_ELEMENTS__ ??= new Set<HTMLElement & { __base__: Map<string, Base>}>());\n}\n\n/**\n * Get all mounted instances or the ones from a given component.\n * @link https://js-toolkit.studiometa.dev/api/helpers/getInstances.html\n */\nexport function getInstances():
|
|
5
|
-
"mappings": "AAAA,SAAS,SAAS,WAAW,YAAY,gBAAgB;AAEzD,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAC5B,SAAS,8BAA8B;AAEvC,IAAI;AAKG,SAAS,WAAW,IAAmB;AAC5C,MAAI,SAAS,IAAI,UAAU,GAAG;AAC5B,OAAG;AACH;AAAA,EACF;AAEA,MAAI,CAAC,OAAO;AACV,YAAQ,IAAI,WAAW;AAAA,EACzB;AAEA,SAAO,MAAM,IAAI,EAAE;AACrB;AAEA,MAAM,YAAY,oBAAI,IAAI;AAG1B,MAAM,YAAY;AAKX,SAAS,YAAY,gBAAgC;AAC1D,QAAM,EAAE,UAAU,IAAI,SAAS,IAAI,YAAY;AAC/C,QAAM,SAAS,SAAS,IAAI,QAAQ;AACpC,QAAM,MAAM,SAAS,YAAY;AAEjC,MAAI,CAAC,UAAU,IAAI,GAAG,GAAG;AACvB,UAAM,QAAQ;AAAA;AAAA,MAEZ,GAAG,MAAM,IAAI,SAAS,cAAc,CAAC;AAAA;AAAA,MAErC,IAAI,SAAS,KAAK,cAAc;AAAA;AAAA,MAEhC,IAAI,SAAS,MAAM,SAAS,GAAG,cAAc,GAAG,SAAS;AAAA;AAAA,MAEzD,IAAI,SAAS,MAAM,SAAS,GAAG,cAAc;AAAA;AAAA,MAE7C,IAAI,SAAS,MAAM,cAAc,GAAG,SAAS;AAAA,IAC/C;AACA,cAAU,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,EACpC;AAEA,SAAO,UAAU,IAAI,GAAG;AAC1B;AAYO,SAAS,qBACd,gBACA,UAAkC,UACnB;AACf,QAAM,WAAW,YAAY,cAAc;AAC3C,MAAI,WAAW,CAAC;AAEhB,MAAI;AACF,eAAW,MAAM,KAAK,QAAQ,iBAAiB,QAAQ,CAAC;AAAA,EAE1D,QAAQ;AAAA,EAAC;AAIT,MAAI,SAAS,WAAW,KAAK,eAAe,CAAC,MAAM,eAAe,CAAC,EAAE,YAAY,GAAG;AAClF,eAAW,MAAM,KAAK,QAAQ,iBAAiB,cAAc,CAAC;AAAA,EAChE;AAEA,SAAO;AACT;AAKO,SAAS,uBAAuB,OAAe,QAA6B;AACjF,SAAO,QAAQ,OAAO,KAAK,KAAK,OAAO,MAAM,SAAS,KAAK;AAC7D;AAKO,SAAS,cAAc,OAAe,SAA+B;AAC1E,SAAO,UAAU,QAAQ,KAAK,KAAK,EAAE,CAAC;AACxC;AAKO,SAAS,eAAe,UAAgB,OAAe,QAAiC;AAC7F,MAAI,uBAAuB,OAAO,MAAM,KAAK,cAAc,OAAO,SAAS,GAAG,GAAG;AAC/E,WAAO,SAAS;AAAA,EAClB;AACF;AAOA,SAAS,sBAAiC;AACxC,SAAQ,WAAW,6BAA6B,oBAAI,IAAU;AAChE;AAMA,SAAS,qBAAwE;AAC/E,SAAQ,WAAW,4BAA4B,oBAAI,IAAkD;AACvG;AAUO,SAAS,aACd,
|
|
4
|
+
"sourcesContent": ["import { isArray, isDefined, SmartQueue, dashCase } from '../utils/index.js';\nimport type { Base, BaseConfig, BaseConstructor } from './index.js';\nimport { features } from './features.js';\nimport { useMutation } from '../services/MutationService.js';\nimport { getInstanceFromElement } from '../helpers/getInstanceFromElement.js';\n\nlet queue: SmartQueue;\n\n/**\n * Add a task to the main queue.\n */\nexport function addToQueue(fn: () => unknown) {\n if (features.get('blocking')) {\n fn();\n return;\n }\n\n if (!queue) {\n queue = new SmartQueue();\n }\n\n return queue.add(fn);\n}\n\nconst selectors = new Map();\n\n// Separator used for multi-component declaration in `data-component` attributeS.\nconst separator = ' ';\n\n/**\n * Get the selector for a given component.\n */\nexport function getSelector(nameOrSelector: string): string {\n const { component } = features.get('attributes');\n const prefix = features.get('prefix');\n const key = prefix + component + nameOrSelector;\n\n if (!selectors.has(key)) {\n const parts = [\n // Tag select\n `${prefix}-${dashCase(nameOrSelector)}`,\n // Single selector\n `[${component}=\"${nameOrSelector}\"]`,\n // Selector in the middle of a list of selectors\n `[${component}*=\"${separator}${nameOrSelector}${separator}\"]`,\n // Selector at the end of a list of selectors\n `[${component}$=\"${separator}${nameOrSelector}\"]`,\n // Selector at the beginning of a list of selectors\n `[${component}^=\"${nameOrSelector}${separator}\"]`,\n ];\n selectors.set(key, parts.join(','));\n }\n\n return selectors.get(key);\n}\n\n/**\n * Get a list of elements based on the name of a component.\n *\n * @param {string} nameOrSelector\n * The name or selector to used for this component.\n * @param {HTMLElement|Document} element\n * The root element on which to query the selector, defaults to `document`.\n * @return {Array<HTMLElement>}\n * A list of elements on which the component should be mounted.\n */\nexport function getComponentElements(\n nameOrSelector: string,\n element: HTMLElement | Document = document,\n): HTMLElement[] {\n const selector = getSelector(nameOrSelector);\n let elements = [];\n\n try {\n elements = Array.from(element.querySelectorAll(selector));\n // eslint-disable-next-line no-empty\n } catch {}\n\n // If no child component found with the default selector, and if the selector does not\n // start with an uppercase letter, matching a component's name, try a classic DOM selector.\n if (elements.length === 0 && nameOrSelector[0] === nameOrSelector[0].toLowerCase()) {\n elements = Array.from(element.querySelectorAll(nameOrSelector));\n }\n\n return elements;\n}\n\n/**\n * Test if an event is defined in the given config.\n */\nexport function eventIsDefinedInConfig(event: string, config: BaseConfig): boolean {\n return isArray(config.emits) && config.emits.includes(event);\n}\n\n/**\n * Test if an event can be used on the given element.\n */\nexport function eventIsNative(event: string, element: HTMLElement): boolean {\n return isDefined(element[`on${event}`]);\n}\n\n/**\n * Get the target of a given event.\n */\nexport function getEventTarget(instance: Base, event: string, config: BaseConfig): Base['$el'] {\n if (eventIsDefinedInConfig(event, config) || eventIsNative(event, instance.$el)) {\n return instance.$el;\n }\n}\n\n/**\n * Get the global instance storage.\n * We attach it to `globalThis` so it can be shared between different\n * instances of the framework.\n */\nfunction getInstancesStorage(): Set<Base> {\n return (globalThis.__JS_TOOLKIT_INSTANCES__ ??= new Set<Base>());\n}\n\n/**\n * Get the global elements storage.\n * It will hold reference to all elements with at least one component attached to it.\n */\nfunction getElementsStorage(): Set<HTMLElement & { __base__: Map<string, Base>}> {\n return (globalThis.__JS_TOOLKIT_ELEMENTS__ ??= new Set<HTMLElement & { __base__: Map<string, Base>}>());\n}\n\n/**\n * Get all mounted instances or the ones from a given component.\n * @link https://js-toolkit.studiometa.dev/api/helpers/getInstances.html\n */\nexport function getInstances(): ReadonlySet<Base>;\nexport function getInstances<T extends BaseConstructor = BaseConstructor>(\n ctor: T,\n): Set<InstanceType<T>>;\nexport function getInstances<T extends BaseConstructor = BaseConstructor>(\n ctor?: T,\n): ReadonlySet<InstanceType<T>> | ReadonlySet<Base> {\n if (isDefined(ctor)) {\n const filteredInstances = new Set<InstanceType<T>>();\n for (const instance of getInstancesStorage()) {\n if (instance instanceof ctor) {\n filteredInstances.add(instance as InstanceType<T>);\n }\n }\n return filteredInstances;\n }\n\n return new Set(getInstancesStorage());\n}\n\nexport function getElements() {\n return new Set(getElementsStorage());\n}\n\nexport function addInstance(instance: Base) {\n getInstancesStorage().add(instance);\n getElementsStorage().add(instance.$el as HTMLElement & { __base__: Map<string, Base>});\n}\n\nexport function deleteInstance(instance: Base) {\n getInstancesStorage().delete(instance);\n getElementsStorage().delete(instance.$el as HTMLElement & { __base__: Map<string, Base>});\n}\n\nconst registryKey = '__JS_TOOLKIT_REGISTRY__';\n\nfunction registry() {\n return (globalThis[registryKey] ??= new Map<string, BaseConstructor>());\n}\n\nfunction mutationCallback() {\n addToQueue(() => {\n for (const [nameOrSelector, ctor] of registry()) {\n for (const el of getComponentElements(nameOrSelector)) {\n if (!getInstanceFromElement(el, ctor)) {\n new ctor(el).$mount();\n }\n }\n }\n });\n\n addToQueue(() => {\n for (const instance of getInstances()) {\n if (!instance.$el.isConnected) {\n instance.$terminate();\n }\n }\n });\n}\n\nexport function addToRegistry(nameOrSelector: string, ctor: BaseConstructor) {\n if (registry().has(nameOrSelector)) {\n return;\n }\n\n registry().set(nameOrSelector, ctor);\n\n // Add children components to the registry\n if (ctor.config?.components) {\n for (const [selector, childConstructor] of Object.entries(ctor.config?.components)) {\n if ('$isBase' in childConstructor && childConstructor.$isBase) {\n addToRegistry(selector, childConstructor);\n }\n }\n }\n\n const mutation = useMutation(document, { childList: true, subtree: true });\n if (!mutation.has(registryKey)) {\n mutation.add(registryKey, mutationCallback);\n }\n}\n\n/**\n * Find the closest instance from the given element in the given set of Base instances.\n */\nexport function findClosestInstance<T extends Base = Base>(element: HTMLElement, instances: Set<T>): T {\n let closest = null;\n let minDepth = Infinity;\n\n for (const instance of instances) {\n let depth = 0;\n let el = element;\n while (el && el !== instance.$el) {\n depth++;\n el = el.parentElement;\n }\n\n if (depth < minDepth) {\n minDepth = depth;\n closest = instance;\n }\n }\n\n return closest;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/helpers/createApp.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { features } from "../Base/features.js";
|
|
2
2
|
import { defineFeatures } from "./defineFeatures.js";
|
|
3
|
+
import { isDev } from "../utils/index.js";
|
|
4
|
+
import { logTree } from "./logTree.js";
|
|
3
5
|
function createApp(App, options = {}) {
|
|
4
6
|
let app;
|
|
5
7
|
const {
|
|
@@ -10,6 +12,9 @@ function createApp(App, options = {}) {
|
|
|
10
12
|
async function init() {
|
|
11
13
|
app = new App(root);
|
|
12
14
|
await app.$mount();
|
|
15
|
+
if (isDev) {
|
|
16
|
+
globalThis.$logTree = () => logTree(app);
|
|
17
|
+
}
|
|
13
18
|
return app;
|
|
14
19
|
}
|
|
15
20
|
let p;
|
package/helpers/createApp.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../packages/js-toolkit/helpers/createApp.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Base, BaseConstructor, BaseProps } from '../Base/index.js';\nimport type { Features } from '../Base/features.js';\nimport { features } from '../Base/features.js';\nimport { defineFeatures } from './defineFeatures.js';\n\nexport type CreateAppOptions = Partial<Features> & {\n root?: HTMLElement;\n};\n\n/**\n * Instantiate and mount the given component on the given root element when the page has been loaded\n * and return a function to use the app instance when it is ready.\n * @link https://js-toolkit.studiometa.dev/api/helpers/createApp.html\n*/\nexport function createApp<S extends BaseConstructor<Base>, T extends BaseProps = BaseProps>(\n App: S,\n options: HTMLElement | CreateAppOptions = {},\n): () => Promise<S & Base<T>> {\n let app: S & Base<T>;\n const {\n root = document.body,\n ...featureOptions\n } = options instanceof HTMLElement ? { root: options } : options;\n\n defineFeatures(featureOptions);\n\n async function init() {\n app = new App(root) as S & Base<T>;\n await app.$mount();\n return app;\n }\n\n let p: Promise<S & Base<T>>;\n\n if (features.get('blocking')) {\n p = init();\n } else {\n p = new Promise<S & Base<T>>((resolve) => {\n if (document.readyState === 'complete') {\n resolve(init());\n } else {\n document.addEventListener('readystatechange', () => {\n if (document.readyState === 'complete') {\n resolve(init());\n }\n });\n }\n });\n }\n\n return () => p;\n}\n"],
|
|
5
|
-
"mappings": "AAEA,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;
|
|
4
|
+
"sourcesContent": ["import type { Base, BaseConstructor, BaseProps } from '../Base/index.js';\nimport type { Features } from '../Base/features.js';\nimport { features } from '../Base/features.js';\nimport { defineFeatures } from './defineFeatures.js';\nimport { isDev } from '../utils/index.js';\nimport { logTree } from './logTree.js';\n\nexport type CreateAppOptions = Partial<Features> & {\n root?: HTMLElement;\n};\n\n/**\n * Instantiate and mount the given component on the given root element when the page has been loaded\n * and return a function to use the app instance when it is ready.\n * @link https://js-toolkit.studiometa.dev/api/helpers/createApp.html\n*/\nexport function createApp<S extends BaseConstructor<Base>, T extends BaseProps = BaseProps>(\n App: S,\n options: HTMLElement | CreateAppOptions = {},\n): () => Promise<S & Base<T>> {\n let app: S & Base<T>;\n const {\n root = document.body,\n ...featureOptions\n } = options instanceof HTMLElement ? { root: options } : options;\n\n defineFeatures(featureOptions);\n\n async function init() {\n app = new App(root) as S & Base<T>;\n await app.$mount();\n if (isDev) {\n globalThis.$logTree = () => logTree(app);\n }\n return app;\n }\n\n let p: Promise<S & Base<T>>;\n\n if (features.get('blocking')) {\n p = init();\n } else {\n p = new Promise<S & Base<T>>((resolve) => {\n if (document.readyState === 'complete') {\n resolve(init());\n } else {\n document.addEventListener('readystatechange', () => {\n if (document.readyState === 'complete') {\n resolve(init());\n }\n });\n }\n });\n }\n\n return () => p;\n}\n"],
|
|
5
|
+
"mappings": "AAEA,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;AAC/B,SAAS,aAAa;AACtB,SAAS,eAAe;AAWjB,SAAS,UACd,KACA,UAA0C,CAAC,GACf;AAC5B,MAAI;AACJ,QAAM;AAAA,IACJ,OAAO,SAAS;AAAA,IAChB,GAAG;AAAA,EACL,IAAI,mBAAmB,cAAc,EAAE,MAAM,QAAQ,IAAI;AAEzD,iBAAe,cAAc;AAE7B,iBAAe,OAAO;AACpB,UAAM,IAAI,IAAI,IAAI;AAClB,UAAM,IAAI,OAAO;AACjB,QAAI,OAAO;AACT,iBAAW,WAAW,MAAM,QAAQ,GAAG;AAAA,IACzC;AACA,WAAO;AAAA,EACT;AAEA,MAAI;AAEJ,MAAI,SAAS,IAAI,UAAU,GAAG;AAC5B,QAAI,KAAK;AAAA,EACX,OAAO;AACL,QAAI,IAAI,QAAqB,CAAC,YAAY;AACxC,UAAI,SAAS,eAAe,YAAY;AACtC,gBAAQ,KAAK,CAAC;AAAA,MAChB,OAAO;AACL,iBAAS,iBAAiB,oBAAoB,MAAM;AAClD,cAAI,SAAS,eAAe,YAAY;AACtC,oBAAQ,KAAK,CAAC;AAAA,UAChB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO,MAAM;AACf;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/helpers/index.d.ts
CHANGED
|
@@ -8,5 +8,6 @@ export * from './importOnMediaQuery.js';
|
|
|
8
8
|
export * from './importWhenIdle.js';
|
|
9
9
|
export * from './importWhenPrefersMotion.js';
|
|
10
10
|
export * from './importWhenVisible.js';
|
|
11
|
+
export * from './logTree.js';
|
|
11
12
|
export * from './registerComponent.js';
|
|
12
13
|
export { type QueryOptions, queryComponent, queryComponentAll, closestComponent, } from './queryComponent.js';
|
package/helpers/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export * from "./importOnMediaQuery.js";
|
|
|
8
8
|
export * from "./importWhenIdle.js";
|
|
9
9
|
export * from "./importWhenPrefersMotion.js";
|
|
10
10
|
export * from "./importWhenVisible.js";
|
|
11
|
+
export * from "./logTree.js";
|
|
11
12
|
export * from "./registerComponent.js";
|
|
12
13
|
import {
|
|
13
14
|
queryComponent,
|
package/helpers/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../packages/js-toolkit/helpers/index.ts"],
|
|
4
|
-
"sourcesContent": ["export * from './createApp.js';\nexport * from './defineFeatures.js';\nexport * from './getClosestParent.js';\nexport * from './getDirectChildren.js';\nexport * from './getInstanceFromElement.js';\nexport * from './importOnInteraction.js';\nexport * from './importOnMediaQuery.js';\nexport * from './importWhenIdle.js';\nexport * from './importWhenPrefersMotion.js';\nexport * from './importWhenVisible.js';\nexport * from './registerComponent.js';\nexport {\n type QueryOptions,\n queryComponent,\n queryComponentAll,\n closestComponent,\n} from './queryComponent.js';\n"],
|
|
5
|
-
"mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OACK;",
|
|
4
|
+
"sourcesContent": ["export * from './createApp.js';\nexport * from './defineFeatures.js';\nexport * from './getClosestParent.js';\nexport * from './getDirectChildren.js';\nexport * from './getInstanceFromElement.js';\nexport * from './importOnInteraction.js';\nexport * from './importOnMediaQuery.js';\nexport * from './importWhenIdle.js';\nexport * from './importWhenPrefersMotion.js';\nexport * from './importWhenVisible.js';\nexport * from './logTree.js';\nexport * from './registerComponent.js';\nexport {\n type QueryOptions,\n queryComponent,\n queryComponentAll,\n closestComponent,\n} from './queryComponent.js';\n"],
|
|
5
|
+
"mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OACK;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Base } from '../Base/Base.js';
|
|
2
|
+
/**
|
|
3
|
+
* Log the component tree starting from the given instance.
|
|
4
|
+
*
|
|
5
|
+
* Uses the global instance registry and DOM containment to build the tree,
|
|
6
|
+
* without relying on the deprecated `$children` API.
|
|
7
|
+
*
|
|
8
|
+
* @param {Base} instance The root component instance.
|
|
9
|
+
* @example
|
|
10
|
+
* ```js
|
|
11
|
+
* import { createApp, logTree } from '@studiometa/js-toolkit';
|
|
12
|
+
*
|
|
13
|
+
* const useApp = createApp(App);
|
|
14
|
+
* useApp().then((app) => logTree(app));
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function logTree(instance: Base): void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { getInstances } from "../Base/index.js";
|
|
2
|
+
function buildTree(root) {
|
|
3
|
+
const allInstances = getInstances();
|
|
4
|
+
const rootNode = { instance: root, children: [] };
|
|
5
|
+
const descendants = [];
|
|
6
|
+
for (const instance of allInstances) {
|
|
7
|
+
if (instance !== root && root.$el.contains(instance.$el)) {
|
|
8
|
+
descendants.push(instance);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
descendants.sort((a, b) => {
|
|
12
|
+
const position = a.$el.compareDocumentPosition(b.$el);
|
|
13
|
+
if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;
|
|
14
|
+
if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;
|
|
15
|
+
return 0;
|
|
16
|
+
});
|
|
17
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
18
|
+
nodeMap.set(root, rootNode);
|
|
19
|
+
for (const instance of descendants) {
|
|
20
|
+
const node = { instance, children: [] };
|
|
21
|
+
nodeMap.set(instance, node);
|
|
22
|
+
let parentNode = rootNode;
|
|
23
|
+
for (const [candidate, candidateNode] of nodeMap) {
|
|
24
|
+
if (candidate !== instance && candidate.$el.contains(instance.$el) && // Pick the most specific (deepest) container
|
|
25
|
+
parentNode.instance.$el.contains(candidate.$el)) {
|
|
26
|
+
parentNode = candidateNode;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
parentNode.children.push(node);
|
|
30
|
+
}
|
|
31
|
+
return rootNode;
|
|
32
|
+
}
|
|
33
|
+
function logNode(node) {
|
|
34
|
+
const { instance } = node;
|
|
35
|
+
const mounted = instance.$isMounted;
|
|
36
|
+
const status = mounted ? "\u25CF" : "\u25CB";
|
|
37
|
+
const label = `${status} ${instance.$id}`;
|
|
38
|
+
if (node.children.length > 0) {
|
|
39
|
+
console.groupCollapsed(label, instance.$el);
|
|
40
|
+
for (const child of node.children) {
|
|
41
|
+
logNode(child);
|
|
42
|
+
}
|
|
43
|
+
console.groupEnd();
|
|
44
|
+
} else {
|
|
45
|
+
console.log(label, instance.$el);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function logTree(instance) {
|
|
49
|
+
const tree = buildTree(instance);
|
|
50
|
+
console.group(`\u{1F333} ${instance.$config.name}`);
|
|
51
|
+
for (const child of tree.children) {
|
|
52
|
+
logNode(child);
|
|
53
|
+
}
|
|
54
|
+
console.groupEnd();
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
logTree
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=logTree.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../packages/js-toolkit/helpers/logTree.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Base } from '../Base/Base.js';\nimport { getInstances } from '../Base/index.js';\n\n/**\n * Build a tree structure from a flat set of instances using DOM containment.\n */\nfunction buildTree(root: Base): TreeNode {\n const allInstances = getInstances();\n const rootNode: TreeNode = { instance: root, children: [] };\n\n // Collect all instances that are descendants of root (excluding root itself)\n const descendants: Base[] = [];\n for (const instance of allInstances) {\n if (instance !== root && root.$el.contains(instance.$el)) {\n descendants.push(instance);\n }\n }\n\n // Sort by DOM order (depth-first)\n descendants.sort((a, b) => {\n const position = a.$el.compareDocumentPosition(b.$el);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;\n if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;\n return 0;\n });\n\n // Build tree: assign each instance to its closest ancestor in the tree\n const nodeMap = new Map<Base, TreeNode>();\n nodeMap.set(root, rootNode);\n\n for (const instance of descendants) {\n const node: TreeNode = { instance, children: [] };\n nodeMap.set(instance, node);\n\n // Find the closest ancestor that is already in the tree\n let parentNode = rootNode;\n for (const [candidate, candidateNode] of nodeMap) {\n if (\n candidate !== instance &&\n candidate.$el.contains(instance.$el) &&\n // Pick the most specific (deepest) container\n parentNode.instance.$el.contains(candidate.$el)\n ) {\n parentNode = candidateNode;\n }\n }\n\n parentNode.children.push(node);\n }\n\n return rootNode;\n}\n\ninterface TreeNode {\n instance: Base;\n children: TreeNode[];\n}\n\n/**\n * Log a tree node and its children using console groups.\n */\nfunction logNode(node: TreeNode): void {\n const { instance } = node;\n const mounted = instance.$isMounted;\n const status = mounted ? '\u25CF' : '\u25CB';\n const label = `${status} ${instance.$id}`;\n\n if (node.children.length > 0) {\n console.groupCollapsed(label, instance.$el);\n for (const child of node.children) {\n logNode(child);\n }\n console.groupEnd();\n } else {\n console.log(label, instance.$el);\n }\n}\n\n/**\n * Log the component tree starting from the given instance.\n *\n * Uses the global instance registry and DOM containment to build the tree,\n * without relying on the deprecated `$children` API.\n *\n * @param {Base} instance The root component instance.\n * @example\n * ```js\n * import { createApp, logTree } from '@studiometa/js-toolkit';\n *\n * const useApp = createApp(App);\n * useApp().then((app) => logTree(app));\n * ```\n */\nexport function logTree(instance: Base): void {\n const tree = buildTree(instance);\n console.group(`\uD83C\uDF33 ${instance.$config.name}`);\n for (const child of tree.children) {\n logNode(child);\n }\n console.groupEnd();\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,oBAAoB;AAK7B,SAAS,UAAU,MAAsB;AACvC,QAAM,eAAe,aAAa;AAClC,QAAM,WAAqB,EAAE,UAAU,MAAM,UAAU,CAAC,EAAE;AAG1D,QAAM,cAAsB,CAAC;AAC7B,aAAW,YAAY,cAAc;AACnC,QAAI,aAAa,QAAQ,KAAK,IAAI,SAAS,SAAS,GAAG,GAAG;AACxD,kBAAY,KAAK,QAAQ;AAAA,IAC3B;AAAA,EACF;AAGA,cAAY,KAAK,CAAC,GAAG,MAAM;AACzB,UAAM,WAAW,EAAE,IAAI,wBAAwB,EAAE,GAAG;AACpD,QAAI,WAAW,KAAK,4BAA6B,QAAO;AACxD,QAAI,WAAW,KAAK,4BAA6B,QAAO;AACxD,WAAO;AAAA,EACT,CAAC;AAGD,QAAM,UAAU,oBAAI,IAAoB;AACxC,UAAQ,IAAI,MAAM,QAAQ;AAE1B,aAAW,YAAY,aAAa;AAClC,UAAM,OAAiB,EAAE,UAAU,UAAU,CAAC,EAAE;AAChD,YAAQ,IAAI,UAAU,IAAI;AAG1B,QAAI,aAAa;AACjB,eAAW,CAAC,WAAW,aAAa,KAAK,SAAS;AAChD,UACE,cAAc,YACd,UAAU,IAAI,SAAS,SAAS,GAAG;AAAA,MAEnC,WAAW,SAAS,IAAI,SAAS,UAAU,GAAG,GAC9C;AACA,qBAAa;AAAA,MACf;AAAA,IACF;AAEA,eAAW,SAAS,KAAK,IAAI;AAAA,EAC/B;AAEA,SAAO;AACT;AAUA,SAAS,QAAQ,MAAsB;AACrC,QAAM,EAAE,SAAS,IAAI;AACrB,QAAM,UAAU,SAAS;AACzB,QAAM,SAAS,UAAU,WAAM;AAC/B,QAAM,QAAQ,GAAG,MAAM,IAAI,SAAS,GAAG;AAEvC,MAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,YAAQ,eAAe,OAAO,SAAS,GAAG;AAC1C,eAAW,SAAS,KAAK,UAAU;AACjC,cAAQ,KAAK;AAAA,IACf;AACA,YAAQ,SAAS;AAAA,EACnB,OAAO;AACL,YAAQ,IAAI,OAAO,SAAS,GAAG;AAAA,EACjC;AACF;AAiBO,SAAS,QAAQ,UAAsB;AAC5C,QAAM,OAAO,UAAU,QAAQ;AAC/B,UAAQ,MAAM,aAAM,SAAS,QAAQ,IAAI,EAAE;AAC3C,aAAW,SAAS,KAAK,UAAU;AACjC,YAAQ,KAAK;AAAA,EACf;AACA,UAAQ,SAAS;AACnB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -42,20 +42,19 @@ function queryComponentAll(query, options = {}) {
|
|
|
42
42
|
function closestComponent(query, options = { from: null }) {
|
|
43
43
|
const { from } = options;
|
|
44
44
|
const parsedQuery = parseQuery(query);
|
|
45
|
-
|
|
46
|
-
let closestInstance = null;
|
|
45
|
+
let closestInstance;
|
|
47
46
|
getAncestorWhere(from, (element) => {
|
|
48
47
|
if (!element) return false;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
const baseMap = element.__base__;
|
|
49
|
+
if (!baseMap) return false;
|
|
50
|
+
const instance = baseMap.get(parsedQuery.name);
|
|
51
|
+
if (instance && instance !== "terminated" && instanceIsMatching(instance, parsedQuery)) {
|
|
52
|
+
closestInstance = instance;
|
|
53
|
+
return true;
|
|
55
54
|
}
|
|
56
55
|
return false;
|
|
57
|
-
})
|
|
58
|
-
return closestInstance
|
|
56
|
+
});
|
|
57
|
+
return closestInstance;
|
|
59
58
|
}
|
|
60
59
|
export {
|
|
61
60
|
closestComponent,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../packages/js-toolkit/helpers/queryComponent.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Base } from '../Base/index.js';\nimport { getInstances } from '../Base/index.js';\nimport { memo } from '../utils/memo.js';\nimport { getAncestorWhere } from '../utils/dom/ancestors.js';\n\nexport interface QueryOptions {\n from?: HTMLElement | Document;\n}\n\ntype ComponentState = 'mounted' | 'destroyed' | 'terminated';\nexport type ParsedQuery = {\n name: string;\n cssSelector?: string;\n state?: string;\n};\n\nconst REGEX_QUERY = /([a-zA-Z0-9]+)(\\((.*)\\))?(:([a-z]+))?/;\n\n/**\n * Parse a query string like 'Foo(.css-selector):mounted' into its parts.\n */\nexport const parseQuery = memo((query: string): ParsedQuery => {\n const [, name, , cssSelector, , state] = query.match(REGEX_QUERY) as [\n string,\n string,\n string | undefined,\n string | undefined,\n string | undefined,\n ComponentState | undefined,\n ];\n\n return {\n name,\n cssSelector,\n state,\n };\n});\n\nexport function instanceIsMatching(instance: Base, parsedQuery: ParsedQuery): boolean {\n if (instance.$config.name !== parsedQuery.name) return false;\n if (parsedQuery.cssSelector && !instance.$el.matches(parsedQuery.cssSelector)) return false;\n\n if (parsedQuery.state === 'mounted' && !instance.$isMounted) return false;\n if (parsedQuery.state === 'destroyed' && instance.$isMounted) return false;\n\n return true;\n}\n\n/**\n * Get the first instance of component with the given query.\n */\nexport function queryComponent<T extends Base = Base>(\n query: string,\n options: QueryOptions = {},\n): T | undefined {\n const parsedQuery = parseQuery(query);\n const { from = document } = options;\n const instances = getInstances() as
|
|
5
|
-
"mappings": "AACA,SAAS,oBAAoB;AAC7B,SAAS,YAAY;AACrB,SAAS,wBAAwB;AAajC,MAAM,cAAc;AAKb,MAAM,aAAa,KAAK,CAAC,UAA+B;AAC7D,QAAM,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,IAAI,MAAM,MAAM,WAAW;AAShE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF,CAAC;AAEM,SAAS,mBAAmB,UAAgB,aAAmC;AACpF,MAAI,SAAS,QAAQ,SAAS,YAAY,KAAM,QAAO;AACvD,MAAI,YAAY,eAAe,CAAC,SAAS,IAAI,QAAQ,YAAY,WAAW,EAAG,QAAO;AAEtF,MAAI,YAAY,UAAU,aAAa,CAAC,SAAS,WAAY,QAAO;AACpE,MAAI,YAAY,UAAU,eAAe,SAAS,WAAY,QAAO;AAErE,SAAO;AACT;AAKO,SAAS,eACd,OACA,UAAwB,CAAC,GACV;AACf,QAAM,cAAc,WAAW,KAAK;AACpC,QAAM,EAAE,OAAO,SAAS,IAAI;AAC5B,QAAM,YAAY,aAAa;AAE/B,aAAW,YAAY,WAAW;AAChC,QAAI,CAAC,mBAAmB,UAAU,WAAW,EAAG;AAChD,QAAI,SAAS,YAAY,EAAE,SAAS,SAAS,OAAO,KAAK,SAAS,SAAS,GAAG,GAAI;AAElF,WAAO;AAAA,EACT;AACF;AAKO,SAAS,kBACd,OACA,UAAwB,CAAC,GACpB;AACL,QAAM,cAAc,WAAW,KAAK;AACpC,QAAM,EAAE,OAAO,SAAS,IAAI;AAC5B,QAAM,YAAY,aAAa;AAC/B,QAAM,oBAAoB,oBAAI,IAAO;AAErC,aAAW,YAAY,WAAW;AAChC,QAAI,CAAC,mBAAmB,UAAU,WAAW,EAAG;AAChD,QAAI,SAAS,YAAY,EAAE,SAAS,SAAS,OAAO,KAAK,SAAS,SAAS,GAAG,GAAI;AAElF,sBAAkB,IAAI,QAAQ;AAAA,EAChC;AAEA,SAAO,MAAM,KAAK,iBAAiB;AACrC;AAKO,SAAS,iBACd,OACA,UAAiC,EAAE,MAAM,KAAK,GAC/B;AACf,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,cAAc,WAAW,KAAK;AACpC,
|
|
4
|
+
"sourcesContent": ["import type { Base, BaseEl } from '../Base/index.js';\nimport { getInstances } from '../Base/index.js';\nimport { memo } from '../utils/memo.js';\nimport { getAncestorWhere } from '../utils/dom/ancestors.js';\n\nexport interface QueryOptions {\n from?: HTMLElement | Document;\n}\n\ntype ComponentState = 'mounted' | 'destroyed' | 'terminated';\nexport type ParsedQuery = {\n name: string;\n cssSelector?: string;\n state?: string;\n};\n\nconst REGEX_QUERY = /([a-zA-Z0-9]+)(\\((.*)\\))?(:([a-z]+))?/;\n\n/**\n * Parse a query string like 'Foo(.css-selector):mounted' into its parts.\n */\nexport const parseQuery = memo((query: string): ParsedQuery => {\n const [, name, , cssSelector, , state] = query.match(REGEX_QUERY) as [\n string,\n string,\n string | undefined,\n string | undefined,\n string | undefined,\n ComponentState | undefined,\n ];\n\n return {\n name,\n cssSelector,\n state,\n };\n});\n\nexport function instanceIsMatching(instance: Base, parsedQuery: ParsedQuery): boolean {\n if (instance.$config.name !== parsedQuery.name) return false;\n if (parsedQuery.cssSelector && !instance.$el.matches(parsedQuery.cssSelector)) return false;\n\n if (parsedQuery.state === 'mounted' && !instance.$isMounted) return false;\n if (parsedQuery.state === 'destroyed' && instance.$isMounted) return false;\n\n return true;\n}\n\n/**\n * Get the first instance of component with the given query.\n */\nexport function queryComponent<T extends Base = Base>(\n query: string,\n options: QueryOptions = {},\n): T | undefined {\n const parsedQuery = parseQuery(query);\n const { from = document } = options;\n const instances = getInstances() as ReadonlySet<T>;\n\n for (const instance of instances) {\n if (!instanceIsMatching(instance, parsedQuery)) continue;\n if (from !== document && !(from === instance.$el || from.contains(instance.$el))) continue;\n\n return instance;\n }\n}\n\n/**\n * Get all instances of component with the given query.\n */\nexport function queryComponentAll<T extends Base = Base>(\n query: string,\n options: QueryOptions = {},\n): T[] {\n const parsedQuery = parseQuery(query);\n const { from = document } = options;\n const instances = getInstances() as ReadonlySet<T>;\n const selectedInstances = new Set<T>();\n\n for (const instance of instances) {\n if (!instanceIsMatching(instance, parsedQuery)) continue;\n if (from !== document && !(from === instance.$el || from.contains(instance.$el))) continue;\n\n selectedInstances.add(instance);\n }\n\n return Array.from(selectedInstances);\n}\n\n/**\n * Get the closest component instance by traversing up the DOM tree.\n */\nexport function closestComponent<T extends Base = Base>(\n query: string,\n options: { from: HTMLElement } = { from: null },\n): T | undefined {\n const { from } = options;\n const parsedQuery = parseQuery(query);\n let closestInstance: T | undefined;\n\n getAncestorWhere(from, (element) => {\n if (!element) return false;\n\n // Use the element's __base__ map for O(1) lookup by component name\n const baseMap = (element as BaseEl).__base__;\n if (!baseMap) return false;\n\n const instance = baseMap.get(parsedQuery.name) as T;\n if (instance && instance !== ('terminated' as unknown) && instanceIsMatching(instance, parsedQuery)) {\n closestInstance = instance;\n return true;\n }\n\n return false;\n });\n\n return closestInstance;\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,oBAAoB;AAC7B,SAAS,YAAY;AACrB,SAAS,wBAAwB;AAajC,MAAM,cAAc;AAKb,MAAM,aAAa,KAAK,CAAC,UAA+B;AAC7D,QAAM,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,IAAI,MAAM,MAAM,WAAW;AAShE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF,CAAC;AAEM,SAAS,mBAAmB,UAAgB,aAAmC;AACpF,MAAI,SAAS,QAAQ,SAAS,YAAY,KAAM,QAAO;AACvD,MAAI,YAAY,eAAe,CAAC,SAAS,IAAI,QAAQ,YAAY,WAAW,EAAG,QAAO;AAEtF,MAAI,YAAY,UAAU,aAAa,CAAC,SAAS,WAAY,QAAO;AACpE,MAAI,YAAY,UAAU,eAAe,SAAS,WAAY,QAAO;AAErE,SAAO;AACT;AAKO,SAAS,eACd,OACA,UAAwB,CAAC,GACV;AACf,QAAM,cAAc,WAAW,KAAK;AACpC,QAAM,EAAE,OAAO,SAAS,IAAI;AAC5B,QAAM,YAAY,aAAa;AAE/B,aAAW,YAAY,WAAW;AAChC,QAAI,CAAC,mBAAmB,UAAU,WAAW,EAAG;AAChD,QAAI,SAAS,YAAY,EAAE,SAAS,SAAS,OAAO,KAAK,SAAS,SAAS,GAAG,GAAI;AAElF,WAAO;AAAA,EACT;AACF;AAKO,SAAS,kBACd,OACA,UAAwB,CAAC,GACpB;AACL,QAAM,cAAc,WAAW,KAAK;AACpC,QAAM,EAAE,OAAO,SAAS,IAAI;AAC5B,QAAM,YAAY,aAAa;AAC/B,QAAM,oBAAoB,oBAAI,IAAO;AAErC,aAAW,YAAY,WAAW;AAChC,QAAI,CAAC,mBAAmB,UAAU,WAAW,EAAG;AAChD,QAAI,SAAS,YAAY,EAAE,SAAS,SAAS,OAAO,KAAK,SAAS,SAAS,GAAG,GAAI;AAElF,sBAAkB,IAAI,QAAQ;AAAA,EAChC;AAEA,SAAO,MAAM,KAAK,iBAAiB;AACrC;AAKO,SAAS,iBACd,OACA,UAAiC,EAAE,MAAM,KAAK,GAC/B;AACf,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,cAAc,WAAW,KAAK;AACpC,MAAI;AAEJ,mBAAiB,MAAM,CAAC,YAAY;AAClC,QAAI,CAAC,QAAS,QAAO;AAGrB,UAAM,UAAW,QAAmB;AACpC,QAAI,CAAC,QAAS,QAAO;AAErB,UAAM,WAAW,QAAQ,IAAI,YAAY,IAAI;AAC7C,QAAI,YAAY,aAAc,gBAA4B,mBAAmB,UAAU,WAAW,GAAG;AACnG,wBAAkB;AAClB,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT,CAAC;AAED,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
package/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../packages/js-toolkit/index.ts"],
|
|
4
|
-
"sourcesContent": ["export const version = '3.
|
|
4
|
+
"sourcesContent": ["export const version = '3.6.0-beta.0' as const;\n\nexport * from './Base/index.js';\nexport * from './Base/types.js';\nexport * from './decorators/index.js';\nexport * from './helpers/index.js';\nexport * from './services/index.js';\n"],
|
|
5
5
|
"mappings": "AAAO,MAAM,UAAU;AAEvB,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -82,7 +82,7 @@ export declare class AbstractService<PropsType = any> {
|
|
|
82
82
|
/**
|
|
83
83
|
* Implements the EventListenerObject interface.
|
|
84
84
|
*/
|
|
85
|
-
handleEvent(
|
|
85
|
+
handleEvent(_event: Event): void;
|
|
86
86
|
/**
|
|
87
87
|
* Add or remove event listeners based on the static `config` property.
|
|
88
88
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../packages/js-toolkit/services/AbstractService.ts"],
|
|
4
|
-
"sourcesContent": ["import { cache } from '../utils/cache.js';\n\nexport interface ServiceInterface<T> {\n /**\n * Remove a function from the resize service by its key.\n */\n remove(key: string | symbol): void;\n /**\n * Add a callback to the service. The callback will receive the current service props as parameter.\n */\n add(key: string | symbol, callback: (props: T) => void): void;\n /**\n * Test if the service has alreaydy a callback for the given key.\n */\n has(key: string | symbol): boolean;\n /**\n * Get the service's props.\n */\n props(): T;\n}\n\n/**\n * Service configuration of events to be attached to targets.\n */\nexport type ServiceConfig = [\n (instance: AbstractService) => EventTarget,\n [string, AddEventListenerOptions?][],\n][];\n\n/**\n * AbstractService class.\n */\nexport class AbstractService<PropsType = any> {\n /**\n * Used to type `this.constructor` correctly\n * @link https://github.com/microsoft/TypeScript/issues/3841#issuecomment-2381594311\n */\n declare ['constructor']: typeof AbstractService;\n\n /**\n * Service configuration.\n */\n static config: ServiceConfig = [];\n\n /**\n * Cache for the created instances.\n */\n static __instances = new Map();\n\n /**\n * Get a service instance as a singleton based on the given key.\n */\n static getInstance<T extends ServiceInterface<any>>(keys: any = [this], ...args: any[]) {\n return cache(keys, () => {\n // @ts-ignore\n const instance = new this(...args);\n return {\n add: (key, callback) => instance.add(key, callback),\n remove: (key) => instance.remove(key),\n has: (key) => instance.has(key),\n props: () => instance.props,\n } as T;\n });\n }\n\n /**\n * Is the service active or not?\n */\n __isInit = false;\n\n /**\n * Props for the service.\n */\n props = {};\n\n /**\n * Holds all the callbacks that will be triggered.\n */\n callbacks: Map<string | symbol, (props: PropsType) => unknown> = new Map();\n\n /**\n * Does the service has the given key?\n */\n has(key: string | symbol): boolean {\n return this.callbacks.has(key);\n }\n\n /**\n * Get a service callback by its key.\n */\n get(key: string | symbol): (props: PropsType) => unknown {\n return this.callbacks.get(key);\n }\n\n /**\n * Add a callback to the service.\n */\n add(key: string | symbol, callback: (props: PropsType) => unknown) {\n if (this.has(key)) {\n console.warn(`The key \\`${String(key)}\\` has already been added.`);\n return;\n }\n\n // Initialize the service when we add the first callback\n if (this.callbacks.size === 0 && !this.__isInit) {\n this.init();\n this.__isInit = true;\n }\n\n this.callbacks.set(key, callback);\n }\n\n /**\n * Remove a callback from the service by its key.\n */\n remove(key: string | symbol) {\n this.callbacks.delete(key);\n\n // Kill the service when we remove the last callback\n if (this.callbacks.size === 0 && this.__isInit) {\n this.kill();\n this.__isInit = false;\n }\n }\n\n /**\n * Trigger all service callbacks with service props.\n */\n trigger(props: PropsType) {\n for (const callback of this.callbacks.values()) {\n callback(props);\n }\n }\n\n /* v8 ignore next 6 */\n /**\n * Implements the EventListenerObject interface.\n */\n handleEvent(
|
|
5
|
-
"mappings": "AAAA,SAAS,aAAa;AAgCf,MAAM,gBAAiC;AAAA;AAAA;AAAA;AAAA,EAU5C,OAAO,SAAwB,CAAC;AAAA;AAAA;AAAA;AAAA,EAKhC,OAAO,cAAc,oBAAI,IAAI;AAAA;AAAA;AAAA;AAAA,EAK7B,OAAO,YAA6C,OAAY,CAAC,IAAI,MAAM,MAAa;AACtF,WAAO,MAAM,MAAM,MAAM;AAEvB,YAAM,WAAW,IAAI,KAAK,GAAG,IAAI;AACjC,aAAO;AAAA,QACL,KAAK,CAAC,KAAK,aAAa,SAAS,IAAI,KAAK,QAAQ;AAAA,QAClD,QAAQ,CAAC,QAAQ,SAAS,OAAO,GAAG;AAAA,QACpC,KAAK,CAAC,QAAQ,SAAS,IAAI,GAAG;AAAA,QAC9B,OAAO,MAAM,SAAS;AAAA,MACxB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW;AAAA;AAAA;AAAA;AAAA,EAKX,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA,EAKT,YAAiE,oBAAI,IAAI;AAAA;AAAA;AAAA;AAAA,EAKzE,IAAI,KAA+B;AACjC,WAAO,KAAK,UAAU,IAAI,GAAG;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,KAAqD;AACvD,WAAO,KAAK,UAAU,IAAI,GAAG;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,KAAsB,UAAyC;AACjE,QAAI,KAAK,IAAI,GAAG,GAAG;AACjB,cAAQ,KAAK,aAAa,OAAO,GAAG,CAAC,4BAA4B;AACjE;AAAA,IACF;AAGA,QAAI,KAAK,UAAU,SAAS,KAAK,CAAC,KAAK,UAAU;AAC/C,WAAK,KAAK;AACV,WAAK,WAAW;AAAA,IAClB;AAEA,SAAK,UAAU,IAAI,KAAK,QAAQ;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,KAAsB;AAC3B,SAAK,UAAU,OAAO,GAAG;AAGzB,QAAI,KAAK,UAAU,SAAS,KAAK,KAAK,UAAU;AAC9C,WAAK,KAAK;AACV,WAAK,WAAW;AAAA,IAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,OAAkB;AACxB,eAAW,YAAY,KAAK,UAAU,OAAO,GAAG;AAC9C,eAAS,KAAK;AAAA,IAChB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,
|
|
4
|
+
"sourcesContent": ["import { cache } from '../utils/cache.js';\n\nexport interface ServiceInterface<T> {\n /**\n * Remove a function from the resize service by its key.\n */\n remove(key: string | symbol): void;\n /**\n * Add a callback to the service. The callback will receive the current service props as parameter.\n */\n add(key: string | symbol, callback: (props: T) => void): void;\n /**\n * Test if the service has alreaydy a callback for the given key.\n */\n has(key: string | symbol): boolean;\n /**\n * Get the service's props.\n */\n props(): T;\n}\n\n/**\n * Service configuration of events to be attached to targets.\n */\nexport type ServiceConfig = [\n (instance: AbstractService) => EventTarget,\n [string, AddEventListenerOptions?][],\n][];\n\n/**\n * AbstractService class.\n */\nexport class AbstractService<PropsType = any> {\n /**\n * Used to type `this.constructor` correctly\n * @link https://github.com/microsoft/TypeScript/issues/3841#issuecomment-2381594311\n */\n declare ['constructor']: typeof AbstractService;\n\n /**\n * Service configuration.\n */\n static config: ServiceConfig = [];\n\n /**\n * Cache for the created instances.\n */\n static __instances = new Map();\n\n /**\n * Get a service instance as a singleton based on the given key.\n */\n static getInstance<T extends ServiceInterface<any>>(keys: any = [this], ...args: any[]) {\n return cache(keys, () => {\n // @ts-ignore\n const instance = new this(...args);\n return {\n add: (key, callback) => instance.add(key, callback),\n remove: (key) => instance.remove(key),\n has: (key) => instance.has(key),\n props: () => instance.props,\n } as T;\n });\n }\n\n /**\n * Is the service active or not?\n */\n __isInit = false;\n\n /**\n * Props for the service.\n */\n props = {};\n\n /**\n * Holds all the callbacks that will be triggered.\n */\n callbacks: Map<string | symbol, (props: PropsType) => unknown> = new Map();\n\n /**\n * Does the service has the given key?\n */\n has(key: string | symbol): boolean {\n return this.callbacks.has(key);\n }\n\n /**\n * Get a service callback by its key.\n */\n get(key: string | symbol): (props: PropsType) => unknown {\n return this.callbacks.get(key);\n }\n\n /**\n * Add a callback to the service.\n */\n add(key: string | symbol, callback: (props: PropsType) => unknown) {\n if (this.has(key)) {\n console.warn(`The key \\`${String(key)}\\` has already been added.`);\n return;\n }\n\n // Initialize the service when we add the first callback\n if (this.callbacks.size === 0 && !this.__isInit) {\n this.init();\n this.__isInit = true;\n }\n\n this.callbacks.set(key, callback);\n }\n\n /**\n * Remove a callback from the service by its key.\n */\n remove(key: string | symbol) {\n this.callbacks.delete(key);\n\n // Kill the service when we remove the last callback\n if (this.callbacks.size === 0 && this.__isInit) {\n this.kill();\n this.__isInit = false;\n }\n }\n\n /**\n * Trigger all service callbacks with service props.\n */\n trigger(props: PropsType) {\n for (const callback of this.callbacks.values()) {\n callback(props);\n }\n }\n\n /* v8 ignore next 6 */\n /**\n * Implements the EventListenerObject interface.\n */\n handleEvent(_event: Event) {\n // Should be implemented.\n }\n\n /**\n * Add or remove event listeners based on the static `config` property.\n */\n __manageEvents(mode: 'add' | 'remove') {\n for (const [target, events] of this.constructor.config) {\n const resolvedTarget = target(this);\n for (const [type, options] of events) {\n resolvedTarget[`${mode}EventListener`](type, this, options);\n }\n }\n }\n\n /**\n * Triggered when the service is initialized.\n */\n init() {\n this.__manageEvents('add');\n }\n\n /**\n * Triggered when the service is killed.\n */\n kill() {\n this.__manageEvents('remove');\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,aAAa;AAgCf,MAAM,gBAAiC;AAAA;AAAA;AAAA;AAAA,EAU5C,OAAO,SAAwB,CAAC;AAAA;AAAA;AAAA;AAAA,EAKhC,OAAO,cAAc,oBAAI,IAAI;AAAA;AAAA;AAAA;AAAA,EAK7B,OAAO,YAA6C,OAAY,CAAC,IAAI,MAAM,MAAa;AACtF,WAAO,MAAM,MAAM,MAAM;AAEvB,YAAM,WAAW,IAAI,KAAK,GAAG,IAAI;AACjC,aAAO;AAAA,QACL,KAAK,CAAC,KAAK,aAAa,SAAS,IAAI,KAAK,QAAQ;AAAA,QAClD,QAAQ,CAAC,QAAQ,SAAS,OAAO,GAAG;AAAA,QACpC,KAAK,CAAC,QAAQ,SAAS,IAAI,GAAG;AAAA,QAC9B,OAAO,MAAM,SAAS;AAAA,MACxB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW;AAAA;AAAA;AAAA;AAAA,EAKX,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA,EAKT,YAAiE,oBAAI,IAAI;AAAA;AAAA;AAAA;AAAA,EAKzE,IAAI,KAA+B;AACjC,WAAO,KAAK,UAAU,IAAI,GAAG;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,KAAqD;AACvD,WAAO,KAAK,UAAU,IAAI,GAAG;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,KAAsB,UAAyC;AACjE,QAAI,KAAK,IAAI,GAAG,GAAG;AACjB,cAAQ,KAAK,aAAa,OAAO,GAAG,CAAC,4BAA4B;AACjE;AAAA,IACF;AAGA,QAAI,KAAK,UAAU,SAAS,KAAK,CAAC,KAAK,UAAU;AAC/C,WAAK,KAAK;AACV,WAAK,WAAW;AAAA,IAClB;AAEA,SAAK,UAAU,IAAI,KAAK,QAAQ;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,KAAsB;AAC3B,SAAK,UAAU,OAAO,GAAG;AAGzB,QAAI,KAAK,UAAU,SAAS,KAAK,KAAK,UAAU;AAC9C,WAAK,KAAK;AACV,WAAK,WAAW;AAAA,IAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,OAAkB;AACxB,eAAW,YAAY,KAAK,UAAU,OAAO,GAAG;AAC9C,eAAS,KAAK;AAAA,IAChB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,QAAe;AAAA,EAE3B;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,MAAwB;AACrC,eAAW,CAAC,QAAQ,MAAM,KAAK,KAAK,YAAY,QAAQ;AACtD,YAAM,iBAAiB,OAAO,IAAI;AAClC,iBAAW,CAAC,MAAM,OAAO,KAAK,QAAQ;AACpC,uBAAe,GAAG,IAAI,eAAe,EAAE,MAAM,MAAM,OAAO;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO;AACL,SAAK,eAAe,KAAK;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO;AACL,SAAK,eAAe,QAAQ;AAAA,EAC9B;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -71,11 +71,11 @@ export interface DragServiceOptions {
|
|
|
71
71
|
}
|
|
72
72
|
export declare class DragService extends AbstractService<DragServiceProps> {
|
|
73
73
|
static MODES: {
|
|
74
|
-
readonly START:
|
|
75
|
-
readonly DRAG:
|
|
76
|
-
readonly DROP:
|
|
77
|
-
readonly INERTIA:
|
|
78
|
-
readonly STOP:
|
|
74
|
+
readonly START: 'start';
|
|
75
|
+
readonly DRAG: 'drag';
|
|
76
|
+
readonly DROP: 'drop';
|
|
77
|
+
readonly INERTIA: 'inertia';
|
|
78
|
+
readonly STOP: 'stop';
|
|
79
79
|
};
|
|
80
80
|
static config: ServiceConfig;
|
|
81
81
|
id: string;
|
package/services/RafService.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export declare class RafService extends AbstractService<RafServiceProps> {
|
|
|
13
13
|
/**
|
|
14
14
|
* @private
|
|
15
15
|
*/
|
|
16
|
-
scheduler: Record<"
|
|
16
|
+
scheduler: Record<"afterWrite" | "read" | "write", (fn: () => unknown) => void>;
|
|
17
17
|
props: RafServiceProps;
|
|
18
18
|
trigger(props: RafServiceProps): void;
|
|
19
19
|
loop(): void;
|
package/services/RafService.js
CHANGED
|
@@ -15,16 +15,22 @@ class RafService extends AbstractService {
|
|
|
15
15
|
delta: 0
|
|
16
16
|
};
|
|
17
17
|
trigger(props) {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
this.scheduler.read(() => {
|
|
19
|
+
const writeQueue = [];
|
|
20
|
+
for (const callback of this.callbacks.values()) {
|
|
20
21
|
const render = callback(props);
|
|
21
22
|
if (isFunction(render)) {
|
|
22
|
-
|
|
23
|
-
render(props);
|
|
24
|
-
});
|
|
23
|
+
writeQueue.push(render);
|
|
25
24
|
}
|
|
26
|
-
}
|
|
27
|
-
|
|
25
|
+
}
|
|
26
|
+
if (writeQueue.length > 0) {
|
|
27
|
+
this.scheduler.write(() => {
|
|
28
|
+
for (let i = 0; i < writeQueue.length; i++) {
|
|
29
|
+
writeQueue[i](props);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
});
|
|
28
34
|
}
|
|
29
35
|
loop() {
|
|
30
36
|
const time = performance.now();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../packages/js-toolkit/services/RafService.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ServiceInterface } from './AbstractService.js';\nimport { AbstractService } from './AbstractService.js';\nimport { domScheduler } from '../utils/scheduler.js';\nimport { isFunction } from '../utils/is.js';\n\nexport interface RafServiceProps {\n time: DOMHighResTimeStamp;\n delta: number;\n}\n\nexport type RafServiceInterface = ServiceInterface<RafServiceProps>;\n\nexport class RafService extends AbstractService<RafServiceProps> {\n /**\n * @private\n */\n isTicking = false;\n\n /**\n * @private\n */\n scheduler = domScheduler;\n\n props: RafServiceProps = {\n time: performance.now(),\n delta: 0,\n };\n\n trigger(props: RafServiceProps) {\n for (const callback of this.callbacks.values()) {\n
|
|
5
|
-
"mappings": "AACA,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AASpB,MAAM,mBAAmB,gBAAiC;AAAA;AAAA;AAAA;AAAA,EAI/D,YAAY;AAAA;AAAA;AAAA;AAAA,EAKZ,YAAY;AAAA,EAEZ,QAAyB;AAAA,IACvB,MAAM,YAAY,IAAI;AAAA,IACtB,OAAO;AAAA,EACT;AAAA,EAEA,QAAQ,OAAwB;AAC9B,
|
|
4
|
+
"sourcesContent": ["import type { ServiceInterface } from './AbstractService.js';\nimport { AbstractService } from './AbstractService.js';\nimport { domScheduler } from '../utils/scheduler.js';\nimport { isFunction } from '../utils/is.js';\n\nexport interface RafServiceProps {\n time: DOMHighResTimeStamp;\n delta: number;\n}\n\nexport type RafServiceInterface = ServiceInterface<RafServiceProps>;\n\nexport class RafService extends AbstractService<RafServiceProps> {\n /**\n * @private\n */\n isTicking = false;\n\n /**\n * @private\n */\n scheduler = domScheduler;\n\n props: RafServiceProps = {\n time: performance.now(),\n delta: 0,\n };\n\n trigger(props: RafServiceProps) {\n this.scheduler.read(() => {\n const writeQueue: Array<(props: RafServiceProps) => unknown> = [];\n\n for (const callback of this.callbacks.values()) {\n const render = callback(props) as ((props: RafServiceProps) => unknown) | void;\n if (isFunction(render)) {\n writeQueue.push(render);\n }\n }\n\n if (writeQueue.length > 0) {\n this.scheduler.write(() => {\n for (let i = 0; i < writeQueue.length; i++) {\n writeQueue[i](props);\n }\n });\n }\n });\n }\n\n loop() {\n const time = performance.now();\n this.props.delta = time - this.props.time;\n this.props.time = time;\n this.trigger(this.props);\n\n if (!this.isTicking) {\n return;\n }\n\n requestAnimationFrame(() => this.loop());\n }\n\n init() {\n this.isTicking = true;\n requestAnimationFrame(() => this.loop());\n }\n\n kill() {\n this.isTicking = false;\n }\n}\n\n/**\n * Use the RequestAnimationFrame (raf) service.\n * @link https://js-toolkit.studiometa.dev/api/services/useRaf.html\n*/\nexport function useRaf(): RafServiceInterface {\n return RafService.getInstance();\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AASpB,MAAM,mBAAmB,gBAAiC;AAAA;AAAA;AAAA;AAAA,EAI/D,YAAY;AAAA;AAAA;AAAA;AAAA,EAKZ,YAAY;AAAA,EAEZ,QAAyB;AAAA,IACvB,MAAM,YAAY,IAAI;AAAA,IACtB,OAAO;AAAA,EACT;AAAA,EAEA,QAAQ,OAAwB;AAC9B,SAAK,UAAU,KAAK,MAAM;AACxB,YAAM,aAAyD,CAAC;AAEhE,iBAAW,YAAY,KAAK,UAAU,OAAO,GAAG;AAC9C,cAAM,SAAS,SAAS,KAAK;AAC7B,YAAI,WAAW,MAAM,GAAG;AACtB,qBAAW,KAAK,MAAM;AAAA,QACxB;AAAA,MACF;AAEA,UAAI,WAAW,SAAS,GAAG;AACzB,aAAK,UAAU,MAAM,MAAM;AACzB,mBAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,uBAAW,CAAC,EAAE,KAAK;AAAA,UACrB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,OAAO;AACL,UAAM,OAAO,YAAY,IAAI;AAC7B,SAAK,MAAM,QAAQ,OAAO,KAAK,MAAM;AACrC,SAAK,MAAM,OAAO;AAClB,SAAK,QAAQ,KAAK,KAAK;AAEvB,QAAI,CAAC,KAAK,WAAW;AACnB;AAAA,IACF;AAEA,0BAAsB,MAAM,KAAK,KAAK,CAAC;AAAA,EACzC;AAAA,EAEA,OAAO;AACL,SAAK,YAAY;AACjB,0BAAsB,MAAM,KAAK,KAAK,CAAC;AAAA,EACzC;AAAA,EAEA,OAAO;AACL,SAAK,YAAY;AAAA,EACnB;AACF;AAMO,SAAS,SAA8B;AAC5C,SAAO,WAAW,YAAY;AAChC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -45,14 +45,32 @@ export interface ScrollServiceProps {
|
|
|
45
45
|
export type ScrollServiceInterface = ServiceInterface<ScrollServiceProps>;
|
|
46
46
|
export declare class ScrollService extends AbstractService<ScrollServiceProps> {
|
|
47
47
|
static config: ServiceConfig;
|
|
48
|
+
/**
|
|
49
|
+
* Cached scroll max values, updated on resize and first scroll.
|
|
50
|
+
* @private
|
|
51
|
+
*/
|
|
52
|
+
__maxX: number | null;
|
|
53
|
+
__maxY: number | null;
|
|
54
|
+
/**
|
|
55
|
+
* Observe scroll container size changes that do not trigger window resize.
|
|
56
|
+
* @private
|
|
57
|
+
*/
|
|
58
|
+
__resizeObserver: ResizeObserver | null;
|
|
48
59
|
props: ScrollServiceProps;
|
|
49
60
|
updateProps(): ScrollServiceProps;
|
|
50
|
-
update(): void;
|
|
61
|
+
update(trigger?: boolean): void;
|
|
51
62
|
onScrollDebounced: (...args: unknown[]) => void;
|
|
52
63
|
/**
|
|
53
|
-
*
|
|
64
|
+
* Update cached max scroll values on resize.
|
|
65
|
+
* @private
|
|
66
|
+
*/
|
|
67
|
+
__updateMaxValues(): void;
|
|
68
|
+
/**
|
|
69
|
+
* Scroll and resize handler.
|
|
54
70
|
*/
|
|
55
|
-
handleEvent(): void;
|
|
71
|
+
handleEvent(event: Event): void;
|
|
72
|
+
init(): void;
|
|
73
|
+
kill(): void;
|
|
56
74
|
}
|
|
57
75
|
/**
|
|
58
76
|
* Use the scroll service.
|