@gnireeg/accordion 0.1.0 → 0.1.2
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/dist/index.d.ts +0 -142
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +270 -264
- package/dist/index.js.map +1 -1
- package/package.json +7 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,143 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AccordionItem component - Expandable/collapsible content container with smooth animations
|
|
3
|
-
*
|
|
4
|
-
* @element accordion-item
|
|
5
|
-
*
|
|
6
|
-
* @attr {boolean} open - When present, the accordion starts in an expanded state
|
|
7
|
-
* @attr {string} animation-time - Animation duration in milliseconds (default: "300")
|
|
8
|
-
* @attr {string} animation-easing - CSS easing function (default: "ease")
|
|
9
|
-
*
|
|
10
|
-
* @slot trigger - The clickable element that toggles the accordion (typically a button)
|
|
11
|
-
* @slot - Default slot for the accordion content
|
|
12
|
-
*
|
|
13
|
-
* @fires accordion-opened - Dispatched when the accordion opens (detail: { open: true })
|
|
14
|
-
* @fires accordion-closed - Dispatched when the accordion closes (detail: { open: false })
|
|
15
|
-
*
|
|
16
|
-
* @cssprop [--animation-time] - Can be overridden via CSS custom properties
|
|
17
|
-
* @cssprop [--animation-easing] - Can be overridden via CSS custom properties
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```html
|
|
21
|
-
* <accordion-item>
|
|
22
|
-
* <button slot="trigger">Click to expand</button>
|
|
23
|
-
* <div>Your content here</div>
|
|
24
|
-
* </accordion-item>
|
|
25
|
-
*
|
|
26
|
-
* <!-- Start expanded with custom animation -->
|
|
27
|
-
* <accordion-item open animation-time="500" animation-easing="ease-in-out">
|
|
28
|
-
* <button slot="trigger">Already open</button>
|
|
29
|
-
* <div>This content is visible by default</div>
|
|
30
|
-
* </accordion-item>
|
|
31
|
-
* ```
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* ```javascript
|
|
35
|
-
* // Programmatic control
|
|
36
|
-
* const accordion = document.querySelector('accordion-item');
|
|
37
|
-
* accordion.show(); // Open
|
|
38
|
-
* accordion.close(); // Close
|
|
39
|
-
* accordion.toggle(); // Toggle state
|
|
40
|
-
*
|
|
41
|
-
* // Listen to events
|
|
42
|
-
* accordion.addEventListener('accordion-opened', (e) => {
|
|
43
|
-
* console.log('Opened!', e.detail);
|
|
44
|
-
* });
|
|
45
|
-
* ```
|
|
46
|
-
*
|
|
47
|
-
* @note Automatically adds ARIA attributes (aria-expanded) for accessibility
|
|
48
|
-
* @note Supports keyboard navigation (Enter/Space) for non-button triggers
|
|
49
|
-
*/
|
|
50
|
-
export declare class AccordionItem extends HTMLElement {
|
|
51
|
-
private shadow;
|
|
52
|
-
private trigger;
|
|
53
|
-
private triggerElement;
|
|
54
|
-
open: boolean;
|
|
55
|
-
private animationTime;
|
|
56
|
-
private easing;
|
|
57
|
-
constructor();
|
|
58
|
-
static get observedAttributes(): string[];
|
|
59
|
-
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
60
|
-
connectedCallback(): void;
|
|
61
|
-
disconnectedCallback(): void;
|
|
62
|
-
private setupTriggerAccessibility;
|
|
63
|
-
private handleTriggerClick;
|
|
64
|
-
private handleKeydown;
|
|
65
|
-
/**
|
|
66
|
-
* Toggles the accordion between open and closed states
|
|
67
|
-
* @public
|
|
68
|
-
*/
|
|
69
|
-
toggle: () => void;
|
|
70
|
-
/**
|
|
71
|
-
* Opens the accordion
|
|
72
|
-
* @public
|
|
73
|
-
* @fires accordion-opened
|
|
74
|
-
*/
|
|
75
|
-
show: () => void;
|
|
76
|
-
/**
|
|
77
|
-
* Closes the accordion
|
|
78
|
-
* @public
|
|
79
|
-
* @fires accordion-closed
|
|
80
|
-
*/
|
|
81
|
-
close: () => void;
|
|
82
|
-
private reflectState;
|
|
83
|
-
private dispatchStateEvent;
|
|
84
|
-
private updateTriggerAccessibility;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* AccordionGroup component - Container for managing multiple accordion items with mutual exclusion
|
|
88
|
-
*
|
|
89
|
-
* @element accordion-group
|
|
90
|
-
*
|
|
91
|
-
* @attr {boolean} allow-multiple-open - When present, allows multiple accordions to be open simultaneously. By default, opening one accordion closes all others in the group.
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* ```html
|
|
95
|
-
* <!-- Only one accordion can be open at a time -->
|
|
96
|
-
* <accordion-group>
|
|
97
|
-
* <accordion-item open>
|
|
98
|
-
* <button slot="trigger">First Item</button>
|
|
99
|
-
* <div>Opening another will close this</div>
|
|
100
|
-
* </accordion-item>
|
|
101
|
-
*
|
|
102
|
-
* <accordion-item>
|
|
103
|
-
* <button slot="trigger">Second Item</button>
|
|
104
|
-
* <div>Only one can be open at a time</div>
|
|
105
|
-
* </accordion-item>
|
|
106
|
-
*
|
|
107
|
-
* <accordion-item>
|
|
108
|
-
* <button slot="trigger">Third Item</button>
|
|
109
|
-
* <div>Same behavior here</div>
|
|
110
|
-
* </accordion-item>
|
|
111
|
-
* </accordion-group>
|
|
112
|
-
* ```
|
|
113
|
-
*
|
|
114
|
-
* @example
|
|
115
|
-
* ```html
|
|
116
|
-
* <!-- Allow multiple accordions to be open -->
|
|
117
|
-
* <accordion-group allow-multiple-open>
|
|
118
|
-
* <accordion-item>
|
|
119
|
-
* <button slot="trigger">First Item</button>
|
|
120
|
-
* <div>Can be open with others</div>
|
|
121
|
-
* </accordion-item>
|
|
122
|
-
*
|
|
123
|
-
* <accordion-item>
|
|
124
|
-
* <button slot="trigger">Second Item</button>
|
|
125
|
-
* <div>Multiple can be open</div>
|
|
126
|
-
* </accordion-item>
|
|
127
|
-
* </accordion-group>
|
|
128
|
-
* ```
|
|
129
|
-
*
|
|
130
|
-
* @note Each accordion-group works independently. Multiple groups on the same page don't affect each other.
|
|
131
|
-
* @note The group listens to 'accordion-opened' events from child accordion-item elements
|
|
132
|
-
*/
|
|
133
|
-
export declare class AccordionGroup extends HTMLElement {
|
|
134
|
-
private allowMultiple;
|
|
135
|
-
private static stylesApplied;
|
|
136
|
-
constructor();
|
|
137
|
-
static get observedAttributes(): string[];
|
|
138
|
-
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
139
|
-
connectedCallback(): void;
|
|
140
|
-
disconnectedCallback(): void;
|
|
141
|
-
private handleAccordionOpened;
|
|
142
|
-
}
|
|
143
1
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
CHANGED
|
@@ -1,139 +1,143 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
this.triggerElement = this.trigger.assignedElements()[0];
|
|
60
|
-
if (!this.triggerElement)
|
|
61
|
-
return;
|
|
62
|
-
// If the slotted element is not a button, add keyboard support
|
|
63
|
-
if (this.triggerElement.tagName !== 'BUTTON' && !this.triggerElement.hasAttribute('role')) {
|
|
64
|
-
this.triggerElement.setAttribute('role', 'button');
|
|
65
|
-
this.triggerElement.setAttribute('tabindex', '0');
|
|
66
|
-
// Add keyboard listener
|
|
67
|
-
this.triggerElement.addEventListener('keydown', this.handleKeydown);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
this.handleTriggerClick = () => {
|
|
71
|
-
this.toggle();
|
|
72
|
-
};
|
|
73
|
-
this.handleKeydown = (e) => {
|
|
74
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
75
|
-
e.preventDefault();
|
|
76
|
-
this.toggle();
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
/**
|
|
80
|
-
* Toggles the accordion between open and closed states
|
|
81
|
-
* @public
|
|
82
|
-
*/
|
|
83
|
-
this.toggle = () => {
|
|
84
|
-
if (this.open) {
|
|
85
|
-
this.close();
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
this.show();
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
/**
|
|
92
|
-
* Opens the accordion
|
|
93
|
-
* @public
|
|
94
|
-
* @fires accordion-opened
|
|
95
|
-
*/
|
|
96
|
-
this.show = () => {
|
|
97
|
-
this.open = true;
|
|
98
|
-
this.reflectState();
|
|
99
|
-
};
|
|
100
|
-
/**
|
|
101
|
-
* Closes the accordion
|
|
102
|
-
* @public
|
|
103
|
-
* @fires accordion-closed
|
|
104
|
-
*/
|
|
105
|
-
this.close = () => {
|
|
1
|
+
"use strict";
|
|
2
|
+
/// <reference path="./jsx.d.ts" />
|
|
3
|
+
// SSR-safe: Only define and register components in browser environment
|
|
4
|
+
if (typeof window !== 'undefined' && typeof HTMLElement !== 'undefined') {
|
|
5
|
+
/**
|
|
6
|
+
* AccordionItem component - Expandable/collapsible content container with smooth animations
|
|
7
|
+
*
|
|
8
|
+
* @element accordion-item
|
|
9
|
+
*
|
|
10
|
+
* @attr {boolean} open - When present, the accordion starts in an expanded state
|
|
11
|
+
* @attr {string} animation-time - Animation duration in milliseconds (default: "300")
|
|
12
|
+
* @attr {string} animation-easing - CSS easing function (default: "ease")
|
|
13
|
+
*
|
|
14
|
+
* @slot trigger - The clickable element that toggles the accordion (typically a button)
|
|
15
|
+
* @slot - Default slot for the accordion content
|
|
16
|
+
*
|
|
17
|
+
* @fires accordion-opened - Dispatched when the accordion opens (detail: { open: true })
|
|
18
|
+
* @fires accordion-closed - Dispatched when the accordion closes (detail: { open: false })
|
|
19
|
+
*
|
|
20
|
+
* @cssprop [--animation-time] - Can be overridden via CSS custom properties
|
|
21
|
+
* @cssprop [--animation-easing] - Can be overridden via CSS custom properties
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```html
|
|
25
|
+
* <accordion-item>
|
|
26
|
+
* <button slot="trigger">Click to expand</button>
|
|
27
|
+
* <div>Your content here</div>
|
|
28
|
+
* </accordion-item>
|
|
29
|
+
*
|
|
30
|
+
* <!-- Start expanded with custom animation -->
|
|
31
|
+
* <accordion-item open animation-time="500" animation-easing="ease-in-out">
|
|
32
|
+
* <button slot="trigger">Already open</button>
|
|
33
|
+
* <div>This content is visible by default</div>
|
|
34
|
+
* </accordion-item>
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```javascript
|
|
39
|
+
* // Programmatic control
|
|
40
|
+
* const accordion = document.querySelector('accordion-item');
|
|
41
|
+
* accordion.show(); // Open
|
|
42
|
+
* accordion.close(); // Close
|
|
43
|
+
* accordion.toggle(); // Toggle state
|
|
44
|
+
*
|
|
45
|
+
* // Listen to events
|
|
46
|
+
* accordion.addEventListener('accordion-opened', (e) => {
|
|
47
|
+
* console.log('Opened!', e.detail);
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @note Automatically adds ARIA attributes (aria-expanded) for accessibility
|
|
52
|
+
* @note Supports keyboard navigation (Enter/Space) for non-button triggers
|
|
53
|
+
*/
|
|
54
|
+
class AccordionItem extends HTMLElement {
|
|
55
|
+
constructor() {
|
|
56
|
+
super();
|
|
57
|
+
this.trigger = null;
|
|
58
|
+
this.triggerElement = null;
|
|
106
59
|
this.open = false;
|
|
107
|
-
this.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
60
|
+
this.setupTriggerAccessibility = () => {
|
|
61
|
+
if (!this.trigger)
|
|
62
|
+
return;
|
|
63
|
+
this.triggerElement = this.trigger.assignedElements()[0];
|
|
64
|
+
if (!this.triggerElement)
|
|
65
|
+
return;
|
|
66
|
+
// If the slotted element is not a button, add keyboard support
|
|
67
|
+
if (this.triggerElement.tagName !== 'BUTTON' && !this.triggerElement.hasAttribute('role')) {
|
|
68
|
+
this.triggerElement.setAttribute('role', 'button');
|
|
69
|
+
this.triggerElement.setAttribute('tabindex', '0');
|
|
70
|
+
// Add keyboard listener
|
|
71
|
+
this.triggerElement.addEventListener('keydown', this.handleKeydown);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
this.handleTriggerClick = () => {
|
|
75
|
+
this.toggle();
|
|
76
|
+
};
|
|
77
|
+
this.handleKeydown = (e) => {
|
|
78
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
79
|
+
e.preventDefault();
|
|
80
|
+
this.toggle();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Toggles the accordion between open and closed states
|
|
85
|
+
* @public
|
|
86
|
+
*/
|
|
87
|
+
this.toggle = () => {
|
|
88
|
+
if (this.open) {
|
|
89
|
+
this.close();
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
this.show();
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Opens the accordion
|
|
97
|
+
* @public
|
|
98
|
+
* @fires accordion-opened
|
|
99
|
+
*/
|
|
100
|
+
this.show = () => {
|
|
101
|
+
this.open = true;
|
|
102
|
+
this.reflectState();
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Closes the accordion
|
|
106
|
+
* @public
|
|
107
|
+
* @fires accordion-closed
|
|
108
|
+
*/
|
|
109
|
+
this.close = () => {
|
|
110
|
+
this.open = false;
|
|
111
|
+
this.reflectState();
|
|
112
|
+
};
|
|
113
|
+
this.reflectState = () => {
|
|
114
|
+
// Update attribute to match property
|
|
115
|
+
this.open ? this.setAttribute('open', '') : this.removeAttribute('open');
|
|
116
|
+
this.updateTriggerAccessibility();
|
|
117
|
+
this.dispatchStateEvent();
|
|
118
|
+
};
|
|
119
|
+
this.dispatchStateEvent = () => {
|
|
120
|
+
// Dispatch custom events
|
|
121
|
+
this.dispatchEvent(new CustomEvent(this.open ? 'accordion-opened' : 'accordion-closed', {
|
|
122
|
+
bubbles: true,
|
|
123
|
+
composed: true,
|
|
124
|
+
detail: { open: this.open }
|
|
125
|
+
}));
|
|
126
|
+
};
|
|
127
|
+
this.updateTriggerAccessibility = () => {
|
|
128
|
+
if (!this.trigger)
|
|
129
|
+
return;
|
|
130
|
+
const triggerElement = this.trigger.assignedElements()[0];
|
|
131
|
+
if (triggerElement) {
|
|
132
|
+
triggerElement.setAttribute('aria-expanded', String(this.open));
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
// Initialize state from attribute
|
|
136
|
+
this.open = this.hasAttribute('open');
|
|
137
|
+
this.animationTime = this.getAttribute('animation-time') || '300';
|
|
138
|
+
this.easing = this.getAttribute('animation-easing') || 'ease';
|
|
139
|
+
this.shadow = this.attachShadow({ mode: 'open' });
|
|
140
|
+
this.shadow.innerHTML = /*HTML*/ `
|
|
137
141
|
<style>
|
|
138
142
|
:host{
|
|
139
143
|
display: block;
|
|
@@ -161,144 +165,146 @@ export class AccordionItem extends HTMLElement {
|
|
|
161
165
|
</div>
|
|
162
166
|
</div>
|
|
163
167
|
`;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
168
|
+
}
|
|
169
|
+
static get observedAttributes() {
|
|
170
|
+
return ['open'];
|
|
171
|
+
}
|
|
172
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
173
|
+
if (oldValue === newValue)
|
|
174
|
+
return;
|
|
175
|
+
switch (name) {
|
|
176
|
+
case 'open':
|
|
177
|
+
const shouldBeOpen = newValue !== null;
|
|
178
|
+
// Only update if state actually changed to prevent infinite loop
|
|
179
|
+
if (this.open !== shouldBeOpen) {
|
|
180
|
+
this.open = shouldBeOpen;
|
|
181
|
+
this.updateTriggerAccessibility();
|
|
182
|
+
this.dispatchStateEvent();
|
|
183
|
+
}
|
|
184
|
+
break;
|
|
185
|
+
default:
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
connectedCallback() {
|
|
190
|
+
this.trigger = this.shadow.querySelector('slot[name="trigger"]');
|
|
191
|
+
if (this.trigger) {
|
|
192
|
+
this.trigger.addEventListener('click', this.handleTriggerClick);
|
|
193
|
+
// Setup accessibility for trigger element
|
|
194
|
+
requestAnimationFrame(() => {
|
|
195
|
+
this.setupTriggerAccessibility();
|
|
177
196
|
this.updateTriggerAccessibility();
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
break;
|
|
181
|
-
default:
|
|
182
|
-
break;
|
|
197
|
+
});
|
|
198
|
+
}
|
|
183
199
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
this.updateTriggerAccessibility();
|
|
193
|
-
});
|
|
200
|
+
disconnectedCallback() {
|
|
201
|
+
if (this.trigger) {
|
|
202
|
+
this.trigger.removeEventListener('click', this.handleTriggerClick);
|
|
203
|
+
}
|
|
204
|
+
// Cleanup keyboard listener
|
|
205
|
+
if (this.triggerElement) {
|
|
206
|
+
this.triggerElement.removeEventListener('keydown', this.handleKeydown);
|
|
207
|
+
}
|
|
194
208
|
}
|
|
195
209
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
210
|
+
/**
|
|
211
|
+
* AccordionGroup component - Container for managing multiple accordion items with mutual exclusion
|
|
212
|
+
*
|
|
213
|
+
* @element accordion-group
|
|
214
|
+
*
|
|
215
|
+
* @attr {boolean} allow-multiple-open - When present, allows multiple accordions to be open simultaneously. By default, opening one accordion closes all others in the group.
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```html
|
|
219
|
+
* <!-- Only one accordion can be open at a time -->
|
|
220
|
+
* <accordion-group>
|
|
221
|
+
* <accordion-item open>
|
|
222
|
+
* <button slot="trigger">First Item</button>
|
|
223
|
+
* <div>Opening another will close this</div>
|
|
224
|
+
* </accordion-item>
|
|
225
|
+
*
|
|
226
|
+
* <accordion-item>
|
|
227
|
+
* <button slot="trigger">Second Item</button>
|
|
228
|
+
* <div>Only one can be open at a time</div>
|
|
229
|
+
* </accordion-item>
|
|
230
|
+
*
|
|
231
|
+
* <accordion-item>
|
|
232
|
+
* <button slot="trigger">Third Item</button>
|
|
233
|
+
* <div>Same behavior here</div>
|
|
234
|
+
* </accordion-item>
|
|
235
|
+
* </accordion-group>
|
|
236
|
+
* ```
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```html
|
|
240
|
+
* <!-- Allow multiple accordions to be open -->
|
|
241
|
+
* <accordion-group allow-multiple-open>
|
|
242
|
+
* <accordion-item>
|
|
243
|
+
* <button slot="trigger">First Item</button>
|
|
244
|
+
* <div>Can be open with others</div>
|
|
245
|
+
* </accordion-item>
|
|
246
|
+
*
|
|
247
|
+
* <accordion-item>
|
|
248
|
+
* <button slot="trigger">Second Item</button>
|
|
249
|
+
* <div>Multiple can be open</div>
|
|
250
|
+
* </accordion-item>
|
|
251
|
+
* </accordion-group>
|
|
252
|
+
* ```
|
|
253
|
+
*
|
|
254
|
+
* @note Each accordion-group works independently. Multiple groups on the same page don't affect each other.
|
|
255
|
+
* @note The group listens to 'accordion-opened' events from child accordion-item elements
|
|
256
|
+
*/
|
|
257
|
+
class AccordionGroup extends HTMLElement {
|
|
258
|
+
constructor() {
|
|
259
|
+
super();
|
|
260
|
+
this.handleAccordionOpened = (e) => {
|
|
261
|
+
if (this.allowMultiple)
|
|
262
|
+
return;
|
|
263
|
+
const childAccordions = this.querySelectorAll('accordion-item');
|
|
264
|
+
childAccordions.forEach(acc => {
|
|
265
|
+
const accordion = acc;
|
|
266
|
+
if (e.target !== accordion) {
|
|
267
|
+
if (accordion.open)
|
|
268
|
+
accordion.close();
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
};
|
|
272
|
+
if (!AccordionGroup.stylesApplied) {
|
|
273
|
+
const sheet = new CSSStyleSheet();
|
|
274
|
+
sheet.replaceSync('accordion-group { display: block; }');
|
|
275
|
+
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
|
|
276
|
+
AccordionGroup.stylesApplied = true;
|
|
277
|
+
}
|
|
278
|
+
this.allowMultiple = this.hasAttribute('allow-multiple-open');
|
|
199
279
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
this.triggerElement.removeEventListener('keydown', this.handleKeydown);
|
|
280
|
+
static get observedAttributes() {
|
|
281
|
+
return ['allow-multiple-open'];
|
|
203
282
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* AccordionGroup component - Container for managing multiple accordion items with mutual exclusion
|
|
208
|
-
*
|
|
209
|
-
* @element accordion-group
|
|
210
|
-
*
|
|
211
|
-
* @attr {boolean} allow-multiple-open - When present, allows multiple accordions to be open simultaneously. By default, opening one accordion closes all others in the group.
|
|
212
|
-
*
|
|
213
|
-
* @example
|
|
214
|
-
* ```html
|
|
215
|
-
* <!-- Only one accordion can be open at a time -->
|
|
216
|
-
* <accordion-group>
|
|
217
|
-
* <accordion-item open>
|
|
218
|
-
* <button slot="trigger">First Item</button>
|
|
219
|
-
* <div>Opening another will close this</div>
|
|
220
|
-
* </accordion-item>
|
|
221
|
-
*
|
|
222
|
-
* <accordion-item>
|
|
223
|
-
* <button slot="trigger">Second Item</button>
|
|
224
|
-
* <div>Only one can be open at a time</div>
|
|
225
|
-
* </accordion-item>
|
|
226
|
-
*
|
|
227
|
-
* <accordion-item>
|
|
228
|
-
* <button slot="trigger">Third Item</button>
|
|
229
|
-
* <div>Same behavior here</div>
|
|
230
|
-
* </accordion-item>
|
|
231
|
-
* </accordion-group>
|
|
232
|
-
* ```
|
|
233
|
-
*
|
|
234
|
-
* @example
|
|
235
|
-
* ```html
|
|
236
|
-
* <!-- Allow multiple accordions to be open -->
|
|
237
|
-
* <accordion-group allow-multiple-open>
|
|
238
|
-
* <accordion-item>
|
|
239
|
-
* <button slot="trigger">First Item</button>
|
|
240
|
-
* <div>Can be open with others</div>
|
|
241
|
-
* </accordion-item>
|
|
242
|
-
*
|
|
243
|
-
* <accordion-item>
|
|
244
|
-
* <button slot="trigger">Second Item</button>
|
|
245
|
-
* <div>Multiple can be open</div>
|
|
246
|
-
* </accordion-item>
|
|
247
|
-
* </accordion-group>
|
|
248
|
-
* ```
|
|
249
|
-
*
|
|
250
|
-
* @note Each accordion-group works independently. Multiple groups on the same page don't affect each other.
|
|
251
|
-
* @note The group listens to 'accordion-opened' events from child accordion-item elements
|
|
252
|
-
*/
|
|
253
|
-
export class AccordionGroup extends HTMLElement {
|
|
254
|
-
constructor() {
|
|
255
|
-
super();
|
|
256
|
-
this.handleAccordionOpened = (e) => {
|
|
257
|
-
if (this.allowMultiple)
|
|
283
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
284
|
+
if (oldValue === newValue)
|
|
258
285
|
return;
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
sheet.replaceSync('accordion-group { display: block; }');
|
|
271
|
-
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
|
|
272
|
-
AccordionGroup.stylesApplied = true;
|
|
286
|
+
switch (name) {
|
|
287
|
+
case 'allow-multiple-open':
|
|
288
|
+
const shouldBeAllowed = newValue !== null;
|
|
289
|
+
// Only update if state actually changed to prevent infinite loop
|
|
290
|
+
if (this.allowMultiple !== shouldBeAllowed) {
|
|
291
|
+
this.allowMultiple = shouldBeAllowed;
|
|
292
|
+
}
|
|
293
|
+
break;
|
|
294
|
+
default:
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
273
297
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
attributeChangedCallback(name, oldValue, newValue) {
|
|
280
|
-
if (oldValue === newValue)
|
|
281
|
-
return;
|
|
282
|
-
switch (name) {
|
|
283
|
-
case 'allow-multiple-open':
|
|
284
|
-
const shouldBeAllowed = newValue !== null;
|
|
285
|
-
// Only update if state actually changed to prevent infinite loop
|
|
286
|
-
if (this.allowMultiple !== shouldBeAllowed) {
|
|
287
|
-
this.allowMultiple = shouldBeAllowed;
|
|
288
|
-
}
|
|
289
|
-
break;
|
|
290
|
-
default:
|
|
291
|
-
break;
|
|
298
|
+
connectedCallback() {
|
|
299
|
+
this.addEventListener('accordion-opened', this.handleAccordionOpened);
|
|
300
|
+
}
|
|
301
|
+
disconnectedCallback() {
|
|
302
|
+
this.removeEventListener('accordion-opened', this.handleAccordionOpened);
|
|
292
303
|
}
|
|
293
304
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
this.removeEventListener('accordion-opened', this.handleAccordionOpened);
|
|
299
|
-
}
|
|
305
|
+
AccordionGroup.stylesApplied = false;
|
|
306
|
+
// Register custom elements
|
|
307
|
+
customElements.define('accordion-item', AccordionItem);
|
|
308
|
+
customElements.define('accordion-group', AccordionGroup);
|
|
300
309
|
}
|
|
301
|
-
AccordionGroup.stylesApplied = false;
|
|
302
|
-
customElements.define('accordion-item', AccordionItem);
|
|
303
|
-
customElements.define('accordion-group', AccordionGroup);
|
|
304
310
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gnireeg/accordion",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Accessible accordion web component with smooth animations, keyboard support, and nested accordion groups",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"
|
|
11
|
-
"
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"node": "./dist/index.js",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./jsx": {
|
|
15
|
+
"types": "./dist/jsx.d.ts"
|
|
12
16
|
}
|
|
13
17
|
},
|
|
14
18
|
"files": [
|