@studiometa/js-toolkit 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Base/index.cjs CHANGED
@@ -172,12 +172,12 @@ var Base = class extends EventTarget {
172
172
  }
173
173
  this.$emit(method, ...args);
174
174
  if (typeof this[method] !== "function") {
175
- return;
175
+ return null;
176
176
  }
177
- this[method].call(this, ...args);
178
177
  if (isDev) {
179
178
  this.__debug(method, this, ...args);
180
179
  }
180
+ return this[method].call(this, ...args);
181
181
  }
182
182
  __hasEvent(event) {
183
183
  const eventHandlers = this.__eventHandlers.get(event);
package/Base/index.d.ts CHANGED
@@ -160,7 +160,7 @@ export default class Base extends EventTarget {
160
160
  * @private
161
161
  * @param {string} method
162
162
  * @param {any[]} args
163
- * @returns {void}
163
+ * @returns {any}
164
164
  */
165
165
  private __callMethod;
166
166
  /**
package/Base/index.js CHANGED
@@ -146,12 +146,12 @@ class Base extends EventTarget {
146
146
  }
147
147
  this.$emit(method, ...args);
148
148
  if (typeof this[method] !== "function") {
149
- return;
149
+ return null;
150
150
  }
151
- this[method].call(this, ...args);
152
151
  if (isDev) {
153
152
  this.__debug(method, this, ...args);
154
153
  }
154
+ return this[method].call(this, ...args);
155
155
  }
156
156
  __hasEvent(event) {
157
157
  const eventHandlers = this.__eventHandlers.get(event);
@@ -35,21 +35,34 @@ module.exports = __toCommonJS(EventsManager_exports);
35
35
  var import_getAllProperties = __toESM(require("../../utils/object/getAllProperties.cjs"), 1);
36
36
  var import_AbstractManager = __toESM(require("./AbstractManager.cjs"), 1);
37
37
  var import_RefsManager = require("./RefsManager.cjs");
38
+ var names = /* @__PURE__ */ new Map();
38
39
  function normalizeName(name) {
39
- return name.replace(/[A-Z]([A-Z].*)/g, (c) => c.toLowerCase()).replace(/[^a-zA-Z\d\s:]/g, " ").replace(/(^\w|\s+\w)/g, (c) => c.trim().toUpperCase()).trim();
40
+ if (!names.has(name)) {
41
+ names.set(name, name.replace(/[A-Z]([A-Z].*)/g, (c) => c.toLowerCase()).replace(/[^a-zA-Z\d\s:]/g, " ").replace(/(^\w|\s+\w)/g, (c) => c.trim().toUpperCase()).trim());
42
+ }
43
+ return names.get(name);
40
44
  }
45
+ var eventNames = /* @__PURE__ */ new Map();
41
46
  function normalizeEventName(name) {
42
- return name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`).replace(/^-/, "");
47
+ if (!eventNames.has(name)) {
48
+ eventNames.set(name, name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`).replace(/^-/, ""));
49
+ }
50
+ return eventNames.get(name);
51
+ }
52
+ var regexes = /* @__PURE__ */ new Map();
53
+ function getRegex(regex) {
54
+ if (!regexes.has(regex)) {
55
+ regexes.set(regex, new RegExp(regex));
56
+ }
57
+ return regexes.get(regex);
43
58
  }
44
59
  function __getEventNameByMethod(that, method, name = "") {
45
- const normalizedName = normalizeName(name);
46
- const regex = new RegExp(`^on${normalizedName}([A-Z].*)$`);
60
+ const regex = getRegex(`^on${normalizeName(name)}([A-Z].*)$`);
47
61
  const [, event] = method.match(regex);
48
62
  return normalizeEventName(event);
49
63
  }
50
64
  function __getEventMethodsByName(that, name = "") {
51
- const normalizedName = normalizeName(name);
52
- const regex = new RegExp(`^on${normalizedName}[A-Z].*$`);
65
+ const regex = getRegex(`^on${normalizeName(name)}[A-Z].*$`);
53
66
  const key = regex.toString();
54
67
  let methods = that.__methodsCache.get(key);
55
68
  if (!methods) {
@@ -1,7 +1,3 @@
1
- /**
2
- * @typedef {import('../index.js').default} Base
3
- * @typedef {import('./ChildrenManager.js').default} ChildrenManager
4
- */
5
1
  /**
6
2
  * Normalize the given name to PascalCase, such as:
7
3
  *
@@ -7,21 +7,34 @@ var __publicField = (obj, key, value) => {
7
7
  import getAllProperties from "../../utils/object/getAllProperties.js";
8
8
  import AbstractManager from "./AbstractManager.js";
9
9
  import { normalizeRefName } from "./RefsManager.js";
10
+ const names = /* @__PURE__ */ new Map();
10
11
  function normalizeName(name) {
11
- return name.replace(/[A-Z]([A-Z].*)/g, (c) => c.toLowerCase()).replace(/[^a-zA-Z\d\s:]/g, " ").replace(/(^\w|\s+\w)/g, (c) => c.trim().toUpperCase()).trim();
12
+ if (!names.has(name)) {
13
+ names.set(name, name.replace(/[A-Z]([A-Z].*)/g, (c) => c.toLowerCase()).replace(/[^a-zA-Z\d\s:]/g, " ").replace(/(^\w|\s+\w)/g, (c) => c.trim().toUpperCase()).trim());
14
+ }
15
+ return names.get(name);
12
16
  }
17
+ const eventNames = /* @__PURE__ */ new Map();
13
18
  function normalizeEventName(name) {
14
- return name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`).replace(/^-/, "");
19
+ if (!eventNames.has(name)) {
20
+ eventNames.set(name, name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`).replace(/^-/, ""));
21
+ }
22
+ return eventNames.get(name);
23
+ }
24
+ const regexes = /* @__PURE__ */ new Map();
25
+ function getRegex(regex) {
26
+ if (!regexes.has(regex)) {
27
+ regexes.set(regex, new RegExp(regex));
28
+ }
29
+ return regexes.get(regex);
15
30
  }
