@hortonstudio/main 1.9.11 → 1.9.20

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 (120) hide show
  1. package/.prettierrc +8 -0
  2. package/README.md +146 -0
  3. package/eslint.config.js +32 -0
  4. package/index.ts +275 -0
  5. package/package.json +19 -2
  6. package/public/bootstrap.js +16 -0
  7. package/src/animations/animations.ts +93 -0
  8. package/src/animations/functions/counter/counter.ts +137 -0
  9. package/src/config.json +570 -0
  10. package/src/config.ts +105 -0
  11. package/src/modules/default/README.md +167 -0
  12. package/src/modules/default/default.ts +71 -0
  13. package/{autoInit → src/modules/default/functions}/accessibility/README.md +44 -12
  14. package/src/modules/default/functions/accessibility/accessibility.ts +54 -0
  15. package/src/modules/default/functions/accordion/README.md +451 -0
  16. package/src/modules/default/functions/accordion/accordion.ts +189 -0
  17. package/src/modules/default/functions/comparison/comparison.ts +424 -0
  18. package/src/modules/default/functions/marquee/marquee.ts +206 -0
  19. package/src/modules/default/functions/navbar/README.md +393 -0
  20. package/src/modules/default/functions/navbar/functions/arrow-navigation/arrow-navigation.ts +183 -0
  21. package/src/modules/default/functions/navbar/functions/dropdown/dropdown.ts +313 -0
  22. package/src/modules/default/functions/navbar/functions/menu/menu.ts +315 -0
  23. package/src/modules/default/functions/navbar/navbar.ts +51 -0
  24. package/{autoInit → src/modules/default/functions}/smooth-scroll/README.md +45 -14
  25. package/{autoInit/smooth-scroll/smooth-scroll.js → src/modules/default/functions/smooth-scroll/smooth-scroll.ts} +33 -38
  26. package/{autoInit → src/modules/default/functions}/transition/README.md +59 -32
  27. package/src/modules/default/functions/transition/transition.ts +290 -0
  28. package/src/modules/normalize/README.md +172 -0
  29. package/src/modules/normalize/functions/clickable/README.md +84 -0
  30. package/src/modules/normalize/functions/clickable/clickable.ts +43 -0
  31. package/src/modules/normalize/functions/clickable/functions/normalize/README.md +213 -0
  32. package/src/modules/normalize/functions/clickable/functions/normalize/normalize.ts +68 -0
  33. package/src/modules/normalize/functions/dupe/README.md +405 -0
  34. package/src/modules/normalize/functions/dupe/dupe.ts +197 -0
  35. package/src/modules/normalize/functions/sync/sync.ts +378 -0
  36. package/src/modules/normalize/normalize.ts +58 -0
  37. package/src/modules/structure/README.md +190 -0
  38. package/src/modules/structure/functions/form/README.md +94 -0
  39. package/src/modules/structure/functions/form/form.ts +54 -0
  40. package/src/modules/structure/functions/form/functions/honeypot/README.md +77 -0
  41. package/src/modules/structure/functions/form/functions/honeypot/honeypot.ts +37 -0
  42. package/src/modules/structure/functions/form/functions/range/README.md +410 -0
  43. package/src/modules/structure/functions/form/functions/range/range.ts +92 -0
  44. package/src/modules/structure/functions/form/functions/select/README.md +393 -0
  45. package/src/modules/structure/functions/form/functions/select/functions/custom-select/custom-select.ts +637 -0
  46. package/src/modules/structure/functions/form/functions/select/functions/states/states.ts +118 -0
  47. package/src/modules/structure/functions/form/functions/select/select.ts +48 -0
  48. package/src/modules/structure/functions/form/functions/test/test.ts +132 -0
  49. package/{autoInit/accessibility → src/modules/structure}/functions/pagination/README.md +147 -72
  50. package/{autoInit/accessibility/functions/pagination/pagination.js → src/modules/structure/functions/pagination/pagination.ts} +98 -50
  51. package/{autoInit → src/modules/structure/functions}/site-settings/README.md +57 -27
  52. package/{autoInit/site-settings/site-settings.js → src/modules/structure/functions/site-settings/site-settings.ts} +36 -32
  53. package/{autoInit/accessibility → src/modules/structure}/functions/toc/README.md +18 -15
  54. package/{autoInit/accessibility/functions/toc/toc.js → src/modules/structure/functions/toc/functions/heading-links/heading-links.ts} +43 -63
  55. package/src/modules/structure/functions/toc/functions/progress-bar/progress-bar.ts +101 -0
  56. package/src/modules/structure/functions/toc/toc.ts +35 -0
  57. package/{autoInit/accessibility → src/modules/structure}/functions/year-replacement/README.md +7 -6
  58. package/src/modules/structure/functions/year-replacement/year-replacement.ts +59 -0
  59. package/src/modules/structure/structure.ts +59 -0
  60. package/src/utils/attributeSelector.ts +78 -0
  61. package/src/utils/cssVariables.ts +24 -0
  62. package/src/utils/gsap.ts +198 -0
  63. package/src/utils/heightAnimator.ts +130 -0
  64. package/src/utils/modalManager.ts +150 -0
  65. package/src/utils.ts +54 -0
  66. package/tsconfig.json +24 -0
  67. package/vite.config.js +45 -0
  68. package/.claude/settings.local.json +0 -70
  69. package/archive/hero.js +0 -794
  70. package/archive/modal.js +0 -80
  71. package/archive/text.js +0 -628
  72. package/autoInit/accessibility/accessibility.js +0 -53
  73. package/autoInit/accessibility/functions/blog-remover/README.md +0 -61
  74. package/autoInit/accessibility/functions/blog-remover/blog-remover.js +0 -31
  75. package/autoInit/accessibility/functions/click-forwarding/README.md +0 -60
  76. package/autoInit/accessibility/functions/click-forwarding/click-forwarding.js +0 -82
  77. package/autoInit/accessibility/functions/dropdown/README.md +0 -212
  78. package/autoInit/accessibility/functions/dropdown/dropdown.js +0 -167
  79. package/autoInit/accessibility/functions/list-accessibility/README.md +0 -56
  80. package/autoInit/accessibility/functions/list-accessibility/list-accessibility.js +0 -23
  81. package/autoInit/accessibility/functions/text-synchronization/README.md +0 -62
  82. package/autoInit/accessibility/functions/text-synchronization/text-synchronization.js +0 -101
  83. package/autoInit/accessibility/functions/year-replacement/year-replacement.js +0 -43
  84. package/autoInit/button/README.md +0 -122
  85. package/autoInit/button/button.js +0 -51
  86. package/autoInit/counter/README.md +0 -274
  87. package/autoInit/counter/counter.js +0 -185
  88. package/autoInit/form/README.md +0 -338
  89. package/autoInit/form/form.js +0 -374
  90. package/autoInit/navbar/README.md +0 -366
  91. package/autoInit/navbar/navbar.js +0 -786
  92. package/autoInit/transition/transition.js +0 -116
  93. package/index.js +0 -305
  94. package/utils/before-after/README.md +0 -520
  95. package/utils/before-after/before-after.js +0 -653
  96. package/utils/css-animations/buttons/main/bgbasic/btn-main-bgbasic.html +0 -10
  97. package/utils/css-animations/buttons/main/bgfill/btn-main-bgfill.html +0 -29
  98. package/utils/css-animations/buttons/navbar/bgbasic/navbar-main-bgbasic.html +0 -17
  99. package/utils/css-animations/buttons/navbar/bgbasic/navbar-menu-bgbasic.html +0 -16
  100. package/utils/css-animations/buttons/navbar/bgfill/navbar-main-bgfill.html +0 -46
  101. package/utils/css-animations/buttons/navbar/bgfill/navbar-menu-bgfill.html +0 -39
  102. package/utils/css-animations/buttons/navbar/color/navbar-announce-color.html +0 -5
  103. package/utils/css-animations/buttons/navbar/color/navbar-main-color.html +0 -7
  104. package/utils/css-animations/buttons/navbar/color/navbar-menu-color.html +0 -7
  105. package/utils/css-animations/buttons/navbar/double-slide/navbar-announce-double-slide.html +0 -40
  106. package/utils/css-animations/buttons/navbar/double-slide/navbar-main-double-slide.html +0 -77
  107. package/utils/css-animations/buttons/navbar/scale/navbar-announce-scale.html +0 -6
  108. package/utils/css-animations/buttons/navbar/scale/navbar-main-scale.html +0 -9
  109. package/utils/css-animations/buttons/navbar/scale/navbar-menu-scale.html +0 -8
  110. package/utils/css-animations/buttons/navbar/underline/navbar-announce-underline.html +0 -32
  111. package/utils/css-animations/buttons/navbar/underline/navbar-main-underline.html +0 -56
  112. package/utils/css-animations/buttons/text/color/text-footer-color.html +0 -5
  113. package/utils/css-animations/buttons/text/color/text-main-color.html +0 -5
  114. package/utils/css-animations/buttons/text/double-slide/text-main-double-slide.html +0 -56
  115. package/utils/css-animations/buttons/text/scale/text-footer-scale.html +0 -6
  116. package/utils/css-animations/buttons/text/scale/text-main-scale.html +0 -6
  117. package/utils/css-animations/buttons/text/underline/text-footer-underline.html +0 -45
  118. package/utils/css-animations/buttons/text/underline/text-main-underline.html +0 -58
  119. package/utils/css-animations/cards/card-clickable.html +0 -11
  120. package/utils/css-animations/defaults.html +0 -69
