panelset 1.0.8 → 1.2.1

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.
@@ -0,0 +1,1120 @@
1
+ //#region src/js/functions/core.ts
2
+ var e = class {
3
+ constructor() {
4
+ this._controller = new AbortController();
5
+ }
6
+ get signal() {
7
+ return this._controller.signal;
8
+ }
9
+ start() {
10
+ return this._controller.abort(), this._controller = new AbortController(), this._controller.signal;
11
+ }
12
+ static waitForTransition(e, t) {
13
+ return new Promise((n) => {
14
+ let r = getComputedStyle(e), i = (parseFloat(r.transitionDuration) || 0) + (parseFloat(r.transitionDelay) || 0);
15
+ if (i === 0) return n();
16
+ let a = !1, o = () => {
17
+ a || (a = !0, e.removeEventListener("transitionend", s), n());
18
+ }, s = (n) => {
19
+ n.target === e && (t && n.propertyName !== t || o());
20
+ };
21
+ e.addEventListener("transitionend", s), setTimeout(o, (i + .05) * 1e3);
22
+ });
23
+ }
24
+ };
25
+ //#endregion
26
+ //#region src/js/functions/focus.ts
27
+ function t(e, t, n) {
28
+ if (!t || t !== "input" && n && !(n.type.startsWith("key") || n instanceof MouseEvent && n.detail === 0)) return;
29
+ let r = (e) => {
30
+ setTimeout(() => e.focus(), 100);
31
+ };
32
+ if (t === !0) e.hasAttribute("tabindex") || e.setAttribute("tabindex", "-1"), r(e);
33
+ else if (t === "heading") {
34
+ let t = e.querySelector("h1, h2, h3, h4, h5, h6");
35
+ t && (t.hasAttribute("tabindex") || t.setAttribute("tabindex", "-1"), r(t));
36
+ } else if (t === "first") {
37
+ let t = e.querySelector("a,button,input,select,textarea,[tabindex]:not([tabindex=\"-1\"])");
38
+ t && r(t);
39
+ } else if (t === "input") {
40
+ let t = e.querySelector("input:not([type=hidden]):not([disabled]),select:not([disabled]),textarea:not([disabled])");
41
+ t && r(t);
42
+ } else typeof t == "function" && setTimeout(() => t(e), 100);
43
+ }
44
+ //#endregion
45
+ //#region src/js/functions/persist.ts
46
+ var n = () => {
47
+ let e = new URLSearchParams(location.search).get("panel");
48
+ return e ? e.split(",").filter(Boolean) : [];
49
+ }, r = (e) => {
50
+ let t = new URL(location.href);
51
+ if (t.searchParams.delete("panel"), e.length) {
52
+ let n = t.search ? "&" : "?";
53
+ history.replaceState(null, "", `${t}${n}panel=${e.join(",")}`);
54
+ } else history.replaceState(null, "", t);
55
+ }, i = (e) => `${location.pathname}::${e}`, a = (e) => localStorage.getItem(i(e)), o = (e, t) => localStorage.setItem(i(e), t);
56
+ //#endregion
57
+ //#region src/js/functions/config.ts
58
+ function s(e, t) {
59
+ switch (t) {
60
+ case "string": return e;
61
+ case "boolean": return e !== "false";
62
+ case "number": return parseInt(e, 10);
63
+ case "json": try {
64
+ return JSON.parse(e);
65
+ } catch {
66
+ return e !== "false";
67
+ }
68
+ }
69
+ }
70
+ function c(e, t) {
71
+ let n = {};
72
+ for (let [r, i] of Object.entries(t)) {
73
+ let [t, a] = i, o = e[t];
74
+ o !== void 0 && (n[r] = s(o, a));
75
+ }
76
+ return n;
77
+ }
78
+ function l(e, t) {
79
+ let n = {};
80
+ for (let [r, i] of Object.entries(t)) {
81
+ let [t, a] = i, o = t.replace(/([A-Z])/g, "-$1").toLowerCase(), c = e.getAttribute(o);
82
+ c !== null && (n[r] = s(c, a));
83
+ }
84
+ return n;
85
+ }
86
+ //#endregion
87
+ //#region src/js/functions/utils.ts
88
+ function u(e, t, n, r) {
89
+ n && console.log(`[${e}] "${t.id || "no id"}" -`, r);
90
+ }
91
+ function d(e, t, n) {
92
+ let r = t.split(/\s+/).filter(Boolean);
93
+ if (!r.length) return;
94
+ let i = (e.getAttribute("aria-describedby") || "").split(/\s+/).filter(Boolean), a = !1;
95
+ for (let e of r) {
96
+ let t = i.includes(e);
97
+ n && !t ? (i.push(e), a = !0) : !n && t && (i.splice(i.indexOf(e), 1), a = !0);
98
+ }
99
+ a && (i.length ? e.setAttribute("aria-describedby", i.join(" ")) : e.removeAttribute("aria-describedby"));
100
+ }
101
+ var f = !1;
102
+ function p(e) {
103
+ !e || f || (f = !0, console.log("[Panel/PanelSet] Browser supports 'interpolate-size', which will be used for opening and closing."));
104
+ }
105
+ function m(e) {
106
+ e.waitUntil = (t) => {
107
+ e.promise = e.promise ? Promise.all([e.promise, t]) : t;
108
+ };
109
+ }
110
+ function h(e, t, n, r, i = {}) {
111
+ let a = i.once === !0;
112
+ e.addEventListener(t, (e) => {
113
+ let t = e, i = n(t.detail), { signal: o } = t.detail;
114
+ if (a && i.dataset.loaded === "true") return;
115
+ let s = r(i, o);
116
+ s && typeof s.then == "function" && t.detail.waitUntil(s.then(() => {
117
+ a && (i.dataset.loaded = "true");
118
+ }));
119
+ });
120
+ }
121
+ //#endregion
122
+ //#region src/js/panelset.ts
123
+ var g, _ = class i {
124
+ static init(e = {}, t = {}) {
125
+ let n, r;
126
+ typeof e == "string" ? (n = e, r = t) : (r = e, n = r.selector || "[data-panelset]");
127
+ let a = document.querySelectorAll(n), o = [];
128
+ return a.forEach((e) => {
129
+ try {
130
+ i._validateElement(e);
131
+ } catch (e) {
132
+ console.error(e.message);
133
+ return;
134
+ }
135
+ if (e.panelSet) {
136
+ o.push(e.panelSet);
137
+ return;
138
+ }
139
+ let t = new i(e, r);
140
+ o.push(t);
141
+ }), o;
142
+ }
143
+ constructor(t, s = {}) {
144
+ this.hasAsyncContent = !1, this._animShow = new e(), this._animOpenClose = new e(), this._isLoadingAsync = !1, this._activating = !1, this._switchDirection = null, this._returnFocusTarget = null, this._heightObserver = null, this._verbController = new AbortController(), this._parsePanelParam = () => {
145
+ let e = n();
146
+ return this.panels.find((t) => t.id && e.includes(t.id))?.id ?? null;
147
+ }, this._persistState = (e) => {
148
+ if (this.config.persist && this.element.id && o(`ps:${this.element.id}`, e), this.config.deepLink) this._updatePanelParam(e);
149
+ else {
150
+ let e = new Set(this.panels.map((e) => e.id).filter(Boolean)), t = n();
151
+ t.some((t) => e.has(t)) && r(t.filter((t) => !e.has(t)));
152
+ }
153
+ }, this._updatePanelParam = (e) => {
154
+ let t = new Set(this.panels.map((e) => e.id).filter(Boolean));
155
+ r([...n().filter((e) => !t.has(e)), e].filter(Boolean));
156
+ }, this._resolveInitialPanel = () => {
157
+ let e = this._parsePanelParam();
158
+ if (e) return e;
159
+ if (this.config.persist) {
160
+ let { id: e } = this.element;
161
+ if (!e) return null;
162
+ let t = a(`ps:${e}`);
163
+ return t && this.panels.some((e) => e.id === t) ? t : null;
164
+ }
165
+ return null;
166
+ }, this._onActivationEdge = (e) => {
167
+ let { atStart: t, atEnd: n } = e.detail;
168
+ this._reflectVerbEndState(t, n);
169
+ };
170
+ let l;
171
+ if (typeof t == "string") {
172
+ if (l = document.querySelector(t), !l) throw Error(`PanelSet: No element found for selector "${t}"`);
173
+ } else l = t;
174
+ if (this.element = l, i._validateElement(l), l.panelSet) return console.warn("PanelSet: already initialized"), l.panelSet;
175
+ l.panelSet = this, i._installVerbDelegation();
176
+ let u = c(l.dataset, i.attrs);
177
+ if (this.config = {
178
+ ...i.defaults,
179
+ ...s,
180
+ ...u
181
+ }, this.panels = this._collectPanels(), this.panels.length === 0) {
182
+ this.panelWrapper = this.element.querySelector(":scope > .panel-wrapper") || this._autoWrapPanels(), this._log("Initialized empty (0 panels) — ready for addPanel()"), this._dispatch("ps:ready", {
183
+ container: this.element,
184
+ instance: this
185
+ }), this._initVerbButtons(), this._observeTrackHeight();
186
+ return;
187
+ }
188
+ let d = this._resolveInitialPanel();
189
+ this.activePanel = (d ? this.panels.find((e) => e.id === d) : null) ?? this.panels.find((e) => e.classList.contains("active")) ?? this.panels[0], this.panelWrapper = this.element.querySelector(":scope > .panel-wrapper") || this._autoWrapPanels(), this.pendingPanel = this.activePanel, this.config.align !== "start" && (this.element.dataset.panelsetAlign = this.config.align), this.config.closable && !this.element.classList.contains("is-open") && this.element.setAttribute("inert", ""), i._nativeInterpolateSize && p(this.config.debug), this._log(`Initialized (${this.panels.length} panels)`), this._dispatch("ps:ready", {
190
+ container: this.element,
191
+ instance: this
192
+ }), this._internalInit(), this._initVerbButtons(), this._observeTrackHeight();
193
+ }
194
+ _observeTrackHeight() {
195
+ let e = this.element.closest("[data-panelset-trackheight]");
196
+ if (!e || typeof ResizeObserver > "u") return;
197
+ let t = e.clientWidth, n = 0;
198
+ this._heightObserver = new ResizeObserver(() => {
199
+ let r = e.clientWidth;
200
+ r !== t && (t = r, cancelAnimationFrame(n), n = requestAnimationFrame(() => this._updateHighestPanel()));
201
+ }), this._heightObserver.observe(e);
202
+ }
203
+ _log(e) {
204
+ u("PanelSet", this.element, this.config.debug, e);
205
+ }
206
+ get _isClosed() {
207
+ return this.config.closable && !this.element.classList.contains("is-open") && !this.element.classList.contains("is-opening");
208
+ }
209
+ static _validateElement(e) {
210
+ if (!e.hasAttribute("data-panelset") && !e.tagName.includes("-")) throw Error("PanelSet: element must have [data-panelset] or be a custom element");
211
+ }
212
+ _autoWrapPanels() {
213
+ let e = document.createElement("div");
214
+ return e.className = "panel-wrapper", this.panels.forEach((t) => e.appendChild(t)), this.element.appendChild(e), e;
215
+ }
216
+ _collectPanels() {
217
+ return Array.from(this.element.querySelectorAll("[role=\"tabpanel\"]")).filter((e) => e.closest("[data-panelset], ps-panelset, [data-panel], ps-panel") === this.element);
218
+ }
219
+ _internalInit() {
220
+ this.panels.forEach((e) => {
221
+ e.classList.remove("fade", "incoming", "outgoing", "levelup", "leveldown"), e === this.activePanel ? (e.hidden = !1, e.classList.add("active")) : (e.hidden = !0, e.classList.remove("active"));
222
+ }), this.element.style.height = "", this._updateHighestPanel(), this.config.manageTriggers && this._updateTabTriggers(this.activePanel), this.config.manageLabels && this._reflectLabels();
223
+ }
224
+ _dispatch(e, t) {
225
+ this.element.dispatchEvent(new CustomEvent(e, {
226
+ detail: t,
227
+ bubbles: !0,
228
+ cancelable: !1
229
+ }));
230
+ }
231
+ _getVerticalMetrics(e) {
232
+ if (!e) return 0;
233
+ let t = getComputedStyle(e);
234
+ return (parseFloat(t.paddingTop) || 0) + (parseFloat(t.paddingBottom) || 0) + (parseFloat(t.borderTopWidth) || 0) + (parseFloat(t.borderBottomWidth) || 0);
235
+ }
236
+ _measureHeight(e) {
237
+ let t = e.offsetHeight;
238
+ return t += this._getVerticalMetrics(this.panelWrapper), t += this._getVerticalMetrics(this.element), t;
239
+ }
240
+ _updateHighestPanel() {
241
+ if (this.element.hasAttribute("data-panelset-trackheight")) {
242
+ console.warn("PanelSet: data-panelset-trackheight on parent only");
243
+ return;
244
+ }
245
+ let e = this.element.closest("[data-panelset-trackheight]");
246
+ if (!e) return;
247
+ this.panels.forEach((e) => {
248
+ e.hidden = !0, e.classList.remove("active");
249
+ });
250
+ let t = 0;
251
+ this.panels.forEach((e) => {
252
+ e.hidden = !1, e.classList.add("active"), e.style.visibility = "hidden";
253
+ let n = this.element.offsetHeight;
254
+ n > t && (t = n), e.hidden = !0, e.classList.remove("active"), e.style.visibility = "";
255
+ }), this.activePanel && (this.activePanel.hidden = !1, this.activePanel.classList.add("active")), e.style.setProperty("--ps-max-height", `${t}px`), this._log(`Max container height: ${t}px`);
256
+ }
257
+ _updateTabTriggers(e) {
258
+ this.panels.forEach((t) => {
259
+ t.id && document.querySelectorAll(`[aria-controls="${t.id}"]`).forEach((n) => {
260
+ let r = t === e;
261
+ n.getAttribute("role") === "tab" && n.closest("[role=\"tablist\"]") ? (n.setAttribute("aria-selected", String(r)), n.removeAttribute("aria-current")) : (r ? n.setAttribute("aria-current", "true") : n.removeAttribute("aria-current"), n.removeAttribute("aria-selected"));
262
+ });
263
+ });
264
+ }
265
+ _reflectLabels() {
266
+ this.panels.forEach((e) => {
267
+ if (!e.id || e.hasAttribute("aria-labelledby") || e.hasAttribute("aria-label")) return;
268
+ let t = Array.from(document.querySelectorAll(`[aria-controls="${e.id}"]`));
269
+ if (t.length === 0) return;
270
+ let n = t.filter((e) => e.getAttribute("role") === "tab"), r = n.length === 1 ? n[0] : t.length === 1 ? t[0] : null;
271
+ r && (r.id || (r.id = this._uniqueId(`${e.id}-tab`)), e.setAttribute("aria-labelledby", r.id));
272
+ });
273
+ }
274
+ _uniqueId(e) {
275
+ let t = e, n = 2;
276
+ for (; document.getElementById(t);) t = `${e}-${n++}`;
277
+ return t;
278
+ }
279
+ _setTriggersActivating(e) {
280
+ this.panels.forEach((t) => {
281
+ t.id && document.querySelectorAll(`[aria-controls="${t.id}"]`).forEach((t) => {
282
+ t.classList.toggle("is-activating", e);
283
+ });
284
+ });
285
+ }
286
+ _cleanupPanels(e) {
287
+ this.panels.forEach((t) => {
288
+ t.classList.remove("fade", "incoming", "outgoing", "levelup", "leveldown"), t === e ? (t.classList.add("active"), t.hidden = !1, t.removeAttribute("inert")) : (t.classList.remove("active"), t.hidden = !0);
289
+ }), this.element.style.height = "", this.element.classList.remove("is-transitioning"), this.activePanel = e, this.config.manageTriggers && this._updateTabTriggers(e);
290
+ }
291
+ _resolveAutoFocus(e, t) {
292
+ if (this.config.manageTriggers) {
293
+ let t = e?.getAttribute("data-auto-focus");
294
+ if (t != null) {
295
+ if (t === "true") return !0;
296
+ if (t === "false") return !1;
297
+ if (t === "heading" || t === "first" || t === "input") return t;
298
+ }
299
+ }
300
+ return t === void 0 ? this.config.autoFocus : t;
301
+ }
302
+ _handleAutoFocus(e, n, r) {
303
+ t(e, n, r);
304
+ }
305
+ _animateOpenClose(t, n, r) {
306
+ let a = t ? "opening" : "closing", o = `is-${t ? "closing" : "opening"}`, s = `is-${a}`;
307
+ this._log(t ? "Opening" : "Closing");
308
+ let c = this._animOpenClose.start(), l = this.element.classList.contains(o) ? this.element.offsetHeight : null, u = t ? null : this.element.offsetHeight;
309
+ this.element.classList.remove(o), t || this.element.classList.remove("is-open"), t && this.element.removeAttribute("inert");
310
+ let d = () => {
311
+ this.element.setAttribute("inert", "");
312
+ let e = r instanceof PointerEvent && r.pointerType !== "";
313
+ this.config.returnFocus && this._returnFocusTarget && !e && this._returnFocusTarget.focus();
314
+ };
315
+ if (n && this.config.transitions) if (this.element.classList.add(s), i._nativeInterpolateSize) t ? (this.element.style.height = l === null ? "0px" : `${l}px`, requestAnimationFrame(() => {
316
+ this.element.style.height = "", e.waitForTransition(this.element, "height").then(() => {
317
+ c.aborted || (this.panelWrapper ? e.waitForTransition(this.panelWrapper) : Promise.resolve()).then(() => {
318
+ c.aborted || (this.element.classList.remove(s), this.element.classList.add("is-open"), this.element.offsetHeight);
319
+ });
320
+ });
321
+ })) : (this.element.style.height = l === null ? `${u}px` : `${l}px`, requestAnimationFrame(() => {
322
+ this.element.style.height = "", e.waitForTransition(this.element, "height").then(() => {
323
+ c.aborted || (this.element.classList.remove(s), this.element.offsetHeight, d());
324
+ });
325
+ }));
326
+ else {
327
+ let n = t ? this._measureHeight(this.pendingPanel) : 0, r = l === null ? t ? this.element.offsetHeight : u ?? 0 : l;
328
+ this.element.style.height = `${r}px`, getComputedStyle(this.element).height, requestAnimationFrame(() => {
329
+ this.element.style.height = `${n}px`, e.waitForTransition(this.element).then(() => {
330
+ c.aborted || (this.element.style.height = "", this.element.classList.remove(s), t && this.element.classList.add("is-open"), this.element.offsetHeight, t || d());
331
+ });
332
+ });
333
+ }
334
+ else t ? this.element.classList.add("is-open") : (this.element.classList.remove("is-open"), d()), this.element.style.height = "";
335
+ }
336
+ getActive() {
337
+ return this.pendingPanel?.id || null;
338
+ }
339
+ refresh() {
340
+ let e = this.activePanel;
341
+ this.panels = this._collectPanels(), this.panels.length !== 0 && (this.activePanel = e && this.panels.includes(e) ? e : this.panels.find((e) => e.classList.contains("active")) ?? this.panels[0], this.pendingPanel = this.activePanel, this.panelWrapper = this.element.querySelector(":scope > .panel-wrapper") || this.panelWrapper, this._internalInit(), this._reflectEnds(), this._log(`Refreshed (${this.panels.length} panels)`));
342
+ }
343
+ addPanel(e, t) {
344
+ e.hasAttribute("role") || e.setAttribute("role", "tabpanel");
345
+ let n = null;
346
+ return t?.before ? n = this.panels.find((e) => e.id === t.before) ?? null : t?.after ? n = this.panels.find((e) => e.id === t.after)?.nextElementSibling ?? null : typeof t?.index == "number" && (n = this.panels[t.index] ?? null), (this.panelWrapper || this._autoWrapPanels()).insertBefore(e, n), this.refresh(), e;
347
+ }
348
+ removePanel(e) {
349
+ let t = this.panels.find((t) => t.id === e);
350
+ t && (t.remove(), this.refresh());
351
+ }
352
+ destroy() {
353
+ this._animShow.start(), this._animOpenClose.start(), this._heightObserver?.disconnect(), this._heightObserver = null, this._verbController.abort(), delete this.element.panelSet, this._log("Destroyed");
354
+ }
355
+ _edgeInfo(e) {
356
+ let t = this.panels.length, n = e ? this.panels.indexOf(e) : -1;
357
+ return {
358
+ index: n,
359
+ total: t,
360
+ atStart: n <= 0,
361
+ atEnd: n === t - 1
362
+ };
363
+ }
364
+ static _installVerbDelegation() {
365
+ i._verbDelegationInstalled || (i._verbDelegationInstalled = !0, document.addEventListener("click", i._onVerbClick));
366
+ }
367
+ static _resolveVerbSet(e, t) {
368
+ let n = e.getAttribute(`data-ps-${t}`);
369
+ return n ? document.querySelector(n) : e.closest("[data-panelset], ps-panelset");
370
+ }
371
+ _initVerbButtons() {
372
+ let { signal: e } = this._verbController;
373
+ this.element.addEventListener("ps:activationstart", this._onActivationEdge, { signal: e }), this.element.addEventListener("ps:activationcomplete", this._onActivationEdge, { signal: e }), this._reflectEnds();
374
+ }
375
+ _reflectEnds() {
376
+ let { atStart: e, atEnd: t } = this._edgeInfo(this.pendingPanel);
377
+ this._reflectVerbEndState(e, t);
378
+ }
379
+ _reflectVerbEndState(e, t) {
380
+ if (this.config.loop) return;
381
+ let n = this._verbButtonsFor("prev"), r = this._verbButtonsFor("next");
382
+ if (this.config.disabledMode !== "native") {
383
+ n.forEach((t) => this._applyVerbDisabled(t, e)), r.forEach((e) => this._applyVerbDisabled(e, t));
384
+ return;
385
+ }
386
+ e || n.forEach((e) => this._applyVerbDisabled(e, !1)), t || r.forEach((e) => this._applyVerbDisabled(e, !1)), e && this._disableVerbNative(n, t ? [] : r), t && this._disableVerbNative(r, e ? [] : n);
387
+ }
388
+ _applyVerbDisabled(e, t) {
389
+ this.config.disabledMode === "native" ? t ? e.setAttribute("disabled", "") : e.removeAttribute("disabled") : e.setAttribute("aria-disabled", String(t));
390
+ let n = e.getAttribute("data-ps-disabled-hint");
391
+ n && d(e, n, t);
392
+ }
393
+ _disableVerbNative(e, t) {
394
+ e.forEach((e) => {
395
+ !e.hasAttribute("disabled") && document.activeElement === e && (t.find((e) => !e.hasAttribute("disabled")) ?? this._verbFocusFallback())?.focus(), this._applyVerbDisabled(e, !0);
396
+ });
397
+ }
398
+ _verbFocusFallback() {
399
+ let e = this.pendingPanel ?? this.activePanel;
400
+ return e ? (e.hasAttribute("tabindex") || e.setAttribute("tabindex", "-1"), e) : null;
401
+ }
402
+ _verbButtonsFor(e) {
403
+ return Array.from(document.querySelectorAll(`[data-ps-${e}]`)).filter((t) => i._resolveVerbSet(t, e) === this.element);
404
+ }
405
+ next(e) {
406
+ this._step(1, e);
407
+ }
408
+ prev(e) {
409
+ this._step(-1, e);
410
+ }
411
+ _step(e, t) {
412
+ let n = this.panels.length;
413
+ if (n === 0) return;
414
+ let r = this.panels.indexOf(this.pendingPanel), i = (r === -1 ? 0 : r) + e, a = !1;
415
+ if (i < 0 || i >= n) {
416
+ if (!this.config.loop) return;
417
+ i = (i + n) % n, a = !0;
418
+ }
419
+ let o = this.panels[i];
420
+ o && o !== this.pendingPanel && this.show(o.id, a ? {
421
+ ...t,
422
+ direction: e > 0 ? "forward" : "backward"
423
+ } : t);
424
+ }
425
+ open(t) {
426
+ let { event: n, transition: r = !0, autoFocus: i } = t || {};
427
+ if (!this.config.closable) {
428
+ this._log("Not closable");
429
+ return;
430
+ }
431
+ let a = this._isClosed, o = this.element.classList.contains("is-closing"), s = this.element.classList.contains("is-loading");
432
+ if (!a && !o || this.element.classList.contains("is-transitioning") && !s) return;
433
+ let c = n?.target instanceof HTMLElement ? n.target.closest("button, a, [role=\"tab\"]") ?? n.target : null, l = this._resolveAutoFocus(c, i);
434
+ c && (this._returnFocusTarget = c), this._animateOpenClose(!0, r), l !== !1 && l !== void 0 && this.pendingPanel && (r && this.config.transitions ? e.waitForTransition(this.element).then(() => {
435
+ this._handleAutoFocus(this.pendingPanel, l, n);
436
+ }) : this._handleAutoFocus(this.pendingPanel, l, n));
437
+ }
438
+ close(e) {
439
+ let { transition: t = !0, event: n } = e || {};
440
+ if (!this.config.closable) {
441
+ this._log("Not closable");
442
+ return;
443
+ }
444
+ let r = this._isClosed, i = this.element.classList.contains("is-closing"), a = this.element.classList.contains("is-opening"), o = this.element.classList.contains("is-loading");
445
+ (r || i) && !a || this.element.classList.contains("is-transitioning") && !o || this._animateOpenClose(!1, t, n);
446
+ }
447
+ toggle(e) {
448
+ let { event: t, transition: n = !0, autoFocus: r } = e || {}, i = this._isClosed, a = this.element.classList.contains("is-closing");
449
+ i || a ? this.open({
450
+ event: t,
451
+ transition: n,
452
+ autoFocus: r
453
+ }) : this.close({
454
+ transition: n,
455
+ event: t
456
+ });
457
+ }
458
+ onBeforeOpen(e, t = {}) {
459
+ this.hasAsyncContent = !0, h(this.element, "ps:beforeopen", (e) => e.targetPanel, e, t);
460
+ }
461
+ async show(t, n) {
462
+ if (this.config.interruptible === !1 && this._activating) return;
463
+ let { event: r, transition: i = !0, autoFocus: a, direction: o } = n || {}, s = r?.target instanceof HTMLElement ? r.target.closest("button, a, [role=\"tab\"]") ?? r.target : null, c = this._resolveAutoFocus(s, a), l = this.panels.find((e) => e.id === t);
464
+ if (!l) {
465
+ this._log(`Panel not found: ${t}`);
466
+ return;
467
+ }
468
+ let u = new CustomEvent("ps:beforeactivate", {
469
+ detail: {
470
+ panelId: t,
471
+ targetPanel: l,
472
+ outgoingPanel: this.activePanel ?? null,
473
+ trigger: s
474
+ },
475
+ bubbles: !0,
476
+ cancelable: !0
477
+ });
478
+ if (!this.element.dispatchEvent(u)) {
479
+ this._log(`Vetoed by ps:beforeactivate: ${t}`);
480
+ return;
481
+ }
482
+ let d = this._isClosed, f = this.element.classList.contains("is-closing"), p = this.element.classList.contains("is-loading");
483
+ if (l === this.pendingPanel) {
484
+ d || f ? this.open({
485
+ event: r,
486
+ transition: i,
487
+ autoFocus: c
488
+ }) : this.config.closable && this.config.closeOnTab && this.close({
489
+ transition: i,
490
+ event: r
491
+ });
492
+ return;
493
+ }
494
+ if ((this.element.classList.contains("is-opening") || f) && !p) return;
495
+ if (d) {
496
+ this.pendingPanel = l, this._cleanupPanels(l), this.open({
497
+ event: r,
498
+ transition: i,
499
+ autoFocus: c
500
+ });
501
+ return;
502
+ }
503
+ let h = this._activating;
504
+ this._activating = !0, this.config.manageTriggers && this.config.interruptible === !1 && this._setTriggersActivating(!0);
505
+ let g = this.pendingPanel, _ = g?.id;
506
+ this.pendingPanel = l;
507
+ let v = h && l === this.activePanel && g !== l;
508
+ this.config.manageTriggers && this._updateTabTriggers(l), this._persistState(t), this.element.classList.remove("is-loading"), !v && g && g !== this.activePanel && g !== l && (g.classList.remove("incoming", "outgoing", "levelup", "leveldown"), g.hidden || g.classList.remove("active"));
509
+ let y = this._isLoadingAsync, b = this._animShow.signal.aborted, x = this._animShow.start();
510
+ !b && y && _ && _ !== t && this._dispatch("ps:activationaborted", {
511
+ panelId: _,
512
+ trigger: s
513
+ }), this._isLoadingAsync = !1, this._log(`${g?.id || "none"} > ${t}`);
514
+ let S = {
515
+ panelId: t,
516
+ targetPanel: l,
517
+ outgoingPanel: g,
518
+ signal: x,
519
+ promise: null,
520
+ waitUntil() {}
521
+ };
522
+ m(S);
523
+ let C = new CustomEvent("ps:beforeopen", {
524
+ detail: S,
525
+ bubbles: !0,
526
+ cancelable: !1
527
+ });
528
+ this.element.dispatchEvent(C);
529
+ let w = S.promise;
530
+ if (w) {
531
+ this._isLoadingAsync = !0, this._log("Waiting for content..."), this.element.style.setProperty("--ps-loading-delay", `${this.config.loadingDelay}ms`), this.element.classList.add("is-loading");
532
+ let n = null, r = i !== !1 && this.config.transitions !== !1, a = r;
533
+ if (typeof this.config.transitions == "object" && (a = r && this.config.transitions.height !== !1), a) if (d) this.element.classList.add("is-open", "is-opening"), this.element.style.height = "0px", requestAnimationFrame(() => {
534
+ this.element.style.height = `${this.config.loadingHeight}px`;
535
+ }), n = e.waitForTransition(this.element, "height");
536
+ else {
537
+ let t = this.element.offsetHeight, r = Math.max(t, this.config.loadingHeight);
538
+ r > t && (this.element.style.height = `${t}px`, requestAnimationFrame(() => {
539
+ this.element.style.height = `${r}px`;
540
+ }), n = e.waitForTransition(this.element, "height"));
541
+ }
542
+ try {
543
+ if (await Promise.all([w, n].filter(Boolean)), x.aborted) {
544
+ this._log(`Aborted during load: ${t}`), this.element.classList.remove("is-loading"), this.element.style.removeProperty("--ps-loading-delay");
545
+ return;
546
+ }
547
+ this._log("Content loaded"), l.dataset.loaded === "true" && this._updateHighestPanel();
548
+ } catch (e) {
549
+ let t = e;
550
+ this._log(`Load failed: ${t.message}`), this.element.classList.remove("is-loading"), this.element.style.removeProperty("--ps-loading-delay"), t.name !== "AbortError" && console.error("Panel load error:", e), this._activating = !1, this.config.manageTriggers && this.config.interruptible === !1 && this._setTriggersActivating(!1);
551
+ return;
552
+ }
553
+ this.element.classList.remove("is-loading"), this.element.style.removeProperty("--ps-loading-delay"), this.element.classList.remove("is-opening");
554
+ }
555
+ if (x.aborted) {
556
+ this._log(`Aborted: ${t}`);
557
+ return;
558
+ }
559
+ let T = v ? g : this.activePanel;
560
+ this._dispatch("ps:activationstart", {
561
+ panelId: t,
562
+ trigger: s,
563
+ outgoingPanel: T,
564
+ ...this._edgeInfo(l)
565
+ });
566
+ let E = i !== !1 && this.config.transitions !== !1, D = E, O = E;
567
+ typeof this.config.transitions == "object" && (D = E && this.config.transitions.panels !== !1, O = E && this.config.transitions.height !== !1), this.panels.forEach((e) => e.classList.toggle("fade", D));
568
+ let k = null;
569
+ if (v) k = this._switchDirection === "leveldown" ? "levelup" : "leveldown";
570
+ else if (this.config.levels && T && T !== l) if (o) k = o === "forward" ? "levelup" : "leveldown";
571
+ else {
572
+ let e = this.panels.indexOf(T), t = this.panels.indexOf(l);
573
+ e !== -1 && t !== -1 && e !== t && (k = t > e ? "levelup" : "leveldown");
574
+ }
575
+ this._switchDirection = k, this.panels.forEach((e) => e.classList.remove("outgoing", "levelup", "leveldown"));
576
+ let A = this.element.offsetHeight;
577
+ O && (this.element.style.height = `${A}px`), l.hidden = !1, l.setAttribute("inert", ""), l.classList.add("incoming"), k && l.classList.add(k), D && this.element.classList.add("is-transitioning"), T && T !== l && (T.classList.remove("active", "incoming"), T.classList.add("outgoing"), k && T.classList.add(k), T.hidden = !1, T.setAttribute("inert", "")), requestAnimationFrame(() => requestAnimationFrame(() => {
578
+ l.classList.add("active"), T && T !== l && T.classList.remove("incoming");
579
+ let n = this._measureHeight(l), i = A !== n;
580
+ O && (this.element.style.height = `${n}px`);
581
+ let a = [];
582
+ D && a.push(e.waitForTransition(l)), O && i && a.push(e.waitForTransition(this.element)), a.length || a.push(Promise.resolve()), Promise.all(a).then(() => {
583
+ if (x.aborted) {
584
+ this._log(`Interrupted: ${t}`);
585
+ return;
586
+ }
587
+ this._cleanupPanels(l), this._log(`✓ ${t}`), c !== !1 && c !== void 0 && this._handleAutoFocus(l, c, r), this._activating = !1, this.config.manageTriggers && this.config.interruptible === !1 && this._setTriggersActivating(!1), this._dispatch("ps:activationcomplete", {
588
+ panelId: t,
589
+ trigger: s,
590
+ outgoingPanel: T,
591
+ ...this._edgeInfo(l)
592
+ });
593
+ });
594
+ }));
595
+ }
596
+ };
597
+ g = _, g.defaults = {
598
+ align: "start",
599
+ transitions: !0,
600
+ levels: !1,
601
+ loop: !1,
602
+ closable: !1,
603
+ closeOnTab: !1,
604
+ disabledMode: "aria",
605
+ loadingHeight: 150,
606
+ loadingDelay: 320,
607
+ returnFocus: !1,
608
+ autoFocus: !1,
609
+ persist: !1,
610
+ deepLink: !1,
611
+ interruptible: !0,
612
+ manageTriggers: !0,
613
+ manageLabels: !0,
614
+ debug: !1
615
+ }, g._nativeInterpolateSize = typeof CSS < "u" && CSS.supports("interpolate-size: allow-keywords"), g._verbDelegationInstalled = !1, g.attrs = {
616
+ align: ["panelsetAlign", "string"],
617
+ transitions: ["transitions", "json"],
618
+ levels: ["psLevels", "boolean"],
619
+ loop: ["psLoop", "boolean"],
620
+ closable: ["closable", "boolean"],
621
+ closeOnTab: ["closeOnTab", "boolean"],
622
+ disabledMode: ["psDisabledMode", "string"],
623
+ loadingHeight: ["loadingHeight", "number"],
624
+ loadingDelay: ["loadingDelay", "number"],
625
+ autoFocus: ["autoFocus", "string"],
626
+ returnFocus: ["returnFocus", "boolean"],
627
+ persist: ["panelPersist", "boolean"],
628
+ deepLink: ["panelDeeplink", "boolean"],
629
+ interruptible: ["interruptible", "boolean"],
630
+ manageTriggers: ["manageTriggers", "boolean"],
631
+ manageLabels: ["manageLabels", "boolean"],
632
+ debug: ["debug", "boolean"]
633
+ }, g._onVerbClick = (e) => {
634
+ let t = e.target;
635
+ if (!(t instanceof Element)) return;
636
+ let n = t.closest("[data-ps-next], [data-ps-prev], [data-ps-close]");
637
+ if (!n || n.getAttribute("aria-disabled") === "true") return;
638
+ let r = n.hasAttribute("data-ps-next") ? "next" : n.hasAttribute("data-ps-prev") ? "prev" : "close", i = g._resolveVerbSet(n, r), a = i?.panelSet;
639
+ if (!a) {
640
+ i && u("PanelSet", i, i.dataset.debug != null && i.dataset.debug !== "false", `data-ps-${r}: PanelSet is not initialised. Add a PanelSet.init().`);
641
+ return;
642
+ }
643
+ a[r]({ event: e });
644
+ };
645
+ //#endregion
646
+ //#region src/js/functions/pinning.ts
647
+ var v = (e) => {
648
+ let t = e.parentElement;
649
+ return t?.querySelector("[data-panel-body]") ? Array.from(t.children).find((e) => e instanceof HTMLElement && e.hasAttribute("data-panel-body")) ?? null : null;
650
+ }, y = (e) => {
651
+ let t = Array.from(e.querySelectorAll("[data-panel-pin]"));
652
+ t.length && t.map((e) => ({
653
+ el: e,
654
+ pin: e.dataset.panelPin,
655
+ w: e.offsetWidth
656
+ })).forEach(({ el: e, pin: t, w: n }) => {
657
+ e.style.boxSizing = "border-box", e.style.width = `${n}px`, t === "end" && (e.style.marginLeft = `calc(100% - ${n}px)`);
658
+ });
659
+ }, b = (e) => {
660
+ e.querySelectorAll("[data-panel-pin]").forEach((e) => {
661
+ e.style.boxSizing = "", e.style.width = "", e.style.marginLeft = "";
662
+ });
663
+ }, x;
664
+ function S(e, t) {
665
+ let { groupSelector: n, scopeSelector: r = n, itemSelector: i, filter: a } = t, o = (e, t) => {
666
+ if (e.closest(r) !== t) return !1;
667
+ let n = e.parentElement?.closest(i);
668
+ return !n || !t.contains(n);
669
+ }, s = e.closest(n);
670
+ return !s || !o(e, s) ? [] : [...s.querySelectorAll(i)].filter((t) => t !== e && o(t, s) && (a ? a(t) : !0));
671
+ }
672
+ var C = class i {
673
+ static init(e = "[data-panel]", t = {}) {
674
+ let n, r;
675
+ return typeof e == "string" ? (n = e, r = t) : (r = e, n = "[data-panel]"), Array.from(document.querySelectorAll(n)).filter((e) => !e.panel).filter((e) => !e.dataset.panel || e.dataset.panel === "data-panel").map((e) => new i(e, r));
676
+ }
677
+ constructor(t, s = {}) {
678
+ this._returnFocusTarget = null, this._tempCloseGroup = null, this._anim = new e(), this._listenerController = new AbortController(), this._activating = !1, this._parsePanelParam = () => {
679
+ let { id: e } = this.element;
680
+ return e ? n().includes(e) : !1;
681
+ }, this._updatePanelParam = (e) => {
682
+ let { id: t } = this.element;
683
+ if (!t) return;
684
+ let i = n();
685
+ r(e ? [...new Set([...i, t])] : i.filter((e) => e !== t));
686
+ }, this._resolveStateConfig = () => {
687
+ let e = (e) => this.element.hasAttribute(e) ? this.element.getAttribute(e) !== "false" : void 0, t = e("data-panel-persist"), n = e("data-panel-deeplink"), r, i, a = this.element.parentElement;
688
+ for (; a && !a.hasAttribute("data-panel");) {
689
+ if (a.hasAttribute("data-panel-group")) {
690
+ a.hasAttribute("data-panel-persist") && (r = a.getAttribute("data-panel-persist") !== "false"), a.hasAttribute("data-panel-deeplink") && (i = a.getAttribute("data-panel-deeplink") !== "false");
691
+ break;
692
+ }
693
+ a = a.parentElement;
694
+ }
695
+ return {
696
+ persist: t ?? r ?? this.config.persist,
697
+ deepLink: n ?? i ?? this.config.deepLink
698
+ };
699
+ }, this._persistState = (e) => {
700
+ if (!this.element.id) return;
701
+ let { persist: t, deepLink: n } = this._resolveStateConfig();
702
+ t && o(`panel:${this.element.id}`, e ? "open" : "closed"), n ? this._updatePanelParam(e) : !e && this._parsePanelParam() && this._updatePanelParam(!1);
703
+ }, this._resolveInitialState = () => {
704
+ let { id: e } = this.element;
705
+ if (!e) return !1;
706
+ if (this._parsePanelParam()) return !0;
707
+ let { persist: t } = this._resolveStateConfig();
708
+ return !!(t && a(`panel:${e}`) === "open");
709
+ }, this._cssProp = () => this.config.axis === "horizontal" ? "width" : "height";
710
+ let l = typeof t == "string" ? document.querySelector(t) : t;
711
+ if (!l) throw Error(`Panel: No element found for selector "${t}"`);
712
+ if (this.element = l, l.panel = this, !l.querySelector(":scope > .panel-wrapper")) {
713
+ let e = document.createElement("div");
714
+ e.className = "panel-wrapper", e.append(...Array.from(l.childNodes)), l.appendChild(e);
715
+ }
716
+ let u = c(l.dataset, i.attrs);
717
+ this.config = {
718
+ ...i.defaults,
719
+ ...s,
720
+ ...u
721
+ }, this.config.axis === "horizontal" && (l.dataset.panelAxis = "horizontal"), this.config.align !== "start" && (l.dataset.panelAlign = this.config.align), this._wireImplicitTriggers(), this._bindTriggers(), this._resolveInitialState() || this.element.classList.contains("is-open") ? (this.element.classList.add("is-open"), this.element.removeAttribute("inert"), this._setTriggerState(!0), this.element.classList.add("is-restored"), requestAnimationFrame(() => requestAnimationFrame(() => this.element.classList.remove("is-restored"))), this._dispatch("panel:opened")) : this.element.setAttribute("inert", ""), i._nativeInterpolateSize && p(this.config.debug), this._log("Initialized");
722
+ }
723
+ _log(e) {
724
+ u("Panel", this.element, this.config.debug, e);
725
+ }
726
+ _wireImplicitTriggers() {
727
+ let e = (e) => e.hasAttribute("data-panel") || !!e.panel, t = (e) => {
728
+ this.element.id || (this.element.id = `panel-${++i._autoIdCounter}`), e.setAttribute("aria-controls", this.element.id), e.hasAttribute("aria-expanded") || e.setAttribute("aria-expanded", "false"), e.removeAttribute("data-panel-trigger");
729
+ }, n = (e) => e.hasAttribute("data-panel-trigger") ? e : /^H[1-6]$/.test(e.tagName) ? e.querySelector(":scope > [data-panel-trigger]") : null;
730
+ for (let r of ["previousElementSibling", "nextElementSibling"]) {
731
+ let i = this.element[r];
732
+ for (; i && !e(i);) {
733
+ let e = n(i);
734
+ if (e) {
735
+ t(e);
736
+ break;
737
+ }
738
+ i = i[r];
739
+ }
740
+ }
741
+ }
742
+ _bindTriggers() {
743
+ let e = this.element.id;
744
+ if (!e) return;
745
+ let { signal: t } = this._listenerController;
746
+ document.querySelectorAll(`[aria-controls="${e}"]`).forEach((e) => {
747
+ e.addEventListener("click", (t) => {
748
+ this._returnFocusTarget = e, this.toggle(t);
749
+ }, { signal: t });
750
+ }), this.element.querySelectorAll("[data-panel-close]").forEach((e) => {
751
+ e.closest("[data-panel]") === this.element && e.addEventListener("click", () => this.close(), { signal: t });
752
+ }), this.config.closeOnResize && window.addEventListener("resize", () => {
753
+ if (!this.isOpen || this.element.classList.contains("is-closing")) return;
754
+ let e = v(this.element);
755
+ e && b(e), this.close();
756
+ }, { signal: t });
757
+ }
758
+ _setTriggerState(e) {
759
+ let t = this.element.id;
760
+ t && document.querySelectorAll(`[aria-controls="${t}"]`).forEach((t) => t.setAttribute("aria-expanded", String(e)));
761
+ }
762
+ _cleanupTempClose() {
763
+ this._tempCloseGroup && (this._tempCloseGroup.style.removeProperty("--ps-tempclose-speed"), this._tempCloseGroup.style.removeProperty("--ps-tempclose-timing"), this._tempCloseGroup = null);
764
+ }
765
+ _closeGroupSiblings() {
766
+ let e = this.element.closest("[data-panel-group]"), t = e?.hasAttribute("data-panel-close-siblings") ?? !1;
767
+ if (!this.config.closeSiblings && !t) return;
768
+ let n = e ? S(this.element, {
769
+ groupSelector: "[data-panel-group]",
770
+ itemSelector: "[data-panel]",
771
+ filter: (e) => !!e.panel?.isOpen
772
+ }) : Array.from(this.element.parentElement?.children ?? []).filter((e) => e instanceof HTMLElement && e !== this.element && !!e.panel?.isOpen);
773
+ n.length && e && (e.style.setProperty("--ps-tempclose-speed", "var(--ps-open-speed)"), e.style.setProperty("--ps-tempclose-timing", "var(--ps-open-timing)"), this._tempCloseGroup = e), n.forEach((e) => {
774
+ e.panel._returnFocusTarget = null, e.panel.close();
775
+ });
776
+ }
777
+ _handleAutoFocus(e) {
778
+ this.config.autoFocus && t(this.element, this.config.autoFocus, e);
779
+ }
780
+ _dispatch(e) {
781
+ (e === "panel:opened" || e === "panel:closed") && (this._activating = !1);
782
+ let t = { trigger: this._returnFocusTarget };
783
+ this.element.dispatchEvent(new CustomEvent(e, {
784
+ detail: t,
785
+ bubbles: !0
786
+ }));
787
+ }
788
+ get isOpen() {
789
+ return this.element.classList.contains("is-open") || this.element.classList.contains("is-opening");
790
+ }
791
+ async open(e) {
792
+ if (this.isOpen && !this.element.classList.contains("is-closing") || this.config.interruptible === !1 && this._activating) return;
793
+ this._activating = !0;
794
+ let t = this._anim.start(), n = this._cssProp(), r = {
795
+ signal: t,
796
+ promise: null,
797
+ waitUntil() {},
798
+ trigger: this._returnFocusTarget
799
+ };
800
+ m(r), this.element.dispatchEvent(new CustomEvent("panel:beforeopen", {
801
+ detail: r,
802
+ bubbles: !0
803
+ })), r.promise ? await this._openAsync(t, n, r.promise, e) : this._openSync(t, n, e);
804
+ }
805
+ async _openAsync(t, n, r, a) {
806
+ let o = await Promise.race([r.then(() => !0), new Promise((e) => {
807
+ let n = setTimeout(() => e(!1), this.config.loadingDelay);
808
+ t.addEventListener("abort", () => clearTimeout(n));
809
+ })]).catch(() => !1);
810
+ if (t.aborted) return;
811
+ if (o) {
812
+ this._openSync(t, n, a);
813
+ return;
814
+ }
815
+ this.element.classList.remove("is-closing"), this.element.removeAttribute("inert"), this.element.classList.add("is-loading"), this.element.querySelector(":scope > .panel-wrapper")?.replaceChildren(), this.element.style.setProperty("--ps-loading-delay", "0ms"), this._setTriggerState(!0), this._persistState(!0), this._dispatch("panel:opening");
816
+ let s = v(this.element);
817
+ s && y(s);
818
+ let c;
819
+ this.config.transitions ? (this.element.classList.add("is-opening"), this.element.style[n] = "0px", getComputedStyle(this.element)[n], requestAnimationFrame(() => {
820
+ this.element.style[n] = `${this.config.loadingHeight}px`;
821
+ }), c = e.waitForTransition(this.element, n)) : this.element.style[n] = `${this.config.loadingHeight}px`;
822
+ try {
823
+ await Promise.all([r, c].filter(Boolean));
824
+ } catch {} finally {
825
+ this.element.classList.remove("is-loading"), this.element.style.removeProperty("--ps-loading-delay");
826
+ }
827
+ if (t.aborted) return;
828
+ let l = this.element.getBoundingClientRect(), u = n === "height" ? l.height : l.width;
829
+ if (this.element.style[n] = "", this.config.transitions) if (i._nativeInterpolateSize) e.waitForTransition(this.element, n).then(() => {
830
+ t.aborted || (this.element.classList.remove("is-opening"), this.element.classList.add("is-open"), this._dispatch("panel:opened"), this._log("Opened"), this._handleAutoFocus(a));
831
+ });
832
+ else {
833
+ this.element.style[n] = "auto";
834
+ let r = this.element.getBoundingClientRect(), i = n === "height" ? r.height : r.width;
835
+ this.element.style[n] = `${u}px`, getComputedStyle(this.element)[n], requestAnimationFrame(() => {
836
+ this.element.style[n] = `${i}px`, e.waitForTransition(this.element, n).then(() => {
837
+ t.aborted || (this.element.style[n] = "", this.element.classList.remove("is-opening"), this.element.classList.add("is-open"), this._dispatch("panel:opened"), this._log("Opened"), this._handleAutoFocus(a));
838
+ });
839
+ });
840
+ }
841
+ else this.element.classList.remove("is-opening"), this.element.classList.add("is-open"), this._dispatch("panel:opened"), this._log("Opened"), this._handleAutoFocus(a);
842
+ }
843
+ _openSync(t, n, r) {
844
+ let a = this.element.classList.contains("is-closing") ? this.element.getBoundingClientRect()[n === "height" ? "height" : "width"] : null;
845
+ this.element.classList.remove("is-closing"), this.element.removeAttribute("inert");
846
+ let o = v(this.element);
847
+ if (this.config.transitions) if (i._nativeInterpolateSize) this.element.classList.add("is-opening"), this.element.style[n] = a === null ? "0px" : `${a}px`, o && y(o), getComputedStyle(this.element)[n], this._setTriggerState(!0), this._persistState(!0), this._closeGroupSiblings(), this._dispatch("panel:opening"), requestAnimationFrame(() => {
848
+ this.element.style[n] = "", e.waitForTransition(this.element, n).then(() => {
849
+ t.aborted || (this.element.classList.remove("is-opening"), this.element.classList.add("is-open"), this._dispatch("panel:opened"), this._cleanupTempClose(), this._log("Opened"), this._handleAutoFocus(r));
850
+ });
851
+ });
852
+ else {
853
+ this._setTriggerState(!0), this._persistState(!0), this._closeGroupSiblings(), this._dispatch("panel:opening"), this.element.style[n] = "auto";
854
+ let i = this.element.getBoundingClientRect(), s = n === "height" ? i.height : i.width;
855
+ this.element.style[n] = a === null ? "0px" : `${a}px`, this.element.classList.add("is-opening"), o && y(o), getComputedStyle(this.element)[n], requestAnimationFrame(() => {
856
+ this.element.style[n] = `${s}px`, e.waitForTransition(this.element, n).then(() => {
857
+ t.aborted || (this.element.style[n] = "", this.element.classList.remove("is-opening"), this.element.classList.add("is-open"), this._dispatch("panel:opened"), this._cleanupTempClose(), this._log("Opened"), this._handleAutoFocus(r));
858
+ });
859
+ });
860
+ }
861
+ else this._setTriggerState(!0), this._persistState(!0), this._closeGroupSiblings(), this._dispatch("panel:opening"), this.element.classList.add("is-open"), this._dispatch("panel:opened"), this._cleanupTempClose(), this._log("Opened"), this._handleAutoFocus(r);
862
+ }
863
+ onBeforeOpen(e, t = {}) {
864
+ h(this.element, "panel:beforeopen", () => this.element, e, t);
865
+ }
866
+ close(t) {
867
+ if (!this.isOpen || this.config.interruptible === !1 && this._activating) return;
868
+ this._activating = !0, this.element.setAttribute("inert", ""), this._setTriggerState(!1);
869
+ let n = this._cssProp(), r = v(this.element), i = this._anim.start();
870
+ this._dispatch("panel:closing");
871
+ let a = () => {
872
+ this.element.classList.remove("is-closing", "is-open", "is-opening"), this.element.style[n] = "", r && b(r), this._persistState(!1), this._dispatch("panel:closed"), this._log("Closed");
873
+ let e = t instanceof PointerEvent && t.pointerType !== "";
874
+ this.config.returnFocus && this._returnFocusTarget && !e && this._returnFocusTarget.focus();
875
+ };
876
+ if (!this.config.transitions) {
877
+ a();
878
+ return;
879
+ }
880
+ let o = this.element.getBoundingClientRect(), s = n === "height" ? o.height : o.width;
881
+ this.element.style[n] = `${s}px`, this.element.classList.remove("is-opening", "is-open"), this.element.classList.add("is-closing"), getComputedStyle(this.element)[n], requestAnimationFrame(() => {
882
+ this.element.style[n] = "0px", e.waitForTransition(this.element, n).then(() => {
883
+ i.aborted || a();
884
+ });
885
+ });
886
+ }
887
+ toggle(e) {
888
+ this.element.classList.contains("is-closing") ? this.open(e) : this.isOpen ? this.close(e) : (e?.target && (this._returnFocusTarget = e.target.closest("button, a") ?? e.target), this.open(e));
889
+ }
890
+ destroy() {
891
+ this._anim.start(), this._listenerController.abort(), this.element.classList.remove("is-opening", "is-closing", "is-loading", "is-open"), this.element.style[this._cssProp()] = "", this.element.setAttribute("inert", ""), this._setTriggerState(!1);
892
+ let e = v(this.element);
893
+ e && b(e), delete this.element.panel, this._log("Destroyed");
894
+ }
895
+ };
896
+ x = C, x.defaults = {
897
+ axis: "vertical",
898
+ align: "start",
899
+ closeOnResize: !1,
900
+ transitions: !0,
901
+ autoFocus: !1,
902
+ returnFocus: !0,
903
+ closeSiblings: !1,
904
+ loadingDelay: 320,
905
+ loadingHeight: 150,
906
+ interruptible: !0,
907
+ persist: !1,
908
+ deepLink: !1,
909
+ debug: !1
910
+ }, x.attrs = {
911
+ axis: ["panelAxis", "string"],
912
+ align: ["panelAlign", "string"],
913
+ autoFocus: ["panelAutoFocus", "string"],
914
+ closeOnResize: ["panelCloseOnResize", "boolean"],
915
+ transitions: ["panelTransitions", "boolean"],
916
+ returnFocus: ["panelReturnFocus", "boolean"],
917
+ closeSiblings: ["panelCloseSiblings", "boolean"],
918
+ loadingDelay: ["panelLoadingDelay", "number"],
919
+ loadingHeight: ["panelLoadingHeight", "number"],
920
+ interruptible: ["panelInterruptible", "boolean"],
921
+ persist: ["panelPersist", "boolean"],
922
+ deepLink: ["panelDeeplink", "boolean"],
923
+ debug: ["debug", "boolean"]
924
+ }, x._nativeInterpolateSize = typeof CSS < "u" && CSS.supports("interpolate-size: allow-keywords"), x._autoIdCounter = 0;
925
+ //#endregion
926
+ //#region src/js/panelcontrol.ts
927
+ var w, T = class e {
928
+ static init(t = "[data-panelcontrol]", n = {}) {
929
+ let r, i;
930
+ return typeof t == "string" ? (r = t, i = n) : (i = t, r = i.selector || "[data-panelcontrol]"), Array.from(document.querySelectorAll(r)).filter((e) => !e.panelControl).map((t) => new e(t, i));
931
+ }
932
+ constructor(t, n = {}) {
933
+ this._setEl = null, this._controller = new AbortController(), this._isTablist = !1, this._activationWired = !1, this._reflectCloseable = () => {
934
+ let e = this.panelSet, t = this.panelSetElement, n = !1;
935
+ if (e) n = !!(e.config.closable && e.config.closeOnTab);
936
+ else if (t) {
937
+ let e = t.dataset.closable != null || t.hasAttribute("closable"), r = t.dataset.closeOnTab != null || t.hasAttribute("close-on-tab");
938
+ n = e && r;
939
+ }
940
+ this.element.toggleAttribute("data-closeable", n);
941
+ }, this._enabled = (e) => e.getAttribute("aria-disabled") !== "true" && !e.hidden, this._onActivation = (e) => {
942
+ let t = this._tabs().find((t) => t.getAttribute("aria-controls") === e.detail?.panelId);
943
+ t && this._setRoving(t);
944
+ }, this._onKeydown = (e) => {
945
+ let t = this._tabs().filter(this._enabled);
946
+ if (!t.length) return;
947
+ let n = this.element.getAttribute("aria-orientation") === "vertical", r = n ? "ArrowDown" : "ArrowRight", i = n ? "ArrowUp" : "ArrowLeft", a = t.indexOf(document.activeElement), o;
948
+ switch (e.key) {
949
+ case r:
950
+ o = t[(a + 1) % t.length];
951
+ break;
952
+ case i:
953
+ o = t[(a - 1 + t.length) % t.length];
954
+ break;
955
+ case "Home":
956
+ o = t[0];
957
+ break;
958
+ case "End":
959
+ o = t[t.length - 1];
960
+ break;
961
+ case "Enter":
962
+ case " ":
963
+ a >= 0 && (e.preventDefault(), this._activate(t[a], e));
964
+ return;
965
+ default: return;
966
+ }
967
+ o && (e.preventDefault(), this._setRoving(o), o.focus(), this._autoActivate() && this._activate(o, e));
968
+ };
969
+ let r = typeof t == "string" ? document.querySelector(t) : t;
970
+ if (!r) throw Error(`PanelControl: No element found for selector "${t}"`);
971
+ if (this.element = r, r.panelControl) return console.warn("PanelControl: already initialized"), r.panelControl;
972
+ r.panelControl = this;
973
+ let i = c(r.dataset, e.attrs);
974
+ this.config = {
975
+ ...e.defaults,
976
+ ...n,
977
+ ...i
978
+ }, this._isTablist = r.getAttribute("role") === "tablist", this._bindTriggers(), this._isTablist && this._setupKeyboard();
979
+ let a = this.panelSetElement;
980
+ this._log(`Initialized (${a ? "linked to a PanelSet" : "no PanelSet found yet"}${this._isTablist ? ", tablist keyboard nav" : ""})`);
981
+ }
982
+ get panelSetElement() {
983
+ if (!this._setEl) {
984
+ let e = this._resolvePanelSet();
985
+ e && (this._setEl = e, this._onElementResolved(e));
986
+ }
987
+ return this._setEl;
988
+ }
989
+ get panelSet() {
990
+ return this.panelSetElement?.panelSet;
991
+ }
992
+ show(e, t) {
993
+ this.panelSet?.show(e, t);
994
+ }
995
+ setTabState(e, t) {
996
+ let n = t === "disabled";
997
+ this.element.querySelectorAll(`[aria-controls="${e}"]`).forEach((e) => {
998
+ e.setAttribute("aria-disabled", String(n));
999
+ let t = e.getAttribute("data-pc-disabled-hint");
1000
+ t && d(e, t, n), this._isTablist && n && (e.tabIndex = -1);
1001
+ }), this._isTablist && n && this._ensureRovingStop();
1002
+ }
1003
+ _log(e) {
1004
+ u("PanelControl", this.element, this.config.debug, e);
1005
+ }
1006
+ _resolvePanelSet() {
1007
+ let e = this.element.getAttribute("data-panelcontrol");
1008
+ if (e) return document.querySelector(e);
1009
+ let t = this.element.querySelector("[aria-controls]")?.getAttribute("aria-controls");
1010
+ return t ? document.getElementById(t)?.closest("[data-panelset], ps-panelset") ?? null : null;
1011
+ }
1012
+ _onElementResolved(e) {
1013
+ let { signal: t } = this._controller;
1014
+ this._isTablist && !this._activationWired && (e.addEventListener("ps:activationcomplete", this._onActivation, { signal: t }), this._activationWired = !0), this._reflectCloseable(), e.panelSet || e.addEventListener("ps:ready", this._reflectCloseable, {
1015
+ once: !0,
1016
+ signal: t
1017
+ });
1018
+ }
1019
+ _bindTriggers() {
1020
+ let { signal: e } = this._controller;
1021
+ this.element.querySelectorAll("[aria-controls]").forEach((t) => {
1022
+ t.addEventListener("click", (e) => {
1023
+ this._activate(t, e);
1024
+ }, { signal: e });
1025
+ });
1026
+ }
1027
+ _activate(e, t) {
1028
+ if (e.getAttribute("aria-disabled") === "true") return;
1029
+ let n = e.getAttribute("aria-controls");
1030
+ if (n) {
1031
+ if (!this.panelSet) {
1032
+ this._log(`Can’t activate '${n}': its PanelSet is not initialised. Add a PanelSet.init().`);
1033
+ return;
1034
+ }
1035
+ this.panelSet.show(n, { event: t }), this._isTablist && this._setRoving(e);
1036
+ }
1037
+ }
1038
+ _tabs() {
1039
+ return Array.from(this.element.querySelectorAll("[role=\"tab\"]"));
1040
+ }
1041
+ _setRoving(e) {
1042
+ this._tabs().forEach((t) => {
1043
+ t.tabIndex = t === e ? 0 : -1;
1044
+ });
1045
+ }
1046
+ _ensureRovingStop() {
1047
+ let e = this._tabs();
1048
+ if (e.some((e) => e.tabIndex === 0 && this._enabled(e))) return;
1049
+ let t = e.find((e) => e.getAttribute("aria-selected") === "true" && this._enabled(e)) ?? e.find(this._enabled);
1050
+ t && this._setRoving(t);
1051
+ }
1052
+ _setupKeyboard() {
1053
+ let e = this._tabs();
1054
+ if (!e.length) return;
1055
+ let t = e.find((e) => e.getAttribute("aria-selected") === "true") ?? e[0];
1056
+ this._setRoving(t), this.element.addEventListener("keydown", this._onKeydown, { signal: this._controller.signal });
1057
+ }
1058
+ _autoActivate() {
1059
+ return this.config.activation === "auto" && !this._autoFocusInPlay() && !this.panelSet?.hasAsyncContent;
1060
+ }
1061
+ _autoFocusInPlay() {
1062
+ let e = this.panelSet;
1063
+ if (e && e.config.autoFocus !== !1) return !0;
1064
+ let t = this.panelSetElement, n = t && (t.dataset.autoFocus ?? t.getAttribute("auto-focus"));
1065
+ return n != null && n !== "false" ? !0 : this._tabs().some((e) => {
1066
+ let t = e.getAttribute("data-auto-focus");
1067
+ return t != null && t !== "false";
1068
+ });
1069
+ }
1070
+ destroy() {
1071
+ this._controller.abort(), delete this.element.panelControl, this._log("Destroyed");
1072
+ }
1073
+ };
1074
+ w = T, w.defaults = {
1075
+ activation: "manual",
1076
+ debug: !1
1077
+ }, w.attrs = {
1078
+ activation: ["activation", "string"],
1079
+ debug: ["debug", "boolean"]
1080
+ };
1081
+ //#endregion
1082
+ //#region src/js/panel.element.ts
1083
+ var E = class extends HTMLElement {
1084
+ connectedCallback() {
1085
+ if (this.panel) return;
1086
+ let e = l(this, C.attrs);
1087
+ new C(this, e);
1088
+ }
1089
+ disconnectedCallback() {}
1090
+ }, D = class extends HTMLElement {
1091
+ connectedCallback() {
1092
+ if (this.panelSet) return;
1093
+ let e = l(this, _.attrs);
1094
+ new _(this, e);
1095
+ }
1096
+ disconnectedCallback() {}
1097
+ }, O = class extends HTMLElement {
1098
+ connectedCallback() {
1099
+ if (this.panelControl) return;
1100
+ let e = l(this, T.attrs);
1101
+ new T(this, e);
1102
+ }
1103
+ disconnectedCallback() {}
1104
+ };
1105
+ function k(e = "ps") {
1106
+ let t = `${e}-panelcontrol`;
1107
+ customElements.get(t) || customElements.define(t, O);
1108
+ }
1109
+ //#endregion
1110
+ //#region src/js/index.ts
1111
+ function A(e = "ps") {
1112
+ let t = (e, t) => {
1113
+ customElements.get(e) || customElements.define(e, t);
1114
+ };
1115
+ t(`${e}-panel`, E), t(`${e}-panelset`, D), t(`${e}-panelcontrol`, O);
1116
+ }
1117
+ //#endregion
1118
+ export { E as a, _ as c, D as i, O as n, T as o, k as r, C as s, A as t };
1119
+
1120
+ //# sourceMappingURL=panelset-core.js.map