16
31
  function __getEventNameByMethod(that, method, name = "") {
17
- const normalizedName = normalizeName(name);
18
- const regex = new RegExp(`^on${normalizedName}([A-Z].*)$`);
32
+ const regex = getRegex(`^on${normalizeName(name)}([A-Z].*)$`);
19
33
  const [, event] = method.match(regex);
20
34
  return normalizeEventName(event);
21
35
  }
22
36
  function __getEventMethodsByName(that, name = "") {
23
- const normalizedName = normalizeName(name);
24
- const regex = new RegExp(`^on${normalizedName}[A-Z].*$`);
37
+ const regex = getRegex(`^on${normalizeName(name)}[A-Z].*$`);
25
38
  const key = regex.toString();
26
39
  let methods = that.__methodsCache.get(key);
27
40
  if (!methods) {
@@ -76,12 +76,12 @@ function __register(that, name, config) {
76
76
  }
77
77
  var OptionsManager = class extends import_AbstractManager.default {
78
78
  constructor(base) {
79
+ var _a, _b;
79
80
  super(base);
80
81
  __publicField(this, "__values", {});
81
82
  __publicField(this, "name", "Base");
82
83
  __publicField(this, "debug", false);
83
84
  __publicField(this, "log", false);
84
- var _a, _b;
85
85
  this.__hideProperties(["__values", "__defaultValues"]);
86
86
  const schema = this.__config.options || {};
87
87
  this.name = this.__config.name;
@@ -49,12 +49,12 @@ function __register(that, name, config) {
49
49
  }
50
50
  class OptionsManager extends AbstractManager {
51
51
  constructor(base) {
52
+ var _a, _b;
52
53
  super(base);
53
54
  __publicField(this, "__values", {});
54
55
  __publicField(this, "name", "Base");
55
56
  __publicField(this, "debug", false);
56
57
  __publicField(this, "log", false);
57
- var _a, _b;
58
58
  this.__hideProperties(["__values", "__defaultValues"]);
59
59
  const schema = this.__config.options || {};
60
60
  this.name = this.__config.name;
@@ -79,7 +79,7 @@ var ServicesManager = class extends import_AbstractManager.default {
79
79
  const { add } = this.__services[service]();
80
80
  const self = this;
81
81
  function serviceHandler(...args) {
82
- self.__base.__callMethod(service, ...args);
82
+ return self.__base.__callMethod(service, ...args);
83
83
  }
84
84
  add(this.__base.$id, serviceHandler);
85
85
  return this.disable.bind(this, service);
@@ -53,7 +53,7 @@ class ServicesManager extends AbstractManager {
53
53
  const { add } = this.__services[service]();
54
54
  const self = this;
55
55
  function serviceHandler(...args) {
56
- self.__base.__callMethod(service, ...args);
56
+ return self.__base.__callMethod(service, ...args);
57
57
  }
58
58
  add(this.__base.$id, serviceHandler);
59
59
  return this.disable.bind(this, service);
@@ -32,6 +32,7 @@ __export(withScrolledInView_exports, {
32
32
  module.exports = __toCommonJS(withScrolledInView_exports);
33
33
  var import_withMountWhenInView = __toESM(require("./withMountWhenInView.cjs"), 1);
34
34
  var import_utils = require("../utils/index.cjs");
35
+ var scheduler = (0, import_utils.useScheduler)(["update", "render"]);
35
36
  function withScrolledInView(BaseClass, options = {}) {
36
37
  var _a;
37
38
  return _a = class extends (0, import_withMountWhenInView.default)(BaseClass, options) {
@@ -83,7 +84,14 @@ function withScrolledInView(BaseClass, options = {}) {
83
84
  if (this.__props.dampedProgress.x === this.__props.progress.x && this.__props.dampedProgress.y === this.__props.progress.y) {
84
85
  this.$services.disable("ticked");
85
86
  }
86
- this.__callMethod("scrolledInView", this.__props);
87
+ scheduler.update(() => {
88
+ const renderFn = this.__callMethod("scrolledInView", this.__props);
89
+ if ((0, import_utils.isFunction)(renderFn)) {
90
+ scheduler.render(() => {
91
+ renderFn(this.__props);
92
+ });
93
+ }
94
+ });
87
95
  }
88
96
  };
89
97
  this.$on("before-mounted", () => {
@@ -5,7 +5,8 @@ var __publicField = (obj, key, value) => {
5
5
  return value;
6
6
  };
7
7
  import withMountWhenInView from "./withMountWhenInView.js";
8
- import { damp, clamp, clamp01, getOffsetSizes, isFunction } from "../utils/index.js";
8
+ import { damp, clamp, clamp01, getOffsetSizes, isFunction, useScheduler } from "../utils/index.js";
9
+ const scheduler = useScheduler(["update", "render"]);
9
10
  function withScrolledInView(BaseClass, options = {}) {
10
11
  var _a;
11
12
  return _a = class extends withMountWhenInView(BaseClass, options) {
@@ -57,7 +58,14 @@ function withScrolledInView(BaseClass, options = {}) {
57
58
  if (this.__props.dampedProgress.x === this.__props.progress.x && this.__props.dampedProgress.y === this.__props.progress.y) {
58
59
  this.$services.disable("ticked");
59
60
  }
60
- this.__callMethod("scrolledInView", this.__props);
61
+ scheduler.update(() => {
62
+ const renderFn = this.__callMethod("scrolledInView", this.__props);
63
+ if (isFunction(renderFn)) {
64
+ scheduler.render(() => {
65
+ renderFn(this.__props);
66
+ });
67
+ }
68
+ });
61
69
  }
62
70
  };
63
71
  this.$on("before-mounted", () => {
@@ -31,9 +31,9 @@ var withVue2_default = (BaseClass, Vue) => {
31
31
  var _a, _b, _c;
32
32
  return _c = class extends BaseClass {
33
33
  constructor(element) {
34
+ var _a2;
34
35
  super(element);
35
36
  __publicField(this, "$vue");
36
- var _a2;
37
37
  const vueConfig = (_a2 = this.vueConfig) != null ? _a2 : this.constructor.vueConfig;
38
38
  if (!vueConfig) {
39
39
  throw new Error("[withVue] You must define a `vueConfig` object.");
@@ -8,9 +8,9 @@ var withVue2_default = (BaseClass, Vue) => {
8
8
  var _a, _b, _c;
9
9
  return _c = class extends BaseClass {
10
10
  constructor(element) {
11
+ var _a2;
11
12
  super(element);
12
13
  __publicField(this, "$vue");
13
- var _a2;
14
14
  const vueConfig = (_a2 = this.vueConfig) != null ? _a2 : this.constructor.vueConfig;
15
15
  if (!vueConfig) {
16
16
  throw new Error("[withVue] You must define a `vueConfig` object.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studiometa/js-toolkit",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "A set of useful little bits of JavaScript to boost your project! 🚀",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -39,7 +39,7 @@
39
39
  "toolkit"
40
40
  ],
41
41
  "dependencies": {
42
- "@motionone/easing": "^10.8.0",
42
+ "@motionone/easing": "^10.9.0",
43
43
  "deepmerge": "^4.2.2"
44
44
  }
45
45
  }
@@ -29,9 +29,9 @@ __export(Service_exports, {
29
29
  module.exports = __toCommonJS(Service_exports);
30
30
  var Service = class {
31
31
  constructor() {
32
+ __publicField(this, "callbacks", /* @__PURE__ */ new Map());
33
+ __publicField(this, "isInit", false);
32
34
  __publicField(this, "props");
33
- this.callbacks = /* @__PURE__ */ new Map();
34
- this.isInit = false;
35
35
  }
36
36
  updateProps(...args) {
37
37
  this.props = args;
@@ -2,7 +2,15 @@
2
2
  * Service abstract class
3
3
  */
4
4
  export default class Service {
5
- callbacks: Map<any, any>;
5
+ /**
6
+ * Map containing the callbacks.
7
+ * @type {Map<string, Function>}
8
+ */
9
+ callbacks: Map<string, Function>;
10
+ /**
11
+ * State flag.
12
+ * @type {boolean}
13
+ */
6
14
  isInit: boolean;
7
15
  /**
8
16
  * @type {unknown}
@@ -6,9 +6,9 @@ var __publicField = (obj, key, value) => {
6
6
  };
7
7
  class Service {
8
8
  constructor() {
9
+ __publicField(this, "callbacks", /* @__PURE__ */ new Map());
10
+ __publicField(this, "isInit", false);
9
11
  __publicField(this, "props");
10
- this.callbacks = /* @__PURE__ */ new Map();
11
- this.isInit = false;
12
12
  }
13
13
  updateProps(...args) {
14
14
  this.props = args;
package/services/raf.cjs CHANGED
@@ -32,6 +32,9 @@ __export(raf_exports, {
32
32
  module.exports = __toCommonJS(raf_exports);
33
33
  var import_Service = __toESM(require("./Service.cjs"), 1);
34
34
  var import_nextFrame = require("../utils/nextFrame.cjs");
35
+ var import_scheduler = require("../utils/scheduler.cjs");
36
+ var import_isFunction = __toESM(require("../utils/isFunction.cjs"), 1);
37
+ var scheduler = (0, import_scheduler.useScheduler)(["update", "render"]);
35
38
  var Raf = class extends import_Service.default {
36
39
  constructor() {
37
40
  super(...arguments);
@@ -63,6 +66,19 @@ var Raf = class extends import_Service.default {
63
66
  this.props.time = window.performance.now();
64
67
  return this.props;
65
68
  }
69
+ trigger(...args) {
70
+ this.callbacks.forEach(function forEachCallback(callback) {
71
+ scheduler.update(function rafUpdate() {
72
+ const render = callback(...args);
73
+ if ((0, import_isFunction.default)(render)) {
74
+ scheduler.render(function rafRender() {
75
+ render(...args);
76
+ });
77
+ }
78
+ });
79
+ });
80
+ return this;
81
+ }
66
82
  };
67
83
  var instance;
68
84
  var raf;
package/services/raf.js CHANGED
@@ -6,6 +6,9 @@ var __publicField = (obj, key, value) => {
6
6
  };
7
7
  import Service from "./Service.js";
8
8
  import { getRaf, getCancelRaf } from "../utils/nextFrame.js";
9
+ import { useScheduler } from "../utils/scheduler.js";
10
+ import isFunction from "../utils/isFunction.js";
11
+ const scheduler = useScheduler(["update", "render"]);
9
12
  class Raf extends Service {
10
13
  constructor() {
11
14
  super(...arguments);
@@ -37,6 +40,19 @@ class Raf extends Service {
37
40
  this.props.time = window.performance.now();
38
41
  return this.props;
39
42
  }
43
+ trigger(...args) {
44
+ this.callbacks.forEach(function forEachCallback(callback) {
45
+ scheduler.update(function rafUpdate() {
46
+ const render = callback(...args);
47
+ if (isFunction(render)) {
48
+ scheduler.render(function rafRender() {
49
+ render(...args);
50
+ });
51
+ }
52
+ });
53
+ });
54
+ return this;
55
+ }
40
56
  }
41
57
  let instance;
42
58
  let raf;
@@ -29,26 +29,29 @@ var import_easing = require("@motionone/easing");
29
29
  var import_math = require("../math/index.cjs");
30
30
  var import_isDefined = __toESM(require("../isDefined.cjs"), 1);
31
31
  var import_transform = __toESM(require("./transform.cjs"), 1);
32
+ var import_raf = __toESM(require("../../services/raf.cjs"), 1);
33
+ var import_scheduler = require("../scheduler.cjs");
32
34
  var id = 0;
33
35
  var running = /* @__PURE__ */ new WeakMap();
36
+ var raf = (0, import_raf.default)();
34
37
  var noop = () => {
35
38
  };
36
39
  var PROGRESS_PRECISION = 1e-4;
37
40
  var CSSUnitConverter = {
38
- "%": (value, sizeRef) => value * sizeRef / 100,
41
+ "%": (value, getSizeRef) => value * getSizeRef() / 100,
39
42
  vh: (value) => value * window.innerHeight / 100,
40
43
  vw: (value) => value * window.innerWidth / 100,
41
44
  vmin: (value) => value * Math.min(window.innerWidth, window.innerHeight) / 100,
42
45
  vmax: (value) => value * Math.max(window.innerWidth, window.innerHeight) / 100
43
46
  };
44
- function getAnimationStepValue(val, sizeRef) {
47
+ function getAnimationStepValue(val, getSizeRef) {
45
48
  if (typeof val === "number") {
46
49
  return val;
47
50
  }
48
51
  if (!val[1] || !CSSUnitConverter[val[1]]) {
49
52
  return val[0];
50
53
  }
51
- return CSSUnitConverter[val[1]](val[0], sizeRef);
54
+ return CSSUnitConverter[val[1]](val[0], getSizeRef);
52
55
  }
53
56
  function linear(value) {
54
57
  return value;
@@ -62,7 +65,7 @@ function normalizeEase(ease) {
62
65
  }
63
66
  return ease;
64
67
  }
65
- var generateTranslateRenderStrategy = (sizeRef) => (element, fromValue, toValue, progress) => (0, import_math.lerp)(getAnimationStepValue(fromValue != null ? fromValue : 0, element[sizeRef]), getAnimationStepValue(toValue != null ? toValue : 0, element[sizeRef]), progress);
68
+ var generateTranslateRenderStrategy = (sizeRef) => (element, fromValue, toValue, progress) => (0, import_math.lerp)(getAnimationStepValue(fromValue != null ? fromValue : 0, () => element[sizeRef]), getAnimationStepValue(toValue != null ? toValue : 0, () => element[sizeRef]), progress);
66
69
  var widthBasedTranslateRenderStrategy = generateTranslateRenderStrategy("offsetWidth");
67
70
  var heightBasedTranslateRenderStrategy = generateTranslateRenderStrategy("offsetHeight");
68
71
  var generateLerpRenderStrategy = (defaultValue) => (element, fromValue, toValue, progress) => (0, import_math.lerp)(fromValue != null ? fromValue : defaultValue, toValue != null ? toValue : defaultValue, progress);
@@ -85,21 +88,34 @@ var transformRenderStrategies = {
85
88
  rotateZ: degreesRenderStrategy
86
89
  };
87
90
  function render(element, from, to, progress) {
88
- var _a, _b;
89
91
  const stepProgress = to.easing((0, import_math.map)(progress, from.offset, to.offset, 0, 1));
90
- if ((0, import_isDefined.default)(from.opacity) || (0, import_isDefined.default)(to.opacity)) {
91
- element.style.opacity = (0, import_math.map)(stepProgress, 0, 1, (_a = from.opacity) != null ? _a : 1, (_b = to.opacity) != null ? _b : 1);
92
- } else if (element.style.opacity) {
93
- element.style.opacity = "";
94
- }
95
- if ((0, import_isDefined.default)(to.transformOrigin)) {
96
- element.style.transformOrigin = to.transformOrigin;
97
- } else if (element.style.transformOrigin) {
98
- element.style.transformOrigin = "";
99
- }
100
- (0, import_transform.default)(element, Object.fromEntries(import_transform.TRANSFORM_PROPS.filter((name) => (0, import_isDefined.default)(from[name]) || (0, import_isDefined.default)(to[name])).map((name) => {
101
- return [name, transformRenderStrategies[name](element, from[name], to[name], stepProgress)];
102
- })));
92
+ import_scheduler.domScheduler.read(function renderRead() {
93
+ var _a, _b;
94
+ let opacity = false;
95
+ if ((0, import_isDefined.default)(from.opacity) || (0, import_isDefined.default)(to.opacity)) {
96
+ opacity = (0, import_math.map)(stepProgress, 0, 1, (_a = from.opacity) != null ? _a : 1, (_b = to.opacity) != null ? _b : 1);
97
+ } else if (element.style.opacity) {
98
+ opacity = "";
99
+ }
100
+ let transformOrigin = false;
101
+ if ((0, import_isDefined.default)(to.transformOrigin)) {
102
+ transformOrigin = to.transformOrigin;
103
+ } else if (element.style.transformOrigin) {
104
+ transformOrigin = "";
105
+ }
106
+ const props = Object.fromEntries(import_transform.TRANSFORM_PROPS.filter((name) => (0, import_isDefined.default)(from[name]) || (0, import_isDefined.default)(to[name])).map((name) => {
107
+ return [name, transformRenderStrategies[name](element, from[name], to[name], stepProgress)];
108
+ }));
109
+ import_scheduler.domScheduler.write(function renderWrite() {
110
+ if (opacity !== false) {
111
+ element.style.opacity = opacity;
112
+ }
113
+ if (transformOrigin !== false) {
114
+ element.style.transformOrigin = transformOrigin;
115
+ }
116
+ (0, import_transform.default)(element, props);
117
+ });
118
+ });
103
119
  }
104
120
  function animate(element, keyframes, options = {}) {
105
121
  var _a;
@@ -128,6 +144,7 @@ function animate(element, keyframes, options = {}) {
128
144
  });
129
145
  function pause() {
130
146
  isRunning = false;
147
+ raf.remove(key);
131
148
  }
132
149
  function progress(newProgress) {
133
150
  if (typeof newProgress === "undefined") {
@@ -137,7 +154,7 @@ function animate(element, keyframes, options = {}) {
137
154
  if (Math.abs(1 - progressValue) < PROGRESS_PRECISION) {
138
155
  progressValue = 1;
139
156
  pause();
140
- requestAnimationFrame(() => onFinish(progressValue, easedProgress));
157
+ import_scheduler.domScheduler.afterWrite(() => onFinish(progressValue, easedProgress));
141
158
  }
142
159
  easedProgress = ease(progressValue);
143
160
  let toIndex = 0;
@@ -148,12 +165,12 @@ function animate(element, keyframes, options = {}) {
148
165
  onProgress(progressValue, easedProgress);
149
166
  return progressValue;
150
167
  }
151
- function tick(time) {
168
+ function tick(props) {
152
169
  if (!isRunning) {
170
+ raf.remove(key);
153
171
  return;
154
172
  }
155
- progress((0, import_math.clamp01)((0, import_math.map)(time, startTime, endTime, 0, 1)));
156
- requestAnimationFrame(tick);
173
+ progress((0, import_math.clamp01)((0, import_math.map)(props.time, startTime, endTime, 0, 1)));
157
174
  }
158
175
  function start() {
159
176
  const runningKeys = running.get(element);
@@ -168,7 +185,7 @@ function animate(element, keyframes, options = {}) {
168
185
  progressValue = 0;
169
186
  easedProgress = 0;
170
187
  isRunning = true;
171
- requestAnimationFrame(tick);
188
+ raf.add(key, tick);
172
189
  }
173
190
  function play() {
174
191
  if (isRunning) {
@@ -177,7 +194,7 @@ function animate(element, keyframes, options = {}) {
177
194
  startTime = performance.now() - (0, import_math.lerp)(0, duration, progressValue);
178
195
  endTime = startTime + duration;
179
196
  isRunning = true;
180
- requestAnimationFrame(tick);
197
+ raf.add(key, tick);
181
198
  }
182
199
  return {
183
200
  start,
@@ -2,26 +2,29 @@ import { cubicBezier } from "@motionone/easing";
2
2
  import { lerp, map, clamp01 } from "../math/index.js";
3
3
  import isDefined from "../isDefined.js";
4
4
  import transform, { TRANSFORM_PROPS } from "./transform.js";
5
+ import useRaf from "../../services/raf.js";
6
+ import { domScheduler as scheduler } from "../scheduler.js";
5
7
  let id = 0;
6
8
  const running = /* @__PURE__ */ new WeakMap();
9
+ const raf = useRaf();
7
10
  const noop = () => {
8
11
  };
9
12
  const PROGRESS_PRECISION = 1e-4;
10
13
  const CSSUnitConverter = {
11
- "%": (value, sizeRef) => value * sizeRef / 100,
14
+ "%": (value, getSizeRef) => value * getSizeRef() / 100,
12
15
  vh: (value) => value * window.innerHeight / 100,
13
16
  vw: (value) => value * window.innerWidth / 100,
14
17
  vmin: (value) => value * Math.min(window.innerWidth, window.innerHeight) / 100,
15
18
  vmax: (value) => value * Math.max(window.innerWidth, window.innerHeight) / 100
16
19
  };
17
- function getAnimationStepValue(val, sizeRef) {
20
+ function getAnimationStepValue(val, getSizeRef) {
18
21
  if (typeof val === "number") {
19
22
  return val;
20
23
  }
21
24
  if (!val[1] || !CSSUnitConverter[val[1]]) {
22
25
  return val[0];
23
26
  }
24
- return CSSUnitConverter[val[1]](val[0], sizeRef);
27
+ return CSSUnitConverter[val[1]](val[0], getSizeRef);
25
28
  }
26
29
  function linear(value) {
27
30
  return value;
@@ -35,7 +38,7 @@ function normalizeEase(ease) {
35
38
  }
36
39
  return ease;
37
40
  }
38
- const generateTranslateRenderStrategy = (sizeRef) => (element, fromValue, toValue, progress) => lerp(getAnimationStepValue(fromValue != null ? fromValue : 0, element[sizeRef]), getAnimationStepValue(toValue != null ? toValue : 0, element[sizeRef]), progress);
41
+ const generateTranslateRenderStrategy = (sizeRef) => (element, fromValue, toValue, progress) => lerp(getAnimationStepValue(fromValue != null ? fromValue : 0, () => element[sizeRef]), getAnimationStepValue(toValue != null ? toValue : 0, () => element[sizeRef]), progress);
39
42
  const widthBasedTranslateRenderStrategy = generateTranslateRenderStrategy("offsetWidth");
40
43
  const heightBasedTranslateRenderStrategy = generateTranslateRenderStrategy("offsetHeight");
41
44
  const generateLerpRenderStrategy = (defaultValue) => (element, fromValue, toValue, progress) => lerp(fromValue != null ? fromValue : defaultValue, toValue != null ? toValue : defaultValue, progress);
@@ -58,21 +61,34 @@ const transformRenderStrategies = {
58
61
  rotateZ: degreesRenderStrategy
59
62
  };
60
63
  function render(element, from, to, progress) {
61
- var _a, _b;
62
64
  const stepProgress = to.easing(map(progress, from.offset, to.offset, 0, 1));
63
- if (isDefined(from.opacity) || isDefined(to.opacity)) {
64
- element.style.opacity = map(stepProgress, 0, 1, (_a = from.opacity) != null ? _a : 1, (_b = to.opacity) != null ? _b : 1);
65
- } else if (element.style.opacity) {
66
- element.style.opacity = "";
67
- }
68
- if (isDefined(to.transformOrigin)) {
69
- element.style.transformOrigin = to.transformOrigin;
70
- } else if (element.style.transformOrigin) {
71
- element.style.transformOrigin = "";
72
- }
73
- transform(element, Object.fromEntries(TRANSFORM_PROPS.filter((name) => isDefined(from[name]) || isDefined(to[name])).map((name) => {
74
- return [name, transformRenderStrategies[name](element, from[name], to[name], stepProgress)];
75
- })));
65
+ scheduler.read(function renderRead() {
66
+ var _a, _b;
67
+ let opacity = false;
68
+ if (isDefined(from.opacity) || isDefined(to.opacity)) {
69
+ opacity = map(stepProgress, 0, 1, (_a = from.opacity) != null ? _a : 1, (_b = to.opacity) != null ? _b : 1);
70
+ } else if (element.style.opacity) {
71
+ opacity = "";
72
+ }
73
+ let transformOrigin = false;
74
+ if (isDefined(to.transformOrigin)) {
75
+ transformOrigin = to.transformOrigin;
76
+ } else if (element.style.transformOrigin) {
77
+ transformOrigin = "";
78
+ }
79
+ const props = Object.fromEntries(TRANSFORM_PROPS.filter((name) => isDefined(from[name]) || isDefined(to[name])).map((name) => {
80
+ return [name, transformRenderStrategies[name](element, from[name], to[name], stepProgress)];
81
+ }));
82
+ scheduler.write(function renderWrite() {
83
+ if (opacity !== false) {
84
+ element.style.opacity = opacity;
85
+ }
86
+ if (transformOrigin !== false) {
87
+ element.style.transformOrigin = transformOrigin;
88
+ }
89
+ transform(element, props);
90
+ });
91
+ });
76
92
  }
77
93
  function animate(element, keyframes, options = {}) {
78
94
  var _a;
@@ -101,6 +117,7 @@ function animate(element, keyframes, options = {}) {
101
117
  });
102
118
  function pause() {
103
119
  isRunning = false;
120
+ raf.remove(key);
104
121
  }
105
122
  function progress(newProgress) {
106
123
  if (typeof newProgress === "undefined") {
@@ -110,7 +127,7 @@ function animate(element, keyframes, options = {}) {
110
127
  if (Math.abs(1 - progressValue) < PROGRESS_PRECISION) {
111
128
  progressValue = 1;
112
129
  pause();
113
- requestAnimationFrame(() => onFinish(progressValue, easedProgress));
130
+ scheduler.afterWrite(() => onFinish(progressValue, easedProgress));
114
131
  }
115
132
  easedProgress = ease(progressValue);
116
133
  let toIndex = 0;
@@ -121,12 +138,12 @@ function animate(element, keyframes, options = {}) {
121
138
  onProgress(progressValue, easedProgress);
122
139
  return progressValue;
123
140
  }
124
- function tick(time) {
141
+ function tick(props) {
125
142
  if (!isRunning) {
143
+ raf.remove(key);
126
144
  return;
127
145
  }
128
- progress(clamp01(map(time, startTime, endTime, 0, 1)));
129
- requestAnimationFrame(tick);
146
+ progress(clamp01(map(props.time, startTime, endTime, 0, 1)));
130
147
  }
131
148
  function start() {
132
149
  const runningKeys = running.get(element);
@@ -141,7 +158,7 @@ function animate(element, keyframes, options = {}) {
141
158
  progressValue = 0;
142
159
  easedProgress = 0;
143
160
  isRunning = true;
144
- requestAnimationFrame(tick);
161
+ raf.add(key, tick);
145
162
  }
146
163
  function play() {
147
164
  if (isRunning) {
@@ -150,7 +167,7 @@ function animate(element, keyframes, options = {}) {
150
167
  startTime = performance.now() - lerp(0, duration, progressValue);
151
168
  endTime = startTime + duration;
152
169
  isRunning = true;
153
- requestAnimationFrame(tick);
170
+ raf.add(key, tick);
154
171
  }
155
172
  return {
156
173
  start,
@@ -31,7 +31,7 @@ __export(transition_exports, {
31
31
  setClassesOrStyles: () => setClassesOrStyles
32
32
  });
33
33
  module.exports = __toCommonJS(transition_exports);
34
- var import_nextFrame = __toESM(require("../nextFrame.cjs"), 1);
34
+ var import_nextFrame = require("../nextFrame.cjs");
35
35
  var classes = __toESM(require("./classes.cjs"), 1);
36
36
  var styles = __toESM(require("./styles.cjs"), 1);
37
37
  var cache = /* @__PURE__ */ new WeakMap();
@@ -67,11 +67,11 @@ async function start(element, classesOrStyles) {
67
67
  const trs = Transition.getInstance(element);
68
68
  trs.isTransitioning = true;
69
69
  setClassesOrStyles(element, classesOrStyles.from);
70
- await (0, import_nextFrame.default)();
71
- await (0, import_nextFrame.default)();
70
+ await (0, import_nextFrame.nextFrame)();
71
+ await (0, import_nextFrame.nextFrame)();
72
72
  setClassesOrStyles(element, classesOrStyles.active);
73
- await (0, import_nextFrame.default)();
74
- await (0, import_nextFrame.default)();
73
+ await (0, import_nextFrame.nextFrame)();
74
+ await (0, import_nextFrame.nextFrame)();
75
75
  }
76
76
  async function next(element, classesOrStyles) {
77
77
  const hasTransition = testTransition(element);
@@ -83,7 +83,7 @@ async function next(element, classesOrStyles) {
83
83
  }
84
84
  setClassesOrStyles(element, classesOrStyles.from, "remove");
85
85
  setClassesOrStyles(element, classesOrStyles.to);
86
- await (0, import_nextFrame.default)();
86
+ await (0, import_nextFrame.nextFrame)();
87
87
  if (!hasTransition) {
88
88
  resolve();
89
89
  }
@@ -4,7 +4,7 @@ var __publicField = (obj, key, value) => {
4
4
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  return value;
6
6
  };
7
- import nextFrame from "../nextFrame.js";
7
+ import { nextFrame } from "../nextFrame.js";
8
8
  import * as classes from "./classes.js";
9
9
  import * as styles from "./styles.js";
10
10
  const cache = /* @__PURE__ */ new WeakMap();
package/utils/index.cjs CHANGED
@@ -31,7 +31,7 @@ __export(utils_exports, {
31
31
  isFunction: () => import_isFunction.default,
32
32
  keyCodes: () => import_keyCodes.default,
33
33
  memoize: () => import_memoize.default,
34
- nextFrame: () => import_nextFrame.default,
34
+ nextFrame: () => import_nextFrame.nextFrame,
35
35
  nextMicrotask: () => import_nextMicrotask.default,
36
36
  nextTick: () => import_nextTick.default,
37
37
  objectToURLSearchParams: () => import_history.objectToURLSearchParams,
@@ -43,7 +43,7 @@ var import_debounce = __toESM(require("./debounce.cjs"), 1);
43
43
  var import_focusTrap = __toESM(require("./focusTrap.cjs"), 1);
44
44
  var import_keyCodes = __toESM(require("./keyCodes.cjs"), 1);
45
45
  var import_memoize = __toESM(require("./memoize.cjs"), 1);
46
- var import_nextFrame = __toESM(require("./nextFrame.cjs"), 1);
46
+ var import_nextFrame = require("./nextFrame.cjs");
47
47
  var import_nextTick = __toESM(require("./nextTick.cjs"), 1);
48
48
  var import_nextMicrotask = __toESM(require("./nextMicrotask.cjs"), 1);
49
49
  var import_throttle = __toESM(require("./throttle.cjs"), 1);
@@ -55,4 +55,5 @@ var import_history = require("./history.cjs");
55
55
  __reExport(utils_exports, require("./collide/index.cjs"), module.exports);
56
56
  __reExport(utils_exports, require("./math/index.cjs"), module.exports);
57
57
  __reExport(utils_exports, require("./string/index.cjs"), module.exports);
58
+ __reExport(utils_exports, require("./scheduler.cjs"), module.exports);
58
59
  if (module.exports.default) module.exports = module.exports.default;
package/utils/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { default as debounce } from "./debounce.js";
2
2
  export { default as focusTrap } from "./focusTrap.js";
3
3
  export { default as keyCodes } from "./keyCodes.js";
4
4
  export { default as memoize } from "./memoize.js";
5
- export { default as nextFrame } from "./nextFrame.js";
5
+ export { nextFrame } from "./nextFrame.js";
6
6
  export { default as nextTick } from "./nextTick.js";
7
7
  export { default as nextMicrotask } from "./nextMicrotask.js";
8
8
  export { default as throttle } from "./throttle.js";
@@ -13,4 +13,5 @@ export * from "./css/index.js";
13
13
  export * from "./collide/index.js";
14
14
  export * from "./math/index.js";
15
15
  export * from "./string/index.js";
16
+ export * from "./scheduler.js";
16
17
  export { objectToURLSearchParams, push as historyPush, replace as historyReplace } from "./history.js";
package/utils/index.js CHANGED
@@ -2,13 +2,13 @@ import { default as default2 } from "./debounce.js";
2
2
  import { default as default3 } from "./focusTrap.js";
3
3
  import { default as default4 } from "./keyCodes.js";
4
4
  import { default as default5 } from "./memoize.js";
5
- import { default as default6 } from "./nextFrame.js";
6
- import { default as default7 } from "./nextTick.js";
7
- import { default as default8 } from "./nextMicrotask.js";
8
- import { default as default9 } from "./throttle.js";
9
- import { default as default10 } from "./scrollTo.js";
10
- import { default as default11 } from "./isDefined.js";
11
- import { default as default12 } from "./isFunction.js";
5
+ import { nextFrame } from "./nextFrame.js";
6
+ import { default as default6 } from "./nextTick.js";
7
+ import { default as default7 } from "./nextMicrotask.js";
8
+ import { default as default8 } from "./throttle.js";
9
+ import { default as default9 } from "./scrollTo.js";
10
+ import { default as default10 } from "./isDefined.js";
11
+ import { default as default11 } from "./isFunction.js";
12
12
  export * from "./css/index.js";
13
13
  import {
14
14
  objectToURLSearchParams,
@@ -18,19 +18,20 @@ import {
18
18
  export * from "./collide/index.js";
19
19
  export * from "./math/index.js";
20
20
  export * from "./string/index.js";
21
+ export * from "./scheduler.js";
21
22
  export {
22
23
  default2 as debounce,
23
24
  default3 as focusTrap,
24
25
  push as historyPush,
25
26
  replace as historyReplace,
26
- default11 as isDefined,
27
- default12 as isFunction,
27
+ default10 as isDefined,
28
+ default11 as isFunction,
28
29
  default4 as keyCodes,
29
30
  default5 as memoize,
30
- default6 as nextFrame,
31
- default8 as nextMicrotask,
32
- default7 as nextTick,
31
+ nextFrame,
32
+ default7 as nextMicrotask,
33
+ default6 as nextTick,
33
34
  objectToURLSearchParams,
34
- default10 as scrollTo,
35
- default9 as throttle
35
+ default9 as scrollTo,
36
+ default8 as throttle
36
37
  };
@@ -19,9 +19,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  // packages/js-toolkit/utils/nextFrame.js
20
20
  var nextFrame_exports = {};
21
21
  __export(nextFrame_exports, {
22
- default: () => nextFrame,
23
22
  getCancelRaf: () => getCancelRaf,
24
- getRaf: () => getRaf
23
+ getRaf: () => getRaf,
24
+ nextFrame: () => nextFrame
25
25
  });
26
26
  module.exports = __toCommonJS(nextFrame_exports);
27
27
  function getRaf() {
@@ -24,4 +24,4 @@ export function getCancelRaf(): (id: number) => void;
24
24
  * console.log('hello world');
25
25
  * ```
26
26
  */
27
- export default function nextFrame<T extends () => any>(fn?: T): Promise<T extends Function ? ReturnType<T> : undefined>;
27
+ export function nextFrame<T extends () => any>(fn?: T): Promise<T extends Function ? ReturnType<T> : undefined>;
@@ -10,7 +10,7 @@ function nextFrame(fn) {
10
10
  });
11
11
  }
12
12
  export {
13
- nextFrame as default,
14
13
  getCancelRaf,
15
- getRaf
14
+ getRaf,
15
+ nextFrame
16
16
  };
@@ -0,0 +1,74 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // packages/js-toolkit/utils/scheduler.js
20
+ var scheduler_exports = {};
21
+ __export(scheduler_exports, {
22
+ domScheduler: () => domScheduler,
23
+ useScheduler: () => useScheduler
24
+ });
25
+ module.exports = __toCommonJS(scheduler_exports);
26
+ function getScheduler(steps) {
27
+ const stepsFns = {};
28
+ const api = {};
29
+ let isScheduled = false;
30
+ const resolvedPromise = Promise.resolve();
31
+ function run(tasks) {
32
+ let task;
33
+ while (task = tasks.shift()) {
34
+ task();
35
+ }
36
+ }
37
+ function flush() {
38
+ steps.forEach(function runStep(step) {
39
+ run(stepsFns[step]);
40
+ });
41
+ isScheduled = false;
42
+ if (steps.reduce((length, step) => length + stepsFns[step].length, 0) > 0) {
43
+ scheduleFlush();
44
+ }
45
+ }
46
+ function scheduleFlush() {
47
+ if (isScheduled) {
48
+ return;
49
+ }
50
+ isScheduled = true;
51
+ resolvedPromise.then(flush);
52
+ }
53
+ steps.forEach((step) => {
54
+ stepsFns[step] = [];
55
+ api[step] = function add(fn) {
56
+ stepsFns[step].push(fn);
57
+ scheduleFlush();
58
+ };
59
+ });
60
+ return api;
61
+ }
62
+ var instances = /* @__PURE__ */ new Map();
63
+ var domSchedulerSteps = ["read", "write", "afterWrite"];
64
+ function useScheduler(steps = domSchedulerSteps) {
65
+ const key = steps.join("-");
66
+ if (instances.has(key)) {
67
+ return instances.get(key);
68
+ }
69
+ const scheduler = getScheduler(steps);
70
+ instances.set(key, scheduler);
71
+ return scheduler;
72
+ }
73
+ var domScheduler = useScheduler(domSchedulerSteps);
74
+ if (module.exports.default) module.exports = module.exports.default;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Use a scheduler based on the given steps.
3
+ * @param {string[]} steps
4
+ * @returns {ReturnType<getScheduler>}
5
+ */
6
+ export function useScheduler(steps?: string[]): ReturnType<typeof getScheduler>;
7
+ export const domScheduler: Record<string, (fn: () => void) => void>;
8
+ /**
9
+ * Generate a scheduler.
10
+ */
11
+ export type T = string;
12
+ /**
13
+ * Generate a scheduler.
14
+ * @typedef {string} T
15
+ * @param {T[]} steps
16
+ * @returns {Record<T, (fn: () => void) => void>}
17
+ */
18
+ declare function getScheduler(steps: T[]): Record<string, (fn: () => void) => void>;
19
+ export {};
@@ -0,0 +1,52 @@
1
+ function getScheduler(steps) {
2
+ const stepsFns = {};
3
+ const api = {};
4
+ let isScheduled = false;
5
+ const resolvedPromise = Promise.resolve();
6
+ function run(tasks) {
7
+ let task;
8
+ while (task = tasks.shift()) {
9
+ task();
10
+ }
11
+ }
12
+ function flush() {
13
+ steps.forEach(function runStep(step) {
14
+ run(stepsFns[step]);
15
+ });
16
+ isScheduled = false;
17
+ if (steps.reduce((length, step) => length + stepsFns[step].length, 0) > 0) {
18
+ scheduleFlush();
19
+ }
20
+ }
21
+ function scheduleFlush() {
22
+ if (isScheduled) {
23
+ return;
24
+ }
25
+ isScheduled = true;
26
+ resolvedPromise.then(flush);
27
+ }
28
+ steps.forEach((step) => {
29
+ stepsFns[step] = [];
30
+ api[step] = function add(fn) {
31
+ stepsFns[step].push(fn);
32
+ scheduleFlush();
33
+ };
34
+ });
35
+ return api;
36
+ }
37
+ const instances = /* @__PURE__ */ new Map();
38
+ const domSchedulerSteps = ["read", "write", "afterWrite"];
39
+ function useScheduler(steps = domSchedulerSteps) {
40
+ const key = steps.join("-");
41
+ if (instances.has(key)) {
42
+ return instances.get(key);
43
+ }
44
+ const scheduler = getScheduler(steps);
45
+ instances.set(key, scheduler);
46
+ return scheduler;
47
+ }
48
+ const domScheduler = useScheduler(domSchedulerSteps);
49
+ export {
50
+ domScheduler,
51
+ useScheduler
52
+ };