@hortonstudio/main 1.2.0 → 1.2.2

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 (2) hide show
  1. package/index.js +148 -42
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,48 +1,77 @@
1
- // ver 1.1.34np
1
+ // ver 1.2.2
2
2
 
3
3
  const API_NAME = 'hsmain';
4
4
 
5
5
  window[API_NAME] = window[API_NAME] || {};
6
6
  window[API_NAME].loaded = false
7
7
 
8
+ // Dynamic module loader function (like Finsweet's approach)
9
+ const loadModule = async (moduleName) => {
10
+ const baseURL = new URL('./', import.meta.url).href;
11
+
12
+ switch (moduleName) {
13
+ case "data-hs-anim-text":
14
+ return import(new URL('./animations/text.js', import.meta.url).href);
15
+ case "data-hs-anim-hero":
16
+ return import(new URL('./animations/hero.js', import.meta.url).href);
17
+ case "data-hs-anim-transition":
18
+ return import(new URL('./animations/transition.js', import.meta.url).href);
19
+ case "data-hs-util-toc":
20
+ return import(new URL('./utils/toc.js', import.meta.url).href);
21
+ case "data-hs-util-progress":
22
+ return import(new URL('./utils/scroll-progress.js', import.meta.url).href);
23
+ case "data-hs-util-navbar":
24
+ return import(new URL('./utils/navbar.js', import.meta.url).href);
25
+ case "smooth-scroll":
26
+ return import(new URL('./autoInit/smooth-scroll.js', import.meta.url).href);
27
+ default:
28
+ throw new Error(`HortonStudio module "${moduleName}" is not supported.`);
29
+ }
30
+
31
+ // Refresh Webflow after processing
32
+ setTimeout(() => {
33
+ if (window.Webflow && window.Webflow.ready) {
34
+ window.Webflow.ready();
35
+ }
36
+
37
+ // Run all registered post-Webflow callbacks (even without Webflow)
38
+ setTimeout(() => {
39
+ postWebflowCallbacks.forEach(callback => {
40
+ try {
41
+ callback();
42
+ } catch (error) {
43
+ console.error('Callback error:', error);
44
+ }
45
+ });
46
+ window[API_NAME].loaded = true;
47
+ }, 100);
48
+ }, 100);
49
+ };
50
+
8
51
  const animationModules = {
9
- "data-hs-anim-text": "./animations/text.js",
10
- "data-hs-anim-hero": "./animations/hero.js",
11
- "data-hs-anim-transition": "./animations/transition.js"
52
+ "data-hs-anim-text": true,
53
+ "data-hs-anim-hero": true,
54
+ "data-hs-anim-transition": true
12
55
  };
13
56
 
14
57
  const utilityModules = {
15
- "data-hs-util-toc": "./utils/toc.js",
16
- "data-hs-util-progress": "./utils/scroll-progress.js",
17
- "data-hs-util-navbar": "./utils/navbar.js"
58
+ "data-hs-util-toc": true,
59
+ "data-hs-util-progress": true,
60
+ "data-hs-util-navbar": true
18
61
  };
19
62
 
20
63
  // Modules that auto-initialize
21
64
  const autoInitModules = {
22
- "smooth-scroll": "./autoInit/smooth-scroll.js"
65
+ "smooth-scroll": true
23
66
  };
24
67
 
25
68
  // Store callbacks to run after Webflow.ready()
26
69
  const postWebflowCallbacks = [];
27
70
 
28
- const loadModule = (moduleName) => {
29
- // Check manual modules first
30
- let modulePath = animationModules[moduleName] || utilityModules[moduleName];
31
-
32
- // Then check auto-init modules
33
- if (!modulePath) {
34
- modulePath = autoInitModules[moduleName];
35
- }
36
-
37
- if (!modulePath) {
38
- throw new Error(`HortonStudio module "${moduleName}" is not supported.`);
39
- }
40
- return import(modulePath);
41
- };
42
-
43
71
  const findCurrentScriptTag = () => {
44
- const scriptTag = document.querySelector('script[data-hs-main]');
45
- return scriptTag || null;
72
+ // Use import.meta.url like Finsweet does
73
+ const scripts = [...document.querySelectorAll(`script[data-hs-main][src="${import.meta.url}"]`)];
74
+ return scripts[0] || document.querySelector('script[data-hs-main]');
46
75
  };
47
76
 
