@hortonstudio/main 1.7.14 → 1.7.16

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/autoInit/form.js CHANGED
@@ -1,4 +1,19 @@
1
1
  export function init() {
2
+ // Honeypot spam prevention
3
+ document.addEventListener('submit', (e) => {
4
+ const form = e.target;
5
+ if (form.tagName !== 'FORM') return;
6
+
7
+ const honeypot = form.querySelector('[data-hs-form="form-handler"]');
8
+ if (honeypot && honeypot.value) {
9
+ // Honeypot filled - likely a bot
10
+ e.preventDefault();
11
+ e.stopPropagation();
12
+ e.stopImmediatePropagation();
13
+ return false;
14
+ }
15
+ }, true);
16
+
2
17
  // Simple Custom Select Component for Webflow
3
18
  (function() {
4
19
  'use strict';
@@ -2,7 +2,7 @@
2
2
  const API_NAME = "hsmain";
3
3
 
4
4
  export async function init() {
5
-
5
+
6
6
  // Wait for Webflow to be ready before initializing transitions
7
7
  window[API_NAME].afterWebflowReady(() => {
8
8
  setTimeout(() => {
@@ -14,104 +14,52 @@ export async function init() {
14
14
  }
15
15
 
16
16
  function initTransitions() {
17
- const transitionTrigger = document.querySelector(".transition-trigger");
18
- const transitionElement = document.querySelector(".transition");
19
-
20
- // Page Load - Trigger entrance animation with optional delay
21
- if (transitionTrigger) {
22
- // Check if entrance transition should be skipped
23
- const skipEntrance = sessionStorage.getItem('skip-entrance-transition');
24
- if (skipEntrance) {
25
- sessionStorage.removeItem('skip-entrance-transition');
26
- // Keep transition element hidden when skipping animation
27
- if (transitionElement) {
28
- transitionElement.style.display = "none";
29
- }
30
- return; // Skip entrance animation
31
- }
32
-
33
- // Check if this is the first page load of the session
34
- const isFirstLoad = !sessionStorage.getItem('transition-loaded');
35
- const delayAttr = transitionElement?.getAttribute('data-hs-delay');
36
- const delaySeconds = delayAttr ? parseFloat(delayAttr) : 0;
37
-
38
-
39
- const triggerAnimation = () => {
40
- Webflow.push(function () {
41
- transitionTrigger.click();
42
- });
43
- };
44
-
45
- if (isFirstLoad && delaySeconds > 0) {
46
- setTimeout(triggerAnimation, delaySeconds * 1000);
47
- sessionStorage.setItem('transition-loaded', 'true');
48
- } else {
49
- triggerAnimation();
50
- if (isFirstLoad) {
51
- sessionStorage.setItem('transition-loaded', 'true');
52
- }
53
- }
54
- }
17
+ const transitionTrigger = document.querySelector('[data-hs-transition="trigger"]');
18
+ const transitionElement = document.querySelector('[data-hs-transition="element"]');
55
19
 
56
- // Monitor for transition completion
57
- function waitForTransitionComplete(callback) {
58
- if (!transitionElement) return;
59
-
60
- const checkComplete = () => {
61
- if (transitionElement.classList.contains('transition-done')) {
62
- callback();
63
- } else {
64
- setTimeout(checkComplete, 50);
65
- }
66
- };
67
- checkComplete();
68
- }
20
+ if (!transitionTrigger || !transitionElement) return;
69
21
 
70
- // Helper function to check if element or any ancestor has data-hs-transition="prevent"
71
- function hasTransitionPrevented(element) {
72
- let current = element;
73
- while (current && current !== document) {
74
- if (current.getAttribute && current.getAttribute('data-hs-transition') === 'prevent') {
75
- return true;
76
- }
77
- current = current.parentElement;
78
- }
79
- return false;
22
+ // Get exit time from data attribute (in seconds)
23
+ const exitTimeAttr = transitionElement.getAttribute('data-hs-exit-time');
24
+ const exitTime = exitTimeAttr ? parseFloat(exitTimeAttr) * 1000 : 0;
25
+
26
+ // Page Load - Trigger entrance animation
27
+ // Check if this is the first page load of the session
28
+ const isFirstLoad = !sessionStorage.getItem('transition-loaded');
29
+
30
+ const triggerAnimation = () => {
31
+ Webflow.push(function () {
32
+ transitionTrigger.click();
33
+ });
34
+ };
35
+
36
+ triggerAnimation();
37
+ if (isFirstLoad) {
38
+ sessionStorage.setItem('transition-loaded', 'true');
80
39
  }
81
40
 
82
41
  // On Link Click
83
42
  document.addEventListener("click", function (e) {
84
43
  const link = e.target.closest("a");
85
-
44
+
86
45
  if (
87
46
  link &&
88
47
  link.hostname === window.location.hostname &&
89
48
  link.getAttribute("href") &&
90
49
  link.getAttribute("href").indexOf("#") === -1 &&
91
- link.getAttribute("target") !== "_blank" &&
92
- transitionTrigger
50
+ link.getAttribute("target") !== "_blank"
93
51
  ) {
94
- // Check if transitions are prevented
95
- const transitionPrevented = hasTransitionPrevented(link);
96
-
97
- if (transitionPrevented) {
98
- // Set flag to prevent entrance animation on next page
99
- sessionStorage.setItem('skip-entrance-transition', 'true');
100
- // Navigate normally without exit animation
101
- return;
102
- }
103
-
104
52
  e.preventDefault();
105
-
53
+
106
54
  let transitionURL = link.getAttribute("href");
107
-
55
+
108
56
  // Trigger exit animation
109
57
  transitionTrigger.click();
110
-
111
- // Wait for animation to complete before navigating
112
- waitForTransitionComplete(() => {
58
+
59
+ // Wait for exit time, then navigate
60
+ setTimeout(() => {
113
61
  window.location = transitionURL;
114
- });
62
+ }, exitTime);
115
63
  }
116
64
  });
117
65
 
@@ -128,4 +76,4 @@ function initTransitions() {
128
76
  transitionElement.style.display = "none";
129
77
  }
130
78
  });
131
- }
79
+ }
package/index.js CHANGED
@@ -29,12 +29,6 @@ const initializeHsMain = async () => {
29
29
 
30
30
  const allDataAttributes = { ...animationModules, ...utilityModules };
31
31
 
32
- const waitForWebflow = async () =>
33
- new Promise((resolve) => {
34
- if (!window.Webflow) window.Webflow = [];
35
- window.Webflow.push(resolve);
36
- });
37
-
38
32
  const moduleMap = {
39
33
  transition: () => import("./autoInit/transition.js"),
40
34
  "data-hs-util-ba": () => import("./utils/before-after.js"),
@@ -253,42 +247,33 @@ const initializeHsMain = async () => {
253
247
  });
254
248
  });
255
249
 
256
- const waitForIx2 = async () => {
250
+ const waitForIx3 = async () => {
257
251
  const startTime = Date.now();
258
252
  const timeout = 2000; // 2 second timeout
259
253
 
260
254
  return new Promise((resolve) => {
261
- const checkIx2 = () => {
255
+ const checkIx3 = () => {
262
256
  const htmlElement = document.documentElement;
263
- const hasIx2 = htmlElement.classList.contains('w-mod-ix3');
257
+ const hasIx3 = htmlElement.classList.contains('w-mod-ix3');
264
258
 
265
- if (hasIx2) {
259
+ if (hasIx3) {
266
260
  resolve(true);
267
261
  } else if (Date.now() - startTime >= timeout) {
268
- console.warn('[hsmain] IX2 (w-mod-ix3) not detected after 2s timeout. Proceeding anyway, but Webflow interactions may not be fully loaded.');
262
+ console.warn('[hsmain] IX3 (w-mod-ix3) not detected after 2s timeout. Proceeding anyway, but Webflow interactions may not be fully loaded.');
269
263
  resolve(false);
270
264
  } else {
271
- setTimeout(checkIx2, 50);
265
+ setTimeout(checkIx3, 50);
272
266
  }
273
267
  };
274
- checkIx2();
268
+ checkIx3();
275
269
  });
276
270
  };
277
271
 
278
272
  const finalize = async () => {
279
273
  processModules();
280
- await waitForWebflow();
281
-
282
- // Small delay to ensure all scripts are fully initialized
283
- await new Promise(resolve => setTimeout(resolve, 10));
284
-
285
- // Force Webflow to reinitialize (not redraw) - rescans DOM and rebinds interactions
286
- if (window.Webflow && typeof window.Webflow.ready === 'function') {
287
- window.Webflow.ready();
288
- }
289
274
 
290
- // Wait for IX2 to be ready before firing callbacks
291
- await waitForIx2();
275
+ // Wait for IX3 to be ready before firing callbacks
276
+ await waitForIx3();
292
277
 
293
278
  window[API_NAME].loaded = true;
294
279
  readyCallbacks.forEach((callback) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hortonstudio/main",
3
- "version": "1.7.14",
3
+ "version": "1.7.16",
4
4
  "description": "Animation and utility library for client websites",
5
5
  "main": "index.js",
6
6
  "type": "module",