@hortonstudio/main 1.9.11 → 1.9.20

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 (120) hide show
  1. package/.prettierrc +8 -0
  2. package/README.md +146 -0
  3. package/eslint.config.js +32 -0
  4. package/index.ts +275 -0
  5. package/package.json +19 -2
  6. package/public/bootstrap.js +16 -0
  7. package/src/animations/animations.ts +93 -0
  8. package/src/animations/functions/counter/counter.ts +137 -0
  9. package/src/config.json +570 -0
  10. package/src/config.ts +105 -0
  11. package/src/modules/default/README.md +167 -0
  12. package/src/modules/default/default.ts +71 -0
  13. package/{autoInit → src/modules/default/functions}/accessibility/README.md +44 -12
  14. package/src/modules/default/functions/accessibility/accessibility.ts +54 -0
  15. package/src/modules/default/functions/accordion/README.md +451 -0
  16. package/src/modules/default/functions/accordion/accordion.ts +189 -0
  17. package/src/modules/default/functions/comparison/comparison.ts +424 -0
  18. package/src/modules/default/functions/marquee/marquee.ts +206 -0
  19. package/src/modules/default/functions/navbar/README.md +393 -0
  20. package/src/modules/default/functions/navbar/functions/arrow-navigation/arrow-navigation.ts +183 -0
  21. package/src/modules/default/functions/navbar/functions/dropdown/dropdown.ts +313 -0
  22. package/src/modules/default/functions/navbar/functions/menu/menu.ts +315 -0
  23. package/src/modules/default/functions/navbar/navbar.ts +51 -0
  24. package/{autoInit → src/modules/default/functions}/smooth-scroll/README.md +45 -14
  25. package/{autoInit/smooth-scroll/smooth-scroll.js → src/modules/default/functions/smooth-scroll/smooth-scroll.ts} +33 -38
  26. package/{autoInit → src/modules/default/functions}/transition/README.md +59 -32
  27. package/src/modules/default/functions/transition/transition.ts +290 -0
  28. package/src/modules/normalize/README.md +172 -0
  29. package/src/modules/normalize/functions/clickable/README.md +84 -0
  30. package/src/modules/normalize/functions/clickable/clickable.ts +43 -0
  31. package/src/modules/normalize/functions/clickable/functions/normalize/README.md +213 -0
  32. package/src/modules/normalize/functions/clickable/functions/normalize/normalize.ts +68 -0
  33. package/src/modules/normalize/functions/dupe/README.md +405 -0
  34. package/src/modules/normalize/functions/dupe/dupe.ts +197 -0
  35. package/src/modules/normalize/functions/sync/sync.ts +378 -0
  36. package/src/modules/normalize/normalize.ts +58 -0
  37. package/src/modules/structure/README.md +190 -0
  38. package/src/modules/structure/functions/form/README.md +94 -0
  39. package/src/modules/structure/functions/form/form.ts +54 -0
  40. package/src/modules/structure/functions/form/functions/honeypot/README.md +77 -0
  41. package/src/modules/structure/functions/form/functions/honeypot/honeypot.ts +37 -0
  42. package/src/modules/structure/functions/form/functions/range/README.md +410 -0
  43. package/src/modules/structure/functions/form/functions/range/range.ts +92 -0
  44. package/src/modules/structure/functions/form/functions/select/README.md +393 -0
  45. package/src/modules/structure/functions/form/functions/select/functions/custom-select/custom-select.ts +637 -0
  46. package/src/modules/structure/functions/form/functions/select/functions/states/states.ts +118 -0
  47. package/src/modules/structure/functions/form/functions/select/select.ts +48 -0
  48. package/src/modules/structure/functions/form/functions/test/test.ts +132 -0
  49. package/{autoInit/accessibility → src/modules/structure}/functions/pagination/README.md +147 -72
  50. package/{autoInit/accessibility/functions/pagination/pagination.js → src/modules/structure/functions/pagination/pagination.ts} +98 -50
  51. package/{autoInit → src/modules/structure/functions}/site-settings/README.md +57 -27
  52. package/{autoInit/site-settings/site-settings.js → src/modules/structure/functions/site-settings/site-settings.ts} +36 -32
  53. package/{autoInit/accessibility → src/modules/structure}/functions/toc/README.md +18 -15
  54. package/{autoInit/accessibility/functions/toc/toc.js → src/modules/structure/functions/toc/functions/heading-links/heading-links.ts} +43 -63
  55. package/src/modules/structure/functions/toc/functions/progress-bar/progress-bar.ts +101 -0
  56. package/src/modules/structure/functions/toc/toc.ts +35 -0
  57. package/{autoInit/accessibility → src/modules/structure}/functions/year-replacement/README.md +7 -6
  58. package/src/modules/structure/functions/year-replacement/year-replacement.ts +59 -0
  59. package/src/modules/structure/structure.ts +59 -0
  60. package/src/utils/attributeSelector.ts +78 -0
  61. package/src/utils/cssVariables.ts +24 -0
  62. package/src/utils/gsap.ts +198 -0
  63. package/src/utils/heightAnimator.ts +130 -0
  64. package/src/utils/modalManager.ts +150 -0
  65. package/src/utils.ts +54 -0
  66. package/tsconfig.json +24 -0
  67. package/vite.config.js +45 -0
  68. package/.claude/settings.local.json +0 -70
  69. package/archive/hero.js +0 -794
  70. package/archive/modal.js +0 -80
  71. package/archive/text.js +0 -628
  72. package/autoInit/accessibility/accessibility.js +0 -53
  73. package/autoInit/accessibility/functions/blog-remover/README.md +0 -61
  74. package/autoInit/accessibility/functions/blog-remover/blog-remover.js +0 -31
  75. package/autoInit/accessibility/functions/click-forwarding/README.md +0 -60
  76. package/autoInit/accessibility/functions/click-forwarding/click-forwarding.js +0 -82
  77. package/autoInit/accessibility/functions/dropdown/README.md +0 -212
  78. package/autoInit/accessibility/functions/dropdown/dropdown.js +0 -167
  79. package/autoInit/accessibility/functions/list-accessibility/README.md +0 -56
  80. package/autoInit/accessibility/functions/list-accessibility/list-accessibility.js +0 -23
  81. package/autoInit/accessibility/functions/text-synchronization/README.md +0 -62
  82. package/autoInit/accessibility/functions/text-synchronization/text-synchronization.js +0 -101
  83. package/autoInit/accessibility/functions/year-replacement/year-replacement.js +0 -43
  84. package/autoInit/button/README.md +0 -122
  85. package/autoInit/button/button.js +0 -51
  86. package/autoInit/counter/README.md +0 -274
  87. package/autoInit/counter/counter.js +0 -185
  88. package/autoInit/form/README.md +0 -338
  89. package/autoInit/form/form.js +0 -374
  90. package/autoInit/navbar/README.md +0 -366
  91. package/autoInit/navbar/navbar.js +0 -786
  92. package/autoInit/transition/transition.js +0 -116
  93. package/index.js +0 -305
  94. package/utils/before-after/README.md +0 -520
  95. package/utils/before-after/before-after.js +0 -653
  96. package/utils/css-animations/buttons/main/bgbasic/btn-main-bgbasic.html +0 -10
  97. package/utils/css-animations/buttons/main/bgfill/btn-main-bgfill.html +0 -29
  98. package/utils/css-animations/buttons/navbar/bgbasic/navbar-main-bgbasic.html +0 -17
  99. package/utils/css-animations/buttons/navbar/bgbasic/navbar-menu-bgbasic.html +0 -16
  100. package/utils/css-animations/buttons/navbar/bgfill/navbar-main-bgfill.html +0 -46
  101. package/utils/css-animations/buttons/navbar/bgfill/navbar-menu-bgfill.html +0 -39
  102. package/utils/css-animations/buttons/navbar/color/navbar-announce-color.html +0 -5
  103. package/utils/css-animations/buttons/navbar/color/navbar-main-color.html +0 -7
  104. package/utils/css-animations/buttons/navbar/color/navbar-menu-color.html +0 -7
  105. package/utils/css-animations/buttons/navbar/double-slide/navbar-announce-double-slide.html +0 -40
  106. package/utils/css-animations/buttons/navbar/double-slide/navbar-main-double-slide.html +0 -77
  107. package/utils/css-animations/buttons/navbar/scale/navbar-announce-scale.html +0 -6
  108. package/utils/css-animations/buttons/navbar/scale/navbar-main-scale.html +0 -9
  109. package/utils/css-animations/buttons/navbar/scale/navbar-menu-scale.html +0 -8
  110. package/utils/css-animations/buttons/navbar/underline/navbar-announce-underline.html +0 -32
  111. package/utils/css-animations/buttons/navbar/underline/navbar-main-underline.html +0 -56
  112. package/utils/css-animations/buttons/text/color/text-footer-color.html +0 -5
  113. package/utils/css-animations/buttons/text/color/text-main-color.html +0 -5
  114. package/utils/css-animations/buttons/text/double-slide/text-main-double-slide.html +0 -56
  115. package/utils/css-animations/buttons/text/scale/text-footer-scale.html +0 -6
  116. package/utils/css-animations/buttons/text/scale/text-main-scale.html +0 -6
  117. package/utils/css-animations/buttons/text/underline/text-footer-underline.html +0 -45
  118. package/utils/css-animations/buttons/text/underline/text-main-underline.html +0 -58
  119. package/utils/css-animations/cards/card-clickable.html +0 -11
  120. package/utils/css-animations/defaults.html +0 -69
