animejs 4.1.2 → 4.2.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +18 -8
  2. package/{lib → dist/bundles}/anime.esm.js +6549 -6265
  3. package/dist/bundles/anime.esm.min.js +7 -0
  4. package/dist/bundles/anime.umd.js +8621 -0
  5. package/dist/bundles/anime.umd.min.js +7 -0
  6. package/dist/modules/animatable/animatable.cjs +150 -0
  7. package/dist/modules/animatable/animatable.d.ts +28 -0
  8. package/dist/modules/animatable/animatable.js +147 -0
  9. package/dist/modules/animatable/index.cjs +15 -0
  10. package/dist/modules/animatable/index.d.ts +1 -0
  11. package/dist/modules/animatable/index.js +8 -0
  12. package/dist/modules/animation/additive.cjs +82 -0
  13. package/dist/modules/animation/additive.d.ts +15 -0
  14. package/dist/modules/animation/additive.js +79 -0
  15. package/dist/modules/animation/animation.cjs +660 -0
  16. package/dist/modules/animation/animation.d.ts +47 -0
  17. package/dist/modules/animation/animation.js +657 -0
  18. package/dist/modules/animation/composition.cjs +383 -0
  19. package/dist/modules/animation/composition.d.ts +10 -0
  20. package/dist/modules/animation/composition.js +377 -0
  21. package/dist/modules/animation/index.cjs +15 -0
  22. package/dist/modules/animation/index.d.ts +1 -0
  23. package/dist/modules/animation/index.js +8 -0
  24. package/dist/modules/core/clock.cjs +110 -0
  25. package/dist/modules/core/clock.d.ts +51 -0
  26. package/dist/modules/core/clock.js +108 -0
  27. package/dist/modules/core/colors.cjs +102 -0
  28. package/dist/modules/core/colors.d.ts +2 -0
  29. package/dist/modules/core/colors.js +100 -0
  30. package/dist/modules/core/consts.cjs +154 -0
  31. package/dist/modules/core/consts.d.ts +59 -0
  32. package/dist/modules/core/consts.js +121 -0
  33. package/dist/modules/core/globals.cjs +77 -0
  34. package/dist/modules/core/globals.d.ts +29 -0
  35. package/dist/modules/core/globals.js +72 -0
  36. package/dist/modules/core/helpers.cjs +304 -0
  37. package/dist/modules/core/helpers.d.ts +43 -0
  38. package/dist/modules/core/helpers.js +261 -0
  39. package/dist/modules/core/render.cjs +389 -0
  40. package/dist/modules/core/render.d.ts +4 -0
  41. package/dist/modules/core/render.js +386 -0
  42. package/dist/modules/core/styles.cjs +116 -0
  43. package/dist/modules/core/styles.d.ts +5 -0
  44. package/dist/modules/core/styles.js +113 -0
  45. package/dist/modules/core/targets.cjs +136 -0
  46. package/dist/modules/core/targets.d.ts +118 -0
  47. package/dist/modules/core/targets.js +132 -0
  48. package/dist/modules/core/transforms.cjs +49 -0
  49. package/dist/modules/core/transforms.d.ts +2 -0
  50. package/dist/modules/core/transforms.js +47 -0
  51. package/dist/modules/core/units.cjs +67 -0
  52. package/dist/modules/core/units.d.ts +3 -0
  53. package/dist/modules/core/units.js +65 -0
  54. package/dist/modules/core/values.cjs +215 -0
  55. package/dist/modules/core/values.d.ts +14 -0
  56. package/dist/modules/core/values.js +205 -0
  57. package/dist/modules/draggable/draggable.cjs +1226 -0
  58. package/dist/modules/draggable/draggable.d.ts +272 -0
  59. package/dist/modules/draggable/draggable.js +1223 -0
  60. package/dist/modules/draggable/index.cjs +15 -0
  61. package/dist/modules/draggable/index.d.ts +1 -0
  62. package/dist/modules/draggable/index.js +8 -0
  63. package/dist/modules/easings/cubic-bezier.cjs +64 -0
  64. package/dist/modules/easings/cubic-bezier.d.ts +2 -0
  65. package/dist/modules/easings/cubic-bezier.js +62 -0
  66. package/dist/modules/easings/eases.cjs +149 -0
  67. package/dist/modules/easings/eases.d.ts +111 -0
  68. package/dist/modules/easings/eases.js +146 -0
  69. package/dist/modules/easings/index.cjs +24 -0
  70. package/dist/modules/easings/index.d.ts +6 -0
  71. package/dist/modules/easings/index.js +13 -0
  72. package/dist/modules/easings/irregular.cjs +41 -0
  73. package/dist/modules/easings/irregular.d.ts +2 -0
  74. package/dist/modules/easings/irregular.js +39 -0
  75. package/dist/modules/easings/linear.cjs +59 -0
  76. package/dist/modules/easings/linear.d.ts +2 -0
  77. package/dist/modules/easings/linear.js +57 -0
  78. package/dist/modules/easings/none.cjs +19 -0
  79. package/dist/modules/easings/none.d.ts +8 -0
  80. package/dist/modules/easings/none.js +17 -0
  81. package/dist/modules/easings/parser.cjs +59 -0
  82. package/dist/modules/easings/parser.d.ts +21 -0
  83. package/dist/modules/easings/parser.js +55 -0
  84. package/dist/modules/easings/steps.cjs +30 -0
  85. package/dist/modules/easings/steps.d.ts +2 -0
  86. package/dist/modules/easings/steps.js +28 -0
  87. package/dist/modules/engine/engine.cjs +168 -0
  88. package/dist/modules/engine/engine.d.ts +21 -0
  89. package/dist/modules/engine/engine.js +166 -0
  90. package/dist/modules/engine/index.cjs +14 -0
  91. package/dist/modules/engine/index.d.ts +1 -0
  92. package/dist/modules/engine/index.js +8 -0
  93. package/dist/modules/events/index.cjs +16 -0
  94. package/dist/modules/events/index.d.ts +1 -0
  95. package/dist/modules/events/index.js +8 -0
  96. package/dist/modules/events/scroll.cjs +936 -0
  97. package/dist/modules/events/scroll.d.ts +189 -0
  98. package/dist/modules/events/scroll.js +932 -0
  99. package/dist/modules/index.cjs +103 -0
  100. package/dist/modules/index.d.ts +19 -0
  101. package/dist/modules/index.js +42 -0
  102. package/dist/modules/scope/index.cjs +15 -0
  103. package/dist/modules/scope/index.d.ts +1 -0
  104. package/dist/modules/scope/index.js +8 -0
  105. package/dist/modules/scope/scope.cjs +254 -0
  106. package/dist/modules/scope/scope.d.ts +115 -0
  107. package/dist/modules/scope/scope.js +251 -0
  108. package/dist/modules/spring/index.cjs +15 -0
  109. package/dist/modules/spring/index.d.ts +1 -0
  110. package/dist/modules/spring/index.js +8 -0
  111. package/dist/modules/spring/spring.cjs +133 -0
  112. package/dist/modules/spring/spring.d.ts +37 -0
  113. package/dist/modules/spring/spring.js +130 -0
  114. package/dist/modules/svg/drawable.cjs +119 -0
  115. package/dist/modules/svg/drawable.d.ts +3 -0
  116. package/dist/modules/svg/drawable.js +117 -0
  117. package/dist/modules/svg/helpers.cjs +30 -0
  118. package/dist/modules/svg/helpers.d.ts +2 -0
  119. package/dist/modules/svg/helpers.js +28 -0
  120. package/dist/modules/svg/index.cjs +18 -0
  121. package/dist/modules/svg/index.d.ts +3 -0
  122. package/dist/modules/svg/index.js +10 -0
  123. package/dist/modules/svg/morphto.cjs +58 -0
  124. package/dist/modules/svg/morphto.d.ts +3 -0
  125. package/dist/modules/svg/morphto.js +56 -0
  126. package/dist/modules/svg/motionpath.cjs +79 -0
  127. package/dist/modules/svg/motionpath.d.ts +7 -0
  128. package/dist/modules/svg/motionpath.js +77 -0
  129. package/dist/modules/text/index.cjs +16 -0
  130. package/dist/modules/text/index.d.ts +1 -0
  131. package/dist/modules/text/index.js +8 -0
  132. package/dist/modules/text/split.cjs +488 -0
  133. package/dist/modules/text/split.d.ts +62 -0
  134. package/dist/modules/text/split.js +484 -0
  135. package/dist/modules/timeline/index.cjs +15 -0
  136. package/dist/modules/timeline/index.d.ts +1 -0
  137. package/dist/modules/timeline/index.js +8 -0
  138. package/dist/modules/timeline/position.cjs +72 -0
  139. package/dist/modules/timeline/position.d.ts +3 -0
  140. package/dist/modules/timeline/position.js +70 -0
  141. package/dist/modules/timeline/timeline.cjs +312 -0
  142. package/dist/modules/timeline/timeline.d.ts +163 -0
  143. package/dist/modules/timeline/timeline.js +309 -0
  144. package/dist/modules/timer/index.cjs +15 -0
  145. package/dist/modules/timer/index.d.ts +1 -0
  146. package/dist/modules/timer/index.js +8 -0
  147. package/dist/modules/timer/timer.cjs +491 -0
  148. package/dist/modules/timer/timer.d.ts +141 -0
  149. package/dist/modules/timer/timer.js +488 -0
  150. package/dist/modules/types/index.d.ts +387 -0
  151. package/dist/modules/utils/chainable.cjs +190 -0
  152. package/dist/modules/utils/chainable.d.ts +135 -0
  153. package/dist/modules/utils/chainable.js +177 -0
  154. package/dist/modules/utils/index.cjs +43 -0
  155. package/dist/modules/utils/index.d.ts +5 -0
  156. package/dist/modules/utils/index.js +14 -0
  157. package/dist/modules/utils/number.cjs +97 -0
  158. package/dist/modules/utils/number.d.ts +9 -0
  159. package/dist/modules/utils/number.js +85 -0
  160. package/dist/modules/utils/random.cjs +77 -0
  161. package/dist/modules/utils/random.d.ts +22 -0
  162. package/dist/modules/utils/random.js +72 -0
  163. package/dist/modules/utils/stagger.cjs +122 -0
  164. package/dist/modules/utils/stagger.d.ts +30 -0
  165. package/dist/modules/utils/stagger.js +120 -0
  166. package/dist/modules/utils/target.cjs +130 -0
  167. package/dist/modules/utils/target.d.ts +126 -0
  168. package/dist/modules/utils/target.js +125 -0
  169. package/dist/modules/utils/time.cjs +57 -0
  170. package/dist/modules/utils/time.d.ts +5 -0
  171. package/dist/modules/utils/time.js +54 -0
  172. package/dist/modules/waapi/composition.cjs +89 -0
  173. package/dist/modules/waapi/composition.d.ts +4 -0
  174. package/dist/modules/waapi/composition.js +86 -0
  175. package/dist/modules/waapi/index.cjs +15 -0
  176. package/dist/modules/waapi/index.d.ts +1 -0
  177. package/dist/modules/waapi/index.js +8 -0
  178. package/dist/modules/waapi/waapi.cjs +473 -0
  179. package/dist/modules/waapi/waapi.d.ts +114 -0
  180. package/dist/modules/waapi/waapi.js +470 -0
  181. package/package.json +130 -33
  182. package/lib/anime.cjs +0 -9
  183. package/lib/anime.esm.min.js +0 -9
  184. package/lib/anime.iife.js +0 -9
  185. package/lib/anime.iife.min.js +0 -9
  186. package/lib/anime.min.cjs +0 -9
  187. package/lib/anime.umd.js +0 -9
  188. package/lib/anime.umd.min.js +0 -9
  189. package/lib/gui/index.js +0 -6341
  190. package/types/index.d.ts +0 -1081
  191. package/types/index.js +0 -7407
