@hortonstudio/main 1.9.4 → 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/{navbar.js → navbar/navbar.js} +128 -118
- 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 +8 -8
- 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,338 @@
|
|
|
1
|
+
# **Form System Documentation**
|
|
2
|
+
|
|
3
|
+
## **Overview**
|
|
4
|
+
|
|
5
|
+
The form system provides two main features:
|
|
6
|
+
1. **Honeypot spam prevention** - Blocks bot submissions using a hidden field
|
|
7
|
+
2. **Custom select component** - Fully accessible, styled select dropdowns that sync with native `<select>` elements for form submission
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## **Honeypot Spam Prevention**
|
|
12
|
+
|
|
13
|
+
### **Required Element**
|
|
14
|
+
|
|
15
|
+
**Honeypot Field** *(hidden field in your form)*
|
|
16
|
+
|
|
17
|
+
* data-hs-form="form-handler"
|
|
18
|
+
* Should be hidden with CSS (bots will auto-fill it, humans won't see it)
|
|
19
|
+
|
|
20
|
+
### **What It Does**
|
|
21
|
+
|
|
22
|
+
1. **Listens for form submissions** - Captures all form submit events
|
|
23
|
+
2. **Checks honeypot field** - If the hidden field has a value, it's likely a bot
|
|
24
|
+
3. **Blocks submission** - Prevents form from submitting if honeypot is filled
|
|
25
|
+
|
|
26
|
+
### **Example**
|
|
27
|
+
|
|
28
|
+
```html
|
|
29
|
+
<form>
|
|
30
|
+
<input type="text" name="name" placeholder="Your Name">
|
|
31
|
+
<input type="email" name="email" placeholder="Your Email">
|
|
32
|
+
|
|
33
|
+
<!-- Honeypot field (hidden with CSS) -->
|
|
34
|
+
<input type="text" name="website" data-hs-form="form-handler" style="display: none;">
|
|
35
|
+
|
|
36
|
+
<button type="submit">Submit</button>
|
|
37
|
+
</form>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Result:** Legitimate users never see the honeypot field. Bots auto-fill all fields, triggering the spam prevention.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## **Custom Select Component**
|
|
45
|
+
|
|
46
|
+
### **Required Elements**
|
|
47
|
+
|
|
48
|
+
**Select Wrapper** *(main container)*
|
|
49
|
+
|
|
50
|
+
* data-hs-form="select"
|
|
51
|
+
|
|
52
|
+
**Native Select** *(hidden select element for form submission)*
|
|
53
|
+
|
|
54
|
+
* Standard `<select>` element with `<option>` children
|
|
55
|
+
* Should have `name` attribute for form submission
|
|
56
|
+
* Will be hidden but remains functional
|
|
57
|
+
|
|
58
|
+
**Toggle Button** *(visual button to open/close dropdown)*
|
|
59
|
+
|
|
60
|
+
* `<button>` element or element with `role="button"`
|
|
61
|
+
* Should contain a `<span>` element for displaying selected text
|
|
62
|
+
* Webflow IX must add/remove `.is-active` class on this button
|
|
63
|
+
|
|
64
|
+
**Custom List** *(dropdown container)*
|
|
65
|
+
|
|
66
|
+
* data-hs-form="select-list"
|
|
67
|
+
* First child is used as template for generating options
|
|
68
|
+
* Webflow IX must show/hide this when button is clicked
|
|
69
|
+
|
|
70
|
+
**Template Element** *(first child of select-list)*
|
|
71
|
+
|
|
72
|
+
* Should contain a `<span>` element for option text
|
|
73
|
+
* Will be cloned for each `<option>` in the native select
|
|
74
|
+
* Original template is removed after cloning
|
|
75
|
+
|
|
76
|
+
**Label** *(optional but recommended)*
|
|
77
|
+
|
|
78
|
+
* Standard `<label>` element
|
|
79
|
+
* Can be inside wrapper or reference select by `for` attribute
|
|
80
|
+
|
|
81
|
+
**Typical element layout:**
|
|
82
|
+
|
|
83
|
+
1. Select Wrapper (data-hs-form="select")
|
|
84
|
+
1. Label (optional)
|
|
85
|
+
1. Text: "Choose an option"
|
|
86
|
+
2. Native Select (`<select>`)
|
|
87
|
+
1. Option 1 (`<option value="value1">`)
|
|
88
|
+
1. Text: "Option 1"
|
|
89
|
+
2. Option 2 (`<option value="value2">`)
|
|
90
|
+
1. Text: "Option 2"
|
|
91
|
+
3. Toggle Button (`<button>`)
|
|
92
|
+
1. Button Text (`<span>`)
|
|
93
|
+
1. Text: "Choose an option"
|
|
94
|
+
4. Custom List (data-hs-form="select-list")
|
|
95
|
+
1. Template Element
|
|
96
|
+
1. Text Span (`<span>`)
|
|
97
|
+
1. Text: "Placeholder"
|
|
98
|
+
|
|
99
|
+
### **What It Does**
|
|
100
|
+
|
|
101
|
+
1. **Unwraps Webflow slots** - Removes any `<div>` wrappers inside `<select>` elements
|
|
102
|
+
2. **Clones template** - Uses first child of select-list as template
|
|
103
|
+
3. **Generates options** - Creates custom option elements from native `<option>` elements
|
|
104
|
+
4. **Syncs state** - Keeps custom UI and native select in sync
|
|
105
|
+
5. **ARIA management** - Automatically updates accessibility attributes
|
|
106
|
+
6. **Keyboard navigation** - Full arrow key, Tab, Enter, Space, Escape support
|
|
107
|
+
7. **Focus management** - Handles focus return, tabbing out, and keyboard navigation
|
|
108
|
+
|
|
109
|
+
### **When It Runs**
|
|
110
|
+
|
|
111
|
+
* Runs once on page load (or DOMContentLoaded)
|
|
112
|
+
* Available for manual re-initialization via `window.initCustomSelects()`
|
|
113
|
+
* Runs again on Barba.js page transitions (via `reinitialize()`)
|
|
114
|
+
|
|
115
|
+
### **Interaction Requirements (IX3)**
|
|
116
|
+
|
|
117
|
+
**CRITICAL:** Webflow interactions MUST add/remove `.is-active` class on the toggle button.
|
|
118
|
+
|
|
119
|
+
**Triggers:**
|
|
120
|
+
|
|
121
|
+
1. **Click trigger** on `<button>` element
|
|
122
|
+
1. `Each click: Toggle play/reverse`
|
|
123
|
+
|
|
124
|
+
**Timeline:**
|
|
125
|
+
|
|
126
|
+
1. 0s: Toggle `.is-active` class on the button element
|
|
127
|
+
2. .06s: Rest of animation (fade in, slide, etc.)
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## **Accessibility**
|
|
132
|
+
|
|
133
|
+
### **Automatic ARIA Setup**
|
|
134
|
+
|
|
135
|
+
For each select, the system automatically:
|
|
136
|
+
|
|
137
|
+
1. **Button (combobox)**
|
|
138
|
+
- `role="combobox"`
|
|
139
|
+
- `aria-haspopup="listbox"`
|
|
140
|
+
- `aria-expanded="true|false"` (synced with `.is-active` class)
|
|
141
|
+
- `aria-controls="[listbox-id]"`
|
|
142
|
+
- `aria-labelledby="[label-id]"` (if label exists)
|
|
143
|
+
- `aria-activedescendant="[option-id]"` (when navigating with arrows)
|
|
144
|
+
|
|
145
|
+
2. **Select List**
|
|
146
|
+
- `role="listbox"`
|
|
147
|
+
- `tabindex="-1"` (not directly tabbable)
|
|
148
|
+
|
|
149
|
+
3. **Options**
|
|
150
|
+
- `role="option"`
|
|
151
|
+
- `aria-selected="true|false"`
|
|
152
|
+
- `tabindex="0"` when dropdown open, `tabindex="-1"` when closed
|
|
153
|
+
- Unique `id` for aria-activedescendant
|
|
154
|
+
|
|
155
|
+
4. **Label**
|
|
156
|
+
- Connected to native select with `for` attribute
|
|
157
|
+
- Linked to button with `aria-labelledby`
|
|
158
|
+
|
|
159
|
+
### **Focus Management**
|
|
160
|
+
|
|
161
|
+
1. **Opening dropdown** - All options become tabbable
|
|
162
|
+
2. **Closing dropdown** - Focus returns to button if inside list
|
|
163
|
+
3. **Tabbing out** - Automatically closes dropdown
|
|
164
|
+
4. **Arrow navigation** - Focuses options with visual `.focused` class
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## **Usage Examples**
|
|
169
|
+
|
|
170
|
+
### **Basic Select**
|
|
171
|
+
|
|
172
|
+
```html
|
|
173
|
+
<div data-hs-form="select">
|
|
174
|
+
<label for="fruit-select">Choose a fruit</label>
|
|
175
|
+
|
|
176
|
+
<select name="fruit" id="fruit-select">
|
|
177
|
+
<option value="">Choose an option</option>
|
|
178
|
+
<option value="apple">Apple</option>
|
|
179
|
+
<option value="banana">Banana</option>
|
|
180
|
+
<option value="orange">Orange</option>
|
|
181
|
+
</select>
|
|
182
|
+
|
|
183
|
+
<button>
|
|
184
|
+
<span>Choose an option</span>
|
|
185
|
+
</button>
|
|
186
|
+
|
|
187
|
+
<div data-hs-form="select-list">
|
|
188
|
+
<div>
|
|
189
|
+
<span>Template</span>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Result:** Creates 4 custom options (including empty "Choose an option"). Native select stays synced for form submission.
|
|
196
|
+
|
|
197
|
+
### **Pre-selected Option**
|
|
198
|
+
|
|
199
|
+
```html
|
|
200
|
+
<select name="size">
|
|
201
|
+
<option value="small">Small</option>
|
|
202
|
+
<option value="medium" selected>Medium</option>
|
|
203
|
+
<option value="large">Large</option>
|
|
204
|
+
</select>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Result:** Button text automatically shows "Medium" on page load. Corresponding custom option has `aria-selected="true"`.
|
|
208
|
+
|
|
209
|
+
### **Options with Special Characters**
|
|
210
|
+
|
|
211
|
+
```html
|
|
212
|
+
<option value='product"deluxe"'>Deluxe Edition</option>
|
|
213
|
+
<option value="user's choice">Custom Option</option>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Result:** Works correctly - uses safe value comparison instead of selector injection.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## **Keyboard Navigation**
|
|
221
|
+
|
|
222
|
+
### **When Button is Focused**
|
|
223
|
+
|
|
224
|
+
1. **Space** or **Enter** � Open/close dropdown
|
|
225
|
+
2. **ArrowDown** � Open dropdown (or focus first option if already open)
|
|
226
|
+
3. **ArrowUp** � Focus last option (if dropdown is open)
|
|
227
|
+
4. **Escape** � Close dropdown (if open)
|
|
228
|
+
|
|
229
|
+
### **When Option is Focused**
|
|
230
|
+
|
|
231
|
+
1. **ArrowDown** � Focus next option
|
|
232
|
+
2. **ArrowUp** � Focus previous option (or close and focus button if on first option)
|
|
233
|
+
3. **Enter** or **Space** � Select option and close dropdown
|
|
234
|
+
4. **Escape** � Close dropdown and return focus to button
|
|
235
|
+
5. **Tab** � Navigate through options, tab out of last option closes dropdown
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## **State Synchronization**
|
|
240
|
+
|
|
241
|
+
### **Native Select � Custom UI**
|
|
242
|
+
|
|
243
|
+
When native select value changes (programmatically or via Webflow):
|
|
244
|
+
1. Finds matching custom option by value
|
|
245
|
+
2. Updates button text
|
|
246
|
+
3. Updates `aria-selected` on all options
|
|
247
|
+
|
|
248
|
+
### **Custom UI � Native Select**
|
|
249
|
+
|
|
250
|
+
When user selects custom option:
|
|
251
|
+
1. Updates native select's `value`
|
|
252
|
+
2. Dispatches `change` event on native select
|
|
253
|
+
3. Updates button text
|
|
254
|
+
4. Updates `aria-selected`
|
|
255
|
+
5. Closes dropdown
|
|
256
|
+
|
|
257
|
+
**Both stay in sync at all times.**
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## **Key Attributes Summary**
|
|
262
|
+
|
|
263
|
+
| Attribute | Purpose | Required On |
|
|
264
|
+
| ----- | ----- | ----- |
|
|
265
|
+
| `data-hs-form="select"` | Select wrapper | Wrapper div |
|
|
266
|
+
| `data-hs-form="select-list"` | Custom options container | List div |
|
|
267
|
+
| `data-hs-form="form-handler"` | Honeypot spam field | Hidden input (optional) |
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## **API**
|
|
272
|
+
|
|
273
|
+
### **Manual Re-initialization**
|
|
274
|
+
|
|
275
|
+
```javascript
|
|
276
|
+
window.initCustomSelects();
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Re-scans page for new selects and initializes them. Useful for dynamically added content.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## **Notes**
|
|
284
|
+
|
|
285
|
+
1. **Native select required** - Must have actual `<select>` element for form submission
|
|
286
|
+
2. **Button must have span** - `<span>` child is required for text updates
|
|
287
|
+
3. **Template is removed** - First child of select-list is cloned then deleted
|
|
288
|
+
4. **Webflow IX required** - Must toggle `.is-active` class on button
|
|
289
|
+
5. **Barba.js compatible** - Automatically cleans up on destroy/reinitialize
|
|
290
|
+
6. **Silent failures** - Missing required elements cause function to return early (no errors)
|
|
291
|
+
7. **Empty values supported** - Options with `value=""` work correctly
|
|
292
|
+
8. **Special characters safe** - Handles quotes and special characters in option values
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## **Common Issues**
|
|
297
|
+
|
|
298
|
+
**Dropdown not opening:**
|
|
299
|
+
|
|
300
|
+
1. Verify Webflow IX adds `.is-active` class to button (not wrapper or list)
|
|
301
|
+
2. Check that button exists and is `<button>` or has `role="button"`
|
|
302
|
+
3. Ensure select-list exists with `data-hs-form="select-list"`
|
|
303
|
+
|
|
304
|
+
**Button text not updating:**
|
|
305
|
+
|
|
306
|
+
1. Verify button has a `<span>` child element
|
|
307
|
+
2. Check that template element has a `<span>` child
|
|
308
|
+
3. Ensure option values match between native and custom
|
|
309
|
+
|
|
310
|
+
**Options not clickable:**
|
|
311
|
+
|
|
312
|
+
1. Check that template element exists as first child of select-list
|
|
313
|
+
2. Verify template has `<span>` for text
|
|
314
|
+
3. Ensure options are being generated (inspect DOM)
|
|
315
|
+
|
|
316
|
+
**Can't tab to options:**
|
|
317
|
+
|
|
318
|
+
1. Verify dropdown is open (`.is-active` class on button)
|
|
319
|
+
2. Check Webflow IX animation shows the select-list
|
|
320
|
+
3. Ensure `display: none` is removed when open
|
|
321
|
+
|
|
322
|
+
**Form not submitting selected value:**
|
|
323
|
+
|
|
324
|
+
1. Native `<select>` must have `name` attribute
|
|
325
|
+
2. Check that native select's value is updating (inspect DOM or use console)
|
|
326
|
+
3. Verify native select is inside `<form>` element
|
|
327
|
+
|
|
328
|
+
**Dropdown doesn't close when tabbing out:**
|
|
329
|
+
|
|
330
|
+
1. Ensure wrapper element properly contains button and list
|
|
331
|
+
2. Check that `data-hs-form="select"` is on wrapper
|
|
332
|
+
3. Verify Webflow IX removes `.is-active` when clicking button again
|
|
333
|
+
|
|
334
|
+
**Spam prevention not working:**
|
|
335
|
+
|
|
336
|
+
1. Verify honeypot field has `data-hs-form="form-handler"`
|
|
337
|
+
2. Ensure field is hidden with CSS (not removed from DOM)
|
|
338
|
+
3. Check that field is inside the `<form>` element
|
|
@@ -105,6 +105,7 @@ export function init() {
|
|
|
105
105
|
// Add ARIA attributes
|
|
106
106
|
customList.setAttribute('role', 'listbox');
|
|
107
107
|
customList.setAttribute('id', `${selectName}-listbox`);
|
|
108
|
+
customList.setAttribute('tabindex', '-1');
|
|
108
109
|
|
|
109
110
|
button.setAttribute('role', 'combobox');
|
|
110
111
|
button.setAttribute('aria-haspopup', 'listbox');
|
|
@@ -127,7 +128,6 @@ export function init() {
|
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
// Track state
|
|
130
|
-
let currentIndex = -1;
|
|
131
131
|
let isOpen = false;
|
|
132
132
|
|
|
133
133
|
// Update expanded state
|
|
@@ -148,7 +148,6 @@ export function init() {
|
|
|
148
148
|
});
|
|
149
149
|
|
|
150
150
|
// Add new focus
|
|
151
|
-
currentIndex = index;
|
|
152
151
|
options[index].classList.add('focused');
|
|
153
152
|
options[index].setAttribute('tabindex', '0');
|
|
154
153
|
options[index].focus();
|
|
@@ -157,7 +156,7 @@ export function init() {
|
|
|
157
156
|
|
|
158
157
|
// Select option
|
|
159
158
|
function selectOption(optionElement) {
|
|
160
|
-
const value = optionElement.getAttribute('data-value');
|
|
159
|
+
const value = optionElement.getAttribute('data-value') || '';
|
|
161
160
|
const text = optionElement.querySelector('span')?.textContent || optionElement.textContent;
|
|
162
161
|
|
|
163
162
|
// Update real select
|
|
@@ -176,7 +175,7 @@ export function init() {
|
|
|
176
175
|
});
|
|
177
176
|
optionElement.setAttribute('aria-selected', 'true');
|
|
178
177
|
|
|
179
|
-
//
|
|
178
|
+
// Close dropdown by clicking button
|
|
180
179
|
button.click();
|
|
181
180
|
}
|
|
182
181
|
|
|
@@ -266,33 +265,46 @@ export function init() {
|
|
|
266
265
|
};
|
|
267
266
|
addHandler(customList, 'click', listClickHandler);
|
|
268
267
|
|
|
269
|
-
//
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
268
|
+
// Handle tabbing out of select list
|
|
269
|
+
const listFocusoutHandler = (e) => {
|
|
270
|
+
// Check if focus is moving outside the wrapper (or to browser chrome)
|
|
271
|
+
if ((!e.relatedTarget || !wrapper.contains(e.relatedTarget)) && button.classList.contains('is-active')) {
|
|
272
|
+
button.click(); // Close the dropdown
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
addHandler(customList, 'focusout', listFocusoutHandler);
|
|
276
|
+
|
|
277
|
+
// Track open/close state via .is-active class on button
|
|
278
|
+
const observer = new MutationObserver(() => {
|
|
279
|
+
const isActive = button.classList.contains('is-active');
|
|
280
|
+
|
|
281
|
+
updateExpandedState(isActive);
|
|
282
|
+
|
|
283
|
+
if (isActive) {
|
|
284
|
+
// Make all options tabbable when opened
|
|
285
|
+
const options = customList.querySelectorAll('[role="option"]');
|
|
286
|
+
options.forEach(opt => {
|
|
287
|
+
opt.setAttribute('tabindex', '0');
|
|
288
|
+
});
|
|
289
|
+
} else {
|
|
290
|
+
// Return focus to button BEFORE aria changes if it was in the list
|
|
291
|
+
if (document.activeElement?.closest('[data-hs-form="select-list"]') === customList) {
|
|
292
|
+
button.focus();
|
|
288
293
|
}
|
|
289
|
-
|
|
294
|
+
|
|
295
|
+
// Reset on close
|
|
296
|
+
button.removeAttribute('aria-activedescendant');
|
|
297
|
+
const options = customList.querySelectorAll('[role="option"]');
|
|
298
|
+
options.forEach(opt => {
|
|
299
|
+
opt.setAttribute('tabindex', '-1');
|
|
300
|
+
});
|
|
301
|
+
}
|
|
290
302
|
});
|
|
291
303
|
|
|
292
|
-
// Observe the
|
|
293
|
-
observer.observe(
|
|
304
|
+
// Observe the button for .is-active class changes
|
|
305
|
+
observer.observe(button, {
|
|
294
306
|
attributes: true,
|
|
295
|
-
attributeFilter: ['
|
|
307
|
+
attributeFilter: ['class']
|
|
296
308
|
});
|
|
297
309
|
addObserver(observer);
|
|
298
310
|
|
|
@@ -300,7 +312,10 @@ export function init() {
|
|
|
300
312
|
const selectChangeHandler = () => {
|
|
301
313
|
const selectedOption = realSelect.options[realSelect.selectedIndex];
|
|
302
314
|
if (selectedOption) {
|
|
303
|
-
const
|
|
315
|
+
const options = customList.querySelectorAll('[role="option"]');
|
|
316
|
+
const customOption = Array.from(options).find(opt =>
|
|
317
|
+
opt.getAttribute('data-value') === selectedOption.value
|
|
318
|
+
);
|
|
304
319
|
if (customOption) {
|
|
305
320
|
// Update button text
|
|
306
321
|
const text = customOption.querySelector('span')?.textContent || customOption.textContent;
|
|
@@ -310,7 +325,7 @@ export function init() {
|
|
|
310
325
|
}
|
|
311
326
|
|
|
312
327
|
// Update aria-selected
|
|
313
|
-
|
|
328
|
+
options.forEach(opt => {
|
|
314
329
|
opt.setAttribute('aria-selected', 'false');
|
|
315
330
|
});
|
|
316
331
|
customOption.setAttribute('aria-selected', 'true');
|