@hortonstudio/main 1.9.7 → 1.9.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/autoInit/accessibility/README.md +6 -38
- package/autoInit/accessibility/accessibility.js +0 -4
- package/package.json +1 -1
- package/autoInit/accessibility/functions/convert-to-span/README.md +0 -59
- package/autoInit/accessibility/functions/convert-to-span/convert-to-span.js +0 -70
- package/autoInit/accessibility/functions/custom-values-replacement/README.md +0 -71
- package/autoInit/accessibility/functions/custom-values-replacement/custom-values-replacement.js +0 -102
- package/autoInit/accessibility/functions/prevent-default/README.md +0 -58
- package/autoInit/accessibility/functions/prevent-default/prevent-default.js +0 -58
- package/autoInit/accessibility/functions/remove-list-accessibility/README.md +0 -57
- package/autoInit/accessibility/functions/remove-list-accessibility/remove-list-accessibility.js +0 -68
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## **Overview**
|
|
4
4
|
|
|
5
|
-
The accessibility system provides
|
|
5
|
+
The accessibility system provides 7 modular functions to enhance website accessibility and functionality. Each function operates independently and can be customized through data attributes.
|
|
6
6
|
|
|
7
7
|
**Note:** This module auto-initializes and loads all functions on page load.
|
|
8
8
|
|
|
@@ -24,63 +24,35 @@ Adds proper ARIA `role="list"` and `role="listitem"` to custom-styled lists.
|
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
-
### **3.
|
|
28
|
-
Removes list semantics by stripping ARIA roles and converting `<ul>/<ol>/<li>` to divs.
|
|
29
|
-
|
|
30
|
-
**Use case:** Decorative list layouts that shouldn't be announced as lists.
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
### **4. Convert to Span**
|
|
35
|
-
Converts most HTML elements to span elements while preserving attributes and content.
|
|
36
|
-
|
|
37
|
-
**Use case:** Removing semantic meaning from purely decorative wrapper elements.
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
### **5. Year Replacement**
|
|
27
|
+
### **3. Year Replacement**
|
|
42
28
|
Replaces `{{year}}` and `{{month}}` placeholders with current year and month.
|
|
43
29
|
|
|
44
30
|
**Use case:** Auto-updating copyright years and date-based content.
|
|
45
31
|
|
|
46
32
|
---
|
|
47
33
|
|
|
48
|
-
### **
|
|
49
|
-
Prevents default behavior on elements including clicks and keyboard activation.
|
|
50
|
-
|
|
51
|
-
**Use case:** Decorative buttons or preventing anchor link scrolling.
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
### **7. Custom Values Replacement**
|
|
56
|
-
Collects custom name-value pairs and replaces `{{name}}` placeholders throughout the page.
|
|
57
|
-
|
|
58
|
-
**Use case:** Dynamic content replacement for user-defined values.
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
### **8. Click Forwarding**
|
|
34
|
+
### **4. Click Forwarding**
|
|
63
35
|
Forwards clicks from decorative wrapper elements to actual interactive trigger elements.
|
|
64
36
|
|
|
65
37
|
**Use case:** Making entire card areas clickable while maintaining semantic structure.
|
|
66
38
|
|
|
67
39
|
---
|
|
68
40
|
|
|
69
|
-
### **
|
|
41
|
+
### **5. Text Synchronization**
|
|
70
42
|
Synchronizes text content and aria-labels from original element to multiple match elements in real-time.
|
|
71
43
|
|
|
72
44
|
**Use case:** Keeping duplicate content in sync across multiple locations.
|
|
73
45
|
|
|
74
46
|
---
|
|
75
47
|
|
|
76
|
-
### **
|
|
48
|
+
### **6. Table of Contents (TOC)**
|
|
77
49
|
Automatically generates a table of contents from H2 headings with smooth scrolling, focus management, and active state tracking.
|
|
78
50
|
|
|
79
51
|
**Use case:** Auto-generated TOC navigation for blog posts and documentation pages.
|
|
80
52
|
|
|
81
53
|
---
|
|
82
54
|
|
|
83
|
-
### **
|
|
55
|
+
### **7. Dropdown**
|
|
84
56
|
Universal dropdown system for FAQ, summary/read-more, and general toggle components. Syncs ARIA with Webflow interactions and optionally updates text content.
|
|
85
57
|
|
|
86
58
|
**Use case:** All dropdown/accordion/toggle patterns with unified ARIA management and optional text swapping.
|
|
@@ -95,11 +67,7 @@ Each function has detailed documentation in its respective folder:
|
|
|
95
67
|
|
|
96
68
|
- `functions/blog-remover/README.md`
|
|
97
69
|
- `functions/list-accessibility/README.md`
|
|
98
|
-
- `functions/remove-list-accessibility/README.md`
|
|
99
|
-
- `functions/convert-to-span/README.md`
|
|
100
70
|
- `functions/year-replacement/README.md`
|
|
101
|
-
- `functions/prevent-default/README.md`
|
|
102
|
-
- `functions/custom-values-replacement/README.md`
|
|
103
71
|
- `functions/click-forwarding/README.md`
|
|
104
72
|
- `functions/text-synchronization/README.md`
|
|
105
73
|
- `functions/toc/README.md`
|
|
@@ -8,11 +8,7 @@ export async function init() {
|
|
|
8
8
|
const functionMap = {
|
|
9
9
|
"blog-remover": () => import("./functions/blog-remover/blog-remover.js"),
|
|
10
10
|
"list-accessibility": () => import("./functions/list-accessibility/list-accessibility.js"),
|
|
11
|
-
"remove-list-accessibility": () => import("./functions/remove-list-accessibility/remove-list-accessibility.js"),
|
|
12
|
-
"convert-to-span": () => import("./functions/convert-to-span/convert-to-span.js"),
|
|
13
11
|
"year-replacement": () => import("./functions/year-replacement/year-replacement.js"),
|
|
14
|
-
"prevent-default": () => import("./functions/prevent-default/prevent-default.js"),
|
|
15
|
-
"custom-values-replacement": () => import("./functions/custom-values-replacement/custom-values-replacement.js"),
|
|
16
12
|
"click-forwarding": () => import("./functions/click-forwarding/click-forwarding.js"),
|
|
17
13
|
"text-synchronization": () => import("./functions/text-synchronization/text-synchronization.js"),
|
|
18
14
|
"toc": () => import("./functions/toc/toc.js"),
|
package/package.json
CHANGED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# **Convert to Span**
|
|
2
|
-
|
|
3
|
-
## **Overview**
|
|
4
|
-
|
|
5
|
-
Converts most HTML elements to span elements while preserving attributes and content. Useful for removing semantic meaning from decorative elements.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## **Required Elements**
|
|
10
|
-
|
|
11
|
-
**Container**
|
|
12
|
-
* data-hs-a11y="convert-span"
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## **What It Does**
|
|
17
|
-
|
|
18
|
-
1. Finds all `[data-hs-a11y="convert-span"]` containers
|
|
19
|
-
2. Converts all descendant elements to `<span>` (except skip list)
|
|
20
|
-
3. Converts container itself to `<span>`
|
|
21
|
-
4. Preserves all attributes except `data-hs-a11y`
|
|
22
|
-
|
|
23
|
-
**Skip List:** `span`, `a`, `button`, `input`, `textarea`, `select`, `img`, `video`, `audio`, `iframe`, `object`, `embed`, `canvas`, `svg`, `form`, `table`, semantic tags, headings, `script`, `style`
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## **Usage Example**
|
|
28
|
-
|
|
29
|
-
```html
|
|
30
|
-
<!-- Before -->
|
|
31
|
-
<div data-hs-a11y="convert-span">
|
|
32
|
-
<p>Text here</p>
|
|
33
|
-
<section>Content</section>
|
|
34
|
-
</div>
|
|
35
|
-
|
|
36
|
-
<!-- After -->
|
|
37
|
-
<span>
|
|
38
|
-
<span>Text here</span>
|
|
39
|
-
<span>Content</span>
|
|
40
|
-
</span>
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
**Result:** All elements become spans, removing semantic meaning.
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## **Key Attributes**
|
|
48
|
-
|
|
49
|
-
| Attribute | Purpose |
|
|
50
|
-
| ----- | ----- |
|
|
51
|
-
| `data-hs-a11y="convert-span"` | Container to convert |
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## **Notes**
|
|
56
|
-
|
|
57
|
-
* One-time DOM transformation
|
|
58
|
-
* Skips interactive and media elements
|
|
59
|
-
* Use for purely decorative wrappers
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
export function init() {
|
|
2
|
-
function setupConvertToSpan() {
|
|
3
|
-
const containers = document.querySelectorAll('[data-hs-a11y="convert-span"]');
|
|
4
|
-
|
|
5
|
-
containers.forEach(container => {
|
|
6
|
-
const skipTags = [
|
|
7
|
-
'span', 'a', 'button', 'input', 'textarea', 'select', 'img', 'video', 'audio',
|
|
8
|
-
'iframe', 'object', 'embed', 'canvas', 'svg', 'form', 'table', 'thead', 'tbody',
|
|
9
|
-
'tr', 'td', 'th', 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'h1', 'h2', 'h3', 'h4',
|
|
10
|
-
'h5', 'h6', 'script', 'style', 'link', 'meta', 'title', 'head', 'html', 'body'
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
// Convert all child elements first
|
|
14
|
-
const elementsToConvert = container.querySelectorAll('*');
|
|
15
|
-
|
|
16
|
-
elementsToConvert.forEach(element => {
|
|
17
|
-
const tagName = element.tagName.toLowerCase();
|
|
18
|
-
|
|
19
|
-
if (!skipTags.includes(tagName)) {
|
|
20
|
-
const newSpan = document.createElement('span');
|
|
21
|
-
|
|
22
|
-
// Copy all attributes except data-hs-a11y
|
|
23
|
-
Array.from(element.attributes).forEach(attr => {
|
|
24
|
-
if (attr.name !== 'data-hs-a11y') {
|
|
25
|
-
newSpan.setAttribute(attr.name, attr.value);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// Move all child nodes
|
|
30
|
-
while (element.firstChild) {
|
|
31
|
-
newSpan.appendChild(element.firstChild);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Replace the element
|
|
35
|
-
element.parentNode.replaceChild(newSpan, element);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// Convert the container itself to span
|
|
40
|
-
const containerTagName = container.tagName.toLowerCase();
|
|
41
|
-
if (!skipTags.includes(containerTagName)) {
|
|
42
|
-
const newSpan = document.createElement('span');
|
|
43
|
-
|
|
44
|
-
// Copy all attributes except data-hs-a11y
|
|
45
|
-
Array.from(container.attributes).forEach(attr => {
|
|
46
|
-
if (attr.name !== 'data-hs-a11y') {
|
|
47
|
-
newSpan.setAttribute(attr.name, attr.value);
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// Move all child nodes
|
|
52
|
-
while (container.firstChild) {
|
|
53
|
-
newSpan.appendChild(container.firstChild);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Replace the container
|
|
57
|
-
container.parentNode.replaceChild(newSpan, container);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
setupConvertToSpan();
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
result: "convert-to-span initialized",
|
|
66
|
-
destroy: () => {
|
|
67
|
-
// No cleanup needed - this is a one-time DOM operation
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# **Custom Values Replacement**
|
|
2
|
-
|
|
3
|
-
## **Overview**
|
|
4
|
-
|
|
5
|
-
Collects custom name-value pairs from a list and replaces `{{name}}` placeholders throughout the page. Similar to site-settings but for user-defined values.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## **Required Elements**
|
|
10
|
-
|
|
11
|
-
**Custom Values List**
|
|
12
|
-
* data-hs-a11y="custom-values-list"
|
|
13
|
-
|
|
14
|
-
**Name Element** *(within list descendants)*
|
|
15
|
-
* data-hs-a11y="custom-values-name"
|
|
16
|
-
|
|
17
|
-
**Value Element** *(within list descendants)*
|
|
18
|
-
* data-hs-a11y="custom-values-value"
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## **What It Does**
|
|
23
|
-
|
|
24
|
-
1. Finds custom values list
|
|
25
|
-
2. Collects name-value pairs from descendants
|
|
26
|
-
3. Replaces `{{name}}` placeholders in all text nodes
|
|
27
|
-
4. Replaces `{{name}}` placeholders in link hrefs
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
## **Usage Example**
|
|
32
|
-
|
|
33
|
-
```html
|
|
34
|
-
<div data-hs-a11y="custom-values-list" style="display: none;">
|
|
35
|
-
<div>
|
|
36
|
-
<span data-hs-a11y="custom-values-name">support-email</span>
|
|
37
|
-
<span data-hs-a11y="custom-values-value">help@example.com</span>
|
|
38
|
-
</div>
|
|
39
|
-
<div>
|
|
40
|
-
<span data-hs-a11y="custom-values-name">phone</span>
|
|
41
|
-
<span data-hs-a11y="custom-values-value">555-1234</span>
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
<p>Contact us at {{support-email}} or call {{phone}}</p>
|
|
46
|
-
<a href="mailto:{{support-email}}">Email Us</a>
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
**Result:**
|
|
50
|
-
```html
|
|
51
|
-
<p>Contact us at help@example.com or call 555-1234</p>
|
|
52
|
-
<a href="mailto:help@example.com">Email Us</a>
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## **Key Attributes**
|
|
58
|
-
|
|
59
|
-
| Attribute | Purpose |
|
|
60
|
-
| ----- | ----- |
|
|
61
|
-
| `data-hs-a11y="custom-values-list"` | Container for values |
|
|
62
|
-
| `data-hs-a11y="custom-values-name"` | Placeholder name |
|
|
63
|
-
| `data-hs-a11y="custom-values-value"` | Replacement value |
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## **Notes**
|
|
68
|
-
|
|
69
|
-
* One-time text replacement
|
|
70
|
-
* List should be hidden with CSS
|
|
71
|
-
* No cleanup needed
|
package/autoInit/accessibility/functions/custom-values-replacement/custom-values-replacement.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
export function init() {
|
|
2
|
-
function setupCustomValuesReplacement() {
|
|
3
|
-
const customValuesList = document.querySelector('[data-hs-a11y="custom-values-list"]');
|
|
4
|
-
|
|
5
|
-
if (!customValuesList) {
|
|
6
|
-
return;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
// Collect all custom values data
|
|
10
|
-
const customValues = {};
|
|
11
|
-
const descendants = customValuesList.getElementsByTagName('*');
|
|
12
|
-
|
|
13
|
-
Array.from(descendants).forEach(descendant => {
|
|
14
|
-
const nameElement = descendant.querySelector('[data-hs-a11y="custom-values-name"]');
|
|
15
|
-
const valueElement = descendant.querySelector('[data-hs-a11y="custom-values-value"]');
|
|
16
|
-
|
|
17
|
-
if (nameElement && valueElement) {
|
|
18
|
-
const name = nameElement.textContent.trim();
|
|
19
|
-
const value = valueElement.textContent.trim();
|
|
20
|
-
|
|
21
|
-
if (name && value) {
|
|
22
|
-
customValues[name] = value;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// If no custom values found, exit early
|
|
28
|
-
if (Object.keys(customValues).length === 0) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Replace text content efficiently using TreeWalker
|
|
33
|
-
const walker = document.createTreeWalker(
|
|
34
|
-
document.body,
|
|
35
|
-
NodeFilter.SHOW_TEXT,
|
|
36
|
-
{
|
|
37
|
-
acceptNode: (node) => {
|
|
38
|
-
// Check if any custom value names exist in the text content
|
|
39
|
-
const text = node.textContent;
|
|
40
|
-
for (const name in customValues) {
|
|
41
|
-
if (text.includes(`{{${name}}}`)) {
|
|
42
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return NodeFilter.FILTER_SKIP;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
const textNodes = [];
|
|
51
|
-
let node;
|
|
52
|
-
while (node = walker.nextNode()) {
|
|
53
|
-
textNodes.push(node);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Replace text in collected nodes
|
|
57
|
-
textNodes.forEach(textNode => {
|
|
58
|
-
let newText = textNode.textContent;
|
|
59
|
-
let hasChanges = false;
|
|
60
|
-
|
|
61
|
-
for (const name in customValues) {
|
|
62
|
-
const placeholder = `{{${name}}}`;
|
|
63
|
-
if (newText.includes(placeholder)) {
|
|
64
|
-
newText = newText.replace(new RegExp(placeholder, 'g'), customValues[name]);
|
|
65
|
-
hasChanges = true;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (hasChanges) {
|
|
70
|
-
textNode.textContent = newText;
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// Replace link hrefs
|
|
75
|
-
const links = document.querySelectorAll('a[href]');
|
|
76
|
-
links.forEach(link => {
|
|
77
|
-
let href = link.getAttribute('href');
|
|
78
|
-
let hasChanges = false;
|
|
79
|
-
|
|
80
|
-
for (const name in customValues) {
|
|
81
|
-
const placeholder = `{{${name}}}`;
|
|
82
|
-
if (href.includes(placeholder)) {
|
|
83
|
-
href = href.replace(new RegExp(placeholder, 'g'), customValues[name]);
|
|
84
|
-
hasChanges = true;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (hasChanges) {
|
|
89
|
-
link.setAttribute('href', href);
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
setupCustomValuesReplacement();
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
result: "custom-values-replacement initialized",
|
|
98
|
-
destroy: () => {
|
|
99
|
-
// No cleanup needed - this is a one-time text replacement
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# **Prevent Default**
|
|
2
|
-
|
|
3
|
-
## **Overview**
|
|
4
|
-
|
|
5
|
-
Prevents default behavior on elements, including clicks and keyboard activation. Useful for decorative buttons or preventing anchor scrolling.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## **Required Elements**
|
|
10
|
-
|
|
11
|
-
**Element to Disable**
|
|
12
|
-
* data-hs-a11y="prevent-default"
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## **What It Does**
|
|
17
|
-
|
|
18
|
-
1. Finds all `[data-hs-a11y="prevent-default"]` elements
|
|
19
|
-
2. Prevents click events
|
|
20
|
-
3. Prevents Enter/Space keyboard activation
|
|
21
|
-
4. For anchor links with `#` hrefs:
|
|
22
|
-
- Removes href attribute
|
|
23
|
-
- Sets `role="button"`
|
|
24
|
-
- Sets `tabindex="0"`
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## **Usage Example**
|
|
29
|
-
|
|
30
|
-
```html
|
|
31
|
-
<!-- Decorative button (no action) -->
|
|
32
|
-
<button data-hs-a11y="prevent-default">
|
|
33
|
-
Disabled Action
|
|
34
|
-
</button>
|
|
35
|
-
|
|
36
|
-
<!-- Anchor link without scroll -->
|
|
37
|
-
<a href="#" data-hs-a11y="prevent-default">
|
|
38
|
-
Click me (won't scroll)
|
|
39
|
-
</a>
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
**Result:** Elements receive focus but perform no action when clicked or activated.
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## **Key Attributes**
|
|
47
|
-
|
|
48
|
-
| Attribute | Purpose |
|
|
49
|
-
| ----- | ----- |
|
|
50
|
-
| `data-hs-a11y="prevent-default"` | Element to disable |
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## **Notes**
|
|
55
|
-
|
|
56
|
-
* Event listeners cleaned up on destroy
|
|
57
|
-
* Useful with Webflow IX for custom behaviors
|
|
58
|
-
* Anchor links converted to role="button"
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
export function init() {
|
|
2
|
-
const cleanup = {
|
|
3
|
-
handlers: []
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
const addHandler = (element, event, handler, options) => {
|
|
7
|
-
element.addEventListener(event, handler, options);
|
|
8
|
-
cleanup.handlers.push({ element, event, handler, options });
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
function setupPreventDefault(addHandler) {
|
|
12
|
-
const elements = document.querySelectorAll('[data-hs-a11y="prevent-default"]');
|
|
13
|
-
|
|
14
|
-
elements.forEach(element => {
|
|
15
|
-
// Prevent click
|
|
16
|
-
const clickHandler = (e) => {
|
|
17
|
-
e.preventDefault();
|
|
18
|
-
e.stopPropagation();
|
|
19
|
-
return false;
|
|
20
|
-
};
|
|
21
|
-
addHandler(element, 'click', clickHandler);
|
|
22
|
-
|
|
23
|
-
// Prevent keyboard activation
|
|
24
|
-
const keydownHandler = (e) => {
|
|
25
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
26
|
-
e.preventDefault();
|
|
27
|
-
e.stopPropagation();
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
addHandler(element, 'keydown', keydownHandler);
|
|
32
|
-
|
|
33
|
-
// Additional prevention for anchor links
|
|
34
|
-
if (element.tagName.toLowerCase() === 'a') {
|
|
35
|
-
// Remove or modify href to prevent scroll
|
|
36
|
-
const originalHref = element.getAttribute('href');
|
|
37
|
-
if (originalHref && (originalHref === '#' || originalHref.startsWith('#'))) {
|
|
38
|
-
element.setAttribute('data-original-href', originalHref);
|
|
39
|
-
element.removeAttribute('href');
|
|
40
|
-
element.setAttribute('role', 'button');
|
|
41
|
-
element.setAttribute('tabindex', '0');
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
setupPreventDefault(addHandler);
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
result: "prevent-default initialized",
|
|
51
|
-
destroy: () => {
|
|
52
|
-
cleanup.handlers.forEach(({ element, event, handler, options }) => {
|
|
53
|
-
element.removeEventListener(event, handler, options);
|
|
54
|
-
});
|
|
55
|
-
cleanup.handlers.length = 0;
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# **Remove List Accessibility**
|
|
2
|
-
|
|
3
|
-
## **Overview**
|
|
4
|
-
|
|
5
|
-
Removes list semantics from elements by stripping ARIA roles and converting semantic list tags to divs. Useful when you need list styling without list semantics.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## **Required Elements**
|
|
10
|
-
|
|
11
|
-
**Container**
|
|
12
|
-
* data-hs-a11y="remove-list"
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## **What It Does**
|
|
17
|
-
|
|
18
|
-
1. Finds all `[data-hs-a11y="remove-list"]` containers
|
|
19
|
-
2. Removes `role="list"` and `role="listitem"` from container and descendants
|
|
20
|
-
3. Converts all `<ul>`, `<ol>`, `<li>` tags to `<div>` elements
|
|
21
|
-
4. Preserves all other attributes and content
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## **Usage Example**
|
|
26
|
-
|
|
27
|
-
```html
|
|
28
|
-
<!-- Before -->
|
|
29
|
-
<ul data-hs-a11y="remove-list">
|
|
30
|
-
<li>Item 1</li>
|
|
31
|
-
<li>Item 2</li>
|
|
32
|
-
</ul>
|
|
33
|
-
|
|
34
|
-
<!-- After -->
|
|
35
|
-
<div>
|
|
36
|
-
<div>Item 1</div>
|
|
37
|
-
<div>Item 2</div>
|
|
38
|
-
</div>
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
**Result:** Visual list styling without list semantics for screen readers.
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
## **Key Attributes**
|
|
46
|
-
|
|
47
|
-
| Attribute | Purpose |
|
|
48
|
-
| ----- | ----- |
|
|
49
|
-
| `data-hs-a11y="remove-list"` | Container to de-semanticize |
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## **Notes**
|
|
54
|
-
|
|
55
|
-
* One-time DOM transformation
|
|
56
|
-
* Useful for decorative list layouts
|
|
57
|
-
* Use sparingly - semantic lists are preferred for actual lists
|
package/autoInit/accessibility/functions/remove-list-accessibility/remove-list-accessibility.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
export function init() {
|
|
2
|
-
function setupRemoveListAccessibility() {
|
|
3
|
-
const containers = document.querySelectorAll('[data-hs-a11y="remove-list"]');
|
|
4
|
-
|
|
5
|
-
containers.forEach(container => {
|
|
6
|
-
// Remove role="list" and role="listitem" from container and all descendants
|
|
7
|
-
const elementsWithListRoles = container.querySelectorAll('[role="list"], [role="listitem"]');
|
|
8
|
-
elementsWithListRoles.forEach(element => {
|
|
9
|
-
element.removeAttribute('role');
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
// Also remove from container itself if it has these roles
|
|
13
|
-
if (container.getAttribute('role') === 'list' || container.getAttribute('role') === 'listitem') {
|
|
14
|
-
container.removeAttribute('role');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Convert semantic lists to divs in container and all descendants
|
|
18
|
-
const listsToConvert = container.querySelectorAll('ul, ol, li');
|
|
19
|
-
listsToConvert.forEach(listElement => {
|
|
20
|
-
const newDiv = document.createElement('div');
|
|
21
|
-
|
|
22
|
-
// Copy all attributes except role
|
|
23
|
-
Array.from(listElement.attributes).forEach(attr => {
|
|
24
|
-
if (attr.name !== 'role') {
|
|
25
|
-
newDiv.setAttribute(attr.name, attr.value);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// Move all child nodes
|
|
30
|
-
while (listElement.firstChild) {
|
|
31
|
-
newDiv.appendChild(listElement.firstChild);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Replace the element
|
|
35
|
-
listElement.parentNode.replaceChild(newDiv, listElement);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// Convert container itself if it's a semantic list
|
|
39
|
-
if (container.tagName.toLowerCase() === 'ul' || container.tagName.toLowerCase() === 'ol' || container.tagName.toLowerCase() === 'li') {
|
|
40
|
-
const newDiv = document.createElement('div');
|
|
41
|
-
|
|
42
|
-
// Copy all attributes except data-hs-a11y and role
|
|
43
|
-
Array.from(container.attributes).forEach(attr => {
|
|
44
|
-
if (attr.name !== 'data-hs-a11y' && attr.name !== 'role') {
|
|
45
|
-
newDiv.setAttribute(attr.name, attr.value);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
// Move all child nodes
|
|
50
|
-
while (container.firstChild) {
|
|
51
|
-
newDiv.appendChild(container.firstChild);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Replace the container
|
|
55
|
-
container.parentNode.replaceChild(newDiv, container);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
setupRemoveListAccessibility();
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
result: "remove-list-accessibility initialized",
|
|
64
|
-
destroy: () => {
|
|
65
|
-
// No cleanup needed - this is a one-time DOM operation
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
}
|