48
77
  const processModules = async (scriptTag) => {
@@ -76,7 +105,6 @@ const processModules = async (scriptTag) => {
76
105
  };
77
106
 
78
107
  const refreshWebflow = () => {
79
-
80
108
  setTimeout(() => {
81
109
  if (window.Webflow && window.Webflow.ready) {
82
110
  window.Webflow.ready();
@@ -115,12 +143,19 @@ const loadHsModule = async (moduleName) => {
115
143
  try {
116
144
  const { init, version } = await loadModule(moduleName);
117
145
  const initResult = await init();
118
- const { result } = initResult || {};
146
+ const { result, destroy } = initResult || {};
119
147
 
120
148
  moduleObj.version = version;
121
- moduleObj.restart = () => {
149
+
150
+ // Finsweet-style destroy and restart methods
151
+ moduleObj.destroy = () => {
152
+ destroy?.();
122
153
  apiInstance.process.delete(moduleName);
123
- return loadHsModule(moduleName);
154
+ };
155
+
156
+ moduleObj.restart = () => {
157
+ moduleObj.destroy?.();
158
+ return apiInstance.load(moduleName);
124
159
  };
125
160
 
126
161
  moduleObj.resolve?.(result);
@@ -137,10 +172,18 @@ const loadHsModule = async (moduleName) => {
137
172
  };
138
173
 
139
174
  const initializeAPI = () => {
140
- const apiInstance = window[API_NAME];
141
-
142
- const existingRequests = Array.isArray(apiInstance) ? apiInstance : [];
143
- const scriptTag = findCurrentScriptTag();
175
+ // Handle early API calls (like Finsweet)
176
+ const existingAPI = window[API_NAME];
177
+ if (existingAPI && !Array.isArray(existingAPI)) {
178
+ processAPI();
179
+ return;
180
+ }
181
+
182
+ const existingRequests = Array.isArray(existingAPI) ? existingAPI : [];
183
+ const scripts = [...document.querySelectorAll(`script[data-hs-main][src="${import.meta.url}"]`)];
184
+ const scriptTag = scripts[0] || document.querySelector('script[data-hs-main]');
185
+
186
+ // Handle rich text blocks
144
187
  const richTextBlocks = document.querySelectorAll('.w-richtext');
145
188
  richTextBlocks.forEach(block => {
146
189
  const images = block.querySelectorAll('img');
@@ -150,17 +193,33 @@ const initializeAPI = () => {
150
193
  });
151
194
 
152
195
  window[API_NAME] = {
153
- scriptTag,
196
+ scripts,
154
197
  modules: {},
155
198
  process: new Set(),
156
-
157
199
  load: loadHsModule,
200
+
201
+ // Push method for queuing (like Finsweet)
202
+ push(...requests) {
203
+ for (let [moduleName, callback] of requests) {
204
+ if (typeof callback === 'function') {
205
+ this.modules[moduleName]?.loading?.then(callback);
206
+ } else {
207
+ this.load(moduleName);
208
+ }
209
+ }
210
+ },
211
+
212
+ // Destroy all modules
213
+ destroy() {
214
+ for (let moduleName in this.modules) {
215
+ this.modules[moduleName]?.destroy?.();
216
+ }
217
+ },
158
218
 
159
219
  // API function for scripts to register post-initialization callbacks
160
220
  afterReady: (callback) => {
161
221
  if (typeof callback === 'function') {
162
222
  postWebflowCallbacks.push(callback);
163
- } else {
164
223
  }
165
224
  },
166
225
 
@@ -168,7 +227,6 @@ const initializeAPI = () => {
168
227
  afterWebflowReady: (callback) => {
169
228
  if (typeof callback === 'function') {
170
229
  postWebflowCallbacks.push(callback);
171
- } else {
172
230
  }
173
231
  },
174
232
 
@@ -189,13 +247,61 @@ const initializeAPI = () => {
189
247
  }
190
248
  };
191
249
 
192
- processModules(scriptTag);
250
+ processAPI();
251
+
252
+ // Process any queued requests
253
+ window[API_NAME].push(...existingRequests);
254
+ };
193
255
 
194
- if (existingRequests.length > 0) {
195
- existingRequests.forEach(request => {
196
- if (typeof request === 'string') {
197
- window[API_NAME].load(request);
256
+ const processAPI = () => {
257
+ // Check for auto mode
258
+ let autoMode = false;
259
+ for (let script of window[API_NAME].scripts || []) {
260
+ autoMode ||= script.getAttribute('data-hs-auto') === 'true';
261
+
262
+ // Load modules based on script attributes
263
+ for (const moduleName of Object.keys({ ...animationModules, ...utilityModules })) {
264
+ if (script.hasAttribute(moduleName)) {
265
+ loadHsModule(moduleName);
198
266
  }
267
+ }
268
+ }
269
+
270
+ // Auto-discovery mode (scan DOM for attributes)
271
+ if (autoMode) {
272
+ document.fonts.ready.then(() => {
273
+ const foundModules = new Set();
274
+ const allElements = document.querySelectorAll('*');
275
+
276
+ for (let element of allElements) {
277
+ for (let attrName of element.getAttributeNames()) {
278
+ // Look for data-hs-[something] attributes
279
+ const match = attrName.match(/^data-hs-([^-=]+)/)?.[1];
280
+ if (match && attributeToModule[match]) {
281
+ foundModules.add(attributeToModule[match]);
282
+ }
283
+ }
284
+ }
285
+
286
+ for (let moduleName of foundModules) {
287
+ loadHsModule(moduleName);
288
+ }
289
+ });
290
+ }
291
+
292
+ // Always load auto-init modules
293
+ for (const moduleName of Object.keys(autoInitModules)) {
294
+ loadHsModule(moduleName);
295
+ }
296
+
297
+ // Hide .transition elements if transition module is not loaded
298
+ const hasTransition = window[API_NAME].scripts?.some(script =>
299
+ script.hasAttribute('data-hs-anim-transition')
300
+ );
301
+ if (!hasTransition) {
302
+ const transitionElements = document.querySelectorAll('.transition');
303
+ transitionElements.forEach(element => {
304
+ element.style.display = 'none';
199
305
  });
200
306
  }
201
307
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hortonstudio/main",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "scripts": {