@@ -0,0 +1,484 @@
1
+ /**
2
+ * Anime.js - text - ESM
3
+ * @version v4.2.0
4
+ * @license MIT
5
+ * @copyright 2025 - Julian Garnier
6
+ */
7
+
8
+ import { isBrowser, doc } from '../core/consts.js';
9
+ import { scope } from '../core/globals.js';
10
+ import { isArr, isObj, isFnc, isUnd, isStr, isNum } from '../core/helpers.js';
11
+ import { getNodeList } from '../core/targets.js';
12
+ import { setValue } from '../core/values.js';
13
+ import { keepTime } from '../utils/time.js';
14
+
15
+ /**
16
+ * @import {
17
+ * Tickable,
18
+ * DOMTarget,
19
+ * SplitTemplateParams,
20
+ * SplitFunctionValue,
21
+ * TextSplitterParams,
22
+ * } from '../types/index.js'
23
+ */
24
+
25
+ const segmenter = (typeof Intl !== 'undefined') && Intl.Segmenter;
26
+ const valueRgx = /\{value\}/g;
27
+ const indexRgx = /\{i\}/g;
28
+ const whiteSpaceGroupRgx = /(\s+)/;
29
+ const whiteSpaceRgx = /^\s+$/;
30
+ const lineType = 'line';
31
+ const wordType = 'word';
32
+ const charType = 'char';
33
+ const dataLine = `data-line`;
34
+
35
+ /**
36
+ * @typedef {Object} Segment
37
+ * @property {String} segment
38
+ * @property {Boolean} [isWordLike]
39
+ */
40
+
41
+ /**
42
+ * @typedef {Object} Segmenter
43
+ * @property {function(String): Iterable<Segment>} segment
44
+ */
45
+
46
+ /** @type {Segmenter} */
47
+ let wordSegmenter = null;
48
+ /** @type {Segmenter} */
49
+ let graphemeSegmenter = null;
50
+ let $splitTemplate = null;
51
+
52
+ /**
53
+ * @param {Segment} seg
54
+ * @return {Boolean}
55
+ */
56
+ const isSegmentWordLike = seg => {
57
+ return seg.isWordLike ||
58
+ seg.segment === ' ' || // Consider spaces as words first, then handle them diffrently later
59
+ isNum(+seg.segment); // Safari doesn't considers numbers as words
60
+ };
61
+
62
+ /**
63
+ * @param {HTMLElement} $el
64
+ */
65
+ const setAriaHidden = $el => $el.setAttribute('aria-hidden', 'true');
66
+
67
+ /**
68
+ * @param {DOMTarget} $el
69
+ * @param {String} type
70
+ * @return {Array<HTMLElement>}
71
+ */
72
+ const getAllTopLevelElements = ($el, type) => [.../** @type {*} */($el.querySelectorAll(`[data-${type}]:not([data-${type}] [data-${type}])`))];
73
+
74
+ const debugColors = { line: '#00D672', word: '#FF4B4B', char: '#5A87FF' };
75
+
76
+ /**
77
+ * @param {HTMLElement} $el
78
+ */
79
+ const filterEmptyElements = $el => {
80
+ if (!$el.childElementCount && !$el.textContent.trim()) {
81
+ const $parent = $el.parentElement;
82
+ $el.remove();
83
+ if ($parent) filterEmptyElements($parent);
84
+ }
85
+ };
86
+
87
+ /**
88
+ * @param {HTMLElement} $el
89
+ * @param {Number} lineIndex
90
+ * @param {Set<HTMLElement>} bin
91
+ * @returns {Set<HTMLElement>}
92
+ */
93
+ const filterLineElements = ($el, lineIndex, bin) => {
94
+ const dataLineAttr = $el.getAttribute(dataLine);
95
+ if (dataLineAttr !== null && +dataLineAttr !== lineIndex || $el.tagName === 'BR') bin.add($el);
96
+ let i = $el.childElementCount;
97
+ while (i--) filterLineElements(/** @type {HTMLElement} */($el.children[i]), lineIndex, bin);
98
+ return bin;
99
+ };
100
+
101
+ /**
102
+ * @param {'line'|'word'|'char'} type
103
+ * @param {SplitTemplateParams} params
104
+ * @return {String}
105
+ */
106
+ const generateTemplate = (type, params = {}) => {
107
+ let template = ``;
108
+ const classString = isStr(params.class) ? ` class="${params.class}"` : '';
109
+ const cloneType = setValue(params.clone, false);
110
+ const wrapType = setValue(params.wrap, false);
111
+ const overflow = wrapType ? wrapType === true ? 'clip' : wrapType : cloneType ? 'clip' : false;
112
+ if (wrapType) template += `<span${overflow ? ` style="overflow:${overflow};"` : ''}>`;
113
+ template += `<span${classString}${cloneType ? ` style="position:relative;"` : ''} data-${type}="{i}">`;
114
+ if (cloneType) {
115
+ const left = cloneType === 'left' ? '-100%' : cloneType === 'right' ? '100%' : '0';
116
+ const top = cloneType === 'top' ? '-100%' : cloneType === 'bottom' ? '100%' : '0';
117
+ template += `<span>{value}</span>`;
118
+ template += `<span inert style="position:absolute;top:${top};left:${left};white-space:nowrap;">{value}</span>`;
119
+ } else {
120
+ template += `{value}`;
121
+ }
122
+ template += `</span>`;
123
+ if (wrapType) template += `</span>`;
124
+ return template;
125
+ };
126
+
127
+ /**
128
+ * @param {String|SplitFunctionValue} htmlTemplate
129
+ * @param {Array<HTMLElement>} store
130
+ * @param {Node|HTMLElement} node
131
+ * @param {DocumentFragment} $parentFragment
132
+ * @param {'line'|'word'|'char'} type
133
+ * @param {Boolean} debug
134
+ * @param {Number} lineIndex
135
+ * @param {Number} [wordIndex]
136
+ * @param {Number} [charIndex]
137
+ * @return {HTMLElement}
138
+ */
139
+ const processHTMLTemplate = (htmlTemplate, store, node, $parentFragment, type, debug, lineIndex, wordIndex, charIndex) => {
140
+ const isLine = type === lineType;
141
+ const isChar = type === charType;
142
+ const className = `_${type}_`;
143
+ const template = isFnc(htmlTemplate) ? htmlTemplate(node) : htmlTemplate;
144
+ const displayStyle = isLine ? 'block' : 'inline-block';
145
+ $splitTemplate.innerHTML = template
146
+ .replace(valueRgx, `<i class="${className}"></i>`)
147
+ .replace(indexRgx, `${isChar ? charIndex : isLine ? lineIndex : wordIndex}`);
148
+ const $content = $splitTemplate.content;
149
+ const $highestParent = /** @type {HTMLElement} */($content.firstElementChild);
150
+ const $split = /** @type {HTMLElement} */($content.querySelector(`[data-${type}]`)) || $highestParent;
151
+ const $replacables = /** @type {NodeListOf<HTMLElement>} */($content.querySelectorAll(`i.${className}`));
152
+ const replacablesLength = $replacables.length;
153
+ if (replacablesLength) {
154
+ $highestParent.style.display = displayStyle;
155
+ $split.style.display = displayStyle;
156
+ $split.setAttribute(dataLine, `${lineIndex}`);
157
+ if (!isLine) {
158
+ $split.setAttribute('data-word', `${wordIndex}`);
159
+ if (isChar) $split.setAttribute('data-char', `${charIndex}`);
160
+ }
161
+ let i = replacablesLength;
162
+ while (i--) {
163
+ const $replace = $replacables[i];
164
+ const $closestParent = $replace.parentElement;
165
+ $closestParent.style.display = displayStyle;
166
+ if (isLine) {
167
+ $closestParent.innerHTML = /** @type {HTMLElement} */(node).innerHTML;
168
+ } else {
169
+ $closestParent.replaceChild(node.cloneNode(true), $replace);
170
+ }
171
+ }
172
+ store.push($split);
173
+ $parentFragment.appendChild($content);
174
+ } else {
175
+ console.warn(`The expression "{value}" is missing from the provided template.`);
176
+ }
177
+ if (debug) $highestParent.style.outline = `1px dotted ${debugColors[type]}`;
178
+ return $highestParent;
179
+ };
180
+
181
+ /**
182
+ * A class that splits text into words and wraps them in span elements while preserving the original HTML structure.
183
+ * @class
184
+ */
185
+ class TextSplitter {
186
+ /**
187
+ * @param {HTMLElement|NodeList|String|Array<HTMLElement>} target
188
+ * @param {TextSplitterParams} [parameters]
189
+ */
190
+ constructor(target, parameters = {}) {
191
+ // Only init segmenters when needed
192
+ if (!wordSegmenter) wordSegmenter = segmenter ? new segmenter([], { granularity: wordType }) : {
193
+ segment: (text) => {
194
+ const segments = [];
195
+ const words = text.split(whiteSpaceGroupRgx);
196
+ for (let i = 0, l = words.length; i < l; i++) {
197
+ const segment = words[i];
198
+ segments.push({
199
+ segment,
200
+ isWordLike: !whiteSpaceRgx.test(segment), // Consider non-whitespace as word-like
201
+ });
202
+ }
203
+ return segments;
204
+ }
205
+ };
206
+ if (!graphemeSegmenter) graphemeSegmenter = segmenter ? new segmenter([], { granularity: 'grapheme' }) : {
207
+ segment: text => [...text].map(char => ({ segment: char }))
208
+ };
209
+ if (!$splitTemplate && isBrowser) $splitTemplate = doc.createElement('template');
210
+ if (scope.current) scope.current.register(this);
211
+ const { words, chars, lines, accessible, includeSpaces, debug } = parameters;
212
+ const $target = /** @type {HTMLElement} */((target = isArr(target) ? target[0] : target) && /** @type {Node} */(target).nodeType ? target : (getNodeList(target) || [])[0]);
213
+ const lineParams = lines === true ? {} : lines;
214
+ const wordParams = words === true || isUnd(words) ? {} : words;
215
+ const charParams = chars === true ? {} : chars;
216
+ this.debug = setValue(debug, false);
217
+ this.includeSpaces = setValue(includeSpaces, false);
218
+ this.accessible = setValue(accessible, true);
219
+ this.linesOnly = lineParams && (!wordParams && !charParams);
220
+ /** @type {String|false|SplitFunctionValue} */
221
+ this.lineTemplate = isObj(lineParams) ? generateTemplate(lineType, /** @type {SplitTemplateParams} */(lineParams)) : lineParams;
222
+ /** @type {String|false|SplitFunctionValue} */
223
+ this.wordTemplate = isObj(wordParams) || this.linesOnly ? generateTemplate(wordType, /** @type {SplitTemplateParams} */(wordParams)) : wordParams;
224
+ /** @type {String|false|SplitFunctionValue} */
225
+ this.charTemplate = isObj(charParams) ? generateTemplate(charType, /** @type {SplitTemplateParams} */(charParams)) : charParams;
226
+ this.$target = $target;
227
+ this.html = $target && $target.innerHTML;
228
+ this.lines = [];
229
+ this.words = [];
230
+ this.chars = [];
231
+ this.effects = [];
232
+ this.effectsCleanups = [];
233
+ this.cache = null;
234
+ this.ready = false;
235
+ this.width = 0;
236
+ this.resizeTimeout = null;
237
+ const handleSplit = () => this.html && (lineParams || wordParams || charParams) && this.split();
238
+ // Make sure this is declared before calling handleSplit() in case revert() is called inside an effect callback
239
+ this.resizeObserver = new ResizeObserver(() => {
240
+ // Use a setTimeout instead of a Timer for better tree shaking
241
+ clearTimeout(this.resizeTimeout);
242
+ this.resizeTimeout = setTimeout(() => {
243
+ const currentWidth = /** @type {HTMLElement} */($target).offsetWidth;
244
+ if (currentWidth === this.width) return;
245
+ this.width = currentWidth;
246
+ handleSplit();
247
+ }, 150);
248
+ });
249
+ // Only declare the font ready promise when splitting by lines and not alreay split
250
+ if (this.lineTemplate && !this.ready) {
251
+ doc.fonts.ready.then(handleSplit);
252
+ } else {
253
+ handleSplit();
254
+ }
255
+ $target ? this.resizeObserver.observe($target) : console.warn('No Text Splitter target found.');
256
+ }
257
+
258
+ /**
259
+ * @param {(...args: any[]) => Tickable | (() => void)} effect
260
+ * @return this
261
+ */
262
+ addEffect(effect) {
263
+ if (!isFnc(effect)) return console.warn('Effect must return a function.');
264
+ const refreshableEffect = keepTime(effect);
265
+ this.effects.push(refreshableEffect);
266
+ if (this.ready) this.effectsCleanups[this.effects.length - 1] = refreshableEffect(this);
267
+ return this;
268
+ }
269
+
270
+ revert() {
271
+ clearTimeout(this.resizeTimeout);
272
+ this.lines.length = this.words.length = this.chars.length = 0;
273
+ this.resizeObserver.disconnect();
274
+ // Make sure to revert the effects after disconnecting the resizeObserver to avoid triggering it in the process
275
+ this.effectsCleanups.forEach(cleanup => isFnc(cleanup) ? cleanup(this) : cleanup.revert && cleanup.revert());
276
+ this.$target.innerHTML = this.html;
277
+ return this;
278
+ }
279
+
280
+ /**
281
+ * Recursively processes a node and its children
282
+ * @param {Node} node
283
+ */
284
+ splitNode(node) {
285
+ const wordTemplate = this.wordTemplate;
286
+ const charTemplate = this.charTemplate;
287
+ const includeSpaces = this.includeSpaces;
288
+ const debug = this.debug;
289
+ const nodeType = node.nodeType;
290
+ if (nodeType === 3) {
291
+ const nodeText = node.nodeValue;
292
+ // If the nodeText is only whitespace, leave it as is
293
+ if (nodeText.trim()) {
294
+ const tempWords = [];
295
+ const words = this.words;
296
+ const chars = this.chars;
297
+ const wordSegments = wordSegmenter.segment(nodeText);
298
+ const $wordsFragment = doc.createDocumentFragment();
299
+ let prevSeg = null;
300
+ for (const wordSegment of wordSegments) {
301
+ const segment = wordSegment.segment;
302
+ const isWordLike = isSegmentWordLike(wordSegment);
303
+ // Determine if this segment should be a new word, first segment always becomes a new word
304
+ if (!prevSeg || (isWordLike && (prevSeg && (isSegmentWordLike(prevSeg))))) {
305
+ tempWords.push(segment);
306
+ } else {
307
+ // Only concatenate if both current and previous are non-word-like and don't contain spaces
308
+ const lastWordIndex = tempWords.length - 1;
309
+ const lastWord = tempWords[lastWordIndex];
310
+ if (!lastWord.includes(' ') && !segment.includes(' ')) {
311
+ tempWords[lastWordIndex] += segment;
312
+ } else {
313
+ tempWords.push(segment);
314
+ }
315
+ }
316
+ prevSeg = wordSegment;
317
+ }
318
+
319
+ for (let i = 0, l = tempWords.length; i < l; i++) {
320
+ const word = tempWords[i];
321
+ if (!word.trim()) {
322
+ // Preserve whitespace only if includeSpaces is false and if the current space is not the first node
323
+ if (i && includeSpaces) continue;
324
+ $wordsFragment.appendChild(doc.createTextNode(word));
325
+ } else {
326
+ const nextWord = tempWords[i + 1];
327
+ const hasWordFollowingSpace = includeSpaces && nextWord && !nextWord.trim();
328
+ const wordToProcess = word;
329
+ const charSegments = charTemplate ? graphemeSegmenter.segment(wordToProcess) : null;
330
+ const $charsFragment = charTemplate ? doc.createDocumentFragment() : doc.createTextNode(hasWordFollowingSpace ? word + '\xa0' : word);
331
+ if (charTemplate) {
332
+ const charSegmentsArray = [...charSegments];
333
+ for (let j = 0, jl = charSegmentsArray.length; j < jl; j++) {
334
+ const charSegment = charSegmentsArray[j];
335
+ const isLastChar = j === jl - 1;
336
+ // If this is the last character and includeSpaces is true with a following space, append the space
337
+ const charText = isLastChar && hasWordFollowingSpace ? charSegment.segment + '\xa0' : charSegment.segment;
338
+ const $charNode = doc.createTextNode(charText);
339
+ processHTMLTemplate(charTemplate, chars, $charNode, /** @type {DocumentFragment} */($charsFragment), charType, debug, -1, words.length, chars.length);
340
+ }
341
+ }
342
+ if (wordTemplate) {
343
+ processHTMLTemplate(wordTemplate, words, $charsFragment, $wordsFragment, wordType, debug, -1, words.length, chars.length);
344
+ // Chars elements must be re-parsed in the split() method if both words and chars are parsed
345
+ } else if (charTemplate) {
346
+ $wordsFragment.appendChild($charsFragment);
347
+ } else {
348
+ $wordsFragment.appendChild(doc.createTextNode(word));
349
+ }
350
+ // Skip the next iteration if we included a space
351
+ if (hasWordFollowingSpace) i++;
352
+ }
353
+ }
354
+ node.parentNode.replaceChild($wordsFragment, node);
355
+ }
356
+ } else if (nodeType === 1) {
357
+ // Converting to an array is necessary to work around childNodes pottential mutation
358
+ const childNodes = /** @type {Array<Node>} */([.../** @type {*} */(node.childNodes)]);
359
+ for (let i = 0, l = childNodes.length; i < l; i++) this.splitNode(childNodes[i]);
360
+ }
361
+ }
362
+
363
+ /**
364
+ * @param {Boolean} clearCache
365
+ * @return {this}
366
+ */
367
+ split(clearCache = false) {
368
+ const $el = this.$target;
369
+ const isCached = !!this.cache && !clearCache;
370
+ const lineTemplate = this.lineTemplate;
371
+ const wordTemplate = this.wordTemplate;
372
+ const charTemplate = this.charTemplate;
373
+ const fontsReady = doc.fonts.status !== 'loading';
374
+ const canSplitLines = lineTemplate && fontsReady;
375
+ this.ready = !lineTemplate || fontsReady;
376
+ if (canSplitLines || clearCache) {
377
+ // No need to revert effects animations here since it's already taken care by the refreshable
378
+ this.effectsCleanups.forEach(cleanup => isFnc(cleanup) && cleanup(this));
379
+ }
380
+ if (!isCached) {
381
+ if (clearCache) {
382
+ $el.innerHTML = this.html;
383
+ this.words.length = this.chars.length = 0;
384
+ }
385
+ this.splitNode($el);
386
+ this.cache = $el.innerHTML;
387
+ }
388
+ if (canSplitLines) {
389
+ if (isCached) $el.innerHTML = this.cache;
390
+ this.lines.length = 0;
391
+ if (wordTemplate) this.words = getAllTopLevelElements($el, wordType);
392
+ }
393
+ // Always reparse characters after a line reset or if both words and chars are activated
394
+ if (charTemplate && (canSplitLines || wordTemplate)) {
395
+ this.chars = getAllTopLevelElements($el, charType);
396
+ }
397
+ // Words are used when lines only and prioritized over chars
398
+ const elementsArray = this.words.length ? this.words : this.chars;
399
+ let y, linesCount = 0;
400
+ for (let i = 0, l = elementsArray.length; i < l; i++) {
401
+ const $el = elementsArray[i];
402
+ const { top, height } = $el.getBoundingClientRect();
403
+ if (y && top - y > height * .5) linesCount++;
404
+ $el.setAttribute(dataLine, `${linesCount}`);
405
+ const nested = $el.querySelectorAll(`[${dataLine}]`);
406
+ let c = nested.length;
407
+ while (c--) nested[c].setAttribute(dataLine, `${linesCount}`);
408
+ y = top;
409
+ }
410
+ if (canSplitLines) {
411
+ const linesFragment = doc.createDocumentFragment();
412
+ const parents = new Set();
413
+ const clones = [];
414
+ for (let lineIndex = 0; lineIndex < linesCount + 1; lineIndex++) {
415
+ const $clone = /** @type {HTMLElement} */($el.cloneNode(true));
416
+ filterLineElements($clone, lineIndex, new Set()).forEach($el => {
417
+ const $parent = $el.parentElement;
418
+ if ($parent) parents.add($parent);
419
+ $el.remove();
420
+ });
421
+ clones.push($clone);
422
+ }
423
+ parents.forEach(filterEmptyElements);
424
+ for (let cloneIndex = 0, clonesLength = clones.length; cloneIndex < clonesLength; cloneIndex++) {
425
+ processHTMLTemplate(lineTemplate, this.lines, clones[cloneIndex], linesFragment, lineType, this.debug, cloneIndex);
426
+ }
427
+ $el.innerHTML = '';
428
+ $el.appendChild(linesFragment);
429
+ if (wordTemplate) this.words = getAllTopLevelElements($el, wordType);
430
+ if (charTemplate) this.chars = getAllTopLevelElements($el, charType);
431
+ }
432
+ // Remove the word wrappers and clear the words array if lines split only
433
+ if (this.linesOnly) {
434
+ const words = this.words;
435
+ let w = words.length;
436
+ while (w--) {
437
+ const $word = words[w];
438
+ $word.replaceWith($word.textContent);
439
+ }
440
+ words.length = 0;
441
+ }
442
+ if (this.accessible && (canSplitLines || !isCached)) {
443
+ const $accessible = doc.createElement('span');
444
+ // Make the accessible element visually-hidden (https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html)
445
+ $accessible.style.cssText = `position:absolute;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);width:1px;height:1px;white-space:nowrap;`;
446
+ // $accessible.setAttribute('tabindex', '-1');
447
+ $accessible.innerHTML = this.html;
448
+ $el.insertBefore($accessible, $el.firstChild);
449
+ this.lines.forEach(setAriaHidden);
450
+ this.words.forEach(setAriaHidden);
451
+ this.chars.forEach(setAriaHidden);
452
+ }
453
+ this.width = /** @type {HTMLElement} */($el).offsetWidth;
454
+ if (canSplitLines || clearCache) {
455
+ this.effects.forEach((effect, i) => this.effectsCleanups[i] = effect(this));
456
+ }
457
+ return this;
458
+ }
459
+
460
+ refresh() {
461
+ this.split(true);
462
+ }
463
+ }
464
+
465
+ /**
466
+ * @param {HTMLElement|NodeList|String|Array<HTMLElement>} target
467
+ * @param {TextSplitterParams} [parameters]
468
+ * @return {TextSplitter}
469
+ */
470
+ const splitText = (target, parameters) => new TextSplitter(target, parameters);
471
+
472
+ /**
473
+ * @deprecated text.split() is deprecated, import splitText() directly, or text.splitText()
474
+ *
475
+ * @param {HTMLElement|NodeList|String|Array<HTMLElement>} target
476
+ * @param {TextSplitterParams} [parameters]
477
+ * @return {TextSplitter}
478
+ */
479
+ const split = (target, parameters) => {
480
+ console.warn('text.split() is deprecated, import splitText() directly, or text.splitText()');
481
+ return new TextSplitter(target, parameters);
482
+ };
483
+
484
+ export { TextSplitter, split, splitText };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Anime.js - timeline - CJS
3
+ * @version v4.2.0
4
+ * @license MIT
5
+ * @copyright 2025 - Julian Garnier
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ var timeline = require('./timeline.cjs');
11
+
12
+
13
+
14
+ exports.Timeline = timeline.Timeline;
15
+ exports.createTimeline = timeline.createTimeline;
@@ -0,0 +1 @@
1
+ export * from "./timeline.js";
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Anime.js - timeline - ESM
3
+ * @version v4.2.0
4
+ * @license MIT
5
+ * @copyright 2025 - Julian Garnier
6
+ */
7
+
8
+ export { Timeline, createTimeline } from './timeline.js';
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Anime.js - timeline - CJS
3
+ * @version v4.2.0
4
+ * @license MIT
5
+ * @copyright 2025 - Julian Garnier
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ var consts = require('../core/consts.cjs');
11
+ var helpers = require('../core/helpers.cjs');
12
+ var values = require('../core/values.cjs');
13
+
14
+ /**
15
+ * @import {
16
+ * Tickable,
17
+ * TimelinePosition,
18
+ * } from '../types/index.js'
19
+ */
20
+
21
+ /**
22
+ * @import {
23
+ * Timeline,
24
+ * } from './timeline.js'
25
+ */
26
+
27
+ /**
28
+ * Timeline's children offsets positions parser
29
+ * @param {Timeline} timeline
30
+ * @param {String} timePosition
31
+ * @return {Number}
32
+ */
33
+ const getPrevChildOffset = (timeline, timePosition) => {
34
+ if (helpers.stringStartsWith(timePosition, '<')) {
35
+ const goToPrevAnimationOffset = timePosition[1] === '<';
36
+ const prevAnimation = /** @type {Tickable} */(timeline._tail);
37
+ const prevOffset = prevAnimation ? prevAnimation._offset + prevAnimation._delay : 0;
38
+ return goToPrevAnimationOffset ? prevOffset : prevOffset + prevAnimation.duration;
39
+ }
40
+ };
41
+
42
+ /**
43
+ * @param {Timeline} timeline
44
+ * @param {TimelinePosition} [timePosition]
45
+ * @return {Number}
46
+ */
47
+ const parseTimelinePosition = (timeline, timePosition) => {
48
+ let tlDuration = timeline.iterationDuration;
49
+ if (tlDuration === consts.minValue) tlDuration = 0;
50
+ if (helpers.isUnd(timePosition)) return tlDuration;
51
+ if (helpers.isNum(+timePosition)) return +timePosition;
52
+ const timePosStr = /** @type {String} */(timePosition);
53
+ const tlLabels = timeline ? timeline.labels : null;
54
+ const hasLabels = !helpers.isNil(tlLabels);
55
+ const prevOffset = getPrevChildOffset(timeline, timePosStr);
56
+ const hasSibling = !helpers.isUnd(prevOffset);
57
+ const matchedRelativeOperator = consts.relativeValuesExecRgx.exec(timePosStr);
58
+ if (matchedRelativeOperator) {
59
+ const fullOperator = matchedRelativeOperator[0];
60
+ const split = timePosStr.split(fullOperator);
61
+ const labelOffset = hasLabels && split[0] ? tlLabels[split[0]] : tlDuration;
62
+ const parsedOffset = hasSibling ? prevOffset : hasLabels ? labelOffset : tlDuration;
63
+ const parsedNumericalOffset = +split[1];
64
+ return values.getRelativeValue(parsedOffset, parsedNumericalOffset, fullOperator[0]);
65
+ } else {
66
+ return hasSibling ? prevOffset :
67
+ hasLabels ? !helpers.isUnd(tlLabels[timePosStr]) ? tlLabels[timePosStr] :
68
+ tlDuration : tlDuration;
69
+ }
70
+ };
71
+
72
+ exports.parseTimelinePosition = parseTimelinePosition;
@@ -0,0 +1,3 @@
1
+ export function parseTimelinePosition(timeline: Timeline, timePosition?: TimelinePosition): number;
2
+ import type { Timeline } from './timeline.js';
3
+ import type { TimelinePosition } from '../types/index.js';
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Anime.js - timeline - ESM
3
+ * @version v4.2.0
4
+ * @license MIT
5
+ * @copyright 2025 - Julian Garnier
6
+ */
7
+
8
+ import { relativeValuesExecRgx, minValue } from '../core/consts.js';
9
+ import { isUnd, isNum, stringStartsWith, isNil } from '../core/helpers.js';
10
+ import { getRelativeValue } from '../core/values.js';
11
+
12
+ /**
13
+ * @import {
14
+ * Tickable,
15
+ * TimelinePosition,
16
+ * } from '../types/index.js'
17
+ */
18
+
19
+ /**
20
+ * @import {
21
+ * Timeline,
22
+ * } from './timeline.js'
23
+ */
24
+
25
+ /**
26
+ * Timeline's children offsets positions parser
27
+ * @param {Timeline} timeline
28
+ * @param {String} timePosition
29
+ * @return {Number}
30
+ */
31
+ const getPrevChildOffset = (timeline, timePosition) => {
32
+ if (stringStartsWith(timePosition, '<')) {
33
+ const goToPrevAnimationOffset = timePosition[1] === '<';
34
+ const prevAnimation = /** @type {Tickable} */(timeline._tail);
35
+ const prevOffset = prevAnimation ? prevAnimation._offset + prevAnimation._delay : 0;
36
+ return goToPrevAnimationOffset ? prevOffset : prevOffset + prevAnimation.duration;
37
+ }
38
+ };
39
+
40
+ /**
41
+ * @param {Timeline} timeline
42
+ * @param {TimelinePosition} [timePosition]
43
+ * @return {Number}
44
+ */
45
+ const parseTimelinePosition = (timeline, timePosition) => {
46
+ let tlDuration = timeline.iterationDuration;
47
+ if (tlDuration === minValue) tlDuration = 0;
48
+ if (isUnd(timePosition)) return tlDuration;
49
+ if (isNum(+timePosition)) return +timePosition;
50
+ const timePosStr = /** @type {String} */(timePosition);
51
+ const tlLabels = timeline ? timeline.labels : null;
52
+ const hasLabels = !isNil(tlLabels);
53
+ const prevOffset = getPrevChildOffset(timeline, timePosStr);
54
+ const hasSibling = !isUnd(prevOffset);
55
+ const matchedRelativeOperator = relativeValuesExecRgx.exec(timePosStr);
56
+ if (matchedRelativeOperator) {
57
+ const fullOperator = matchedRelativeOperator[0];
58
+ const split = timePosStr.split(fullOperator);
59
+ const labelOffset = hasLabels && split[0] ? tlLabels[split[0]] : tlDuration;
60
+ const parsedOffset = hasSibling ? prevOffset : hasLabels ? labelOffset : tlDuration;
61
+ const parsedNumericalOffset = +split[1];
62
+ return getRelativeValue(parsedOffset, parsedNumericalOffset, fullOperator[0]);
63
+ } else {
64
+ return hasSibling ? prevOffset :
65
+ hasLabels ? !isUnd(tlLabels[timePosStr]) ? tlLabels[timePosStr] :
66
+ tlDuration : tlDuration;
67
+ }
68
+ };
69
+
70
+ export { parseTimelinePosition };