@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.
- package/index.js +288 -245
- package/package.json +1 -1
package/index.js
CHANGED
@@ -1,286 +1,329 @@
|
|
1
|
-
// ver 1.2.
|
1
|
+
// ver 1.2.6
|
2
2
|
|
3
3
|
const API_NAME = 'hsmain';
|
4
4
|
|
5
|
-
console.log(`🟢 ${API_NAME} v1.2.
|
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
|
-
//
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
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
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
125
|
-
|
126
|
-
|
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
|
-
|
131
|
-
|
132
|
-
|
133
|
-
};
|
104
|
+
// Create module object
|
105
|
+
const moduleObj = apiInstance.modules[moduleName] || {};
|
106
|
+
apiInstance.modules[moduleName] = moduleObj;
|
134
107
|
|
135
|
-
|
136
|
-
|
137
|
-
|
108
|
+
// Create loading promise
|
109
|
+
moduleObj.loading = new Promise((resolve, reject) => {
|
110
|
+
moduleObj.resolve = resolve;
|
111
|
+
moduleObj.reject = reject;
|
112
|
+
});
|
138
113
|
|
139
|
-
|
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
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
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
|
-
//
|
150
|
-
|
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.
|
162
|
-
|
163
|
-
|
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:
|
180
|
-
loading:
|
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
|
-
|
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
|
-
|
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
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
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
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
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
|
-
|
230
|
-
|
231
|
-
|
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
|
-
|
257
|
-
|
258
|
-
|
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
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
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
|
-
//
|
280
|
-
|
281
|
-
|
322
|
+
// Start initialization
|
323
|
+
initializeMain().catch(error => {
|
324
|
+
console.error(`❌ Failed to initialize ${API_NAME}:`, error);
|
325
|
+
});
|
326
|
+
};
|
282
327
|
|
283
|
-
//
|
284
|
-
|
285
|
-
console.error(`❌ Failed to initialize ${API_NAME}:`, error);
|
286
|
-
});
|
328
|
+
// Run initialization
|
329
|
+
initializeHsMain();
|