@magic-spells/collapsible-content 1.1.0 → 1.2.0
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/README.md +64 -6
- package/dist/collapsible-content.cjs.js +190 -63
- package/dist/collapsible-content.cjs.js.map +1 -1
- package/dist/collapsible-content.css +1 -0
- package/dist/collapsible-content.esm.js +190 -64
- package/dist/collapsible-content.esm.js.map +1 -1
- package/dist/collapsible-content.js +190 -63
- package/dist/collapsible-content.js.map +1 -1
- package/dist/collapsible-content.min.css +1 -1
- package/dist/collapsible-content.min.js +1 -1
- package/package.json +1 -1
- package/src/collapsible-content.css +1 -0
- package/src/collapsible-content.js +190 -64
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ A lightweight, accessible Web Component for creating collapsible content section
|
|
|
11
11
|
- Accessible (ARIA attributes, keyboard support, focus management)
|
|
12
12
|
- Smooth animations with `prefers-reduced-motion` support
|
|
13
13
|
- Smooth mid-animation reversal on rapid clicks
|
|
14
|
+
- Fully drivable from markup (`open` attribute, `<collapsible-group>`) or from JS
|
|
14
15
|
- Safe to import multiple times (no double-registration errors)
|
|
15
16
|
|
|
16
17
|
## Installation
|
|
@@ -60,7 +61,7 @@ Add the `open` attribute to start with content visible:
|
|
|
60
61
|
|
|
61
62
|
Animation duration scales dynamically with content height using a px/sec speed model. Short panels animate quickly, tall panels take proportionally longer — no fixed duration that feels too slow or too fast.
|
|
62
63
|
|
|
63
|
-
The default speed is `900` px/sec. Duration is clamped between 250ms and
|
|
64
|
+
The default speed is `900` px/sec. Duration is clamped between 250ms and 800ms so animations always feel responsive. Tune it with the `speed`, `min-duration`, and `max-duration` attributes:
|
|
64
65
|
|
|
65
66
|
```html
|
|
66
67
|
<!-- Default: 900px/sec -->
|
|
@@ -80,7 +81,7 @@ The default speed is `900` px/sec. Duration is clamped between 250ms and 1s so a
|
|
|
80
81
|
| -------------- | ------- | ------------------------------------------ |
|
|
81
82
|
| `speed` | `900` | Animation speed in pixels per second |
|
|
82
83
|
| `min-duration` | `0.25` | Minimum animation duration in seconds |
|
|
83
|
-
| `max-duration` | `
|
|
84
|
+
| `max-duration` | `0.8` | Maximum animation duration in seconds |
|
|
84
85
|
|
|
85
86
|
## Accordion Groups
|
|
86
87
|
|
|
@@ -104,9 +105,37 @@ Link collapsible components together with the `group` attribute so that opening
|
|
|
104
105
|
|
|
105
106
|
Items without a `group` attribute continue to work independently. All items in a group can be closed simultaneously — clicking the open item simply closes it.
|
|
106
107
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
### Grouping by ancestor
|
|
109
|
+
|
|
110
|
+
`<collapsible-group>` links items by position instead of by name — handy when the markup is generated and there is no name to share. Add `exclusive` to get accordion behavior:
|
|
111
|
+
|
|
112
|
+
```html
|
|
113
|
+
<collapsible-group exclusive>
|
|
114
|
+
<collapsible-component>
|
|
115
|
+
<button type="button">Question One</button>
|
|
116
|
+
<collapsible-content>
|
|
117
|
+
<p>Answer one.</p>
|
|
118
|
+
</collapsible-content>
|
|
119
|
+
</collapsible-component>
|
|
120
|
+
|
|
121
|
+
<collapsible-component>
|
|
122
|
+
<button type="button">Question Two</button>
|
|
123
|
+
<collapsible-content>
|
|
124
|
+
<p>Answer two.</p>
|
|
125
|
+
</collapsible-content>
|
|
126
|
+
</collapsible-component>
|
|
127
|
+
</collapsible-group>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
An authored `open` is taken at face value on first connect — two items in an exclusive group that both start open both stay open, and no events fire. Exclusivity is enforced only on a real state change.
|
|
131
|
+
|
|
132
|
+
Without `exclusive` the group is just a container and items stay independent. A component joins its *nearest* ancestor group, so nested groups do not interfere. An explicit `group="name"` always wins — such a component ignores any surrounding `<collapsible-group>`.
|
|
133
|
+
|
|
134
|
+
| Attribute | Element | Default | Description |
|
|
135
|
+
| ----------- | --------------------------- | ------- | ------------------------------------------------------ |
|
|
136
|
+
| `group` | `<collapsible-component>` | — | Group name; items with the same name form an accordion |
|
|
137
|
+
| `exclusive` | `<collapsible-group>` | — | Opening one item in the group closes the others |
|
|
138
|
+
| `open` | `<collapsible-content>` | — | Expanded state; add or remove it to animate open/closed |
|
|
110
139
|
|
|
111
140
|
## Customization
|
|
112
141
|
|
|
@@ -125,6 +154,17 @@ collapsible-content {
|
|
|
125
154
|
|
|
126
155
|
## Events
|
|
127
156
|
|
|
157
|
+
### collapsible:toggle
|
|
158
|
+
|
|
159
|
+
Fired on `<collapsible-component>` after every state change — a button click, a property or method call, an `open` attribute change, or a sibling closed by an exclusive group. It bubbles and crosses shadow boundaries, so a single listener can cover a whole page. A no-op change fires nothing.
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
document.addEventListener('collapsible:toggle', (e) => {
|
|
163
|
+
console.log(e.detail.open); // boolean — the new state
|
|
164
|
+
console.log(e.detail.content); // the <collapsible-content> element
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
128
168
|
### collapsible-error
|
|
129
169
|
|
|
130
170
|
Fired when the component is missing required children:
|
|
@@ -137,7 +177,25 @@ document.addEventListener('collapsible-error', (e) => {
|
|
|
137
177
|
|
|
138
178
|
## Programmatic Control
|
|
139
179
|
|
|
140
|
-
|
|
180
|
+
`<collapsible-component>` exposes an `open` property plus `show()`, `hide()`, and `toggle()`. All are idempotent:
|
|
181
|
+
|
|
182
|
+
```javascript
|
|
183
|
+
const item = document.querySelector('collapsible-component');
|
|
184
|
+
item.show(); // expand
|
|
185
|
+
item.hide(); // collapse
|
|
186
|
+
item.toggle(); // flip
|
|
187
|
+
item.open = true; // same as show()
|
|
188
|
+
console.log(item.open); // read current state
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
You can also drive it from markup — adding or removing the `open` attribute on `<collapsible-content>` runs the same animation:
|
|
192
|
+
|
|
193
|
+
```javascript
|
|
194
|
+
content.setAttribute('open', ''); // expand
|
|
195
|
+
content.removeAttribute('open'); // collapse
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Or set the `collapsed` property on the `<collapsible-content>` element directly:
|
|
141
199
|
|
|
142
200
|
```javascript
|
|
143
201
|
const content = document.querySelector('collapsible-content');
|
|
@@ -2,35 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
const DEFAULT_SPEED = 900; // px per second
|
|
4
4
|
const MIN_DURATION = 0.25; // seconds
|
|
5
|
-
const MAX_DURATION =
|
|
5
|
+
const MAX_DURATION = 0.8; // seconds
|
|
6
|
+
|
|
7
|
+
// hidden hook the content element uses to report a state change to its component
|
|
8
|
+
const NOTIFY = Symbol('collapsible:notify');
|
|
9
|
+
|
|
10
|
+
// named accordion groups — group attribute value -> Set of components
|
|
11
|
+
const namedGroups = new Map();
|
|
12
|
+
|
|
13
|
+
// <collapsible-group> element -> Set of components that joined it
|
|
14
|
+
const elementGroups = new WeakMap();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Optional ancestor element that links components without a shared group name.
|
|
18
|
+
* Add the `exclusive` attribute to make opening one item close the others.
|
|
19
|
+
*/
|
|
20
|
+
class CollapsibleGroup extends HTMLElement {}
|
|
6
21
|
|
|
7
22
|
/**
|
|
8
23
|
* Custom element that creates a collapsible/expandable component with proper accessibility
|
|
9
24
|
*/
|
|
10
25
|
class CollapsibleComponent extends HTMLElement {
|
|
11
|
-
static #groups = new Map();
|
|
12
|
-
|
|
13
|
-
static #addToGroup(name, instance) {
|
|
14
|
-
if (!CollapsibleComponent.#groups.has(name)) {
|
|
15
|
-
CollapsibleComponent.#groups.set(name, new Set());
|
|
16
|
-
}
|
|
17
|
-
CollapsibleComponent.#groups.get(name).add(instance);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
static #removeFromGroup(name, instance) {
|
|
21
|
-
const group = CollapsibleComponent.#groups.get(name);
|
|
22
|
-
if (group) {
|
|
23
|
-
group.delete(instance);
|
|
24
|
-
if (group.size === 0) CollapsibleComponent.#groups.delete(name);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
26
|
static get observedAttributes() {
|
|
29
27
|
return ['group'];
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
#handleClick;
|
|
33
31
|
#abortController;
|
|
32
|
+
#groupElement = null;
|
|
34
33
|
|
|
35
34
|
/**
|
|
36
35
|
* Initializes the component and sets up references to child elements
|
|
@@ -45,10 +44,7 @@ class CollapsibleComponent extends HTMLElement {
|
|
|
45
44
|
|
|
46
45
|
// define click handler — content is source of truth
|
|
47
46
|
_.#handleClick = () => {
|
|
48
|
-
|
|
49
|
-
_.content.collapsed = !wasCollapsed;
|
|
50
|
-
_.button.setAttribute('aria-expanded', !_.content.collapsed);
|
|
51
|
-
if (wasCollapsed) _.#closeSiblings();
|
|
47
|
+
_.content.collapsed = !_.content.collapsed;
|
|
52
48
|
};
|
|
53
49
|
}
|
|
54
50
|
|
|
@@ -59,6 +55,13 @@ class CollapsibleComponent extends HTMLElement {
|
|
|
59
55
|
connectedCallback() {
|
|
60
56
|
const _ = this;
|
|
61
57
|
|
|
58
|
+
// (re)join a group on every connect — a DOM move runs disconnect then connect,
|
|
59
|
+
// and attributeChangedCallback only fires on a real attribute change.
|
|
60
|
+
// Both registries are Sets, so re-adding on first connect is a no-op.
|
|
61
|
+
const name = _.#groupName;
|
|
62
|
+
if (name) _.#addToNamedGroup(name);
|
|
63
|
+
else _.#joinGroupElement();
|
|
64
|
+
|
|
62
65
|
// initialize element references once
|
|
63
66
|
_.button = _.querySelector('button');
|
|
64
67
|
_.content = _.querySelector('collapsible-content');
|
|
@@ -112,8 +115,16 @@ class CollapsibleComponent extends HTMLElement {
|
|
|
112
115
|
|
|
113
116
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
114
117
|
if (name !== 'group') return;
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
const _ = this;
|
|
119
|
+
|
|
120
|
+
// an empty group="" counts as no name
|
|
121
|
+
if (oldValue) _.#removeFromNamedGroup(oldValue);
|
|
122
|
+
if (newValue) _.#addToNamedGroup(newValue);
|
|
123
|
+
|
|
124
|
+
// an explicit group name wins over any ancestor <collapsible-group>
|
|
125
|
+
if (!_.isConnected) return;
|
|
126
|
+
if (newValue) _.#leaveGroupElement();
|
|
127
|
+
else _.#joinGroupElement();
|
|
117
128
|
}
|
|
118
129
|
|
|
119
130
|
/**
|
|
@@ -122,26 +133,108 @@ class CollapsibleComponent extends HTMLElement {
|
|
|
122
133
|
*/
|
|
123
134
|
disconnectedCallback() {
|
|
124
135
|
const _ = this;
|
|
125
|
-
const
|
|
126
|
-
if (
|
|
136
|
+
const name = _.#groupName;
|
|
137
|
+
if (name) _.#removeFromNamedGroup(name);
|
|
138
|
+
_.#leaveGroupElement();
|
|
127
139
|
if (_.#abortController) {
|
|
128
140
|
_.#abortController.abort();
|
|
129
141
|
_.#abortController = null;
|
|
130
142
|
}
|
|
131
143
|
}
|
|
132
144
|
|
|
133
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Whether the panel is currently expanded
|
|
147
|
+
* @returns {boolean}
|
|
148
|
+
*/
|
|
149
|
+
get open() {
|
|
150
|
+
return !!this.content && !this.content.collapsed;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
set open(value) {
|
|
154
|
+
if (this.content) this.content.collapsed = !value;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Expands the panel (no-op if already expanded) */
|
|
158
|
+
show() {
|
|
159
|
+
this.open = true;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Collapses the panel (no-op if already collapsed) */
|
|
163
|
+
hide() {
|
|
164
|
+
this.open = false;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Toggles the panel */
|
|
168
|
+
toggle() {
|
|
169
|
+
this.open = !this.open;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Reports a state change coming from the content element
|
|
174
|
+
* @param {CollapsibleContent} content - the content element that changed
|
|
175
|
+
* @param {boolean} open - the new expanded state
|
|
176
|
+
*/
|
|
177
|
+
[NOTIFY](content, open) {
|
|
134
178
|
const _ = this;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
179
|
+
if (_.content !== content) return;
|
|
180
|
+
|
|
181
|
+
if (_.button) _.button.setAttribute('aria-expanded', String(open));
|
|
182
|
+
if (open) _.#closeSiblings();
|
|
183
|
+
|
|
184
|
+
_.dispatchEvent(
|
|
185
|
+
new CustomEvent('collapsible:toggle', {
|
|
186
|
+
bubbles: true,
|
|
187
|
+
composed: true,
|
|
188
|
+
detail: { open, content },
|
|
189
|
+
})
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Group name, with an empty group="" normalized to null */
|
|
194
|
+
get #groupName() {
|
|
195
|
+
return this.getAttribute('group') || null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
#addToNamedGroup(name) {
|
|
199
|
+
if (!namedGroups.has(name)) namedGroups.set(name, new Set());
|
|
200
|
+
namedGroups.get(name).add(this);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
#removeFromNamedGroup(name) {
|
|
204
|
+
const group = namedGroups.get(name);
|
|
138
205
|
if (!group) return;
|
|
139
|
-
|
|
206
|
+
group.delete(this);
|
|
207
|
+
if (group.size === 0) namedGroups.delete(name);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
#joinGroupElement() {
|
|
211
|
+
const _ = this;
|
|
212
|
+
const element = _.closest('collapsible-group');
|
|
213
|
+
if (!element) return;
|
|
214
|
+
if (!elementGroups.has(element)) elementGroups.set(element, new Set());
|
|
215
|
+
elementGroups.get(element).add(_);
|
|
216
|
+
_.#groupElement = element;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
#leaveGroupElement() {
|
|
220
|
+
const _ = this;
|
|
221
|
+
if (!_.#groupElement) return;
|
|
222
|
+
elementGroups.get(_.#groupElement)?.delete(_);
|
|
223
|
+
_.#groupElement = null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
#closeSiblings() {
|
|
227
|
+
const _ = this;
|
|
228
|
+
const name = _.#groupName;
|
|
229
|
+
let siblings = null;
|
|
230
|
+
if (name) siblings = namedGroups.get(name);
|
|
231
|
+
else if (_.#groupElement?.hasAttribute('exclusive'))
|
|
232
|
+
siblings = elementGroups.get(_.#groupElement);
|
|
233
|
+
if (!siblings) return;
|
|
234
|
+
|
|
235
|
+
for (const sibling of siblings) {
|
|
140
236
|
if (sibling === _) continue;
|
|
141
|
-
if (!sibling.content.collapsed)
|
|
142
|
-
sibling.content.collapsed = true;
|
|
143
|
-
sibling.button.setAttribute('aria-expanded', 'false');
|
|
144
|
-
}
|
|
237
|
+
if (sibling.content && !sibling.content.collapsed) sibling.content.collapsed = true;
|
|
145
238
|
}
|
|
146
239
|
}
|
|
147
240
|
}
|
|
@@ -150,9 +243,14 @@ class CollapsibleComponent extends HTMLElement {
|
|
|
150
243
|
* Custom element that provides animated collapsible content
|
|
151
244
|
*/
|
|
152
245
|
class CollapsibleContent extends HTMLElement {
|
|
246
|
+
static get observedAttributes() {
|
|
247
|
+
return ['open'];
|
|
248
|
+
}
|
|
249
|
+
|
|
153
250
|
#handleTransitionEnd;
|
|
154
251
|
#abortController;
|
|
155
|
-
#
|
|
252
|
+
#ready = false;
|
|
253
|
+
#selfWrite = false;
|
|
156
254
|
|
|
157
255
|
/**
|
|
158
256
|
* Initializes the content element and binds event handlers
|
|
@@ -166,7 +264,6 @@ class CollapsibleContent extends HTMLElement {
|
|
|
166
264
|
if (event.target !== _) return;
|
|
167
265
|
if (event.propertyName !== 'height') return;
|
|
168
266
|
|
|
169
|
-
_.#animating = false;
|
|
170
267
|
_.style.removeProperty('--collapsible-duration');
|
|
171
268
|
|
|
172
269
|
// remove the inline height to allow dynamic content changes
|
|
@@ -189,6 +286,9 @@ class CollapsibleContent extends HTMLElement {
|
|
|
189
286
|
_.addEventListener('transitionend', _.#handleTransitionEnd, {
|
|
190
287
|
signal: _.#abortController.signal,
|
|
191
288
|
});
|
|
289
|
+
|
|
290
|
+
// from here on, an external `open` attribute change animates
|
|
291
|
+
_.#ready = true;
|
|
192
292
|
}
|
|
193
293
|
|
|
194
294
|
/**
|
|
@@ -197,13 +297,24 @@ class CollapsibleContent extends HTMLElement {
|
|
|
197
297
|
*/
|
|
198
298
|
disconnectedCallback() {
|
|
199
299
|
const _ = this;
|
|
200
|
-
_.#
|
|
300
|
+
_.#ready = false;
|
|
201
301
|
if (_.#abortController) {
|
|
202
302
|
_.#abortController.abort();
|
|
203
303
|
_.#abortController = null;
|
|
204
304
|
}
|
|
205
305
|
}
|
|
206
306
|
|
|
307
|
+
/**
|
|
308
|
+
* Runs the transition when `open` is added or removed from outside
|
|
309
|
+
*/
|
|
310
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
311
|
+
const _ = this;
|
|
312
|
+
if (name !== 'open' || _.#selfWrite || !_.#ready) return;
|
|
313
|
+
// only presence matters — ignore value-only changes (open -> open="x")
|
|
314
|
+
if ((oldValue === null) === (newValue === null)) return;
|
|
315
|
+
_.#transition(newValue === null);
|
|
316
|
+
}
|
|
317
|
+
|
|
207
318
|
get #speed() {
|
|
208
319
|
const attr = this.getAttribute('speed');
|
|
209
320
|
if (attr === null) return DEFAULT_SPEED;
|
|
@@ -233,52 +344,64 @@ class CollapsibleContent extends HTMLElement {
|
|
|
233
344
|
}
|
|
234
345
|
|
|
235
346
|
/**
|
|
236
|
-
*
|
|
237
|
-
* @param {boolean}
|
|
347
|
+
* Animates to the requested state, then reports the change
|
|
348
|
+
* @param {boolean} collapsed - target state (the `open` attribute already matches)
|
|
238
349
|
*/
|
|
239
|
-
|
|
350
|
+
#transition(collapsed) {
|
|
240
351
|
const _ = this;
|
|
241
|
-
const collapsed = Boolean(value);
|
|
242
|
-
if (_.collapsed === collapsed) return;
|
|
243
352
|
|
|
244
353
|
// check if transitions are enabled (respects prefers-reduced-motion)
|
|
245
354
|
const hasTransition = getComputedStyle(_).transitionDuration !== '0s';
|
|
246
355
|
|
|
247
356
|
if (collapsed) {
|
|
248
|
-
_.removeAttribute('open');
|
|
249
357
|
_.setAttribute('aria-hidden', 'true');
|
|
250
358
|
_.setAttribute('inert', '');
|
|
251
359
|
|
|
252
360
|
if (!hasTransition) {
|
|
253
361
|
_.style.height = '0px';
|
|
254
|
-
|
|
362
|
+
} else {
|
|
363
|
+
// capture current height in px (converts auto or mid-animation value)
|
|
364
|
+
const currentHeight = _.getBoundingClientRect().height;
|
|
365
|
+
_.style.height = `${currentHeight}px`;
|
|
366
|
+
_.#setDynamicDuration(currentHeight, 0);
|
|
367
|
+
_.offsetHeight; // force reflow — browser commits the px start value
|
|
368
|
+
_.style.height = '0px';
|
|
255
369
|
}
|
|
256
|
-
|
|
257
|
-
// capture current height in px (converts auto or mid-animation value)
|
|
258
|
-
const currentHeight = _.getBoundingClientRect().height;
|
|
259
|
-
_.style.height = `${currentHeight}px`;
|
|
260
|
-
_.#setDynamicDuration(currentHeight, 0);
|
|
261
|
-
_.#animating = true;
|
|
262
|
-
_.offsetHeight; // force reflow — browser commits the px start value
|
|
263
|
-
_.style.height = '0px';
|
|
264
370
|
} else {
|
|
265
|
-
_.setAttribute('open', '');
|
|
266
371
|
_.removeAttribute('aria-hidden');
|
|
267
372
|
_.removeAttribute('inert');
|
|
268
373
|
|
|
269
374
|
if (!hasTransition) {
|
|
270
375
|
_.style.height = 'auto';
|
|
271
|
-
|
|
376
|
+
} else {
|
|
377
|
+
// capture current height in px (0px or mid-animation value)
|
|
378
|
+
const currentHeight = _.getBoundingClientRect().height;
|
|
379
|
+
_.style.height = `${currentHeight}px`;
|
|
380
|
+
_.#setDynamicDuration(currentHeight, _.scrollHeight);
|
|
381
|
+
_.offsetHeight; // force reflow — browser commits the px start value
|
|
382
|
+
_.style.height = `${_.scrollHeight}px`;
|
|
272
383
|
}
|
|
273
|
-
|
|
274
|
-
// capture current height in px (0px or mid-animation value)
|
|
275
|
-
const currentHeight = _.getBoundingClientRect().height;
|
|
276
|
-
_.style.height = `${currentHeight}px`;
|
|
277
|
-
_.#setDynamicDuration(currentHeight, _.scrollHeight);
|
|
278
|
-
_.#animating = true;
|
|
279
|
-
_.offsetHeight; // force reflow — browser commits the px start value
|
|
280
|
-
_.style.height = `${_.scrollHeight}px`;
|
|
281
384
|
}
|
|
385
|
+
|
|
386
|
+
_.closest('collapsible-component')?.[NOTIFY]?.(_, !collapsed);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Handles setting the collapsed state with animation
|
|
391
|
+
* @param {boolean} value - Whether element should be collapsed
|
|
392
|
+
*/
|
|
393
|
+
set collapsed(value) {
|
|
394
|
+
const _ = this;
|
|
395
|
+
const collapsed = Boolean(value);
|
|
396
|
+
if (_.collapsed === collapsed) return;
|
|
397
|
+
|
|
398
|
+
// mirror to the attribute without re-entering attributeChangedCallback
|
|
399
|
+
_.#selfWrite = true;
|
|
400
|
+
if (collapsed) _.removeAttribute('open');
|
|
401
|
+
else _.setAttribute('open', '');
|
|
402
|
+
_.#selfWrite = false;
|
|
403
|
+
|
|
404
|
+
_.#transition(collapsed);
|
|
282
405
|
}
|
|
283
406
|
|
|
284
407
|
/**
|
|
@@ -297,7 +420,11 @@ if (!customElements.get('collapsible-content')) {
|
|
|
297
420
|
if (!customElements.get('collapsible-component')) {
|
|
298
421
|
customElements.define('collapsible-component', CollapsibleComponent);
|
|
299
422
|
}
|
|
423
|
+
if (!customElements.get('collapsible-group')) {
|
|
424
|
+
customElements.define('collapsible-group', CollapsibleGroup);
|
|
425
|
+
}
|
|
300
426
|
|
|
301
427
|
exports.CollapsibleComponent = CollapsibleComponent;
|
|
302
428
|
exports.CollapsibleContent = CollapsibleContent;
|
|
429
|
+
exports.CollapsibleGroup = CollapsibleGroup;
|
|
303
430
|
//# sourceMappingURL=collapsible-content.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collapsible-content.cjs.js","sources":["../src/collapsible-content.js"],"sourcesContent":["import './collapsible-content.css';\n\nconst DEFAULT_SPEED = 900; // px per second\nconst MIN_DURATION = 0.25; // seconds\nconst MAX_DURATION = 1.0; // seconds\n\n/**\n * Custom element that creates a collapsible/expandable component with proper accessibility\n */\nclass CollapsibleComponent extends HTMLElement {\n\tstatic #groups = new Map();\n\n\tstatic #addToGroup(name, instance) {\n\t\tif (!CollapsibleComponent.#groups.has(name)) {\n\t\t\tCollapsibleComponent.#groups.set(name, new Set());\n\t\t}\n\t\tCollapsibleComponent.#groups.get(name).add(instance);\n\t}\n\n\tstatic #removeFromGroup(name, instance) {\n\t\tconst group = CollapsibleComponent.#groups.get(name);\n\t\tif (group) {\n\t\t\tgroup.delete(instance);\n\t\t\tif (group.size === 0) CollapsibleComponent.#groups.delete(name);\n\t\t}\n\t}\n\n\tstatic get observedAttributes() {\n\t\treturn ['group'];\n\t}\n\n\t#handleClick;\n\t#abortController;\n\n\t/**\n\t * Initializes the component and sets up references to child elements\n\t */\n\tconstructor() {\n\t\tsuper();\n\t\tconst _ = this;\n\n\t\t// store references to elements once to avoid re-querying\n\t\t_.button = null;\n\t\t_.content = null;\n\n\t\t// define click handler — content is source of truth\n\t\t_.#handleClick = () => {\n\t\t\tconst wasCollapsed = _.content.collapsed;\n\t\t\t_.content.collapsed = !wasCollapsed;\n\t\t\t_.button.setAttribute('aria-expanded', !_.content.collapsed);\n\t\t\tif (wasCollapsed) _.#closeSiblings();\n\t\t};\n\t}\n\n\t/**\n\t * Called when element is added to the DOM\n\t * Sets up accessibility attributes and event listeners\n\t */\n\tconnectedCallback() {\n\t\tconst _ = this;\n\n\t\t// initialize element references once\n\t\t_.button = _.querySelector('button');\n\t\t_.content = _.querySelector('collapsible-content');\n\n\t\tif (!_.button || !_.content) {\n\t\t\tconst error = new Error(\n\t\t\t\t'CollapsibleComponent requires a <button> and a <collapsible-content>.'\n\t\t\t);\n\t\t\tconsole.error(error.message);\n\t\t\t_.dispatchEvent(\n\t\t\t\tnew CustomEvent('collapsible-error', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tdetail: { error },\n\t\t\t\t})\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// generate ids if not provided\n\t\t_.button.id ||= `collapsible-button-${crypto.randomUUID().slice(0, 8)}`;\n\t\t_.content.id ||= `collapsible-content-${crypto.randomUUID().slice(0, 8)}`;\n\n\t\t// set accessibility attributes\n\t\tif (!_.button.hasAttribute('type')) {\n\t\t\t_.button.type = 'button';\n\t\t}\n\t\t_.button.setAttribute('aria-controls', _.content.id);\n\t\t_.content.setAttribute('aria-labelledby', _.button.id);\n\t\tif (!_.content.hasAttribute('role')) {\n\t\t\t_.content.setAttribute('role', 'region');\n\t\t}\n\n\t\t// set initial state without triggering an opening/closing animation\n\t\tconst open = _.content.hasAttribute('open');\n\t\t_.button.setAttribute('aria-expanded', open);\n\t\t_.content.style.height = open ? 'auto' : '0px';\n\t\tif (open) {\n\t\t\t_.content.removeAttribute('aria-hidden');\n\t\t\t_.content.removeAttribute('inert');\n\t\t} else {\n\t\t\t_.content.setAttribute('aria-hidden', 'true');\n\t\t\t_.content.setAttribute('inert', '');\n\t\t}\n\n\t\t// use AbortController to prevent duplicate listeners on reconnection\n\t\t_.#abortController = new AbortController();\n\t\t_.button.addEventListener('click', _.#handleClick, {\n\t\t\tsignal: _.#abortController.signal,\n\t\t});\n\t}\n\n\tattributeChangedCallback(name, oldValue, newValue) {\n\t\tif (name !== 'group') return;\n\t\tif (oldValue) CollapsibleComponent.#removeFromGroup(oldValue, this);\n\t\tif (newValue) CollapsibleComponent.#addToGroup(newValue, this);\n\t}\n\n\t/**\n\t * Called when element is removed from the DOM\n\t * Cleans up event listeners\n\t */\n\tdisconnectedCallback() {\n\t\tconst _ = this;\n\t\tconst group = _.getAttribute('group');\n\t\tif (group) CollapsibleComponent.#removeFromGroup(group, _);\n\t\tif (_.#abortController) {\n\t\t\t_.#abortController.abort();\n\t\t\t_.#abortController = null;\n\t\t}\n\t}\n\n\t#closeSiblings() {\n\t\tconst _ = this;\n\t\tconst groupName = _.getAttribute('group');\n\t\tif (!groupName) return;\n\t\tconst group = CollapsibleComponent.#groups.get(groupName);\n\t\tif (!group) return;\n\t\tfor (const sibling of group) {\n\t\t\tif (sibling === _) continue;\n\t\t\tif (!sibling.content.collapsed) {\n\t\t\t\tsibling.content.collapsed = true;\n\t\t\t\tsibling.button.setAttribute('aria-expanded', 'false');\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Custom element that provides animated collapsible content\n */\nclass CollapsibleContent extends HTMLElement {\n\t#handleTransitionEnd;\n\t#abortController;\n\t#animating = false;\n\n\t/**\n\t * Initializes the content element and binds event handlers\n\t */\n\tconstructor() {\n\t\tsuper();\n\t\tconst _ = this;\n\n\t\t// define event handler using arrow function for proper binding\n\t\t_.#handleTransitionEnd = (event) => {\n\t\t\tif (event.target !== _) return;\n\t\t\tif (event.propertyName !== 'height') return;\n\n\t\t\t_.#animating = false;\n\t\t\t_.style.removeProperty('--collapsible-duration');\n\n\t\t\t// remove the inline height to allow dynamic content changes\n\t\t\tif (!_.collapsed) {\n\t\t\t\t_.style.height = 'auto';\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Called when element is added to the DOM\n\t * Sets initial height based on open attribute\n\t */\n\tconnectedCallback() {\n\t\tconst _ = this;\n\t\t_.style.height = _.hasAttribute('open') ? 'auto' : '0';\n\n\t\t// use AbortController to prevent duplicate listeners on reconnection\n\t\t_.#abortController = new AbortController();\n\t\t_.addEventListener('transitionend', _.#handleTransitionEnd, {\n\t\t\tsignal: _.#abortController.signal,\n\t\t});\n\t}\n\n\t/**\n\t * Called when element is removed from the DOM\n\t * Cleans up event listeners\n\t */\n\tdisconnectedCallback() {\n\t\tconst _ = this;\n\t\t_.#animating = false;\n\t\tif (_.#abortController) {\n\t\t\t_.#abortController.abort();\n\t\t\t_.#abortController = null;\n\t\t}\n\t}\n\n\tget #speed() {\n\t\tconst attr = this.getAttribute('speed');\n\t\tif (attr === null) return DEFAULT_SPEED;\n\t\tconst value = Number(attr);\n\t\treturn value > 0 ? value : DEFAULT_SPEED;\n\t}\n\n\tget #minDuration() {\n\t\tconst attr = this.getAttribute('min-duration');\n\t\tif (attr === null) return MIN_DURATION;\n\t\tconst value = Number(attr);\n\t\treturn value > 0 ? value : MIN_DURATION;\n\t}\n\n\tget #maxDuration() {\n\t\tconst attr = this.getAttribute('max-duration');\n\t\tif (attr === null) return MAX_DURATION;\n\t\tconst value = Number(attr);\n\t\treturn value > 0 ? value : MAX_DURATION;\n\t}\n\n\t#setDynamicDuration(currentHeight, targetHeight) {\n\t\tconst _ = this;\n\t\tconst delta = Math.abs(targetHeight - currentHeight);\n\t\tconst duration = Math.min(_.#maxDuration, Math.max(_.#minDuration, delta / _.#speed));\n\t\t_.style.setProperty('--collapsible-duration', `${duration.toFixed(3)}s`);\n\t}\n\n\t/**\n\t * Handles setting the collapsed state with animation\n\t * @param {boolean} value - Whether element should be collapsed\n\t */\n\tset collapsed(value) {\n\t\tconst _ = this;\n\t\tconst collapsed = Boolean(value);\n\t\tif (_.collapsed === collapsed) return;\n\n\t\t// check if transitions are enabled (respects prefers-reduced-motion)\n\t\tconst hasTransition = getComputedStyle(_).transitionDuration !== '0s';\n\n\t\tif (collapsed) {\n\t\t\t_.removeAttribute('open');\n\t\t\t_.setAttribute('aria-hidden', 'true');\n\t\t\t_.setAttribute('inert', '');\n\n\t\t\tif (!hasTransition) {\n\t\t\t\t_.style.height = '0px';\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// capture current height in px (converts auto or mid-animation value)\n\t\t\tconst currentHeight = _.getBoundingClientRect().height;\n\t\t\t_.style.height = `${currentHeight}px`;\n\t\t\t_.#setDynamicDuration(currentHeight, 0);\n\t\t\t_.#animating = true;\n\t\t\t_.offsetHeight; // force reflow — browser commits the px start value\n\t\t\t_.style.height = '0px';\n\t\t} else {\n\t\t\t_.setAttribute('open', '');\n\t\t\t_.removeAttribute('aria-hidden');\n\t\t\t_.removeAttribute('inert');\n\n\t\t\tif (!hasTransition) {\n\t\t\t\t_.style.height = 'auto';\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// capture current height in px (0px or mid-animation value)\n\t\t\tconst currentHeight = _.getBoundingClientRect().height;\n\t\t\t_.style.height = `${currentHeight}px`;\n\t\t\t_.#setDynamicDuration(currentHeight, _.scrollHeight);\n\t\t\t_.#animating = true;\n\t\t\t_.offsetHeight; // force reflow — browser commits the px start value\n\t\t\t_.style.height = `${_.scrollHeight}px`;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the collapsed state\n\t * @returns {boolean} Whether element is collapsed\n\t */\n\tget collapsed() {\n\t\treturn !this.hasAttribute('open');\n\t}\n}\n\n// register custom elements if not already defined\nif (!customElements.get('collapsible-content')) {\n\tcustomElements.define('collapsible-content', CollapsibleContent);\n}\nif (!customElements.get('collapsible-component')) {\n\tcustomElements.define('collapsible-component', CollapsibleComponent);\n}\n\nexport { CollapsibleContent, CollapsibleComponent };\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"collapsible-content.cjs.js","sources":["../src/collapsible-content.js"],"sourcesContent":["import './collapsible-content.css';\n\nconst DEFAULT_SPEED = 900; // px per second\nconst MIN_DURATION = 0.25; // seconds\nconst MAX_DURATION = 0.8; // seconds\n\n// hidden hook the content element uses to report a state change to its component\nconst NOTIFY = Symbol('collapsible:notify');\n\n// named accordion groups — group attribute value -> Set of components\nconst namedGroups = new Map();\n\n// <collapsible-group> element -> Set of components that joined it\nconst elementGroups = new WeakMap();\n\n/**\n * Optional ancestor element that links components without a shared group name.\n * Add the `exclusive` attribute to make opening one item close the others.\n */\nclass CollapsibleGroup extends HTMLElement {}\n\n/**\n * Custom element that creates a collapsible/expandable component with proper accessibility\n */\nclass CollapsibleComponent extends HTMLElement {\n\tstatic get observedAttributes() {\n\t\treturn ['group'];\n\t}\n\n\t#handleClick;\n\t#abortController;\n\t#groupElement = null;\n\n\t/**\n\t * Initializes the component and sets up references to child elements\n\t */\n\tconstructor() {\n\t\tsuper();\n\t\tconst _ = this;\n\n\t\t// store references to elements once to avoid re-querying\n\t\t_.button = null;\n\t\t_.content = null;\n\n\t\t// define click handler — content is source of truth\n\t\t_.#handleClick = () => {\n\t\t\t_.content.collapsed = !_.content.collapsed;\n\t\t};\n\t}\n\n\t/**\n\t * Called when element is added to the DOM\n\t * Sets up accessibility attributes and event listeners\n\t */\n\tconnectedCallback() {\n\t\tconst _ = this;\n\n\t\t// (re)join a group on every connect — a DOM move runs disconnect then connect,\n\t\t// and attributeChangedCallback only fires on a real attribute change.\n\t\t// Both registries are Sets, so re-adding on first connect is a no-op.\n\t\tconst name = _.#groupName;\n\t\tif (name) _.#addToNamedGroup(name);\n\t\telse _.#joinGroupElement();\n\n\t\t// initialize element references once\n\t\t_.button = _.querySelector('button');\n\t\t_.content = _.querySelector('collapsible-content');\n\n\t\tif (!_.button || !_.content) {\n\t\t\tconst error = new Error(\n\t\t\t\t'CollapsibleComponent requires a <button> and a <collapsible-content>.'\n\t\t\t);\n\t\t\tconsole.error(error.message);\n\t\t\t_.dispatchEvent(\n\t\t\t\tnew CustomEvent('collapsible-error', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tdetail: { error },\n\t\t\t\t})\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// generate ids if not provided\n\t\t_.button.id ||= `collapsible-button-${crypto.randomUUID().slice(0, 8)}`;\n\t\t_.content.id ||= `collapsible-content-${crypto.randomUUID().slice(0, 8)}`;\n\n\t\t// set accessibility attributes\n\t\tif (!_.button.hasAttribute('type')) {\n\t\t\t_.button.type = 'button';\n\t\t}\n\t\t_.button.setAttribute('aria-controls', _.content.id);\n\t\t_.content.setAttribute('aria-labelledby', _.button.id);\n\t\tif (!_.content.hasAttribute('role')) {\n\t\t\t_.content.setAttribute('role', 'region');\n\t\t}\n\n\t\t// set initial state without triggering an opening/closing animation\n\t\tconst open = _.content.hasAttribute('open');\n\t\t_.button.setAttribute('aria-expanded', open);\n\t\t_.content.style.height = open ? 'auto' : '0px';\n\t\tif (open) {\n\t\t\t_.content.removeAttribute('aria-hidden');\n\t\t\t_.content.removeAttribute('inert');\n\t\t} else {\n\t\t\t_.content.setAttribute('aria-hidden', 'true');\n\t\t\t_.content.setAttribute('inert', '');\n\t\t}\n\n\t\t// use AbortController to prevent duplicate listeners on reconnection\n\t\t_.#abortController = new AbortController();\n\t\t_.button.addEventListener('click', _.#handleClick, {\n\t\t\tsignal: _.#abortController.signal,\n\t\t});\n\t}\n\n\tattributeChangedCallback(name, oldValue, newValue) {\n\t\tif (name !== 'group') return;\n\t\tconst _ = this;\n\n\t\t// an empty group=\"\" counts as no name\n\t\tif (oldValue) _.#removeFromNamedGroup(oldValue);\n\t\tif (newValue) _.#addToNamedGroup(newValue);\n\n\t\t// an explicit group name wins over any ancestor <collapsible-group>\n\t\tif (!_.isConnected) return;\n\t\tif (newValue) _.#leaveGroupElement();\n\t\telse _.#joinGroupElement();\n\t}\n\n\t/**\n\t * Called when element is removed from the DOM\n\t * Cleans up event listeners\n\t */\n\tdisconnectedCallback() {\n\t\tconst _ = this;\n\t\tconst name = _.#groupName;\n\t\tif (name) _.#removeFromNamedGroup(name);\n\t\t_.#leaveGroupElement();\n\t\tif (_.#abortController) {\n\t\t\t_.#abortController.abort();\n\t\t\t_.#abortController = null;\n\t\t}\n\t}\n\n\t/**\n\t * Whether the panel is currently expanded\n\t * @returns {boolean}\n\t */\n\tget open() {\n\t\treturn !!this.content && !this.content.collapsed;\n\t}\n\n\tset open(value) {\n\t\tif (this.content) this.content.collapsed = !value;\n\t}\n\n\t/** Expands the panel (no-op if already expanded) */\n\tshow() {\n\t\tthis.open = true;\n\t}\n\n\t/** Collapses the panel (no-op if already collapsed) */\n\thide() {\n\t\tthis.open = false;\n\t}\n\n\t/** Toggles the panel */\n\ttoggle() {\n\t\tthis.open = !this.open;\n\t}\n\n\t/**\n\t * Reports a state change coming from the content element\n\t * @param {CollapsibleContent} content - the content element that changed\n\t * @param {boolean} open - the new expanded state\n\t */\n\t[NOTIFY](content, open) {\n\t\tconst _ = this;\n\t\tif (_.content !== content) return;\n\n\t\tif (_.button) _.button.setAttribute('aria-expanded', String(open));\n\t\tif (open) _.#closeSiblings();\n\n\t\t_.dispatchEvent(\n\t\t\tnew CustomEvent('collapsible:toggle', {\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t\tdetail: { open, content },\n\t\t\t})\n\t\t);\n\t}\n\n\t/** Group name, with an empty group=\"\" normalized to null */\n\tget #groupName() {\n\t\treturn this.getAttribute('group') || null;\n\t}\n\n\t#addToNamedGroup(name) {\n\t\tif (!namedGroups.has(name)) namedGroups.set(name, new Set());\n\t\tnamedGroups.get(name).add(this);\n\t}\n\n\t#removeFromNamedGroup(name) {\n\t\tconst group = namedGroups.get(name);\n\t\tif (!group) return;\n\t\tgroup.delete(this);\n\t\tif (group.size === 0) namedGroups.delete(name);\n\t}\n\n\t#joinGroupElement() {\n\t\tconst _ = this;\n\t\tconst element = _.closest('collapsible-group');\n\t\tif (!element) return;\n\t\tif (!elementGroups.has(element)) elementGroups.set(element, new Set());\n\t\telementGroups.get(element).add(_);\n\t\t_.#groupElement = element;\n\t}\n\n\t#leaveGroupElement() {\n\t\tconst _ = this;\n\t\tif (!_.#groupElement) return;\n\t\telementGroups.get(_.#groupElement)?.delete(_);\n\t\t_.#groupElement = null;\n\t}\n\n\t#closeSiblings() {\n\t\tconst _ = this;\n\t\tconst name = _.#groupName;\n\t\tlet siblings = null;\n\t\tif (name) siblings = namedGroups.get(name);\n\t\telse if (_.#groupElement?.hasAttribute('exclusive'))\n\t\t\tsiblings = elementGroups.get(_.#groupElement);\n\t\tif (!siblings) return;\n\n\t\tfor (const sibling of siblings) {\n\t\t\tif (sibling === _) continue;\n\t\t\tif (sibling.content && !sibling.content.collapsed) sibling.content.collapsed = true;\n\t\t}\n\t}\n}\n\n/**\n * Custom element that provides animated collapsible content\n */\nclass CollapsibleContent extends HTMLElement {\n\tstatic get observedAttributes() {\n\t\treturn ['open'];\n\t}\n\n\t#handleTransitionEnd;\n\t#abortController;\n\t#ready = false;\n\t#selfWrite = false;\n\n\t/**\n\t * Initializes the content element and binds event handlers\n\t */\n\tconstructor() {\n\t\tsuper();\n\t\tconst _ = this;\n\n\t\t// define event handler using arrow function for proper binding\n\t\t_.#handleTransitionEnd = (event) => {\n\t\t\tif (event.target !== _) return;\n\t\t\tif (event.propertyName !== 'height') return;\n\n\t\t\t_.style.removeProperty('--collapsible-duration');\n\n\t\t\t// remove the inline height to allow dynamic content changes\n\t\t\tif (!_.collapsed) {\n\t\t\t\t_.style.height = 'auto';\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Called when element is added to the DOM\n\t * Sets initial height based on open attribute\n\t */\n\tconnectedCallback() {\n\t\tconst _ = this;\n\t\t_.style.height = _.hasAttribute('open') ? 'auto' : '0';\n\n\t\t// use AbortController to prevent duplicate listeners on reconnection\n\t\t_.#abortController = new AbortController();\n\t\t_.addEventListener('transitionend', _.#handleTransitionEnd, {\n\t\t\tsignal: _.#abortController.signal,\n\t\t});\n\n\t\t// from here on, an external `open` attribute change animates\n\t\t_.#ready = true;\n\t}\n\n\t/**\n\t * Called when element is removed from the DOM\n\t * Cleans up event listeners\n\t */\n\tdisconnectedCallback() {\n\t\tconst _ = this;\n\t\t_.#ready = false;\n\t\tif (_.#abortController) {\n\t\t\t_.#abortController.abort();\n\t\t\t_.#abortController = null;\n\t\t}\n\t}\n\n\t/**\n\t * Runs the transition when `open` is added or removed from outside\n\t */\n\tattributeChangedCallback(name, oldValue, newValue) {\n\t\tconst _ = this;\n\t\tif (name !== 'open' || _.#selfWrite || !_.#ready) return;\n\t\t// only presence matters — ignore value-only changes (open -> open=\"x\")\n\t\tif ((oldValue === null) === (newValue === null)) return;\n\t\t_.#transition(newValue === null);\n\t}\n\n\tget #speed() {\n\t\tconst attr = this.getAttribute('speed');\n\t\tif (attr === null) return DEFAULT_SPEED;\n\t\tconst value = Number(attr);\n\t\treturn value > 0 ? value : DEFAULT_SPEED;\n\t}\n\n\tget #minDuration() {\n\t\tconst attr = this.getAttribute('min-duration');\n\t\tif (attr === null) return MIN_DURATION;\n\t\tconst value = Number(attr);\n\t\treturn value > 0 ? value : MIN_DURATION;\n\t}\n\n\tget #maxDuration() {\n\t\tconst attr = this.getAttribute('max-duration');\n\t\tif (attr === null) return MAX_DURATION;\n\t\tconst value = Number(attr);\n\t\treturn value > 0 ? value : MAX_DURATION;\n\t}\n\n\t#setDynamicDuration(currentHeight, targetHeight) {\n\t\tconst _ = this;\n\t\tconst delta = Math.abs(targetHeight - currentHeight);\n\t\tconst duration = Math.min(_.#maxDuration, Math.max(_.#minDuration, delta / _.#speed));\n\t\t_.style.setProperty('--collapsible-duration', `${duration.toFixed(3)}s`);\n\t}\n\n\t/**\n\t * Animates to the requested state, then reports the change\n\t * @param {boolean} collapsed - target state (the `open` attribute already matches)\n\t */\n\t#transition(collapsed) {\n\t\tconst _ = this;\n\n\t\t// check if transitions are enabled (respects prefers-reduced-motion)\n\t\tconst hasTransition = getComputedStyle(_).transitionDuration !== '0s';\n\n\t\tif (collapsed) {\n\t\t\t_.setAttribute('aria-hidden', 'true');\n\t\t\t_.setAttribute('inert', '');\n\n\t\t\tif (!hasTransition) {\n\t\t\t\t_.style.height = '0px';\n\t\t\t} else {\n\t\t\t\t// capture current height in px (converts auto or mid-animation value)\n\t\t\t\tconst currentHeight = _.getBoundingClientRect().height;\n\t\t\t\t_.style.height = `${currentHeight}px`;\n\t\t\t\t_.#setDynamicDuration(currentHeight, 0);\n\t\t\t\t_.offsetHeight; // force reflow — browser commits the px start value\n\t\t\t\t_.style.height = '0px';\n\t\t\t}\n\t\t} else {\n\t\t\t_.removeAttribute('aria-hidden');\n\t\t\t_.removeAttribute('inert');\n\n\t\t\tif (!hasTransition) {\n\t\t\t\t_.style.height = 'auto';\n\t\t\t} else {\n\t\t\t\t// capture current height in px (0px or mid-animation value)\n\t\t\t\tconst currentHeight = _.getBoundingClientRect().height;\n\t\t\t\t_.style.height = `${currentHeight}px`;\n\t\t\t\t_.#setDynamicDuration(currentHeight, _.scrollHeight);\n\t\t\t\t_.offsetHeight; // force reflow — browser commits the px start value\n\t\t\t\t_.style.height = `${_.scrollHeight}px`;\n\t\t\t}\n\t\t}\n\n\t\t_.closest('collapsible-component')?.[NOTIFY]?.(_, !collapsed);\n\t}\n\n\t/**\n\t * Handles setting the collapsed state with animation\n\t * @param {boolean} value - Whether element should be collapsed\n\t */\n\tset collapsed(value) {\n\t\tconst _ = this;\n\t\tconst collapsed = Boolean(value);\n\t\tif (_.collapsed === collapsed) return;\n\n\t\t// mirror to the attribute without re-entering attributeChangedCallback\n\t\t_.#selfWrite = true;\n\t\tif (collapsed) _.removeAttribute('open');\n\t\telse _.setAttribute('open', '');\n\t\t_.#selfWrite = false;\n\n\t\t_.#transition(collapsed);\n\t}\n\n\t/**\n\t * Gets the collapsed state\n\t * @returns {boolean} Whether element is collapsed\n\t */\n\tget collapsed() {\n\t\treturn !this.hasAttribute('open');\n\t}\n}\n\n// register custom elements if not already defined\nif (!customElements.get('collapsible-content')) {\n\tcustomElements.define('collapsible-content', CollapsibleContent);\n}\nif (!customElements.get('collapsible-component')) {\n\tcustomElements.define('collapsible-component', CollapsibleComponent);\n}\nif (!customElements.get('collapsible-group')) {\n\tcustomElements.define('collapsible-group', CollapsibleGroup);\n}\n\nexport { CollapsibleContent, CollapsibleComponent, CollapsibleGroup };\n"],"names":[],"mappings":"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"}
|