@hortonstudio/main 1.2.35 → 1.4.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.
@@ -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,90 @@
1
- // Version:1.2.35
1
+ // Version:1.4.0
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
+ "custom-values": true,
35
+ form: true,
29
36
  };
30
37
 
31
38
  const allDataAttributes = { ...animationModules, ...utilityModules };
32
39
 
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
- });
40
+ const waitForWebflow = async () =>
41
+ new Promise((resolve) => {
42
+ if (!window.Webflow) window.Webflow = [];
43
+ window.Webflow.push(resolve);
44
+ });
45
45
 
46
46
  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')
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"),
57
+ counter: () => import("./autoInit/counter.js"),
58
+ "custom-values": () => import("./autoInit/custom-values.js"),
59
+ form: () => import("./autoInit/form.js"),
57
60
  };
58
61
 
59
- let scripts = [...document.querySelectorAll(`script[type="module"][src="${import.meta.url}"]`)];
60
-
62
+ let scripts = [
63
+ ...document.querySelectorAll(
64
+ `script[type="module"][src="${import.meta.url}"]`,
65
+ ),
66
+ ];
67
+
61
68
  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
- });
69
+ scripts = [
70
+ ...document.querySelectorAll(
71
+ 'script[type="module"][src*="@hortonstudio/main"]',
72
+ ),
73
+ ].filter((script) => {
74
+ const scriptSrc = script.src;
75
+ const currentSrc = import.meta.url;
76
+ const scriptPackage = scriptSrc.match(
77
+ /@hortonstudio\/main(@[\d.]+)?/,
78
+ )?.[0];
79
+ const currentPackage = currentSrc.match(
80
+ /@hortonstudio\/main(@[\d.]+)?/,
81
+ )?.[0];
82
+ return (
83
+ scriptPackage &&
84
+ currentPackage &&
85
+ scriptPackage.split("@")[0] === currentPackage.split("@")[0]
86
+ );
87
+ });
71
88
  }
72
89
 