@@ -1,274 +0,0 @@
1
- # **Counter System Documentation**
2
-
3
- ## **Overview**
4
-
5
- The counter system provides animated number counting that triggers when the counter scrolls into view. It supports prefixes, suffixes, decimals, and automatically handles accessibility by combining all text content into an aria-label.
6
-
7
- ---
8
-
9
- ## **Counter Setup**
10
-
11
- ### **Required Elements**
12
-
13
- **Counter Wrapper** *(main wrapper of the counter)*
14
-
15
- * data-hs-counter="wrapper"
16
-
17
- **Counter Number** *(the number element to animate)*
18
-
19
- * data-hs-anim="counter"
20
- * Contains the target number with optional prefix/suffix (e.g., "20+", "$1,500", "99.9%")
21
-
22
- **Typical element layout:**
23
-
24
- 1. Counter Wrapper (data-hs-counter="wrapper")
25
- 1. Counter Number (data-hs-anim="counter")
26
- 1. Text: "20+"
27
- 2. Description Text (optional)
28
- 1. Text: "Years of Experience"
29
-
30
- ### **What It Does**
31
-
32
- 1. **Parses numbers** - Extracts prefix, number, and suffix from counter text
33
- 2. **Scroll trigger** - Uses IntersectionObserver to detect when counter enters viewport
34
- 3. **Animates count** - Counts from 0 to target number with easeOutQuart easing
35
- 4. **Accessibility** - Combines ALL text within wrapper into aria-label (e.g., "20+ Years of Experience")
36
- 5. **Respects motion preferences** - Skips animation if user has `prefers-reduced-motion` enabled
37
-
38
- ### **When It Runs**
39
-
40
- * Runs once on page load to set up observers
41
- * Triggers animation when counter scrolls into view (threshold: 0)
42
- * Each counter only animates once (tracks with `data-animated="true"`)
43
- * Runs again on Barba.js page transitions (via `reinitialize()`)
44
-
45
- ---
46
-
47
- ## **Number Formats**
48
-
49
- ### **Supported Formats**
50
-
51
- The counter automatically detects and preserves:
52
-
53
- **Prefix:**
54
- ```
55
- $1000 � Counts from $0 to $1000
56
- +500 � Counts from +0 to +500
57
- ```
58
-
59
- **Suffix:**
60
- ```
61
- 100% � Counts from 0% to 100%
62
- 50+ � Counts from 0+ to 50+
63
- 1000K � Counts from 0K to 1000K
64
- ```
65
-
66
- **Decimals:**
67
- ```
68
- 99.9 � Counts from 0.0 to 99.9 (preserves 1 decimal)
69
- 3.14159 � Counts from 0.00000 to 3.14159 (preserves 5 decimals)
70
- ```
71
-
72
- **Combined:**
73
- ```
74
- $99.99 � Counts from $0.00 to $99.99
75
- 50.5% � Counts from 0.0% to 50.5%
76
- ```
77
-
78
- ---
79
-
80
- ## **Accessibility**
81
-
82
- ### **Automatic ARIA Setup**
83
-
84
- For each counter wrapper, the system:
85
-
86
- 1. **Combines all text** - Uses TreeWalker to find all text nodes within wrapper
87
- 2. **Creates aria-label** - Joins text with spaces (e.g., "20+ Years of Experience")
88
- 3. **Sets role** - Adds `role="img"` to wrapper
89
- 4. **Hides children** - Sets `aria-hidden="true"` on all descendant elements
90
-
91
- ### **Example**
92
-
93
- ```html
94
- <!-- Before JS runs -->
95
- <div data-hs-counter="wrapper">
96
- <div data-hs-anim="counter">20+</div>
97
- <div>Years of Experience</div>
98
- </div>
99
-
100
- <!-- After JS runs -->
101
- <div data-hs-counter="wrapper" aria-label="20+ Years of Experience" role="img">
102
- <div data-hs-anim="counter" aria-hidden="true">20+</div>
103
- <div aria-hidden="true">Years of Experience</div>
104
- </div>
105
- ```
106
-
107
- Screen readers announce: "20+ Years of Experience"
108
-
109
- ---
110
-
111
- ## **Usage Examples**
112
-
113
- ### **Basic Counter**
114
-
115
- ```html
116
- <div data-hs-counter="wrapper">
117
- <div data-hs-anim="counter">1000</div>
118
- </div>
119
- ```
120
-
121
- **Result:** Counts from 0 to 1000 when scrolled into view
122
- **aria-label:** "1000"
123
-
124
- ### **Counter with Description**
125
-
126
- ```html
127
- <div data-hs-counter="wrapper">
128
- <div data-hs-anim="counter">50+</div>
129
- <p>Projects Completed</p>
130
- </div>
131
- ```
132
-
133
- **Result:** Counts from 0+ to 50+
134
- **aria-label:** "50+ Projects Completed"
135
-
136
- ### **Currency Counter**
137
-
138
- ```html
139
- <div data-hs-counter="wrapper">
140
- <div data-hs-anim="counter">$99.99</div>
141
- <p>Starting Price</p>
142
- </div>
143
- ```
144
-
145
- **Result:** Counts from $0.00 to $99.99
146
- **aria-label:** "$99.99 Starting Price"
147
-
148
- ### **Percentage Counter**
149
-
150
- ```html
151
- <div data-hs-counter="wrapper">
152
- <div data-hs-anim="counter">99.9%</div>
153
- <p>Uptime Guarantee</p>
154
- </div>
155
- ```
156
-
157
- **Result:** Counts from 0.0% to 99.9%
158
- **aria-label:** "99.9% Uptime Guarantee"
159
-
160
- ---
161
-
162
- ## **Configuration**
163
-
164
- ### **Default Settings**
165
-
166
- ```javascript
167
- {
168
- duration: 3000 // Animation duration in milliseconds
169
- }
170
- ```
171
-
172
- ### **Updating Config**
173
-
174
- ```javascript
175
- window.hsmain.counter.updateConfig({
176
- duration: 2000 // Faster animation
177
- });
178
- ```
179
-
180
- **Note:** Config changes only affect counters that haven't animated yet.
181
-
182
- ---
183
-
184
- ## **API Methods**
185
-
186
- ### **Trigger Animation Manually**
187
-
188
- ```javascript
189
- window.hsmain.counter.triggerAnimation('[data-hs-counter="wrapper"]');
190
- ```
191
-
192
- Manually triggers animation for a specific counter (bypasses scroll detection).
193
-
194
- ### **Reset All Counters**
195
-
196
- ```javascript
197
- window.hsmain.counter.reset();
198
- ```
199
-
200
- Resets all counters to original state and re-enables scroll triggers.
201
-
202
- ### **Access Counter Elements**
203
-
204
- ```javascript
205
- window.hsmain.counter.counters
206
- ```
207
-
208
- Returns array of all counter wrapper elements.
209
-
210
- ---
211
-
212
- ## **Animation Behavior**
213
-
214
- ### **Easing Function**
215
-
216
- Uses **easeOutQuart** for smooth deceleration:
217
- - Starts fast
218
- - Slows down as it approaches target
219
- - Creates natural counting effect
220
-
221
- ### **Reduced Motion**
222
-
223
- If user has `prefers-reduced-motion: reduce` enabled:
224
- - Skips animation entirely
225
- - Shows final number immediately
226
- - Respects user accessibility preferences
227
-
228
- ---
229
-
230
- ## **Key Attributes Summary**
231
-
232
- | Attribute | Purpose | Required On |
233
- | ----- | ----- | ----- |
234
- | `data-hs-counter="wrapper"` | Counter container | Wrapper div |
235
- | `data-hs-anim="counter"` | Number to animate | Number element |
236
-
237
- ---
238
-
239
- ## **Notes**
240
-
241
- 1. **One-time animation** - Each counter animates only once when first scrolled into view
242
- 2. **IntersectionObserver** - Uses `threshold: 0` (triggers as soon as any part is visible)
243
- 3. **Original text preserved** - Stores original value in `data-hs-original` attribute
244
- 4. **Barba.js compatible** - Automatically reinitializes on page transitions
245
- 5. **No visual component** - Works with any styling, just handles number animation and a11y
246
-
247
- ---
248
-
249
- ## **Common Issues**
250
-
251
- **Counter not animating:**
252
-
253
- 1. Verify `data-hs-counter="wrapper"` is on container element
254
- 2. Check that `data-hs-anim="counter"` is on number element
255
- 3. Ensure number element contains parseable number
256
- 4. Check if `prefers-reduced-motion` is enabled (animation skips)
257
-
258
- **Wrong number format:**
259
-
260
- 1. Counter auto-detects prefix/suffix - ensure format is: `[prefix][number][suffix]`
261
- 2. Decimals are auto-detected from original number
262
- 3. Use dot (.) for decimal separator, not comma
263
-
264
- **Aria-label missing text:**
265
-
266
- 1. Ensure all text is within `[data-hs-counter="wrapper"]`
267
- 2. Check that text nodes have actual content (not just whitespace)
268
- 3. Verify elements aren't hidden with `display: none` when script runs
269
-
270
- **Counter animates multiple times:**
271
-
272
- 1. This shouldn't happen - check if `reset()` is being called unintentionally
273
- 2. Verify `data-animated` attribute is being set correctly
274
- 3. Check for multiple script instances running
@@ -1,185 +0,0 @@
1
- export function init() {
2
- const config = {
3
- duration: 3000,
4
- };
5
-
6
- let counters = [];
7
- let observer = null;
8
-
9
- function updateConfig(newConfig) {
10
- Object.assign(config, newConfig);
11
- }
12
-
13
- function easeOutQuart(t) {
14
- return 1 - Math.pow(1 - t, 4);
15
- }
16
-
17
- function parseText(text) {
18
- const match = text.match(/([^\d.]*)(\d*\.?\d+)(.*)/);
19
- return {
20
- prefix: match[1] || "",
21
- number: parseFloat(match[2]),
22
- suffix: match[3] || "",
23
- };
24
- }
25
-
26
- function formatNumber(value, prefix, suffix, decimals = 0) {
27
- const formattedNumber = decimals > 0 ? value.toFixed(decimals) : Math.round(value);
28
- return `${prefix}${formattedNumber}${suffix}`;
29
- }
30
-
31
- function prefersReducedMotion() {
32
- return window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
33
- }
34
-
35
- function animateCounter(element, targetValue, prefix, suffix, decimals) {
36
- if (prefersReducedMotion()) {
37
- element.textContent = element.getAttribute("data-hs-original");
38
- return;
39
- }
40
-
41
- const startTime = Date.now();
42
- const startValue = 0;
43
-
44
- const animate = () => {
45
- const elapsed = Date.now() - startTime;
46
- const progress = Math.min(elapsed / config.duration, 1);
47
- const easedProgress = easeOutQuart(progress);
48
- const currentValue = startValue + (targetValue - startValue) * easedProgress;
49
-
50
- element.textContent = formatNumber(currentValue, prefix, suffix, decimals);
51
-
52
- if (progress < 1) {
53
- requestAnimationFrame(animate);
54
- } else {
55
- element.textContent = element.getAttribute("data-hs-original");
56
- }
57
- };
58
-
59
- element.textContent = formatNumber(0, prefix, suffix, decimals);
60
- requestAnimationFrame(animate);
61
- }
62
-
63
- function setupObserver() {
64
- observer = new IntersectionObserver((entries) => {
65
- entries.forEach((entry) => {
66
- if (entry.isIntersecting && !entry.target.dataset.animated) {
67
- const numberElement = entry.target.querySelector('[data-hs-anim="counter"]');
68
- startAnimation(numberElement);
69
- entry.target.dataset.animated = "true";
70
- }
71
- });
72
- }, { threshold: 0 });
73
- }
74
-
75
- function startAnimation(element) {
76
- const originalText = element.getAttribute("data-hs-original");
77
- const parsed = parseText(originalText);
78
- const decimals = (parsed.number.toString().split(".")[1] || "").length;
79
-
80
- animateCounter(element, parsed.number, parsed.prefix, parsed.suffix, decimals);
81
- }
82
-
83
- function setupStatsAccessibility() {
84
- const statsElements = document.querySelectorAll('[data-hs-counter="wrapper"]');
85
-
86
- statsElements.forEach((element) => {
87
- // Collect all text nodes and join with spaces
88
- const walker = document.createTreeWalker(
89
- element,
90
- NodeFilter.SHOW_TEXT,
91
- null
92
- );
93
-
94
- const textParts = [];
95
- let node;
96
- while (node = walker.nextNode()) {
97
- const text = node.textContent.trim();
98
- if (text) {
99
- textParts.push(text);
100
- }
101
- }
102
-
103
- const allText = textParts.join(' ');
104
-
105
- element.setAttribute("aria-label", allText);
106
- element.setAttribute("role", "img");
107
-
108
- const allChildren = element.querySelectorAll("*");
109
- allChildren.forEach((child) => {
110
- child.setAttribute("aria-hidden", "true");
111
- });
112
- });
113
- }
114
-
115
- function initCounters() {
116
- const wrappers = document.querySelectorAll('[data-hs-counter="wrapper"]');
117
-
118
- wrappers.forEach((wrapper) => {
119
- const numberElement = wrapper.querySelector('[data-hs-anim="counter"]');
120
- const parsed = parseText(numberElement.textContent.trim());
121
-
122
- numberElement.setAttribute("data-hs-original", numberElement.textContent.trim());
123
- counters.push(wrapper);
124
- });
125
-
126
- setupObserver();
127
-
128
- counters.forEach((counter) => {
129
- observer.observe(counter);
130
- });
131
-
132
- setupStatsAccessibility();
133
- }
134
-
135
- function triggerAnimation(selector) {
136
- const wrapper = document.querySelector(selector);
137
- const numberElement = wrapper.querySelector('[data-hs-anim="counter"]');
138
- startAnimation(numberElement);
139
- wrapper.dataset.animated = "true";
140
- }
141
-
142
- function reset() {
143
- counters.forEach((wrapper) => {
144
- delete wrapper.dataset.animated;
145
- const numberElement = wrapper.querySelector('[data-hs-anim="counter"]');
146
- numberElement.textContent = numberElement.getAttribute("data-hs-original");
147
- });
148
-
149
- counters.forEach((counter) => {
150
- observer.unobserve(counter);
151
- observer.observe(counter);
152
- });
153
-
154
- setupStatsAccessibility();
155
- }
156
-
157
- initCounters();
158
-
159
- window.hsmain = window.hsmain || {};
160
- window.hsmain.counter = {
161
- config,
162
- updateConfig,
163
- triggerAnimation,
164
- reset,
165
- counters,
166
- };
167
-
168
- return {
169
- result: "counter initialized",
170
- destroy: () => {
171
- // Disconnect observer
172
- if (observer) {
173
- observer.disconnect();
174
- }
175
-
176
- // Clear counters array
177
- counters.length = 0;
178
-
179
- // Remove window API
180
- if (window.hsmain && window.hsmain.counter) {
181
- delete window.hsmain.counter;
182
- }
183
- }
184
- };
185
- }