@hortonstudio/main 1.9.7 → 1.9.9

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.
@@ -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
@@ -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
@@ -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
- }
File without changes