73
90
  const loadModule = async (moduleName) => {
@@ -121,9 +138,12 @@ const initializeHsMain = async () => {
121
138
  process: new Set(),
122
139
  load: loadModule,
123
140
  loaded: false,
141
+ barbaEnabled: false,
142
+ embedScriptManager: null,
143
+ barbaManager: null,
124
144
  push(...items) {
125
145
  for (const [moduleName, callback] of items) {
126
- if (typeof callback === 'function') {
146
+ if (typeof callback === "function") {
127
147
  this.modules[moduleName]?.loading?.then(callback);
128
148
  } else {
129
149
  this.load(moduleName);
@@ -135,8 +155,61 @@ const initializeHsMain = async () => {
135
155
  this.modules[moduleName]?.destroy?.();
136
156
  }
137
157
  },
158
+ async reinitialize() {
159
+ // Complete teardown and reinit
160
+ this.destroy();
161
+ this.modules = {};
162
+ this.process = new Set();
163
+
164
+ // Re-scan for modules including in w-embeds
165
+ await this.scanForEmbedModules();
166
+ processModules();
167
+ },
168
+ async scanForEmbedModules() {
169
+ const embeds = document.querySelectorAll(".w-embed");
170
+ embeds.forEach((embed) => {
171
+ const scripts = embed.querySelectorAll("script[data-hs-module]");
172
+ scripts.forEach((script) => {
173
+ // Extract module info from data attributes
174
+ const moduleType = script.getAttribute("data-hs-module-type");
175
+ const moduleName = script.getAttribute("data-hs-module");
176
+
177
+ if (moduleType && moduleName) {
178
+ const moduleKey = `data-hs-${moduleType}-${moduleName}`;
179
+ if (moduleMap[moduleKey]) {
180
+ this.load(moduleKey);
181
+ }
182
+ }
183
+ });
184
+ });
185
+ },
186
+ async setBarbaMode(enabled) {
187
+ this.barbaEnabled = enabled;
188
+ if (enabled && !this.barbaManager) {
189
+ try {
190
+ const module = await import("./barba/barbaManager.js");
191
+ this.barbaManager = module.initializeBarba();
192
+ if (!this.barbaManager) {
193
+ }
194
+ } catch (error) {
195
+ this.barbaEnabled = false;
196
+ }
197
+ }
198
+ },
199
+ enableBarba() {
200
+ return this.setBarbaMode(true);
201
+ },
202
+ async initEmbedScriptManager() {
203
+ if (!this.embedScriptManager) {
204
+ const { EmbedScriptManager } = await import(
205
+ "./barba/embedScriptManager.js"
206
+ );
207
+ this.embedScriptManager = new EmbedScriptManager();
208
+ }
209
+ return this.embedScriptManager;
210
+ },
138
211
  afterReady(callback) {
139
- if (typeof callback === 'function') {
212
+ if (typeof callback === "function") {
140
213
  if (this.loaded) {
141
214
  callback();
142
215
  } else {
@@ -145,7 +218,7 @@ const initializeHsMain = async () => {
145
218
  }
146
219
  },
147
220
  afterWebflowReady(callback) {
148
- if (typeof callback === 'function') {
221
+ if (typeof callback === "function") {
149
222
  if (this.loaded) {
150
223
  callback();
151
224
  } else {
@@ -157,7 +230,7 @@ const initializeHsMain = async () => {
157
230
  if (moduleName) {
158
231
  return {
159
232
  loaded: !!this.modules[moduleName],
160
- loading: this.process.has(moduleName)
233
+ loading: this.process.has(moduleName),
161
234
  };
162
235
  }
163
236
  return {
@@ -165,76 +238,55 @@ const initializeHsMain = async () => {
165
238
  loading: [...this.process],
166
239
  animations: Object.keys(animationModules),
167
240
  utilities: Object.keys(utilityModules),
168
- autoInit: Object.keys(autoInitModules)
241
+ autoInit: Object.keys(autoInitModules),
242
+ barbaEnabled: this.barbaEnabled,
169
243
  };
170
- }
244
+ },
171
245
  };
172
246
 
173
247
  const processModules = () => {
174
248
  for (const script of scripts) {
175
- const isAutoDetect = script.getAttribute('data-hs-auto') === 'true';
176
-
177
249
  for (const attrName of Object.keys(allDataAttributes)) {
178
250
  if (script.hasAttribute(attrName)) {
179
251
  loadModule(attrName);
180
252
  }
181
253
  }
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
254
  }
203
255
 
204
256
  for (const moduleName of Object.keys(autoInitModules)) {
205
257
  loadModule(moduleName);
206
258
  }
207
259
 
208
- if (!scripts.some(script => script.hasAttribute('data-hs-anim-transition'))) {
209
- document.querySelectorAll('.transition').forEach(element => {
210
- element.style.display = 'none';
260
+ if (
261
+ !scripts.some((script) => script.hasAttribute("data-hs-anim-transition"))
262
+ ) {
263
+ document.querySelectorAll(".transition").forEach((element) => {
264
+ element.style.display = "none";
211
265
  });
212
266
  }
213
267
  };
214
268
 
215
- document.querySelectorAll('.w-richtext').forEach(richtext => {
216
- richtext.querySelectorAll('img').forEach(img => {
217
- img.loading = 'eager';
269
+ document.querySelectorAll(".w-richtext").forEach((richtext) => {
270
+ richtext.querySelectorAll("img").forEach((img) => {
271
+ img.loading = "eager";
218
272
  });
219
273
  });
220
274
 
221
275
  const finalize = async () => {
222
276
  processModules();
223
277
  await waitForWebflow();
278
+
224
279
  window[API_NAME].loaded = true;
225
- readyCallbacks.forEach(callback => {
280
+ readyCallbacks.forEach((callback) => {
226
281
  try {
227
282
  callback();
228
- } catch (error) {
229
- // Silent fail for callbacks
230
- }
283
+ } catch (error) {}
231
284
  });
285
+ readyCallbacks.length = 0; // Clear array after execution
232
286
  };
233
287
 
234
288
  window[API_NAME].push(...queuedModules);
235
- finalize().catch(() => {
236
- // Silent fail for initialization
237
- });
289
+ finalize().catch(() => {});
238
290
  };
239
291
 
240
- initializeHsMain();
292
+ 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.0",
4
4
  "description": "Animation and utility library for client websites",
5
5
  "main": "index.js",
6
6
  "type": "module",