@studiometa/js-toolkit 3.0.0-alpha.3 → 3.0.0-alpha.5

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.js CHANGED
@@ -1,4 +1,10 @@
1
- import { getComponentElements, getEventTarget, addToQueue, registerInstance } from "./utils.js";
1
+ import {
2
+ getComponentElements,
3
+ getEventTarget,
4
+ addToQueue,
5
+ addInstance,
6
+ deleteInstance
7
+ } from "./utils.js";
2
8
  import {
3
9
  ChildrenManager,
4
10
  RefsManager,
@@ -182,7 +188,6 @@ class Base extends EventTarget {
182
188
  }
183
189
  return;
184
190
  }
185
- registerInstance(this);
186
191
  this.$id = `${__config.name}-${id}`;
187
192
  id += 1;
188
193
  this.$el = element;
@@ -193,6 +198,12 @@ class Base extends EventTarget {
193
198
  for (const service of ["Options", "Services", "Events", "Refs", "Children"]) {
194
199
  this[`__${service.toLowerCase()}`] = new this.__managers[`${service}Manager`](this);
195
200
  }
201
+ this.$on("mounted", () => {
202
+ addInstance(this);
203
+ });
204
+ this.$on("destroyed", () => {
205
+ deleteInstance(this);
206
+ });
196
207
  if (isDev) {
197
208
  this.__debug("constructor", this);
198
209
  }
package/Base/Base.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/js-toolkit/Base/Base.ts"],
4
- "sourcesContent": ["/* eslint-disable no-use-before-define */\nimport { getComponentElements, getEventTarget, addToQueue, registerInstance } from './utils.js';\nimport {\n ChildrenManager,\n RefsManager,\n ServicesManager,\n EventsManager,\n OptionsManager,\n} from './managers/index.js';\nimport { noop, isDev, isFunction, isArray } from '../utils/index.js';\n\nlet id = 0;\n\nexport type BaseEl = HTMLElement & { __base__?: WeakMap<BaseConstructor, Base | 'terminated'> };\nexport type BaseConstructor<T extends Base = Base> = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new (...args: any[]): T;\n prototype: Base;\n} & Pick<typeof Base, keyof typeof Base>;\nexport type BaseAsyncConstructor<T extends Base = Base> = (\n instance: Base,\n) => Promise<BaseConstructor<T> | { default: BaseConstructor<T> }>;\nexport type BaseOptions = { [name: string]: unknown };\nexport type BaseRefs = { [name: string]: HTMLElement | HTMLElement[] };\nexport type BaseChildren = { [nameOrSelector: string]: Base[] | Promise<Base>[] };\nexport type BaseConfigComponents = {\n [nameOrSelector: string]: BaseConstructor | BaseAsyncConstructor;\n};\n\nexport type BaseConfig = {\n name: string;\n debug?: boolean;\n log?: boolean;\n refs?: string[];\n emits?: string[];\n components?: BaseConfigComponents;\n options?: import('./managers/OptionsManager').OptionsSchema;\n};\n\nexport type BaseProps = {\n $el?: HTMLElement;\n $options?: BaseOptions;\n $refs?: BaseRefs;\n $children?: BaseChildren;\n $parent?: Base;\n};\n\nexport type Managers = {\n ChildrenManager: typeof ChildrenManager;\n EventsManager: typeof EventsManager;\n OptionsManager: typeof OptionsManager;\n RefsManager: typeof RefsManager;\n ServicesManager: typeof ServicesManager;\n};\n\n/**\n * Base class.\n */\nexport class Base<T extends BaseProps = BaseProps> extends EventTarget {\n /**\n * This is a Base instance.\n */\n static readonly $isBase = true as const;\n\n /**\n * The instance parent.\n */\n $parent: T['$parent'] & Base = null;\n\n /**\n * The instance id.\n */\n $id: string;\n\n /**\n * The root element.\n */\n $el: T['$el'] & BaseEl;\n\n /**\n * The state of the component.\n */\n $isMounted = false;\n\n /**\n * Store the event handlers.\n */\n __eventHandlers: Map<string, Set<EventListenerOrEventListenerObject>> = new Map();\n\n /**\n * Get the root instance of the app.\n */\n get $root(): Base {\n if (!this.$parent) {\n return this;\n }\n\n let parent = this.$parent;\n let root = this.$parent;\n\n while (parent) {\n if (!parent.$parent) {\n root = parent;\n }\n\n parent = parent.$parent;\n }\n\n return root;\n }\n\n /**\n * Merge configuration with the parents' configurations.\n */\n get __config(): BaseConfig {\n let proto = Object.getPrototypeOf(this);\n let { config } = proto.constructor;\n\n while (proto.constructor.config && proto.constructor.$isBase) {\n config = { ...proto.constructor.config, ...config };\n\n if (proto.constructor.config.options) {\n config.options = { ...proto.constructor.config.options, ...config.options };\n }\n\n if (proto.constructor.config.emits && config.emits) {\n config.emits = [...proto.constructor.config.emits, ...config.emits];\n }\n\n proto = Object.getPrototypeOf(proto);\n }\n\n config.options = config.options ?? {};\n config.refs = config.refs ?? [];\n config.components = config.components ?? {};\n\n return config;\n }\n\n static config: BaseConfig = {\n name: 'Base',\n emits: [\n // hook events\n 'before-mounted',\n 'mounted',\n 'updated',\n 'destroyed',\n 'terminated',\n // default services' events\n 'ticked',\n 'scrolled',\n 'resized',\n 'moved',\n 'loaded',\n 'keyed',\n ],\n };\n\n __services: ServicesManager;\n\n get $services(): ServicesManager {\n return this.__services;\n }\n\n __refs: RefsManager & T['$refs'] & BaseRefs;\n\n get $refs(): RefsManager & T['$refs'] & BaseRefs {\n return this.__refs;\n }\n\n __options: OptionsManager & T['$options'] & BaseOptions;\n\n get $options(): OptionsManager & T['$options'] & BaseOptions {\n return this.__options;\n }\n\n __children: ChildrenManager & T['$children'] & BaseChildren;\n\n get $children(): ChildrenManager & T['$children'] & BaseChildren {\n return this.__children;\n }\n\n __events: EventsManager;\n\n /**\n * Small helper to log stuff.\n */\n get $log(): (...args: unknown[]) => void {\n return this.__options.log ? window.console.log.bind(window, `[${this.__config.name}]`) : noop;\n }\n\n /**\n * Small helper to make warning easier.\n */\n get $warn(): (...args: unknown[]) => void {\n return this.__options.log ? window.console.warn.bind(window, `[${this.__config.name}]`) : noop;\n }\n\n /**\n * Small helper to debug information.\n */\n get __debug(): (...args: unknown[]) => void {\n return isDev && this.__options.debug\n ? window.console.log.bind(window, `[debug] [${this.$id}]`)\n : noop;\n }\n\n /**\n * Get manager constructors.\n */\n get __managers(): Managers {\n return {\n ChildrenManager,\n EventsManager,\n OptionsManager,\n RefsManager,\n ServicesManager,\n };\n }\n\n /**\n * Call an instance method and emit corresponding events.\n */\n __callMethod(method: string, ...args: unknown[]): unknown {\n if (isDev) {\n this.__debug('callMethod', method, ...args);\n }\n\n this.$emit(method, ...args);\n\n // We always emit an event, but we do not call the method if it does not exist\n if (!isFunction(this[method])) {\n return null;\n }\n\n if (isDev) {\n this.__debug(method, this, ...args);\n }\n\n return this[method].call(this, ...args);\n }\n\n /**\n * Test if the given event has been bound to the instance.\n *\n * @param {string} event The event's name.\n * @returns {boolean} Wether the given event has been bound or not.\n */\n __hasEvent(event: string): boolean {\n const eventHandlers = this.__eventHandlers.get(event);\n return eventHandlers && eventHandlers.size > 0;\n }\n\n /**\n * Class constructor where all the magic takes place.\n *\n * @param {HTMLElement} element The component's root element dd.\n */\n constructor(element: HTMLElement) {\n super();\n\n if (!element) {\n if (isDev) {\n throw new Error('The root element must be defined.');\n }\n return;\n }\n\n const { __config } = this;\n\n if (__config.name === 'Base') {\n if (isDev) {\n throw new Error('The `config.name` property is required.');\n }\n return;\n }\n\n registerInstance(this);\n\n this.$id = `${__config.name}-${id}`;\n id += 1;\n\n this.$el = element;\n\n if (!this.$el.__base__) {\n this.$el.__base__ = new WeakMap();\n }\n\n this.$el.__base__.set(this.__ctor, this);\n\n for (const service of ['Options', 'Services', 'Events', 'Refs', 'Children']) {\n this[`__${service.toLowerCase()}`] = new this.__managers[`${service}Manager`](this);\n }\n\n if (isDev) {\n this.__debug('constructor', this);\n }\n }\n\n /**\n * Trigger the `mounted` callback.\n */\n $mount(): this {\n if (this.$isMounted) {\n return this;\n }\n\n this.$emit('before-mounted');\n\n if (isDev) {\n this.__debug('$mount');\n }\n\n addToQueue(() => this.$children.registerAll());\n addToQueue(() => this.$refs.registerAll());\n addToQueue(() => this.__events.bindRootElement());\n addToQueue(() => this.$services.enableAll());\n addToQueue(() => this.$children.mountAll());\n // eslint-disable-next-line no-return-assign\n addToQueue(() => (this.$isMounted = true));\n addToQueue(() => this.__callMethod('mounted'));\n\n return this;\n }\n\n /**\n * Update the instance children.\n */\n $update(): this {\n if (isDev) {\n this.__debug('$update');\n }\n\n // Undo\n addToQueue(() => this.$refs.unregisterAll());\n addToQueue(() => this.$services.disableAll());\n // Redo\n addToQueue(() => this.$children.registerAll());\n addToQueue(() => this.$refs.registerAll());\n addToQueue(() => this.$services.enableAll());\n // Update\n addToQueue(() => this.$children.updateAll());\n addToQueue(() => this.__callMethod('updated'));\n\n return this;\n }\n\n /**\n * Trigger the `destroyed` callback.\n */\n $destroy(): this {\n if (!this.$isMounted) {\n return this;\n }\n\n if (isDev) {\n this.__debug('$destroy');\n }\n\n // eslint-disable-next-line no-return-assign\n addToQueue(() => (this.$isMounted = false));\n addToQueue(() => this.__events.unbindRootElement());\n addToQueue(() => this.$refs.unregisterAll());\n addToQueue(() => this.$services.disableAll());\n addToQueue(() => this.$children.destroyAll());\n addToQueue(() => this.__callMethod('destroyed'));\n\n return this;\n }\n\n /**\n * Terminate a child instance when it is not needed anymore.\n */\n $terminate(): void {\n if (isDev) {\n this.__debug('$terminate');\n }\n\n // First, destroy the component.\n addToQueue(() => this.$destroy());\n // Execute the `terminated` hook if it exists\n addToQueue(() => this.__callMethod('terminated'));\n // Delete instance\n addToQueue(() => this.$el.__base__.set(this.__ctor, 'terminated'));\n }\n\n /**\n * Add an emitted event.\n *\n * @param {string} event The event name.\n * @returns {void}\n */\n __addEmits(event: string): void {\n const ctor = this.__ctor;\n if (isArray(ctor.config.emits)) {\n ctor.config.emits.push(event);\n } else {\n ctor.config.emits = [event];\n }\n }\n\n /**\n * Remove an emitted event.\n *\n * @param {string} event The event name.\n * @returns {void}\n */\n __removeEmits(event: string): void {\n const ctor = this.__ctor;\n const index = ctor.config.emits.indexOf(event);\n ctor.config.emits.splice(index, 1);\n }\n\n /**\n * Get the instance constructor.\n */\n get __ctor(): BaseConstructor {\n return this.constructor as BaseConstructor;\n }\n\n /**\n * Bind a listener function to an event.\n *\n * @param {string} event\n * Name of the event.\n * @param {EventListenerOrEventListenerObject} listener\n * Function to be called.\n * @param {boolean|AddEventListenerOptions} [options]\n * Options for the `removeEventListener` method.\n * @returns {() => void}\n * A function to unbind the listener.\n */\n $on(\n event: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): () => void {\n if (isDev) {\n this.__debug('$on', event, listener, options);\n }\n\n let set = this.__eventHandlers.get(event);\n\n if (!set) {\n set = new Set();\n this.__eventHandlers.set(event, set);\n }\n\n set.add(listener);\n\n const target = getEventTarget(this, event, this.__config);\n target.addEventListener(event, listener, options);\n\n return () => {\n this.$off(event, listener, options);\n };\n }\n\n /**\n * Unbind a listener function from an event.\n *\n * @param {string} event\n * Name of the event.\n * @param {EventListenerOrEventListenerObject} listener\n * Function to be removed.\n * @param {boolean|EventListenerOptions} [options]\n * Options for the `removeEventListener` method.\n * @returns {void}\n */\n $off(\n event: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ) {\n if (isDev) {\n this.__debug('$off', event, listener);\n }\n\n this.__eventHandlers.get(event).delete(listener);\n\n const target = getEventTarget(this, event, this.__config);\n target.removeEventListener(event, listener, options);\n }\n\n /**\n * Emits an event.\n *\n * @param {string} event Name of the event.\n * @param {any[]} args The arguments to apply to the functions bound to this event.\n * @returns {void}\n */\n $emit(event: string, ...args: unknown[]) {\n if (isDev) {\n this.__debug('$emit', event, args);\n }\n\n this.dispatchEvent(new CustomEvent(event, { detail: args }));\n }\n\n /**\n * Register and mount all instances of the component.\n */\n static $register(nameOrSelector?: string): Base[] {\n return getComponentElements(nameOrSelector ?? this.config.name).map((el) =>\n new this(el).$mount(),\n );\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* eslint-disable no-use-before-define */\nimport {\n getComponentElements,\n getEventTarget,\n addToQueue,\n addInstance,\n deleteInstance,\n} from './utils.js';\nimport {\n ChildrenManager,\n RefsManager,\n ServicesManager,\n EventsManager,\n OptionsManager,\n} from './managers/index.js';\nimport { noop, isDev, isFunction, isArray } from '../utils/index.js';\n\nlet id = 0;\n\nexport type BaseEl = HTMLElement & { __base__?: WeakMap<BaseConstructor, Base | 'terminated'> };\nexport type BaseConstructor<T extends Base = Base> = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new (...args: any[]): T;\n prototype: Base;\n} & Pick<typeof Base, keyof typeof Base>;\nexport type BaseAsyncConstructor<T extends Base = Base> = (\n instance: Base,\n) => Promise<BaseConstructor<T> | { default: BaseConstructor<T> }>;\nexport type BaseOptions = { [name: string]: unknown };\nexport type BaseRefs = { [name: string]: HTMLElement | HTMLElement[] };\nexport type BaseChildren = { [nameOrSelector: string]: Base[] | Promise<Base>[] };\nexport type BaseConfigComponents = {\n [nameOrSelector: string]: BaseConstructor | BaseAsyncConstructor;\n};\n\nexport type BaseConfig = {\n name: string;\n debug?: boolean;\n log?: boolean;\n refs?: string[];\n emits?: string[];\n components?: BaseConfigComponents;\n options?: import('./managers/OptionsManager').OptionsSchema;\n};\n\nexport type BaseProps = {\n $el?: HTMLElement;\n $options?: BaseOptions;\n $refs?: BaseRefs;\n $children?: BaseChildren;\n $parent?: Base;\n};\n\nexport type Managers = {\n ChildrenManager: typeof ChildrenManager;\n EventsManager: typeof EventsManager;\n OptionsManager: typeof OptionsManager;\n RefsManager: typeof RefsManager;\n ServicesManager: typeof ServicesManager;\n};\n\n/**\n * Base class.\n */\nexport class Base<T extends BaseProps = BaseProps> extends EventTarget {\n /**\n * This is a Base instance.\n */\n static readonly $isBase = true as const;\n\n /**\n * The instance parent.\n */\n $parent: T['$parent'] & Base = null;\n\n /**\n * The instance id.\n */\n $id: string;\n\n /**\n * The root element.\n */\n $el: T['$el'] & BaseEl;\n\n /**\n * The state of the component.\n */\n $isMounted = false;\n\n /**\n * Store the event handlers.\n */\n __eventHandlers: Map<string, Set<EventListenerOrEventListenerObject>> = new Map();\n\n /**\n * Get the root instance of the app.\n */\n get $root(): Base {\n if (!this.$parent) {\n return this;\n }\n\n let parent = this.$parent;\n let root = this.$parent;\n\n while (parent) {\n if (!parent.$parent) {\n root = parent;\n }\n\n parent = parent.$parent;\n }\n\n return root;\n }\n\n /**\n * Merge configuration with the parents' configurations.\n */\n get __config(): BaseConfig {\n let proto = Object.getPrototypeOf(this);\n let { config } = proto.constructor;\n\n while (proto.constructor.config && proto.constructor.$isBase) {\n config = { ...proto.constructor.config, ...config };\n\n if (proto.constructor.config.options) {\n config.options = { ...proto.constructor.config.options, ...config.options };\n }\n\n if (proto.constructor.config.emits && config.emits) {\n config.emits = [...proto.constructor.config.emits, ...config.emits];\n }\n\n proto = Object.getPrototypeOf(proto);\n }\n\n config.options = config.options ?? {};\n config.refs = config.refs ?? [];\n config.components = config.components ?? {};\n\n return config;\n }\n\n static config: BaseConfig = {\n name: 'Base',\n emits: [\n // hook events\n 'before-mounted',\n 'mounted',\n 'updated',\n 'destroyed',\n 'terminated',\n // default services' events\n 'ticked',\n 'scrolled',\n 'resized',\n 'moved',\n 'loaded',\n 'keyed',\n ],\n };\n\n __services: ServicesManager;\n\n get $services(): ServicesManager {\n return this.__services;\n }\n\n __refs: RefsManager & T['$refs'] & BaseRefs;\n\n get $refs(): RefsManager & T['$refs'] & BaseRefs {\n return this.__refs;\n }\n\n __options: OptionsManager & T['$options'] & BaseOptions;\n\n get $options(): OptionsManager & T['$options'] & BaseOptions {\n return this.__options;\n }\n\n __children: ChildrenManager & T['$children'] & BaseChildren;\n\n get $children(): ChildrenManager & T['$children'] & BaseChildren {\n return this.__children;\n }\n\n __events: EventsManager;\n\n /**\n * Small helper to log stuff.\n */\n get $log(): (...args: unknown[]) => void {\n return this.__options.log ? window.console.log.bind(window, `[${this.__config.name}]`) : noop;\n }\n\n /**\n * Small helper to make warning easier.\n */\n get $warn(): (...args: unknown[]) => void {\n return this.__options.log ? window.console.warn.bind(window, `[${this.__config.name}]`) : noop;\n }\n\n /**\n * Small helper to debug information.\n */\n get __debug(): (...args: unknown[]) => void {\n return isDev && this.__options.debug\n ? window.console.log.bind(window, `[debug] [${this.$id}]`)\n : noop;\n }\n\n /**\n * Get manager constructors.\n */\n get __managers(): Managers {\n return {\n ChildrenManager,\n EventsManager,\n OptionsManager,\n RefsManager,\n ServicesManager,\n };\n }\n\n /**\n * Call an instance method and emit corresponding events.\n */\n __callMethod(method: string, ...args: unknown[]): unknown {\n if (isDev) {\n this.__debug('callMethod', method, ...args);\n }\n\n this.$emit(method, ...args);\n\n // We always emit an event, but we do not call the method if it does not exist\n if (!isFunction(this[method])) {\n return null;\n }\n\n if (isDev) {\n this.__debug(method, this, ...args);\n }\n\n return this[method].call(this, ...args);\n }\n\n /**\n * Test if the given event has been bound to the instance.\n *\n * @param {string} event The event's name.\n * @returns {boolean} Wether the given event has been bound or not.\n */\n __hasEvent(event: string): boolean {\n const eventHandlers = this.__eventHandlers.get(event);\n return eventHandlers && eventHandlers.size > 0;\n }\n\n /**\n * Class constructor where all the magic takes place.\n *\n * @param {HTMLElement} element The component's root element dd.\n */\n constructor(element: HTMLElement) {\n super();\n\n if (!element) {\n if (isDev) {\n throw new Error('The root element must be defined.');\n }\n return;\n }\n\n const { __config } = this;\n\n if (__config.name === 'Base') {\n if (isDev) {\n throw new Error('The `config.name` property is required.');\n }\n return;\n }\n\n this.$id = `${__config.name}-${id}`;\n id += 1;\n\n this.$el = element;\n\n if (!this.$el.__base__) {\n this.$el.__base__ = new WeakMap();\n }\n\n this.$el.__base__.set(this.__ctor, this);\n\n for (const service of ['Options', 'Services', 'Events', 'Refs', 'Children']) {\n this[`__${service.toLowerCase()}`] = new this.__managers[`${service}Manager`](this);\n }\n\n this.$on('mounted', () => {\n addInstance(this);\n });\n this.$on('destroyed', () => {\n deleteInstance(this);\n });\n\n if (isDev) {\n this.__debug('constructor', this);\n }\n }\n\n /**\n * Trigger the `mounted` callback.\n */\n $mount(): this {\n if (this.$isMounted) {\n return this;\n }\n\n this.$emit('before-mounted');\n\n if (isDev) {\n this.__debug('$mount');\n }\n\n addToQueue(() => this.$children.registerAll());\n addToQueue(() => this.$refs.registerAll());\n addToQueue(() => this.__events.bindRootElement());\n addToQueue(() => this.$services.enableAll());\n addToQueue(() => this.$children.mountAll());\n // eslint-disable-next-line no-return-assign\n addToQueue(() => (this.$isMounted = true));\n addToQueue(() => this.__callMethod('mounted'));\n\n return this;\n }\n\n /**\n * Update the instance children.\n */\n $update(): this {\n if (isDev) {\n this.__debug('$update');\n }\n\n // Undo\n addToQueue(() => this.$refs.unregisterAll());\n addToQueue(() => this.$services.disableAll());\n // Redo\n addToQueue(() => this.$children.registerAll());\n addToQueue(() => this.$refs.registerAll());\n addToQueue(() => this.$services.enableAll());\n // Update\n addToQueue(() => this.$children.updateAll());\n addToQueue(() => this.__callMethod('updated'));\n\n return this;\n }\n\n /**\n * Trigger the `destroyed` callback.\n */\n $destroy(): this {\n if (!this.$isMounted) {\n return this;\n }\n\n if (isDev) {\n this.__debug('$destroy');\n }\n\n // eslint-disable-next-line no-return-assign\n addToQueue(() => (this.$isMounted = false));\n addToQueue(() => this.__events.unbindRootElement());\n addToQueue(() => this.$refs.unregisterAll());\n addToQueue(() => this.$services.disableAll());\n addToQueue(() => this.$children.destroyAll());\n addToQueue(() => this.__callMethod('destroyed'));\n\n return this;\n }\n\n /**\n * Terminate a child instance when it is not needed anymore.\n */\n $terminate(): void {\n if (isDev) {\n this.__debug('$terminate');\n }\n\n // First, destroy the component.\n addToQueue(() => this.$destroy());\n // Execute the `terminated` hook if it exists\n addToQueue(() => this.__callMethod('terminated'));\n // Delete instance\n addToQueue(() => this.$el.__base__.set(this.__ctor, 'terminated'));\n }\n\n /**\n * Add an emitted event.\n *\n * @param {string} event The event name.\n * @returns {void}\n */\n __addEmits(event: string): void {\n const ctor = this.__ctor;\n if (isArray(ctor.config.emits)) {\n ctor.config.emits.push(event);\n } else {\n ctor.config.emits = [event];\n }\n }\n\n /**\n * Remove an emitted event.\n *\n * @param {string} event The event name.\n * @returns {void}\n */\n __removeEmits(event: string): void {\n const ctor = this.__ctor;\n const index = ctor.config.emits.indexOf(event);\n ctor.config.emits.splice(index, 1);\n }\n\n /**\n * Get the instance constructor.\n */\n get __ctor(): BaseConstructor {\n return this.constructor as BaseConstructor;\n }\n\n /**\n * Bind a listener function to an event.\n *\n * @param {string} event\n * Name of the event.\n * @param {EventListenerOrEventListenerObject} listener\n * Function to be called.\n * @param {boolean|AddEventListenerOptions} [options]\n * Options for the `removeEventListener` method.\n * @returns {() => void}\n * A function to unbind the listener.\n */\n $on(\n event: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): () => void {\n if (isDev) {\n this.__debug('$on', event, listener, options);\n }\n\n let set = this.__eventHandlers.get(event);\n\n if (!set) {\n set = new Set();\n this.__eventHandlers.set(event, set);\n }\n\n set.add(listener);\n\n const target = getEventTarget(this, event, this.__config);\n target.addEventListener(event, listener, options);\n\n return () => {\n this.$off(event, listener, options);\n };\n }\n\n /**\n * Unbind a listener function from an event.\n *\n * @param {string} event\n * Name of the event.\n * @param {EventListenerOrEventListenerObject} listener\n * Function to be removed.\n * @param {boolean|EventListenerOptions} [options]\n * Options for the `removeEventListener` method.\n * @returns {void}\n */\n $off(\n event: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ) {\n if (isDev) {\n this.__debug('$off', event, listener);\n }\n\n this.__eventHandlers.get(event).delete(listener);\n\n const target = getEventTarget(this, event, this.__config);\n target.removeEventListener(event, listener, options);\n }\n\n /**\n * Emits an event.\n *\n * @param {string} event Name of the event.\n * @param {any[]} args The arguments to apply to the functions bound to this event.\n * @returns {void}\n */\n $emit(event: string, ...args: unknown[]) {\n if (isDev) {\n this.__debug('$emit', event, args);\n }\n\n this.dispatchEvent(new CustomEvent(event, { detail: args }));\n }\n\n /**\n * Register and mount all instances of the component.\n */\n static $register(nameOrSelector?: string): Base[] {\n return getComponentElements(nameOrSelector ?? this.config.name).map((el) =>\n new this(el).$mount(),\n );\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -11,7 +11,7 @@ export declare class AbstractManager {
11
11
  * Get the base instance root element.
12
12
  */
13
13
  get __element(): HTMLElement & {
14
- __base__?: WeakMap<import("../Base.js").BaseConstructor<Base<import("../Base.js").BaseProps>>, Base<import("../Base.js").BaseProps> | "terminated">;
14
+ __base__?: WeakMap<import("../Base.js").BaseConstructor, Base | "terminated">;
15
15
  };
16
16
  /**
17
17
  * Get the base instance config.
@@ -49,5 +49,5 @@ export declare class ChildrenManager extends AbstractManager {
49
49
  * @private
50
50
  */
51
51
  __register(name: string, component: BaseConstructor | BaseAsyncConstructor): void;
52
- __getValue(name: string, component: BaseConstructor | BaseAsyncConstructor): (Base<import("../Base.js").BaseProps> | "terminated" | Promise<Base<import("../Base.js").BaseProps> | "terminated">)[];
52
+ __getValue(name: string, component: BaseConstructor | BaseAsyncConstructor): (Base<import("../Base.js").BaseProps> | Promise<Base<import("../Base.js").BaseProps> | "terminated">)[];
53
53
  }
@@ -4,25 +4,25 @@ import type { Base } from '../index.js';
4
4
  type OptionType = StringConstructor | NumberConstructor | BooleanConstructor | ArrayConstructor | ObjectConstructor;
5
5
  type ArrayOption = {
6
6
  type: ArrayConstructor;
7
- default?: () => unknown[];
7
+ default?: (instance: Base) => unknown[];
8
8
  merge?: boolean | DeepmergeOptions;
9
9
  };
10
10
  type ObjectOption = {
11
11
  type: ObjectConstructor;
12
- default?: () => unknown;
12
+ default?: (instance: Base) => unknown;
13
13
  merge?: boolean | DeepmergeOptions;
14
14
  };
15
15
  type StringOption = {
16
16
  type: StringConstructor;
17
- default?: string;
17
+ default?: string | ((instance: Base) => string);
18
18
  };
19
19
  type NumberOption = {
20
20
  type: NumberConstructor;
21
- default?: number;
21
+ default?: number | ((instance: Base) => number);
22
22
  };
23
23
  type BooleanOption = {
24
24
  type: BooleanConstructor;
25
- default?: boolean;
25
+ default?: boolean | ((instance: Base) => boolean);
26
26
  };
27
27
  export type OptionObject = ArrayOption | ObjectOption | StringOption | NumberOption | BooleanOption;
28
28
  export type OptionsSchema = {
@@ -92,7 +92,8 @@ class OptionsManager extends AbstractManager {
92
92
  * Get an option value.
93
93
  */
94
94
  get(name, config) {
95
- const { type, default: defaultValue } = config;
95
+ const { type } = config;
96
+ const defaultValue = isFunction(config.default) ? config.default(this.__base) : config.default;
96
97
  const propertyName = __getPropertyName(name);
97
98
  const hasProperty = isDefined(this.__element.dataset[propertyName]);
98
99
  if (type === Boolean) {
@@ -110,9 +111,9 @@ class OptionsManager extends AbstractManager {
110
111
  if (type === Array || type === Object) {
111
112
  config = type === Array ? config : config;
112
113
  if (!this.__values[name]) {
113
- let val = hasProperty ? JSON.parse(value) : config.default();
114
+ let val = hasProperty ? JSON.parse(value) : defaultValue;
114
115
  if (isDefined(config.merge)) {
115
- val = isBoolean(config.merge) ? deepmerge(config.default(), val) : deepmerge(config.default(), val, config.merge);
116
+ val = isBoolean(config.merge) ? deepmerge(defaultValue, val) : deepmerge(defaultValue, val, config.merge);
116
117
  }
117
118
  this.__values[name] = val;
118
119
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../packages/js-toolkit/Base/managers/OptionsManager.ts"],
4
- "sourcesContent": ["import deepmerge from 'deepmerge';\nimport type { Options as DeepmergeOptions } from 'deepmerge';\nimport { AbstractManager } from './AbstractManager.js';\nimport { isDev, isFunction, isDefined, isBoolean, isArray, isObject } from '../../utils/index.js';\nimport type { Base } from '../index.js';\n\ntype OptionType =\n | StringConstructor\n | NumberConstructor\n | BooleanConstructor\n | ArrayConstructor\n | ObjectConstructor;\n\ntype ArrayOption = {\n type: ArrayConstructor;\n default?: () => unknown[];\n merge?: boolean | DeepmergeOptions;\n};\n\ntype ObjectOption = {\n type: ObjectConstructor;\n default?: () => unknown;\n merge?: boolean | DeepmergeOptions;\n};\n\ntype StringOption = {\n type: StringConstructor;\n default?: string;\n};\n\ntype NumberOption = {\n type: NumberConstructor;\n default?: number;\n};\n\ntype BooleanOption = {\n type: BooleanConstructor;\n default?: boolean;\n};\n\nexport type OptionObject = ArrayOption | ObjectOption | StringOption | NumberOption | BooleanOption;\nexport type OptionsSchema = { [name: string]: OptionType | OptionObject };\nexport type OptionsInterface = { [optionName: string]: unknown };\n\n/**\n * List of allowed types.\n */\nconst types: Set<OptionType> = new Set([String, Number, Boolean, Array, Object]);\n\n/**\n * The default values to return for each available type.\n */\nconst __defaultValues = {\n String: '',\n Number: 0,\n Boolean: false,\n Array: () => [],\n Object: () => ({}),\n};\n\n/**\n * Property name cache.\n */\nconst __propertyNameCache: Map<string, string> = new Map();\n\n/**\n * Get a property name.\n */\nexport function __getPropertyName(name: string, prefix = '') {\n const key = name + prefix;\n\n if (__propertyNameCache.has(key)) {\n return __propertyNameCache.get(key);\n }\n\n const propertyName = `option${prefix}${name.replace(/^\\w/, (c) => c.toUpperCase())}`;\n __propertyNameCache.set(key, propertyName);\n return propertyName;\n}\n\n/**\n * Register an option.\n *\n * @param {OptionsManager} that\n * @param {string} name\n * @param {OptionObject} config\n * @returns {void}\n * @private\n */\nfunction __register(that: OptionsManager, name: string, config: OptionObject) {\n if (!types.has(config.type)) {\n if (isDev) {\n throw new Error(\n `The \"${name}\" option has an invalid type. The allowed types are: String, Number, Boolean, Array and Object.`,\n );\n }\n return;\n }\n\n config.default = config.default ?? __defaultValues[config.type.name];\n\n if ((config.type === Array || config.type === Object) && !isFunction(config.default)) {\n if (isDev) {\n throw new Error(\n `The default value for options of type \"${config.type.name}\" must be returned by a function.`,\n );\n }\n return;\n }\n\n Object.defineProperty(that, name, {\n get: () => that.get(name, config),\n set: (value) => {\n that.set(name, value, config);\n },\n enumerable: true,\n });\n}\n\n/**\n * Class options to manage options as data attributes on an HTML element.\n *\n * @todo Use `MutationObserver` to update values? Might be more performant.\n */\nexport class OptionsManager extends AbstractManager {\n /**\n * An object to store Array and Object values for reference.\n *\n * @private\n */\n __values = {};\n\n /**\n * Default value for the name property.\n */\n name = 'Base';\n\n /**\n * Default value for the debug property.\n */\n debug = false;\n\n /**\n * Default value for the log property.\n */\n log = false;\n\n /**\n * Class constructor.\n */\n constructor(base: Base) {\n super(base);\n\n this.__hideProperties(['__values', '__defaultValues']);\n const schema: OptionsSchema = this.__config.options || {};\n this.name = this.__config.name;\n\n schema.debug = {\n type: Boolean,\n default: this.__config.debug ?? false,\n };\n\n schema.log = {\n type: Boolean,\n default: this.__config.log ?? false,\n };\n\n for (const [name, config] of Object.entries(schema)) {\n __register(\n this,\n name,\n types.has(config as OptionType)\n ? ({ type: config as OptionType } as OptionObject)\n : (config as OptionObject),\n );\n }\n }\n\n /**\n * Get an option value.\n */\n get(name: string, config: OptionObject) {\n const { type, default: defaultValue } = config;\n const propertyName = __getPropertyName(name);\n const hasProperty = isDefined(this.__element.dataset[propertyName]);\n\n if (type === Boolean) {\n if (defaultValue) {\n const negatedPropertyName = __getPropertyName(name, 'No');\n const hasNegatedProperty = isDefined(this.__element.dataset[negatedPropertyName]);\n\n return !hasNegatedProperty;\n }\n\n return hasProperty || defaultValue;\n }\n\n const value = this.__element.dataset[propertyName];\n\n if (type === Number) {\n return hasProperty ? Number(value) : defaultValue;\n }\n\n if (type === Array || type === Object) {\n // eslint-disable-next-line no-param-reassign\n config = type === Array ? (config as ArrayOption) : (config as ObjectOption);\n\n if (!this.__values[name]) {\n let val = hasProperty ? JSON.parse(value) : config.default();\n\n if (isDefined(config.merge)) {\n val = isBoolean(config.merge)\n ? deepmerge(config.default(), val)\n : deepmerge(config.default(), val, config.merge);\n }\n\n this.__values[name] = val;\n }\n\n return this.__values[name];\n }\n\n return hasProperty ? value : defaultValue;\n }\n\n /**\n * Set an option value.\n */\n set(name: string, value: unknown, config: OptionObject) {\n const { type, default: defaultValue } = config;\n const propertyName = __getPropertyName(name);\n\n if (value.constructor.name !== type.name) {\n if (isDev) {\n const val = isArray(value) || isObject(value) ? JSON.stringify(value) : value;\n throw new TypeError(\n `The \"${val}\" value for the \"${name}\" option must be of type \"${type.name}\"`,\n );\n }\n return;\n }\n\n switch (type) {\n case Boolean:\n if (defaultValue) {\n const negatedPropertyName = __getPropertyName(name, 'No');\n\n if (value) {\n delete this.__element.dataset[negatedPropertyName];\n } else {\n this.__element.dataset[negatedPropertyName] = '';\n }\n } else if (value) {\n this.__element.dataset[propertyName] = '';\n } else {\n delete this.__element.dataset[propertyName];\n }\n break;\n case Array:\n case Object:\n this.__values[name] = value;\n break;\n default:\n this.__element.dataset[propertyName] = value as string;\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import deepmerge from 'deepmerge';\nimport type { Options as DeepmergeOptions } from 'deepmerge';\nimport { AbstractManager } from './AbstractManager.js';\nimport { isDev, isFunction, isDefined, isBoolean, isArray, isObject } from '../../utils/index.js';\nimport type { Base } from '../index.js';\n\ntype OptionType =\n | StringConstructor\n | NumberConstructor\n | BooleanConstructor\n | ArrayConstructor\n | ObjectConstructor;\n\ntype ArrayOption = {\n type: ArrayConstructor;\n default?: (instance: Base) => unknown[];\n merge?: boolean | DeepmergeOptions;\n};\n\ntype ObjectOption = {\n type: ObjectConstructor;\n default?: (instance: Base) => unknown;\n merge?: boolean | DeepmergeOptions;\n};\n\ntype StringOption = {\n type: StringConstructor;\n default?: string | ((instance: Base) => string);\n};\n\ntype NumberOption = {\n type: NumberConstructor;\n default?: number | ((instance: Base) => number);\n};\n\ntype BooleanOption = {\n type: BooleanConstructor;\n default?: boolean | ((instance: Base) => boolean);\n};\n\nexport type OptionObject = ArrayOption | ObjectOption | StringOption | NumberOption | BooleanOption;\nexport type OptionsSchema = { [name: string]: OptionType | OptionObject };\nexport type OptionsInterface = { [optionName: string]: unknown };\n\n/**\n * List of allowed types.\n */\nconst types: Set<OptionType> = new Set([String, Number, Boolean, Array, Object]);\n\n/**\n * The default values to return for each available type.\n */\nconst __defaultValues = {\n String: '',\n Number: 0,\n Boolean: false,\n Array: () => [],\n Object: () => ({}),\n};\n\n/**\n * Property name cache.\n */\nconst __propertyNameCache: Map<string, string> = new Map();\n\n/**\n * Get a property name.\n */\nexport function __getPropertyName(name: string, prefix = '') {\n const key = name + prefix;\n\n if (__propertyNameCache.has(key)) {\n return __propertyNameCache.get(key);\n }\n\n const propertyName = `option${prefix}${name.replace(/^\\w/, (c) => c.toUpperCase())}`;\n __propertyNameCache.set(key, propertyName);\n return propertyName;\n}\n\n/**\n * Register an option.\n *\n * @param {OptionsManager} that\n * @param {string} name\n * @param {OptionObject} config\n * @returns {void}\n * @private\n */\nfunction __register(that: OptionsManager, name: string, config: OptionObject) {\n if (!types.has(config.type)) {\n if (isDev) {\n throw new Error(\n `The \"${name}\" option has an invalid type. The allowed types are: String, Number, Boolean, Array and Object.`,\n );\n }\n return;\n }\n\n config.default = config.default ?? __defaultValues[config.type.name];\n\n if ((config.type === Array || config.type === Object) && !isFunction(config.default)) {\n if (isDev) {\n throw new Error(\n `The default value for options of type \"${config.type.name}\" must be returned by a function.`,\n );\n }\n return;\n }\n\n Object.defineProperty(that, name, {\n get: () => that.get(name, config),\n set: (value) => {\n that.set(name, value, config);\n },\n enumerable: true,\n });\n}\n\n/**\n * Class options to manage options as data attributes on an HTML element.\n *\n * @todo Use `MutationObserver` to update values? Might be more performant.\n */\nexport class OptionsManager extends AbstractManager {\n /**\n * An object to store Array and Object values for reference.\n *\n * @private\n */\n __values = {};\n\n /**\n * Default value for the name property.\n */\n name = 'Base';\n\n /**\n * Default value for the debug property.\n */\n debug = false;\n\n /**\n * Default value for the log property.\n */\n log = false;\n\n /**\n * Class constructor.\n */\n constructor(base: Base) {\n super(base);\n\n this.__hideProperties(['__values', '__defaultValues']);\n const schema: OptionsSchema = this.__config.options || {};\n this.name = this.__config.name;\n\n schema.debug = {\n type: Boolean,\n default: this.__config.debug ?? false,\n };\n\n schema.log = {\n type: Boolean,\n default: this.__config.log ?? false,\n };\n\n for (const [name, config] of Object.entries(schema)) {\n __register(\n this,\n name,\n types.has(config as OptionType)\n ? ({ type: config as OptionType } as OptionObject)\n : (config as OptionObject),\n );\n }\n }\n\n /**\n * Get an option value.\n */\n get(name: string, config: OptionObject) {\n const { type } = config;\n const defaultValue = isFunction(config.default) ? config.default(this.__base) : config.default;\n const propertyName = __getPropertyName(name);\n const hasProperty = isDefined(this.__element.dataset[propertyName]);\n\n if (type === Boolean) {\n if (defaultValue) {\n const negatedPropertyName = __getPropertyName(name, 'No');\n const hasNegatedProperty = isDefined(this.__element.dataset[negatedPropertyName]);\n\n return !hasNegatedProperty;\n }\n\n return hasProperty || defaultValue;\n }\n\n const value = this.__element.dataset[propertyName];\n\n if (type === Number) {\n return hasProperty ? Number(value) : defaultValue;\n }\n\n if (type === Array || type === Object) {\n // eslint-disable-next-line no-param-reassign\n config = type === Array ? (config as ArrayOption) : (config as ObjectOption);\n\n if (!this.__values[name]) {\n let val = hasProperty ? JSON.parse(value) : defaultValue;\n\n if (isDefined(config.merge)) {\n val = isBoolean(config.merge)\n ? deepmerge(defaultValue, val)\n : deepmerge(defaultValue, val, config.merge);\n }\n\n this.__values[name] = val;\n }\n\n return this.__values[name];\n }\n\n return hasProperty ? value : defaultValue;\n }\n\n /**\n * Set an option value.\n */\n set(name: string, value: unknown, config: OptionObject) {\n const { type, default: defaultValue } = config;\n const propertyName = __getPropertyName(name);\n\n if (value.constructor.name !== type.name) {\n if (isDev) {\n const val = isArray(value) || isObject(value) ? JSON.stringify(value) : value;\n throw new TypeError(\n `The \"${val}\" value for the \"${name}\" option must be of type \"${type.name}\"`,\n );\n }\n return;\n }\n\n switch (type) {\n case Boolean:\n if (defaultValue) {\n const negatedPropertyName = __getPropertyName(name, 'No');\n\n if (value) {\n delete this.__element.dataset[negatedPropertyName];\n } else {\n this.__element.dataset[negatedPropertyName] = '';\n }\n } else if (value) {\n this.__element.dataset[propertyName] = '';\n } else {\n delete this.__element.dataset[propertyName];\n }\n break;\n case Array:\n case Object:\n this.__values[name] = value;\n break;\n default:\n this.__element.dataset[propertyName] = value as string;\n }\n }\n}\n"],
5
+ "mappings": "AAAA,OAAO,eAAe;AAEtB,SAAS,uBAAuB;AAChC,SAAS,OAAO,YAAY,WAAW,WAAW,SAAS,gBAAgB;AA4C3E,MAAM,QAAyB,oBAAI,IAAI,CAAC,QAAQ,QAAQ,SAAS,OAAO,MAAM,CAAC;AAK/E,MAAM,kBAAkB;AAAA,EACtB,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,OAAO,MAAM,CAAC;AAAA,EACd,QAAQ,OAAO,CAAC;AAClB;AAKA,MAAM,sBAA2C,oBAAI,IAAI;AAKlD,SAAS,kBAAkB,MAAc,SAAS,IAAI;AAC3D,QAAM,MAAM,OAAO;AAEnB,MAAI,oBAAoB,IAAI,GAAG,GAAG;AAChC,WAAO,oBAAoB,IAAI,GAAG;AAAA,EACpC;AAEA,QAAM,eAAe,SAAS,MAAM,GAAG,KAAK,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAClF,sBAAoB,IAAI,KAAK,YAAY;AACzC,SAAO;AACT;AAWA,SAAS,WAAW,MAAsB,MAAc,QAAsB;AAC5E,MAAI,CAAC,MAAM,IAAI,OAAO,IAAI,GAAG;AAC3B,QAAI,OAAO;AACT,YAAM,IAAI;AAAA,QACR,QAAQ,IAAI;AAAA,MACd;AAAA,IACF;AACA;AAAA,EACF;AAEA,SAAO,UAAU,OAAO,WAAW,gBAAgB,OAAO,KAAK,IAAI;AAEnE,OAAK,OAAO,SAAS,SAAS,OAAO,SAAS,WAAW,CAAC,WAAW,OAAO,OAAO,GAAG;AACpF,QAAI,OAAO;AACT,YAAM,IAAI;AAAA,QACR,0CAA0C,OAAO,KAAK,IAAI;AAAA,MAC5D;AAAA,IACF;AACA;AAAA,EACF;AAEA,SAAO,eAAe,MAAM,MAAM;AAAA,IAChC,KAAK,MAAM,KAAK,IAAI,MAAM,MAAM;AAAA,IAChC,KAAK,CAAC,UAAU;AACd,WAAK,IAAI,MAAM,OAAO,MAAM;AAAA,IAC9B;AAAA,IACA,YAAY;AAAA,EACd,CAAC;AACH;AAOO,MAAM,uBAAuB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlD,WAAW,CAAC;AAAA;AAAA;AAAA;AAAA,EAKZ,OAAO;AAAA;AAAA;AAAA;AAAA,EAKP,QAAQ;AAAA;AAAA;AAAA;AAAA,EAKR,MAAM;AAAA;AAAA;AAAA;AAAA,EAKN,YAAY,MAAY;AACtB,UAAM,IAAI;AAEV,SAAK,iBAAiB,CAAC,YAAY,iBAAiB,CAAC;AACrD,UAAM,SAAwB,KAAK,SAAS,WAAW,CAAC;AACxD,SAAK,OAAO,KAAK,SAAS;AAE1B,WAAO,QAAQ;AAAA,MACb,MAAM;AAAA,MACN,SAAS,KAAK,SAAS,SAAS;AAAA,IAClC;AAEA,WAAO,MAAM;AAAA,MACX,MAAM;AAAA,MACN,SAAS,KAAK,SAAS,OAAO;AAAA,IAChC;AAEA,eAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,MAAM,GAAG;AACnD;AAAA,QACE;AAAA,QACA;AAAA,QACA,MAAM,IAAI,MAAoB,IACzB,EAAE,MAAM,OAAqB,IAC7B;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAc,QAAsB;AACtC,UAAM,EAAE,KAAK,IAAI;AACjB,UAAM,eAAe,WAAW,OAAO,OAAO,IAAI,OAAO,QAAQ,KAAK,MAAM,IAAI,OAAO;AACvF,UAAM,eAAe,kBAAkB,IAAI;AAC3C,UAAM,cAAc,UAAU,KAAK,UAAU,QAAQ,YAAY,CAAC;AAElE,QAAI,SAAS,SAAS;AACpB,UAAI,cAAc;AAChB,cAAM,sBAAsB,kBAAkB,MAAM,IAAI;AACxD,cAAM,qBAAqB,UAAU,KAAK,UAAU,QAAQ,mBAAmB,CAAC;AAEhF,eAAO,CAAC;AAAA,MACV;AAEA,aAAO,eAAe;AAAA,IACxB;AAEA,UAAM,QAAQ,KAAK,UAAU,QAAQ,YAAY;AAEjD,QAAI,SAAS,QAAQ;AACnB,aAAO,cAAc,OAAO,KAAK,IAAI;AAAA,IACvC;AAEA,QAAI,SAAS,SAAS,SAAS,QAAQ;AAErC,eAAS,SAAS,QAAS,SAA0B;AAErD,UAAI,CAAC,KAAK,SAAS,IAAI,GAAG;AACxB,YAAI,MAAM,cAAc,KAAK,MAAM,KAAK,IAAI;AAE5C,YAAI,UAAU,OAAO,KAAK,GAAG;AAC3B,gBAAM,UAAU,OAAO,KAAK,IACxB,UAAU,cAAc,GAAG,IAC3B,UAAU,cAAc,KAAK,OAAO,KAAK;AAAA,QAC/C;AAEA,aAAK,SAAS,IAAI,IAAI;AAAA,MACxB;AAEA,aAAO,KAAK,SAAS,IAAI;AAAA,IAC3B;AAEA,WAAO,cAAc,QAAQ;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAc,OAAgB,QAAsB;AACtD,UAAM,EAAE,MAAM,SAAS,aAAa,IAAI;AACxC,UAAM,eAAe,kBAAkB,IAAI;AAE3C,QAAI,MAAM,YAAY,SAAS,KAAK,MAAM;AACxC,UAAI,OAAO;AACT,cAAM,MAAM,QAAQ,KAAK,KAAK,SAAS,KAAK,IAAI,KAAK,UAAU,KAAK,IAAI;AACxE,cAAM,IAAI;AAAA,UACR,QAAQ,GAAG,oBAAoB,IAAI,6BAA6B,KAAK,IAAI;AAAA,QAC3E;AAAA,MACF;AACA;AAAA,IACF;AAEA,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,YAAI,cAAc;AAChB,gBAAM,sBAAsB,kBAAkB,MAAM,IAAI;AAExD,cAAI,OAAO;AACT,mBAAO,KAAK,UAAU,QAAQ,mBAAmB;AAAA,UACnD,OAAO;AACL,iBAAK,UAAU,QAAQ,mBAAmB,IAAI;AAAA,UAChD;AAAA,QACF,WAAW,OAAO;AAChB,eAAK,UAAU,QAAQ,YAAY,IAAI;AAAA,QACzC,OAAO;AACL,iBAAO,KAAK,UAAU,QAAQ,YAAY;AAAA,QAC5C;AACA;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,aAAK,SAAS,IAAI,IAAI;AACtB;AAAA,MACF;AACE,aAAK,UAAU,QAAQ,YAAY,IAAI;AAAA,IAC3C;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -85,15 +85,13 @@ class RefsManager extends AbstractManager {
85
85
  * Register all refs.
86
86
  */
87
87
  registerAll() {
88
- for (const refName of this.__refs)
89
- __register(this, refName);
88
+ for (const refName of this.__refs) __register(this, refName);
90
89
  }
91
90
  /**
92
91
  * Unregister all refs.
93
92
  */
94
93
  unregisterAll() {
95
- for (const refName of this.__refs)
96
- __unregister(this, refName);
94
+ for (const refName of this.__refs) __unregister(this, refName);
97
95
  }
98
96
  }
99
97
  export {
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../packages/js-toolkit/Base/managers/RefsManager.ts"],
4
4
  "sourcesContent": ["import { AbstractManager } from './AbstractManager.js';\nimport {\n isDev,\n isArray,\n isDefined,\n getAncestorWhereUntil,\n endsWith,\n startsWith,\n} from '../../utils/index.js';\n\nconst NORMALIZE_REF_NAME_REGEX = /\\[\\]$/;\nconst NAMESPACED_REF_REGEX = /^(.*\\.)/;\nconst normalizedRefNamesCache = new Map();\n\n/**\n * Normalize the name of ref.\n */\nexport function normalizeRefName(name: string) {\n if (normalizedRefNamesCache.has(name)) {\n return normalizedRefNamesCache.get(name);\n }\n\n let normalizedName = name;\n\n if (endsWith(name, '[]')) {\n normalizedName = normalizedName.replace(NORMALIZE_REF_NAME_REGEX, '');\n }\n\n if (normalizedName.includes('.')) {\n return normalizedName.replace(NAMESPACED_REF_REGEX, '');\n }\n\n normalizedRefNamesCache.set(name, normalizedName);\n return normalizedName;\n}\n\n/**\n * Filter refs belonging to the related Base instance.\n */\nfunction refBelongToInstance(ref: HTMLElement, rootElement: HTMLElement, name: string) {\n const isPrefixed = startsWith(ref.dataset.ref, name);\n const firstComponentAncestor = getAncestorWhereUntil(\n ref,\n (el) =>\n el &&\n (isPrefixed ? el.dataset.component === name && el : isDefined(el.dataset.component)) &&\n el !== rootElement,\n (el) => el === rootElement,\n );\n\n return firstComponentAncestor === rootElement;\n}\n\n/**\n * Register one ref.\n *\n * @param {RefsManager} that\n * @param {string} refName The ref name.\n * @private\n */\nfunction __register(that: RefsManager, refName: string) {\n const isMultiple = endsWith(refName, '[]');\n const propName = normalizeRefName(refName);\n const { name } = that.__base.$options;\n\n const refs = Array.from(\n that.__element.querySelectorAll<HTMLElement>(\n `[data-ref=\"${refName}\"],[data-ref=\"${name}.${refName}\"]`,\n ),\n ).filter((ref) => refBelongToInstance(ref, that.__element, name));\n\n if (isDev && !isMultiple && refs.length > 1) {\n console.warn(\n // @ts-ignore\n `[${that.__base.$options.name}]`,\n `The \"${refName}\" ref has been found multiple times.`,\n 'Did you forgot to add the `[]` suffix to its name?',\n );\n }\n\n if (!isMultiple && refs.length <= 1 && !isDefined(refs[0])) {\n if (isDev) {\n console.warn(\n // @ts-ignore\n `[${that.__base.$options.name}]`,\n `The \"${refName}\" ref is missing.`,\n `Is there an \\`[data-ref=\"${refName}\"]\\` element in the component's scope?`,\n );\n }\n\n return;\n }\n\n that.__eventsManager.bindRef(refName, refs);\n\n Object.defineProperty(that, propName, {\n // @todo remove usage of non-multiple refs as array\n value: isMultiple || refs.length > 1 ? refs : refs[0],\n enumerable: true,\n configurable: true,\n });\n}\n\n/**\n * Unregister one ref.\n */\nfunction __unregister(that: RefsManager, refName: string) {\n const propName = normalizeRefName(refName);\n const refs = isArray(that[propName]) ? that[propName] : [that[propName]];\n that.__eventsManager.unbindRef(refName, refs);\n}\n\n/**\n * Refs Manager\n *\n * @todo Use `MutationObserver` to automatically update refs?\n */\nexport class RefsManager extends AbstractManager {\n /**\n * Get refs configuration.\n */\n get __refs() {\n return this.__config.refs ?? [];\n }\n\n /**\n * Register all refs.\n */\n registerAll() {\n for (const refName of this.__refs) __register(this, refName);\n }\n\n /**\n * Unregister all refs.\n */\n unregisterAll() {\n for (const refName of this.__refs) __unregister(this, refName);\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAM,2BAA2B;AACjC,MAAM,uBAAuB;AAC7B,MAAM,0BAA0B,oBAAI,IAAI;AAKjC,SAAS,iBAAiB,MAAc;AAC7C,MAAI,wBAAwB,IAAI,IAAI,GAAG;AACrC,WAAO,wBAAwB,IAAI,IAAI;AAAA,EACzC;AAEA,MAAI,iBAAiB;AAErB,MAAI,SAAS,MAAM,IAAI,GAAG;AACxB,qBAAiB,eAAe,QAAQ,0BAA0B,EAAE;AAAA,EACtE;AAEA,MAAI,eAAe,SAAS,GAAG,GAAG;AAChC,WAAO,eAAe,QAAQ,sBAAsB,EAAE;AAAA,EACxD;AAEA,0BAAwB,IAAI,MAAM,cAAc;AAChD,SAAO;AACT;AAKA,SAAS,oBAAoB,KAAkB,aAA0B,MAAc;AACrF,QAAM,aAAa,WAAW,IAAI,QAAQ,KAAK,IAAI;AACnD,QAAM,yBAAyB;AAAA,IAC7B;AAAA,IACA,CAAC,OACC,OACC,aAAa,GAAG,QAAQ,cAAc,QAAQ,KAAK,UAAU,GAAG,QAAQ,SAAS,MAClF,OAAO;AAAA,IACT,CAAC,OAAO,OAAO;AAAA,EACjB;AAEA,SAAO,2BAA2B;AACpC;AASA,SAAS,WAAW,MAAmB,SAAiB;AACtD,QAAM,aAAa,SAAS,SAAS,IAAI;AACzC,QAAM,WAAW,iBAAiB,OAAO;AACzC,QAAM,EAAE,KAAK,IAAI,KAAK,OAAO;AAE7B,QAAM,OAAO,MAAM;AAAA,IACjB,KAAK,UAAU;AAAA,MACb,cAAc,OAAO,iBAAiB,IAAI,IAAI,OAAO;AAAA,IACvD;AAAA,EACF,EAAE,OAAO,CAAC,QAAQ,oBAAoB,KAAK,KAAK,WAAW,IAAI,CAAC;AAEhE,MAAI,SAAS,CAAC,cAAc,KAAK,SAAS,GAAG;AAC3C,YAAQ;AAAA;AAAA,MAEN,IAAI,KAAK,OAAO,SAAS,IAAI;AAAA,MAC7B,QAAQ,OAAO;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,cAAc,KAAK,UAAU,KAAK,CAAC,UAAU,KAAK,CAAC,CAAC,GAAG;AAC1D,QAAI,OAAO;AACT,cAAQ;AAAA;AAAA,QAEN,IAAI,KAAK,OAAO,SAAS,IAAI;AAAA,QAC7B,QAAQ,OAAO;AAAA,QACf,4BAA4B,OAAO;AAAA,MACrC;AAAA,IACF;AAEA;AAAA,EACF;AAEA,OAAK,gBAAgB,QAAQ,SAAS,IAAI;AAE1C,SAAO,eAAe,MAAM,UAAU;AAAA;AAAA,IAEpC,OAAO,cAAc,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC;AAAA,IACpD,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB,CAAC;AACH;AAKA,SAAS,aAAa,MAAmB,SAAiB;AACxD,QAAM,WAAW,iBAAiB,OAAO;AACzC,QAAM,OAAO,QAAQ,KAAK,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,QAAQ,CAAC;AACvE,OAAK,gBAAgB,UAAU,SAAS,IAAI;AAC9C;AAOO,MAAM,oBAAoB,gBAAgB;AAAA;AAAA;AAAA;AAAA,EAI/C,IAAI,SAAS;AACX,WAAO,KAAK,SAAS,QAAQ,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc;AACZ,eAAW,WAAW,KAAK;AAAQ,iBAAW,MAAM,OAAO;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB;AACd,eAAW,WAAW,KAAK;AAAQ,mBAAa,MAAM,OAAO;AAAA,EAC/D;AACF;",
5
+ "mappings": "AAAA,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAM,2BAA2B;AACjC,MAAM,uBAAuB;AAC7B,MAAM,0BAA0B,oBAAI,IAAI;AAKjC,SAAS,iBAAiB,MAAc;AAC7C,MAAI,wBAAwB,IAAI,IAAI,GAAG;AACrC,WAAO,wBAAwB,IAAI,IAAI;AAAA,EACzC;AAEA,MAAI,iBAAiB;AAErB,MAAI,SAAS,MAAM,IAAI,GAAG;AACxB,qBAAiB,eAAe,QAAQ,0BAA0B,EAAE;AAAA,EACtE;AAEA,MAAI,eAAe,SAAS,GAAG,GAAG;AAChC,WAAO,eAAe,QAAQ,sBAAsB,EAAE;AAAA,EACxD;AAEA,0BAAwB,IAAI,MAAM,cAAc;AAChD,SAAO;AACT;AAKA,SAAS,oBAAoB,KAAkB,aAA0B,MAAc;AACrF,QAAM,aAAa,WAAW,IAAI,QAAQ,KAAK,IAAI;AACnD,QAAM,yBAAyB;AAAA,IAC7B;AAAA,IACA,CAAC,OACC,OACC,aAAa,GAAG,QAAQ,cAAc,QAAQ,KAAK,UAAU,GAAG,QAAQ,SAAS,MAClF,OAAO;AAAA,IACT,CAAC,OAAO,OAAO;AAAA,EACjB;AAEA,SAAO,2BAA2B;AACpC;AASA,SAAS,WAAW,MAAmB,SAAiB;AACtD,QAAM,aAAa,SAAS,SAAS,IAAI;AACzC,QAAM,WAAW,iBAAiB,OAAO;AACzC,QAAM,EAAE,KAAK,IAAI,KAAK,OAAO;AAE7B,QAAM,OAAO,MAAM;AAAA,IACjB,KAAK,UAAU;AAAA,MACb,cAAc,OAAO,iBAAiB,IAAI,IAAI,OAAO;AAAA,IACvD;AAAA,EACF,EAAE,OAAO,CAAC,QAAQ,oBAAoB,KAAK,KAAK,WAAW,IAAI,CAAC;AAEhE,MAAI,SAAS,CAAC,cAAc,KAAK,SAAS,GAAG;AAC3C,YAAQ;AAAA;AAAA,MAEN,IAAI,KAAK,OAAO,SAAS,IAAI;AAAA,MAC7B,QAAQ,OAAO;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,cAAc,KAAK,UAAU,KAAK,CAAC,UAAU,KAAK,CAAC,CAAC,GAAG;AAC1D,QAAI,OAAO;AACT,cAAQ;AAAA;AAAA,QAEN,IAAI,KAAK,OAAO,SAAS,IAAI;AAAA,QAC7B,QAAQ,OAAO;AAAA,QACf,4BAA4B,OAAO;AAAA,MACrC;AAAA,IACF;AAEA;AAAA,EACF;AAEA,OAAK,gBAAgB,QAAQ,SAAS,IAAI;AAE1C,SAAO,eAAe,MAAM,UAAU;AAAA;AAAA,IAEpC,OAAO,cAAc,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC;AAAA,IACpD,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB,CAAC;AACH;AAKA,SAAS,aAAa,MAAmB,SAAiB;AACxD,QAAM,WAAW,iBAAiB,OAAO;AACzC,QAAM,OAAO,QAAQ,KAAK,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,QAAQ,CAAC;AACvE,OAAK,gBAAgB,UAAU,SAAS,IAAI;AAC9C;AAOO,MAAM,oBAAoB,gBAAgB;AAAA;AAAA;AAAA;AAAA,EAI/C,IAAI,SAAS;AACX,WAAO,KAAK,SAAS,QAAQ,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc;AACZ,eAAW,WAAW,KAAK,OAAQ,YAAW,MAAM,OAAO;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB;AACd,eAAW,WAAW,KAAK,OAAQ,cAAa,MAAM,OAAO;AAAA,EAC/D;AACF;",
6
6
  "names": []
7
7
  }
package/Base/utils.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Base, BaseConfig } from './index.js';
1
+ import type { Base, BaseConfig, BaseConstructor } from './index.js';
2
2
  /**
3
3
  * Add a task to the main queue.
4
4
  */
@@ -28,5 +28,10 @@ export declare function eventIsNative(event: string, element: HTMLElement): bool
28
28
  * @todo Return false in v3 if event is not defined or not native to prevent adding a listener.
29
29
  */
30
30
  export declare function getEventTarget(instance: Base, event: string, config: BaseConfig): Base | Base['$el'];
31
- export declare function getInstances<T extends typeof Base = typeof Base>(ctor: T): Set<InstanceType<T>>;
32
- export declare function registerInstance(instance: any): void;
31
+ /**
32
+ * Get all mounted instances or the ones from a given component.
33
+ */
34
+ export declare function getInstances(): Set<Base>;
35
+ export declare function getInstances<T extends BaseConstructor = BaseConstructor>(ctor: T): Set<InstanceType<T>>;
36
+ export declare function addInstance(instance: Base): void;
37
+ export declare function deleteInstance(instance: Base): void;
package/Base/utils.js CHANGED
@@ -63,23 +63,34 @@ function getEventTarget(instance, event, config) {
63
63
  }
64
64
  return instance;
65
65
  }
66
- const instances = /* @__PURE__ */ new Map();
66
+ const instances = /* @__PURE__ */ new Set();
67
67
  function getInstances(ctor) {
68
- if (!instances.has(ctor)) {
69
- instances.set(ctor, /* @__PURE__ */ new Set());
68
+ if (isDefined(ctor)) {
69
+ const filteredInstances = /* @__PURE__ */ new Set();
70
+ for (const instance of instances) {
71
+ if (instance instanceof ctor) {
72
+ filteredInstances.add(instance);
73
+ }
74
+ }
75
+ return filteredInstances;
76
+ } else {
77
+ return new Set(instances);
70
78
  }
71
- return instances.get(ctor);
72
79
  }
73
- function registerInstance(instance) {
74
- getInstances(instance.constructor).add(instance);
80
+ function addInstance(instance) {
81
+ instances.add(instance);
82
+ }
83
+ function deleteInstance(instance) {
84
+ instances.delete(instance);
75
85
  }
76
86
  export {
87
+ addInstance,
77
88
  addToQueue,
89
+ deleteInstance,
78
90
  eventIsDefinedInConfig,
79
91
  eventIsNative,
80
92
  getComponentElements,
81
93
  getEventTarget,
82
- getInstances,
83
- registerInstance
94
+ getInstances
84
95
  };
85
96
  //# sourceMappingURL=utils.js.map
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, isDev, SmartQueue } from '../utils/index.js';\nimport type { Base, BaseConfig } from './index.js';\nimport { features } from './features.js';\n\nlet queue: SmartQueue;\n\n/**\n * Add a task to the main queue.\n */\nexport function addToQueue(fn: () => unknown): void {\n if (features.get('blocking')) {\n fn();\n return;\n }\n\n if (!queue) {\n queue = new SmartQueue();\n }\n\n 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 */\nfunction getSelector(nameOrSelector: string): string {\n if (!selectors.has(nameOrSelector)) {\n const parts = [\n // Single selector\n `[data-component=\"${nameOrSelector}\"]`,\n // Selector in the middle of a list of selectors\n `[data-component*=\"${separator}${nameOrSelector}${separator}\"]`,\n // Selector at the end of a list of selectors\n `[data-component$=\"${separator}${nameOrSelector}\"]`,\n // Selector at the beginning of a list of selectors\n `[data-component^=\"${nameOrSelector}${separator}\"]`,\n ];\n selectors.set(nameOrSelector, parts.join(','));\n }\n\n return selectors.get(nameOrSelector);\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 * @returns {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 *\n * @todo Return false in v3 if event is not defined or not native to prevent adding a listener.\n */\nexport function getEventTarget(\n instance: Base,\n event: string,\n config: BaseConfig,\n): Base | Base['$el'] {\n if (eventIsDefinedInConfig(event, config)) {\n return instance;\n }\n\n if (eventIsNative(event, instance.$el)) {\n return instance.$el;\n }\n\n if (isDev) {\n console.warn(\n `[${config.name}]`,\n `The \"${event}\" event is missing from the configuration and is not a native`,\n `event for the root element of type \\`${instance.$el.constructor.name}\\`.`,\n );\n }\n\n // @todo v3 return false or null\n return instance;\n}\n\nconst instances = new Map<typeof Base, Set<Base>>();\n\nexport function getInstances<T extends typeof Base = typeof Base>(ctor: T): Set<InstanceType<T>> {\n if (!instances.has(ctor)) {\n instances.set(ctor, new Set<InstanceType<T>>());\n }\n\n return instances.get(ctor) as Set<InstanceType<T>>;\n}\n\nexport function registerInstance(instance) {\n getInstances(instance.constructor).add(instance);\n}\n"],
5
- "mappings": "AAAA,SAAS,SAAS,WAAW,OAAO,kBAAkB;AAEtD,SAAS,gBAAgB;AAEzB,IAAI;AAKG,SAAS,WAAW,IAAyB;AAClD,MAAI,SAAS,IAAI,UAAU,GAAG;AAC5B,OAAG;AACH;AAAA,EACF;AAEA,MAAI,CAAC,OAAO;AACV,YAAQ,IAAI,WAAW;AAAA,EACzB;AAEA,QAAM,IAAI,EAAE;AACd;AAEA,MAAM,YAAY,oBAAI,IAAI;AAG1B,MAAM,YAAY;AAKlB,SAAS,YAAY,gBAAgC;AACnD,MAAI,CAAC,UAAU,IAAI,cAAc,GAAG;AAClC,UAAM,QAAQ;AAAA;AAAA,MAEZ,oBAAoB,cAAc;AAAA;AAAA,MAElC,qBAAqB,SAAS,GAAG,cAAc,GAAG,SAAS;AAAA;AAAA,MAE3D,qBAAqB,SAAS,GAAG,cAAc;AAAA;AAAA,MAE/C,qBAAqB,cAAc,GAAG,SAAS;AAAA,IACjD;AACA,cAAU,IAAI,gBAAgB,MAAM,KAAK,GAAG,CAAC;AAAA,EAC/C;AAEA,SAAO,UAAU,IAAI,cAAc;AACrC;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;AAOO,SAAS,eACd,UACA,OACA,QACoB;AACpB,MAAI,uBAAuB,OAAO,MAAM,GAAG;AACzC,WAAO;AAAA,EACT;AAEA,MAAI,cAAc,OAAO,SAAS,GAAG,GAAG;AACtC,WAAO,SAAS;AAAA,EAClB;AAEA,MAAI,OAAO;AACT,YAAQ;AAAA,MACN,IAAI,OAAO,IAAI;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,wCAAwC,SAAS,IAAI,YAAY,IAAI;AAAA,IACvE;AAAA,EACF;AAGA,SAAO;AACT;AAEA,MAAM,YAAY,oBAAI,IAA4B;AAE3C,SAAS,aAAkD,MAA+B;AAC/F,MAAI,CAAC,UAAU,IAAI,IAAI,GAAG;AACxB,cAAU,IAAI,MAAM,oBAAI,IAAqB,CAAC;AAAA,EAChD;AAEA,SAAO,UAAU,IAAI,IAAI;AAC3B;AAEO,SAAS,iBAAiB,UAAU;AACzC,eAAa,SAAS,WAAW,EAAE,IAAI,QAAQ;AACjD;",
4
+ "sourcesContent": ["import { isArray, isDefined, isDev, SmartQueue } from '../utils/index.js';\nimport type { Base, BaseConfig, BaseConstructor } from './index.js';\nimport { features } from './features.js';\n\nlet queue: SmartQueue;\n\n/**\n * Add a task to the main queue.\n */\nexport function addToQueue(fn: () => unknown): void {\n if (features.get('blocking')) {\n fn();\n return;\n }\n\n if (!queue) {\n queue = new SmartQueue();\n }\n\n 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 */\nfunction getSelector(nameOrSelector: string): string {\n if (!selectors.has(nameOrSelector)) {\n const parts = [\n // Single selector\n `[data-component=\"${nameOrSelector}\"]`,\n // Selector in the middle of a list of selectors\n `[data-component*=\"${separator}${nameOrSelector}${separator}\"]`,\n // Selector at the end of a list of selectors\n `[data-component$=\"${separator}${nameOrSelector}\"]`,\n // Selector at the beginning of a list of selectors\n `[data-component^=\"${nameOrSelector}${separator}\"]`,\n ];\n selectors.set(nameOrSelector, parts.join(','));\n }\n\n return selectors.get(nameOrSelector);\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 * @returns {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 *\n * @todo Return false in v3 if event is not defined or not native to prevent adding a listener.\n */\nexport function getEventTarget(\n instance: Base,\n event: string,\n config: BaseConfig,\n): Base | Base['$el'] {\n if (eventIsDefinedInConfig(event, config)) {\n return instance;\n }\n\n if (eventIsNative(event, instance.$el)) {\n return instance.$el;\n }\n\n if (isDev) {\n console.warn(\n `[${config.name}]`,\n `The \"${event}\" event is missing from the configuration and is not a native`,\n `event for the root element of type \\`${instance.$el.constructor.name}\\`.`,\n );\n }\n\n // @todo v3 return false or null\n return instance;\n}\n\nconst instances = new Set<Base>();\n\n/**\n * Get all mounted instances or the ones from a given component.\n */\nexport function getInstances(): Set<Base>;\nexport function getInstances<T extends BaseConstructor = BaseConstructor>(ctor: T): Set<InstanceType<T>>;\nexport function getInstances<T extends BaseConstructor = BaseConstructor>(ctor?: T): Set<InstanceType<T>> | Set<Base> {\n if (isDefined(ctor)) {\n const filteredInstances = new Set<InstanceType<T>>();\n for (const instance of instances) {\n if (instance instanceof ctor) {\n filteredInstances.add(instance as InstanceType<T>);\n }\n }\n return filteredInstances;\n } else {\n return new Set(instances);\n }\n}\n\nexport function addInstance(instance: Base) {\n instances.add(instance);\n}\n\nexport function deleteInstance(instance: Base) {\n instances.delete(instance);\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS,WAAW,OAAO,kBAAkB;AAEtD,SAAS,gBAAgB;AAEzB,IAAI;AAKG,SAAS,WAAW,IAAyB;AAClD,MAAI,SAAS,IAAI,UAAU,GAAG;AAC5B,OAAG;AACH;AAAA,EACF;AAEA,MAAI,CAAC,OAAO;AACV,YAAQ,IAAI,WAAW;AAAA,EACzB;AAEA,QAAM,IAAI,EAAE;AACd;AAEA,MAAM,YAAY,oBAAI,IAAI;AAG1B,MAAM,YAAY;AAKlB,SAAS,YAAY,gBAAgC;AACnD,MAAI,CAAC,UAAU,IAAI,cAAc,GAAG;AAClC,UAAM,QAAQ;AAAA;AAAA,MAEZ,oBAAoB,cAAc;AAAA;AAAA,MAElC,qBAAqB,SAAS,GAAG,cAAc,GAAG,SAAS;AAAA;AAAA,MAE3D,qBAAqB,SAAS,GAAG,cAAc;AAAA;AAAA,MAE/C,qBAAqB,cAAc,GAAG,SAAS;AAAA,IACjD;AACA,cAAU,IAAI,gBAAgB,MAAM,KAAK,GAAG,CAAC;AAAA,EAC/C;AAEA,SAAO,UAAU,IAAI,cAAc;AACrC;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;AAOO,SAAS,eACd,UACA,OACA,QACoB;AACpB,MAAI,uBAAuB,OAAO,MAAM,GAAG;AACzC,WAAO;AAAA,EACT;AAEA,MAAI,cAAc,OAAO,SAAS,GAAG,GAAG;AACtC,WAAO,SAAS;AAAA,EAClB;AAEA,MAAI,OAAO;AACT,YAAQ;AAAA,MACN,IAAI,OAAO,IAAI;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,wCAAwC,SAAS,IAAI,YAAY,IAAI;AAAA,IACvE;AAAA,EACF;AAGA,SAAO;AACT;AAEA,MAAM,YAAY,oBAAI,IAAU;AAOzB,SAAS,aAA0D,MAA4C;AACpH,MAAI,UAAU,IAAI,GAAG;AACnB,UAAM,oBAAoB,oBAAI,IAAqB;AACnD,eAAW,YAAY,WAAW;AAChC,UAAI,oBAAoB,MAAM;AAC5B,0BAAkB,IAAI,QAA2B;AAAA,MACnD;AAAA,IACF;AACA,WAAO;AAAA,EACT,OAAO;AACL,WAAO,IAAI,IAAI,SAAS;AAAA,EAC1B;AACF;AAEO,SAAS,YAAY,UAAgB;AAC1C,YAAU,IAAI,QAAQ;AACxB;AAEO,SAAS,eAAe,UAAgB;AAC7C,YAAU,OAAO,QAAQ;AAC3B;",
6
6
  "names": []
7
7
  }
package/README.md CHANGED
@@ -30,6 +30,105 @@ This project is a JavaScript micro-framework (along with its utility functions)
30
30
 
31
31
  Visit [js-toolkit.studiometa.dev](https://js-toolkit.studiometa.dev) to learn more.
32
32
 
33
+ ## Quick overview
34
+
35
+ This framework lets you define components as classes, and bind them to the DOM with `data-…` attributes. For example, here is how a `Counter` component would be defined in JavaScript:
36
+
37
+ ```js
38
+ import { Base } from '@studiometa/js-toolkit';
39
+
40
+ export default class Counter extends Base {
41
+ static config = {
42
+ name: 'Counter',
43
+ refs: ['add', 'remove', 'count'],
44
+ };
45
+
46
+ get counter() {
47
+ return this.$refs.count.valueAsNumber;
48
+ }
49
+
50
+ set counter(value) {
51
+ this.$refs.count.value = value;
52
+ }
53
+
54
+ onAddClick() {
55
+ this.counter += 1;
56
+ }
57
+
58
+ onRemoveClick() {
59
+ this.counter -= 1;
60
+ }
61
+ }
62
+ ```
63
+
64
+ And its accompanying HTML would be sprinkled with `data-…` attributes to bind elements from the DOM to the JavaScript class.
65
+
66
+ ```html
67
+ <div data-component="Counter">
68
+ <button data-ref="add">Add</button>
69
+ <button data-ref="remove">Remove</button>
70
+ <input data-ref="count" type="number" value="0" />
71
+ </div>
72
+ ```
73
+
74
+ You can define options that can be specified with `data-option-...` attributes as well. First in JavaScript:
75
+
76
+ ```diff
77
+ class Counter extends Base {
78
+ static config = {
79
+ name: 'Counter',
80
+ refs: ['add', 'remove', 'count'],
81
+ + options: {
82
+ + step: {
83
+ + type: Number,
84
+ + default: 1,
85
+ + },
86
+ + },
87
+ };
88
+
89
+ onAddClick() {
90
+ - this.counter += 1;
91
+ + this.counter += this.$options.step;
92
+ }
93
+
94
+ onRemoveClick() {
95
+ - this.counter -= 1;
96
+ + this.counter -= this.$options.step;
97
+ }
98
+ }
99
+ ```
100
+
101
+ And then adjust it as you wish in your HTML:
102
+
103
+ ```diff
104
+ - <div data-component="Counter">
105
+ + <div data-component="Counter" data-option-step="2">
106
+ <button data-ref="add">Add</button>
107
+ <button data-ref="remove">Remove</button>
108
+ <input data-ref="count" type="number" value="0">
109
+ </div>
110
+ ```
111
+
112
+ The framework also offers a way to instantiate a root component as an application, with child components as dependencies:
113
+
114
+ ```js
115
+ import { Base, createApp } from '@studiometa/js-toolkit';
116
+ import Counter from './components/Counter.js';
117
+
118
+ class App extends Base {
119
+ static config = {
120
+ name: 'App',
121
+ components: {
122
+ Counter,
123
+ },
124
+ };
125
+ }
126
+
127
+ export default createApp(App);
128
+ ```
129
+
130
+ Visit our ["Getting Started" guide](https://js-toolkit.studiometa.dev/guide/) to learn more and try the above component by visiting [the playground](https://ui.studiometa.dev/-/play/#script=eNqVkjFPwzAQhff%2BijcguRVtEGurSpTuDKyIwdiXYprYkX2pQFX%2BO7bjlg6A1EiJndO97873bNrOecYRjzLQHMqTZNp0HQbU3rUQD4F7bVxLLO8%2BwoKda%2FaGxWoyUY0MAVvXWyYP%2BmSyOmQOjhMgsGSjoJytzQ7rHAOsbGkJUVRinoOe6rDEi5BaizmEp9YdKO1UShOvY5br2DgbE0dSqkDdzx%2FAX11kP%2FXtG%2FlRkh5NtewbXuL%2BFBvGzRC%2FQzwHsCOOfeaOprMC9MS9t%2BB3E6qb1GCVM6qDbHrahLHKKiESIVwQcsYJ87s%2BjiOvZ72zG623jVH7cwNZWZi4XRdSGUKVzn6hfs4j%2Bwew%2BBsQEaOVyfbrbIyKYqFy8SJZsnzhTzG5TDstcdyp2umSTeM7W30DtazCdQ%3D%3D&html=eNptjkEKwyAQRfc9hcw%2BpHStQukNegOTmYJQZ8SOQm9fUzcJZPX5vLd4FmMzGDRMq6QsTKwOHlJZqcAAkjUKTx%2Bl7OAG%2FmKMXaqq8OCFXg4CIvg7op0HOrcKJWkE%2Fvnfgxs5V92p69YARr%2BZHHBNy9bTwrv2e%2B0Rdu7l%2Fgd%2BLEBJ&style=eNpLyk%2BpVKjmUlAoSExJycxLt1IwLErNteaqBQBpsgf8).
131
+
33
132
  ## Contributing
34
133
 
35
134
  This projects follows the [Git Flow](https://github.com/petervanderdoes/gitflow-avh) methodology to manage its branches and features. The packages and their dependencies are managed with NPM workspaces. The files are linted with ESLint, type checked with TypeScript and formatted with Prettier.
@@ -12,8 +12,7 @@ function importWhenVisible(fn, nameOrSelectorOrElement, parent, observerOptions
12
12
  }
13
13
  }, observerOptions);
14
14
  const elements = getTargetElements(nameOrSelectorOrElement, parent?.$el);
15
- for (const element of elements)
16
- observer.observe(element);
15
+ for (const element of elements) observer.observe(element);
17
16
  });
18
17
  }
19
18
  export {
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../packages/js-toolkit/helpers/importWhenVisible.ts"],
4
4
  "sourcesContent": ["import type { Base, BaseConstructor } from '../Base/index.js';\nimport { getTargetElements } from './utils.js';\nimport { getComponentResolver } from '../utils/index.js';\n\n/**\n * Import a component when it is visible.\n *\n * @template {BaseConstructor} T\n * @param {() => Promise<T|{default:T}>} fn\n * The import function.\n * @param {string|HTMLElement|HTMLElement[]} nameOrSelectorOrElement\n * The name or selector for the component.\n * @param {Base} [parent]\n * The parent component.\n * @param {IntersectionObserverInit} [observerOptions]\n * Options for the `IntersectionObserver` instance.\n * @returns {Promise<T>}\n */\nexport default function importWhenVisible<T extends BaseConstructor = BaseConstructor>(\n fn: () => Promise<T | { default: T }>,\n nameOrSelectorOrElement: string | HTMLElement | HTMLElement[],\n parent?: Base,\n observerOptions: IntersectionObserverInit = {},\n): Promise<T> {\n const resolver = getComponentResolver(fn);\n\n return new Promise((resolve) => {\n const observer = new IntersectionObserver((entries) => {\n const someEntriesAreVisible = entries.some((entry) => entry.isIntersecting);\n if (someEntriesAreVisible) {\n setTimeout(() => {\n resolver(resolve, () => observer.disconnect());\n }, 0);\n }\n }, observerOptions);\n\n const elements = getTargetElements(nameOrSelectorOrElement, parent?.$el);\n for (const element of elements) observer.observe(element);\n });\n}\n"],
5
- "mappings": "AACA,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AAgBtB,SAAR,kBACL,IACA,yBACA,QACA,kBAA4C,CAAC,GACjC;AACZ,QAAM,WAAW,qBAAqB,EAAE;AAExC,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,WAAW,IAAI,qBAAqB,CAAC,YAAY;AACrD,YAAM,wBAAwB,QAAQ,KAAK,CAAC,UAAU,MAAM,cAAc;AAC1E,UAAI,uBAAuB;AACzB,mBAAW,MAAM;AACf,mBAAS,SAAS,MAAM,SAAS,WAAW,CAAC;AAAA,QAC/C,GAAG,CAAC;AAAA,MACN;AAAA,IACF,GAAG,eAAe;AAElB,UAAM,WAAW,kBAAkB,yBAAyB,QAAQ,GAAG;AACvE,eAAW,WAAW;AAAU,eAAS,QAAQ,OAAO;AAAA,EAC1D,CAAC;AACH;",
5
+ "mappings": "AACA,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AAgBtB,SAAR,kBACL,IACA,yBACA,QACA,kBAA4C,CAAC,GACjC;AACZ,QAAM,WAAW,qBAAqB,EAAE;AAExC,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,WAAW,IAAI,qBAAqB,CAAC,YAAY;AACrD,YAAM,wBAAwB,QAAQ,KAAK,CAAC,UAAU,MAAM,cAAc;AAC1E,UAAI,uBAAuB;AACzB,mBAAW,MAAM;AACf,mBAAS,SAAS,MAAM,SAAS,WAAW,CAAC;AAAA,QAC/C,GAAG,CAAC;AAAA,MACN;AAAA,IACF,GAAG,eAAe;AAElB,UAAM,WAAW,kBAAkB,yBAAyB,QAAQ,GAAG;AACvE,eAAW,WAAW,SAAU,UAAS,QAAQ,OAAO;AAAA,EAC1D,CAAC;AACH;",
6
6
  "names": []
7
7
  }
package/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- export { Base } from './Base/index.js';
1
+ export * from './Base/index.js';
2
+ export * from './Base/types.js';
2
3
  export * from './decorators/index.js';
3
4
  export * from './helpers/index.js';
4
5
  export * from './services/index.js';
5
- export type { BaseProps, BaseConstructor, BaseAsyncConstructor, BaseConfig } from './Base/index.js';
6
- export type { BaseInterface, BaseDecorator } from './Base/types.js';
package/index.js CHANGED
@@ -1,8 +1,6 @@
1
- import { Base } from "./Base/index.js";
1
+ export * from "./Base/index.js";
2
+ export * from "./Base/types.js";
2
3
  export * from "./decorators/index.js";
3
4
  export * from "./helpers/index.js";
4
5
  export * from "./services/index.js";
5
- export {
6
- Base
7
- };
8
6
  //# sourceMappingURL=index.js.map
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 { Base } from './Base/index.js';\nexport * from './decorators/index.js';\nexport * from './helpers/index.js';\nexport * from './services/index.js';\n\nexport type { BaseProps, BaseConstructor, BaseAsyncConstructor, BaseConfig } from './Base/index.js';\n\nexport type { BaseInterface, BaseDecorator } from './Base/types.js';\n"],
5
- "mappings": "AAAA,SAAS,YAAY;AACrB,cAAc;AACd,cAAc;AACd,cAAc;",
4
+ "sourcesContent": ["export * 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
+ "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studiometa/js-toolkit",
3
- "version": "3.0.0-alpha.3",
3
+ "version": "3.0.0-alpha.5",
4
4
  "description": "A set of useful little bits of JavaScript to boost your project! 🚀",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -7,26 +7,40 @@ export interface ScrollServiceProps {
7
7
  x: boolean;
8
8
  y: boolean;
9
9
  };
10
+ changedX: boolean;
11
+ changedY: boolean;
10
12
  last: {
11
13
  x: number;
12
14
  y: number;
13
15
  };
16
+ lastX: number;
17
+ lastY: number;
14
18
  delta: {
15
19
  x: number;
16
20
  y: number;
17
21
  };
22
+ deltaX: number;
23
+ deltaY: number;
18
24
  progress: {
19
25
  x: number;
20
26
  y: number;
21
27
  };
28
+ progressX: number;
29
+ progressY: number;
22
30
  max: {
23
31
  x: number;
24
32
  y: number;
25
33
  };
34
+ maxX: number;
35
+ maxY: number;
26
36
  direction: {
27
37
  x: 'LEFT' | 'RIGHT' | 'NONE';
28
38
  y: 'UP' | 'DOWN' | 'NONE';
29
39
  };
40
+ isUp: boolean;
41
+ isRight: boolean;
42
+ isDown: boolean;
43
+ isLeft: boolean;
30
44
  }
31
45
  /**
32
46
  * Use the scroll service.
@@ -10,18 +10,22 @@ function createScrollService() {
10
10
  if (window.scrollX !== props.x) {
11
11
  props.x = window.scrollX;
12
12
  }
13
- props.changed.x = props.x !== xLast;
14
- props.changed.y = props.y !== yLast;
15
- props.last.x = xLast;
16
- props.last.y = yLast;
17
- props.delta.x = props.x - xLast;
18
- props.delta.y = props.y - yLast;
19
- props.max.x = (document.scrollingElement || document.body).scrollWidth - window.innerWidth;
20
- props.max.y = (document.scrollingElement || document.body).scrollHeight - window.innerHeight;
21
- props.progress.x = props.max.x === 0 ? 1 : props.x / props.max.x;
22
- props.progress.y = props.max.y === 0 ? 1 : props.y / props.max.y;
23
- props.direction.x = props.x > xLast ? "RIGHT" : props.x < xLast ? "LEFT" : "NONE";
24
- props.direction.y = props.y > yLast ? "DOWN" : props.y < yLast ? "UP" : "NONE";
13
+ props.changed.x = props.changedX = props.x !== xLast;
14
+ props.changed.y = props.changedY = props.y !== yLast;
15
+ props.last.x = props.lastX = xLast;
16
+ props.last.y = props.lastY = yLast;
17
+ props.delta.x = props.deltaX = props.x - xLast;
18
+ props.delta.y = props.deltaY = props.y - yLast;
19
+ props.max.x = props.maxX = (document.scrollingElement || document.body).scrollWidth - window.innerWidth;
20
+ props.max.y = props.maxY = (document.scrollingElement || document.body).scrollHeight - window.innerHeight;
21
+ props.progress.x = props.progressX = props.max.x === 0 ? 1 : props.x / props.max.x;
22
+ props.progress.y = props.progressY = props.max.y === 0 ? 1 : props.y / props.max.y;
23
+ props.isUp = props.y < yLast;
24
+ props.isRight = props.x > xLast;
25
+ props.isDown = props.y > yLast;
26
+ props.isLeft = props.x < xLast;
27
+ props.direction.x = props.isRight ? "RIGHT" : props.isLeft ? "LEFT" : "NONE";
28
+ props.direction.y = props.isDown ? "DOWN" : props.isUp ? "UP" : "NONE";
25
29
  return props;
26
30
  }
27
31
  const onScrollDebounced = debounce(() => {
@@ -39,26 +43,40 @@ function createScrollService() {
39
43
  x: false,
40
44
  y: false
41
45
  },
46
+ changedX: false,
47
+ changedY: false,
42
48
  last: {
43
49
  x: window.scrollX,
44
50
  y: window.scrollY
45
51
  },
52
+ lastX: window.scrollX,
53
+ lastY: window.scrollY,
46
54
  delta: {
47
55
  x: 0,
48
56
  y: 0
49
57
  },
58
+ deltaX: 0,
59
+ deltaY: 0,
50
60
  max: {
51
61
  x: (document.scrollingElement || document.body).scrollWidth - window.innerWidth,
52
62
  y: (document.scrollingElement || document.body).scrollHeight - window.innerHeight
53
63
  },
64
+ maxX: (document.scrollingElement || document.body).scrollWidth - window.innerWidth,
65
+ maxY: (document.scrollingElement || document.body).scrollHeight - window.innerHeight,
54
66
  progress: {
55
67
  x: 0,
56
68
  y: 0
57
69
  },
70
+ progressX: 0,
71
+ progressY: 0,
58
72
  direction: {
59
73
  x: "NONE",
60
74
  y: "NONE"
61
- }
75
+ },
76
+ isUp: false,
77
+ isRight: false,
78
+ isDown: false,
79
+ isLeft: false
62
80
  },
63
81
  init() {
64
82
  document.addEventListener("scroll", onScroll, { passive: true, capture: true });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/js-toolkit/services/scroll.ts"],
4
- "sourcesContent": ["/* eslint-disable no-use-before-define, @typescript-eslint/no-use-before-define */\nimport { useService } from './service.js';\nimport debounce from '../utils/debounce.js';\nimport type { ServiceInterface } from './index.js';\n\nexport type ScrollService = ServiceInterface<ScrollServiceProps>;\n\nexport interface ScrollServiceProps {\n x: number;\n y: number;\n changed: { x: boolean; y: boolean };\n last: { x: number; y: number };\n delta: { x: number; y: number };\n progress: { x: number; y: number };\n max: { x: number; y: number };\n direction: { x: 'LEFT' | 'RIGHT' | 'NONE'; y: 'UP' | 'DOWN' | 'NONE' };\n}\n\n/**\n * Create scroll service.\n */\nfunction createScrollService(): ScrollService {\n /**\n * Update props.\n */\n function updateProps(): ScrollServiceProps {\n const yLast = props.y;\n const xLast = props.x;\n\n // Check scroll Y\n if (window.scrollY !== props.y) {\n props.y = window.scrollY;\n }\n\n // Check scroll x\n if (window.scrollX !== props.x) {\n props.x = window.scrollX;\n }\n\n props.changed.x = props.x !== xLast;\n props.changed.y = props.y !== yLast;\n props.last.x = xLast;\n props.last.y = yLast;\n props.delta.x = props.x - xLast;\n props.delta.y = props.y - yLast;\n props.max.x = (document.scrollingElement || document.body).scrollWidth - window.innerWidth;\n props.max.y = (document.scrollingElement || document.body).scrollHeight - window.innerHeight;\n props.progress.x = props.max.x === 0 ? 1 : props.x / props.max.x;\n props.progress.y = props.max.y === 0 ? 1 : props.y / props.max.y;\n /* eslint-disable no-nested-ternary */\n props.direction.x = props.x > xLast ? 'RIGHT' : props.x < xLast ? 'LEFT' : 'NONE';\n props.direction.y = props.y > yLast ? 'DOWN' : props.y < yLast ? 'UP' : 'NONE';\n /* eslint-enable no-nested-ternary */\n\n return props;\n }\n\n const onScrollDebounced = debounce(() => {\n trigger(updateProps());\n }, 100);\n\n /**\n * Scroll handler.\n */\n function onScroll() {\n trigger(updateProps());\n onScrollDebounced();\n }\n\n const { add, remove, has, props, trigger } = useService({\n props: {\n x: window.scrollX,\n y: window.scrollY,\n changed: {\n x: false,\n y: false,\n },\n last: {\n x: window.scrollX,\n y: window.scrollY,\n },\n delta: {\n x: 0,\n y: 0,\n },\n max: {\n x: (document.scrollingElement || document.body).scrollWidth - window.innerWidth,\n y: (document.scrollingElement || document.body).scrollHeight - window.innerHeight,\n },\n progress: {\n x: 0,\n y: 0,\n },\n direction: {\n x: 'NONE',\n y: 'NONE',\n },\n } as ScrollServiceProps,\n init() {\n document.addEventListener('scroll', onScroll, { passive: true, capture: true });\n },\n kill() {\n document.removeEventListener('scroll', onScroll);\n },\n });\n\n return {\n add,\n remove,\n has,\n props: () => props,\n };\n}\n\nlet scroll;\n\n/**\n * Use the scroll service.\n *\n * ```js\n * import { useScroll } from '@studiometa/js-toolkit/services';\n * const { add, remove, props } = useScroll();\n * add(key, (props) => {});\n * remove(key);\n * props();\n * ```\n */\nexport default function useScroll(): ScrollService {\n if (!scroll) {\n scroll = createScrollService();\n }\n\n return scroll;\n}\n"],
5
- "mappings": "AACA,SAAS,kBAAkB;AAC3B,OAAO,cAAc;AAmBrB,SAAS,sBAAqC;AAI5C,WAAS,cAAkC;AACzC,UAAM,QAAQ,MAAM;AACpB,UAAM,QAAQ,MAAM;AAGpB,QAAI,OAAO,YAAY,MAAM,GAAG;AAC9B,YAAM,IAAI,OAAO;AAAA,IACnB;AAGA,QAAI,OAAO,YAAY,MAAM,GAAG;AAC9B,YAAM,IAAI,OAAO;AAAA,IACnB;AAEA,UAAM,QAAQ,IAAI,MAAM,MAAM;AAC9B,UAAM,QAAQ,IAAI,MAAM,MAAM;AAC9B,UAAM,KAAK,IAAI;AACf,UAAM,KAAK,IAAI;AACf,UAAM,MAAM,IAAI,MAAM,IAAI;AAC1B,UAAM,MAAM,IAAI,MAAM,IAAI;AAC1B,UAAM,IAAI,KAAK,SAAS,oBAAoB,SAAS,MAAM,cAAc,OAAO;AAChF,UAAM,IAAI,KAAK,SAAS,oBAAoB,SAAS,MAAM,eAAe,OAAO;AACjF,UAAM,SAAS,IAAI,MAAM,IAAI,MAAM,IAAI,IAAI,MAAM,IAAI,MAAM,IAAI;AAC/D,UAAM,SAAS,IAAI,MAAM,IAAI,MAAM,IAAI,IAAI,MAAM,IAAI,MAAM,IAAI;AAE/D,UAAM,UAAU,IAAI,MAAM,IAAI,QAAQ,UAAU,MAAM,IAAI,QAAQ,SAAS;AAC3E,UAAM,UAAU,IAAI,MAAM,IAAI,QAAQ,SAAS,MAAM,IAAI,QAAQ,OAAO;AAGxE,WAAO;AAAA,EACT;AAEA,QAAM,oBAAoB,SAAS,MAAM;AACvC,YAAQ,YAAY,CAAC;AAAA,EACvB,GAAG,GAAG;AAKN,WAAS,WAAW;AAClB,YAAQ,YAAY,CAAC;AACrB,sBAAkB;AAAA,EACpB;AAEA,QAAM,EAAE,KAAK,QAAQ,KAAK,OAAO,QAAQ,IAAI,WAAW;AAAA,IACtD,OAAO;AAAA,MACL,GAAG,OAAO;AAAA,MACV,GAAG,OAAO;AAAA,MACV,SAAS;AAAA,QACP,GAAG;AAAA,QACH,GAAG;AAAA,MACL;AAAA,MACA,MAAM;AAAA,QACJ,GAAG,OAAO;AAAA,QACV,GAAG,OAAO;AAAA,MACZ;AAAA,MACA,OAAO;AAAA,QACL,GAAG;AAAA,QACH,GAAG;AAAA,MACL;AAAA,MACA,KAAK;AAAA,QACH,IAAI,SAAS,oBAAoB,SAAS,MAAM,cAAc,OAAO;AAAA,QACrE,IAAI,SAAS,oBAAoB,SAAS,MAAM,eAAe,OAAO;AAAA,MACxE;AAAA,MACA,UAAU;AAAA,QACR,GAAG;AAAA,QACH,GAAG;AAAA,MACL;AAAA,MACA,WAAW;AAAA,QACT,GAAG;AAAA,QACH,GAAG;AAAA,MACL;AAAA,IACF;AAAA,IACA,OAAO;AACL,eAAS,iBAAiB,UAAU,UAAU,EAAE,SAAS,MAAM,SAAS,KAAK,CAAC;AAAA,IAChF;AAAA,IACA,OAAO;AACL,eAAS,oBAAoB,UAAU,QAAQ;AAAA,IACjD;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AACF;AAEA,IAAI;AAaW,SAAR,YAA4C;AACjD,MAAI,CAAC,QAAQ;AACX,aAAS,oBAAoB;AAAA,EAC/B;AAEA,SAAO;AACT;",
4
+ "sourcesContent": ["/* eslint-disable no-use-before-define, @typescript-eslint/no-use-before-define */\nimport { useService } from './service.js';\nimport debounce from '../utils/debounce.js';\nimport type { ServiceInterface } from './index.js';\n\nexport type ScrollService = ServiceInterface<ScrollServiceProps>;\n\nexport interface ScrollServiceProps {\n x: number;\n y: number;\n changed: { x: boolean; y: boolean };\n changedX: boolean;\n changedY: boolean;\n last: { x: number; y: number };\n lastX: number;\n lastY: number;\n delta: { x: number; y: number };\n deltaX: number;\n deltaY: number;\n progress: { x: number; y: number };\n progressX: number;\n progressY: number;\n max: { x: number; y: number };\n maxX: number;\n maxY: number;\n direction: { x: 'LEFT' | 'RIGHT' | 'NONE'; y: 'UP' | 'DOWN' | 'NONE' };\n isUp: boolean;\n isRight: boolean;\n isDown: boolean;\n isLeft: boolean;\n}\n\n/**\n * Create scroll service.\n */\nfunction createScrollService(): ScrollService {\n /**\n * Update props.\n */\n function updateProps(): ScrollServiceProps {\n const yLast = props.y;\n const xLast = props.x;\n\n // Check scroll Y\n if (window.scrollY !== props.y) {\n props.y = window.scrollY;\n }\n\n // Check scroll x\n if (window.scrollX !== props.x) {\n props.x = window.scrollX;\n }\n\n props.changed.x = props.changedX = props.x !== xLast;\n props.changed.y = props.changedY = props.y !== yLast;\n props.last.x = props.lastX = xLast;\n props.last.y = props.lastY = yLast;\n props.delta.x = props.deltaX = props.x - xLast;\n props.delta.y = props.deltaY = props.y - yLast;\n props.max.x = props.maxX = (document.scrollingElement || document.body).scrollWidth - window.innerWidth;\n props.max.y = props.maxY = (document.scrollingElement || document.body).scrollHeight - window.innerHeight;\n props.progress.x = props.progressX = props.max.x === 0 ? 1 : props.x / props.max.x;\n props.progress.y = props.progressY = props.max.y === 0 ? 1 : props.y / props.max.y;\n props.isUp = props.y < yLast;\n props.isRight = props.x > xLast;\n props.isDown = props.y > yLast;\n props.isLeft = props.x < xLast;\n /* eslint-disable no-nested-ternary */\n props.direction.x = props.isRight ? 'RIGHT' : props.isLeft ? 'LEFT' : 'NONE';\n props.direction.y = props.isDown ? 'DOWN' : props.isUp ? 'UP' : 'NONE';\n /* eslint-enable no-nested-ternary */\n\n return props;\n }\n\n const onScrollDebounced = debounce(() => {\n trigger(updateProps());\n }, 100);\n\n /**\n * Scroll handler.\n */\n function onScroll() {\n trigger(updateProps());\n onScrollDebounced();\n }\n\n const { add, remove, has, props, trigger } = useService({\n props: {\n x: window.scrollX,\n y: window.scrollY,\n changed: {\n x: false,\n y: false,\n },\n changedX: false,\n changedY: false,\n last: {\n x: window.scrollX,\n y: window.scrollY,\n },\n lastX: window.scrollX,\n lastY: window.scrollY,\n delta: {\n x: 0,\n y: 0,\n },\n deltaX: 0,\n deltaY: 0,\n max: {\n x: (document.scrollingElement || document.body).scrollWidth - window.innerWidth,\n y: (document.scrollingElement || document.body).scrollHeight - window.innerHeight,\n },\n maxX: (document.scrollingElement || document.body).scrollWidth - window.innerWidth,\n maxY: (document.scrollingElement || document.body).scrollHeight - window.innerHeight,\n progress: {\n x: 0,\n y: 0,\n },\n progressX: 0,\n progressY: 0,\n direction: {\n x: 'NONE',\n y: 'NONE',\n },\n isUp: false,\n isRight: false,\n isDown: false,\n isLeft: false,\n } as ScrollServiceProps,\n init() {\n document.addEventListener('scroll', onScroll, { passive: true, capture: true });\n },\n kill() {\n document.removeEventListener('scroll', onScroll);\n },\n });\n\n return {\n add,\n remove,\n has,\n props: () => props,\n };\n}\n\nlet scroll;\n\n/**\n * Use the scroll service.\n *\n * ```js\n * import { useScroll } from '@studiometa/js-toolkit/services';\n * const { add, remove, props } = useScroll();\n * add(key, (props) => {});\n * remove(key);\n * props();\n * ```\n */\nexport default function useScroll(): ScrollService {\n if (!scroll) {\n scroll = createScrollService();\n }\n\n return scroll;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }