@studiometa/js-toolkit 3.0.4 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,4 @@
1
+ import { useScroll } from "../../services/index.js";
1
2
  import { withMountWhenInView } from "../withMountWhenInView.js";
2
3
  import {
3
4
  damp,
@@ -14,11 +15,7 @@ function updateProgress(props, axis, progressKey, currentKey) {
14
15
  );
15
16
  }
16
17
  function updateProps(props, dampFactor, dampPrecision, axis = "x") {
17
- props.current[axis] = clamp(
18
- axis === "x" ? window.scrollX : window.scrollY,
19
- props.start[axis],
20
- props.end[axis]
21
- );
18
+ props.current[axis] = clamp(useScroll().props()[axis], props.start[axis], props.end[axis]);
22
19
  props.dampedCurrent[axis] = damp(
23
20
  props.current[axis],
24
21
  props.dampedCurrent[axis],
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../packages/js-toolkit/decorators/withScrolledInView/withScrolledInView.ts"],
4
- "sourcesContent": ["import type { BaseInterface, BaseDecorator } from '../../Base/types.js';\nimport type { Base, BaseProps, BaseConfig } from '../../Base/index.js';\nimport type {\n RafServiceProps,\n ScrollServiceProps,\n ResizeServiceProps,\n} from '../../services/index.js';\nimport { withMountWhenInView } from '../withMountWhenInView.js';\nimport {\n damp,\n clamp,\n clamp01,\n getOffsetSizes,\n isFunction,\n domScheduler as scheduler,\n} from '../../utils/index.js';\nimport { normalizeOffset, getEdges } from './utils.js';\n\nexport interface WithScrolledInViewProps extends BaseProps {\n $options: {\n dampFactor: number;\n dampPrecision: number;\n offset: string;\n };\n}\n\nexport type ScrollInViewProps = {\n start: {\n x: number;\n y: number;\n };\n end: {\n x: number;\n y: number;\n };\n current: {\n x: number;\n y: number;\n };\n dampedCurrent: {\n x: number;\n y: number;\n };\n progress: {\n x: number;\n y: number;\n };\n dampedProgress: {\n x: number;\n y: number;\n };\n};\n\nexport type WithScrolledInViewOptions = IntersectionObserverInit & {\n useOffsetSizes?: boolean;\n};\n\nfunction updateProgress(\n props: ScrollInViewProps,\n axis: 'x' | 'y',\n progressKey: 'progress' | 'dampedProgress',\n currentKey: 'current' | 'dampedCurrent',\n) {\n props[progressKey][axis] =\n props.start[axis] === props.end[axis]\n ? 0\n : clamp01(\n (props[currentKey][axis] - props.start[axis]) / (props.end[axis] - props.start[axis]),\n );\n}\n\n/**\n * Update props on tick.\n */\nfunction updateProps(\n props: ScrollInViewProps,\n dampFactor: number,\n dampPrecision: number,\n axis: 'x' | 'y' = 'x',\n): void {\n props.current[axis] = clamp(\n axis === 'x' ? window.scrollX : window.scrollY,\n props.start[axis],\n props.end[axis],\n );\n props.dampedCurrent[axis] = damp(\n props.current[axis],\n props.dampedCurrent[axis],\n dampFactor,\n dampPrecision,\n );\n updateProgress(props, axis, 'progress', 'current');\n updateProgress(props, axis, 'dampedProgress', 'dampedCurrent');\n}\n\nexport interface WithScrolledInViewInterface extends BaseInterface {\n /**\n * @type {ScrollInViewProps}\n */\n readonly props: ScrollInViewProps;\n dampFactor?: number;\n dampPrecision?: number;\n mounted(): void;\n resized(props: ResizeServiceProps): void;\n scrolled(props: ScrollServiceProps): void;\n ticked(props: RafServiceProps): void;\n destroyed(): void;\n}\n\n/**\n * Add scrolled in view capabilities to a component.\n */\nexport function withScrolledInView<S extends Base = Base>(\n BaseClass: typeof Base,\n options: WithScrolledInViewOptions = {},\n): BaseDecorator<WithScrolledInViewInterface, S, WithScrolledInViewProps> {\n /**\n * Class.\n */\n class WithScrolledInView<T extends BaseProps = BaseProps> extends withMountWhenInView(\n BaseClass,\n options,\n )<T & WithScrolledInViewProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n ...BaseClass.config,\n emits: ['scrolledInView'],\n options: {\n dampFactor: {\n type: Number,\n default: 0.1,\n },\n dampPrecision: {\n type: Number,\n default: 0.001,\n },\n offset: {\n type: String,\n default: 'start end / end start',\n },\n },\n };\n\n __props: ScrollInViewProps = {\n start: {\n x: 0,\n y: 0,\n },\n end: {\n x: 0,\n y: 0,\n },\n current: {\n x: 0,\n y: 0,\n },\n dampedCurrent: {\n x: 0,\n y: 0,\n },\n progress: {\n x: 0,\n y: 0,\n },\n dampedProgress: {\n x: 0,\n y: 0,\n },\n };\n\n shouldEvaluateProps = true;\n\n get props() {\n if (this.shouldEvaluateProps) {\n this.shouldEvaluateProps = false;\n const targetSizes = options.useOffsetSizes\n ? getOffsetSizes(this.$el)\n : this.$el.getBoundingClientRect();\n\n targetSizes.y += window.scrollY;\n targetSizes.x += window.scrollX;\n\n const containerSizes = {\n x: 0,\n y: 0,\n height: window.innerHeight,\n width: window.innerWidth,\n };\n\n const offset = normalizeOffset(this.$options.offset);\n\n // Y axis\n const [yStart, yEnd] = getEdges('y', targetSizes, containerSizes, offset);\n const yCurrent = clamp(window.scrollY, yStart, yEnd);\n const yProgress = yStart === yEnd ? 0 : clamp01((yCurrent - yStart) / (yEnd - yStart));\n // X axis\n const [xStart, xEnd] = getEdges('x', targetSizes, containerSizes, offset);\n const xCurrent = clamp(window.scrollX, xStart, xEnd);\n const xProgress = xStart === xEnd ? 0 : clamp01((xCurrent - xStart) / (xEnd - xStart));\n\n this.__props.start.x = xStart;\n this.__props.start.y = yStart;\n this.__props.end.x = xEnd;\n this.__props.end.y = yEnd;\n this.__props.current.x = xCurrent;\n this.__props.current.y = yCurrent;\n this.__props.dampedCurrent.x = xCurrent;\n this.__props.dampedCurrent.y = yCurrent;\n this.__props.progress.x = xProgress;\n this.__props.progress.y = yProgress;\n this.__props.dampedProgress.x = xProgress;\n this.__props.dampedProgress.y = yProgress;\n }\n\n return this.__props;\n }\n\n /**\n * Bind listeners.\n */\n constructor(element: HTMLElement) {\n super(element);\n\n const render = () => {\n scheduler.read(() => {\n // @ts-ignore\n const renderFn = this.__callMethod('scrolledInView', this.props);\n if (isFunction(renderFn)) {\n scheduler.write(() => {\n renderFn(this.__props);\n });\n }\n });\n };\n\n const delegate = {\n handleEvent(event: CustomEvent) {\n delegate[event.type](event.detail[0]);\n },\n resized: () => {\n this.shouldEvaluateProps = true;\n render();\n },\n scrolled: (props: ScrollServiceProps) => {\n if (props.changed.y || props.changed.x) {\n this.$services.enable('ticked');\n }\n },\n mounted: () => render(),\n ticked: () => {\n const { dampFactor, dampPrecision } = this.$options;\n updateProps(this.__props, dampFactor, dampPrecision, 'x');\n updateProps(this.__props, dampFactor, dampPrecision, 'y');\n\n if (\n this.__props.dampedCurrent.x === this.__props.current.x &&\n this.__props.dampedCurrent.y === this.__props.current.y\n ) {\n this.$services.disable('ticked');\n }\n\n render();\n },\n };\n\n this.$on('before-mounted', () => {\n this.$on('mounted', delegate);\n this.$on('resized', delegate);\n this.$on('scrolled', delegate);\n this.$on('ticked', delegate);\n });\n\n this.$on('destroyed', () => {\n this.$off('mounted', delegate);\n this.$off('resized', delegate);\n this.$off('scrolled', delegate);\n this.$off('ticked', delegate);\n\n // Clamp damped values to their final value and trigger one last render on destroy\n this.__props.dampedCurrent.x = this.__props.current.x;\n this.__props.dampedCurrent.y = this.__props.current.y;\n this.__props.dampedProgress.x = this.__props.progress.x;\n this.__props.dampedProgress.y = this.__props.progress.y;\n render();\n });\n }\n }\n\n // @ts-ignore\n return WithScrolledInView;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { BaseInterface, BaseDecorator } from '../../Base/types.js';\nimport type { Base, BaseProps, BaseConfig } from '../../Base/index.js';\nimport type {\n RafServiceProps,\n ScrollServiceProps,\n ResizeServiceProps,\n} from '../../services/index.js';\nimport { useScroll } from '../../services/index.js';\nimport { withMountWhenInView } from '../withMountWhenInView.js';\nimport {\n damp,\n clamp,\n clamp01,\n getOffsetSizes,\n isFunction,\n domScheduler as scheduler,\n} from '../../utils/index.js';\nimport { normalizeOffset, getEdges } from './utils.js';\n\nexport interface WithScrolledInViewProps extends BaseProps {\n $options: {\n dampFactor: number;\n dampPrecision: number;\n offset: string;\n };\n}\n\nexport type ScrollInViewProps = {\n start: {\n x: number;\n y: number;\n };\n end: {\n x: number;\n y: number;\n };\n current: {\n x: number;\n y: number;\n };\n dampedCurrent: {\n x: number;\n y: number;\n };\n progress: {\n x: number;\n y: number;\n };\n dampedProgress: {\n x: number;\n y: number;\n };\n};\n\nexport type WithScrolledInViewOptions = IntersectionObserverInit & {\n useOffsetSizes?: boolean;\n};\n\nfunction updateProgress(\n props: ScrollInViewProps,\n axis: 'x' | 'y',\n progressKey: 'progress' | 'dampedProgress',\n currentKey: 'current' | 'dampedCurrent',\n) {\n props[progressKey][axis] =\n props.start[axis] === props.end[axis]\n ? 0\n : clamp01(\n (props[currentKey][axis] - props.start[axis]) / (props.end[axis] - props.start[axis]),\n );\n}\n\n/**\n * Update props on tick.\n */\nfunction updateProps(\n props: ScrollInViewProps,\n dampFactor: number,\n dampPrecision: number,\n axis: 'x' | 'y' = 'x',\n): void {\n props.current[axis] = clamp(useScroll().props()[axis], props.start[axis], props.end[axis]);\n props.dampedCurrent[axis] = damp(\n props.current[axis],\n props.dampedCurrent[axis],\n dampFactor,\n dampPrecision,\n );\n updateProgress(props, axis, 'progress', 'current');\n updateProgress(props, axis, 'dampedProgress', 'dampedCurrent');\n}\n\nexport interface WithScrolledInViewInterface extends BaseInterface {\n /**\n * @type {ScrollInViewProps}\n */\n readonly props: ScrollInViewProps;\n dampFactor?: number;\n dampPrecision?: number;\n mounted(): void;\n resized(props: ResizeServiceProps): void;\n scrolled(props: ScrollServiceProps): void;\n ticked(props: RafServiceProps): void;\n destroyed(): void;\n}\n\n/**\n * Add scrolled in view capabilities to a component.\n */\nexport function withScrolledInView<S extends Base = Base>(\n BaseClass: typeof Base,\n options: WithScrolledInViewOptions = {},\n): BaseDecorator<WithScrolledInViewInterface, S, WithScrolledInViewProps> {\n /**\n * Class.\n */\n class WithScrolledInView<T extends BaseProps = BaseProps> extends withMountWhenInView(\n BaseClass,\n options,\n )<T & WithScrolledInViewProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n ...BaseClass.config,\n emits: ['scrolledInView'],\n options: {\n dampFactor: {\n type: Number,\n default: 0.1,\n },\n dampPrecision: {\n type: Number,\n default: 0.001,\n },\n offset: {\n type: String,\n default: 'start end / end start',\n },\n },\n };\n\n __props: ScrollInViewProps = {\n start: {\n x: 0,\n y: 0,\n },\n end: {\n x: 0,\n y: 0,\n },\n current: {\n x: 0,\n y: 0,\n },\n dampedCurrent: {\n x: 0,\n y: 0,\n },\n progress: {\n x: 0,\n y: 0,\n },\n dampedProgress: {\n x: 0,\n y: 0,\n },\n };\n\n shouldEvaluateProps = true;\n\n get props() {\n if (this.shouldEvaluateProps) {\n this.shouldEvaluateProps = false;\n const targetSizes = options.useOffsetSizes\n ? getOffsetSizes(this.$el)\n : this.$el.getBoundingClientRect();\n\n targetSizes.y += window.scrollY;\n targetSizes.x += window.scrollX;\n\n const containerSizes = {\n x: 0,\n y: 0,\n height: window.innerHeight,\n width: window.innerWidth,\n };\n\n const offset = normalizeOffset(this.$options.offset);\n\n // Y axis\n const [yStart, yEnd] = getEdges('y', targetSizes, containerSizes, offset);\n const yCurrent = clamp(window.scrollY, yStart, yEnd);\n const yProgress = yStart === yEnd ? 0 : clamp01((yCurrent - yStart) / (yEnd - yStart));\n // X axis\n const [xStart, xEnd] = getEdges('x', targetSizes, containerSizes, offset);\n const xCurrent = clamp(window.scrollX, xStart, xEnd);\n const xProgress = xStart === xEnd ? 0 : clamp01((xCurrent - xStart) / (xEnd - xStart));\n\n this.__props.start.x = xStart;\n this.__props.start.y = yStart;\n this.__props.end.x = xEnd;\n this.__props.end.y = yEnd;\n this.__props.current.x = xCurrent;\n this.__props.current.y = yCurrent;\n this.__props.dampedCurrent.x = xCurrent;\n this.__props.dampedCurrent.y = yCurrent;\n this.__props.progress.x = xProgress;\n this.__props.progress.y = yProgress;\n this.__props.dampedProgress.x = xProgress;\n this.__props.dampedProgress.y = yProgress;\n }\n\n return this.__props;\n }\n\n /**\n * Bind listeners.\n */\n constructor(element: HTMLElement) {\n super(element);\n\n const render = () => {\n scheduler.read(() => {\n // @ts-ignore\n const renderFn = this.__callMethod('scrolledInView', this.props);\n if (isFunction(renderFn)) {\n scheduler.write(() => {\n renderFn(this.__props);\n });\n }\n });\n };\n\n const delegate = {\n handleEvent(event: CustomEvent) {\n delegate[event.type](event.detail[0]);\n },\n resized: () => {\n this.shouldEvaluateProps = true;\n render();\n },\n scrolled: (props: ScrollServiceProps) => {\n if (props.changed.y || props.changed.x) {\n this.$services.enable('ticked');\n }\n },\n mounted: () => render(),\n ticked: () => {\n const { dampFactor, dampPrecision } = this.$options;\n updateProps(this.__props, dampFactor, dampPrecision, 'x');\n updateProps(this.__props, dampFactor, dampPrecision, 'y');\n\n if (\n this.__props.dampedCurrent.x === this.__props.current.x &&\n this.__props.dampedCurrent.y === this.__props.current.y\n ) {\n this.$services.disable('ticked');\n }\n\n render();\n },\n };\n\n this.$on('before-mounted', () => {\n this.$on('mounted', delegate);\n this.$on('resized', delegate);\n this.$on('scrolled', delegate);\n this.$on('ticked', delegate);\n });\n\n this.$on('destroyed', () => {\n this.$off('mounted', delegate);\n this.$off('resized', delegate);\n this.$off('scrolled', delegate);\n this.$off('ticked', delegate);\n\n // Clamp damped values to their final value and trigger one last render on destroy\n this.__props.dampedCurrent.x = this.__props.current.x;\n this.__props.dampedCurrent.y = this.__props.current.y;\n this.__props.dampedProgress.x = this.__props.progress.x;\n this.__props.dampedProgress.y = this.__props.progress.y;\n render();\n });\n }\n }\n\n // @ts-ignore\n return WithScrolledInView;\n}\n"],
5
+ "mappings": "AAOA,SAAS,iBAAiB;AAC1B,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,OACX;AACP,SAAS,iBAAiB,gBAAgB;AAyC1C,SAAS,eACP,OACA,MACA,aACA,YACA;AACA,QAAM,WAAW,EAAE,IAAI,IACrB,MAAM,MAAM,IAAI,MAAM,MAAM,IAAI,IAAI,IAChC,IACA;AAAA,KACG,MAAM,UAAU,EAAE,IAAI,IAAI,MAAM,MAAM,IAAI,MAAM,MAAM,IAAI,IAAI,IAAI,MAAM,MAAM,IAAI;AAAA,EACrF;AACR;AAKA,SAAS,YACP,OACA,YACA,eACA,OAAkB,KACZ;AACN,QAAM,QAAQ,IAAI,IAAI,MAAM,UAAU,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM,MAAM,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC;AACzF,QAAM,cAAc,IAAI,IAAI;AAAA,IAC1B,MAAM,QAAQ,IAAI;AAAA,IAClB,MAAM,cAAc,IAAI;AAAA,IACxB;AAAA,IACA;AAAA,EACF;AACA,iBAAe,OAAO,MAAM,YAAY,SAAS;AACjD,iBAAe,OAAO,MAAM,kBAAkB,eAAe;AAC/D;AAmBO,SAAS,mBACd,WACA,UAAqC,CAAC,GACkC;AAAA,EAIxE,MAAM,2BAA4D;AAAA,IAChE;AAAA,IACA;AAAA,EACF,EAA+B;AAAA;AAAA;AAAA;AAAA,IAI7B,OAAO,SAAqB;AAAA,MAC1B,GAAG,UAAU;AAAA,MACb,OAAO,CAAC,gBAAgB;AAAA,MACxB,SAAS;AAAA,QACP,YAAY;AAAA,UACV,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,QACA,eAAe;AAAA,UACb,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,QACA,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,IAEA,UAA6B;AAAA,MAC3B,OAAO;AAAA,QACL,GAAG;AAAA,QACH,GAAG;AAAA,MACL;AAAA,MACA,KAAK;AAAA,QACH,GAAG;AAAA,QACH,GAAG;AAAA,MACL;AAAA,MACA,SAAS;AAAA,QACP,GAAG;AAAA,QACH,GAAG;AAAA,MACL;AAAA,MACA,eAAe;AAAA,QACb,GAAG;AAAA,QACH,GAAG;AAAA,MACL;AAAA,MACA,UAAU;AAAA,QACR,GAAG;AAAA,QACH,GAAG;AAAA,MACL;AAAA,MACA,gBAAgB;AAAA,QACd,GAAG;AAAA,QACH,GAAG;AAAA,MACL;AAAA,IACF;AAAA,IAEA,sBAAsB;AAAA,IAEtB,IAAI,QAAQ;AACV,UAAI,KAAK,qBAAqB;AAC5B,aAAK,sBAAsB;AAC3B,cAAM,cAAc,QAAQ,iBACxB,eAAe,KAAK,GAAG,IACvB,KAAK,IAAI,sBAAsB;AAEnC,oBAAY,KAAK,OAAO;AACxB,oBAAY,KAAK,OAAO;AAExB,cAAM,iBAAiB;AAAA,UACrB,GAAG;AAAA,UACH,GAAG;AAAA,UACH,QAAQ,OAAO;AAAA,UACf,OAAO,OAAO;AAAA,QAChB;AAEA,cAAM,SAAS,gBAAgB,KAAK,SAAS,MAAM;AAGnD,cAAM,CAAC,QAAQ,IAAI,IAAI,SAAS,KAAK,aAAa,gBAAgB,MAAM;AACxE,cAAM,WAAW,MAAM,OAAO,SAAS,QAAQ,IAAI;AACnD,cAAM,YAAY,WAAW,OAAO,IAAI,SAAS,WAAW,WAAW,OAAO,OAAO;AAErF,cAAM,CAAC,QAAQ,IAAI,IAAI,SAAS,KAAK,aAAa,gBAAgB,MAAM;AACxE,cAAM,WAAW,MAAM,OAAO,SAAS,QAAQ,IAAI;AACnD,cAAM,YAAY,WAAW,OAAO,IAAI,SAAS,WAAW,WAAW,OAAO,OAAO;AAErF,aAAK,QAAQ,MAAM,IAAI;AACvB,aAAK,QAAQ,MAAM,IAAI;AACvB,aAAK,QAAQ,IAAI,IAAI;AACrB,aAAK,QAAQ,IAAI,IAAI;AACrB,aAAK,QAAQ,QAAQ,IAAI;AACzB,aAAK,QAAQ,QAAQ,IAAI;AACzB,aAAK,QAAQ,cAAc,IAAI;AAC/B,aAAK,QAAQ,cAAc,IAAI;AAC/B,aAAK,QAAQ,SAAS,IAAI;AAC1B,aAAK,QAAQ,SAAS,IAAI;AAC1B,aAAK,QAAQ,eAAe,IAAI;AAChC,aAAK,QAAQ,eAAe,IAAI;AAAA,MAClC;AAEA,aAAO,KAAK;AAAA,IACd;AAAA;AAAA;AAAA;AAAA,IAKA,YAAY,SAAsB;AAChC,YAAM,OAAO;AAEb,YAAM,SAAS,MAAM;AACnB,kBAAU,KAAK,MAAM;AAEnB,gBAAM,WAAW,KAAK,aAAa,kBAAkB,KAAK,KAAK;AAC/D,cAAI,WAAW,QAAQ,GAAG;AACxB,sBAAU,MAAM,MAAM;AACpB,uBAAS,KAAK,OAAO;AAAA,YACvB,CAAC;AAAA,UACH;AAAA,QACF,CAAC;AAAA,MACH;AAEA,YAAM,WAAW;AAAA,QACf,YAAY,OAAoB;AAC9B,mBAAS,MAAM,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC;AAAA,QACtC;AAAA,QACA,SAAS,MAAM;AACb,eAAK,sBAAsB;AAC3B,iBAAO;AAAA,QACT;AAAA,QACA,UAAU,CAAC,UAA8B;AACvC,cAAI,MAAM,QAAQ,KAAK,MAAM,QAAQ,GAAG;AACtC,iBAAK,UAAU,OAAO,QAAQ;AAAA,UAChC;AAAA,QACF;AAAA,QACA,SAAS,MAAM,OAAO;AAAA,QACtB,QAAQ,MAAM;AACZ,gBAAM,EAAE,YAAY,cAAc,IAAI,KAAK;AAC3C,sBAAY,KAAK,SAAS,YAAY,eAAe,GAAG;AACxD,sBAAY,KAAK,SAAS,YAAY,eAAe,GAAG;AAExD,cACE,KAAK,QAAQ,cAAc,MAAM,KAAK,QAAQ,QAAQ,KACtD,KAAK,QAAQ,cAAc,MAAM,KAAK,QAAQ,QAAQ,GACtD;AACA,iBAAK,UAAU,QAAQ,QAAQ;AAAA,UACjC;AAEA,iBAAO;AAAA,QACT;AAAA,MACF;AAEA,WAAK,IAAI,kBAAkB,MAAM;AAC/B,aAAK,IAAI,WAAW,QAAQ;AAC5B,aAAK,IAAI,WAAW,QAAQ;AAC5B,aAAK,IAAI,YAAY,QAAQ;AAC7B,aAAK,IAAI,UAAU,QAAQ;AAAA,MAC7B,CAAC;AAED,WAAK,IAAI,aAAa,MAAM;AAC1B,aAAK,KAAK,WAAW,QAAQ;AAC7B,aAAK,KAAK,WAAW,QAAQ;AAC7B,aAAK,KAAK,YAAY,QAAQ;AAC9B,aAAK,KAAK,UAAU,QAAQ;AAG5B,aAAK,QAAQ,cAAc,IAAI,KAAK,QAAQ,QAAQ;AACpD,aAAK,QAAQ,cAAc,IAAI,KAAK,QAAQ,QAAQ;AACpD,aAAK,QAAQ,eAAe,IAAI,KAAK,QAAQ,SAAS;AACtD,aAAK,QAAQ,eAAe,IAAI,KAAK,QAAQ,SAAS;AACtD,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAGA,SAAO;AACT;",
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.4",
3
+ "version": "3.1.0",
4
4
  "description": "A set of useful little bits of JavaScript to boost your project! 🚀",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -2,6 +2,7 @@ import type { ServiceInterface } from './AbstractService.js';
2
2
  import { AbstractService } from './AbstractService.js';
3
3
  export interface RafServiceProps {
4
4
  time: DOMHighResTimeStamp;
5
+ delta: number;
5
6
  }
6
7
  export type RafServiceInterface = ServiceInterface<RafServiceProps>;
7
8
  export declare class RafService extends AbstractService<RafServiceProps> {
@@ -11,7 +11,8 @@ class RafService extends AbstractService {
11
11
  */
12
12
  scheduler = domScheduler;
13
13
  props = {
14
- time: performance.now()
14
+ time: performance.now(),
15
+ delta: 0
15
16
  };
16
17
  trigger(props) {
17
18
  for (const callback of this.callbacks.values()) {
@@ -26,7 +27,9 @@ class RafService extends AbstractService {
26
27
  }
27
28
  }
28
29
  loop() {
29
- this.props.time = performance.now();
30
+ const time = performance.now();
31
+ this.props.delta = time - this.props.time;
32
+ this.props.time = time;
30
33
  this.trigger(this.props);
31
34
  if (!this.isTicking) {
32
35
  return;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/js-toolkit/services/RafService.ts"],
4
- "sourcesContent": ["import type { ServiceInterface } from './AbstractService.js';\nimport { AbstractService } from './AbstractService.js';\nimport { domScheduler } from '../utils/scheduler.js';\nimport { isFunction } from '../utils/is.js';\n\nexport interface RafServiceProps {\n time: DOMHighResTimeStamp;\n}\n\nexport type RafServiceInterface = ServiceInterface<RafServiceProps>;\n\nexport class RafService extends AbstractService<RafServiceProps> {\n /**\n * @private\n */\n isTicking = false;\n\n /**\n * @private\n */\n scheduler = domScheduler;\n\n props: RafServiceProps = {\n time: performance.now(),\n };\n\n trigger(props: RafServiceProps) {\n for (const callback of this.callbacks.values()) {\n this.scheduler.read(() => {\n const render = callback(props) as (() => unknown) | void;\n if (isFunction(render)) {\n this.scheduler.write(() => {\n // @ts-ignore\n render(props);\n });\n }\n });\n }\n }\n\n loop() {\n this.props.time = performance.now();\n this.trigger(this.props);\n\n if (!this.isTicking) {\n return;\n }\n\n requestAnimationFrame(() => this.loop());\n }\n\n init() {\n this.isTicking = true;\n requestAnimationFrame(() => this.loop());\n }\n\n kill() {\n this.isTicking = false;\n }\n}\n\n/**\n * Use the RequestAnimationFrame (raf) service.\n */\nexport function useRaf(): RafServiceInterface {\n return RafService.getInstance();\n}\n"],
5
- "mappings": "AACA,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAQpB,MAAM,mBAAmB,gBAAiC;AAAA;AAAA;AAAA;AAAA,EAI/D,YAAY;AAAA;AAAA;AAAA;AAAA,EAKZ,YAAY;AAAA,EAEZ,QAAyB;AAAA,IACvB,MAAM,YAAY,IAAI;AAAA,EACxB;AAAA,EAEA,QAAQ,OAAwB;AAC9B,eAAW,YAAY,KAAK,UAAU,OAAO,GAAG;AAC9C,WAAK,UAAU,KAAK,MAAM;AACxB,cAAM,SAAS,SAAS,KAAK;AAC7B,YAAI,WAAW,MAAM,GAAG;AACtB,eAAK,UAAU,MAAM,MAAM;AAEzB,mBAAO,KAAK;AAAA,UACd,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,OAAO;AACL,SAAK,MAAM,OAAO,YAAY,IAAI;AAClC,SAAK,QAAQ,KAAK,KAAK;AAEvB,QAAI,CAAC,KAAK,WAAW;AACnB;AAAA,IACF;AAEA,0BAAsB,MAAM,KAAK,KAAK,CAAC;AAAA,EACzC;AAAA,EAEA,OAAO;AACL,SAAK,YAAY;AACjB,0BAAsB,MAAM,KAAK,KAAK,CAAC;AAAA,EACzC;AAAA,EAEA,OAAO;AACL,SAAK,YAAY;AAAA,EACnB;AACF;AAKO,SAAS,SAA8B;AAC5C,SAAO,WAAW,YAAY;AAChC;",
4
+ "sourcesContent": ["import type { ServiceInterface } from './AbstractService.js';\nimport { AbstractService } from './AbstractService.js';\nimport { domScheduler } from '../utils/scheduler.js';\nimport { isFunction } from '../utils/is.js';\n\nexport interface RafServiceProps {\n time: DOMHighResTimeStamp;\n delta: number;\n}\n\nexport type RafServiceInterface = ServiceInterface<RafServiceProps>;\n\nexport class RafService extends AbstractService<RafServiceProps> {\n /**\n * @private\n */\n isTicking = false;\n\n /**\n * @private\n */\n scheduler = domScheduler;\n\n props: RafServiceProps = {\n time: performance.now(),\n delta: 0,\n };\n\n trigger(props: RafServiceProps) {\n for (const callback of this.callbacks.values()) {\n this.scheduler.read(() => {\n const render = callback(props) as (() => unknown) | void;\n if (isFunction(render)) {\n this.scheduler.write(() => {\n // @ts-ignore\n render(props);\n });\n }\n });\n }\n }\n\n loop() {\n const time = performance.now();\n this.props.delta = time - this.props.time;\n this.props.time = time;\n this.trigger(this.props);\n\n if (!this.isTicking) {\n return;\n }\n\n requestAnimationFrame(() => this.loop());\n }\n\n init() {\n this.isTicking = true;\n requestAnimationFrame(() => this.loop());\n }\n\n kill() {\n this.isTicking = false;\n }\n}\n\n/**\n * Use the RequestAnimationFrame (raf) service.\n */\nexport function useRaf(): RafServiceInterface {\n return RafService.getInstance();\n}\n"],
5
+ "mappings": "AACA,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AASpB,MAAM,mBAAmB,gBAAiC;AAAA;AAAA;AAAA;AAAA,EAI/D,YAAY;AAAA;AAAA;AAAA;AAAA,EAKZ,YAAY;AAAA,EAEZ,QAAyB;AAAA,IACvB,MAAM,YAAY,IAAI;AAAA,IACtB,OAAO;AAAA,EACT;AAAA,EAEA,QAAQ,OAAwB;AAC9B,eAAW,YAAY,KAAK,UAAU,OAAO,GAAG;AAC9C,WAAK,UAAU,KAAK,MAAM;AACxB,cAAM,SAAS,SAAS,KAAK;AAC7B,YAAI,WAAW,MAAM,GAAG;AACtB,eAAK,UAAU,MAAM,MAAM;AAEzB,mBAAO,KAAK;AAAA,UACd,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,OAAO;AACL,UAAM,OAAO,YAAY,IAAI;AAC7B,SAAK,MAAM,QAAQ,OAAO,KAAK,MAAM;AACrC,SAAK,MAAM,OAAO;AAClB,SAAK,QAAQ,KAAK,KAAK;AAEvB,QAAI,CAAC,KAAK,WAAW;AACnB;AAAA,IACF;AAEA,0BAAsB,MAAM,KAAK,KAAK,CAAC;AAAA,EACzC;AAAA,EAEA,OAAO;AACL,SAAK,YAAY;AACjB,0BAAsB,MAAM,KAAK,KAAK,CAAC;AAAA,EACzC;AAAA,EAEA,OAAO;AACL,SAAK,YAAY;AAAA,EACnB;AACF;AAKO,SAAS,SAA8B;AAC5C,SAAO,WAAW,YAAY;AAChC;",
6
6
  "names": []
7
7
  }
@@ -47,6 +47,7 @@ export declare class ScrollService extends AbstractService<ScrollServiceProps> {
47
47
  static config: ServiceConfig;
48
48
  props: ScrollServiceProps;
49
49
  updateProps(): ScrollServiceProps;
50
+ update(): void;
50
51
  onScrollDebounced: (...args: unknown[]) => void;
51
52
  /**
52
53
  * Scroll handler.
@@ -1,6 +1,7 @@
1
1
  import { AbstractService } from "./AbstractService.js";
2
2
  import { debounce } from "../utils/debounce.js";
3
3
  import { PASSIVE_CAPTURE_EVENT_OPTIONS } from "./utils.js";
4
+ import { nextTick } from "../utils/nextTick.js";
4
5
  class ScrollService extends AbstractService {
5
6
  static config = [[() => document, [["scroll", PASSIVE_CAPTURE_EVENT_OPTIONS]]]];
6
7
  props = {
@@ -69,14 +70,17 @@ class ScrollService extends AbstractService {
69
70
  props.direction.y = props.isDown ? "DOWN" : props.isUp ? "UP" : "NONE";
70
71
  return props;
71
72
  }
73
+ update() {
74
+ nextTick(() => this.updateProps()).then(() => this.trigger(this.props));
75
+ }
72
76
  onScrollDebounced = debounce(() => {
73
- this.trigger(this.updateProps());
77
+ this.update();
74
78
  }, 100);
75
79
  /**
76
80
  * Scroll handler.
77
81
  */
78
82
  handleEvent() {
79
- this.trigger(this.updateProps());
83
+ this.update();
80
84
  this.onScrollDebounced();
81
85
  }
82
86
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/js-toolkit/services/ScrollService.ts"],
4
- "sourcesContent": ["import type { ServiceConfig, ServiceInterface } from './AbstractService.js';\nimport { AbstractService } from './AbstractService.js';\nimport { debounce } from '../utils/debounce.js';\nimport { PASSIVE_CAPTURE_EVENT_OPTIONS } from './utils.js';\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\nexport type ScrollServiceInterface = ServiceInterface<ScrollServiceProps>;\n\nexport class ScrollService extends AbstractService<ScrollServiceProps> {\n static config: ServiceConfig = [[() => document, [['scroll', PASSIVE_CAPTURE_EVENT_OPTIONS]]]];\n\n props: ScrollServiceProps = {\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.scrollWidth - window.innerWidth,\n y: document.scrollingElement.scrollHeight - window.innerHeight,\n },\n maxX: document.scrollingElement.scrollWidth - window.innerWidth,\n maxY: document.scrollingElement.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 };\n\n updateProps(): ScrollServiceProps {\n const { props } = this;\n const yLast = props.y;\n const xLast = props.x;\n\n props.y = window.scrollY;\n props.x = window.scrollX;\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.scrollWidth - window.innerWidth;\n props.max.y = props.maxY = document.scrollingElement.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 onScrollDebounced = debounce(() => {\n this.trigger(this.updateProps());\n }, 100);\n\n /**\n * Scroll handler.\n */\n handleEvent() {\n this.trigger(this.updateProps());\n this.onScrollDebounced();\n }\n}\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 function useScroll(): ScrollServiceInterface {\n return ScrollService.getInstance();\n}\n"],
5
- "mappings": "AACA,SAAS,uBAAuB;AAChC,SAAS,gBAAgB;AACzB,SAAS,qCAAqC;AA6BvC,MAAM,sBAAsB,gBAAoC;AAAA,EACrE,OAAO,SAAwB,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC,UAAU,6BAA6B,CAAC,CAAC,CAAC;AAAA,EAE7F,QAA4B;AAAA,IAC1B,GAAG,OAAO;AAAA,IACV,GAAG,OAAO;AAAA,IACV,SAAS;AAAA,MACP,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV,UAAU;AAAA,IACV,MAAM;AAAA,MACJ,GAAG,OAAO;AAAA,MACV,GAAG,OAAO;AAAA,IACZ;AAAA,IACA,OAAO,OAAO;AAAA,IACd,OAAO,OAAO;AAAA,IACd,OAAO;AAAA,MACL,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,KAAK;AAAA,MACH,GAAG,SAAS,iBAAiB,cAAc,OAAO;AAAA,MAClD,GAAG,SAAS,iBAAiB,eAAe,OAAO;AAAA,IACrD;AAAA,IACA,MAAM,SAAS,iBAAiB,cAAc,OAAO;AAAA,IACrD,MAAM,SAAS,iBAAiB,eAAe,OAAO;AAAA,IACtD,UAAU;AAAA,MACR,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,IACX,WAAW;AAAA,MACT,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AAAA,EAEA,cAAkC;AAChC,UAAM,EAAE,MAAM,IAAI;AAClB,UAAM,QAAQ,MAAM;AACpB,UAAM,QAAQ,MAAM;AAEpB,UAAM,IAAI,OAAO;AACjB,UAAM,IAAI,OAAO;AACjB,UAAM,QAAQ,IAAI,MAAM,WAAW,MAAM,MAAM;AAC/C,UAAM,QAAQ,IAAI,MAAM,WAAW,MAAM,MAAM;AAC/C,UAAM,KAAK,IAAI,MAAM,QAAQ;AAC7B,UAAM,KAAK,IAAI,MAAM,QAAQ;AAC7B,UAAM,MAAM,IAAI,MAAM,SAAS,MAAM,IAAI;AACzC,UAAM,MAAM,IAAI,MAAM,SAAS,MAAM,IAAI;AACzC,UAAM,IAAI,IAAI,MAAM,OAAO,SAAS,iBAAiB,cAAc,OAAO;AAC1E,UAAM,IAAI,IAAI,MAAM,OAAO,SAAS,iBAAiB,eAAe,OAAO;AAC3E,UAAM,SAAS,IAAI,MAAM,YAAY,MAAM,IAAI,MAAM,IAAI,IAAI,MAAM,IAAI,MAAM,IAAI;AACjF,UAAM,SAAS,IAAI,MAAM,YAAY,MAAM,IAAI,MAAM,IAAI,IAAI,MAAM,IAAI,MAAM,IAAI;AACjF,UAAM,OAAO,MAAM,IAAI;AACvB,UAAM,UAAU,MAAM,IAAI;AAC1B,UAAM,SAAS,MAAM,IAAI;AACzB,UAAM,SAAS,MAAM,IAAI;AAEzB,UAAM,UAAU,IAAI,MAAM,UAAU,UAAU,MAAM,SAAS,SAAS;AACtE,UAAM,UAAU,IAAI,MAAM,SAAS,SAAS,MAAM,OAAO,OAAO;AAGhE,WAAO;AAAA,EACT;AAAA,EAEA,oBAAoB,SAAS,MAAM;AACjC,SAAK,QAAQ,KAAK,YAAY,CAAC;AAAA,EACjC,GAAG,GAAG;AAAA;AAAA;AAAA;AAAA,EAKN,cAAc;AACZ,SAAK,QAAQ,KAAK,YAAY,CAAC;AAC/B,SAAK,kBAAkB;AAAA,EACzB;AACF;AAaO,SAAS,YAAoC;AAClD,SAAO,cAAc,YAAY;AACnC;",
4
+ "sourcesContent": ["import type { ServiceConfig, ServiceInterface } from './AbstractService.js';\nimport { AbstractService } from './AbstractService.js';\nimport { debounce } from '../utils/debounce.js';\nimport { PASSIVE_CAPTURE_EVENT_OPTIONS } from './utils.js';\nimport { nextTick } from '../utils/nextTick.js';\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\nexport type ScrollServiceInterface = ServiceInterface<ScrollServiceProps>;\n\nexport class ScrollService extends AbstractService<ScrollServiceProps> {\n static config: ServiceConfig = [[() => document, [['scroll', PASSIVE_CAPTURE_EVENT_OPTIONS]]]];\n\n props: ScrollServiceProps = {\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.scrollWidth - window.innerWidth,\n y: document.scrollingElement.scrollHeight - window.innerHeight,\n },\n maxX: document.scrollingElement.scrollWidth - window.innerWidth,\n maxY: document.scrollingElement.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 };\n\n updateProps(): ScrollServiceProps {\n const { props } = this;\n const yLast = props.y;\n const xLast = props.x;\n\n props.y = window.scrollY;\n props.x = window.scrollX;\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.scrollWidth - window.innerWidth;\n props.max.y = props.maxY = document.scrollingElement.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 update() {\n nextTick(() => this.updateProps()).then(() => this.trigger(this.props));\n }\n\n onScrollDebounced = debounce(() => {\n this.update();\n }, 100);\n\n /**\n * Scroll handler.\n */\n handleEvent() {\n this.update();\n this.onScrollDebounced();\n }\n}\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 function useScroll(): ScrollServiceInterface {\n return ScrollService.getInstance();\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"root":["../packages/global.d.ts","../packages/js-toolkit/index.ts","../packages/js-toolkit/base/base.ts","../packages/js-toolkit/base/features.ts","../packages/js-toolkit/base/index.ts","../packages/js-toolkit/base/types.ts","../packages/js-toolkit/base/utils.ts","../packages/js-toolkit/base/managers/abstractmanager.ts","../packages/js-toolkit/base/managers/childrenmanager.ts","../packages/js-toolkit/base/managers/eventsmanager.ts","../packages/js-toolkit/base/managers/optionsmanager.ts","../packages/js-toolkit/base/managers/refsmanager.ts","../packages/js-toolkit/base/managers/responsiveoptionsmanager.ts","../packages/js-toolkit/base/managers/servicesmanager.ts","../packages/js-toolkit/base/managers/index.ts","../packages/js-toolkit/decorators/index.ts","../packages/js-toolkit/decorators/withbreakpointmanager.ts","../packages/js-toolkit/decorators/withbreakpointobserver.ts","../packages/js-toolkit/decorators/withdrag.ts","../packages/js-toolkit/decorators/withextraconfig.ts","../packages/js-toolkit/decorators/withfreezedoptions.ts","../packages/js-toolkit/decorators/withintersectionobserver.ts","../packages/js-toolkit/decorators/withmountonmediaquery.ts","../packages/js-toolkit/decorators/withmountwheninview.ts","../packages/js-toolkit/decorators/withmountwhenprefersmotion.ts","../packages/js-toolkit/decorators/withmutation.ts","../packages/js-toolkit/decorators/withname.ts","../packages/js-toolkit/decorators/withrelativepointer.ts","../packages/js-toolkit/decorators/withresponsiveoptions.ts","../packages/js-toolkit/decorators/withscrolledinview/index.ts","../packages/js-toolkit/decorators/withscrolledinview/types.ts","../packages/js-toolkit/decorators/withscrolledinview/utils.ts","../packages/js-toolkit/decorators/withscrolledinview/withscrolledinview.ts","../packages/js-toolkit/helpers/createapp.ts","../packages/js-toolkit/helpers/getclosestparent.ts","../packages/js-toolkit/helpers/getdirectchildren.ts","../packages/js-toolkit/helpers/getinstancefromelement.ts","../packages/js-toolkit/helpers/importoninteraction.ts","../packages/js-toolkit/helpers/importonmediaquery.ts","../packages/js-toolkit/helpers/importwhenidle.ts","../packages/js-toolkit/helpers/importwhenprefersmotion.ts","../packages/js-toolkit/helpers/importwhenvisible.ts","../packages/js-toolkit/helpers/index.ts","../packages/js-toolkit/helpers/utils.ts","../packages/js-toolkit/services/abstractservice.ts","../packages/js-toolkit/services/dragservice.ts","../packages/js-toolkit/services/keyservice.ts","../packages/js-toolkit/services/loadservice.ts","../packages/js-toolkit/services/mutationservice.ts","../packages/js-toolkit/services/pointerservice.ts","../packages/js-toolkit/services/rafservice.ts","../packages/js-toolkit/services/resizeservice.ts","../packages/js-toolkit/services/scrollservice.ts","../packages/js-toolkit/services/index.ts","../packages/js-toolkit/services/utils.ts","../packages/js-toolkit/utils/queue.ts","../packages/js-toolkit/utils/smartqueue.ts","../packages/js-toolkit/utils/cache.ts","../packages/js-toolkit/utils/debounce.ts","../packages/js-toolkit/utils/getcomponentresolver.ts","../packages/js-toolkit/utils/has.ts","../packages/js-toolkit/utils/history.ts","../packages/js-toolkit/utils/index.ts","../packages/js-toolkit/utils/is.ts","../packages/js-toolkit/utils/keycodes.ts","../packages/js-toolkit/utils/loadelement.ts","../packages/js-toolkit/utils/memo.ts","../packages/js-toolkit/utils/memoize.ts","../packages/js-toolkit/utils/nextframe.ts","../packages/js-toolkit/utils/nextmicrotask.ts","../packages/js-toolkit/utils/nexttick.ts","../packages/js-toolkit/utils/noop.ts","../packages/js-toolkit/utils/random.ts","../packages/js-toolkit/utils/scheduler.ts","../packages/js-toolkit/utils/scrollto.ts","../packages/js-toolkit/utils/throttle.ts","../packages/js-toolkit/utils/trapfocus.ts","../packages/js-toolkit/utils/tween.ts","../packages/js-toolkit/utils/wait.ts","../packages/js-toolkit/utils/collide/boundingrecttocircle.ts","../packages/js-toolkit/utils/collide/collidecirclecircle.ts","../packages/js-toolkit/utils/collide/collidecirclerect.ts","../packages/js-toolkit/utils/collide/collidepointcircle.ts","../packages/js-toolkit/utils/collide/collidepointrect.ts","../packages/js-toolkit/utils/collide/colliderectrect.ts","../packages/js-toolkit/utils/collide/index.ts","../packages/js-toolkit/utils/css/animate.ts","../packages/js-toolkit/utils/css/classes.ts","../packages/js-toolkit/utils/css/getoffsetsizes.ts","../packages/js-toolkit/utils/css/index.ts","../packages/js-toolkit/utils/css/matrix.ts","../packages/js-toolkit/utils/css/styles.ts","../packages/js-toolkit/utils/css/transform.ts","../packages/js-toolkit/utils/css/transition.ts","../packages/js-toolkit/utils/css/utils.ts","../packages/js-toolkit/utils/dom/ancestors.ts","../packages/js-toolkit/utils/dom/createelement.ts","../packages/js-toolkit/utils/dom/index.ts","../packages/js-toolkit/utils/math/clamp.ts","../packages/js-toolkit/utils/math/clamp01.ts","../packages/js-toolkit/utils/math/createeases.ts","../packages/js-toolkit/utils/math/createrange.ts","../packages/js-toolkit/utils/math/damp.ts","../packages/js-toolkit/utils/math/ease.ts","../packages/js-toolkit/utils/math/index.ts","../packages/js-toolkit/utils/math/inertiafinalvalue.ts","../packages/js-toolkit/utils/math/lerp.ts","../packages/js-toolkit/utils/math/map.ts","../packages/js-toolkit/utils/math/mean.ts","../packages/js-toolkit/utils/math/round.ts","../packages/js-toolkit/utils/object/getallproperties.ts","../packages/js-toolkit/utils/string/changecase.ts","../packages/js-toolkit/utils/string/endswith.ts","../packages/js-toolkit/utils/string/index.ts","../packages/js-toolkit/utils/string/startswith.ts","../packages/js-toolkit/utils/string/withleadingcharacters.ts","../packages/js-toolkit/utils/string/withleadingslash.ts","../packages/js-toolkit/utils/string/withtrailingcharacters.ts","../packages/js-toolkit/utils/string/withtrailingslash.ts","../packages/js-toolkit/utils/string/withoutleadingcharacters.ts","../packages/js-toolkit/utils/string/withoutleadingcharactersrecursive.ts","../packages/js-toolkit/utils/string/withoutleadingslash.ts","../packages/js-toolkit/utils/string/withouttrailingcharacters.ts","../packages/js-toolkit/utils/string/withouttrailingcharactersrecursive.ts","../packages/js-toolkit/utils/string/withouttrailingslash.ts"],"version":"5.8.3"}
1
+ {"root":["../packages/global.d.ts","../packages/js-toolkit/index.ts","../packages/js-toolkit/base/base.ts","../packages/js-toolkit/base/features.ts","../packages/js-toolkit/base/index.ts","../packages/js-toolkit/base/types.ts","../packages/js-toolkit/base/utils.ts","../packages/js-toolkit/base/managers/abstractmanager.ts","../packages/js-toolkit/base/managers/childrenmanager.ts","../packages/js-toolkit/base/managers/eventsmanager.ts","../packages/js-toolkit/base/managers/optionsmanager.ts","../packages/js-toolkit/base/managers/refsmanager.ts","../packages/js-toolkit/base/managers/responsiveoptionsmanager.ts","../packages/js-toolkit/base/managers/servicesmanager.ts","../packages/js-toolkit/base/managers/index.ts","../packages/js-toolkit/decorators/index.ts","../packages/js-toolkit/decorators/withbreakpointmanager.ts","../packages/js-toolkit/decorators/withbreakpointobserver.ts","../packages/js-toolkit/decorators/withdrag.ts","../packages/js-toolkit/decorators/withextraconfig.ts","../packages/js-toolkit/decorators/withfreezedoptions.ts","../packages/js-toolkit/decorators/withintersectionobserver.ts","../packages/js-toolkit/decorators/withmountonmediaquery.ts","../packages/js-toolkit/decorators/withmountwheninview.ts","../packages/js-toolkit/decorators/withmountwhenprefersmotion.ts","../packages/js-toolkit/decorators/withmutation.ts","../packages/js-toolkit/decorators/withname.ts","../packages/js-toolkit/decorators/withrelativepointer.ts","../packages/js-toolkit/decorators/withresponsiveoptions.ts","../packages/js-toolkit/decorators/withscrolledinview/index.ts","../packages/js-toolkit/decorators/withscrolledinview/types.ts","../packages/js-toolkit/decorators/withscrolledinview/utils.ts","../packages/js-toolkit/decorators/withscrolledinview/withscrolledinview.ts","../packages/js-toolkit/helpers/createapp.ts","../packages/js-toolkit/helpers/getclosestparent.ts","../packages/js-toolkit/helpers/getdirectchildren.ts","../packages/js-toolkit/helpers/getinstancefromelement.ts","../packages/js-toolkit/helpers/importoninteraction.ts","../packages/js-toolkit/helpers/importonmediaquery.ts","../packages/js-toolkit/helpers/importwhenidle.ts","../packages/js-toolkit/helpers/importwhenprefersmotion.ts","../packages/js-toolkit/helpers/importwhenvisible.ts","../packages/js-toolkit/helpers/index.ts","../packages/js-toolkit/helpers/utils.ts","../packages/js-toolkit/services/abstractservice.ts","../packages/js-toolkit/services/dragservice.ts","../packages/js-toolkit/services/keyservice.ts","../packages/js-toolkit/services/loadservice.ts","../packages/js-toolkit/services/mutationservice.ts","../packages/js-toolkit/services/pointerservice.ts","../packages/js-toolkit/services/rafservice.ts","../packages/js-toolkit/services/resizeservice.ts","../packages/js-toolkit/services/scrollservice.ts","../packages/js-toolkit/services/index.ts","../packages/js-toolkit/services/utils.ts","../packages/js-toolkit/utils/queue.ts","../packages/js-toolkit/utils/smartqueue.ts","../packages/js-toolkit/utils/cache.ts","../packages/js-toolkit/utils/debounce.ts","../packages/js-toolkit/utils/getcomponentresolver.ts","../packages/js-toolkit/utils/has.ts","../packages/js-toolkit/utils/history.ts","../packages/js-toolkit/utils/index.ts","../packages/js-toolkit/utils/is.ts","../packages/js-toolkit/utils/keycodes.ts","../packages/js-toolkit/utils/loadelement.ts","../packages/js-toolkit/utils/memo.ts","../packages/js-toolkit/utils/memoize.ts","../packages/js-toolkit/utils/nextframe.ts","../packages/js-toolkit/utils/nextmicrotask.ts","../packages/js-toolkit/utils/nexttick.ts","../packages/js-toolkit/utils/noop.ts","../packages/js-toolkit/utils/random.ts","../packages/js-toolkit/utils/scheduler.ts","../packages/js-toolkit/utils/scrollto.ts","../packages/js-toolkit/utils/throttle.ts","../packages/js-toolkit/utils/trapfocus.ts","../packages/js-toolkit/utils/tween.ts","../packages/js-toolkit/utils/wait.ts","../packages/js-toolkit/utils/collide/boundingrecttocircle.ts","../packages/js-toolkit/utils/collide/collidecirclecircle.ts","../packages/js-toolkit/utils/collide/collidecirclerect.ts","../packages/js-toolkit/utils/collide/collidepointcircle.ts","../packages/js-toolkit/utils/collide/collidepointrect.ts","../packages/js-toolkit/utils/collide/colliderectrect.ts","../packages/js-toolkit/utils/collide/index.ts","../packages/js-toolkit/utils/css/animate.ts","../packages/js-toolkit/utils/css/classes.ts","../packages/js-toolkit/utils/css/getoffsetsizes.ts","../packages/js-toolkit/utils/css/index.ts","../packages/js-toolkit/utils/css/matrix.ts","../packages/js-toolkit/utils/css/styles.ts","../packages/js-toolkit/utils/css/transform.ts","../packages/js-toolkit/utils/css/transition.ts","../packages/js-toolkit/utils/css/utils.ts","../packages/js-toolkit/utils/dom/ancestors.ts","../packages/js-toolkit/utils/dom/createelement.ts","../packages/js-toolkit/utils/dom/index.ts","../packages/js-toolkit/utils/math/clamp.ts","../packages/js-toolkit/utils/math/clamp01.ts","../packages/js-toolkit/utils/math/createeases.ts","../packages/js-toolkit/utils/math/createrange.ts","../packages/js-toolkit/utils/math/damp.ts","../packages/js-toolkit/utils/math/ease.ts","../packages/js-toolkit/utils/math/index.ts","../packages/js-toolkit/utils/math/inertiafinalvalue.ts","../packages/js-toolkit/utils/math/lerp.ts","../packages/js-toolkit/utils/math/map.ts","../packages/js-toolkit/utils/math/mean.ts","../packages/js-toolkit/utils/math/round.ts","../packages/js-toolkit/utils/math/smoothto.ts","../packages/js-toolkit/utils/math/spring.ts","../packages/js-toolkit/utils/math/wrap.ts","../packages/js-toolkit/utils/object/getallproperties.ts","../packages/js-toolkit/utils/string/changecase.ts","../packages/js-toolkit/utils/string/endswith.ts","../packages/js-toolkit/utils/string/index.ts","../packages/js-toolkit/utils/string/startswith.ts","../packages/js-toolkit/utils/string/withleadingcharacters.ts","../packages/js-toolkit/utils/string/withleadingslash.ts","../packages/js-toolkit/utils/string/withtrailingcharacters.ts","../packages/js-toolkit/utils/string/withtrailingslash.ts","../packages/js-toolkit/utils/string/withoutleadingcharacters.ts","../packages/js-toolkit/utils/string/withoutleadingcharactersrecursive.ts","../packages/js-toolkit/utils/string/withoutleadingslash.ts","../packages/js-toolkit/utils/string/withouttrailingcharacters.ts","../packages/js-toolkit/utils/string/withouttrailingcharactersrecursive.ts","../packages/js-toolkit/utils/string/withouttrailingslash.ts"],"version":"5.9.2"}
@@ -17,6 +17,7 @@ const TRANSFORM_PROPS = [
17
17
  "skewY"
18
18
  ];
19
19
  function transform(elementOrElements, props) {
20
+ if (!elementOrElements) return;
20
21
  let value = "";
21
22
  if (isDefined(props.x) || isDefined(props.y) || isDefined(props.z)) {
22
23
  value += `translate3d(${props.x ?? 0}px, ${props.y ?? 0}px, ${props.z ?? 0}px) `;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../packages/js-toolkit/utils/css/transform.ts"],
4
- "sourcesContent": ["import { isDefined } from '../is.js';\n// eslint-disable-next-line import/extensions\nimport { eachElements } from './utils.js';\n\nexport type TransformProps = Partial<{\n x: number;\n y: number;\n z: number;\n rotate: number;\n rotateX: number;\n rotateY: number;\n rotateZ: number;\n scale: number;\n scaleX: number;\n scaleY: number;\n scaleZ: number;\n skew: number;\n skewX: number;\n skewY: number;\n}>;\n\nexport const TRANSFORM_PROPS = [\n 'x',\n 'y',\n 'z',\n 'rotate',\n 'rotateX',\n 'rotateY',\n 'rotateZ',\n 'scale',\n 'scaleX',\n 'scaleY',\n 'scaleZ',\n 'skew',\n 'skewX',\n 'skewY',\n];\n\n/**\n * Generate a CSS transform.\n */\nexport function transform(\n elementOrElements: HTMLElement | HTMLElement[] | NodeListOf<HTMLElement>,\n props: TransformProps,\n): string {\n let value = '';\n\n if (isDefined(props.x) || isDefined(props.y) || isDefined(props.z)) {\n value += `translate3d(${props.x ?? 0}px, ${props.y ?? 0}px, ${props.z ?? 0}px) `;\n }\n\n if (isDefined(props.rotate)) {\n value += `rotate(${props.rotate}deg) `;\n } else {\n if (isDefined(props.rotateX)) {\n value += `rotateX(${props.rotateX}deg) `;\n }\n\n if (isDefined(props.rotateY)) {\n value += `rotateY(${props.rotateY}deg) `;\n }\n\n if (isDefined(props.rotateZ)) {\n value += `rotateZ(${props.rotateZ}deg) `;\n }\n }\n\n if (isDefined(props.scale)) {\n value += `scale(${props.scale}) `;\n } else {\n if (isDefined(props.scaleX)) {\n value += `scaleX(${props.scaleX}) `;\n }\n\n if (isDefined(props.scaleY)) {\n value += `scaleY(${props.scaleY}) `;\n }\n\n if (isDefined(props.scaleZ)) {\n value += `scaleZ(${props.scaleZ}) `;\n }\n }\n\n if (isDefined(props.skew)) {\n value += `skew(${props.skew}deg) `;\n } else {\n if (isDefined(props.skewX)) {\n value += `skewX(${props.skewX}deg) `;\n }\n\n if (isDefined(props.skewY)) {\n value += `skewY(${props.skewY}deg) `;\n }\n }\n\n eachElements(elementOrElements, (element) => {\n element.style.transform = value;\n });\n return value;\n}\n"],
5
- "mappings": "AAAA,SAAS,iBAAiB;AAE1B,SAAS,oBAAoB;AAmBtB,MAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,SAAS,UACd,mBACA,OACQ;AACR,MAAI,QAAQ;AAEZ,MAAI,UAAU,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,GAAG;AAClE,aAAS,eAAe,MAAM,KAAK,CAAC,OAAO,MAAM,KAAK,CAAC,OAAO,MAAM,KAAK,CAAC;AAAA,EAC5E;AAEA,MAAI,UAAU,MAAM,MAAM,GAAG;AAC3B,aAAS,UAAU,MAAM,MAAM;AAAA,EACjC,OAAO;AACL,QAAI,UAAU,MAAM,OAAO,GAAG;AAC5B,eAAS,WAAW,MAAM,OAAO;AAAA,IACnC;AAEA,QAAI,UAAU,MAAM,OAAO,GAAG;AAC5B,eAAS,WAAW,MAAM,OAAO;AAAA,IACnC;AAEA,QAAI,UAAU,MAAM,OAAO,GAAG;AAC5B,eAAS,WAAW,MAAM,OAAO;AAAA,IACnC;AAAA,EACF;AAEA,MAAI,UAAU,MAAM,KAAK,GAAG;AAC1B,aAAS,SAAS,MAAM,KAAK;AAAA,EAC/B,OAAO;AACL,QAAI,UAAU,MAAM,MAAM,GAAG;AAC3B,eAAS,UAAU,MAAM,MAAM;AAAA,IACjC;AAEA,QAAI,UAAU,MAAM,MAAM,GAAG;AAC3B,eAAS,UAAU,MAAM,MAAM;AAAA,IACjC;AAEA,QAAI,UAAU,MAAM,MAAM,GAAG;AAC3B,eAAS,UAAU,MAAM,MAAM;AAAA,IACjC;AAAA,EACF;AAEA,MAAI,UAAU,MAAM,IAAI,GAAG;AACzB,aAAS,QAAQ,MAAM,IAAI;AAAA,EAC7B,OAAO;AACL,QAAI,UAAU,MAAM,KAAK,GAAG;AAC1B,eAAS,SAAS,MAAM,KAAK;AAAA,IAC/B;AAEA,QAAI,UAAU,MAAM,KAAK,GAAG;AAC1B,eAAS,SAAS,MAAM,KAAK;AAAA,IAC/B;AAAA,EACF;AAEA,eAAa,mBAAmB,CAAC,YAAY;AAC3C,YAAQ,MAAM,YAAY;AAAA,EAC5B,CAAC;AACD,SAAO;AACT;",
4
+ "sourcesContent": ["import { isDefined } from '../is.js';\n// eslint-disable-next-line import/extensions\nimport { eachElements } from './utils.js';\n\nexport type TransformProps = Partial<{\n x: number;\n y: number;\n z: number;\n rotate: number;\n rotateX: number;\n rotateY: number;\n rotateZ: number;\n scale: number;\n scaleX: number;\n scaleY: number;\n scaleZ: number;\n skew: number;\n skewX: number;\n skewY: number;\n}>;\n\nexport const TRANSFORM_PROPS = [\n 'x',\n 'y',\n 'z',\n 'rotate',\n 'rotateX',\n 'rotateY',\n 'rotateZ',\n 'scale',\n 'scaleX',\n 'scaleY',\n 'scaleZ',\n 'skew',\n 'skewX',\n 'skewY',\n];\n\n/**\n * Generate a CSS transform.\n */\nexport function transform(\n elementOrElements: HTMLElement | HTMLElement[] | NodeListOf<HTMLElement>,\n props: TransformProps,\n): string {\n if (!elementOrElements) return\n\n let value = '';\n\n if (isDefined(props.x) || isDefined(props.y) || isDefined(props.z)) {\n value += `translate3d(${props.x ?? 0}px, ${props.y ?? 0}px, ${props.z ?? 0}px) `;\n }\n\n if (isDefined(props.rotate)) {\n value += `rotate(${props.rotate}deg) `;\n } else {\n if (isDefined(props.rotateX)) {\n value += `rotateX(${props.rotateX}deg) `;\n }\n\n if (isDefined(props.rotateY)) {\n value += `rotateY(${props.rotateY}deg) `;\n }\n\n if (isDefined(props.rotateZ)) {\n value += `rotateZ(${props.rotateZ}deg) `;\n }\n }\n\n if (isDefined(props.scale)) {\n value += `scale(${props.scale}) `;\n } else {\n if (isDefined(props.scaleX)) {\n value += `scaleX(${props.scaleX}) `;\n }\n\n if (isDefined(props.scaleY)) {\n value += `scaleY(${props.scaleY}) `;\n }\n\n if (isDefined(props.scaleZ)) {\n value += `scaleZ(${props.scaleZ}) `;\n }\n }\n\n if (isDefined(props.skew)) {\n value += `skew(${props.skew}deg) `;\n } else {\n if (isDefined(props.skewX)) {\n value += `skewX(${props.skewX}deg) `;\n }\n\n if (isDefined(props.skewY)) {\n value += `skewY(${props.skewY}deg) `;\n }\n }\n\n eachElements(elementOrElements, (element) => {\n element.style.transform = value;\n });\n return value;\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAE1B,SAAS,oBAAoB;AAmBtB,MAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,SAAS,UACd,mBACA,OACQ;AACR,MAAI,CAAC,kBAAmB;AAExB,MAAI,QAAQ;AAEZ,MAAI,UAAU,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,GAAG;AAClE,aAAS,eAAe,MAAM,KAAK,CAAC,OAAO,MAAM,KAAK,CAAC,OAAO,MAAM,KAAK,CAAC;AAAA,EAC5E;AAEA,MAAI,UAAU,MAAM,MAAM,GAAG;AAC3B,aAAS,UAAU,MAAM,MAAM;AAAA,EACjC,OAAO;AACL,QAAI,UAAU,MAAM,OAAO,GAAG;AAC5B,eAAS,WAAW,MAAM,OAAO;AAAA,IACnC;AAEA,QAAI,UAAU,MAAM,OAAO,GAAG;AAC5B,eAAS,WAAW,MAAM,OAAO;AAAA,IACnC;AAEA,QAAI,UAAU,MAAM,OAAO,GAAG;AAC5B,eAAS,WAAW,MAAM,OAAO;AAAA,IACnC;AAAA,EACF;AAEA,MAAI,UAAU,MAAM,KAAK,GAAG;AAC1B,aAAS,SAAS,MAAM,KAAK;AAAA,EAC/B,OAAO;AACL,QAAI,UAAU,MAAM,MAAM,GAAG;AAC3B,eAAS,UAAU,MAAM,MAAM;AAAA,IACjC;AAEA,QAAI,UAAU,MAAM,MAAM,GAAG;AAC3B,eAAS,UAAU,MAAM,MAAM;AAAA,IACjC;AAEA,QAAI,UAAU,MAAM,MAAM,GAAG;AAC3B,eAAS,UAAU,MAAM,MAAM;AAAA,IACjC;AAAA,EACF;AAEA,MAAI,UAAU,MAAM,IAAI,GAAG;AACzB,aAAS,QAAQ,MAAM,IAAI;AAAA,EAC7B,OAAO;AACL,QAAI,UAAU,MAAM,KAAK,GAAG;AAC1B,eAAS,SAAS,MAAM,KAAK;AAAA,IAC/B;AAEA,QAAI,UAAU,MAAM,KAAK,GAAG;AAC1B,eAAS,SAAS,MAAM,KAAK;AAAA,IAC/B;AAAA,EACF;AAEA,eAAa,mBAAmB,CAAC,YAAY;AAC3C,YAAQ,MAAM,YAAY;AAAA,EAC5B,CAAC;AACD,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -5,8 +5,11 @@ export { createRange } from './createRange.js';
5
5
  export { clamp } from './clamp.js';
6
6
  export { clamp01 } from './clamp01.js';
7
7
  export { damp } from './damp.js';
8
+ export { spring } from './spring.js';
8
9
  export { inertiaFinalValue } from './inertiaFinalValue.js';
9
10
  export { lerp } from './lerp.js';
10
11
  export { map } from './map.js';
11
12
  export { round } from './round.js';
12
13
  export { mean } from './mean.js';
14
+ export { smoothTo } from './smoothTo.js';
15
+ export { wrap } from './wrap.js';
@@ -5,11 +5,14 @@ import { createRange } from "./createRange.js";
5
5
  import { clamp } from "./clamp.js";
6
6
  import { clamp01 } from "./clamp01.js";
7
7
  import { damp } from "./damp.js";
8
+ import { spring } from "./spring.js";
8
9
  import { inertiaFinalValue } from "./inertiaFinalValue.js";
9
10
  import { lerp } from "./lerp.js";
10
11
  import { map } from "./map.js";
11
12
  import { round } from "./round.js";
12
13
  import { mean } from "./mean.js";
14
+ import { smoothTo } from "./smoothTo.js";
15
+ import { wrap } from "./wrap.js";
13
16
  export {
14
17
  clamp,
15
18
  clamp01,
@@ -20,6 +23,9 @@ export {
20
23
  lerp,
21
24
  map,
22
25
  mean,
23
- round
26
+ round,
27
+ smoothTo,
28
+ spring,
29
+ wrap
24
30
  };
25
31
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../packages/js-toolkit/utils/math/index.ts"],
4
- "sourcesContent": ["export * as ease from './ease.js';\nexport * from './createEases.js';\nexport * from './ease.js';\nexport { createRange } from './createRange.js';\nexport { clamp } from './clamp.js';\nexport { clamp01 } from './clamp01.js';\nexport { damp } from './damp.js';\nexport { inertiaFinalValue } from './inertiaFinalValue.js';\nexport { lerp } from './lerp.js';\nexport { map } from './map.js';\nexport { round } from './round.js';\nexport { mean } from './mean.js';\n"],
5
- "mappings": "AAAA,YAAY,UAAU;AACtB,cAAc;AACd,cAAc;AACd,SAAS,mBAAmB;AAC5B,SAAS,aAAa;AACtB,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,yBAAyB;AAClC,SAAS,YAAY;AACrB,SAAS,WAAW;AACpB,SAAS,aAAa;AACtB,SAAS,YAAY;",
4
+ "sourcesContent": ["export * as ease from './ease.js';\nexport * from './createEases.js';\nexport * from './ease.js';\nexport { createRange } from './createRange.js';\nexport { clamp } from './clamp.js';\nexport { clamp01 } from './clamp01.js';\nexport { damp } from './damp.js';\nexport { spring } from './spring.js';\nexport { inertiaFinalValue } from './inertiaFinalValue.js';\nexport { lerp } from './lerp.js';\nexport { map } from './map.js';\nexport { round } from './round.js';\nexport { mean } from './mean.js';\nexport { smoothTo } from './smoothTo.js';\nexport { wrap } from './wrap.js';\n"],
5
+ "mappings": "AAAA,YAAY,UAAU;AACtB,cAAc;AACd,cAAc;AACd,SAAS,mBAAmB;AAC5B,SAAS,aAAa;AACtB,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,cAAc;AACvB,SAAS,yBAAyB;AAClC,SAAS,YAAY;AACrB,SAAS,WAAW;AACpB,SAAS,aAAa;AACtB,SAAS,YAAY;AACrB,SAAS,gBAAgB;AACzB,SAAS,YAAY;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,50 @@
1
+ export type SmoothToOptions = Partial<{
2
+ /**
3
+ * Damping factor, the smaller the smoother, defaults to 0.6.
4
+ */
5
+ damping: number;
6
+ /**
7
+ * Precision used to decide when the smoothing should end, defaults to 1 / 1e8.
8
+ */
9
+ precision: number;
10
+ /**
11
+ * Enable spring physics, defaults to `true` if one of `stiffness` or `mass` is set, defaults to `false` otherwise.
12
+ */
13
+ spring: boolean;
14
+ /**
15
+ * Stiffness factor for spring physics, the higher the stiffer, defaults to 0.1.
16
+ */
17
+ stiffness: number;
18
+ /**
19
+ * Mass factor when spring is enabled, the higher the heavier, defaults to 1.
20
+ */
21
+ mass: number;
22
+ }>;
23
+ /**
24
+ * Create a smoothing function that will smoothly tween between two values.
25
+ * @param {number} [start] The initial value.
26
+ * @param {SmoothToOptions} [options] Options for the transition.
27
+ * @see https://js-toolkit.studiometa.dev/utils/math/smoothTo.html
28
+ * @example
29
+ * ```js
30
+ * const x = smoothTo(0);
31
+ * x.subscribe((value) => console.log(value));
32
+ * x(100); // 0.1
33
+ * ```
34
+ */
35
+ export declare function smoothTo(start?: number, options?: SmoothToOptions): {
36
+ (newValue?: number): number;
37
+ /**
38
+ * Subscribe a callback to the value update.
39
+ */
40
+ subscribe: (fn: (value: number) => any) => () => boolean;
41
+ /**
42
+ * Unsubscribe a callback from the value update.
43
+ */
44
+ unsubscribe: (fn: (value: number) => any) => boolean;
45
+ raw(): number;
46
+ damping(val?: number): number;
47
+ precision(val?: number): number;
48
+ stiffness(val?: number): number;
49
+ spring(val?: boolean): boolean;
50
+ };
@@ -0,0 +1,60 @@
1
+ import { useRaf } from "../../services/RafService.js";
2
+ import { damp } from "./damp.js";
3
+ import { spring } from "./spring.js";
4
+ import { isFunction, isDefined } from "../is.js";
5
+ function smoothTo(start = 0, options = {}) {
6
+ const { add, has, remove } = useRaf();
7
+ const key = Symbol();
8
+ const fns = /* @__PURE__ */ new Set();
9
+ let damping = options.damping ?? 0.6;
10
+ let precision = options.precision ?? 1 / 1e8;
11
+ let stiffness = options.stiffness ?? 0.1;
12
+ let mass = options.mass ?? 1;
13
+ let isSpring = options.spring === true || isDefined(options.stiffness) || isDefined(options.mass);
14
+ let value = start;
15
+ let smoothed = start;
16
+ let velocity = 0;
17
+ function tick() {
18
+ if (isSpring) {
19
+ [smoothed, velocity] = spring(value, smoothed, velocity, stiffness, damping, mass, precision);
20
+ } else {
21
+ smoothed = damp(value, smoothed, damping, precision);
22
+ }
23
+ for (const fn of fns) {
24
+ fn(smoothed);
25
+ }
26
+ if (smoothed === value) remove(key);
27
+ }
28
+ function subscribe(fn) {
29
+ if (isFunction(fn)) {
30
+ fns.add(fn);
31
+ }
32
+ return () => unsubscribe(fn);
33
+ }
34
+ function unsubscribe(fn) {
35
+ return fns.delete(fn);
36
+ }
37
+ function update(newValue) {
38
+ if (!isDefined(newValue)) {
39
+ return smoothed;
40
+ }
41
+ value = newValue;
42
+ if (!has(key)) {
43
+ add(key, tick);
44
+ }
45
+ return smoothed;
46
+ }
47
+ update.subscribe = subscribe;
48
+ update.unsubscribe = unsubscribe;
49
+ update.raw = () => value;
50
+ update.damping = (val) => damping = val ?? damping;
51
+ update.precision = (val) => precision = val ?? precision;
52
+ update.stiffness = (val) => stiffness = val ?? stiffness;
53
+ update.spring = (val) => isSpring = val ?? isSpring;
54
+ update(start);
55
+ return update;
56
+ }
57
+ export {
58
+ smoothTo
59
+ };
60
+ //# sourceMappingURL=smoothTo.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../packages/js-toolkit/utils/math/smoothTo.ts"],
4
+ "sourcesContent": ["import { useRaf } from '../../services/RafService.js';\nimport { damp } from './damp.js';\nimport { spring } from './spring.js';\nimport { isFunction, isDefined } from '../is.js';\n\nexport type SmoothToOptions = Partial<{\n /**\n * Damping factor, the smaller the smoother, defaults to 0.6.\n */\n damping: number;\n /**\n * Precision used to decide when the smoothing should end, defaults to 1 / 1e8.\n */\n precision: number;\n /**\n * Enable spring physics, defaults to `true` if one of `stiffness` or `mass` is set, defaults to `false` otherwise.\n */\n spring: boolean;\n /**\n * Stiffness factor for spring physics, the higher the stiffer, defaults to 0.1.\n */\n stiffness: number;\n /**\n * Mass factor when spring is enabled, the higher the heavier, defaults to 1.\n */\n mass: number;\n}>;\n\n/**\n * Create a smoothing function that will smoothly tween between two values.\n * @param {number} [start] The initial value.\n * @param {SmoothToOptions} [options] Options for the transition.\n * @see https://js-toolkit.studiometa.dev/utils/math/smoothTo.html\n * @example\n * ```js\n * const x = smoothTo(0);\n * x.subscribe((value) => console.log(value));\n * x(100); // 0.1\n * ```\n */\nexport function smoothTo(start = 0, options: SmoothToOptions = {}) {\n const { add, has, remove } = useRaf();\n const key = Symbol();\n const fns = new Set<(value: number) => any>();\n\n let damping = options.damping ?? 0.6;\n let precision = options.precision ?? 1 / 1e8;\n let stiffness = options.stiffness ?? 0.1;\n let mass = options.mass ?? 1;\n let isSpring = options.spring === true || isDefined(options.stiffness) || isDefined(options.mass);\n\n let value = start;\n let smoothed = start;\n let velocity = 0;\n\n /**\n * Callback for the useRaf service.\n */\n function tick() {\n if (isSpring) {\n [smoothed, velocity] = spring(value, smoothed, velocity, stiffness, damping, mass, precision);\n } else {\n smoothed = damp(value, smoothed, damping, precision);\n }\n\n for (const fn of fns) {\n fn(smoothed);\n }\n\n if (smoothed === value) remove(key);\n }\n\n /**\n * Subscribe a callback to the value update.\n */\n function subscribe(fn: (value: number) => any) {\n if (isFunction(fn)) {\n fns.add(fn);\n }\n\n return () => unsubscribe(fn);\n }\n\n /**\n * Unsubscribe a callback to the value update.\n */\n function unsubscribe(fn: (value: number) => any) {\n return fns.delete(fn);\n }\n\n /**\n * Update the value if a parameter is given, get the value if no parameter is given.\n */\n function update(newValue?: number): number {\n if (!isDefined(newValue)) {\n return smoothed;\n }\n\n value = newValue;\n\n if (!has(key)) {\n add(key, tick);\n }\n\n return smoothed;\n }\n\n /**\n * Subscribe a callback to the value update.\n */\n update.subscribe = subscribe;\n\n /**\n * Unsubscribe a callback from the value update.\n */\n update.unsubscribe = unsubscribe;\n\n /**\n * Get the raw target value.\n */\n update.raw = () => value;\n /**\n * Get or set the damping factor.\n */\n update.damping = (val?: number) => (damping = val ?? damping);\n\n /**\n * Get or set the precision.\n */\n update.precision = (val?: number) => (precision = val ?? precision);\n\n /**\n * Get or set the stiffness factor.\n */\n update.stiffness = (val?: number) => (stiffness = val ?? stiffness);\n\n /**\n * Get or set the spring option.\n */\n update.spring = (val?: boolean) => (isSpring = val ?? isSpring);\n\n update(start);\n return update;\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAAc;AACvB,SAAS,YAAY;AACrB,SAAS,cAAc;AACvB,SAAS,YAAY,iBAAiB;AAqC/B,SAAS,SAAS,QAAQ,GAAG,UAA2B,CAAC,GAAG;AACjE,QAAM,EAAE,KAAK,KAAK,OAAO,IAAI,OAAO;AACpC,QAAM,MAAM,OAAO;AACnB,QAAM,MAAM,oBAAI,IAA4B;AAE5C,MAAI,UAAU,QAAQ,WAAW;AACjC,MAAI,YAAY,QAAQ,aAAa,IAAI;AACzC,MAAI,YAAY,QAAQ,aAAa;AACrC,MAAI,OAAO,QAAQ,QAAQ;AAC3B,MAAI,WAAW,QAAQ,WAAW,QAAQ,UAAU,QAAQ,SAAS,KAAK,UAAU,QAAQ,IAAI;AAEhG,MAAI,QAAQ;AACZ,MAAI,WAAW;AACf,MAAI,WAAW;AAKf,WAAS,OAAO;AACd,QAAI,UAAU;AACZ,OAAC,UAAU,QAAQ,IAAI,OAAO,OAAO,UAAU,UAAU,WAAW,SAAS,MAAM,SAAS;AAAA,IAC9F,OAAO;AACL,iBAAW,KAAK,OAAO,UAAU,SAAS,SAAS;AAAA,IACrD;AAEA,eAAW,MAAM,KAAK;AACpB,SAAG,QAAQ;AAAA,IACb;AAEA,QAAI,aAAa,MAAO,QAAO,GAAG;AAAA,EACpC;AAKA,WAAS,UAAU,IAA4B;AAC7C,QAAI,WAAW,EAAE,GAAG;AAClB,UAAI,IAAI,EAAE;AAAA,IACZ;AAEA,WAAO,MAAM,YAAY,EAAE;AAAA,EAC7B;AAKA,WAAS,YAAY,IAA4B;AAC/C,WAAO,IAAI,OAAO,EAAE;AAAA,EACtB;AAKA,WAAS,OAAO,UAA2B;AACzC,QAAI,CAAC,UAAU,QAAQ,GAAG;AACxB,aAAO;AAAA,IACT;AAEA,YAAQ;AAER,QAAI,CAAC,IAAI,GAAG,GAAG;AACb,UAAI,KAAK,IAAI;AAAA,IACf;AAEA,WAAO;AAAA,EACT;AAKA,SAAO,YAAY;AAKnB,SAAO,cAAc;AAKrB,SAAO,MAAM,MAAM;AAInB,SAAO,UAAU,CAAC,QAAkB,UAAU,OAAO;AAKrD,SAAO,YAAY,CAAC,QAAkB,YAAY,OAAO;AAKzD,SAAO,YAAY,CAAC,QAAkB,YAAY,OAAO;AAKzD,SAAO,SAAS,CAAC,QAAmB,WAAW,OAAO;AAEtD,SAAO,KAAK;AACZ,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Get the next spring value using velocity and spring physics.
3
+ * @param {number} targetValue The final value.
4
+ * @param {number} currentValue The current value.
5
+ * @param {number} currentVelocity The current velocity.
6
+ * @param {number} [stiffness=0.1] The spring stiffness (or tension) factor, defaults to 0.1.
7
+ * @param {number} [damping=0.8] The damping factor (or friction) to reduce oscillation, defaults to 0.6.
8
+ * @param {number} [mass=1] The mass factor affecting acceleration, defaults to 1.
9
+ * @param {number} [precision=1/1e4] The precision used to calculate the latest value, defaults to 1/1e4.
10
+ * @returns {[number, number]} The next value and velocity.
11
+ * @see https://js-toolkit.studiometa.dev/utils/math/spring.html
12
+ */
13
+ export declare function spring(targetValue: number, currentValue: number, currentVelocity: number, stiffness?: number, damping?: number, mass?: number, precision?: number): [number, number];
@@ -0,0 +1,11 @@
1
+ function spring(targetValue, currentValue, currentVelocity, stiffness = 0.1, damping = 0.6, mass = 1, precision = 1 / 1e4) {
2
+ const force = (targetValue - currentValue) * stiffness;
3
+ const acceleration = force / mass;
4
+ const velocity = currentVelocity * damping + acceleration;
5
+ const value = Math.abs(targetValue - currentValue) < precision && Math.abs(velocity) < precision ? targetValue : currentValue + velocity;
6
+ return [value, value === targetValue ? 0 : velocity];
7
+ }
8
+ export {
9
+ spring
10
+ };
11
+ //# sourceMappingURL=spring.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../packages/js-toolkit/utils/math/spring.ts"],
4
+ "sourcesContent": ["/**\n * Get the next spring value using velocity and spring physics.\n * @param {number} targetValue The final value.\n * @param {number} currentValue The current value.\n * @param {number} currentVelocity The current velocity.\n * @param {number} [stiffness=0.1] The spring stiffness (or tension) factor, defaults to 0.1.\n * @param {number} [damping=0.8] The damping factor (or friction) to reduce oscillation, defaults to 0.6.\n * @param {number} [mass=1] The mass factor affecting acceleration, defaults to 1.\n * @param {number} [precision=1/1e4] The precision used to calculate the latest value, defaults to 1/1e4.\n * @returns {[number, number]} The next value and velocity.\n * @see https://js-toolkit.studiometa.dev/utils/math/spring.html\n */\nexport function spring(\n targetValue: number,\n currentValue: number,\n currentVelocity: number,\n stiffness = 0.1,\n damping = 0.6,\n mass = 1,\n precision = 1 / 1e4,\n): [number, number] {\n const force = (targetValue - currentValue) * stiffness;\n const acceleration = force / mass;\n const velocity = currentVelocity * damping + acceleration;\n const value =\n Math.abs(targetValue - currentValue) < precision && Math.abs(velocity) < precision\n ? targetValue\n : currentValue + velocity;\n\n return [value, value === targetValue ? 0 : velocity];\n}\n"],
5
+ "mappings": "AAYO,SAAS,OACd,aACA,cACA,iBACA,YAAY,KACZ,UAAU,KACV,OAAO,GACP,YAAY,IAAI,KACE;AAClB,QAAM,SAAS,cAAc,gBAAgB;AAC7C,QAAM,eAAe,QAAQ;AAC7B,QAAM,WAAW,kBAAkB,UAAU;AAC7C,QAAM,QACJ,KAAK,IAAI,cAAc,YAAY,IAAI,aAAa,KAAK,IAAI,QAAQ,IAAI,YACrE,cACA,eAAe;AAErB,SAAO,CAAC,OAAO,UAAU,cAAc,IAAI,QAAQ;AACrD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Wrap a value in the min and max range.
3
+ */
4
+ export declare function wrap(value: number, min: number, max: number): number;
@@ -0,0 +1,8 @@
1
+ function wrap(value, min, max) {
2
+ const range = max - min;
3
+ return min === max ? min : (range + (value - min) % range) % range + min;
4
+ }
5
+ export {
6
+ wrap
7
+ };
8
+ //# sourceMappingURL=wrap.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../packages/js-toolkit/utils/math/wrap.ts"],
4
+ "sourcesContent": ["/**\n * Wrap a value in the min and max range.\n */\nexport function wrap(value: number, min: number, max: number): number {\n const range = max - min;\n return min === max ? min : ((range + ((value - min) % range)) % range) + min;\n}\n"],
5
+ "mappings": "AAGO,SAAS,KAAK,OAAe,KAAa,KAAqB;AACpE,QAAM,QAAQ,MAAM;AACpB,SAAO,QAAQ,MAAM,OAAQ,SAAU,QAAQ,OAAO,SAAU,QAAS;AAC3E;",
6
+ "names": []
7
+ }
package/utils/random.d.ts CHANGED
@@ -1,9 +1,16 @@
1
+ /**
2
+ * Get a random number between given bounds.
3
+ * @param {number} a First bound.
4
+ * @param {number} [b] Second bound, defaults to 0.
5
+ * @returns {number} A number between `a` and `b`.
6
+ */
7
+ export declare function random(a: number, b?: number): number;
1
8
  /**
2
9
  * Get a random integer between bounds
3
10
  *
4
- * @param {number} a Lower bound
5
- * @param {number} b Upper bound
6
- * @returns {number}
11
+ * @param {number} a First bound.
12
+ * @param {number} b Second bound.
13
+ * @returns {number} An integer between `a` and `b`;
7
14
  */
8
15
  export declare function randomInt(a: number, b?: number): number;
9
16
  /**
@@ -11,5 +18,6 @@ export declare function randomInt(a: number, b?: number): number;
11
18
  *
12
19
  * @param {T[] | string} items Array or string
13
20
  * @returns {T | undefined}
21
+ * @throws {Error} Throws an error if `items` is not an array or a string.
14
22
  */
15
23
  export declare function randomItem<T>(items: T[] | string): T | string | undefined;
package/utils/random.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import { isArray, isString } from "./is.js";
2
+ function random(a, b = 0) {
3
+ return Math.random() * (b - a) + a;
4
+ }
2
5
  function randomInt(a, b = 0) {
3
- return Math.floor(Math.random() * (a - b + 1)) + b;
6
+ return Math.round(random(a, b));
4
7
  }
5
8
  function randomItem(items) {
6
9
  if (!isArray(items) && !isString(items)) {
@@ -9,6 +12,7 @@ function randomItem(items) {
9
12
  return items.length > 0 ? items[randomInt(items.length - 1)] : void 0;
10
13
  }
11
14
  export {
15
+ random,
12
16
  randomInt,
13
17
  randomItem
14
18
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/js-toolkit/utils/random.ts"],
4
- "sourcesContent": ["import { isArray, isString } from './is.js';\n\n/**\n * Get a random integer between bounds\n *\n * @param {number} a Lower bound\n * @param {number} b Upper bound\n * @returns {number}\n */\nexport function randomInt(a: number, b = 0): number {\n return Math.floor(Math.random() * (a - b + 1)) + b;\n}\n\n/**\n * Get a random item of an array or a random character of a string\n *\n * @param {T[] | string} items Array or string\n * @returns {T | undefined}\n */\nexport function randomItem<T>(items: T[] | string): T | string | undefined {\n if (!isArray(items) && !isString(items)) {\n throw new Error('randomItem() expects an array or a string as argument.');\n }\n return items.length > 0 ? items[randomInt(items.length - 1)] : undefined;\n}\n"],
5
- "mappings": "AAAA,SAAS,SAAS,gBAAgB;AAS3B,SAAS,UAAU,GAAW,IAAI,GAAW;AAClD,SAAO,KAAK,MAAM,KAAK,OAAO,KAAK,IAAI,IAAI,EAAE,IAAI;AACnD;AAQO,SAAS,WAAc,OAA6C;AACzE,MAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,SAAS,KAAK,GAAG;AACvC,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,SAAO,MAAM,SAAS,IAAI,MAAM,UAAU,MAAM,SAAS,CAAC,CAAC,IAAI;AACjE;",
4
+ "sourcesContent": ["import { isArray, isString } from './is.js';\n\n/**\n * Get a random number between given bounds.\n * @param {number} a First bound.\n * @param {number} [b] Second bound, defaults to 0.\n * @returns {number} A number between `a` and `b`.\n */\nexport function random(a: number, b = 0): number {\n return Math.random() * (b - a) + a;\n}\n\n/**\n * Get a random integer between bounds\n *\n * @param {number} a First bound.\n * @param {number} b Second bound.\n * @returns {number} An integer between `a` and `b`;\n */\nexport function randomInt(a: number, b = 0): number {\n return Math.round(random(a, b));\n}\n\n/**\n * Get a random item of an array or a random character of a string\n *\n * @param {T[] | string} items Array or string\n * @returns {T | undefined}\n * @throws {Error} Throws an error if `items` is not an array or a string.\n */\nexport function randomItem<T>(items: T[] | string): T | string | undefined {\n if (!isArray(items) && !isString(items)) {\n throw new Error('randomItem() expects an array or a string as argument.');\n }\n return items.length > 0 ? items[randomInt(items.length - 1)] : undefined;\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS,gBAAgB;AAQ3B,SAAS,OAAO,GAAW,IAAI,GAAW;AAC/C,SAAO,KAAK,OAAO,KAAK,IAAI,KAAK;AACnC;AASO,SAAS,UAAU,GAAW,IAAI,GAAW;AAClD,SAAO,KAAK,MAAM,OAAO,GAAG,CAAC,CAAC;AAChC;AASO,SAAS,WAAc,OAA6C;AACzE,MAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,SAAS,KAAK,GAAG;AACvC,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,SAAO,MAAM,SAAS,IAAI,MAAM,UAAU,MAAM,SAAS,CAAC,CAAC,IAAI;AACjE;",
6
6
  "names": []
7
7
  }
package/utils/scrollTo.js CHANGED
@@ -80,7 +80,8 @@ function scrollTo(target, { rootElement = window, axis = yAxis, offset = 0, ...t
80
80
  (progress) => {
81
81
  rootElement.scrollTo({
82
82
  left: lerp(initialScrollPosition.left, targetScrollPosition.left, progress),
83
- top: lerp(initialScrollPosition.top, targetScrollPosition.top, progress)
83
+ top: lerp(initialScrollPosition.top, targetScrollPosition.top, progress),
84
+ behavior: "instant"
84
85
  });
85
86
  },
86
87
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/js-toolkit/utils/scrollTo.ts"],
4
- "sourcesContent": ["import { tween } from './tween.js';\nimport type { TweenOptions } from './tween.js';\nimport { isString, isNumber, isFunction, isDefined } from './is.js';\nimport { lerp } from './math/index.js';\n\nexport interface ScrollPosition {\n left: number;\n top: number;\n}\n\nexport type ScrollTarget = string | HTMLElement | number | Partial<ScrollPosition>;\n\nexport interface ScrollToOptions extends TweenOptions {\n /**\n * Root element that will be scrolled.\n */\n rootElement?: HTMLElement | typeof window;\n /**\n * Scroll direction.\n */\n axis?: (typeof scrollTo.axis)[keyof typeof scrollTo.axis];\n /**\n * Distance from the target.\n */\n offset?: number;\n}\n\nconst xAxis = Symbol(0);\nconst yAxis = Symbol(1);\nconst bothAxis = Symbol(2);\n\nfunction isHtmlElement(rootElement: ScrollToOptions['rootElement']): rootElement is HTMLElement {\n return rootElement instanceof HTMLElement;\n}\n\n/**\n * Get the current root element or window scroll position.\n */\nfunction getCurrentScrollPosition(rootElement: ScrollToOptions['rootElement']): ScrollPosition {\n return {\n left: isHtmlElement(rootElement) ? rootElement.scrollTop : rootElement.scrollX,\n top: isHtmlElement(rootElement) ? rootElement.scrollLeft : rootElement.scrollY,\n };\n}\n\n/**\n * Get the maximum scroll position values.\n */\nfunction getMaxScrollPosition(rootElement?: ScrollToOptions['rootElement']): ScrollPosition {\n return {\n left: isHtmlElement(rootElement)\n ? rootElement.scrollWidth - rootElement.offsetWidth\n : document.documentElement.scrollWidth - window.innerWidth,\n top: isHtmlElement(rootElement)\n ? rootElement.scrollHeight - rootElement.offsetHeight\n : document.documentElement.scrollHeight - window.innerHeight,\n };\n}\n\n/**\n * Get the target scroll position.\n */\nfunction getTargetScrollPosition(\n initialScrollPosition: ScrollPosition,\n maxScrollPosition: ScrollPosition,\n target: ScrollTarget,\n axis: ScrollToOptions['axis'],\n offset: number,\n): ScrollPosition {\n let { top, left } = initialScrollPosition;\n\n if (target instanceof HTMLElement || isString(target)) {\n const targetElement = target instanceof HTMLElement ? target : document.querySelector(target);\n\n if (!targetElement) {\n return { top, left };\n }\n\n const sizes = targetElement.getBoundingClientRect();\n const styles = getComputedStyle(targetElement);\n const scrollMargin = {\n left: Number.parseInt(styles.scrollMarginLeft || '0', 10),\n top: Number.parseInt(styles.scrollMarginTop || '0', 10),\n };\n\n // Set the scroll position of the target element.\n left = sizes.left + initialScrollPosition.left - scrollMargin.left;\n top = sizes.top + initialScrollPosition.top - scrollMargin.top;\n } else if (isNumber(target)) {\n left = target;\n top = target;\n } else {\n left = target.left ?? left;\n top = target.top ?? top;\n }\n\n left -= offset;\n top -= offset;\n\n if (axis !== bothAxis) {\n if (axis !== xAxis && !isDefined((target as Partial<ScrollPosition>).left)) {\n left = initialScrollPosition.left;\n }\n\n if (axis !== yAxis) {\n top = initialScrollPosition.top;\n }\n }\n\n return {\n left: Math.min(left, maxScrollPosition.left),\n top: Math.min(top, maxScrollPosition.top),\n };\n}\n\n/**\n * Scroll to an element.\n *\n * @returns {Promise<ScrollPosition>} A promising resolving with the scroll position.\n */\nexport function scrollTo(\n target: string | HTMLElement | number | Partial<ScrollPosition>,\n { rootElement = window, axis = yAxis, offset = 0, ...tweenOptions }: ScrollToOptions = {},\n): Promise<ScrollPosition> {\n const initialScrollPosition = getCurrentScrollPosition(rootElement);\n const maxScrollPosition = getMaxScrollPosition(rootElement);\n const targetScrollPosition = getTargetScrollPosition(\n initialScrollPosition,\n maxScrollPosition,\n target,\n axis,\n offset,\n );\n\n return new Promise((resolve) => {\n function eventHandler() {\n /* eslint-disable @typescript-eslint/no-use-before-define */\n tw.pause();\n stop();\n /* eslint-enable @typescript-eslint/no-use-before-define */\n }\n\n function stop() {\n rootElement.removeEventListener('wheel', eventHandler);\n rootElement.removeEventListener('touchmove', eventHandler);\n\n // Resolve the promise on animation finish.\n resolve(getCurrentScrollPosition(rootElement));\n }\n\n // Setup tween.\n const tw = tween(\n (progress) => {\n rootElement.scrollTo({\n left: lerp(initialScrollPosition.left, targetScrollPosition.left, progress),\n top: lerp(initialScrollPosition.top, targetScrollPosition.top, progress),\n });\n },\n {\n smooth: 0.2,\n ...tweenOptions,\n onFinish(progress) {\n if (isFunction(tweenOptions.onFinish)) {\n tweenOptions.onFinish(progress);\n }\n\n stop();\n },\n },\n );\n\n rootElement.addEventListener('wheel', eventHandler, { passive: true });\n rootElement.addEventListener('touchmove', eventHandler, { passive: true });\n tw.start();\n });\n}\n\nscrollTo.axis = {\n x: xAxis,\n y: yAxis,\n both: bothAxis,\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { tween } from './tween.js';\nimport type { TweenOptions } from './tween.js';\nimport { isString, isNumber, isFunction, isDefined } from './is.js';\nimport { lerp } from './math/index.js';\n\nexport interface ScrollPosition {\n left: number;\n top: number;\n}\n\nexport type ScrollTarget = string | HTMLElement | number | Partial<ScrollPosition>;\n\nexport interface ScrollToOptions extends TweenOptions {\n /**\n * Root element that will be scrolled.\n */\n rootElement?: HTMLElement | typeof window;\n /**\n * Scroll direction.\n */\n axis?: (typeof scrollTo.axis)[keyof typeof scrollTo.axis];\n /**\n * Distance from the target.\n */\n offset?: number;\n}\n\nconst xAxis = Symbol(0);\nconst yAxis = Symbol(1);\nconst bothAxis = Symbol(2);\n\nfunction isHtmlElement(rootElement: ScrollToOptions['rootElement']): rootElement is HTMLElement {\n return rootElement instanceof HTMLElement;\n}\n\n/**\n * Get the current root element or window scroll position.\n */\nfunction getCurrentScrollPosition(rootElement: ScrollToOptions['rootElement']): ScrollPosition {\n return {\n left: isHtmlElement(rootElement) ? rootElement.scrollTop : rootElement.scrollX,\n top: isHtmlElement(rootElement) ? rootElement.scrollLeft : rootElement.scrollY,\n };\n}\n\n/**\n * Get the maximum scroll position values.\n */\nfunction getMaxScrollPosition(rootElement?: ScrollToOptions['rootElement']): ScrollPosition {\n return {\n left: isHtmlElement(rootElement)\n ? rootElement.scrollWidth - rootElement.offsetWidth\n : document.documentElement.scrollWidth - window.innerWidth,\n top: isHtmlElement(rootElement)\n ? rootElement.scrollHeight - rootElement.offsetHeight\n : document.documentElement.scrollHeight - window.innerHeight,\n };\n}\n\n/**\n * Get the target scroll position.\n */\nfunction getTargetScrollPosition(\n initialScrollPosition: ScrollPosition,\n maxScrollPosition: ScrollPosition,\n target: ScrollTarget,\n axis: ScrollToOptions['axis'],\n offset: number,\n): ScrollPosition {\n let { top, left } = initialScrollPosition;\n\n if (target instanceof HTMLElement || isString(target)) {\n const targetElement = target instanceof HTMLElement ? target : document.querySelector(target);\n\n if (!targetElement) {\n return { top, left };\n }\n\n const sizes = targetElement.getBoundingClientRect();\n const styles = getComputedStyle(targetElement);\n const scrollMargin = {\n left: Number.parseInt(styles.scrollMarginLeft || '0', 10),\n top: Number.parseInt(styles.scrollMarginTop || '0', 10),\n };\n\n // Set the scroll position of the target element.\n left = sizes.left + initialScrollPosition.left - scrollMargin.left;\n top = sizes.top + initialScrollPosition.top - scrollMargin.top;\n } else if (isNumber(target)) {\n left = target;\n top = target;\n } else {\n left = target.left ?? left;\n top = target.top ?? top;\n }\n\n left -= offset;\n top -= offset;\n\n if (axis !== bothAxis) {\n if (axis !== xAxis && !isDefined((target as Partial<ScrollPosition>).left)) {\n left = initialScrollPosition.left;\n }\n\n if (axis !== yAxis) {\n top = initialScrollPosition.top;\n }\n }\n\n return {\n left: Math.min(left, maxScrollPosition.left),\n top: Math.min(top, maxScrollPosition.top),\n };\n}\n\n/**\n * Scroll to an element.\n *\n * @returns {Promise<ScrollPosition>} A promising resolving with the scroll position.\n */\nexport function scrollTo(\n target: string | HTMLElement | number | Partial<ScrollPosition>,\n { rootElement = window, axis = yAxis, offset = 0, ...tweenOptions }: ScrollToOptions = {},\n): Promise<ScrollPosition> {\n const initialScrollPosition = getCurrentScrollPosition(rootElement);\n const maxScrollPosition = getMaxScrollPosition(rootElement);\n const targetScrollPosition = getTargetScrollPosition(\n initialScrollPosition,\n maxScrollPosition,\n target,\n axis,\n offset,\n );\n\n return new Promise((resolve) => {\n function eventHandler() {\n /* eslint-disable @typescript-eslint/no-use-before-define */\n tw.pause();\n stop();\n /* eslint-enable @typescript-eslint/no-use-before-define */\n }\n\n function stop() {\n rootElement.removeEventListener('wheel', eventHandler);\n rootElement.removeEventListener('touchmove', eventHandler);\n\n // Resolve the promise on animation finish.\n resolve(getCurrentScrollPosition(rootElement));\n }\n\n // Setup tween.\n const tw = tween(\n (progress) => {\n rootElement.scrollTo({\n left: lerp(initialScrollPosition.left, targetScrollPosition.left, progress),\n top: lerp(initialScrollPosition.top, targetScrollPosition.top, progress),\n behavior: 'instant',\n });\n },\n {\n smooth: 0.2,\n ...tweenOptions,\n onFinish(progress) {\n if (isFunction(tweenOptions.onFinish)) {\n tweenOptions.onFinish(progress);\n }\n\n stop();\n },\n },\n );\n\n rootElement.addEventListener('wheel', eventHandler, { passive: true });\n rootElement.addEventListener('touchmove', eventHandler, { passive: true });\n tw.start();\n });\n}\n\nscrollTo.axis = {\n x: xAxis,\n y: yAxis,\n both: bothAxis,\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/utils/tween.d.ts CHANGED
@@ -45,9 +45,18 @@ export interface TweenOptions {
45
45
  * The smooth factor. Setting this option to `true` or a `number` will disable the `duration` option.
46
46
  */
47
47
  smooth?: true | number;
48
+ /**
49
+ * Enable spring transition. Setting this option to `true` or a `number` will disable the `duration` option.
50
+ * If `true`, a default stiffness of 0.1 will be used, if a `number` is given, it will be used instead.
51
+ */
52
+ spring?: true | number;
53
+ /**
54
+ * When spring physics are enabled, use the mass option to make the object heavier or lighter. Defaults to `1`.
55
+ */
56
+ mass?: number;
48
57
  /**
49
58
  * The precision for when to consider the tween finished.
50
- * Defaults to `0.0001`.
59
+ * Defaults to `0.00001`.
51
60
  */
52
61
  precision?: number;
53
62
  /**
@@ -69,5 +78,6 @@ export interface TweenOptions {
69
78
  export declare function normalizeEase(ease: EasingFunction | BezierCurve): EasingFunction;
70
79
  /**
71
80
  * Tween from 0 to 1.
81
+ * @see https://js-toolkit.studiometa.dev/utils/tween.html
72
82
  */
73
83
  export declare function tween(callback: (progress: number) => unknown, options?: TweenOptions): Tween;
package/utils/tween.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { cubicBezier } from "@motionone/easing";
2
- import { lerp, map, clamp01, damp, inertiaFinalValue } from "./math/index.js";
2
+ import { lerp, map, clamp01, damp, inertiaFinalValue, spring } from "./math/index.js";
3
3
  import { isDefined, isArray, isNumber } from "./is.js";
4
4
  import { noop, noopValue as linear } from "./noop.js";
5
5
  import { useRaf } from "../services/RafService.js";
6
6
  let id = 0;
7
- const DEFAULT_PROGRESS_PRECISION = 1e-4;
7
+ const DEFAULT_PROGRESS_PRECISION = 1 / 1e4;
8
8
  function normalizeEase(ease) {
9
9
  if (!isDefined(ease)) {
10
10
  return linear;
@@ -18,8 +18,12 @@ function tween(callback, options = {}) {
18
18
  const raf = useRaf();
19
19
  let progressValue = 0;
20
20
  let easedProgress = 0;
21
+ let velocity = 0;
21
22
  const isSmooth = isDefined(options.smooth) && (isNumber(options.smooth) || options.smooth);
22
- const smoothFactor = isNumber(options.smooth) ? options.smooth : 0.1;
23
+ const isSpring = isDefined(options.spring) && (isNumber(options.spring) || options.spring);
24
+ const stiffness = isNumber(options.spring) ? options.spring : 0.1;
25
+ const mass = isNumber(options.mass) ? options.mass : 1;
26
+ const damping = isNumber(options.smooth) ? options.smooth : 0.1;
23
27
  const precision = options.precision ?? DEFAULT_PROGRESS_PRECISION;
24
28
  const ease = normalizeEase(options.easing);
25
29
  let delay = options.delay ?? 0;
@@ -40,15 +44,29 @@ function tween(callback, options = {}) {
40
44
  if (!isDefined(newProgress)) {
41
45
  return easedProgress;
42
46
  }
47
+ let shouldStop = false;
43
48
  progressValue = newProgress;
44
- easedProgress = isSmooth ? damp(progressValue, easedProgress, smoothFactor, precision) : ease(progressValue);
49
+ if (isSpring) {
50
+ [easedProgress, velocity] = spring(
51
+ progressValue,
52
+ easedProgress,
53
+ velocity,
54
+ stiffness,
55
+ damping,
56
+ mass,
57
+ precision
58
+ );
59
+ } else {
60
+ easedProgress = isSmooth ? damp(progressValue, easedProgress, damping, precision) : ease(progressValue);
61
+ }
45
62
  if (Math.abs(1 - easedProgress) < precision) {
46
63
  progressValue = 1;
47
64
  easedProgress = 1;
65
+ shouldStop = true;
48
66
  }
49
67
  callback(easedProgress);
50
68
  onProgress(easedProgress);
51
- if (easedProgress === 1) {
69
+ if (shouldStop) {
52
70
  pause();
53
71
  requestAnimationFrame(() => onFinish(easedProgress));
54
72
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/js-toolkit/utils/tween.ts"],
4
- "sourcesContent": ["import { cubicBezier } from '@motionone/easing';\nimport { lerp, map, clamp01, damp, inertiaFinalValue } from './math/index.js';\nimport { isDefined, isArray, isNumber } from './is.js';\nimport { noop, noopValue as linear } from './noop.js';\nimport { useRaf } from '../services/RafService.js';\nimport type { EasingFunction } from './math/createEases.js';\n\nlet id = 0;\nconst DEFAULT_PROGRESS_PRECISION = 0.0001;\n\nexport type BezierCurve = [number, number, number, number];\n\n/**\n * Controls for a tween.\n */\nexport interface Tween {\n /**\n * Start the tween from the beginning.\n */\n start: () => void;\n /**\n * Finish the tween and set its state to the end.\n */\n finish: () => void;\n /**\n * Pause the tween.\n */\n pause: () => void;\n /**\n * Start the tween from the current paused progress.\n */\n play: () => void;\n /**\n * Set and get the tween's progress.\n */\n progress: (progress?: number) => number;\n}\n\nexport interface TweenOptions {\n /**\n * The duration, in seconds.\n * Defaults to `1`.\n */\n duration?: number;\n /**\n * The delay, in seconds.\n * Defaults to `0`.\n */\n delay?: number;\n /**\n * The easing function or bezier curve to use.\n * Defaults to a linear easing function.\n */\n easing?: EasingFunction | BezierCurve;\n /**\n * The smooth factor. Setting this option to `true` or a `number` will disable the `duration` option.\n */\n smooth?: true | number;\n /**\n * The precision for when to consider the tween finished.\n * Defaults to `0.0001`.\n */\n precision?: number;\n /**\n * A callback executed on start.\n */\n onStart?: (progress: number) => void;\n /**\n * A callback executed each time the progress is updated.\n */\n onProgress?: (progress: number) => void;\n /**\n * A callback executed when the tween is finished.\n */\n onFinish?: (progress: number) => void;\n}\n\n/**\n * Normalize a easing function with default fallbacks.\n */\nexport function normalizeEase(ease: EasingFunction | BezierCurve): EasingFunction {\n if (!isDefined(ease)) {\n return linear;\n }\n\n if (isArray(ease)) {\n return cubicBezier(...ease);\n }\n\n return ease;\n}\n\n/**\n * Tween from 0 to 1.\n */\nexport function tween(callback: (progress: number) => unknown, options: TweenOptions = {}): Tween {\n const raf = useRaf();\n\n let progressValue = 0;\n let easedProgress = 0;\n\n const isSmooth = isDefined(options.smooth) && (isNumber(options.smooth) || options.smooth);\n const smoothFactor = isNumber(options.smooth) ? options.smooth : 0.1;\n const precision = options.precision ?? DEFAULT_PROGRESS_PRECISION;\n const ease = normalizeEase(options.easing);\n\n let delay = options.delay ?? 0;\n delay *= 1000;\n let duration = options.duration ?? 1;\n duration *= 1000;\n\n /* eslint-disable @typescript-eslint/no-use-before-define */\n let startTime = getStartTime();\n let endTime = getEndTime(startTime);\n /* eslint-enable @typescript-eslint/no-use-before-define */\n\n const key = `tw-${id}`;\n id += 1;\n\n const { onStart = noop, onProgress = noop, onFinish = noop } = options;\n let isRunning = false;\n\n /**\n * Pause the animation.\n */\n function pause() {\n isRunning = false;\n raf.remove(key);\n }\n\n /**\n * Set the progress value.\n */\n function progress(newProgress: number) {\n if (!isDefined(newProgress)) {\n return easedProgress;\n }\n\n progressValue = newProgress;\n easedProgress = isSmooth\n ? damp(progressValue, easedProgress, smoothFactor, precision)\n : ease(progressValue);\n\n // Stop when reaching precision\n if (Math.abs(1 - easedProgress) < precision) {\n progressValue = 1;\n easedProgress = 1;\n }\n\n callback(easedProgress);\n onProgress(easedProgress);\n\n if (easedProgress === 1) {\n pause();\n requestAnimationFrame(() => onFinish(easedProgress));\n }\n\n return easedProgress;\n }\n\n /**\n * Loop for rendering the animation.\n */\n function tick(props: { time: number }) {\n progress(clamp01(map(props.time, startTime, endTime, 0, 1)));\n }\n\n function getStartTime() {\n return performance.now() + delay;\n }\n\n function getEndTime(time: number) {\n return isSmooth ? inertiaFinalValue(time, 1) : time + duration;\n }\n\n /**\n * Play the animation.\n */\n function start() {\n onStart(0);\n startTime = getStartTime();\n endTime = getEndTime(startTime);\n progressValue = 0;\n easedProgress = 0;\n isRunning = true;\n\n raf.add(key, tick);\n }\n\n /**\n * Play a paused animation.\n */\n function play() {\n if (isRunning) {\n return;\n }\n\n startTime = getStartTime() - lerp(0, duration, progressValue);\n endTime = getEndTime(startTime);\n isRunning = true;\n\n raf.add(key, tick);\n }\n\n return {\n start,\n finish: () => progress(1),\n pause,\n play,\n progress,\n };\n}\n"],
5
- "mappings": "AAAA,SAAS,mBAAmB;AAC5B,SAAS,MAAM,KAAK,SAAS,MAAM,yBAAyB;AAC5D,SAAS,WAAW,SAAS,gBAAgB;AAC7C,SAAS,MAAM,aAAa,cAAc;AAC1C,SAAS,cAAc;AAGvB,IAAI,KAAK;AACT,MAAM,6BAA6B;AAwE5B,SAAS,cAAc,MAAoD;AAChF,MAAI,CAAC,UAAU,IAAI,GAAG;AACpB,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,IAAI,GAAG;AACjB,WAAO,YAAY,GAAG,IAAI;AAAA,EAC5B;AAEA,SAAO;AACT;AAKO,SAAS,MAAM,UAAyC,UAAwB,CAAC,GAAU;AAChG,QAAM,MAAM,OAAO;AAEnB,MAAI,gBAAgB;AACpB,MAAI,gBAAgB;AAEpB,QAAM,WAAW,UAAU,QAAQ,MAAM,MAAM,SAAS,QAAQ,MAAM,KAAK,QAAQ;AACnF,QAAM,eAAe,SAAS,QAAQ,MAAM,IAAI,QAAQ,SAAS;AACjE,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,OAAO,cAAc,QAAQ,MAAM;AAEzC,MAAI,QAAQ,QAAQ,SAAS;AAC7B,WAAS;AACT,MAAI,WAAW,QAAQ,YAAY;AACnC,cAAY;AAGZ,MAAI,YAAY,aAAa;AAC7B,MAAI,UAAU,WAAW,SAAS;AAGlC,QAAM,MAAM,MAAM,EAAE;AACpB,QAAM;AAEN,QAAM,EAAE,UAAU,MAAM,aAAa,MAAM,WAAW,KAAK,IAAI;AAC/D,MAAI,YAAY;AAKhB,WAAS,QAAQ;AACf,gBAAY;AACZ,QAAI,OAAO,GAAG;AAAA,EAChB;AAKA,WAAS,SAAS,aAAqB;AACrC,QAAI,CAAC,UAAU,WAAW,GAAG;AAC3B,aAAO;AAAA,IACT;AAEA,oBAAgB;AAChB,oBAAgB,WACZ,KAAK,eAAe,eAAe,cAAc,SAAS,IAC1D,KAAK,aAAa;AAGtB,QAAI,KAAK,IAAI,IAAI,aAAa,IAAI,WAAW;AAC3C,sBAAgB;AAChB,sBAAgB;AAAA,IAClB;AAEA,aAAS,aAAa;AACtB,eAAW,aAAa;AAExB,QAAI,kBAAkB,GAAG;AACvB,YAAM;AACN,4BAAsB,MAAM,SAAS,aAAa,CAAC;AAAA,IACrD;AAEA,WAAO;AAAA,EACT;AAKA,WAAS,KAAK,OAAyB;AACrC,aAAS,QAAQ,IAAI,MAAM,MAAM,WAAW,SAAS,GAAG,CAAC,CAAC,CAAC;AAAA,EAC7D;AAEA,WAAS,eAAe;AACtB,WAAO,YAAY,IAAI,IAAI;AAAA,EAC7B;AAEA,WAAS,WAAW,MAAc;AAChC,WAAO,WAAW,kBAAkB,MAAM,CAAC,IAAI,OAAO;AAAA,EACxD;AAKA,WAAS,QAAQ;AACf,YAAQ,CAAC;AACT,gBAAY,aAAa;AACzB,cAAU,WAAW,SAAS;AAC9B,oBAAgB;AAChB,oBAAgB;AAChB,gBAAY;AAEZ,QAAI,IAAI,KAAK,IAAI;AAAA,EACnB;AAKA,WAAS,OAAO;AACd,QAAI,WAAW;AACb;AAAA,IACF;AAEA,gBAAY,aAAa,IAAI,KAAK,GAAG,UAAU,aAAa;AAC5D,cAAU,WAAW,SAAS;AAC9B,gBAAY;AAEZ,QAAI,IAAI,KAAK,IAAI;AAAA,EACnB;AAEA,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,MAAM,SAAS,CAAC;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { cubicBezier } from '@motionone/easing';\nimport { lerp, map, clamp01, damp, inertiaFinalValue, spring } from './math/index.js';\nimport { isDefined, isArray, isNumber } from './is.js';\nimport { noop, noopValue as linear } from './noop.js';\nimport { useRaf } from '../services/RafService.js';\nimport type { EasingFunction } from './math/createEases.js';\n\nlet id = 0;\nconst DEFAULT_PROGRESS_PRECISION = 1 / 1e4;\n\nexport type BezierCurve = [number, number, number, number];\n\n/**\n * Controls for a tween.\n */\nexport interface Tween {\n /**\n * Start the tween from the beginning.\n */\n start: () => void;\n /**\n * Finish the tween and set its state to the end.\n */\n finish: () => void;\n /**\n * Pause the tween.\n */\n pause: () => void;\n /**\n * Start the tween from the current paused progress.\n */\n play: () => void;\n /**\n * Set and get the tween's progress.\n */\n progress: (progress?: number) => number;\n}\n\nexport interface TweenOptions {\n /**\n * The duration, in seconds.\n * Defaults to `1`.\n */\n duration?: number;\n /**\n * The delay, in seconds.\n * Defaults to `0`.\n */\n delay?: number;\n /**\n * The easing function or bezier curve to use.\n * Defaults to a linear easing function.\n */\n easing?: EasingFunction | BezierCurve;\n /**\n * The smooth factor. Setting this option to `true` or a `number` will disable the `duration` option.\n */\n smooth?: true | number;\n /**\n * Enable spring transition. Setting this option to `true` or a `number` will disable the `duration` option.\n * If `true`, a default stiffness of 0.1 will be used, if a `number` is given, it will be used instead.\n */\n spring?: true | number;\n /**\n * When spring physics are enabled, use the mass option to make the object heavier or lighter. Defaults to `1`.\n */\n mass?: number;\n /**\n * The precision for when to consider the tween finished.\n * Defaults to `0.00001`.\n */\n precision?: number;\n /**\n * A callback executed on start.\n */\n onStart?: (progress: number) => void;\n /**\n * A callback executed each time the progress is updated.\n */\n onProgress?: (progress: number) => void;\n /**\n * A callback executed when the tween is finished.\n */\n onFinish?: (progress: number) => void;\n}\n\n/**\n * Normalize a easing function with default fallbacks.\n */\nexport function normalizeEase(ease: EasingFunction | BezierCurve): EasingFunction {\n if (!isDefined(ease)) {\n return linear;\n }\n\n if (isArray(ease)) {\n return cubicBezier(...ease);\n }\n\n return ease;\n}\n\n/**\n * Tween from 0 to 1.\n * @see https://js-toolkit.studiometa.dev/utils/tween.html\n */\nexport function tween(callback: (progress: number) => unknown, options: TweenOptions = {}): Tween {\n const raf = useRaf();\n\n let progressValue = 0;\n let easedProgress = 0;\n let velocity = 0;\n\n const isSmooth = isDefined(options.smooth) && (isNumber(options.smooth) || options.smooth);\n const isSpring = isDefined(options.spring) && (isNumber(options.spring) || options.spring);\n const stiffness = isNumber(options.spring) ? options.spring : 0.1;\n const mass = isNumber(options.mass) ? options.mass : 1;\n const damping = isNumber(options.smooth) ? options.smooth : 0.1;\n const precision = options.precision ?? DEFAULT_PROGRESS_PRECISION;\n const ease = normalizeEase(options.easing);\n\n let delay = options.delay ?? 0;\n delay *= 1000;\n let duration = options.duration ?? 1;\n duration *= 1000;\n\n /* eslint-disable @typescript-eslint/no-use-before-define */\n let startTime = getStartTime();\n let endTime = getEndTime(startTime);\n /* eslint-enable @typescript-eslint/no-use-before-define */\n\n const key = `tw-${id}`;\n id += 1;\n\n const { onStart = noop, onProgress = noop, onFinish = noop } = options;\n let isRunning = false;\n\n /**\n * Pause the animation.\n */\n function pause() {\n isRunning = false;\n raf.remove(key);\n }\n\n /**\n * Set the progress value.\n */\n function progress(newProgress: number) {\n if (!isDefined(newProgress)) {\n return easedProgress;\n }\n\n let shouldStop = false;\n\n progressValue = newProgress;\n if (isSpring) {\n [easedProgress, velocity] = spring(\n progressValue,\n easedProgress,\n velocity,\n stiffness,\n damping,\n mass,\n precision,\n );\n } else {\n easedProgress = isSmooth\n ? damp(progressValue, easedProgress, damping, precision)\n : ease(progressValue);\n }\n\n // Stop when reaching precision\n if (Math.abs(1 - easedProgress) < precision) {\n progressValue = 1;\n easedProgress = 1;\n shouldStop = true;\n }\n\n callback(easedProgress);\n onProgress(easedProgress);\n\n if (shouldStop) {\n pause();\n requestAnimationFrame(() => onFinish(easedProgress));\n }\n\n return easedProgress;\n }\n\n /**\n * Loop for rendering the animation.\n */\n function tick(props: { time: number }) {\n progress(clamp01(map(props.time, startTime, endTime, 0, 1)));\n }\n\n function getStartTime() {\n return performance.now() + delay;\n }\n\n function getEndTime(time: number) {\n return isSmooth ? inertiaFinalValue(time, 1) : time + duration;\n }\n\n /**\n * Play the animation.\n */\n function start() {\n onStart(0);\n startTime = getStartTime();\n endTime = getEndTime(startTime);\n progressValue = 0;\n easedProgress = 0;\n isRunning = true;\n\n raf.add(key, tick);\n }\n\n /**\n * Play a paused animation.\n */\n function play() {\n if (isRunning) {\n return;\n }\n\n startTime = getStartTime() - lerp(0, duration, progressValue);\n endTime = getEndTime(startTime);\n isRunning = true;\n\n raf.add(key, tick);\n }\n\n return {\n start,\n finish: () => progress(1),\n pause,\n play,\n progress,\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }