panelset 1.0.6 → 1.0.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/CHANGELOG.md +14 -0
- package/dist/index.d.ts +0 -1
- package/dist/panelset.js +109 -126
- package/dist/panelset.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
## [1.0.8] - 2026-02-18
|
|
5
|
+
|
|
6
|
+
### Changed
|
|
7
|
+
- Removed aria-selected.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## [1.0.7] - 2026-02-18
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Add data-attribute for autoFocus. This will override show() or global autoFocus settings.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
3
17
|
## [1.0.6] - 2026-02-18
|
|
4
18
|
|
|
5
19
|
### Added
|
package/dist/index.d.ts
CHANGED
package/dist/panelset.js
CHANGED
|
@@ -10,49 +10,49 @@ const h = class h {
|
|
|
10
10
|
if (this.element = e, h._validateElement(e), e.panelSet || e.dataset.panelset === "true")
|
|
11
11
|
return console.warn("PanelSet: Element already initialized, returning existing instance"), e.panelSet;
|
|
12
12
|
e.panelSet = this;
|
|
13
|
-
const
|
|
13
|
+
const l = h._getDataConfig(e);
|
|
14
14
|
if (this.config = h._mergeConfig(
|
|
15
15
|
h.defaults,
|
|
16
|
-
|
|
16
|
+
l,
|
|
17
17
|
i
|
|
18
18
|
), this.panels = Array.from(e.querySelectorAll('[role="tabpanel"]')), this.panels.length === 0) {
|
|
19
19
|
const s = `<${e.tagName.toLowerCase()}${e.id ? ` id="${e.id}"` : ""}${e.className ? ` class="${e.className}"` : ""}>`;
|
|
20
20
|
console.error(`PanelSet: No panels with [role="tabpanel"] found inside ${s}. Make sure panel elements are children of the [data-panelset] element.`), this.panels = [], this.activePanel = null, this.panelWrapper = null, this.pendingPanel = null;
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
|
-
this.activePanel = this.panels.find((s) => s.classList.contains("active")) || this.panels[0], this.panelWrapper = this.element.querySelector(".panel-wrapper") || this._autoWrapPanels(), this.pendingPanel = this.activePanel, this.element.dataset.panelset = "true", this._log(`Initialized (${this.panels.length} panels)`), this._dispatch("ps:ready", { container: this.element, instance: this }), this._internalInit()
|
|
24
|
-
let
|
|
23
|
+
this.activePanel = this.panels.find((s) => s.classList.contains("active")) || this.panels[0], this.panelWrapper = this.element.querySelector(".panel-wrapper") || this._autoWrapPanels(), this.pendingPanel = this.activePanel, this.element.dataset.panelset = "true", this._log(`Initialized (${this.panels.length} panels)`), this._dispatch("ps:ready", { container: this.element, instance: this }), this._internalInit();
|
|
24
|
+
let o;
|
|
25
25
|
window.addEventListener("resize", () => {
|
|
26
|
-
clearTimeout(
|
|
26
|
+
clearTimeout(o), o = setTimeout(() => {
|
|
27
27
|
this._updateHighestPanel();
|
|
28
28
|
}, 250);
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
31
|
// Parse data attributes from element
|
|
32
32
|
static _getDataConfig(t) {
|
|
33
|
-
const i = t.dataset, e = {},
|
|
33
|
+
const i = t.dataset, e = {}, l = {
|
|
34
34
|
transitions: "json",
|
|
35
35
|
closable: "boolean",
|
|
36
36
|
emptyPanelHeight: "number",
|
|
37
37
|
loadingDelay: "number",
|
|
38
38
|
debug: "boolean"
|
|
39
39
|
};
|
|
40
|
-
for (const [
|
|
41
|
-
if (!(
|
|
42
|
-
const n = i[
|
|
40
|
+
for (const [o, s] of Object.entries(l)) {
|
|
41
|
+
if (!(o in i)) continue;
|
|
42
|
+
const n = i[o];
|
|
43
43
|
if (n !== void 0)
|
|
44
44
|
switch (s) {
|
|
45
45
|
case "boolean":
|
|
46
|
-
e[
|
|
46
|
+
e[o] = n !== "false";
|
|
47
47
|
break;
|
|
48
48
|
case "number":
|
|
49
|
-
e[
|
|
49
|
+
e[o] = parseInt(n, 10);
|
|
50
50
|
break;
|
|
51
51
|
case "json":
|
|
52
52
|
try {
|
|
53
|
-
e[
|
|
53
|
+
e[o] = JSON.parse(n);
|
|
54
54
|
} catch {
|
|
55
|
-
e[
|
|
55
|
+
e[o] = n !== "false";
|
|
56
56
|
}
|
|
57
57
|
break;
|
|
58
58
|
}
|
|
@@ -74,22 +74,22 @@ const h = class h {
|
|
|
74
74
|
* @returns Array of PanelSet instances
|
|
75
75
|
*/
|
|
76
76
|
static init(t = {}, i = {}) {
|
|
77
|
-
let e,
|
|
78
|
-
typeof t == "string" ? (e = t,
|
|
79
|
-
const
|
|
80
|
-
return
|
|
77
|
+
let e, l;
|
|
78
|
+
typeof t == "string" ? (e = t, l = i) : (l = t, e = l.selector || "[data-panelset]");
|
|
79
|
+
const o = document.querySelectorAll(e), s = [];
|
|
80
|
+
return o.forEach((n) => {
|
|
81
81
|
try {
|
|
82
82
|
h._validateElement(n);
|
|
83
|
-
} catch (
|
|
84
|
-
console.error(
|
|
83
|
+
} catch (r) {
|
|
84
|
+
console.error(r.message);
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
87
|
if (n.panelSet || n.dataset.panelset === "true") {
|
|
88
88
|
n.panelSet && s.push(n.panelSet);
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
|
-
const
|
|
92
|
-
s.push(
|
|
91
|
+
const a = new h(n, l);
|
|
92
|
+
s.push(a);
|
|
93
93
|
}), s;
|
|
94
94
|
}
|
|
95
95
|
// Debug logging helper
|
|
@@ -127,7 +127,7 @@ const h = class h {
|
|
|
127
127
|
_getVerticalMetrics(t) {
|
|
128
128
|
if (!t) return 0;
|
|
129
129
|
const i = getComputedStyle(t);
|
|
130
|
-
return ["paddingTop", "paddingBottom", "borderTopWidth", "borderBottomWidth"].reduce((e,
|
|
130
|
+
return ["paddingTop", "paddingBottom", "borderTopWidth", "borderBottomWidth"].reduce((e, l) => e + (parseFloat(i[l]) || 0), 0);
|
|
131
131
|
}
|
|
132
132
|
_measureHeight(t) {
|
|
133
133
|
let i = t.offsetHeight;
|
|
@@ -142,12 +142,12 @@ const h = class h {
|
|
|
142
142
|
if (!t) return;
|
|
143
143
|
let i = 0;
|
|
144
144
|
this.panels.forEach((e) => {
|
|
145
|
-
const
|
|
145
|
+
const l = e.hidden, o = e.classList.contains("active");
|
|
146
146
|
this.panels.forEach((n) => {
|
|
147
147
|
n.hidden = !0, n.classList.remove("active");
|
|
148
148
|
}), e.hidden = !1, e.classList.add("active"), e.style.visibility = "hidden", this.element.offsetHeight;
|
|
149
149
|
const s = this.element.offsetHeight;
|
|
150
|
-
s > i && (i = s), e.hidden =
|
|
150
|
+
s > i && (i = s), e.hidden = l, o || e.classList.remove("active"), e.style.visibility = "";
|
|
151
151
|
}), this.activePanel && (this.activePanel.hidden = !1, this.activePanel.classList.add("active")), this.panels.forEach((e) => {
|
|
152
152
|
e !== this.activePanel && (e.hidden = !0, e.classList.remove("active"));
|
|
153
153
|
}), t.style.setProperty("--ps-max-height", `${i}px`), this._log(`Max container height: ${i}px (set on tracking parent)`);
|
|
@@ -159,8 +159,8 @@ const h = class h {
|
|
|
159
159
|
}
|
|
160
160
|
_waitForTransition(t) {
|
|
161
161
|
return new Promise((i) => {
|
|
162
|
-
const e = getComputedStyle(t),
|
|
163
|
-
if (
|
|
162
|
+
const e = getComputedStyle(t), l = parseFloat(e.transitionDuration) || 0, o = parseFloat(e.transitionDelay) || 0;
|
|
163
|
+
if (l + o === 0) {
|
|
164
164
|
i();
|
|
165
165
|
return;
|
|
166
166
|
}
|
|
@@ -175,48 +175,36 @@ const h = class h {
|
|
|
175
175
|
this._log("Skipping autofocus (touch/mouse interaction)");
|
|
176
176
|
return;
|
|
177
177
|
}
|
|
178
|
-
const
|
|
178
|
+
const o = (s, n) => {
|
|
179
179
|
setTimeout(() => {
|
|
180
180
|
s.focus(), this._log(n);
|
|
181
181
|
}, 100);
|
|
182
182
|
};
|
|
183
183
|
if (i === !0)
|
|
184
|
-
t.hasAttribute("tabindex") || t.setAttribute("tabindex", "-1"),
|
|
184
|
+
t.hasAttribute("tabindex") || t.setAttribute("tabindex", "-1"), o(t, `Auto-focused panel: ${t.id}`);
|
|
185
185
|
else if (i === "heading") {
|
|
186
186
|
const s = t.querySelector("h1, h2, h3, h4, h5, h6");
|
|
187
|
-
s && (s.hasAttribute("tabindex") || s.setAttribute("tabindex", "-1"),
|
|
187
|
+
s && (s.hasAttribute("tabindex") || s.setAttribute("tabindex", "-1"), o(s, `Auto-focused heading in: ${t.id}`));
|
|
188
188
|
} else if (i === "first") {
|
|
189
189
|
const s = t.querySelector('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])');
|
|
190
|
-
s &&
|
|
190
|
+
s && o(s, `Auto-focused first element in: ${t.id}`);
|
|
191
191
|
} else if (i === "input") {
|
|
192
192
|
const s = t.querySelector('input:not([type="hidden"]):not([disabled]), select:not([disabled]), textarea:not([disabled])');
|
|
193
|
-
s &&
|
|
193
|
+
s && o(s, `Auto-focused input in: ${t.id}`);
|
|
194
194
|
} else typeof i == "function" && (i(t), this._log(`Auto-focused (custom) in: ${t.id}`));
|
|
195
195
|
}
|
|
196
|
-
_syncAriaWithActivePanel() {
|
|
197
|
-
if (!this.activePanel?.id) return;
|
|
198
|
-
const t = document.querySelector(
|
|
199
|
-
`[role="tab"][aria-controls="${this.activePanel.id}"]`
|
|
200
|
-
);
|
|
201
|
-
if (!t)
|
|
202
|
-
return;
|
|
203
|
-
const i = t.closest('[role="tablist"]');
|
|
204
|
-
i && (i.querySelectorAll('[role="tab"]').forEach((o) => {
|
|
205
|
-
o.setAttribute("aria-selected", "false");
|
|
206
|
-
}), t.setAttribute("aria-selected", "true"));
|
|
207
|
-
}
|
|
208
196
|
// Shared helper for open/close
|
|
209
197
|
_animateOpenClose(t, i) {
|
|
210
|
-
const e = t ? "opening" : "closing",
|
|
198
|
+
const e = t ? "opening" : "closing", o = `is-${t ? "closing" : "opening"}`, s = `is-${e}`;
|
|
211
199
|
this._log(t ? "Opening" : "Closing"), this._openCloseGeneration++;
|
|
212
200
|
const n = this._openCloseGeneration;
|
|
213
|
-
this.element.classList.contains(
|
|
214
|
-
const
|
|
201
|
+
this.element.classList.contains(o) && this.element.classList.remove(o);
|
|
202
|
+
const a = t ? this._measureHeight(this.pendingPanel) : 0;
|
|
215
203
|
if (i && this.config.transitions) {
|
|
216
204
|
this.element.classList.add(s);
|
|
217
|
-
const
|
|
218
|
-
this.element.style.height = `${
|
|
219
|
-
this.element.style.height = `${
|
|
205
|
+
const r = this.element.offsetHeight;
|
|
206
|
+
this.element.style.height = `${r}px`, t && this.element.classList.remove("is-closed"), requestAnimationFrame(() => {
|
|
207
|
+
this.element.style.height = `${a}px`, this._waitForTransition(this.element).then(() => {
|
|
220
208
|
this._openCloseGeneration === n && (this.element.style.height = "", this.element.classList.remove(s), t || this.element.classList.add("is-closed"));
|
|
221
209
|
});
|
|
222
210
|
});
|
|
@@ -238,19 +226,23 @@ const h = class h {
|
|
|
238
226
|
const {
|
|
239
227
|
event: i,
|
|
240
228
|
transition: e = !0,
|
|
241
|
-
autoFocus:
|
|
229
|
+
autoFocus: l
|
|
242
230
|
} = t || {};
|
|
243
231
|
if (!this.config.closable) {
|
|
244
232
|
this._log("Cannot open: closable is false");
|
|
245
233
|
return;
|
|
246
234
|
}
|
|
247
|
-
const
|
|
248
|
-
if (!
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
235
|
+
const o = this.element.classList.contains("is-closed"), s = this.element.classList.contains("is-closing");
|
|
236
|
+
if (!o && !s) return;
|
|
237
|
+
const n = i?.target instanceof HTMLElement ? i.target.closest('button, a, [role="tab"]') ?? i.target : null;
|
|
238
|
+
let a;
|
|
239
|
+
if (n?.hasAttribute("data-auto-focus")) {
|
|
240
|
+
const r = n.getAttribute("data-auto-focus");
|
|
241
|
+
r === "true" ? a = !0 : r === "false" ? a = !1 : (r === "heading" || r === "first" || r === "input") && (a = r);
|
|
242
|
+
} else l !== void 0 ? a = l : a = this.config.autoFocus;
|
|
243
|
+
this._animateOpenClose(!0, e), a !== !1 && a !== void 0 && this.pendingPanel && (e && this.config.transitions ? this._waitForTransition(this.element).then(() => {
|
|
244
|
+
this._handleAutoFocus(this.pendingPanel, a, i);
|
|
245
|
+
}) : this._handleAutoFocus(this.pendingPanel, a, i));
|
|
254
246
|
}
|
|
255
247
|
/**
|
|
256
248
|
* Close a closable panelset
|
|
@@ -264,8 +256,8 @@ const h = class h {
|
|
|
264
256
|
this._log("Cannot close: closable is false");
|
|
265
257
|
return;
|
|
266
258
|
}
|
|
267
|
-
const e = this.element.classList.contains("is-closed"),
|
|
268
|
-
e && !
|
|
259
|
+
const e = this.element.classList.contains("is-closed"), l = this.element.classList.contains("is-opening");
|
|
260
|
+
e && !l || this._animateOpenClose(!1, i);
|
|
269
261
|
}
|
|
270
262
|
/**
|
|
271
263
|
* Toggle a closable panelset between open and closed
|
|
@@ -275,9 +267,9 @@ const h = class h {
|
|
|
275
267
|
const {
|
|
276
268
|
event: i,
|
|
277
269
|
transition: e = !0,
|
|
278
|
-
autoFocus:
|
|
279
|
-
} = t || {},
|
|
280
|
-
|
|
270
|
+
autoFocus: l
|
|
271
|
+
} = t || {}, o = this.element.classList.contains("is-closed"), s = this.element.classList.contains("is-closing");
|
|
272
|
+
o || s ? this.open({ event: i, transition: e, autoFocus: l }) : this.close({ transition: e });
|
|
281
273
|
}
|
|
282
274
|
/**
|
|
283
275
|
* Register a handler for async content loading
|
|
@@ -286,17 +278,17 @@ const h = class h {
|
|
|
286
278
|
*/
|
|
287
279
|
onBeforeActivate(t, i = {}) {
|
|
288
280
|
const e = i.once === !0;
|
|
289
|
-
this.element.addEventListener("ps:beforeactivate", (
|
|
290
|
-
const
|
|
281
|
+
this.element.addEventListener("ps:beforeactivate", (l) => {
|
|
282
|
+
const o = l, { targetPanel: s, signal: n } = o.detail;
|
|
291
283
|
if (e && s.dataset.loaded === "true") {
|
|
292
284
|
this.config.debug && this._log(`Skipping ${s.id} (already loaded)`);
|
|
293
285
|
return;
|
|
294
286
|
}
|
|
295
|
-
const
|
|
296
|
-
|
|
287
|
+
const a = t(s, n);
|
|
288
|
+
a && typeof a.then == "function" && (o.detail.promise = a.then(() => {
|
|
297
289
|
e && (s.dataset.loaded = "true");
|
|
298
|
-
}).catch((
|
|
299
|
-
throw
|
|
290
|
+
}).catch((r) => {
|
|
291
|
+
throw r.name === "AbortError" ? (this.config.debug && this._log(`Load aborted: ${s.id}`), r) : (this._log(`Load failed: ${r.message}`), r);
|
|
300
292
|
}));
|
|
301
293
|
});
|
|
302
294
|
}
|
|
@@ -309,79 +301,70 @@ const h = class h {
|
|
|
309
301
|
async show(t, i) {
|
|
310
302
|
const {
|
|
311
303
|
event: e,
|
|
312
|
-
transition:
|
|
313
|
-
autoFocus:
|
|
304
|
+
transition: l = !0,
|
|
305
|
+
autoFocus: o
|
|
314
306
|
} = i || {}, s = e?.target instanceof HTMLElement ? e.target.closest('button, a, [role="tab"]') ?? e.target : null;
|
|
315
307
|
let n;
|
|
316
|
-
if (
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
n = this.config.autoFocus;
|
|
323
|
-
if (s?.getAttribute("role") === "tab") {
|
|
324
|
-
const r = s.closest('[role="tablist"]');
|
|
325
|
-
r && (r.querySelectorAll('[role="tab"]').forEach((f) => {
|
|
326
|
-
f.setAttribute("aria-selected", "false");
|
|
327
|
-
}), s.setAttribute("aria-selected", "true"));
|
|
328
|
-
}
|
|
329
|
-
const l = this.panels.find((r) => r.id === t);
|
|
330
|
-
if (!l) {
|
|
308
|
+
if (s?.hasAttribute("data-auto-focus")) {
|
|
309
|
+
const c = s.getAttribute("data-auto-focus");
|
|
310
|
+
c === "true" ? n = !0 : c === "false" ? n = !1 : (c === "heading" || c === "first" || c === "input") && (n = c);
|
|
311
|
+
} else o !== void 0 ? n = o : n = this.config.autoFocus;
|
|
312
|
+
const a = this.panels.find((c) => c.id === t);
|
|
313
|
+
if (!a) {
|
|
331
314
|
this._log(`Panel not found: ${t}`);
|
|
332
315
|
return;
|
|
333
316
|
}
|
|
334
|
-
if (
|
|
335
|
-
const
|
|
336
|
-
this.pendingPanel =
|
|
317
|
+
if (a === this.pendingPanel) return;
|
|
318
|
+
const r = this.pendingPanel, _ = r?.id;
|
|
319
|
+
this.pendingPanel = a, this.element.classList.remove("is-loading"), r && r !== this.activePanel && r !== a && (r.classList.remove("incoming"), r.hidden || r.classList.remove("active"));
|
|
337
320
|
const C = this._isLoadingAsync;
|
|
338
321
|
this._currentAbortController && (this._currentAbortController.abort(), C && _ && _ !== t && this._dispatch("ps:activationaborted", {
|
|
339
322
|
panelId: _,
|
|
340
323
|
trigger: s
|
|
341
324
|
}));
|
|
342
325
|
const p = new AbortController();
|
|
343
|
-
this._currentAbortController = p, this._isLoadingAsync = !1, this._log(`${
|
|
344
|
-
const
|
|
326
|
+
this._currentAbortController = p, this._isLoadingAsync = !1, this._log(`${r?.id || "none"} → ${t}`);
|
|
327
|
+
const L = {
|
|
345
328
|
panelId: t,
|
|
346
|
-
targetPanel:
|
|
347
|
-
outgoingPanel:
|
|
329
|
+
targetPanel: a,
|
|
330
|
+
outgoingPanel: r,
|
|
348
331
|
signal: p.signal,
|
|
349
332
|
promise: null
|
|
350
|
-
},
|
|
351
|
-
detail:
|
|
333
|
+
}, w = new CustomEvent("ps:beforeactivate", {
|
|
334
|
+
detail: L,
|
|
352
335
|
bubbles: !0,
|
|
353
336
|
cancelable: !1
|
|
354
337
|
});
|
|
355
|
-
this.element.dispatchEvent(
|
|
356
|
-
const
|
|
357
|
-
if (
|
|
338
|
+
this.element.dispatchEvent(w);
|
|
339
|
+
const P = L.promise;
|
|
340
|
+
if (P) {
|
|
358
341
|
this._isLoadingAsync = !0, this._log("Waiting for content...");
|
|
359
|
-
let
|
|
360
|
-
if (this.config.loadingDelay > 0 ?
|
|
361
|
-
this.element.classList.add("is-loading"),
|
|
362
|
-
}, this.config.loadingDelay) : (this.element.classList.add("is-loading"),
|
|
363
|
-
const
|
|
364
|
-
let m =
|
|
365
|
-
if (typeof this.config.transitions == "object" && (m =
|
|
366
|
-
const
|
|
367
|
-
this.element.style.height = `${
|
|
342
|
+
let c, f = !1;
|
|
343
|
+
if (this.config.loadingDelay > 0 ? c = setTimeout(() => {
|
|
344
|
+
this.element.classList.add("is-loading"), f = !0;
|
|
345
|
+
}, this.config.loadingDelay) : (this.element.classList.add("is-loading"), f = !0), !(this.activePanel && this.activePanel !== a)) {
|
|
346
|
+
const u = l !== !1 && this.config.transitions !== !1;
|
|
347
|
+
let m = u;
|
|
348
|
+
if (typeof this.config.transitions == "object" && (m = u && this.config.transitions.height !== !1), m) {
|
|
349
|
+
const E = this.element.offsetHeight;
|
|
350
|
+
this.element.style.height = `${E}px`, requestAnimationFrame(() => {
|
|
368
351
|
this.element.style.height = `${this.config.emptyPanelHeight}px`;
|
|
369
352
|
});
|
|
370
353
|
}
|
|
371
354
|
}
|
|
372
355
|
try {
|
|
373
|
-
if (await
|
|
374
|
-
this._log(`Aborted during load: ${t}`),
|
|
356
|
+
if (await P, c && clearTimeout(c), p.signal.aborted) {
|
|
357
|
+
this._log(`Aborted during load: ${t}`), f && this.element.classList.remove("is-loading");
|
|
375
358
|
return;
|
|
376
359
|
}
|
|
377
|
-
this._log("Content loaded"),
|
|
378
|
-
} catch (
|
|
379
|
-
|
|
380
|
-
const m =
|
|
381
|
-
this._log(`Load failed: ${m.message}`),
|
|
360
|
+
this._log("Content loaded"), a.dataset.loaded === "true" && this._updateHighestPanel();
|
|
361
|
+
} catch (u) {
|
|
362
|
+
c && clearTimeout(c);
|
|
363
|
+
const m = u;
|
|
364
|
+
this._log(`Load failed: ${m.message}`), f && this.element.classList.remove("is-loading"), m.name !== "AbortError" && console.error("Panel load error:", u);
|
|
382
365
|
return;
|
|
383
366
|
}
|
|
384
|
-
|
|
367
|
+
f && this.element.classList.remove("is-loading");
|
|
385
368
|
}
|
|
386
369
|
if (p.signal.aborted) {
|
|
387
370
|
this._log(`Aborted: ${t}`);
|
|
@@ -391,23 +374,23 @@ const h = class h {
|
|
|
391
374
|
panelId: t,
|
|
392
375
|
trigger: s
|
|
393
376
|
});
|
|
394
|
-
const
|
|
395
|
-
let
|
|
396
|
-
typeof this.config.transitions == "object" && (
|
|
377
|
+
const v = l !== !1 && this.config.transitions !== !1;
|
|
378
|
+
let b = v, y = v;
|
|
379
|
+
typeof this.config.transitions == "object" && (b = v && this.config.transitions.panels !== !1, y = v && this.config.transitions.height !== !1), this.panels.forEach((c) => c.classList.toggle("fade", b));
|
|
397
380
|
const A = this.element.offsetHeight;
|
|
398
381
|
y && (this.element.style.height = `${A}px`);
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
const
|
|
403
|
-
y && (this.element.style.height = `${
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
if (this.pendingPanel !==
|
|
382
|
+
const d = this.activePanel;
|
|
383
|
+
a.hidden = !1, a.classList.add("incoming"), b && this.element.classList.add("is-transitioning"), d && d !== a && (d.classList.remove("active", "incoming"), d.hidden = !1), requestAnimationFrame(() => {
|
|
384
|
+
a.classList.add("active"), d && d !== a && d.classList.remove("incoming");
|
|
385
|
+
const c = this._measureHeight(a), f = A !== c;
|
|
386
|
+
y && (this.element.style.height = `${c}px`);
|
|
387
|
+
const g = [];
|
|
388
|
+
b && g.push(this._waitForTransition(a)), y && f && g.push(this._waitForTransition(this.element)), g.length || g.push(Promise.resolve()), Promise.all(g).then(() => {
|
|
389
|
+
if (this.pendingPanel !== a) {
|
|
407
390
|
this._log(`Interrupted: ${t}`);
|
|
408
391
|
return;
|
|
409
392
|
}
|
|
410
|
-
this._cleanupPanels(
|
|
393
|
+
this._cleanupPanels(a), this._log(`✓ ${t}`), n !== !1 && n !== void 0 && this._handleAutoFocus(a, n, e), this._dispatch("ps:activationcomplete", {
|
|
411
394
|
panelId: t,
|
|
412
395
|
trigger: s
|
|
413
396
|
});
|
package/dist/panelset.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panelset.js","sources":["../src/lib/index.ts"],"sourcesContent":["import './styles/panelset.scss';\n\n// Configuration types\nexport interface PanelSetConfig {\n\tselector?: string;\n\ttransitions?: boolean | {\n\t\tpanels?: boolean;\n\t\theight?: boolean;\n\t};\n\tclosable?: boolean;\n\temptyPanelHeight?: number;\n\tloadingDelay?: number;\n\tautoFocus?: boolean | 'heading' | 'first' | 'input';\n\tdebug?: boolean;\n}\n\n// Event detail types\nexport interface ReadyEventDetail {\n\tcontainer: HTMLElement;\n\tinstance: PanelSet;\n}\n\nexport interface BeforeActivateEventDetail {\n\tpanelId: string;\n\ttargetPanel: HTMLElement;\n\toutgoingPanel: HTMLElement | null;\n\tsignal: AbortSignal;\n\tpromise: Promise<void> | null;\n}\n\nexport interface ActivationEventDetail {\n\tpanelId: string;\n\ttrigger: HTMLElement | null;\n}\n\nexport interface ActivationAbortedEventDetail {\n\tpanelId: string;\n\ttrigger: HTMLElement | null;\n}\n\n// Handler options\nexport interface HandlerOptions {\n\tonce?: boolean;\n}\n\n// Show options\nexport interface ShowOptions {\n\tevent?: Event;\n\ttransition?: boolean;\n\tautoFocus?: boolean | 'heading' | 'first' | 'input' | ((panel: HTMLElement) => void);\n}\n\n// Async content handler type\nexport type AsyncContentHandler = (\n\ttargetPanel: HTMLElement,\n\tsignal: AbortSignal\n) => Promise<void> | void;\n\ndeclare global {\n\tinterface HTMLElement {\n\t\tpanelSet?: PanelSet;\n\t}\n}\n\nexport class PanelSet {\n\t// Default configuration\n\tstatic defaults: Required<Omit<PanelSetConfig, 'selector'>> = {\n\t\ttransitions: true,\n\t\tclosable: false,\n\t\temptyPanelHeight: 200,\n\t\tloadingDelay: 300,\n\t\tautoFocus: false,\n\t\tdebug: false\n\t};\n\n\t// Instance properties\n\telement!: HTMLElement;\n\tconfig!: Required<Omit<PanelSetConfig, 'selector'>>;\n\tpanels!: HTMLElement[];\n\tactivePanel!: HTMLElement;\n\tpanelWrapper!: HTMLElement;\n\tpendingPanel!: HTMLElement;\n\n\tprivate _openCloseGeneration: number = 0;\n\tprivate _isLoadingAsync: boolean = false;\n\tprivate _currentAbortController?: AbortController;\n\n\t// Parse data attributes from element\n\tstatic _getDataConfig(element: HTMLElement): Partial<PanelSetConfig> {\n\t\tconst data = element.dataset;\n\t\tconst config: Partial<PanelSetConfig> = {};\n\n\t\t// Define attribute types\n\t\tconst attrs: Record<string, 'json' | 'boolean' | 'number'> = {\n\t\t\ttransitions: 'json',\n\t\t\tclosable: 'boolean',\n\t\t\temptyPanelHeight: 'number',\n\t\t\tloadingDelay: 'number',\n\t\t\tdebug: 'boolean'\n\t\t};\n\n\t\t// Parse each attribute\n\t\tfor (const [key, type] of Object.entries(attrs)) {\n\t\t\tif (!(key in data)) continue;\n\n\t\t\tconst value = data[key];\n\t\t\tif (value === undefined) continue;\n\n\t\t\tswitch (type) {\n\t\t\t\tcase 'boolean':\n\t\t\t\t\t(config as any)[key] = value !== 'false';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'number':\n\t\t\t\t\t(config as any)[key] = parseInt(value, 10);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'json':\n\t\t\t\t\ttry {\n\t\t\t\t\t\t(config as any)[key] = JSON.parse(value);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Fall back to boolean parsing\n\t\t\t\t\t\t(config as any)[key] = value !== 'false';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn config;\n\t}\n\n\t// Merge configurations\n\tstatic _mergeConfig(\n\t\tdefaults: Required<Omit<PanelSetConfig, 'selector'>>,\n\t\tdataConfig: Partial<PanelSetConfig>,\n\t\toptions: Partial<PanelSetConfig>\n\t): Required<Omit<PanelSetConfig, 'selector'>> {\n\t\treturn {\n\t\t\t...defaults,\n\t\t\t...dataConfig,\n\t\t\t...options\n\t\t} as Required<Omit<PanelSetConfig, 'selector'>>;\n\t}\n\n\t/**\n\t * Initialize PanelSet instances\n\t * @param selectorOrOptions - CSS selector string or config object\n\t * @param options - Additional config options (when first param is selector)\n\t * @returns Array of PanelSet instances\n\t */\n\tstatic init(selectorOrOptions: string | PanelSetConfig = {}, options: PanelSetConfig = {}): PanelSet[] {\n\t\t// Handle different call signatures\n\t\tlet selector: string;\n\t\tlet config: PanelSetConfig;\n\n\t\tif (typeof selectorOrOptions === 'string') {\n\t\t\t// init('#demo') or init('#demo', {debug: true})\n\t\t\tselector = selectorOrOptions;\n\t\t\tconfig = options;\n\t\t} else {\n\t\t\t// init() or init({selector: '#demo', debug: true})\n\t\t\tconfig = selectorOrOptions;\n\t\t\tselector = config.selector || '[data-panelset]';\n\t\t}\n\n\t\tconst elements = document.querySelectorAll<HTMLElement>(selector);\n\t\tconst instances: PanelSet[] = [];\n\n\t\telements.forEach(el => {\n\n\t\t\ttry {\n\t\t\t\tPanelSet._validateElement(el);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error((error as Error).message);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip if already initialized\n\t\t\tif (el.panelSet || el.dataset.panelset === 'true') {\n\t\t\t\tif (el.panelSet) instances.push(el.panelSet);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst instance = new PanelSet(el, config);\n\t\t\tinstances.push(instance);\n\t\t});\n\n\t\treturn instances;\n\t}\n\n\tconstructor(elementOrSelector: HTMLElement | string, options: PanelSetConfig = {}) {\n\t\t// Handle both element and selector\n\t\tlet element: HTMLElement | null;\n\t\tif (typeof elementOrSelector === 'string') {\n\t\t\telement = document.querySelector<HTMLElement>(elementOrSelector);\n\t\t\tif (!element) {\n\t\t\t\tthrow new Error(`PanelSet: No element found for selector \"${elementOrSelector}\"`);\n\t\t\t}\n\t\t} else {\n\t\t\telement = elementOrSelector;\n\t\t}\n\n\t\tthis.element = element;\n\n\t\t// Validate element\n\t\tPanelSet._validateElement(element);\n\n\t\t// Check if already initialized\n\t\tif (element.panelSet || element.dataset.panelset === 'true') {\n\t\t\tconsole.warn('PanelSet: Element already initialized, returning existing instance');\n\t\t\treturn element.panelSet!;\n\t\t}\n\n\t\t// Store instance on element\n\t\telement.panelSet = this;\n\n\t\tconst dataConfig = PanelSet._getDataConfig(element);\n\t\tthis.config = PanelSet._mergeConfig(\n\t\t\tPanelSet.defaults,\n\t\t\tdataConfig,\n\t\t\toptions\n\t\t);\n\n\t\tthis.panels = Array.from(element.querySelectorAll<HTMLElement>('[role=\"tabpanel\"]'));\n\n\t\tif (this.panels.length === 0) {\n\t\t\tconst elementDesc = `<${element.tagName.toLowerCase()}${element.id ? ` id=\"${element.id}\"` : ''}${element.className ? ` class=\"${element.className}\"` : ''}>`;\n\t\t\tconsole.error(`PanelSet: No panels with [role=\"tabpanel\"] found inside ${elementDesc}. Make sure panel elements are children of the [data-panelset] element.`);\n\t\t\t// Set safe defaults and bail\n\t\t\tthis.panels = [];\n\t\t\tthis.activePanel = null as any;\n\t\t\tthis.panelWrapper = null as any;\n\t\t\tthis.pendingPanel = null as any;\n\t\t\treturn;\n\t\t}\n\n\n\t\tthis.activePanel =\n\t\t\tthis.panels.find(p => p.classList.contains('active')) || this.panels[0];\n\t\tthis.panelWrapper =\n\t\t\tthis.element.querySelector<HTMLElement>('.panel-wrapper') || this._autoWrapPanels();\n\n\t\tthis.pendingPanel = this.activePanel;\n\n\n\n\n\t\tthis.element.dataset.panelset = 'true';\n\n\t\tthis._log(`Initialized (${this.panels.length} panels)`);\n\t\tthis._dispatch<ReadyEventDetail>('ps:ready', { container: this.element, instance: this });\n\n\t\tthis._internalInit();\n\n\t\tthis._syncAriaWithActivePanel();\n\n\t\tlet resizeTimeout: ReturnType<typeof setTimeout>;\n\t\twindow.addEventListener('resize', () => {\n\t\t\tclearTimeout(resizeTimeout);\n\t\t\tresizeTimeout = setTimeout(() => {\n\t\t\t\tthis._updateHighestPanel();\n\t\t\t}, 250);\n\t\t});\n\n\t}\n\n\t// Debug logging helper\n\tprivate _log(message: string): void {\n\t\tif (!this.config.debug) return;\n\t\tconst id = this.element.id || 'no id';\n\t\tconsole.log(`[PanelSet] - \"${id}\" -`, message);\n\t}\n\n\tprivate static _validateElement(element: HTMLElement): void {\n\t\tif (!element.hasAttribute('data-panelset')) {\n\t\t\tconst elementDesc = `<${element.tagName.toLowerCase()}${element.id ? ` id=\"${element.id}\"` : ''}${element.className ? ` class=\"${element.className}\"` : ''}>`;\n\t\t\tthrow new Error(`PanelSet: Element is missing required data-panelset attribute. Element: ${elementDesc}`);\n\t\t}\n\t}\n\n\tprivate _autoWrapPanels(): HTMLElement {\n\t\tconst wrapper = document.createElement('div');\n\t\twrapper.className = 'panel-wrapper';\n\t\tthis.panels.forEach(panel => wrapper.appendChild(panel));\n\t\tthis.element.appendChild(wrapper);\n\t\treturn wrapper;\n\t}\n\n\tprivate _internalInit(): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tpanel.classList.remove('fade', 'incoming');\n\t\t\tif (panel !== this.activePanel) {\n\t\t\t\tpanel.hidden = true;\n\t\t\t\tpanel.classList.remove('active');\n\t\t\t} else {\n\t\t\t\tpanel.hidden = false;\n\t\t\t\tpanel.classList.add('active');\n\t\t\t}\n\t\t});\n\t\tthis.element.style.height = '';\n\t\tthis._updateHighestPanel();\n\t}\n\t\n\n\t// Dispatch custom event helper\n\tprivate _dispatch<T = unknown>(eventName: string, detail: T): void {\n\t\tthis.element.dispatchEvent(\n\t\t\tnew CustomEvent(eventName, {\n\t\t\t\tdetail,\n\t\t\t\tbubbles: true,\n\t\t\t\tcancelable: false\n\t\t\t})\n\t\t);\n\t}\n\n\t/* --- Modular helpers --- */\n\n\tprivate _getVerticalMetrics(el: HTMLElement | null): number {\n\t\tif (!el) return 0;\n\t\tconst s = getComputedStyle(el);\n\t\treturn ['paddingTop', 'paddingBottom', 'borderTopWidth', 'borderBottomWidth']\n\t\t\t.reduce((sum, prop) => sum + (parseFloat(s[prop as keyof CSSStyleDeclaration] as string) || 0), 0);\n\t}\n\n\tprivate _measureHeight(panel: HTMLElement): number {\n\t\tlet total = panel.offsetHeight;\n\t\ttotal += this._getVerticalMetrics(this.panelWrapper);\n\t\ttotal += this._getVerticalMetrics(this.element);\n\t\treturn total;\n\t}\n\n\tprivate _updateHighestPanel(): void {\n\n\t\t// Warn if user tries self-tracking\n\t\tif (this.element.hasAttribute('data-ps-track-height')) {\n\t\t\tconsole.warn('PanelSet: data-ps-track-height should be placed on a parent element, not on [data-panelset] itself. Height tracking skipped.');\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// Look for parent with tracking attribute\n\t\tconst trackingParent = this.element.closest('[data-ps-track-height]');\n\t\tif (!trackingParent) return; // Skip if no tracking parent found\n\t\t\n\t\tlet maxContainerHeight = 0;\n\t\t\n\t\t// Measure each panel as if it were active\n\t\tthis.panels.forEach(panel => {\n\t\t\t// Save state\n\t\t\tconst wasHidden = panel.hidden;\n\t\t\tconst wasActive = panel.classList.contains('active');\n\t\t\t\n\t\t\t// Make this panel active temporarily\n\t\t\tthis.panels.forEach(p => {\n\t\t\t\tp.hidden = true;\n\t\t\t\tp.classList.remove('active');\n\t\t\t});\n\t\t\t\n\t\t\tpanel.hidden = false;\n\t\t\tpanel.classList.add('active');\n\t\t\tpanel.style.visibility = 'hidden';\n\t\t\t\n\t\t\t// Force reflow\n\t\t\tthis.element.offsetHeight;\n\t\t\t\n\t\t\t// Measure the CONTAINER height (includes padding and borders)\n\t\t\tconst containerHeight = this.element.offsetHeight;\n\t\t\tif (containerHeight > maxContainerHeight) {\n\t\t\t\tmaxContainerHeight = containerHeight;\n\t\t\t}\n\t\t\t\n\t\t\t// Restore state\n\t\t\tpanel.hidden = wasHidden;\n\t\t\tif (!wasActive) panel.classList.remove('active');\n\t\t\tpanel.style.visibility = '';\n\t\t});\n\n\t\tif (this.activePanel) {\n\t\t\tthis.activePanel.hidden = false;\n\t\t\tthis.activePanel.classList.add('active');\n\t\t}\n\t\tthis.panels.forEach(p => {\n\t\t\tif (p !== this.activePanel) {\n\t\t\t\tp.hidden = true;\n\t\t\t\tp.classList.remove('active');\n\t\t\t}\n\t\t});\n\t\t\n\t\t// Set CSS variable on the tracking parent\n\t\t(trackingParent as HTMLElement).style.setProperty('--ps-max-height', `${maxContainerHeight}px`);\n\t\tthis._log(`Max container height: ${maxContainerHeight}px (set on tracking parent)`);\n\t}\n\n\tprivate _cleanupPanels(newPanel: HTMLElement): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tpanel.classList.remove('fade', 'incoming');\n\t\t\tif (panel !== newPanel) {\n\t\t\t\tpanel.classList.remove('active');\n\t\t\t\tpanel.hidden = true;\n\t\t\t} else {\n\t\t\t\tpanel.classList.add('active');\n\t\t\t\tpanel.hidden = false;\n\t\t\t}\n\t\t});\n\t\tthis.element.style.height = '';\n\t\tthis.element.classList.remove('is-transitioning');\n\t\tthis.activePanel = newPanel;\n\t}\n\n\tprivate _waitForTransition(element: HTMLElement): Promise<void> {\n\t\treturn new Promise(resolve => {\n\t\t\tconst styles = getComputedStyle(element);\n\t\t\tconst duration = parseFloat(styles.transitionDuration) || 0;\n\t\t\tconst delay = parseFloat(styles.transitionDelay) || 0;\n\t\t\tif (duration + delay === 0) {\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst handler = (e: TransitionEvent) => {\n\t\t\t\tif (e.target !== element) return;\n\t\t\t\telement.removeEventListener('transitionend', handler);\n\t\t\t\tresolve();\n\t\t\t};\n\t\t\telement.addEventListener('transitionend', handler);\n\t\t});\n\t}\n\n\tprivate _handleAutoFocus(panel: HTMLElement, autoFocus: boolean | 'heading' | 'first' | 'input' | ((panel: HTMLElement) => void), event?: Event): void {\n\t\t// Skip keyboard detection for 'input' mode - forms need focus regardless of input method\n\t\tconst bypassKeyboardDetection = autoFocus === 'input';\n\t\t\n\t\tif (!bypassKeyboardDetection && autoFocus && event) {\n\t\t\tconst isKeyboardEvent = \n\t\t\t\tevent.type.startsWith('key') || \n\t\t\t\t(event instanceof MouseEvent && event.detail === 0);\n\t\t\t\n\t\t\t// If touch/mouse, skip autofocus\n\t\t\tif (!isKeyboardEvent) {\n\t\t\t\tthis._log('Skipping autofocus (touch/mouse interaction)');\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Helper to focus with delay (helps screen readers announce properly)\n\t\tconst focusWithDelay = (element: HTMLElement, logMessage: string) => {\n\t\t\tsetTimeout(() => {\n\t\t\t\telement.focus();\n\t\t\t\tthis._log(logMessage);\n\t\t\t}, 100);\n\t\t};\n\n\t\tif (autoFocus === true) {\n\t\t\t// Focus the panel itself\n\t\t\tif (!panel.hasAttribute('tabindex')) {\n\t\t\t\tpanel.setAttribute('tabindex', '-1');\n\t\t\t}\n\t\t\tfocusWithDelay(panel, `Auto-focused panel: ${panel.id}`);\n\t\t} else if (autoFocus === 'heading') {\n\t\t\t// Focus first heading\n\t\t\tconst heading = panel.querySelector<HTMLElement>('h1, h2, h3, h4, h5, h6');\n\t\t\tif (heading) {\n\t\t\t\tif (!heading.hasAttribute('tabindex')) {\n\t\t\t\t\theading.setAttribute('tabindex', '-1');\n\t\t\t\t}\n\t\t\t\tfocusWithDelay(heading, `Auto-focused heading in: ${panel.id}`);\n\t\t\t}\n\t\t} else if (autoFocus === 'first') {\n\t\t\t// Focus first focusable element\n\t\t\tconst focusable = panel.querySelector<HTMLElement>('a, button, input, select, textarea, [tabindex]:not([tabindex=\"-1\"])');\n\t\t\tif (focusable) {\n\t\t\t\tfocusWithDelay(focusable, `Auto-focused first element in: ${panel.id}`);\n\t\t\t}\n\t\t} else if (autoFocus === 'input') {\n\t\t\t// Focus first form input (bypasses keyboard detection)\n\t\t\tconst input = panel.querySelector<HTMLElement>('input:not([type=\"hidden\"]):not([disabled]), select:not([disabled]), textarea:not([disabled])');\n\t\t\tif (input) {\n\t\t\t\tfocusWithDelay(input, `Auto-focused input in: ${panel.id}`);\n\t\t\t}\n\t\t} else if (typeof autoFocus === 'function') {\n\t\t\t// Custom function - apply immediately (user's responsibility)\n\t\t\tautoFocus(panel);\n\t\t\tthis._log(`Auto-focused (custom) in: ${panel.id}`);\n\t\t}\n\t}\n\n\tprivate _syncAriaWithActivePanel(): void {\n\t\tif (!this.activePanel?.id) return;\n\t\t\n\t\t// Find tab that controls the active panel\n\t\tconst controllingTab = document.querySelector(\n\t\t\t`[role=\"tab\"][aria-controls=\"${this.activePanel.id}\"]`\n\t\t) as HTMLElement;\n\t\t\n\t\tif (!controllingTab) {\n\t\t\t// No tab found for active panel - might be a sub-panel\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// Update all tabs in the tablist\n\t\tconst tablist = controllingTab.closest('[role=\"tablist\"]');\n\t\tif (tablist) {\n\t\t\tconst allTabs = tablist.querySelectorAll('[role=\"tab\"]');\n\t\t\tallTabs.forEach(tab => {\n\t\t\t\ttab.setAttribute('aria-selected', 'false');\n\t\t\t});\n\t\t\tcontrollingTab.setAttribute('aria-selected', 'true');\n\t\t}\n\t}\n\n\t// Shared helper for open/close\n\tprivate _animateOpenClose(isOpening: boolean, withTransition: boolean): void {\n\t\tconst action = isOpening ? 'opening' : 'closing';\n\t\tconst oppositeAction = isOpening ? 'closing' : 'opening';\n\t\tconst oppositeClass = `is-${oppositeAction}`;\n\t\tconst actionClass = `is-${action}`;\n\n\t\tthis._log(isOpening ? 'Opening' : 'Closing');\n\n\t\tthis._openCloseGeneration++;\n\t\tconst myGeneration = this._openCloseGeneration;\n\n\t\t// Remove opposite state if interrupting\n\t\tif (this.element.classList.contains(oppositeClass)) {\n\t\t\tthis.element.classList.remove(oppositeClass);\n\t\t}\n\n\t\tconst targetHeight = isOpening ? this._measureHeight(this.pendingPanel) : 0;\n\n\t\tif (withTransition && this.config.transitions) {\n\t\t\tthis.element.classList.add(actionClass);\n\n\t\t\tconst currentHeight = this.element.offsetHeight;\n\t\t\tthis.element.style.height = `${currentHeight}px`;\n\n\t\t\tif (isOpening) this.element.classList.remove('is-closed');\n\n\t\t\trequestAnimationFrame(() => {\n\t\t\t\tthis.element.style.height = `${targetHeight}px`;\n\n\t\t\t\tthis._waitForTransition(this.element).then(() => {\n\t\t\t\t\tif (this._openCloseGeneration === myGeneration) {\n\t\t\t\t\t\tthis.element.style.height = '';\n\t\t\t\t\t\tthis.element.classList.remove(actionClass);\n\t\t\t\t\t\tif (!isOpening) this.element.classList.add('is-closed');\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t} else {\n\t\t\tif (isOpening) {\n\t\t\t\tthis.element.classList.remove('is-closed');\n\t\t\t} else {\n\t\t\t\tthis.element.classList.add('is-closed');\n\t\t\t}\n\t\t\tthis.element.style.height = '';\n\t\t}\n\t}\n\n\t/**\n\t * Get the ID of the currently active panel\n\t * @returns Panel ID or null if no panel is active\n\t */\n\tgetActive(): string | null {\n\t\treturn this.pendingPanel?.id || null;\n\t}\n\n\n\t/**\n\t * Open a closable panelset\n\t * @param options - Configuration options\n\t */\n\topen(options?: ShowOptions): void {\n\t\tconst {\n\t\t\tevent,\n\t\t\ttransition = true,\n\t\t\tautoFocus\n\t\t} = options || {};\n\n\t\tif (!this.config.closable) {\n\t\t\tthis._log('Cannot open: closable is false');\n\t\t\treturn;\n\t\t}\n\n\t\tconst isClosed = this.element.classList.contains('is-closed');\n\t\tconst isClosing = this.element.classList.contains('is-closing');\n\n\t\tif (!isClosed && !isClosing) return;\n\n\t\tthis._animateOpenClose(true, transition);\n\t\t\n\t\t// Handle autofocus after opening\n\t\tconst finalAutoFocus = autoFocus ?? this.config.autoFocus;\n\t\tif (finalAutoFocus !== false && finalAutoFocus !== undefined && this.pendingPanel) {\n\t\t\tif (transition && this.config.transitions) {\n\t\t\t\tthis._waitForTransition(this.element).then(() => {\n\t\t\t\t\tthis._handleAutoFocus(this.pendingPanel, finalAutoFocus, event);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis._handleAutoFocus(this.pendingPanel, finalAutoFocus, event);\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Close a closable panelset\n\t * @param options - Configuration options\n\t */\n\tclose(options?: ShowOptions): void {\n\t\tconst {\n\t\t\ttransition = true\n\t\t} = options || {};\n\n\t\tif (!this.config.closable) {\n\t\t\tthis._log('Cannot close: closable is false');\n\t\t\treturn;\n\t\t}\n\n\t\tconst isClosed = this.element.classList.contains('is-closed');\n\t\tconst isOpening = this.element.classList.contains('is-opening');\n\n\t\tif (isClosed && !isOpening) return;\n\n\t\tthis._animateOpenClose(false, transition);\n\t}\n\n\n\t/**\n\t * Toggle a closable panelset between open and closed\n\t * @param options - Configuration options\n\t */\n\ttoggle(options?: ShowOptions): void {\n\t\tconst {\n\t\t\tevent,\n\t\t\ttransition = true,\n\t\t\tautoFocus\n\t\t} = options || {};\n\n\t\tconst isClosed = this.element.classList.contains('is-closed');\n\t\tconst isClosing = this.element.classList.contains('is-closing');\n\n\t\t// If closed or closing, open it\n\t\tif (isClosed || isClosing) {\n\t\t\tthis.open({ event, transition, autoFocus });\n\t\t} else {\n\t\t\tthis.close({ transition });\n\t\t}\n\t}\n\n\t/**\n\t * Register a handler for async content loading\n\t * @param handler - Async content handler function\n\t * @param options - Handler options (once: whether to load only once)\n\t */\n\tonBeforeActivate(handler: AsyncContentHandler, options: HandlerOptions = {}): void {\n\t\tconst once = options.once === true; // Default: false (always reload)\n\n\t\tthis.element.addEventListener('ps:beforeactivate', (e) => {\n\t\t\tconst event = e as CustomEvent<BeforeActivateEventDetail>;\n\t\t\tconst { targetPanel, signal } = event.detail;\n\n\t\t\t// Skip if already loaded and once=true\n\t\t\tif (once && targetPanel.dataset.loaded === 'true') {\n\t\t\t\tif (this.config.debug) {\n\t\t\t\t\tthis._log(`Skipping ${targetPanel.id} (already loaded)`);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Call user handler\n\t\t\tconst result = handler(targetPanel, signal);\n\n\t\t\t// If handler returns a promise, attach it to the event\n\t\t\tif (result && typeof result.then === 'function') {\n\t\t\t\tevent.detail.promise = result\n\t\t\t\t\t.then(() => {\n\t\t\t\t\t\t// Auto-mark as loaded on success if once=true\n\t\t\t\t\t\tif (once) {\n\t\t\t\t\t\t\ttargetPanel.dataset.loaded = 'true';\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.catch(error => {\n\t\t\t\t\t\tif (error.name === 'AbortError') {\n\t\t\t\t\t\t\tif (this.config.debug) {\n\t\t\t\t\t\t\t\tthis._log(`Load aborted: ${targetPanel.id}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._log(`Load failed: ${error.message}`);\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\t/* --- Main logic --- */\n\n\n\t/**\n\t * Show a panel by ID\n\t * @param panelId - ID of the panel to show\n\t * @param options - Configuration options for this activation\n\t */\n\tasync show(panelId: string, options?: ShowOptions): Promise<void> {\n\t\tconst {\n\t\t\tevent,\n\t\t\ttransition = true,\n\t\t\tautoFocus\n\t\t} = options || {};\n\n\t\t// Always derive trigger from event\n\t\tconst resolvedTrigger = event?.target instanceof HTMLElement \n\t\t\t? (event.target.closest('button, a, [role=\"tab\"]') as HTMLElement) ?? event.target\n\t\t\t: null;\n\n\t\t// Resolve autoFocus with priority cascade\n\t\tlet finalAutoFocus: boolean | 'heading' | 'first' | 'input' | ((panel: HTMLElement) => void) | undefined;\n\t\t\n\t\tif (autoFocus !== undefined) {\n\t\t\t// 1. Explicit option (highest priority)\n\t\t\tfinalAutoFocus = autoFocus;\n\t\t} else if (resolvedTrigger?.hasAttribute('data-auto-focus')) {\n\t\t\t// 2. Data attribute on trigger\n\t\t\tconst attrValue = resolvedTrigger.getAttribute('data-auto-focus');\n\t\t\tif (attrValue === 'true') {\n\t\t\t\tfinalAutoFocus = true;\n\t\t\t} else if (attrValue === 'false') {\n\t\t\t\tfinalAutoFocus = false;\n\t\t\t} else if (attrValue === 'heading' || attrValue === 'first' || attrValue === 'input') {\n\t\t\t\tfinalAutoFocus = attrValue;\n\t\t\t}\n\t\t} else {\n\t\t\t// 3. Global config (fallback)\n\t\t\tfinalAutoFocus = this.config.autoFocus;\n\t\t}\n\n\t\t// Update ARIA attributes immediately (before transitions) if trigger is a tab\n\t\tif (resolvedTrigger?.getAttribute('role') === 'tab') {\n\t\t\tconst tablist = resolvedTrigger.closest('[role=\"tablist\"]');\n\t\t\tif (tablist) {\n\t\t\t\tconst allTabs = tablist.querySelectorAll('[role=\"tab\"]');\n\t\t\t\tallTabs.forEach(tab => {\n\t\t\t\t\ttab.setAttribute('aria-selected', 'false');\n\t\t\t\t});\n\t\t\t\tresolvedTrigger.setAttribute('aria-selected', 'true');\n\t\t\t}\n\t\t}\n\n\t\tconst newPanel = this.panels.find(p => p.id === panelId);\n\n\t\tif (!newPanel) {\n\t\t\tthis._log(`Panel not found: ${panelId}`);\n\t\t\treturn;\n\t\t}\n\n\t\tif (newPanel === this.pendingPanel) return;\n\n\t\tconst prevPanel = this.pendingPanel;\n\t\tconst prevPanelId = prevPanel?.id;\n\t\tthis.pendingPanel = newPanel;\n\n\t\tthis.element.classList.remove('is-loading');\n\n\t\tif (prevPanel && prevPanel !== this.activePanel && prevPanel !== newPanel) {\n\t\t\tprevPanel.classList.remove('incoming');\n\t\t\tif (prevPanel.hidden) {\n\t\t\t\t// Was never visible, keep hidden\n\t\t\t} else {\n\t\t\t\tprevPanel.classList.remove('active');\n\t\t\t}\n\t\t}\n\n\t\tconst wasLoadingAsync = this._isLoadingAsync;\n\n\t\tif (this._currentAbortController) {\n\t\t\tthis._currentAbortController.abort();\n\n\t\t\tif (wasLoadingAsync && prevPanelId && prevPanelId !== panelId) {\n\t\t\t\tthis._dispatch<ActivationAbortedEventDetail>('ps:activationaborted', {\n\t\t\t\t\tpanelId: prevPanelId,\n\t\t\t\t\ttrigger: resolvedTrigger\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst abortController = new AbortController();\n\t\tthis._currentAbortController = abortController;\n\t\tthis._isLoadingAsync = false;\n\n\t\tthis._log(`${prevPanel?.id || 'none'} → ${panelId}`);\n\n\t\tconst beforeActivateDetail: BeforeActivateEventDetail = {\n\t\t\tpanelId,\n\t\t\ttargetPanel: newPanel,\n\t\t\toutgoingPanel: prevPanel,\n\t\t\tsignal: abortController.signal,\n\t\t\tpromise: null\n\t\t};\n\n\t\tconst beforeActivateEvent = new CustomEvent('ps:beforeactivate', {\n\t\t\tdetail: beforeActivateDetail,\n\t\t\tbubbles: true,\n\t\t\tcancelable: false\n\t\t});\n\n\t\tthis.element.dispatchEvent(beforeActivateEvent);\n\n\t\tconst userPromise = beforeActivateDetail.promise;\n\n\t\tif (userPromise) {\n\t\t\tthis._isLoadingAsync = true;\n\t\t\tthis._log('Waiting for content...');\n\n\t\t\tlet spinnerTimeout: ReturnType<typeof setTimeout> | undefined;\n\t\t\tlet loadingShown = false;\n\n\t\t\tif (this.config.loadingDelay > 0) {\n\t\t\t\tspinnerTimeout = setTimeout(() => {\n\t\t\t\t\tthis.element.classList.add('is-loading');\n\t\t\t\t\tloadingShown = true;\n\t\t\t\t}, this.config.loadingDelay);\n\t\t\t} else {\n\t\t\t\tthis.element.classList.add('is-loading');\n\t\t\t\tloadingShown = true;\n\t\t\t}\n\n\t\t\tconst hasPreviousPanel = this.activePanel && this.activePanel !== newPanel;\n\n\t\t\tif (!hasPreviousPanel) {\n\t\t\t\tconst shouldTransition = transition !== false && this.config.transitions !== false;\n\t\t\t\tlet heightTransition = shouldTransition;\n\t\t\t\tif (typeof this.config.transitions === 'object') {\n\t\t\t\t\theightTransition = shouldTransition && this.config.transitions.height !== false;\n\t\t\t\t}\n\n\t\t\t\tif (heightTransition) {\n\t\t\t\t\tconst currentHeight = this.element.offsetHeight;\n\t\t\t\t\tthis.element.style.height = `${currentHeight}px`;\n\n\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\tthis.element.style.height = `${this.config.emptyPanelHeight}px`;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait userPromise;\n\n\t\t\t\tif (spinnerTimeout) clearTimeout(spinnerTimeout);\n\n\t\t\t\tif (abortController.signal.aborted) {\n\t\t\t\t\tthis._log(`Aborted during load: ${panelId}`);\n\t\t\t\t\tif (loadingShown) this.element.classList.remove('is-loading');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._log('Content loaded');\n\n\t\t\t\tif (newPanel.dataset.loaded === 'true') {\n\t\t\t\t\tthis._updateHighestPanel();\n\t\t\t\t}\n\n\t\t\t} catch (error) {\n\t\t\t\tif (spinnerTimeout) clearTimeout(spinnerTimeout);\n\n\t\t\t\tconst err = error as Error;\n\t\t\t\tthis._log(`Load failed: ${err.message}`);\n\t\t\t\tif (loadingShown) this.element.classList.remove('is-loading');\n\n\t\t\t\tif (err.name !== 'AbortError') {\n\t\t\t\t\tconsole.error('Panel load error:', error);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (loadingShown) this.element.classList.remove('is-loading');\n\t\t}\n\n\t\tif (abortController.signal.aborted) {\n\t\t\tthis._log(`Aborted: ${panelId}`);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._dispatch<ActivationEventDetail>('ps:activationstart', {\n\t\t\tpanelId,\n\t\t\ttrigger: resolvedTrigger\n\t\t});\n\n\t\tconst shouldTransition = transition !== false && this.config.transitions !== false;\n\n\t\tlet panelTransition = shouldTransition;\n\t\tlet heightTransition = shouldTransition;\n\n\t\tif (typeof this.config.transitions === 'object') {\n\t\t\tpanelTransition = shouldTransition && this.config.transitions.panels !== false;\n\t\t\theightTransition = shouldTransition && this.config.transitions.height !== false;\n\t\t}\n\n\t\tthis.panels.forEach(panel => panel.classList.toggle('fade', panelTransition));\n\n\t\tconst startHeight = this.element.offsetHeight;\n\t\tif (heightTransition) {\n\t\t\tthis.element.style.height = `${startHeight}px`;\n\t\t}\n\n\t\tconst outgoingPanel = this.activePanel;\n\n\t\tnewPanel.hidden = false;\n\t\tnewPanel.classList.add('incoming');\n\t\tif (panelTransition) {\n\t\t\tthis.element.classList.add('is-transitioning');\n\t\t}\n\t\tif (outgoingPanel && outgoingPanel !== newPanel) {\n\t\t\toutgoingPanel.classList.remove('active', 'incoming');\n\t\t\toutgoingPanel.hidden = false;\n\t\t}\n\n\t\trequestAnimationFrame(() => {\n\t\t\tnewPanel.classList.add('active');\n\t\t\tif (outgoingPanel && outgoingPanel !== newPanel) {\n\t\t\t\toutgoingPanel.classList.remove('incoming');\n\t\t\t}\n\n\t\t\tconst targetHeight = this._measureHeight(newPanel);\n\t\t\tconst heightChanged = startHeight !== targetHeight;\n\n\t\t\tif (heightTransition) {\n\t\t\t\tthis.element.style.height = `${targetHeight}px`;\n\t\t\t}\n\n\t\t\tconst promises: Promise<void>[] = [];\n\t\t\tif (panelTransition) {\n\t\t\t\tpromises.push(this._waitForTransition(newPanel));\n\t\t\t}\n\t\t\tif (heightTransition && heightChanged) {\n\t\t\t\tpromises.push(this._waitForTransition(this.element));\n\t\t\t}\n\t\t\tif (!promises.length) promises.push(Promise.resolve());\n\n\t\t\tPromise.all(promises).then(() => {\n\t\t\t\tif (this.pendingPanel !== newPanel) {\n\t\t\t\t\tthis._log(`Interrupted: ${panelId}`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._cleanupPanels(newPanel);\n\t\t\t\tthis._log(`✓ ${panelId}`);\n\n\t\t\t\t// Handle auto-focus\n\t\t\t\tif (finalAutoFocus !== false && finalAutoFocus !== undefined) {\n\t\t\t\t\tthis._handleAutoFocus(newPanel, finalAutoFocus, event);\n\t\t\t\t}\n\n\t\t\t\tthis._dispatch<ActivationEventDetail>('ps:activationcomplete', {\n\t\t\t\t\tpanelId,\n\t\t\t\t\ttrigger: resolvedTrigger\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t}\n\n}\n\nexport default PanelSet;"],"names":["_PanelSet","elementOrSelector","options","element","dataConfig","elementDesc","p","resizeTimeout","data","config","attrs","key","type","value","defaults","selectorOrOptions","selector","elements","instances","el","error","instance","message","id","wrapper","panel","eventName","detail","s","sum","prop","total","trackingParent","maxContainerHeight","wasHidden","wasActive","containerHeight","newPanel","resolve","styles","duration","delay","handler","e","autoFocus","event","focusWithDelay","logMessage","heading","focusable","input","controllingTab","tablist","tab","isOpening","withTransition","action","oppositeClass","actionClass","myGeneration","targetHeight","currentHeight","transition","isClosed","isClosing","finalAutoFocus","once","targetPanel","signal","result","panelId","resolvedTrigger","attrValue","prevPanel","prevPanelId","wasLoadingAsync","abortController","beforeActivateDetail","beforeActivateEvent","userPromise","spinnerTimeout","loadingShown","shouldTransition","heightTransition","err","panelTransition","startHeight","outgoingPanel","heightChanged","promises","PanelSet"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"panelset.js","sources":["../src/lib/index.ts"],"sourcesContent":["import './styles/panelset.scss';\n\n// Configuration types\nexport interface PanelSetConfig {\n\tselector?: string;\n\ttransitions?: boolean | {\n\t\tpanels?: boolean;\n\t\theight?: boolean;\n\t};\n\tclosable?: boolean;\n\temptyPanelHeight?: number;\n\tloadingDelay?: number;\n\tautoFocus?: boolean | 'heading' | 'first' | 'input';\n\tdebug?: boolean;\n}\n\n// Event detail types\nexport interface ReadyEventDetail {\n\tcontainer: HTMLElement;\n\tinstance: PanelSet;\n}\n\nexport interface BeforeActivateEventDetail {\n\tpanelId: string;\n\ttargetPanel: HTMLElement;\n\toutgoingPanel: HTMLElement | null;\n\tsignal: AbortSignal;\n\tpromise: Promise<void> | null;\n}\n\nexport interface ActivationEventDetail {\n\tpanelId: string;\n\ttrigger: HTMLElement | null;\n}\n\nexport interface ActivationAbortedEventDetail {\n\tpanelId: string;\n\ttrigger: HTMLElement | null;\n}\n\n// Handler options\nexport interface HandlerOptions {\n\tonce?: boolean;\n}\n\n// Show options\nexport interface ShowOptions {\n\tevent?: Event;\n\ttransition?: boolean;\n\tautoFocus?: boolean | 'heading' | 'first' | 'input' | ((panel: HTMLElement) => void);\n}\n\n// Async content handler type\nexport type AsyncContentHandler = (\n\ttargetPanel: HTMLElement,\n\tsignal: AbortSignal\n) => Promise<void> | void;\n\ndeclare global {\n\tinterface HTMLElement {\n\t\tpanelSet?: PanelSet;\n\t}\n}\n\nexport class PanelSet {\n\t// Default configuration\n\tstatic defaults: Required<Omit<PanelSetConfig, 'selector'>> = {\n\t\ttransitions: true,\n\t\tclosable: false,\n\t\temptyPanelHeight: 200,\n\t\tloadingDelay: 300,\n\t\tautoFocus: false,\n\t\tdebug: false\n\t};\n\n\t// Instance properties\n\telement!: HTMLElement;\n\tconfig!: Required<Omit<PanelSetConfig, 'selector'>>;\n\tpanels!: HTMLElement[];\n\tactivePanel!: HTMLElement;\n\tpanelWrapper!: HTMLElement;\n\tpendingPanel!: HTMLElement;\n\n\tprivate _openCloseGeneration: number = 0;\n\tprivate _isLoadingAsync: boolean = false;\n\tprivate _currentAbortController?: AbortController;\n\n\t// Parse data attributes from element\n\tstatic _getDataConfig(element: HTMLElement): Partial<PanelSetConfig> {\n\t\tconst data = element.dataset;\n\t\tconst config: Partial<PanelSetConfig> = {};\n\n\t\t// Define attribute types\n\t\tconst attrs: Record<string, 'json' | 'boolean' | 'number'> = {\n\t\t\ttransitions: 'json',\n\t\t\tclosable: 'boolean',\n\t\t\temptyPanelHeight: 'number',\n\t\t\tloadingDelay: 'number',\n\t\t\tdebug: 'boolean'\n\t\t};\n\n\t\t// Parse each attribute\n\t\tfor (const [key, type] of Object.entries(attrs)) {\n\t\t\tif (!(key in data)) continue;\n\n\t\t\tconst value = data[key];\n\t\t\tif (value === undefined) continue;\n\n\t\t\tswitch (type) {\n\t\t\t\tcase 'boolean':\n\t\t\t\t\t(config as any)[key] = value !== 'false';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'number':\n\t\t\t\t\t(config as any)[key] = parseInt(value, 10);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'json':\n\t\t\t\t\ttry {\n\t\t\t\t\t\t(config as any)[key] = JSON.parse(value);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Fall back to boolean parsing\n\t\t\t\t\t\t(config as any)[key] = value !== 'false';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn config;\n\t}\n\n\t// Merge configurations\n\tstatic _mergeConfig(\n\t\tdefaults: Required<Omit<PanelSetConfig, 'selector'>>,\n\t\tdataConfig: Partial<PanelSetConfig>,\n\t\toptions: Partial<PanelSetConfig>\n\t): Required<Omit<PanelSetConfig, 'selector'>> {\n\t\treturn {\n\t\t\t...defaults,\n\t\t\t...dataConfig,\n\t\t\t...options\n\t\t} as Required<Omit<PanelSetConfig, 'selector'>>;\n\t}\n\n\t/**\n\t * Initialize PanelSet instances\n\t * @param selectorOrOptions - CSS selector string or config object\n\t * @param options - Additional config options (when first param is selector)\n\t * @returns Array of PanelSet instances\n\t */\n\tstatic init(selectorOrOptions: string | PanelSetConfig = {}, options: PanelSetConfig = {}): PanelSet[] {\n\t\t// Handle different call signatures\n\t\tlet selector: string;\n\t\tlet config: PanelSetConfig;\n\n\t\tif (typeof selectorOrOptions === 'string') {\n\t\t\t// init('#demo') or init('#demo', {debug: true})\n\t\t\tselector = selectorOrOptions;\n\t\t\tconfig = options;\n\t\t} else {\n\t\t\t// init() or init({selector: '#demo', debug: true})\n\t\t\tconfig = selectorOrOptions;\n\t\t\tselector = config.selector || '[data-panelset]';\n\t\t}\n\n\t\tconst elements = document.querySelectorAll<HTMLElement>(selector);\n\t\tconst instances: PanelSet[] = [];\n\n\t\telements.forEach(el => {\n\n\t\t\ttry {\n\t\t\t\tPanelSet._validateElement(el);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error((error as Error).message);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip if already initialized\n\t\t\tif (el.panelSet || el.dataset.panelset === 'true') {\n\t\t\t\tif (el.panelSet) instances.push(el.panelSet);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst instance = new PanelSet(el, config);\n\t\t\tinstances.push(instance);\n\t\t});\n\n\t\treturn instances;\n\t}\n\n\tconstructor(elementOrSelector: HTMLElement | string, options: PanelSetConfig = {}) {\n\t\t// Handle both element and selector\n\t\tlet element: HTMLElement | null;\n\t\tif (typeof elementOrSelector === 'string') {\n\t\t\telement = document.querySelector<HTMLElement>(elementOrSelector);\n\t\t\tif (!element) {\n\t\t\t\tthrow new Error(`PanelSet: No element found for selector \"${elementOrSelector}\"`);\n\t\t\t}\n\t\t} else {\n\t\t\telement = elementOrSelector;\n\t\t}\n\n\t\tthis.element = element;\n\n\t\t// Validate element\n\t\tPanelSet._validateElement(element);\n\n\t\t// Check if already initialized\n\t\tif (element.panelSet || element.dataset.panelset === 'true') {\n\t\t\tconsole.warn('PanelSet: Element already initialized, returning existing instance');\n\t\t\treturn element.panelSet!;\n\t\t}\n\n\t\t// Store instance on element\n\t\telement.panelSet = this;\n\n\t\tconst dataConfig = PanelSet._getDataConfig(element);\n\t\tthis.config = PanelSet._mergeConfig(\n\t\t\tPanelSet.defaults,\n\t\t\tdataConfig,\n\t\t\toptions\n\t\t);\n\n\t\tthis.panels = Array.from(element.querySelectorAll<HTMLElement>('[role=\"tabpanel\"]'));\n\n\t\tif (this.panels.length === 0) {\n\t\t\tconst elementDesc = `<${element.tagName.toLowerCase()}${element.id ? ` id=\"${element.id}\"` : ''}${element.className ? ` class=\"${element.className}\"` : ''}>`;\n\t\t\tconsole.error(`PanelSet: No panels with [role=\"tabpanel\"] found inside ${elementDesc}. Make sure panel elements are children of the [data-panelset] element.`);\n\t\t\t// Set safe defaults and bail\n\t\t\tthis.panels = [];\n\t\t\tthis.activePanel = null as any;\n\t\t\tthis.panelWrapper = null as any;\n\t\t\tthis.pendingPanel = null as any;\n\t\t\treturn;\n\t\t}\n\n\n\t\tthis.activePanel =\n\t\t\tthis.panels.find(p => p.classList.contains('active')) || this.panels[0];\n\t\tthis.panelWrapper =\n\t\t\tthis.element.querySelector<HTMLElement>('.panel-wrapper') || this._autoWrapPanels();\n\n\t\tthis.pendingPanel = this.activePanel;\n\n\n\n\n\t\tthis.element.dataset.panelset = 'true';\n\n\t\tthis._log(`Initialized (${this.panels.length} panels)`);\n\t\tthis._dispatch<ReadyEventDetail>('ps:ready', { container: this.element, instance: this });\n\n\t\tthis._internalInit();\n\n\t\tlet resizeTimeout: ReturnType<typeof setTimeout>;\n\t\twindow.addEventListener('resize', () => {\n\t\t\tclearTimeout(resizeTimeout);\n\t\t\tresizeTimeout = setTimeout(() => {\n\t\t\t\tthis._updateHighestPanel();\n\t\t\t}, 250);\n\t\t});\n\n\t}\n\n\t// Debug logging helper\n\tprivate _log(message: string): void {\n\t\tif (!this.config.debug) return;\n\t\tconst id = this.element.id || 'no id';\n\t\tconsole.log(`[PanelSet] - \"${id}\" -`, message);\n\t}\n\n\tprivate static _validateElement(element: HTMLElement): void {\n\t\tif (!element.hasAttribute('data-panelset')) {\n\t\t\tconst elementDesc = `<${element.tagName.toLowerCase()}${element.id ? ` id=\"${element.id}\"` : ''}${element.className ? ` class=\"${element.className}\"` : ''}>`;\n\t\t\tthrow new Error(`PanelSet: Element is missing required data-panelset attribute. Element: ${elementDesc}`);\n\t\t}\n\t}\n\n\tprivate _autoWrapPanels(): HTMLElement {\n\t\tconst wrapper = document.createElement('div');\n\t\twrapper.className = 'panel-wrapper';\n\t\tthis.panels.forEach(panel => wrapper.appendChild(panel));\n\t\tthis.element.appendChild(wrapper);\n\t\treturn wrapper;\n\t}\n\n\tprivate _internalInit(): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tpanel.classList.remove('fade', 'incoming');\n\t\t\tif (panel !== this.activePanel) {\n\t\t\t\tpanel.hidden = true;\n\t\t\t\tpanel.classList.remove('active');\n\t\t\t} else {\n\t\t\t\tpanel.hidden = false;\n\t\t\t\tpanel.classList.add('active');\n\t\t\t}\n\t\t});\n\t\tthis.element.style.height = '';\n\t\tthis._updateHighestPanel();\n\t}\n\t\n\n\t// Dispatch custom event helper\n\tprivate _dispatch<T = unknown>(eventName: string, detail: T): void {\n\t\tthis.element.dispatchEvent(\n\t\t\tnew CustomEvent(eventName, {\n\t\t\t\tdetail,\n\t\t\t\tbubbles: true,\n\t\t\t\tcancelable: false\n\t\t\t})\n\t\t);\n\t}\n\n\t/* --- Modular helpers --- */\n\n\tprivate _getVerticalMetrics(el: HTMLElement | null): number {\n\t\tif (!el) return 0;\n\t\tconst s = getComputedStyle(el);\n\t\treturn ['paddingTop', 'paddingBottom', 'borderTopWidth', 'borderBottomWidth']\n\t\t\t.reduce((sum, prop) => sum + (parseFloat(s[prop as keyof CSSStyleDeclaration] as string) || 0), 0);\n\t}\n\n\tprivate _measureHeight(panel: HTMLElement): number {\n\t\tlet total = panel.offsetHeight;\n\t\ttotal += this._getVerticalMetrics(this.panelWrapper);\n\t\ttotal += this._getVerticalMetrics(this.element);\n\t\treturn total;\n\t}\n\n\tprivate _updateHighestPanel(): void {\n\n\t\t// Warn if user tries self-tracking\n\t\tif (this.element.hasAttribute('data-ps-track-height')) {\n\t\t\tconsole.warn('PanelSet: data-ps-track-height should be placed on a parent element, not on [data-panelset] itself. Height tracking skipped.');\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// Look for parent with tracking attribute\n\t\tconst trackingParent = this.element.closest('[data-ps-track-height]');\n\t\tif (!trackingParent) return; // Skip if no tracking parent found\n\t\t\n\t\tlet maxContainerHeight = 0;\n\t\t\n\t\t// Measure each panel as if it were active\n\t\tthis.panels.forEach(panel => {\n\t\t\t// Save state\n\t\t\tconst wasHidden = panel.hidden;\n\t\t\tconst wasActive = panel.classList.contains('active');\n\t\t\t\n\t\t\t// Make this panel active temporarily\n\t\t\tthis.panels.forEach(p => {\n\t\t\t\tp.hidden = true;\n\t\t\t\tp.classList.remove('active');\n\t\t\t});\n\t\t\t\n\t\t\tpanel.hidden = false;\n\t\t\tpanel.classList.add('active');\n\t\t\tpanel.style.visibility = 'hidden';\n\t\t\t\n\t\t\t// Force reflow\n\t\t\tthis.element.offsetHeight;\n\t\t\t\n\t\t\t// Measure the CONTAINER height (includes padding and borders)\n\t\t\tconst containerHeight = this.element.offsetHeight;\n\t\t\tif (containerHeight > maxContainerHeight) {\n\t\t\t\tmaxContainerHeight = containerHeight;\n\t\t\t}\n\t\t\t\n\t\t\t// Restore state\n\t\t\tpanel.hidden = wasHidden;\n\t\t\tif (!wasActive) panel.classList.remove('active');\n\t\t\tpanel.style.visibility = '';\n\t\t});\n\n\t\tif (this.activePanel) {\n\t\t\tthis.activePanel.hidden = false;\n\t\t\tthis.activePanel.classList.add('active');\n\t\t}\n\t\tthis.panels.forEach(p => {\n\t\t\tif (p !== this.activePanel) {\n\t\t\t\tp.hidden = true;\n\t\t\t\tp.classList.remove('active');\n\t\t\t}\n\t\t});\n\t\t\n\t\t// Set CSS variable on the tracking parent\n\t\t(trackingParent as HTMLElement).style.setProperty('--ps-max-height', `${maxContainerHeight}px`);\n\t\tthis._log(`Max container height: ${maxContainerHeight}px (set on tracking parent)`);\n\t}\n\n\tprivate _cleanupPanels(newPanel: HTMLElement): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tpanel.classList.remove('fade', 'incoming');\n\t\t\tif (panel !== newPanel) {\n\t\t\t\tpanel.classList.remove('active');\n\t\t\t\tpanel.hidden = true;\n\t\t\t} else {\n\t\t\t\tpanel.classList.add('active');\n\t\t\t\tpanel.hidden = false;\n\t\t\t}\n\t\t});\n\t\tthis.element.style.height = '';\n\t\tthis.element.classList.remove('is-transitioning');\n\t\tthis.activePanel = newPanel;\n\t}\n\n\tprivate _waitForTransition(element: HTMLElement): Promise<void> {\n\t\treturn new Promise(resolve => {\n\t\t\tconst styles = getComputedStyle(element);\n\t\t\tconst duration = parseFloat(styles.transitionDuration) || 0;\n\t\t\tconst delay = parseFloat(styles.transitionDelay) || 0;\n\t\t\tif (duration + delay === 0) {\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst handler = (e: TransitionEvent) => {\n\t\t\t\tif (e.target !== element) return;\n\t\t\t\telement.removeEventListener('transitionend', handler);\n\t\t\t\tresolve();\n\t\t\t};\n\t\t\telement.addEventListener('transitionend', handler);\n\t\t});\n\t}\n\n\tprivate _handleAutoFocus(panel: HTMLElement, autoFocus: boolean | 'heading' | 'first' | 'input' | ((panel: HTMLElement) => void), event?: Event): void {\n\t\t// Skip keyboard detection for 'input' mode - forms need focus regardless of input method\n\t\tconst bypassKeyboardDetection = autoFocus === 'input';\n\t\t\n\t\tif (!bypassKeyboardDetection && autoFocus && event) {\n\t\t\tconst isKeyboardEvent = \n\t\t\t\tevent.type.startsWith('key') || \n\t\t\t\t(event instanceof MouseEvent && event.detail === 0);\n\t\t\t\n\t\t\t// If touch/mouse, skip autofocus\n\t\t\tif (!isKeyboardEvent) {\n\t\t\t\tthis._log('Skipping autofocus (touch/mouse interaction)');\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Helper to focus with delay (helps screen readers announce properly)\n\t\tconst focusWithDelay = (element: HTMLElement, logMessage: string) => {\n\t\t\tsetTimeout(() => {\n\t\t\t\telement.focus();\n\t\t\t\tthis._log(logMessage);\n\t\t\t}, 100);\n\t\t};\n\n\t\tif (autoFocus === true) {\n\t\t\t// Focus the panel itself\n\t\t\tif (!panel.hasAttribute('tabindex')) {\n\t\t\t\tpanel.setAttribute('tabindex', '-1');\n\t\t\t}\n\t\t\tfocusWithDelay(panel, `Auto-focused panel: ${panel.id}`);\n\t\t} else if (autoFocus === 'heading') {\n\t\t\t// Focus first heading\n\t\t\tconst heading = panel.querySelector<HTMLElement>('h1, h2, h3, h4, h5, h6');\n\t\t\tif (heading) {\n\t\t\t\tif (!heading.hasAttribute('tabindex')) {\n\t\t\t\t\theading.setAttribute('tabindex', '-1');\n\t\t\t\t}\n\t\t\t\tfocusWithDelay(heading, `Auto-focused heading in: ${panel.id}`);\n\t\t\t}\n\t\t} else if (autoFocus === 'first') {\n\t\t\t// Focus first focusable element\n\t\t\tconst focusable = panel.querySelector<HTMLElement>('a, button, input, select, textarea, [tabindex]:not([tabindex=\"-1\"])');\n\t\t\tif (focusable) {\n\t\t\t\tfocusWithDelay(focusable, `Auto-focused first element in: ${panel.id}`);\n\t\t\t}\n\t\t} else if (autoFocus === 'input') {\n\t\t\t// Focus first form input (bypasses keyboard detection)\n\t\t\tconst input = panel.querySelector<HTMLElement>('input:not([type=\"hidden\"]):not([disabled]), select:not([disabled]), textarea:not([disabled])');\n\t\t\tif (input) {\n\t\t\t\tfocusWithDelay(input, `Auto-focused input in: ${panel.id}`);\n\t\t\t}\n\t\t} else if (typeof autoFocus === 'function') {\n\t\t\t// Custom function - apply immediately (user's responsibility)\n\t\t\tautoFocus(panel);\n\t\t\tthis._log(`Auto-focused (custom) in: ${panel.id}`);\n\t\t}\n\t}\n\n\t// Shared helper for open/close\n\tprivate _animateOpenClose(isOpening: boolean, withTransition: boolean): void {\n\t\tconst action = isOpening ? 'opening' : 'closing';\n\t\tconst oppositeAction = isOpening ? 'closing' : 'opening';\n\t\tconst oppositeClass = `is-${oppositeAction}`;\n\t\tconst actionClass = `is-${action}`;\n\n\t\tthis._log(isOpening ? 'Opening' : 'Closing');\n\n\t\tthis._openCloseGeneration++;\n\t\tconst myGeneration = this._openCloseGeneration;\n\n\t\t// Remove opposite state if interrupting\n\t\tif (this.element.classList.contains(oppositeClass)) {\n\t\t\tthis.element.classList.remove(oppositeClass);\n\t\t}\n\n\t\tconst targetHeight = isOpening ? this._measureHeight(this.pendingPanel) : 0;\n\n\t\tif (withTransition && this.config.transitions) {\n\t\t\tthis.element.classList.add(actionClass);\n\n\t\t\tconst currentHeight = this.element.offsetHeight;\n\t\t\tthis.element.style.height = `${currentHeight}px`;\n\n\t\t\tif (isOpening) this.element.classList.remove('is-closed');\n\n\t\t\trequestAnimationFrame(() => {\n\t\t\t\tthis.element.style.height = `${targetHeight}px`;\n\n\t\t\t\tthis._waitForTransition(this.element).then(() => {\n\t\t\t\t\tif (this._openCloseGeneration === myGeneration) {\n\t\t\t\t\t\tthis.element.style.height = '';\n\t\t\t\t\t\tthis.element.classList.remove(actionClass);\n\t\t\t\t\t\tif (!isOpening) this.element.classList.add('is-closed');\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t} else {\n\t\t\tif (isOpening) {\n\t\t\t\tthis.element.classList.remove('is-closed');\n\t\t\t} else {\n\t\t\t\tthis.element.classList.add('is-closed');\n\t\t\t}\n\t\t\tthis.element.style.height = '';\n\t\t}\n\t}\n\n\t/**\n\t * Get the ID of the currently active panel\n\t * @returns Panel ID or null if no panel is active\n\t */\n\tgetActive(): string | null {\n\t\treturn this.pendingPanel?.id || null;\n\t}\n\n\n\t/**\n\t * Open a closable panelset\n\t * @param options - Configuration options\n\t */\n\topen(options?: ShowOptions): void {\n\t\tconst {\n\t\t\tevent,\n\t\t\ttransition = true,\n\t\t\tautoFocus\n\t\t} = options || {};\n\n\t\tif (!this.config.closable) {\n\t\t\tthis._log('Cannot open: closable is false');\n\t\t\treturn;\n\t\t}\n\n\t\tconst isClosed = this.element.classList.contains('is-closed');\n\t\tconst isClosing = this.element.classList.contains('is-closing');\n\n\t\tif (!isClosed && !isClosing) return;\n\n\t\t// Derive trigger for data-attribute check\n\t\tconst resolvedTrigger = event?.target instanceof HTMLElement \n\t\t\t? (event.target.closest('button, a, [role=\"tab\"]') as HTMLElement) ?? event.target\n\t\t\t: null;\n\n\t\t// Resolve autoFocus with priority cascade\n\t\tlet finalAutoFocus: boolean | 'heading' | 'first' | 'input' | ((panel: HTMLElement) => void) | undefined;\n\t\t\n\t\tif (resolvedTrigger?.hasAttribute('data-auto-focus')) {\n\t\t\tconst attrValue = resolvedTrigger.getAttribute('data-auto-focus');\n\t\t\tif (attrValue === 'true') {\n\t\t\t\tfinalAutoFocus = true;\n\t\t\t} else if (attrValue === 'false') {\n\t\t\t\tfinalAutoFocus = false;\n\t\t\t} else if (attrValue === 'heading' || attrValue === 'first' || attrValue === 'input') {\n\t\t\t\tfinalAutoFocus = attrValue;\n\t\t\t}\n\t\t} else if (autoFocus !== undefined) {\n\t\t\tfinalAutoFocus = autoFocus;\n\t\t} else {\n\t\t\tfinalAutoFocus = this.config.autoFocus;\n\t\t}\n\n\t\tthis._animateOpenClose(true, transition);\n\t\t\n\t\t// Handle autofocus after opening\n\t\tif (finalAutoFocus !== false && finalAutoFocus !== undefined && this.pendingPanel) {\n\t\t\tif (transition && this.config.transitions) {\n\t\t\t\tthis._waitForTransition(this.element).then(() => {\n\t\t\t\t\tthis._handleAutoFocus(this.pendingPanel, finalAutoFocus, event);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis._handleAutoFocus(this.pendingPanel, finalAutoFocus, event);\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Close a closable panelset\n\t * @param options - Configuration options\n\t */\n\tclose(options?: ShowOptions): void {\n\t\tconst {\n\t\t\ttransition = true\n\t\t} = options || {};\n\n\t\tif (!this.config.closable) {\n\t\t\tthis._log('Cannot close: closable is false');\n\t\t\treturn;\n\t\t}\n\n\t\tconst isClosed = this.element.classList.contains('is-closed');\n\t\tconst isOpening = this.element.classList.contains('is-opening');\n\n\t\tif (isClosed && !isOpening) return;\n\n\t\tthis._animateOpenClose(false, transition);\n\t}\n\n\n\t/**\n\t * Toggle a closable panelset between open and closed\n\t * @param options - Configuration options\n\t */\n\ttoggle(options?: ShowOptions): void {\n\t\tconst {\n\t\t\tevent,\n\t\t\ttransition = true,\n\t\t\tautoFocus\n\t\t} = options || {};\n\n\t\tconst isClosed = this.element.classList.contains('is-closed');\n\t\tconst isClosing = this.element.classList.contains('is-closing');\n\n\t\t// If closed or closing, open it\n\t\tif (isClosed || isClosing) {\n\t\t\t// Just pass through to open() - it handles priority cascade\n\t\t\tthis.open({ event, transition, autoFocus });\n\t\t} else {\n\t\t\tthis.close({ transition });\n\t\t}\n\t}\n\n\t/**\n\t * Register a handler for async content loading\n\t * @param handler - Async content handler function\n\t * @param options - Handler options (once: whether to load only once)\n\t */\n\tonBeforeActivate(handler: AsyncContentHandler, options: HandlerOptions = {}): void {\n\t\tconst once = options.once === true; // Default: false (always reload)\n\n\t\tthis.element.addEventListener('ps:beforeactivate', (e) => {\n\t\t\tconst event = e as CustomEvent<BeforeActivateEventDetail>;\n\t\t\tconst { targetPanel, signal } = event.detail;\n\n\t\t\t// Skip if already loaded and once=true\n\t\t\tif (once && targetPanel.dataset.loaded === 'true') {\n\t\t\t\tif (this.config.debug) {\n\t\t\t\t\tthis._log(`Skipping ${targetPanel.id} (already loaded)`);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Call user handler\n\t\t\tconst result = handler(targetPanel, signal);\n\n\t\t\t// If handler returns a promise, attach it to the event\n\t\t\tif (result && typeof result.then === 'function') {\n\t\t\t\tevent.detail.promise = result\n\t\t\t\t\t.then(() => {\n\t\t\t\t\t\t// Auto-mark as loaded on success if once=true\n\t\t\t\t\t\tif (once) {\n\t\t\t\t\t\t\ttargetPanel.dataset.loaded = 'true';\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.catch(error => {\n\t\t\t\t\t\tif (error.name === 'AbortError') {\n\t\t\t\t\t\t\tif (this.config.debug) {\n\t\t\t\t\t\t\t\tthis._log(`Load aborted: ${targetPanel.id}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._log(`Load failed: ${error.message}`);\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\t/* --- Main logic --- */\n\n\n\t/**\n\t * Show a panel by ID\n\t * @param panelId - ID of the panel to show\n\t * @param options - Configuration options for this activation\n\t */\n\tasync show(panelId: string, options?: ShowOptions): Promise<void> {\n\t\tconst {\n\t\t\tevent,\n\t\t\ttransition = true,\n\t\t\tautoFocus\n\t\t} = options || {};\n\n\t\t// Always derive trigger from event\n\t\tconst resolvedTrigger = event?.target instanceof HTMLElement \n\t\t\t? (event.target.closest('button, a, [role=\"tab\"]') as HTMLElement) ?? event.target\n\t\t\t: null;\n\n\t\t// Resolve autoFocus with priority cascade\n\t\tlet finalAutoFocus: boolean | 'heading' | 'first' | 'input' | ((panel: HTMLElement) => void) | undefined;\n\n\t\tif (resolvedTrigger?.hasAttribute('data-auto-focus')) {\n\t\t\t// 1. Data attribute on trigger (highest priority - most specific)\n\t\t\tconst attrValue = resolvedTrigger.getAttribute('data-auto-focus');\n\t\t\tif (attrValue === 'true') {\n\t\t\t\tfinalAutoFocus = true;\n\t\t\t} else if (attrValue === 'false') {\n\t\t\t\tfinalAutoFocus = false;\n\t\t\t} else if (attrValue === 'heading' || attrValue === 'first' || attrValue === 'input') {\n\t\t\t\tfinalAutoFocus = attrValue;\n\t\t\t}\n\t\t} else if (autoFocus !== undefined) {\n\t\t\t// 2. Explicit option (when no data attribute)\n\t\t\tfinalAutoFocus = autoFocus;\n\t\t} else {\n\t\t\t// 3. Global config (fallback)\n\t\t\tfinalAutoFocus = this.config.autoFocus;\n\t\t}\n\n\t\tconst newPanel = this.panels.find(p => p.id === panelId);\n\n\t\tif (!newPanel) {\n\t\t\tthis._log(`Panel not found: ${panelId}`);\n\t\t\treturn;\n\t\t}\n\n\t\tif (newPanel === this.pendingPanel) return;\n\n\t\tconst prevPanel = this.pendingPanel;\n\t\tconst prevPanelId = prevPanel?.id;\n\t\tthis.pendingPanel = newPanel;\n\n\t\tthis.element.classList.remove('is-loading');\n\n\t\tif (prevPanel && prevPanel !== this.activePanel && prevPanel !== newPanel) {\n\t\t\tprevPanel.classList.remove('incoming');\n\t\t\tif (prevPanel.hidden) {\n\t\t\t\t// Was never visible, keep hidden\n\t\t\t} else {\n\t\t\t\tprevPanel.classList.remove('active');\n\t\t\t}\n\t\t}\n\n\t\tconst wasLoadingAsync = this._isLoadingAsync;\n\n\t\tif (this._currentAbortController) {\n\t\t\tthis._currentAbortController.abort();\n\n\t\t\tif (wasLoadingAsync && prevPanelId && prevPanelId !== panelId) {\n\t\t\t\tthis._dispatch<ActivationAbortedEventDetail>('ps:activationaborted', {\n\t\t\t\t\tpanelId: prevPanelId,\n\t\t\t\t\ttrigger: resolvedTrigger\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst abortController = new AbortController();\n\t\tthis._currentAbortController = abortController;\n\t\tthis._isLoadingAsync = false;\n\n\t\tthis._log(`${prevPanel?.id || 'none'} → ${panelId}`);\n\n\t\tconst beforeActivateDetail: BeforeActivateEventDetail = {\n\t\t\tpanelId,\n\t\t\ttargetPanel: newPanel,\n\t\t\toutgoingPanel: prevPanel,\n\t\t\tsignal: abortController.signal,\n\t\t\tpromise: null\n\t\t};\n\n\t\tconst beforeActivateEvent = new CustomEvent('ps:beforeactivate', {\n\t\t\tdetail: beforeActivateDetail,\n\t\t\tbubbles: true,\n\t\t\tcancelable: false\n\t\t});\n\n\t\tthis.element.dispatchEvent(beforeActivateEvent);\n\n\t\tconst userPromise = beforeActivateDetail.promise;\n\n\t\tif (userPromise) {\n\t\t\tthis._isLoadingAsync = true;\n\t\t\tthis._log('Waiting for content...');\n\n\t\t\tlet spinnerTimeout: ReturnType<typeof setTimeout> | undefined;\n\t\t\tlet loadingShown = false;\n\n\t\t\tif (this.config.loadingDelay > 0) {\n\t\t\t\tspinnerTimeout = setTimeout(() => {\n\t\t\t\t\tthis.element.classList.add('is-loading');\n\t\t\t\t\tloadingShown = true;\n\t\t\t\t}, this.config.loadingDelay);\n\t\t\t} else {\n\t\t\t\tthis.element.classList.add('is-loading');\n\t\t\t\tloadingShown = true;\n\t\t\t}\n\n\t\t\tconst hasPreviousPanel = this.activePanel && this.activePanel !== newPanel;\n\n\t\t\tif (!hasPreviousPanel) {\n\t\t\t\tconst shouldTransition = transition !== false && this.config.transitions !== false;\n\t\t\t\tlet heightTransition = shouldTransition;\n\t\t\t\tif (typeof this.config.transitions === 'object') {\n\t\t\t\t\theightTransition = shouldTransition && this.config.transitions.height !== false;\n\t\t\t\t}\n\n\t\t\t\tif (heightTransition) {\n\t\t\t\t\tconst currentHeight = this.element.offsetHeight;\n\t\t\t\t\tthis.element.style.height = `${currentHeight}px`;\n\n\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\tthis.element.style.height = `${this.config.emptyPanelHeight}px`;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait userPromise;\n\n\t\t\t\tif (spinnerTimeout) clearTimeout(spinnerTimeout);\n\n\t\t\t\tif (abortController.signal.aborted) {\n\t\t\t\t\tthis._log(`Aborted during load: ${panelId}`);\n\t\t\t\t\tif (loadingShown) this.element.classList.remove('is-loading');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._log('Content loaded');\n\n\t\t\t\tif (newPanel.dataset.loaded === 'true') {\n\t\t\t\t\tthis._updateHighestPanel();\n\t\t\t\t}\n\n\t\t\t} catch (error) {\n\t\t\t\tif (spinnerTimeout) clearTimeout(spinnerTimeout);\n\n\t\t\t\tconst err = error as Error;\n\t\t\t\tthis._log(`Load failed: ${err.message}`);\n\t\t\t\tif (loadingShown) this.element.classList.remove('is-loading');\n\n\t\t\t\tif (err.name !== 'AbortError') {\n\t\t\t\t\tconsole.error('Panel load error:', error);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (loadingShown) this.element.classList.remove('is-loading');\n\t\t}\n\n\t\tif (abortController.signal.aborted) {\n\t\t\tthis._log(`Aborted: ${panelId}`);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._dispatch<ActivationEventDetail>('ps:activationstart', {\n\t\t\tpanelId,\n\t\t\ttrigger: resolvedTrigger\n\t\t});\n\n\t\tconst shouldTransition = transition !== false && this.config.transitions !== false;\n\n\t\tlet panelTransition = shouldTransition;\n\t\tlet heightTransition = shouldTransition;\n\n\t\tif (typeof this.config.transitions === 'object') {\n\t\t\tpanelTransition = shouldTransition && this.config.transitions.panels !== false;\n\t\t\theightTransition = shouldTransition && this.config.transitions.height !== false;\n\t\t}\n\n\t\tthis.panels.forEach(panel => panel.classList.toggle('fade', panelTransition));\n\n\t\tconst startHeight = this.element.offsetHeight;\n\t\tif (heightTransition) {\n\t\t\tthis.element.style.height = `${startHeight}px`;\n\t\t}\n\n\t\tconst outgoingPanel = this.activePanel;\n\n\t\tnewPanel.hidden = false;\n\t\tnewPanel.classList.add('incoming');\n\t\tif (panelTransition) {\n\t\t\tthis.element.classList.add('is-transitioning');\n\t\t}\n\t\tif (outgoingPanel && outgoingPanel !== newPanel) {\n\t\t\toutgoingPanel.classList.remove('active', 'incoming');\n\t\t\toutgoingPanel.hidden = false;\n\t\t}\n\n\t\trequestAnimationFrame(() => {\n\t\t\tnewPanel.classList.add('active');\n\t\t\tif (outgoingPanel && outgoingPanel !== newPanel) {\n\t\t\t\toutgoingPanel.classList.remove('incoming');\n\t\t\t}\n\n\t\t\tconst targetHeight = this._measureHeight(newPanel);\n\t\t\tconst heightChanged = startHeight !== targetHeight;\n\n\t\t\tif (heightTransition) {\n\t\t\t\tthis.element.style.height = `${targetHeight}px`;\n\t\t\t}\n\n\t\t\tconst promises: Promise<void>[] = [];\n\t\t\tif (panelTransition) {\n\t\t\t\tpromises.push(this._waitForTransition(newPanel));\n\t\t\t}\n\t\t\tif (heightTransition && heightChanged) {\n\t\t\t\tpromises.push(this._waitForTransition(this.element));\n\t\t\t}\n\t\t\tif (!promises.length) promises.push(Promise.resolve());\n\n\t\t\tPromise.all(promises).then(() => {\n\t\t\t\tif (this.pendingPanel !== newPanel) {\n\t\t\t\t\tthis._log(`Interrupted: ${panelId}`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._cleanupPanels(newPanel);\n\t\t\t\tthis._log(`✓ ${panelId}`);\n\n\t\t\t\t// Handle auto-focus\n\t\t\t\tif (finalAutoFocus !== false && finalAutoFocus !== undefined) {\n\t\t\t\t\tthis._handleAutoFocus(newPanel, finalAutoFocus, event);\n\t\t\t\t}\n\n\t\t\t\tthis._dispatch<ActivationEventDetail>('ps:activationcomplete', {\n\t\t\t\t\tpanelId,\n\t\t\t\t\ttrigger: resolvedTrigger\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t}\n\n}\n\nexport default PanelSet;"],"names":["_PanelSet","elementOrSelector","options","element","dataConfig","elementDesc","p","resizeTimeout","data","config","attrs","key","type","value","defaults","selectorOrOptions","selector","elements","instances","el","error","instance","message","id","wrapper","panel","eventName","detail","s","sum","prop","total","trackingParent","maxContainerHeight","wasHidden","wasActive","containerHeight","newPanel","resolve","styles","duration","delay","handler","e","autoFocus","event","focusWithDelay","logMessage","heading","focusable","input","isOpening","withTransition","action","oppositeClass","actionClass","myGeneration","targetHeight","currentHeight","transition","isClosed","isClosing","resolvedTrigger","finalAutoFocus","attrValue","once","targetPanel","signal","result","panelId","prevPanel","prevPanelId","wasLoadingAsync","abortController","beforeActivateDetail","beforeActivateEvent","userPromise","spinnerTimeout","loadingShown","shouldTransition","heightTransition","err","panelTransition","startHeight","outgoingPanel","heightChanged","promises","PanelSet"],"mappings":"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"}
|