@hortonstudio/main 1.2.6 → 1.2.8

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 +288 -245
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,286 +1,329 @@
1
- // ver 1.2.5
1
+ // ver 1.2.6
2
2
 
3
3
  const API_NAME = 'hsmain';
4
4
 
5
- console.log(`🟢 ${API_NAME} v1.2.5 initializing...`);
5
+ console.log(`🟢 ${API_NAME} v1.2.6 initializing...`);
6
6
  console.log('🔍 DOM state:', document.readyState);
7
7
  console.log('🔍 Script URL:', import.meta.url);
8
8
 
9
- // Prevent double initialization
10
- if (window[API_NAME] && !Array.isArray(window[API_NAME])) {
11
- console.log('⚠️ API already initialized');
12
- throw new Error(`${API_NAME} is already running.`);
13
- }
9
+ // Main initialization function
10
+ const initializeHsMain = () => {
11
+ // Handle existing API
12
+ if (window[API_NAME] && !Array.isArray(window[API_NAME]) && window[API_NAME].loaded) {
13
+ console.log('⚠️ API already loaded, skipping initialization');
14
+ return;
15
+ }
14
16
 
15
- // Store any early API calls
16
- const existingRequests = Array.isArray(window[API_NAME]) ? window[API_NAME] : [];
17
+ // Store any early API calls
18
+ const existingRequests = Array.isArray(window[API_NAME]) ? window[API_NAME] : [];
17
19
 
18
- // Module definitions
19
- const animationModules = {
20
- "data-hs-anim-text": true,
21
- "data-hs-anim-hero": true,
22
- "data-hs-anim-transition": true
23
- };
20
+ // Module definitions
21
+ const animationModules = {
22
+ "data-hs-anim-text": true,
23
+ "data-hs-anim-hero": true,
24
+ "data-hs-anim-transition": true
25
+ };
24
26
 
25
- const utilityModules = {
26
- "data-hs-util-toc": true,
27
- "data-hs-util-progress": true,
28
- "data-hs-util-navbar": true
29
- };
27
+ const utilityModules = {
28
+ "data-hs-util-toc": true,
29
+ "data-hs-util-progress": true,
30
+ "data-hs-util-navbar": true
31
+ };
30
32
 
31
- const autoInitModules = {
32
- "smooth-scroll": true
33
- };
33
+ const autoInitModules = {
34
+ "smooth-scroll": true
35
+ };
34
36
 
35
- // All available modules
36
- const allModules = { ...animationModules, ...utilityModules };
37
+ // All available modules
38
+ const allModules = { ...animationModules, ...utilityModules };
37
39
 
38
- // Dynamic module loader (like Finsweet)
39
- const loadModule = async (moduleName) => {
40
- console.log(`📦 Loading module: ${moduleName}`);
41
-
42
- switch (moduleName) {
43
- case "data-hs-anim-text":
44
- return import(new URL('./animations/text.js', import.meta.url).href);
45
- case "data-hs-anim-hero":
46
- return import(new URL('./animations/hero.js', import.meta.url).href);
47
- case "data-hs-anim-transition":
48
- return import(new URL('./animations/transition.js', import.meta.url).href);
49
- case "data-hs-util-toc":
50
- return import(new URL('./utils/toc.js', import.meta.url).href);
51
- case "data-hs-util-progress":
52
- return import(new URL('./utils/scroll-progress.js', import.meta.url).href);
53
- case "data-hs-util-navbar":
54
- return import(new URL('./utils/navbar.js', import.meta.url).href);
55
- case "smooth-scroll":
56
- return import(new URL('./autoInit/smooth-scroll.js', import.meta.url).href);
57
- default:
58
- console.error(`❌ Unsupported module: ${moduleName}`);
59
- throw new Error(`${API_NAME} module "${moduleName}" is not supported.`);
60
- }
61
- };
40
+ // Dynamic module loader (like Finsweet)
41
+ const loadModule = async (moduleName) => {
42
+ console.log(`📦 Loading module: ${moduleName}`);
43
+
44
+ switch (moduleName) {
45
+ case "data-hs-anim-text":
46
+ return import(new URL('./animations/text.js', import.meta.url).href);
47
+ case "data-hs-anim-hero":
48
+ return import(new URL('./animations/hero.js', import.meta.url).href);
49
+ case "data-hs-anim-transition":
50
+ return import(new URL('./animations/transition.js', import.meta.url).href);
51
+ case "data-hs-util-toc":
52
+ return import(new URL('./utils/toc.js', import.meta.url).href);
53
+ case "data-hs-util-progress":
54
+ return import(new URL('./utils/scroll-progress.js', import.meta.url).href);
55
+ case "data-hs-util-navbar":
56
+ return import(new URL('./utils/navbar.js', import.meta.url).href);
57
+ case "smooth-scroll":
58
+ return import(new URL('./autoInit/smooth-scroll.js', import.meta.url).href);
59
+ default:
60
+ console.error(`❌ Unsupported module: ${moduleName}`);
61
+ throw new Error(`${API_NAME} module "${moduleName}" is not supported.`);
62
+ }
63
+ };
62
64
 
63
- // Webflow ready helper (like Finsweet)
64
- const waitWebflowReady = async () => {
65
- return new Promise((resolve) => {
66
- window.Webflow ||= [];
67
- window.Webflow.push(resolve);
68
- });
69
- };
65
+ // Webflow ready helper (like Finsweet)
66
+ const waitWebflowReady = async () => {
67
+ return new Promise((resolve) => {
68
+ window.Webflow ||= [];
69
+ window.Webflow.push(resolve);
70
+ });
71
+ };
70
72
 
71
- // DOM ready helper (like Finsweet)
72
- const waitDOMReady = async () => {
73
- return new Promise((resolve) => {
74
- if (document.readyState === 'loading') {
75
- document.addEventListener('DOMContentLoaded', resolve);
76
- } else {
77
- resolve();
78
- }
79
- });
80
- };
73
+ // DOM ready helper (like Finsweet)
74
+ const waitDOMReady = async () => {
75
+ return new Promise((resolve) => {
76
+ if (document.readyState === 'loading') {
77
+ document.addEventListener('DOMContentLoaded', resolve);
78
+ } else {
79
+ resolve();
80
+ }
81
+ });
82
+ };
81
83
 
82
- // Find script tags (Finsweet approach)
83
- const scripts = [...document.querySelectorAll(`script[type="module"][src="${import.meta.url}"]`)];
84
- console.log(`📄 Found ${scripts.length} matching script tags`);
84
+ // Find script tags (Finsweet approach)
85
+ const scripts = [...document.querySelectorAll(`script[type="module"][src="${import.meta.url}"]`)];
86
+ console.log(`📄 Found ${scripts.length} matching script tags`);
85
87
 
86
- // Module loading function
87
- const loadHsModule = async (moduleName) => {
88
- console.log(`🔄 loadHsModule called for: ${moduleName}`);
89
-
90
- const apiInstance = window[API_NAME];
91
-
92
- // Check if already processing
93
- if (apiInstance.process.has(moduleName)) {
94
- console.log(`⚠️ Module ${moduleName} already processing`);
95
- return apiInstance.modules[moduleName]?.loading;
96
- }
97
-
98
- // Add to processing set
99
- console.log(`➕ Adding ${moduleName} to process set`);
100
- apiInstance.process.add(moduleName);
101
-
102
- // Create module object
103
- const moduleObj = apiInstance.modules[moduleName] || {};
104
- apiInstance.modules[moduleName] = moduleObj;
105
-
106
- // Create loading promise
107
- moduleObj.loading = new Promise((resolve, reject) => {
108
- moduleObj.resolve = resolve;
109
- moduleObj.reject = reject;
110
- });
111
-
112
- try {
113
- console.log(`📦 Importing ${moduleName}...`);
114
- const { init, version } = await loadModule(moduleName);
115
- console.log(`✅ ${moduleName} imported, version: ${version}`);
88
+ // Module loading function
89
+ const loadHsModule = async (moduleName) => {
90
+ console.log(`🔄 loadHsModule called for: ${moduleName}`);
116
91
 
117
- console.log(`🔧 Initializing ${moduleName}...`);
118
- const initResult = await init();
119
- const { result, destroy } = initResult || {};
120
- console.log(`✅ ${moduleName} initialized:`, result);
92
+ const apiInstance = window[API_NAME];
121
93
 
122
- moduleObj.version = version;
94
+ // Check if already processing
95
+ if (apiInstance.process.has(moduleName)) {
96
+ console.log(`⚠️ Module ${moduleName} already processing`);
97
+ return apiInstance.modules[moduleName]?.loading;
98
+ }
123
99
 
124
- // Add destroy and restart methods
125
- moduleObj.destroy = () => {
126
- destroy?.();
127
- apiInstance.process.delete(moduleName);
128
- };
100
+ // Add to processing set
101
+ console.log(`➕ Adding ${moduleName} to process set`);
102
+ apiInstance.process.add(moduleName);
129
103
 
130
- moduleObj.restart = () => {
131
- moduleObj.destroy?.();
132
- return apiInstance.load(moduleName);
133
- };
104
+ // Create module object
105
+ const moduleObj = apiInstance.modules[moduleName] || {};
106
+ apiInstance.modules[moduleName] = moduleObj;
134
107
 
135
- moduleObj.resolve?.(result);
136
- delete moduleObj.resolve;
137
- delete moduleObj.reject;
108
+ // Create loading promise
109
+ moduleObj.loading = new Promise((resolve, reject) => {
110
+ moduleObj.resolve = resolve;
111
+ moduleObj.reject = reject;
112
+ });
138
113
 
139
- return result;
114
+ try {
115
+ console.log(`📦 Importing ${moduleName}...`);
116
+ const { init, version } = await loadModule(moduleName);
117
+ console.log(`✅ ${moduleName} imported, version: ${version}`);
118
+
119
+ console.log(`🔧 Initializing ${moduleName}...`);
120
+ const initResult = await init();
121
+ const { result, destroy } = initResult || {};
122
+ console.log(`✅ ${moduleName} initialized:`, result);
123
+
124
+ moduleObj.version = version;
125
+
126
+ // Add destroy and restart methods
127
+ moduleObj.destroy = () => {
128
+ destroy?.();
129
+ apiInstance.process.delete(moduleName);
130
+ };
131
+
132
+ moduleObj.restart = () => {
133
+ moduleObj.destroy?.();
134
+ return apiInstance.load(moduleName);
135
+ };
136
+
137
+ moduleObj.resolve?.(result);
138
+ delete moduleObj.resolve;
139
+ delete moduleObj.reject;
140
+
141
+ return result;
142
+
143
+ } catch (error) {
144
+ console.error(`❌ Failed to load ${moduleName}:`, error);
145
+ moduleObj.reject?.(error);
146
+ apiInstance.process.delete(moduleName);
147
+ throw error;
148
+ }
149
+ };
150
+
151
+ // Store callbacks to run after initialization
152
+ const postWebflowCallbacks = [];
153
+
154
+ // Initialize API
155
+ window[API_NAME] = {
156
+ scripts,
157
+ modules: {},
158
+ process: new Set(),
159
+ load: loadHsModule,
160
+ loaded: false,
140
161
 
141
- } catch (error) {
142
- console.error(`❌ Failed to load ${moduleName}:`, error);
143
- moduleObj.reject?.(error);
144
- apiInstance.process.delete(moduleName);
145
- throw error;
146
- }
147
- };
162
+ // Push method for queuing
163
+ push(...requests) {
164
+ for (let [moduleName, callback] of requests) {
165
+ if (typeof callback === 'function') {
166
+ this.modules[moduleName]?.loading?.then(callback);
167
+ } else {
168
+ this.load(moduleName);
169
+ }
170
+ }
171
+ },
172
+
173
+ // Destroy all modules
174
+ destroy() {
175
+ for (let moduleName in this.modules) {
176
+ this.modules[moduleName]?.destroy?.();
177
+ }
178
+ },
148
179
 
149
- // Initialize API
150
- window[API_NAME] = {
151
- scripts,
152
- modules: {},
153
- process: new Set(),
154
- load: loadHsModule,
155
- loaded: false,
156
-
157
- // Push method for queuing
158
- push(...requests) {
159
- for (let [moduleName, callback] of requests) {
180
+ // API function for scripts to register post-initialization callbacks
181
+ afterReady(callback) {
160
182
  if (typeof callback === 'function') {
161
- this.modules[moduleName]?.loading?.then(callback);
162
- } else {
163
- this.load(moduleName);
183
+ if (this.loaded) {
184
+ callback();
185
+ } else {
186
+ postWebflowCallbacks.push(callback);
187
+ }
188
+ }
189
+ },
190
+
191
+ // Legacy alias for Webflow compatibility
192
+ afterWebflowReady(callback) {
193
+ if (typeof callback === 'function') {
194
+ if (this.loaded) {
195
+ callback();
196
+ } else {
197
+ postWebflowCallbacks.push(callback);
198
+ }
199
+ }
200
+ },
201
+
202
+ // Status method
203
+ status(moduleName) {
204
+ if (!moduleName) {
205
+ return {
206
+ loaded: Object.keys(this.modules),
207
+ loading: [...this.process],
208
+ animations: Object.keys(animationModules),
209
+ utilities: Object.keys(utilityModules),
210
+ autoInit: Object.keys(autoInitModules)
211
+ };
164
212
  }
165
- }
166
- },
167
-
168
- // Destroy all modules
169
- destroy() {
170
- for (let moduleName in this.modules) {
171
- this.modules[moduleName]?.destroy?.();
172
- }
173
- },
174
-
175
- // Status method
176
- status(moduleName) {
177
- if (!moduleName) {
178
213
  return {
179
- loaded: Object.keys(this.modules),
180
- loading: [...this.process],
181
- animations: Object.keys(animationModules),
182
- utilities: Object.keys(utilityModules),
183
- autoInit: Object.keys(autoInitModules)
214
+ loaded: !!this.modules[moduleName],
215
+ loading: this.process.has(moduleName)
184
216
  };
185
217
  }
186
- return {
187
- loaded: !!this.modules[moduleName],
188
- loading: this.process.has(moduleName)
189
- };
190
- }
191
- };
218
+ };
192
219
 
193
- // Process modules from script tags
194
- const processScriptModules = () => {
195
- console.log(`⚙️ Processing ${scripts.length} script tags`);
196
-
197
- for (const script of scripts) {
198
- console.log(`🏷️ Processing script:`, script.src);
199
-
200
- // Check for auto mode
201
- const autoMode = script.getAttribute('data-hs-auto') === 'true';
202
- console.log(`🔍 Auto mode: ${autoMode}`);
220
+ // Process modules from script tags
221
+ const processScriptModules = () => {
222
+ console.log(`⚙️ Processing ${scripts.length} script tags`);
203
223
 
204
- // Load modules based on script attributes
205
- for (const moduleName of Object.keys(allModules)) {
206
- if (script.hasAttribute(moduleName)) {
207
- console.log(`✅ Found attribute for: ${moduleName}`);
208
- loadHsModule(moduleName);
224
+ for (const script of scripts) {
225
+ console.log(`🏷️ Processing script:`, script.src);
226
+
227
+ // Check for auto mode
228
+ const autoMode = script.getAttribute('data-hs-auto') === 'true';
229
+ console.log(`🔍 Auto mode: ${autoMode}`);
230
+
231
+ // Load modules based on script attributes
232
+ for (const moduleName of Object.keys(allModules)) {
233
+ if (script.hasAttribute(moduleName)) {
234
+ console.log(`✅ Found attribute for: ${moduleName}`);
235
+ loadHsModule(moduleName);
236
+ }
209
237
  }
210
- }
211
-
212
- // Auto-discovery mode
213
- if (autoMode) {
214
- waitDOMReady().then(() => {
215
- console.log(`🔍 Starting auto-discovery...`);
216
- const foundModules = new Set();
217
- const allElements = document.querySelectorAll('*');
218
-
219
- for (const element of allElements) {
220
- for (const attrName of element.getAttributeNames()) {
221
- // Look for data-hs-* attributes
222
- const match = attrName.match(/^(data-hs-(?:anim|util)-[^-=]+)/)?.[1];
223
- if (match && allModules[match]) {
224
- foundModules.add(match);
238
+
239
+ // Auto-discovery mode
240
+ if (autoMode) {
241
+ waitDOMReady().then(() => {
242
+ console.log(`🔍 Starting auto-discovery...`);
243
+ const foundModules = new Set();
244
+ const allElements = document.querySelectorAll('*');
245
+
246
+ for (const element of allElements) {
247
+ for (const attrName of element.getAttributeNames()) {
248
+ // Look for data-hs-* attributes
249
+ const match = attrName.match(/^(data-hs-(?:anim|util)-[^-=]+)/)?.[1];
250
+ if (match && allModules[match]) {
251
+ foundModules.add(match);
252
+ }
225
253
  }
226
254
  }
227
- }
228
-
229
- console.log(`🔍 Auto-discovered modules:`, [...foundModules]);
230
- for (const moduleName of foundModules) {
231
- loadHsModule(moduleName);
232
- }
255
+
256
+ console.log(`🔍 Auto-discovered modules:`, [...foundModules]);
257
+ for (const moduleName of foundModules) {
258
+ loadHsModule(moduleName);
259
+ }
260
+ });
261
+ }
262
+ }
263
+
264
+ // Always load auto-init modules
265
+ console.log(`🔄 Loading auto-init modules:`, Object.keys(autoInitModules));
266
+ for (const moduleName of Object.keys(autoInitModules)) {
267
+ loadHsModule(moduleName);
268
+ }
269
+
270
+ // Hide .transition elements if transition module is not loaded
271
+ const hasTransition = scripts.some(script => script.hasAttribute('data-hs-anim-transition'));
272
+ if (!hasTransition) {
273
+ const transitionElements = document.querySelectorAll('.transition');
274
+ transitionElements.forEach(element => {
275
+ element.style.display = 'none';
233
276
  });
234
277
  }
235
- }
236
-
237
- // Always load auto-init modules
238
- console.log(`🔄 Loading auto-init modules:`, Object.keys(autoInitModules));
239
- for (const moduleName of Object.keys(autoInitModules)) {
240
- loadHsModule(moduleName);
241
- }
242
-
243
- // Hide .transition elements if transition module is not loaded
244
- const hasTransition = scripts.some(script => script.hasAttribute('data-hs-anim-transition'));
245
- if (!hasTransition) {
246
- const transitionElements = document.querySelectorAll('.transition');
247
- transitionElements.forEach(element => {
248
- element.style.display = 'none';
249
- });
250
- }
251
- };
278
+ };
252
279
 
253
- // Handle rich text blocks
254
- const richTextBlocks = document.querySelectorAll('.w-richtext');
255
- richTextBlocks.forEach(block => {
256
- const images = block.querySelectorAll('img');
257
- images.forEach(img => {
258
- img.loading = 'eager';
280
+ // Handle rich text blocks
281
+ const richTextBlocks = document.querySelectorAll('.w-richtext');
282
+ richTextBlocks.forEach(block => {
283
+ const images = block.querySelectorAll('img');
284
+ images.forEach(img => {
285
+ img.loading = 'eager';
286
+ });
259
287
  });
260
- });
261
288
 
262
- // Main initialization
263
- const initializeMain = async () => {
264
- console.log(`🚀 Starting main initialization...`);
265
-
266
- // Process script modules
267
- processScriptModules();
268
-
269
- // Wait for Webflow
270
- console.log(`⏳ Waiting for Webflow...`);
271
- await waitWebflowReady();
272
- console.log(`✅ Webflow ready`);
273
-
274
- // Mark as loaded
275
- window[API_NAME].loaded = true;
276
- console.log(`🎉 ${API_NAME} fully loaded and ready!`);
277
- };
289
+ // Main initialization
290
+ const initializeMain = async () => {
291
+ console.log(`🚀 Starting main initialization...`);
292
+
293
+ // Process script modules
294
+ processScriptModules();
295
+
296
+ // Wait for Webflow
297
+ console.log(`⏳ Waiting for Webflow...`);
298
+ await waitWebflowReady();
299
+ console.log(`✅ Webflow ready`);
300
+
301
+ // Mark as loaded
302
+ window[API_NAME].loaded = true;
303
+
304
+ // Run all registered post-Webflow callbacks
305
+ console.log(`🔄 Running ${postWebflowCallbacks.length} post-Webflow callbacks`);
306
+ postWebflowCallbacks.forEach((callback, index) => {
307
+ try {
308
+ console.log(`📞 Executing callback ${index + 1}/${postWebflowCallbacks.length}`);
309
+ callback();
310
+ } catch (error) {
311
+ console.error(`❌ Callback ${index + 1} failed:`, error);
312
+ }
313
+ });
314
+
315
+ console.log(`🎉 ${API_NAME} fully loaded and ready!`);
316
+ };
317
+
318
+ // Process any early requests
319
+ console.log(`📝 Processing ${existingRequests.length} early requests`);
320
+ window[API_NAME].push(...existingRequests);
278
321
 
279
- // Process any early requests
280
- console.log(`📝 Processing ${existingRequests.length} early requests`);
281
- window[API_NAME].push(...existingRequests);
322
+ // Start initialization
323
+ initializeMain().catch(error => {
324
+ console.error(`❌ Failed to initialize ${API_NAME}:`, error);
325
+ });
326
+ };
282
327
 
283
- // Start initialization
284
- initializeMain().catch(error => {
285
- console.error(`❌ Failed to initialize ${API_NAME}:`, error);
286
- });
328
+ // Run initialization
329
+ initializeHsMain();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hortonstudio/main",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "scripts": {