@hortonstudio/main 1.2.35 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,89 +1,91 @@
1
- const API_NAME = 'hsmain';
1
+ const API_NAME = "hsmain";
2
2
 
3
3
  export async function init() {
4
- const api = window[API_NAME];
5
- api.afterWebflowReady(() => {
6
- if (typeof $ !== 'undefined') {
7
- $(document).off('click.wf-scroll');
8
- }
9
- });
10
-
11
- // Disable CSS smooth scrolling
12
- document.documentElement.style.scrollBehavior = 'auto';
13
- document.body.style.scrollBehavior = 'auto';
14
-
15
- // Check if user prefers reduced motion
16
- function prefersReducedMotion() {
17
- return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
18
- }
19
-
20
- function getScrollOffset() {
21
- const offsetValue = getComputedStyle(document.documentElement)
22
- .getPropertyValue('--misc--scroll-offset').trim();
23
- return parseInt(offsetValue) || 0;
24
- }
25
-
26
- // Smooth scroll to element with offset
27
- function scrollToElement(target, offset = 0) {
28
- if (!target) return;
29
-
30
- // Skip animation if user prefers reduced motion
31
- if (prefersReducedMotion()) {
32
- const targetPosition = target.getBoundingClientRect().top + window.scrollY - offset;
33
- window.scrollTo(0, targetPosition);
34
- target.setAttribute('tabindex', '-1');
35
- target.focus({ preventScroll: true });
36
- return;
37
- }
38
-
39
- gsap.to(window, {
40
- duration: 1,
41
- scrollTo: {
42
- y: target,
43
- offsetY: offset
44
- },
45
- ease: "power2.out",
46
- onComplete: function() {
47
- target.setAttribute('tabindex', '-1');
48
- target.focus({ preventScroll: true });
49
- }
50
- });
4
+ const api = window[API_NAME];
5
+ api.afterWebflowReady(() => {
6
+ if (typeof $ !== "undefined") {
7
+ $(document).off("click.wf-scroll");
51
8
  }
52
-
53
- // Handle anchor link clicks and keyboard activation
54
- function handleAnchorClicks() {
55
- document.addEventListener('click', handleAnchorActivation);
56
- document.addEventListener('keydown', function(e) {
57
- if (e.key === 'Enter' || e.key === ' ') {
58
- handleAnchorActivation(e);
59
- }
60
- });
9
+ });
10
+
11
+ // Disable CSS smooth scrolling
12
+ document.documentElement.style.scrollBehavior = "auto";
13
+ document.body.style.scrollBehavior = "auto";
14
+
15
+ // Check if user prefers reduced motion
16
+ function prefersReducedMotion() {
17
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
18
+ }
19
+
20
+ function getScrollOffset() {
21
+ const offsetValue = getComputedStyle(document.documentElement)
22
+ .getPropertyValue("--misc--scroll-offset")
23
+ .trim();
24
+ return parseInt(offsetValue) || 0;
25
+ }
26
+
27
+ // Smooth scroll to element with offset
28
+ function scrollToElement(target, offset = 0) {
29
+ if (!target) return;
30
+
31
+ // Skip animation if user prefers reduced motion
32
+ if (prefersReducedMotion()) {
33
+ const targetPosition =
34
+ target.getBoundingClientRect().top + window.scrollY - offset;
35
+ window.scrollTo(0, targetPosition);
36
+ target.setAttribute("tabindex", "-1");
37
+ target.focus({ preventScroll: true });
38
+ return;
61
39
  }
62
-
63
- function handleAnchorActivation(e) {
64
- const link = e.target.closest('a[href^="#"]');
65
- if (!link) return;
66
-
67
- const href = link.getAttribute('href');
68
- if (!href || href === '#') return;
69
-
70
- const targetId = href.substring(1);
71
- const targetElement = document.getElementById(targetId);
72
-
73
- if (targetElement) {
74
- e.preventDefault();
75
- if (history.replaceState) {
76
- history.replaceState(null, null, `#${targetElement.id}`);
77
- }
78
- const offset = getScrollOffset();
79
- scrollToElement(targetElement, offset);
80
- }
40
+
41
+ gsap.to(window, {
42
+ duration: 1,
43
+ scrollTo: {
44
+ y: target,
45
+ offsetY: offset,
46
+ },
47
+ ease: "power2.out",
48
+ onComplete: function () {
49
+ target.setAttribute("tabindex", "-1");
50
+ target.focus({ preventScroll: true });
51
+ },
52
+ });
53
+ }
54
+
55
+ // Handle anchor link clicks and keyboard activation
56
+ function handleAnchorClicks() {
57
+ document.addEventListener("click", handleAnchorActivation);
58
+ document.addEventListener("keydown", function (e) {
59
+ if (e.key === "Enter" || e.key === " ") {
60
+ handleAnchorActivation(e);
61
+ }
62
+ });
63
+ }
64
+
65
+ function handleAnchorActivation(e) {
66
+ const link = e.target.closest('a[href^="#"]');
67
+ if (!link) return;
68
+
69
+ const href = link.getAttribute("href");
70
+ if (!href || href === "#") return;
71
+
72
+ const targetId = href.substring(1);
73
+ const targetElement = document.getElementById(targetId);
74
+
75
+ if (targetElement) {
76
+ e.preventDefault();
77
+ if (history.replaceState) {
78
+ history.replaceState(null, null, `#${targetElement.id}`);
79
+ }
80
+ const offset = getScrollOffset();
81
+ scrollToElement(targetElement, offset);
81
82
  }
82
-
83
- // Initialize anchor link handling
84
- handleAnchorClicks();
85
-
86
- return {
87
- result: 'autoInit-smooth-scroll initialized'
88
- };
89
- }
83
+ }
84
+
85
+ // Initialize anchor link handling
86
+ handleAnchorClicks();
87
+
88
+ return {
89
+ result: "autoInit-smooth-scroll initialized",
90
+ };
91
+ }
package/index.js CHANGED
@@ -1,73 +1,88 @@
1
- // Version:1.2.35
1
+ // Version:1.4.1
2
2
 
3
- const API_NAME = 'hsmain';
3
+ const API_NAME = "hsmain";
4
4
 
5
5
  const initializeHsMain = async () => {
6
- if (window[API_NAME] && !Array.isArray(window[API_NAME]) && window[API_NAME].loaded) {
6
+ if (
7
+ window[API_NAME] &&
8
+ !Array.isArray(window[API_NAME]) &&
9
+ window[API_NAME].loaded
10
+ ) {
7
11
  return;
8
12
  }
9
13
 
10
14
  const queuedModules = Array.isArray(window[API_NAME]) ? window[API_NAME] : [];
11
15
 
12
16
  const animationModules = {
13
- 'data-hs-anim-text': true,
14
- 'data-hs-anim-hero': true,
15
- 'data-hs-anim-transition': true
17
+ "data-hs-anim-text": true,
18
+ "data-hs-anim-hero": true,
19
+ "data-hs-anim-transition": true,
16
20
  };
17
21
 
18
22
  const utilityModules = {
19
- 'data-hs-util-toc': true,
20
- 'data-hs-util-progress': true,
21
- 'data-hs-util-ba': true
23
+ "data-hs-util-toc": true,
24
+ "data-hs-util-progress": true,
25
+ "data-hs-util-ba": true,
22
26
  };
23
27
 
24
28
  const autoInitModules = {
25
- 'smooth-scroll': true,
26
- 'modal': true,
27
- 'navbar': true,
28
- 'accessibility': true
29
+ "smooth-scroll": true,
30
+ modal: true,
31
+ navbar: true,
32
+ accessibility: true,
33
+ counter: true,
34
+ form: true,
29
35
  };
30
36
 
31
37
  const allDataAttributes = { ...animationModules, ...utilityModules };
32
38
 
33
- const waitForWebflow = async () => new Promise(resolve => {
34
- if (!window.Webflow) window.Webflow = [];
35
- window.Webflow.push(resolve);
36
- });
37
-
38
- const waitForDOMContentLoaded = async () => new Promise(resolve => {
39
- if (document.readyState === 'loading') {
40
- document.addEventListener('DOMContentLoaded', resolve);
41
- } else {
42
- resolve();
43
- }
44
- });
39
+ const waitForWebflow = async () =>
40
+ new Promise((resolve) => {
41
+ if (!window.Webflow) window.Webflow = [];
42
+ window.Webflow.push(resolve);
43
+ });
45
44
 
46
45
  const moduleMap = {
47
- 'data-hs-anim-text': () => import('./animations/text.js'),
48
- 'data-hs-anim-hero': () => import('./animations/hero.js'),
49
- 'data-hs-anim-transition': () => import('./animations/transition.js'),
50
- 'data-hs-util-toc': () => import('./utils/toc.js'),
51
- 'data-hs-util-progress': () => import('./utils/scroll-progress.js'),
52
- 'data-hs-util-ba': () => import('./utils/before-after.js'),
53
- 'smooth-scroll': () => import('./autoInit/smooth-scroll.js'),
54
- 'modal': () => import('./autoInit/modal.js'),
55
- 'navbar': () => import('./autoInit/navbar.js'),
56
- 'accessibility': () => import('./autoInit/accessibility.js')
46
+ "data-hs-anim-text": () => import("./animations/text.js"),
47
+ "data-hs-anim-hero": () => import("./animations/hero.js"),
48
+ "data-hs-anim-transition": () => import("./animations/transition.js"),
49
+ "data-hs-util-toc": () => import("./utils/toc.js"),
50
+ "data-hs-util-progress": () => import("./utils/scroll-progress.js"),
51
+ "data-hs-util-ba": () => import("./utils/before-after.js"),
52
+ "smooth-scroll": () => import("./autoInit/smooth-scroll.js"),
53
+ modal: () => import("./autoInit/modal.js"),
54
+ navbar: () => import("./autoInit/navbar.js"),
55
+ accessibility: () => import("./autoInit/accessibility.js"),
56
+ counter: () => import("./autoInit/counter.js"),
57
+ form: () => import("./autoInit/form.js"),
57
58
  };
58
59
 
59
- let scripts = [...document.querySelectorAll(`script[type="module"][src="${import.meta.url}"]`)];
60
-
60
+ let scripts = [
61
+ ...document.querySelectorAll(
62
+ `script[type="module"][src="${import.meta.url}"]`,
63
+ ),
64
+ ];
65
+
61
66
  if (scripts.length === 0) {
62
- scripts = [...document.querySelectorAll('script[type="module"][src*="@hortonstudio/main"]')]
63
- .filter(script => {
64
- const scriptSrc = script.src;
65
- const currentSrc = import.meta.url;
66
- const scriptPackage = scriptSrc.match(/@hortonstudio\/main(@[\d.]+)?/)?.[0];
67
- const currentPackage = currentSrc.match(/@hortonstudio\/main(@[\d.]+)?/)?.[0];
68
- return scriptPackage && currentPackage &&
69
- scriptPackage.split('@')[0] === currentPackage.split('@')[0];
70
- });
67
+ scripts = [
68
+ ...document.querySelectorAll(
69
+ 'script[type="module"][src*="@hortonstudio/main"]',
70
+ ),
71
+ ].filter((script) => {
72
+ const scriptSrc = script.src;
73
+ const currentSrc = import.meta.url;
74
+ const scriptPackage = scriptSrc.match(
75
+ /@hortonstudio\/main(@[\d.]+)?/,
76
+ )?.[0];
77
+ const currentPackage = currentSrc.match(
78
+ /@hortonstudio\/main(@[\d.]+)?/,
79
+ )?.[0];
80
+ return (
81
+ scriptPackage &&
82
+ currentPackage &&
83
+ scriptPackage.split("@")[0] === currentPackage.split("@")[0]
84
+ );
85
+ });
71
86
  }
72
87
 
73
88
  const loadModule = async (moduleName) => {
@@ -121,9 +136,12 @@ const initializeHsMain = async () => {
121
136
  process: new Set(),
122
137
  load: loadModule,
123
138
  loaded: false,
139
+ barbaEnabled: false,
140
+ embedScriptManager: null,
141
+ barbaManager: null,
124
142
  push(...items) {
125
143
  for (const [moduleName, callback] of items) {
126
- if (typeof callback === 'function') {
144
+ if (typeof callback === "function") {
127
145
  this.modules[moduleName]?.loading?.then(callback);
128
146
  } else {
129
147
  this.load(moduleName);
@@ -135,8 +153,61 @@ const initializeHsMain = async () => {
135
153
  this.modules[moduleName]?.destroy?.();
136
154
  }
137
155
  },
156
+ async reinitialize() {
157
+ // Complete teardown and reinit
158
+ this.destroy();
159
+ this.modules = {};
160
+ this.process = new Set();
161
+
162
+ // Re-scan for modules including in w-embeds
163
+ await this.scanForEmbedModules();
164
+ processModules();
165
+ },
166
+ async scanForEmbedModules() {
167
+ const embeds = document.querySelectorAll(".w-embed");
168
+ embeds.forEach((embed) => {
169
+ const scripts = embed.querySelectorAll("script[data-hs-module]");
170
+ scripts.forEach((script) => {
171
+ // Extract module info from data attributes
172
+ const moduleType = script.getAttribute("data-hs-module-type");
173
+ const moduleName = script.getAttribute("data-hs-module");
174
+
175
+ if (moduleType && moduleName) {
176
+ const moduleKey = `data-hs-${moduleType}-${moduleName}`;
177
+ if (moduleMap[moduleKey]) {
178
+ this.load(moduleKey);
179
+ }
180
+ }
181
+ });
182
+ });
183
+ },
184
+ async setBarbaMode(enabled) {
185
+ this.barbaEnabled = enabled;
186
+ if (enabled && !this.barbaManager) {
187
+ try {
188
+ const module = await import("./barba/barbaManager.js");
189
+ this.barbaManager = module.initializeBarba();
190
+ if (!this.barbaManager) {
191
+ }
192
+ } catch (error) {
193
+ this.barbaEnabled = false;
194
+ }
195
+ }
196
+ },
197
+ enableBarba() {
198
+ return this.setBarbaMode(true);
199
+ },
200
+ async initEmbedScriptManager() {
201
+ if (!this.embedScriptManager) {
202
+ const { EmbedScriptManager } = await import(
203
+ "./barba/embedScriptManager.js"
204
+ );
205
+ this.embedScriptManager = new EmbedScriptManager();
206
+ }
207
+ return this.embedScriptManager;
208
+ },
138
209
  afterReady(callback) {
139
- if (typeof callback === 'function') {
210
+ if (typeof callback === "function") {
140
211
  if (this.loaded) {
141
212
  callback();
142
213
  } else {
@@ -145,7 +216,7 @@ const initializeHsMain = async () => {
145
216
  }
146
217
  },
147
218
  afterWebflowReady(callback) {
148
- if (typeof callback === 'function') {
219
+ if (typeof callback === "function") {
149
220
  if (this.loaded) {
150
221
  callback();
151
222
  } else {
@@ -157,7 +228,7 @@ const initializeHsMain = async () => {
157
228
  if (moduleName) {
158
229
  return {
159
230
  loaded: !!this.modules[moduleName],
160
- loading: this.process.has(moduleName)
231
+ loading: this.process.has(moduleName),
161
232
  };
162
233
  }
163
234
  return {
@@ -165,76 +236,55 @@ const initializeHsMain = async () => {
165
236
  loading: [...this.process],
166
237
  animations: Object.keys(animationModules),
167
238
  utilities: Object.keys(utilityModules),
168
- autoInit: Object.keys(autoInitModules)
239
+ autoInit: Object.keys(autoInitModules),
240
+ barbaEnabled: this.barbaEnabled,
169
241
  };
170
- }
242
+ },
171
243
  };
172
244
 
173
245
  const processModules = () => {
174
246
  for (const script of scripts) {
175
- const isAutoDetect = script.getAttribute('data-hs-auto') === 'true';
176
-
177
247
  for (const attrName of Object.keys(allDataAttributes)) {
178
248
  if (script.hasAttribute(attrName)) {
179
249
  loadModule(attrName);
180
250
  }
181
251
  }
182
-
183
- if (isAutoDetect) {
184
- waitForDOMContentLoaded().then(() => {
185
- const foundAttributes = new Set();
186
- const allElements = document.querySelectorAll('*');
187
-
188
- for (const element of allElements) {
189
- for (const attrName of element.getAttributeNames()) {
190
- const match = attrName.match(/^(data-hs-(?:anim|util)-[^-=]+)/)?.[1];
191
- if (match && allDataAttributes[match]) {
192
- foundAttributes.add(match);
193
- }
194
- }
195
- }
196
-
197
- for (const attrName of foundAttributes) {
198
- loadModule(attrName);
199
- }
200
- });
201
- }
202
252
  }
203
253
 
204
254
  for (const moduleName of Object.keys(autoInitModules)) {
205
255
  loadModule(moduleName);
206
256
  }
207
257
 
208
- if (!scripts.some(script => script.hasAttribute('data-hs-anim-transition'))) {
209
- document.querySelectorAll('.transition').forEach(element => {
210
- element.style.display = 'none';
258
+ if (
259
+ !scripts.some((script) => script.hasAttribute("data-hs-anim-transition"))
260
+ ) {
261
+ document.querySelectorAll(".transition").forEach((element) => {
262
+ element.style.display = "none";
211
263
  });
212
264
  }
213
265
  };
214
266
 
215
- document.querySelectorAll('.w-richtext').forEach(richtext => {
216
- richtext.querySelectorAll('img').forEach(img => {
217
- img.loading = 'eager';
267
+ document.querySelectorAll(".w-richtext").forEach((richtext) => {
268
+ richtext.querySelectorAll("img").forEach((img) => {
269
+ img.loading = "eager";
218
270
  });
219
271
  });
220
272
 
221
273
  const finalize = async () => {
222
274
  processModules();
223
275
  await waitForWebflow();
276
+
224
277
  window[API_NAME].loaded = true;
225
- readyCallbacks.forEach(callback => {
278
+ readyCallbacks.forEach((callback) => {
226
279
  try {
227
280
  callback();
228
- } catch (error) {
229
- // Silent fail for callbacks
230
- }
281
+ } catch (error) {}
231
282
  });
283
+ readyCallbacks.length = 0; // Clear array after execution
232
284
  };
233
285
 
234
286
  window[API_NAME].push(...queuedModules);
235
- finalize().catch(() => {
236
- // Silent fail for initialization
237
- });
287
+ finalize().catch(() => {});
238
288
  };
239
289
 
240
- initializeHsMain();
290
+ initializeHsMain();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hortonstudio/main",
3
- "version": "1.2.35",
3
+ "version": "1.4.1",
4
4
  "description": "Animation and utility library for client websites",
5
5
  "main": "index.js",
6
6
  "type": "module",