@hortonstudio/main 1.9.6 → 1.9.7
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/autoInit/accessibility/README.md +126 -0
- package/autoInit/accessibility/accessibility.js +56 -0
- package/autoInit/accessibility/functions/blog-remover/README.md +61 -0
- package/autoInit/accessibility/functions/blog-remover/blog-remover.js +31 -0
- package/autoInit/accessibility/functions/click-forwarding/README.md +60 -0
- package/autoInit/accessibility/functions/click-forwarding/click-forwarding.js +82 -0
- package/autoInit/accessibility/functions/convert-to-span/README.md +59 -0
- package/autoInit/accessibility/functions/convert-to-span/convert-to-span.js +70 -0
- package/autoInit/accessibility/functions/custom-values-replacement/README.md +71 -0
- package/autoInit/accessibility/functions/custom-values-replacement/custom-values-replacement.js +102 -0
- package/autoInit/accessibility/functions/dropdown/README.md +212 -0
- package/autoInit/accessibility/functions/dropdown/dropdown.js +167 -0
- package/autoInit/accessibility/functions/list-accessibility/README.md +56 -0
- package/autoInit/accessibility/functions/list-accessibility/list-accessibility.js +23 -0
- package/autoInit/accessibility/functions/prevent-default/README.md +58 -0
- package/autoInit/accessibility/functions/prevent-default/prevent-default.js +58 -0
- package/autoInit/accessibility/functions/remove-list-accessibility/README.md +57 -0
- package/autoInit/accessibility/functions/remove-list-accessibility/remove-list-accessibility.js +68 -0
- package/autoInit/accessibility/functions/text-synchronization/README.md +62 -0
- package/autoInit/accessibility/functions/text-synchronization/text-synchronization.js +101 -0
- package/autoInit/accessibility/functions/toc/README.md +79 -0
- package/autoInit/accessibility/functions/toc/toc.js +191 -0
- package/autoInit/accessibility/functions/year-replacement/README.md +54 -0
- package/autoInit/accessibility/functions/year-replacement/year-replacement.js +43 -0
- package/autoInit/button/README.md +122 -0
- package/autoInit/counter/README.md +274 -0
- package/autoInit/{counter.js → counter/counter.js} +20 -5
- package/autoInit/form/README.md +338 -0
- package/autoInit/{form.js → form/form.js} +44 -29
- package/autoInit/navbar/README.md +366 -0
- package/autoInit/site-settings/README.md +218 -0
- package/autoInit/smooth-scroll/README.md +386 -0
- package/autoInit/transition/README.md +301 -0
- package/autoInit/{transition.js → transition/transition.js} +13 -2
- package/index.js +7 -7
- package/package.json +1 -1
- package/autoInit/accessibility.js +0 -786
- /package/autoInit/{button.js → button/button.js} +0 -0
- /package/autoInit/{site-settings.js → site-settings/site-settings.js} +0 -0
- /package/autoInit/{smooth-scroll.js → smooth-scroll/smooth-scroll.js} +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# **Button Icon System Documentation**
|
|
2
|
+
|
|
3
|
+
## **Overview**
|
|
4
|
+
|
|
5
|
+
The button icon system automatically clones icons from a "main" slot to a "placeholder" slot within button wrappers. This allows for consistent icon duplication for animation or styling purposes.
|
|
6
|
+
|
|
7
|
+
**Note:** This functionality is **already set up** in the Global / Button components. This documentation is for custom button implementations that require this icon cloning behavior.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## **Button Icon Cloning**
|
|
12
|
+
|
|
13
|
+
### **Required Elements**
|
|
14
|
+
|
|
15
|
+
**Button Wrapper** *(main wrapper of the button)*
|
|
16
|
+
|
|
17
|
+
* data-site-button="wrapper"
|
|
18
|
+
|
|
19
|
+
**Icon Wrapper** *(wraps both main and placeholder icons)*
|
|
20
|
+
|
|
21
|
+
* data-site-button-icon="wrapper"
|
|
22
|
+
|
|
23
|
+
**Main Icon** *(the source icon to be cloned)*
|
|
24
|
+
|
|
25
|
+
* data-site-button-icon="main"
|
|
26
|
+
* Contains: `[data-site-icon="slot"]` (the actual icon element)
|
|
27
|
+
|
|
28
|
+
**Placeholder Icon** *(the destination for the cloned icon)*
|
|
29
|
+
|
|
30
|
+
* data-site-button-icon="placeholder"
|
|
31
|
+
* Contains: `[data-site-icon="slot"]` (will be replaced with cloned icon)
|
|
32
|
+
|
|
33
|
+
**Typical element layout:**
|
|
34
|
+
|
|
35
|
+
1. Button Wrapper (data-site-button="wrapper")
|
|
36
|
+
1. Button Content
|
|
37
|
+
1. Icon Wrapper (data-site-button-icon="wrapper")
|
|
38
|
+
1. Main Icon (data-site-button-icon="main")
|
|
39
|
+
1. Icon Slot (data-site-icon="slot")
|
|
40
|
+
1. SVG or Icon Element
|
|
41
|
+
2. Placeholder Icon (data-site-button-icon="placeholder")
|
|
42
|
+
1. Icon Slot (data-site-icon="slot")
|
|
43
|
+
1. Empty (will be replaced)
|
|
44
|
+
|
|
45
|
+
### **What It Does**
|
|
46
|
+
|
|
47
|
+
1. **Finds all button wrappers** with `[data-site-button="wrapper"]`
|
|
48
|
+
2. **Checks for icon wrapper** - If no `[data-site-button-icon="wrapper"]`, skips button
|
|
49
|
+
3. **Clones main icon** - Gets first `[data-site-icon="slot"]` inside main icon
|
|
50
|
+
4. **Replaces placeholder** - Swaps placeholder slot with cloned main slot
|
|
51
|
+
|
|
52
|
+
### **When It Runs**
|
|
53
|
+
|
|
54
|
+
* Runs once on page load
|
|
55
|
+
* Runs again on Barba.js page transitions (via `reinitialize()`)
|
|
56
|
+
* No ongoing monitoring or event listeners
|
|
57
|
+
|
|
58
|
+
### **Notes**
|
|
59
|
+
|
|
60
|
+
1. **Global / Button components** already include this setup by default
|
|
61
|
+
* Use this documentation only for custom button implementations
|
|
62
|
+
2. If any required element is missing, that button is skipped (no errors)
|
|
63
|
+
3. The system works independently for each button on the page
|
|
64
|
+
4. No cleanup needed - purely DOM manipulation
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## **Example Structure**
|
|
69
|
+
|
|
70
|
+
```html
|
|
71
|
+
<div data-site-button="wrapper">
|
|
72
|
+
<div data-site-button-icon="wrapper">
|
|
73
|
+
<!-- Main icon (source) -->
|
|
74
|
+
<div data-site-button-icon="main">
|
|
75
|
+
<div data-site-icon="slot">
|
|
76
|
+
<svg><!-- Your icon --></svg>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<!-- Placeholder icon (destination) -->
|
|
81
|
+
<div data-site-button-icon="placeholder">
|
|
82
|
+
<div data-site-icon="slot">
|
|
83
|
+
<!-- This entire element gets replaced with cloned main slot -->
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Result:** The placeholder slot is replaced with an exact clone of the main slot (including the SVG).
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## **Key Attributes Summary**
|
|
95
|
+
|
|
96
|
+
| Attribute | Purpose | Required On |
|
|
97
|
+
| ----- | ----- | ----- |
|
|
98
|
+
| `data-site-button="wrapper"` | Button container | Wrapper div |
|
|
99
|
+
| `data-site-button-icon="wrapper"` | Icon container | Icon wrapper div |
|
|
100
|
+
| `data-site-button-icon="main"` | Source icon | Main icon div |
|
|
101
|
+
| `data-site-button-icon="placeholder"` | Clone destination | Placeholder icon div |
|
|
102
|
+
| `data-site-icon="slot"` | Icon slot element | Both main and placeholder |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## **Common Issues**
|
|
107
|
+
|
|
108
|
+
**Icons not cloning:**
|
|
109
|
+
|
|
110
|
+
1. Verify all required attributes are present
|
|
111
|
+
2. Check that `[data-site-icon="slot"]` is the **first child** of both main and placeholder
|
|
112
|
+
3. Ensure button wrapper has `[data-site-button="wrapper"]`
|
|
113
|
+
|
|
114
|
+
**Icons not updating after Barba transition:**
|
|
115
|
+
|
|
116
|
+
1. Ensure `window.hsmain.reinitialize()` is called after transition
|
|
117
|
+
2. Check that new page content has proper button structure
|
|
118
|
+
|
|
119
|
+
**Multiple buttons on page:**
|
|
120
|
+
|
|
121
|
+
1. Each button works independently - if one fails, others continue
|
|
122
|
+
2. Check console for warnings about missing elements
|
|
@@ -0,0 +1,274 @@
|
|
|
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
|
|
@@ -84,12 +84,27 @@ export function init() {
|
|
|
84
84
|
const statsElements = document.querySelectorAll('[data-hs-counter="wrapper"]');
|
|
85
85
|
|
|
86
86
|
statsElements.forEach((element) => {
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
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);
|
|
91
106
|
element.setAttribute("role", "img");
|
|
92
|
-
|
|
107
|
+
|
|
93
108
|
const allChildren = element.querySelectorAll("*");
|
|
94
109
|
allChildren.forEach((child) => {
|
|
95
110
|
child.setAttribute("aria-hidden", "true");
|