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

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.
@@ -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": "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",
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/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/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.4",
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
  }