@hortonstudio/main 1.2.8 → 1.2.11
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/animations/hero.js +69 -0
- package/animations/text.js +72 -8
- package/index.js +5 -42
- package/package.json +1 -1
package/animations/hero.js
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
const API_NAME = 'hsmain';
|
2
2
|
|
3
|
+
// Check for reduced motion preference
|
4
|
+
const prefersReducedMotion = () => {
|
5
|
+
return window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
6
|
+
};
|
7
|
+
|
3
8
|
// Animation timing (in seconds)
|
4
9
|
const timing = {
|
5
10
|
announce: 0,
|
@@ -119,12 +124,76 @@ function startHeroAnimations() {
|
|
119
124
|
init();
|
120
125
|
}
|
121
126
|
|
127
|
+
function showHeroElementsWithoutAnimation() {
|
128
|
+
// Simply show all hero elements without any animation or split text
|
129
|
+
const allHeroElements = [
|
130
|
+
...document.querySelectorAll('[data-hs-hero="announce"]'),
|
131
|
+
...document.querySelectorAll('[data-hs-hero="nav"]'),
|
132
|
+
...document.querySelectorAll('[data-hs-hero="nav-menu"]'),
|
133
|
+
...document.querySelectorAll('[data-hs-hero="nav-logo"]'),
|
134
|
+
...document.querySelectorAll('[data-hs-hero="nav-button"] > *:first-child'),
|
135
|
+
...document.querySelectorAll('[data-hs-hero="nav-list"] > * > *:first-child'),
|
136
|
+
...document.querySelectorAll('[data-hs-hero="heading"] > *:first-child'),
|
137
|
+
...document.querySelectorAll('[data-hs-hero="subheading"] > *:first-child'),
|
138
|
+
...document.querySelectorAll('[data-hs-hero="tag"] > *:first-child'),
|
139
|
+
...document.querySelectorAll('[data-hs-hero="button"] > *'),
|
140
|
+
...document.querySelectorAll('[data-hs-hero="image"]'),
|
141
|
+
...document.querySelectorAll('[data-hs-hero="appear"]')
|
142
|
+
];
|
143
|
+
|
144
|
+
allHeroElements.forEach(element => {
|
145
|
+
if (element) {
|
146
|
+
gsap.set(element, {
|
147
|
+
autoAlpha: 1,
|
148
|
+
opacity: 1,
|
149
|
+
y: 0,
|
150
|
+
yPercent: 0
|
151
|
+
});
|
152
|
+
// Remove any pointer-events restrictions
|
153
|
+
element.style.pointerEvents = '';
|
154
|
+
}
|
155
|
+
});
|
156
|
+
|
157
|
+
// Restore page-wide tabbing
|
158
|
+
const allFocusableElements = document.querySelectorAll('[data-original-tabindex]');
|
159
|
+
allFocusableElements.forEach(el => {
|
160
|
+
el.style.pointerEvents = '';
|
161
|
+
const originalTabindex = el.getAttribute('data-original-tabindex');
|
162
|
+
if (originalTabindex === '0') {
|
163
|
+
el.removeAttribute('tabindex');
|
164
|
+
} else {
|
165
|
+
el.setAttribute('tabindex', originalTabindex);
|
166
|
+
}
|
167
|
+
el.removeAttribute('data-original-tabindex');
|
168
|
+
});
|
169
|
+
}
|
170
|
+
|
122
171
|
export async function init() {
|
123
172
|
if (typeof window.gsap === "undefined") {
|
124
173
|
console.error('GSAP not found - hero animations disabled');
|
125
174
|
return;
|
126
175
|
}
|
127
176
|
|
177
|
+
if (prefersReducedMotion()) {
|
178
|
+
// For reduced motion, just show elements without animation
|
179
|
+
showHeroElementsWithoutAnimation();
|
180
|
+
|
181
|
+
// Still expose the API for consistency
|
182
|
+
window[API_NAME] = window[API_NAME] || {};
|
183
|
+
window[API_NAME].heroAnimations = {
|
184
|
+
config: config,
|
185
|
+
updateConfig: updateConfig,
|
186
|
+
start: startHeroAnimations,
|
187
|
+
kill: killHeroAnimations,
|
188
|
+
restart: () => {
|
189
|
+
killHeroAnimations();
|
190
|
+
startHeroAnimations();
|
191
|
+
}
|
192
|
+
};
|
193
|
+
|
194
|
+
return { result: 'anim-hero initialized (reduced motion)' };
|
195
|
+
}
|
196
|
+
|
128
197
|
gsap.registerPlugin(ScrollTrigger, SplitText);
|
129
198
|
|
130
199
|
// Element selection
|
package/animations/text.js
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
const API_NAME = 'hsmain';
|
2
2
|
|
3
|
+
// Check for reduced motion preference
|
4
|
+
const prefersReducedMotion = () => {
|
5
|
+
return window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
6
|
+
};
|
7
|
+
|
3
8
|
const config = {
|
4
9
|
global: {
|
5
10
|
animationDelay: 0
|
@@ -62,6 +67,12 @@ function killTextAnimations() {
|
|
62
67
|
}
|
63
68
|
|
64
69
|
function startTextAnimations() {
|
70
|
+
if (prefersReducedMotion()) {
|
71
|
+
// For reduced motion, just show elements without animation
|
72
|
+
showElementsWithoutAnimation();
|
73
|
+
return;
|
74
|
+
}
|
75
|
+
|
65
76
|
setInitialStates().then(() => {
|
66
77
|
initAnimations();
|
67
78
|
});
|
@@ -73,14 +84,36 @@ function waitForFonts() {
|
|
73
84
|
return document.fonts.ready;
|
74
85
|
}
|
75
86
|
|
87
|
+
function showElementsWithoutAnimation() {
|
88
|
+
// Simply show all text elements without any animation or split text
|
89
|
+
const allTextElements = [
|
90
|
+
...document.querySelectorAll(".a-char-split > *:first-child"),
|
91
|
+
...document.querySelectorAll(".a-word-split > *:first-child"),
|
92
|
+
...document.querySelectorAll(".a-line-split > *:first-child"),
|
93
|
+
...document.querySelectorAll('.a-appear')
|
94
|
+
];
|
95
|
+
|
96
|
+
allTextElements.forEach(element => {
|
97
|
+
gsap.set(element, {
|
98
|
+
autoAlpha: 1,
|
99
|
+
y: 0,
|
100
|
+
yPercent: 0,
|
101
|
+
opacity: 1
|
102
|
+
});
|
103
|
+
});
|
104
|
+
}
|
105
|
+
|
76
106
|
const CharSplitAnimations = {
|
77
107
|
async initial() {
|
78
108
|
await waitForFonts();
|
79
109
|
|
110
|
+
if (prefersReducedMotion()) {
|
111
|
+
return;
|
112
|
+
}
|
113
|
+
|
80
114
|
const elements = document.querySelectorAll(".a-char-split > *:first-child");
|
81
115
|
|
82
|
-
elements.forEach((textElement
|
83
|
-
|
116
|
+
elements.forEach((textElement) => {
|
84
117
|
const split = SplitText.create(textElement, {
|
85
118
|
type: "chars",
|
86
119
|
mask: "chars",
|
@@ -98,6 +131,10 @@ const CharSplitAnimations = {
|
|
98
131
|
async animate() {
|
99
132
|
await waitForFonts();
|
100
133
|
|
134
|
+
if (prefersReducedMotion()) {
|
135
|
+
return;
|
136
|
+
}
|
137
|
+
|
101
138
|
document.querySelectorAll(".a-char-split > *:first-child").forEach((textElement) => {
|
102
139
|
const chars = textElement.querySelectorAll('.char');
|
103
140
|
const tl = gsap.timeline({
|
@@ -127,10 +164,13 @@ const WordSplitAnimations = {
|
|
127
164
|
async initial() {
|
128
165
|
await waitForFonts();
|
129
166
|
|
167
|
+
if (prefersReducedMotion()) {
|
168
|
+
return;
|
169
|
+
}
|
170
|
+
|
130
171
|
const elements = document.querySelectorAll(".a-word-split > *:first-child");
|
131
172
|
|
132
|
-
elements.forEach((textElement
|
133
|
-
|
173
|
+
elements.forEach((textElement) => {
|
134
174
|
const split = SplitText.create(textElement, {
|
135
175
|
type: "words",
|
136
176
|
mask: "words",
|
@@ -148,6 +188,10 @@ const WordSplitAnimations = {
|
|
148
188
|
async animate() {
|
149
189
|
await waitForFonts();
|
150
190
|
|
191
|
+
if (prefersReducedMotion()) {
|
192
|
+
return;
|
193
|
+
}
|
194
|
+
|
151
195
|
document.querySelectorAll(".a-word-split > *:first-child").forEach((textElement) => {
|
152
196
|
const words = textElement.querySelectorAll('.word');
|
153
197
|
const tl = gsap.timeline({
|
@@ -177,10 +221,13 @@ const LineSplitAnimations = {
|
|
177
221
|
async initial() {
|
178
222
|
await waitForFonts();
|
179
223
|
|
224
|
+
if (prefersReducedMotion()) {
|
225
|
+
return;
|
226
|
+
}
|
227
|
+
|
180
228
|
const elements = document.querySelectorAll(".a-line-split > *:first-child");
|
181
229
|
|
182
|
-
elements.forEach((textElement
|
183
|
-
|
230
|
+
elements.forEach((textElement) => {
|
184
231
|
const split = SplitText.create(textElement, {
|
185
232
|
type: "lines",
|
186
233
|
mask: "lines",
|
@@ -198,6 +245,10 @@ const LineSplitAnimations = {
|
|
198
245
|
async animate() {
|
199
246
|
await waitForFonts();
|
200
247
|
|
248
|
+
if (prefersReducedMotion()) {
|
249
|
+
return;
|
250
|
+
}
|
251
|
+
|
201
252
|
document.querySelectorAll(".a-line-split > *:first-child").forEach((textElement) => {
|
202
253
|
const lines = textElement.querySelectorAll('.line');
|
203
254
|
const tl = gsap.timeline({
|
@@ -227,6 +278,10 @@ const AppearAnimations = {
|
|
227
278
|
async initial() {
|
228
279
|
await waitForFonts();
|
229
280
|
|
281
|
+
if (prefersReducedMotion()) {
|
282
|
+
return;
|
283
|
+
}
|
284
|
+
|
230
285
|
const elements = document.querySelectorAll('.a-appear');
|
231
286
|
elements.forEach(element => {
|
232
287
|
gsap.set(element, {
|
@@ -239,6 +294,10 @@ const AppearAnimations = {
|
|
239
294
|
async animate() {
|
240
295
|
await waitForFonts();
|
241
296
|
|
297
|
+
if (prefersReducedMotion()) {
|
298
|
+
return;
|
299
|
+
}
|
300
|
+
|
242
301
|
document.querySelectorAll('.a-appear').forEach(element => {
|
243
302
|
const tl = gsap.timeline({
|
244
303
|
scrollTrigger: {
|
@@ -284,8 +343,13 @@ async function initAnimations() {
|
|
284
343
|
}
|
285
344
|
|
286
345
|
export async function init() {
|
287
|
-
|
288
|
-
|
346
|
+
if (prefersReducedMotion()) {
|
347
|
+
// For reduced motion, just show elements without animation
|
348
|
+
showElementsWithoutAnimation();
|
349
|
+
} else {
|
350
|
+
await setInitialStates();
|
351
|
+
initAnimations();
|
352
|
+
}
|
289
353
|
|
290
354
|
window.addEventListener('resize', ScrollTrigger.refresh());
|
291
355
|
|
package/index.js
CHANGED
@@ -1,16 +1,11 @@
|
|
1
|
-
// ver 1.2.
|
1
|
+
// ver 1.2.11
|
2
2
|
|
3
3
|
const API_NAME = 'hsmain';
|
4
4
|
|
5
|
-
console.log(`🟢 ${API_NAME} v1.2.6 initializing...`);
|
6
|
-
console.log('🔍 DOM state:', document.readyState);
|
7
|
-
console.log('🔍 Script URL:', import.meta.url);
|
8
|
-
|
9
5
|
// Main initialization function
|
10
6
|
const initializeHsMain = () => {
|
11
7
|
// Handle existing API
|
12
8
|
if (window[API_NAME] && !Array.isArray(window[API_NAME]) && window[API_NAME].loaded) {
|
13
|
-
console.log('⚠️ API already loaded, skipping initialization');
|
14
9
|
return;
|
15
10
|
}
|
16
11
|
|
@@ -39,8 +34,6 @@ const initializeHsMain = () => {
|
|
39
34
|
|
40
35
|
// Dynamic module loader (like Finsweet)
|
41
36
|
const loadModule = async (moduleName) => {
|
42
|
-
console.log(`📦 Loading module: ${moduleName}`);
|
43
|
-
|
44
37
|
switch (moduleName) {
|
45
38
|
case "data-hs-anim-text":
|
46
39
|
return import(new URL('./animations/text.js', import.meta.url).href);
|
@@ -57,7 +50,6 @@ const initializeHsMain = () => {
|
|
57
50
|
case "smooth-scroll":
|
58
51
|
return import(new URL('./autoInit/smooth-scroll.js', import.meta.url).href);
|
59
52
|
default:
|
60
|
-
console.error(`❌ Unsupported module: ${moduleName}`);
|
61
53
|
throw new Error(`${API_NAME} module "${moduleName}" is not supported.`);
|
62
54
|
}
|
63
55
|
};
|
@@ -83,22 +75,17 @@ const initializeHsMain = () => {
|
|
83
75
|
|
84
76
|
// Find script tags (Finsweet approach)
|
85
77
|
const scripts = [...document.querySelectorAll(`script[type="module"][src="${import.meta.url}"]`)];
|
86
|
-
console.log(`📄 Found ${scripts.length} matching script tags`);
|
87
78
|
|
88
79
|
// Module loading function
|
89
80
|
const loadHsModule = async (moduleName) => {
|
90
|
-
console.log(`🔄 loadHsModule called for: ${moduleName}`);
|
91
|
-
|
92
81
|
const apiInstance = window[API_NAME];
|
93
82
|
|
94
83
|
// Check if already processing
|
95
84
|
if (apiInstance.process.has(moduleName)) {
|
96
|
-
console.log(`⚠️ Module ${moduleName} already processing`);
|
97
85
|
return apiInstance.modules[moduleName]?.loading;
|
98
86
|
}
|
99
87
|
|
100
88
|
// Add to processing set
|
101
|
-
console.log(`➕ Adding ${moduleName} to process set`);
|
102
89
|
apiInstance.process.add(moduleName);
|
103
90
|
|
104
91
|
// Create module object
|
@@ -112,14 +99,9 @@ const initializeHsMain = () => {
|
|
112
99
|
});
|
113
100
|
|
114
101
|
try {
|
115
|
-
console.log(`📦 Importing ${moduleName}...`);
|
116
102
|
const { init, version } = await loadModule(moduleName);
|
117
|
-
console.log(`✅ ${moduleName} imported, version: ${version}`);
|
118
|
-
|
119
|
-
console.log(`🔧 Initializing ${moduleName}...`);
|
120
103
|
const initResult = await init();
|
121
104
|
const { result, destroy } = initResult || {};
|
122
|
-
console.log(`✅ ${moduleName} initialized:`, result);
|
123
105
|
|
124
106
|
moduleObj.version = version;
|
125
107
|
|
@@ -141,7 +123,6 @@ const initializeHsMain = () => {
|
|
141
123
|
return result;
|
142
124
|
|
143
125
|
} catch (error) {
|
144
|
-
console.error(`❌ Failed to load ${moduleName}:`, error);
|
145
126
|
moduleObj.reject?.(error);
|
146
127
|
apiInstance.process.delete(moduleName);
|
147
128
|
throw error;
|
@@ -219,19 +200,13 @@ const initializeHsMain = () => {
|
|
219
200
|
|
220
201
|
// Process modules from script tags
|
221
202
|
const processScriptModules = () => {
|
222
|
-
console.log(`⚙️ Processing ${scripts.length} script tags`);
|
223
|
-
|
224
203
|
for (const script of scripts) {
|
225
|
-
console.log(`🏷️ Processing script:`, script.src);
|
226
|
-
|
227
204
|
// Check for auto mode
|
228
205
|
const autoMode = script.getAttribute('data-hs-auto') === 'true';
|
229
|
-
console.log(`🔍 Auto mode: ${autoMode}`);
|
230
206
|
|
231
207
|
// Load modules based on script attributes
|
232
208
|
for (const moduleName of Object.keys(allModules)) {
|
233
209
|
if (script.hasAttribute(moduleName)) {
|
234
|
-
console.log(`✅ Found attribute for: ${moduleName}`);
|
235
210
|
loadHsModule(moduleName);
|
236
211
|
}
|
237
212
|
}
|
@@ -239,7 +214,6 @@ const initializeHsMain = () => {
|
|
239
214
|
// Auto-discovery mode
|
240
215
|
if (autoMode) {
|
241
216
|
waitDOMReady().then(() => {
|
242
|
-
console.log(`🔍 Starting auto-discovery...`);
|
243
217
|
const foundModules = new Set();
|
244
218
|
const allElements = document.querySelectorAll('*');
|
245
219
|
|
@@ -253,7 +227,6 @@ const initializeHsMain = () => {
|
|
253
227
|
}
|
254
228
|
}
|
255
229
|
|
256
|
-
console.log(`🔍 Auto-discovered modules:`, [...foundModules]);
|
257
230
|
for (const moduleName of foundModules) {
|
258
231
|
loadHsModule(moduleName);
|
259
232
|
}
|
@@ -262,7 +235,6 @@ const initializeHsMain = () => {
|
|
262
235
|
}
|
263
236
|
|
264
237
|
// Always load auto-init modules
|
265
|
-
console.log(`🔄 Loading auto-init modules:`, Object.keys(autoInitModules));
|
266
238
|
for (const moduleName of Object.keys(autoInitModules)) {
|
267
239
|
loadHsModule(moduleName);
|
268
240
|
}
|
@@ -288,40 +260,31 @@ const initializeHsMain = () => {
|
|
288
260
|
|
289
261
|
// Main initialization
|
290
262
|
const initializeMain = async () => {
|
291
|
-
console.log(`🚀 Starting main initialization...`);
|
292
|
-
|
293
263
|
// Process script modules
|
294
264
|
processScriptModules();
|
295
265
|
|
296
266
|
// Wait for Webflow
|
297
|
-
console.log(`⏳ Waiting for Webflow...`);
|
298
267
|
await waitWebflowReady();
|
299
|
-
console.log(`✅ Webflow ready`);
|
300
268
|
|
301
269
|
// Mark as loaded
|
302
270
|
window[API_NAME].loaded = true;
|
303
271
|
|
304
272
|
// Run all registered post-Webflow callbacks
|
305
|
-
|
306
|
-
postWebflowCallbacks.forEach((callback, index) => {
|
273
|
+
postWebflowCallbacks.forEach((callback) => {
|
307
274
|
try {
|
308
|
-
console.log(`📞 Executing callback ${index + 1}/${postWebflowCallbacks.length}`);
|
309
275
|
callback();
|
310
276
|
} catch (error) {
|
311
|
-
|
277
|
+
// Silent fail for callbacks
|
312
278
|
}
|
313
279
|
});
|
314
|
-
|
315
|
-
console.log(`🎉 ${API_NAME} fully loaded and ready!`);
|
316
280
|
};
|
317
281
|
|
318
282
|
// Process any early requests
|
319
|
-
console.log(`📝 Processing ${existingRequests.length} early requests`);
|
320
283
|
window[API_NAME].push(...existingRequests);
|
321
284
|
|
322
285
|
// Start initialization
|
323
|
-
initializeMain().catch(
|
324
|
-
|
286
|
+
initializeMain().catch(() => {
|
287
|
+
// Silent fail for initialization
|
325
288
|
});
|
326
289
|
};
|
327
290
|
|