package/archive/modal.js DELETED
@@ -1,80 +0,0 @@
1
- function initModal() {
2
- const config = {
3
- transitionDuration: 0.3,
4
- blurOpacity: 0.5,
5
- };
6
-
7
-
8
- function openModal(element) {
9
- document.body.classList.add("u-overflow-clip");
10
-
11
- // Add blur to all other modals
12
- document.querySelectorAll("[data-hs-modal]").forEach((modal) => {
13
- if (modal !== element) {
14
- modal.style.display = "block";
15
- modal.style.opacity = config.blurOpacity;
16
- modal.style.transition = `opacity ${config.transitionDuration}s ease`;
17
- }
18
- });
19
- }
20
-
21
- function closeModal(element) {
22
- document.body.classList.remove("u-overflow-clip");
23
-
24
- // Remove blur from all other modals
25
- document.querySelectorAll("[data-hs-modal]").forEach((modal) => {
26
- if (modal !== element) {
27
- modal.style.display = "none";
28
- modal.style.opacity = "0";
29
- modal.style.transition = `opacity ${config.transitionDuration}s ease`;
30
- }
31
- });
32
- }
33
-
34
-
35
- function toggleModal(element) {
36
- element.x = ((element.x || 0) + 1) % 2;
37
-
38
- if (element.x) {
39
- openModal(element);
40
- } else {
41
- closeModal(element);
42
- }
43
- }
44
-
45
- // Initialize openclose functionality
46
- document
47
- .querySelectorAll('[data-hs-modal="openclose"]')
48
- .forEach((trigger) => {
49
- trigger.addEventListener("click", function () {
50
- toggleModal(this);
51
- });
52
- });
53
-
54
- // Initialize open functionality
55
- document.querySelectorAll('[data-hs-modal="open"]').forEach((trigger) => {
56
- trigger.addEventListener("click", function () {
57
- openModal(this);
58
- });
59
- });
60
-
61
- // Initialize close functionality
62
- document.querySelectorAll('[data-hs-modal="close"]').forEach((trigger) => {
63
- trigger.addEventListener("click", function () {
64
- closeModal(this);
65
- });
66
- });
67
-
68
-
69
- return { result: "modal initialized" };
70
- }
71
-
72
- export function init() {
73
- if (document.readyState === "loading") {
74
- document.addEventListener("DOMContentLoaded", initModal);
75
- } else {
76
- initModal();
77
- }
78
-
79
- return { result: "modal initialized" };
80
- }
package/archive/text.js DELETED
@@ -1,628 +0,0 @@
1
- const API_NAME = "hsmain";
2
-
3
- // Module-scoped variables for resize handling
4
- let resizeHandler;
5
-
6
- // Check for reduced motion preference
7
- const prefersReducedMotion = () => {
8
- return (
9
- window.matchMedia &&
10
- window.matchMedia("(prefers-reduced-motion: reduce)").matches
11
- );
12
- };
13
-
14
- const config = {
15
- global: {
16
- animationDelay: 0,
17
- },
18
- wordSplit: {
19
- duration: 1.5,
20
- stagger: 0.05,
21
- yPercent: 110,
22
- ease: "power4.out",
23
- start: "top 97%",
24
- },
25
- lineSplit: {
26
- duration: 1.5,
27
- stagger: 0.1,
28
- yPercent: 110,
29
- ease: "power4.out",
30
- start: "top 97%",
31
- },
32
- charSplit: {
33
- duration: 1.2,
34
- stagger: 0.015,
35
- yPercent: 110,
36
- ease: "power4.out",
37
- start: "top 97%",
38
- },
39
- appear: {
40
- y: 50,
41
- duration: 1.5,
42
- ease: "power3.out",
43
- start: "top 97%",
44
- },
45
- reveal: {
46
- y: 50,
47
- duration: 1.5,
48
- ease: "power3.out",
49
- start: "top 97%",
50
- },
51
- };
52
-
53
- function updateConfig(newConfig) {
54
- function deepMerge(target, source) {
55
- for (const key in source) {
56
- if (
57
- source[key] &&
58
- typeof source[key] === "object" &&
59
- !Array.isArray(source[key])
60
- ) {
61
- target[key] = target[key] || {};
62
- deepMerge(target[key], source[key]);
63
- } else {
64
- target[key] = source[key];
65
- }
66
- }
67
- return target;
68
- }
69
-
70
- deepMerge(config, newConfig);
71
- }
72
-
73
- function killTextAnimations() {
74
- activeAnimations.forEach(({ timeline, element }) => {
75
- if (timeline) {
76
- timeline.kill();
77
- }
78
- if (element?.splitTextInstance) {
79
- element.splitTextInstance.revert();
80
- }
81
- });
82
- activeAnimations.length = 0;
83
- }
84
-
85
- function startTextAnimations() {
86
- if (prefersReducedMotion()) {
87
- // For reduced motion, just show elements without animation
88
- showElementsWithoutAnimation();
89
- return;
90
- }
91
-
92
- setInitialStates().then(() => {
93
- initAnimations();
94
- });
95
- }
96
-
97
- let activeAnimations = [];
98
-
99
- async function waitForFonts() {
100
- try {
101
- return await document.fonts.ready;
102
- } catch (error) {
103
- console.warn("Font loading error:", error);
104
- return Promise.resolve();
105
- }
106
- }
107
-
108
- function findTextElement(container) {
109
- // Simple direct approach: if container has direct text content, use it
110
- // Otherwise use first child with text content
111
- const firstChild = container.firstElementChild;
112
- return firstChild && firstChild.textContent.trim() ? firstChild : container;
113
- }
114
-
115
- function showElementsWithoutAnimation() {
116
- // Safari-optimized: Use single query with comma-separated selectors
117
- // This is significantly faster than multiple querySelectorAll calls
118
- const allTextElements = document.querySelectorAll(
119
- '[data-hs-anim="char"], [data-hs-anim="word"], [data-hs-anim="line"], [data-hs-anim="appear"], [data-hs-anim="reveal"], [data-hs-anim="group"]'
120
- );
121
-
122
- // Batch DOM operations for better Safari performance
123
- const elementsArray = Array.from(allTextElements);
124
- elementsArray.forEach((element) => {
125
- try {
126
- gsap.set(element, {
127
- autoAlpha: 1,
128
- y: 0,
129
- yPercent: 0,
130
- opacity: 1,
131
- });
132
- } catch (error) {
133
- console.warn("Error setting element visibility:", error);
134
- }
135
- });
136
- }
137
-
138
- const CharSplitAnimations = {
139
- async initial() {
140
- await waitForFonts();
141
-
142
- if (prefersReducedMotion()) {
143
- return;
144
- }
145
-
146
- const elements = document.querySelectorAll('[data-hs-anim="char"]');
147
-
148
- elements.forEach((container) => {
149
- const textElement = findTextElement(container);
150
-
151
- const split = SplitText.create(textElement, {
152
- type: "words,chars",
153
- mask: "chars",
154
- charsClass: "char",
155
- });
156
- container.splitTextInstance = split;
157
-
158
- gsap.set(split.chars, {
159
- yPercent: config.charSplit.yPercent,
160
- });
161
- gsap.set(textElement, { autoAlpha: 1 });
162
- });
163
- },
164
-
165
- async animate() {
166
- await waitForFonts();
167
-
168
- if (prefersReducedMotion()) {
169
- return;
170
- }
171
-
172
- const elements = document.querySelectorAll('[data-hs-anim="char"]');
173
-
174
- elements.forEach((container) => {
175
- const chars = container.querySelectorAll(".char");
176
-
177
- const tl = gsap.timeline({
178
- scrollTrigger: {
179
- trigger: container,
180
- start: config.charSplit.start,
181
- invalidateOnRefresh: true,
182
- toggleActions: "play none none none",
183
- once: true,
184
- },
185
- onComplete: () => {
186
- if (container.splitTextInstance) {
187
- container.splitTextInstance.revert();
188
- delete container.splitTextInstance;
189
- }
190
- },
191
- });
192
-
193
- tl.to(chars, {
194
- yPercent: 0,
195
- duration: config.charSplit.duration,
196
- stagger: config.charSplit.stagger,
197
- ease: config.charSplit.ease,
198
- });
199
-
200
- activeAnimations.push({ timeline: tl, element: container });
201
- });
202
- },
203
- };
204
-
205
- const WordSplitAnimations = {
206
- async initial() {
207
- await waitForFonts();
208
-
209
- if (prefersReducedMotion()) {
210
- return;
211
- }
212
-
213
- const elements = document.querySelectorAll('[data-hs-anim="word"]');
214
-
215
- elements.forEach((container) => {
216
- const textElement = findTextElement(container);
217
-
218
- const split = SplitText.create(textElement, {
219
- type: "words",
220
- mask: "words",
221
- wordsClass: "word",
222
- });
223
- container.splitTextInstance = split;
224
-
225
- gsap.set(split.words, {
226
- yPercent: config.wordSplit.yPercent,
227
- });
228
- gsap.set(textElement, { autoAlpha: 1 });
229
- });
230
- },
231
-
232
- async animate() {
233
- await waitForFonts();
234
-
235
- if (prefersReducedMotion()) {
236
- return;
237
- }
238
-
239
- const elements = document.querySelectorAll('[data-hs-anim="word"]');
240
-
241
- elements.forEach((container) => {
242
- const words = container.querySelectorAll(".word");
243
-
244
- const tl = gsap.timeline({
245
- scrollTrigger: {
246
- trigger: container,
247
- start: config.wordSplit.start,
248
- invalidateOnRefresh: true,
249
- toggleActions: "play none none none",
250
- once: true,
251
- },
252
- onComplete: () => {
253
- if (container.splitTextInstance) {
254
- container.splitTextInstance.revert();
255
- delete container.splitTextInstance;
256
- }
257
- },
258
- });
259
-
260
- tl.to(words, {
261
- yPercent: 0,
262
- duration: config.wordSplit.duration,
263
- stagger: config.wordSplit.stagger,
264
- ease: config.wordSplit.ease,
265
- });
266
-
267
- activeAnimations.push({ timeline: tl, element: container });
268
- });
269
- },
270
- };
271
-
272
- const LineSplitAnimations = {
273
- async initial() {
274
- await waitForFonts();
275
-
276
- if (prefersReducedMotion()) {
277
- return;
278
- }
279
-
280
- const elements = document.querySelectorAll('[data-hs-anim="line"]');
281
-
282
- elements.forEach((container) => {
283
- const textElement = findTextElement(container);
284
-
285
- const split = SplitText.create(textElement, {
286
- type: "lines",
287
- mask: "lines",
288
- linesClass: "line",
289
- });
290
- container.splitTextInstance = split;
291
-
292
- gsap.set(split.lines, {
293
- yPercent: config.lineSplit.yPercent,
294
- });
295
- gsap.set(textElement, { autoAlpha: 1 });
296
- });
297
- },
298
-
299
- async animate() {
300
- await waitForFonts();
301
-
302
- if (prefersReducedMotion()) {
303
- return;
304
- }
305
-
306
- const elements = document.querySelectorAll('[data-hs-anim="line"]');
307
-
308
- elements.forEach((container) => {
309
- const lines = container.querySelectorAll(".line");
310
-
311
- const tl = gsap.timeline({
312
- scrollTrigger: {
313
- trigger: container,
314
- start: config.lineSplit.start,
315
- invalidateOnRefresh: true,
316
- toggleActions: "play none none none",
317
- once: true,
318
- },
319
- onComplete: () => {
320
- if (container.splitTextInstance) {
321
- container.splitTextInstance.revert();
322
- delete container.splitTextInstance;
323
- }
324
- },
325
- });
326
-
327
- tl.to(lines, {
328
- yPercent: 0,
329
- duration: config.lineSplit.duration,
330
- stagger: config.lineSplit.stagger,
331
- ease: config.lineSplit.ease,
332
- });
333
-
334
- activeAnimations.push({ timeline: tl, element: container });
335
- });
336
- },
337
- };
338
-
339
- const AppearAnimations = {
340
- async initial() {
341
- await waitForFonts();
342
-
343
- if (prefersReducedMotion()) {
344
- return;
345
- }
346
-
347
- const elements = document.querySelectorAll('[data-hs-anim="appear"]');
348
- elements.forEach((element) => {
349
- gsap.set(element, {
350
- y: config.appear.y,
351
- opacity: 0,
352
- });
353
- });
354
- },
355
-
356
- async animate() {
357
- await waitForFonts();
358
-
359
- if (prefersReducedMotion()) {
360
- return;
361
- }
362
-
363
- const elements = document.querySelectorAll('[data-hs-anim="appear"]');
364
-
365
- elements.forEach((element) => {
366
- const tl = gsap.timeline({
367
- scrollTrigger: {
368
- trigger: element,
369
- start: config.appear.start,
370
- invalidateOnRefresh: true,
371
- toggleActions: "play none none none",
372
- once: true,
373
- },
374
- });
375
-
376
- tl.to(element, {
377
- y: 0,
378
- opacity: 1,
379
- duration: config.appear.duration,
380
- ease: config.appear.ease,
381
- });
382
-
383
- activeAnimations.push({ timeline: tl, element: element });
384
- });
385
- },
386
- };
387
-
388
- const RevealAnimations = {
389
- async initial() {
390
- await waitForFonts();
391
-
392
- if (prefersReducedMotion()) {
393
- return;
394
- }
395
-
396
- const elements = document.querySelectorAll('[data-hs-anim="reveal"]');
397
- elements.forEach((element) => {
398
- gsap.set(element, {
399
- y: config.reveal.y,
400
- opacity: 0,
401
- });
402
- });
403
- },
404
-
405
- async animate() {
406
- await waitForFonts();
407
-
408
- if (prefersReducedMotion()) {
409
- return;
410
- }
411
-
412
- const elements = document.querySelectorAll('[data-hs-anim="reveal"]');
413
-
414
- elements.forEach((element) => {
415
- const tl = gsap.timeline({
416
- scrollTrigger: {
417
- trigger: element,
418
- start: config.reveal.start,
419
- invalidateOnRefresh: true,
420
- toggleActions: "play none none none",
421
- once: true,
422
- },
423
- });
424
-
425
- tl.to(element, {
426
- y: 0,
427
- opacity: 1,
428
- duration: config.reveal.duration,
429
- ease: config.reveal.ease,
430
- });
431
-
432
- activeAnimations.push({ timeline: tl, element: element });
433
- });
434
- },
435
- };
436
-
437
- const GroupAnimations = {
438
- async initial() {
439
- await waitForFonts();
440
-
441
- if (prefersReducedMotion()) {
442
- return;
443
- }
444
-
445
- const elements = document.querySelectorAll('[data-hs-anim="group"]');
446
- elements.forEach((element) => {
447
- const children = Array.from(element.children);
448
- gsap.set(children, {
449
- y: config.appear.y,
450
- opacity: 0,
451
- });
452
- });
453
- },
454
-
455
- async animate() {
456
- await waitForFonts();
457
-
458
- if (prefersReducedMotion()) {
459
- return;
460
- }
461
-
462
- const elements = document.querySelectorAll('[data-hs-anim="group"]');
463
-
464
- elements.forEach((element) => {
465
- const children = Array.from(element.children);
466
- const tl = gsap.timeline({
467
- scrollTrigger: {
468
- trigger: element,
469
- start: config.appear.start,
470
- invalidateOnRefresh: true,
471
- toggleActions: "play none none none",
472
- once: true,
473
- },
474
- });
475
-
476
- tl.to(children, {
477
- y: 0,
478
- opacity: 1,
479
- duration: config.appear.duration,
480
- ease: config.appear.ease,
481
- stagger: 0.1,
482
- });
483
-
484
- activeAnimations.push({ timeline: tl, element: element });
485
- });
486
- },
487
- };
488
-
489
- async function setInitialStates() {
490
- await Promise.all([
491
- CharSplitAnimations.initial(),
492
- WordSplitAnimations.initial(),
493
- LineSplitAnimations.initial(),
494
- AppearAnimations.initial(),
495
- RevealAnimations.initial(),
496
- GroupAnimations.initial(),
497
- ]);
498
- }
499
-
500
- async function initAnimations() {
501
- if (config.global.animationDelay > 0) {
502
- await new Promise((resolve) =>
503
- setTimeout(resolve, config.global.animationDelay * 1000),
504
- );
505
- }
506
-
507
- await Promise.all([
508
- CharSplitAnimations.animate(),
509
- WordSplitAnimations.animate(),
510
- LineSplitAnimations.animate(),
511
- AppearAnimations.animate(),
512
- RevealAnimations.animate(),
513
- GroupAnimations.animate(),
514
- ]);
515
- }
516
-
517
- export async function init() {
518
- // Prevent duplicate initialization
519
- const elements = document.querySelectorAll(
520
- "[data-hs-anim-text]:not([data-initialized])",
521
- );
522
- if (
523
- elements.length === 0 &&
524
- document.querySelectorAll(
525
- '[data-hs-anim="char"]:not([data-initialized]), [data-hs-anim="word"]:not([data-initialized]), [data-hs-anim="line"]:not([data-initialized]), [data-hs-anim="appear"]:not([data-initialized]), [data-hs-anim="reveal"]:not([data-initialized]), [data-hs-anim="group"]:not([data-initialized])',
526
- ).length === 0
527
- ) {
528
- return { result: "anim-text already initialized", destroy: () => {} };
529
- }
530
-
531
- // Mark elements as initialized
532
- elements.forEach((el) => el.setAttribute("data-initialized", "true"));
533
- document
534
- .querySelectorAll(
535
- '[data-hs-anim="char"], [data-hs-anim="word"], [data-hs-anim="line"], [data-hs-anim="appear"], [data-hs-anim="reveal"], [data-hs-anim="group"]',
536
- )
537
- .forEach((el) => {
538
- el.setAttribute("data-initialized", "true");
539
- });
540
-
541
- if (prefersReducedMotion()) {
542
- // For reduced motion, just show elements without animation
543
- showElementsWithoutAnimation();
544
- } else {
545
- await setInitialStates();
546
- initAnimations();
547
- }
548
-
549
- // Safari optimization: Throttled resize handler using requestAnimationFrame
550
- let resizeScheduled = false;
551
- let lastWidth = window.innerWidth;
552
-
553
- resizeHandler = () => {
554
- const currentWidth = window.innerWidth;
555
- if (currentWidth !== lastWidth && !resizeScheduled) {
556
- lastWidth = currentWidth;
557
- resizeScheduled = true;
558
-
559
- // Use requestAnimationFrame instead of setTimeout for better Safari performance
560
- requestAnimationFrame(() => {
561
- try {
562
- ScrollTrigger.refresh();
563
- } catch (error) {
564
- console.warn("Error refreshing ScrollTrigger:", error);
565
- } finally {
566
- resizeScheduled = false;
567
- }
568
- });
569
- }
570
- };
571
- window.addEventListener("resize", resizeHandler, { passive: true });
572
-
573
- // Safari optimization: Simplified page load handling
574
- // Complex event handlers and multiple timeouts cause Safari lag
575
- if (document.readyState === 'complete') {
576
- requestAnimationFrame(() => {
577
- try {
578
- ScrollTrigger.refresh();
579
- } catch (error) {
580
- console.warn("Error refreshing ScrollTrigger:", error);
581
- }
582
- });
583
- }
584
-
585
- // Initialize API with proper checks
586
- if (!window[API_NAME]) {
587
- window[API_NAME] = {};
588
- }
589
-
590
- const api = window[API_NAME];
591
- api.textAnimations = {
592
- config: config,
593
- updateConfig: updateConfig,
594
- start: startTextAnimations,
595
- kill: killTextAnimations,
596
- restart: () => {
597
- killTextAnimations();
598
- startTextAnimations();
599
- },
600
- cleanup: () => {
601
- killTextAnimations();
602
- window.removeEventListener("resize", resizeHandler);
603
- },
604
- };
605
-
606
- // Return destroy function
607
- const destroy = () => {
608
- // Kill all animations
609
- killTextAnimations();
610
-
611
- // Remove resize handler
612
- if (resizeHandler) {
613
- window.removeEventListener("resize", resizeHandler);
614
- }
615
-
616
- // Remove initialized markers
617
- document.querySelectorAll("[data-initialized]").forEach((el) => {
618
- el.removeAttribute("data-initialized");
619
- });
620
-
621
- // Clean up API
622
- if (api.textAnimations) {
623
- delete api.textAnimations;
624
- }
625
- };
626
-
627
- return { result: "anim-text initialized", destroy };
628
- }