@nysds/nys-tab 1.18.0 → 1.18.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nys-tab.js +97 -81
- package/dist/nys-tab.js.map +1 -1
- package/dist/nys-tabgroup.d.ts +6 -3
- package/package.json +2 -2
package/dist/nys-tab.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { LitElement as
|
|
2
|
-
import { property as
|
|
1
|
+
import { LitElement as f, unsafeCSS as g, html as m } from "lit";
|
|
2
|
+
import { property as h } from "lit/decorators.js";
|
|
3
3
|
/*!
|
|
4
4
|
* █▄ █ █ █ █▀▀▀█ █▀▀▄ █▀▀▀█
|
|
5
5
|
* █ █ █ █▄▄▄█ ▀▀▀▄▄ █ █ ▀▀▀▄▄
|
|
@@ -10,14 +10,14 @@ import { property as c } from "lit/decorators.js";
|
|
|
10
10
|
* Repository: https://github.com/its-hcd/nysds
|
|
11
11
|
* License: MIT
|
|
12
12
|
*/
|
|
13
|
-
const
|
|
14
|
-
var
|
|
13
|
+
const w = ':host{--_nys-tabgroup-gap: var(--nys-space-100, 8px);--_nys-tabgroup-padding: var(--nys-space-50, 4px);--_nys-tabgroup-background-color: var(--nys-color-surface, #ffffff);--_nys-tab-border-width: 3px;--_nys-tab-border-radius: var(--nys-radius-md, 4px);--_nys-tab-border-color: var(--nys-color-neutral-50);--_nys-tab-border-color--hover: var(--nys-color-theme-weak, #cddde9);--_nys-tab-border-color--active: var(--nys-color-theme-mid, #457aa5);--_nys-tab-border-color--disabled: var(--_nys-tab-border-color);--_nys-tab-border-color--selected: var(--nys-color-theme, #154973);--_nys-tab-border-color--selected--hover: var( --nys-color-theme-strong, #0e324f );--_nys-tab-border-color--selected--active: var( --nys-color-theme-stronger, #081b2b );--_nys-tab-background-color: var(--nys-color-surface, #ffffff);--_nys-tab-background-color--hover: var(--nys-color-theme-weaker, #eff6fb);--_nys-tab-background-color--active: var(--nys-color-theme-weak, #cddde9);--_nys-tab-background-color--disabled: var(--_nys-tab-background-color);--_nys-tab-background-color--selected: var(--nys-color-neutral-10, #f6f6f6);--_nys-tab-color: var(--nys-color-text-weak, #4A4D4F);--_nys-tab-color--selected: var(--nys-color-text, #1B1B1B);--_nys-tab-color--disabled: var(--nys-color-text-disabled, #bec0c1);--_nys-tab-padding--x: var(--nys-space-150, 12px);--_nys-tab-padding--y: var(--nys-space-200, 16px);--_nys-tabpanel-padding: var(--nys-space-400, 32px);--_nys-tabpanel-max-height: var(--nys-tabpanel-max-height)}.nys-tab{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;cursor:pointer;appearance:none;-webkit-appearance:none;padding:var(--_nys-tab-padding--y) var(--_nys-tab-padding--x);border-color:var(--_nys-tab-border-color);border-style:none none solid;border-width:var(--_nys-tab-border-width);border-radius:var(--_nys-tab-border-radius) var(--_nys-tab-border-radius) 0 0;background-color:var(--_nys-tab-background-color);color:var(--_nys-tab-color);font-family:var(--nys-font-family-ui, var(--nys-font-family-sans, "Proxima Nova", "Helvetica Neue", "Helvetica", "Arial", sans-serif));font-size:var(--nys-font-size-ui-md, 16px);font-weight:var(--nys-font-weight-semibold, 600);line-height:var(--nys-size-200, 16px);text-decoration:none}:host(:not([disabled])) .nys-tab:hover{background-color:var(--_nys-tab-background-color--hover);border-color:var(--_nys-tab-border-color--hover);color:var(--_nys-tab-color)}:host(:not([disabled])) .nys-tab:active{background-color:var(--_nys-tab-background-color--active);border-color:var(--_nys-tab-border-color--active);color:var(--_nys-tab-color)}:host([disabled]) .nys-tab{background-color:var(--_nys-tab-background-color--disabled);border-color:var(--_nys-tab-border-color--disabled);color:var(--_nys-tab-color--disabled);cursor:not-allowed;pointer-events:auto}:host(:focus-visible){outline:none}:host(:focus-visible) .nys-tab{outline:solid var(--nys-border-width-md, 2px) var(--nys-color-focus, #004dd1);outline-offset:var(--nys-space-2px, 2px)}:host([selected]) .nys-tab{background-color:var(--_nys-tab-background-color--selected);border-color:var(--_nys-tab-border-color--selected);color:var(--_nys-tab-color--selected)}:host([selected]:not([disabled])) .nys-tab:hover{border-color:var(--_nys-tab-border-color--selected--hover)}:host([selected]:not([disabled])) .nys-tab:active{border-color:var(--_nys-tab-border-color--selected--active)}.nys-tabgroup{background-color:var(--_nys-tabgroup-background-color)}.nys-tabgroup__tabs-container{position:relative}.nys-tabgroup__tabs-container .scroll-shadow{position:absolute;top:50%;transform:translateY(-50%);z-index:2;opacity:0;pointer-events:none;transition:opacity .2s;height:calc(var(--nys-space-600, 48px) + var(--_nys-tab-border-width));width:var(--nys-space-200, 16px)}.nys-tabgroup__tabs-container .scroll-shadow--left{left:0;background-image:linear-gradient(to left,transparent,var(--nys-color-neutral-100, #D0D0CE))}.nys-tabgroup__tabs-container .scroll-shadow--right{right:0;background-image:linear-gradient(to right,transparent,var(--nys-color-neutral-100, #D0D0CE))}.nys-tabgroup__tabs-container .scroll-shadow.is-visible{opacity:1}.nys-tabgroup__tabs-container .nys-tabgroup__tabs-background{position:absolute;inset:0;margin:var(--_nys-tabgroup-padding);border-bottom:solid var(--_nys-tab-border-color) var(--_nys-tab-border-width)}.nys-tabgroup__tabs-container .nys-tabgroup__tabs{position:relative;display:flex;gap:var(--_nys-tabgroup-gap);overflow-x:auto;white-space:nowrap;-ms-overflow-style:none;scrollbar-width:none;padding:var(--_nys-tabgroup-padding)}.nys-tabgroup__tabs-container .nys-tabgroup__tabs::-webkit-scrollbar{display:none}.nys-tabgroup__panels{padding:var(--_nys-tabpanel-padding);background-color:var(--_nys-tabpanel-background-color);max-height:var(--_nys-tabpanel-max-height);overflow-y:auto}';
|
|
14
|
+
var $ = Object.defineProperty, v = (i, t, r, n) => {
|
|
15
15
|
for (var e = void 0, s = i.length - 1, o; s >= 0; s--)
|
|
16
16
|
(o = i[s]) && (e = o(t, r, e) || e);
|
|
17
|
-
return e &&
|
|
17
|
+
return e && $(t, r, e), e;
|
|
18
18
|
};
|
|
19
|
-
let
|
|
20
|
-
const
|
|
19
|
+
let R = 0;
|
|
20
|
+
const k = class k extends f {
|
|
21
21
|
constructor() {
|
|
22
22
|
super(...arguments), this.id = "", this.label = "", this.selected = !1, this.disabled = !1, this._onKeydown = (t) => {
|
|
23
23
|
this.disabled || t.key !== "Enter" && t.key !== " " || (t.preventDefault(), this._handleClick());
|
|
@@ -58,7 +58,7 @@ const g = class g extends p {
|
|
|
58
58
|
* `<nys-tabgroup>` overrides `tabindex` to `"0"` on the selected tab.
|
|
59
59
|
*/
|
|
60
60
|
connectedCallback() {
|
|
61
|
-
super.connectedCallback(), this.id || (this.id = `nys-tab-${Date.now()}-${
|
|
61
|
+
super.connectedCallback(), this.id || (this.id = `nys-tab-${Date.now()}-${R++}`), this.setAttribute("role", "tab"), this.setAttribute("tabindex", "-1"), this.addEventListener("keydown", this._onKeydown), this.addEventListener("focus", this._onFocus), this.addEventListener("blur", this._onBlur), this.addEventListener("click", this._onClick);
|
|
62
62
|
}
|
|
63
63
|
disconnectedCallback() {
|
|
64
64
|
super.disconnectedCallback(), this.removeEventListener("keydown", this._onKeydown), this.removeEventListener("focus", this._onFocus), this.removeEventListener("blur", this._onBlur), this.removeEventListener("click", this._onClick);
|
|
@@ -97,34 +97,34 @@ const g = class g extends p {
|
|
|
97
97
|
// Render
|
|
98
98
|
// ---------------------------------------------------------------------------
|
|
99
99
|
render() {
|
|
100
|
-
return
|
|
100
|
+
return m`<span class="nys-tab">${this.label}</span>`;
|
|
101
101
|
}
|
|
102
102
|
};
|
|
103
|
-
|
|
104
|
-
let
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
],
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
],
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
],
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
],
|
|
117
|
-
customElements.get("nys-tab") || customElements.define("nys-tab",
|
|
118
|
-
var
|
|
103
|
+
k.styles = g(w);
|
|
104
|
+
let b = k;
|
|
105
|
+
v([
|
|
106
|
+
h({ type: String, reflect: !0 })
|
|
107
|
+
], b.prototype, "id");
|
|
108
|
+
v([
|
|
109
|
+
h({ type: String })
|
|
110
|
+
], b.prototype, "label");
|
|
111
|
+
v([
|
|
112
|
+
h({ type: Boolean, reflect: !0 })
|
|
113
|
+
], b.prototype, "selected");
|
|
114
|
+
v([
|
|
115
|
+
h({ type: Boolean, reflect: !0 })
|
|
116
|
+
], b.prototype, "disabled");
|
|
117
|
+
customElements.get("nys-tab") || customElements.define("nys-tab", b);
|
|
118
|
+
var P = Object.defineProperty, L = (i, t, r, n) => {
|
|
119
119
|
for (var e = void 0, s = i.length - 1, o; s >= 0; s--)
|
|
120
120
|
(o = i[s]) && (e = o(t, r, e) || e);
|
|
121
|
-
return e &&
|
|
121
|
+
return e && P(t, r, e), e;
|
|
122
122
|
};
|
|
123
|
-
let
|
|
124
|
-
const
|
|
123
|
+
let z = 0;
|
|
124
|
+
const x = class x extends f {
|
|
125
125
|
constructor() {
|
|
126
126
|
super(...arguments), this.id = "", this.name = "", this._updateScrollShadows = () => {
|
|
127
|
-
const { scrollLeft: t, scrollWidth: r, clientWidth:
|
|
127
|
+
const { scrollLeft: t, scrollWidth: r, clientWidth: n } = this._tabsEl, e = t > 0, s = t + n < r;
|
|
128
128
|
this._shadowLeft.classList.toggle("is-visible", e), this._shadowRight.classList.toggle("is-visible", s);
|
|
129
129
|
}, this._handleWheel = (t) => {
|
|
130
130
|
t.deltaY !== 0 && (t.preventDefault(), this._tabsEl.scrollLeft += t.deltaY);
|
|
@@ -138,7 +138,7 @@ const m = class m extends p {
|
|
|
138
138
|
* Auto-generates a unique `id` if one was not provided.
|
|
139
139
|
*/
|
|
140
140
|
connectedCallback() {
|
|
141
|
-
super.connectedCallback(), this.id || (this.id = `nys-tabgroup-${Date.now()}-${
|
|
141
|
+
super.connectedCallback(), this.id || (this.id = `nys-tabgroup-${Date.now()}-${z++}`);
|
|
142
142
|
}
|
|
143
143
|
/**
|
|
144
144
|
* Called after the element's shadow DOM has been rendered for the first time.
|
|
@@ -157,6 +157,9 @@ const m = class m extends p {
|
|
|
157
157
|
() => this._updateScrollShadows()
|
|
158
158
|
), this._resizeObserver.observe(this._tabsEl);
|
|
159
159
|
}
|
|
160
|
+
disconnectedCallback() {
|
|
161
|
+
super.disconnectedCallback(), this._tabsEl?.removeEventListener("scroll", this._updateScrollShadows), this._tabsEl?.removeEventListener("wheel", this._handleWheel), this._resizeObserver?.disconnect(), this._resizeObserver = void 0;
|
|
162
|
+
}
|
|
160
163
|
/**
|
|
161
164
|
* Returns all `<nys-tab>` elements currently residing in the shadow-DOM
|
|
162
165
|
* tabs container, in DOM order.
|
|
@@ -197,13 +200,13 @@ const m = class m extends p {
|
|
|
197
200
|
* @param selectedIndex - Zero-based index of the tab/panel pair to activate.
|
|
198
201
|
* @returns void
|
|
199
202
|
*/
|
|
200
|
-
_applySelection(t, r,
|
|
203
|
+
_applySelection(t, r, n) {
|
|
201
204
|
t.forEach((e, s) => {
|
|
202
|
-
const o = s ===
|
|
203
|
-
e.setAttribute("aria-selected", o ? "true" : "false"), e.setAttribute("tabindex", o ? "0" : "-1"),
|
|
205
|
+
const o = s === n, a = r[s];
|
|
206
|
+
e.setAttribute("aria-selected", o ? "true" : "false"), e.setAttribute("tabindex", o ? "0" : "-1"), a?.id && e.setAttribute("aria-controls", a.id), o ? e.setAttribute("selected", "") : e.removeAttribute("selected");
|
|
204
207
|
}), r.forEach((e, s) => {
|
|
205
|
-
const o = s ===
|
|
206
|
-
|
|
208
|
+
const o = s === n, a = t[s];
|
|
209
|
+
a && e.setAttribute("aria-labelledby", a.id), o ? e.removeAttribute("hidden") : e.setAttribute("hidden", "");
|
|
207
210
|
});
|
|
208
211
|
}
|
|
209
212
|
// ---------------------------------------------------------------------------
|
|
@@ -214,27 +217,40 @@ const m = class m extends p {
|
|
|
214
217
|
*
|
|
215
218
|
* Iterates over all assigned elements and moves each `<nys-tab>` into
|
|
216
219
|
* `.nys-tabgroup__tabs` and each `<nys-tabpanel>` into
|
|
217
|
-
* `.nys-tabgroup__panels
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
+
* `.nys-tabgroup__panels`. If a panel has an `aria-labelledby` attribute,
|
|
221
|
+
* it is explicitly paired with the tab it references; otherwise panels are
|
|
222
|
+
* paired with tabs by index order. After sorting, calls `_applySelection`
|
|
223
|
+
* using the first element that already has a `selected` attribute, or
|
|
224
|
+
* index `0` if none is found.
|
|
220
225
|
*
|
|
221
226
|
* @param e - The `Event` fired by the `<slot>` element on slot change.
|
|
222
227
|
* @returns void
|
|
223
228
|
*/
|
|
224
229
|
_sortChildren(t) {
|
|
225
|
-
const
|
|
230
|
+
const n = t.target.assignedElements(), e = this.shadowRoot?.querySelector(".nys-tabgroup__tabs"), s = this.shadowRoot?.querySelector(
|
|
226
231
|
".nys-tabgroup__panels"
|
|
227
232
|
);
|
|
228
233
|
if (!e || !s) return;
|
|
229
|
-
const o = [],
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
234
|
+
const o = [], a = /* @__PURE__ */ new Map(), d = [];
|
|
235
|
+
n.forEach((l) => {
|
|
236
|
+
const c = l.tagName.toLowerCase();
|
|
237
|
+
if (c === "nys-tab")
|
|
238
|
+
e.appendChild(l), o.push(l);
|
|
239
|
+
else if (c === "nys-tabpanel") {
|
|
240
|
+
s.appendChild(l);
|
|
241
|
+
const _ = l, S = _.getAttribute("aria-labelledby");
|
|
242
|
+
S ? a.set(S, _) : d.push(_);
|
|
243
|
+
}
|
|
233
244
|
});
|
|
234
|
-
const
|
|
245
|
+
const u = [];
|
|
246
|
+
o.forEach((l) => {
|
|
247
|
+
const c = l.id;
|
|
248
|
+
c && a.has(c) ? (u.push(a.get(c)), a.delete(c)) : d.length > 0 && u.push(d.shift());
|
|
249
|
+
}), a.forEach((l) => u.push(l)), u.forEach((l) => s.appendChild(l));
|
|
250
|
+
const C = o.findIndex(
|
|
235
251
|
(l) => l.hasAttribute("selected")
|
|
236
|
-
),
|
|
237
|
-
this._applySelection(o,
|
|
252
|
+
), A = C !== -1 ? C : 0;
|
|
253
|
+
this._applySelection(o, u, A);
|
|
238
254
|
}
|
|
239
255
|
/**
|
|
240
256
|
* Handles the `nys-tab-select` custom event bubbled up from a child
|
|
@@ -252,8 +268,8 @@ const m = class m extends p {
|
|
|
252
268
|
(o) => o.tagName?.toLowerCase() === "nys-tab"
|
|
253
269
|
);
|
|
254
270
|
if (!r) return;
|
|
255
|
-
const
|
|
256
|
-
s !== -1 && this._applySelection(
|
|
271
|
+
const n = this._getTabs(), e = this._getPanels(), s = n.indexOf(r);
|
|
272
|
+
s !== -1 && this._applySelection(n, e, s);
|
|
257
273
|
}
|
|
258
274
|
/**
|
|
259
275
|
* Implements the ARIA radio-button keyboard pattern:
|
|
@@ -274,31 +290,31 @@ const m = class m extends p {
|
|
|
274
290
|
* @returns void
|
|
275
291
|
*/
|
|
276
292
|
_handleKeydown(t) {
|
|
277
|
-
const r = this._getTabs().filter((
|
|
293
|
+
const r = this._getTabs().filter((d) => !d.hasAttribute("disabled"));
|
|
278
294
|
if (r.length === 0) return;
|
|
279
|
-
const
|
|
280
|
-
(
|
|
281
|
-
), e =
|
|
295
|
+
const n = t.composedPath().find(
|
|
296
|
+
(d) => d.tagName?.toLowerCase() === "nys-tab"
|
|
297
|
+
), e = n ? r.indexOf(n) : -1;
|
|
282
298
|
if (e === -1) return;
|
|
283
299
|
const s = "ArrowLeft", o = "ArrowRight";
|
|
284
|
-
let
|
|
300
|
+
let a = e;
|
|
285
301
|
switch (t.key) {
|
|
286
302
|
case s:
|
|
287
|
-
|
|
303
|
+
a = (e - 1 + r.length) % r.length;
|
|
288
304
|
break;
|
|
289
305
|
case o:
|
|
290
|
-
|
|
306
|
+
a = (e + 1) % r.length;
|
|
291
307
|
break;
|
|
292
308
|
default:
|
|
293
309
|
return;
|
|
294
310
|
}
|
|
295
|
-
|
|
311
|
+
a !== e && r[a].focus?.();
|
|
296
312
|
}
|
|
297
313
|
// ---------------------------------------------------------------------------
|
|
298
314
|
// Render
|
|
299
315
|
// ---------------------------------------------------------------------------
|
|
300
316
|
render() {
|
|
301
|
-
return
|
|
317
|
+
return m`
|
|
302
318
|
<div class="nys-tabgroup" @nys-tab-select=${this._handleTabSelect}>
|
|
303
319
|
<div class="nys-tabgroup__tabs-container">
|
|
304
320
|
<div class="nys-tabgroup__tabs-background"></div>
|
|
@@ -317,22 +333,22 @@ const m = class m extends p {
|
|
|
317
333
|
`;
|
|
318
334
|
}
|
|
319
335
|
};
|
|
320
|
-
|
|
321
|
-
let
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
],
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
],
|
|
328
|
-
customElements.get("nys-tabgroup") || customElements.define("nys-tabgroup",
|
|
329
|
-
var
|
|
336
|
+
x.styles = g(w);
|
|
337
|
+
let y = x;
|
|
338
|
+
L([
|
|
339
|
+
h({ type: String, reflect: !0 })
|
|
340
|
+
], y.prototype, "id");
|
|
341
|
+
L([
|
|
342
|
+
h({ type: String })
|
|
343
|
+
], y.prototype, "name");
|
|
344
|
+
customElements.get("nys-tabgroup") || customElements.define("nys-tabgroup", y);
|
|
345
|
+
var B = Object.defineProperty, D = (i, t, r, n) => {
|
|
330
346
|
for (var e = void 0, s = i.length - 1, o; s >= 0; s--)
|
|
331
347
|
(o = i[s]) && (e = o(t, r, e) || e);
|
|
332
|
-
return e &&
|
|
348
|
+
return e && B(t, r, e), e;
|
|
333
349
|
};
|
|
334
|
-
let
|
|
335
|
-
const
|
|
350
|
+
let O = 0;
|
|
351
|
+
const E = class E extends f {
|
|
336
352
|
constructor() {
|
|
337
353
|
super(...arguments), this.id = "";
|
|
338
354
|
}
|
|
@@ -340,28 +356,28 @@ const w = class w extends p {
|
|
|
340
356
|
// Lifecycle
|
|
341
357
|
// ---------------------------------------------------------------------------
|
|
342
358
|
connectedCallback() {
|
|
343
|
-
super.connectedCallback(), this.id || (this.id = `nys-tabpanel-${Date.now()}-${
|
|
359
|
+
super.connectedCallback(), this.id || (this.id = `nys-tabpanel-${Date.now()}-${O++}`), this.setAttribute("role", "tabpanel");
|
|
344
360
|
}
|
|
345
361
|
// ---------------------------------------------------------------------------
|
|
346
362
|
// Render
|
|
347
363
|
// ---------------------------------------------------------------------------
|
|
348
364
|
render() {
|
|
349
|
-
return
|
|
365
|
+
return m`
|
|
350
366
|
<div class="nys-tabpanel" tabindex="0">
|
|
351
367
|
<slot></slot>
|
|
352
368
|
</div>
|
|
353
369
|
`;
|
|
354
370
|
}
|
|
355
371
|
};
|
|
356
|
-
|
|
357
|
-
let
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
],
|
|
361
|
-
customElements.get("nys-tabpanel") || customElements.define("nys-tabpanel",
|
|
372
|
+
E.styles = g(w);
|
|
373
|
+
let p = E;
|
|
374
|
+
D([
|
|
375
|
+
h({ type: String, reflect: !0 })
|
|
376
|
+
], p.prototype, "id");
|
|
377
|
+
customElements.get("nys-tabpanel") || customElements.define("nys-tabpanel", p);
|
|
362
378
|
export {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
379
|
+
b as NysTab,
|
|
380
|
+
y as NysTabgroup,
|
|
381
|
+
p as NysTabpanel
|
|
366
382
|
};
|
|
367
383
|
//# sourceMappingURL=nys-tab.js.map
|
package/dist/nys-tab.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nys-tab.js","sources":["../src/nys-tab.ts","../src/nys-tabgroup.ts","../src/nys-tabpanel.ts"],"sourcesContent":["import { LitElement, html, unsafeCSS } from \"lit\";\nimport { property } from \"lit/decorators.js\";\n// @ts-ignore: SCSS module imported via bundler as inline\nimport styles from \"./nys-tab.scss?inline\";\n\n/** @internal Monotonically increasing counter used to generate unique element IDs. */\nlet componentIdCounter = 0;\n\n/**\n * `<nys-tab>` is a single tab within a `<nys-tabgroup>`.\n *\n * The host element carries `role=\"tab\"`, `tabindex`, `aria-selected`,\n * `aria-controls`, and `aria-disabled` so assistive technologies see the\n * correct ARIA tab semantics on the element that is actually focused.\n * `<nys-tabgroup>` manages `tabindex`, `aria-selected`, and `aria-controls`\n * via `_applySelection`; do not set them directly on this element.\n *\n * @element nys-tab\n *\n * @fires nys-tab-select - Dispatched when the tab is activated via click or\n * Enter / Space. Bubbles and crosses shadow DOM boundaries.\n * `detail: { id: string, label: string }`\n * @fires nys-tab-focus - Dispatched when the host receives focus. Bubbles and\n * crosses shadow DOM boundaries. `detail: { id: string }`\n * @fires nys-tab-blur - Dispatched when the host loses focus. Bubbles and\n * crosses shadow DOM boundaries. `detail: { id: string }`\n *\n * @slot - No slots; content is derived from the `label` property.\n *\n * @example `<nys-tab>` and `<nys-tabpanel>` should always be wrapped by `<nys-tabgroup>`\n * ```html\n * <!-- Always place <nys-tab> elements inside a <nys-tabgroup>. -->\n * <nys-tabgroup name=\"My Tabs\">\n * <nys-tab label=\"Overview\"></nys-tab>\n * <nys-tab label=\"Details\" selected></nys-tab>\n * <nys-tab label=\"Archived\" disabled></nys-tab>\n * <nys-tabpanel><p>Overview content</p></nys-tabpanel>\n * <nys-tabpanel><p>Details content (shown by default)</p></nys-tabpanel>\n * <nys-tabpanel><p>Archived content</p></nys-tabpanel>\n * </nys-tabgroup>\n * ```\n */\nexport class NysTab extends LitElement {\n static styles = unsafeCSS(styles);\n\n /**\n * Unique identifier for the tab element.\n * Reflected to the DOM attribute so `aria-controls` references resolve.\n *\n * @attr id\n */\n @property({ type: String, reflect: true }) id = \"\";\n\n /**\n * Visible text label rendered inside the inner `<span>`.\n *\n * @attr label\n */\n @property({ type: String }) label = \"\";\n\n /**\n * Whether this tab is the currently active tab.\n * Managed by `<nys-tabgroup>`; reflected for CSS attribute selectors.\n *\n * @attr selected\n */\n @property({ type: Boolean, reflect: true }) selected = false;\n\n /**\n * Whether this tab is disabled.\n * Reflected to the DOM attribute for CSS styling.\n *\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true }) disabled = false;\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Sets `role=\"tab\"` and `tabindex=\"-1\"` on the host (the element that AT\n * will read and that receives keyboard focus). Attaches host-level listeners\n * for keydown, focus, blur, and click so that interaction events work\n * correctly on the host element itself.\n *\n * Click is handled at the host level so iOS VoiceOver double-tap (which\n * dispatches `click` directly on the host because of `role=\"tab\"`, bypassing\n * shadow-DOM children) activates the tab. Normal taps land on the inner\n * `<span>` and bubble up to this listener.\n *\n * `<nys-tabgroup>` overrides `tabindex` to `\"0\"` on the selected tab.\n */\n connectedCallback() {\n super.connectedCallback();\n if (!this.id) {\n this.id = `nys-tab-${Date.now()}-${componentIdCounter++}`;\n }\n this.setAttribute(\"role\", \"tab\");\n this.setAttribute(\"tabindex\", \"-1\");\n this.addEventListener(\"keydown\", this._onKeydown);\n this.addEventListener(\"focus\", this._onFocus);\n this.addEventListener(\"blur\", this._onBlur);\n this.addEventListener(\"click\", this._onClick);\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener(\"keydown\", this._onKeydown);\n this.removeEventListener(\"focus\", this._onFocus);\n this.removeEventListener(\"blur\", this._onBlur);\n this.removeEventListener(\"click\", this._onClick);\n }\n\n /**\n * Keeps `aria-disabled` on the host in sync with the `disabled` property so\n * AT perceives the disabled state on the element it actually focuses.\n */\n updated(changed: Map<string, unknown>) {\n if (changed.has(\"disabled\")) {\n if (this.disabled) {\n this.setAttribute(\"aria-disabled\", \"true\");\n } else {\n this.removeAttribute(\"aria-disabled\");\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------------------\n\n /**\n * Focuses the host element. The host carries `role=\"tab\"` and `tabindex`,\n * so it is the correct element for AT to land on.\n */\n public focus(options?: FocusOptions): void {\n super.focus(options);\n }\n\n // ---------------------------------------------------------------------------\n // Event Handlers\n // ---------------------------------------------------------------------------\n\n /**\n * Enter / Space on the focused host activate the tab.\n * Arrow-key navigation is handled one level up by `<nys-tabgroup>`.\n */\n private _onKeydown = (e: KeyboardEvent): void => {\n if (this.disabled) return;\n if (e.key !== \"Enter\" && e.key !== \" \") return;\n e.preventDefault();\n this._handleClick();\n };\n\n /**\n * Host focus → dispatch `nys-tab-focus` for external observers.\n */\n private _onFocus = (): void => {\n this.dispatchEvent(\n new CustomEvent(\"nys-tab-focus\", {\n bubbles: true,\n composed: true,\n detail: { id: this.id },\n }),\n );\n };\n\n /**\n * Host blur → dispatch `nys-tab-blur` for external observers.\n */\n private _onBlur = (): void => {\n this.dispatchEvent(\n new CustomEvent(\"nys-tab-blur\", {\n bubbles: true,\n composed: true,\n detail: { id: this.id },\n }),\n );\n };\n\n /**\n * Host-level click handler. Activates the tab regardless of whether the\n * click landed on the inner element (normal pointer/keyboard tap, which\n * bubbles up) or directly on the host (iOS VoiceOver double-tap dispatches\n * `click` on the element with `role=\"tab\"`, bypassing shadow-DOM children).\n */\n private _onClick = (): void => {\n this._handleClick();\n };\n\n /**\n * Focuses the host then dispatches `nys-tab-select`. Called from both the\n * click handler and the keydown handler.\n */\n private _handleClick(): void {\n if (this.disabled) return;\n this.focus();\n this.dispatchEvent(\n new CustomEvent(\"nys-tab-select\", {\n bubbles: true,\n composed: true,\n detail: { id: this.id, label: this.label },\n }),\n );\n }\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n\n render() {\n // Inner element is a non-interactive `<span>` (not `<button>`) so that\n // axe-core's `nested-interactive` rule does not fire — the host already\n // carries `role=\"tab\"` + `tabindex` and is the interactive control.\n // Disabled gating, click activation, and keyboard activation all happen\n // on the host; the span is purely a styling/labeling target.\n return html`<span class=\"nys-tab\">${this.label}</span>`;\n }\n}\n\nif (!customElements.get(\"nys-tab\")) {\n customElements.define(\"nys-tab\", NysTab);\n}\n","import { LitElement, html, unsafeCSS } from \"lit\";\nimport { property } from \"lit/decorators.js\";\n// @ts-ignore: SCSS module imported via bundler as inline\nimport styles from \"./nys-tab.scss?inline\";\n\n/** @internal Monotonically increasing counter used to generate unique element IDs. */\nlet componentIdCounter = 0;\n\n/**\n * `<nys-tabgroup>` is the container for `<nys-tab>` and `<nys-tabpanel>`\n * elements.\n *\n * Accepts tabs and panels as flat light-DOM children in any order (interleaved\n * or grouped). On slot change, children are sorted into dedicated shadow-DOM\n * containers, ARIA relationships are wired, and the first selected (or first)\n * tab is activated.\n *\n * Scroll shadows are rendered on either side of the tab list and toggled via\n * `ResizeObserver` and a `scroll` listener so they accurately reflect whether\n * overflow content exists in each direction.\n *\n * Keyboard navigation follows the\n * {@link https://www.w3.org/WAI/ARIA/apg/patterns/tabs/ ARIA Tabs Pattern}:\n * - Arrow keys move focus without changing selection.\n * - Enter / Space confirm selection on the focused tab.\n *\n * @element nys-tabgroup\n *\n * @slot - Accepts `<nys-tab>` and `<nys-tabpanel>` children. Elements are\n * moved into internal shadow-DOM containers on `slotchange`; the slot\n * itself is not rendered visibly.\n *\n * @example Disable a tab using the `disabled` attribute on `<nys-tab>`.\n * ```html\n * <nys-tabgroup name=\"Account Settings\">\n * <nys-tab label=\"Profile\"></nys-tab>\n * <nys-tab label=\"Security\"></nys-tab>\n * <nys-tab label=\"Notifications\" disabled></nys-tab>\n * <nys-tabpanel><p>Manage your profile information.</p></nys-tabpanel>\n * <nys-tabpanel><p>Update your password and 2FA settings.</p></nys-tabpanel>\n * <nys-tabpanel><p>Notification preferences (coming soon).</p></nys-tabpanel>\n * </nys-tabgroup>\n * ```\n *\n * @example Pre-select a tab using the `selected` attribute on `<nys-tab>`.\n * ```html\n * <nys-tabgroup name=\"Reports\">\n * <nys-tab label=\"Summary\"></nys-tab>\n * <nys-tab label=\"Details\" selected></nys-tab>\n * <nys-tabpanel><p>Summary view</p></nys-tabpanel>\n * <nys-tabpanel><p>Detailed view (shown by default)</p></nys-tabpanel>\n * </nys-tabgroup>\n * ```\n */\nexport class NysTabgroup extends LitElement {\n static styles = unsafeCSS(styles);\n\n /**\n * Unique identifier for the tabgroup element.\n * If not provided, one is auto-generated in `connectedCallback`.\n * Reflected to the DOM attribute.\n *\n * @attr id\n */\n @property({ type: String, reflect: true }) id = \"\";\n\n /**\n * The name of the tab group.\n * Used for form submission and accessibility purposes.\n *\n * @attr name\n */\n @property({ type: String }) name = \"\";\n\n /**\n * Cached in `firstUpdated` and used by `_updateScrollShadows` to read\n * scroll position and dimensions.\n */\n private _tabsEl!: HTMLElement;\n\n /**\n * Reference to the left scroll-shadow overlay element.\n * Receives the `is-visible` class when the tab list is scrolled away from\n * its leftmost position.\n */\n private _shadowLeft!: HTMLElement;\n\n /**\n * Reference to the right scroll-shadow overlay element.\n * Receives the `is-visible` class when overflow content exists to the right\n * of the current scroll position.\n */\n private _shadowRight!: HTMLElement;\n\n /**\n * `ResizeObserver` instance watching `_tabsEl` for size changes.\n * Re-evaluates scroll shadow visibility whenever the tab list is resized\n * (e.g. viewport resize, dynamic tab additions).\n * Stored so it can be disconnected if needed.\n */\n private _resizeObserver?: ResizeObserver;\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Called when the element is inserted into the document.\n * Auto-generates a unique `id` if one was not provided.\n */\n connectedCallback() {\n super.connectedCallback();\n if (!this.id) {\n this.id = `nys-tabgroup-${Date.now()}-${componentIdCounter++}`;\n }\n }\n\n /**\n * Called after the element's shadow DOM has been rendered for the first time.\n *\n * Caches references to the tab list and scroll-shadow elements, performs an\n * initial scroll-shadow evaluation, and attaches:\n * - A `scroll` event listener on `_tabsEl` to update shadows on scroll.\n * - A `ResizeObserver` on `_tabsEl` to update shadows when the container\n * is resized.\n */\n firstUpdated() {\n const root = this.shadowRoot!;\n this._tabsEl = root.querySelector(\".nys-tabgroup__tabs\")!;\n this._shadowLeft = root.querySelector(\".scroll-shadow--left\")!;\n this._shadowRight = root.querySelector(\".scroll-shadow--right\")!;\n\n this._updateScrollShadows();\n\n this._tabsEl.addEventListener(\"scroll\", this._updateScrollShadows);\n this._tabsEl.addEventListener(\"wheel\", this._handleWheel, {\n passive: false,\n });\n\n this._resizeObserver = new ResizeObserver(() =>\n this._updateScrollShadows(),\n );\n this._resizeObserver.observe(this._tabsEl);\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Reads the current scroll state of `_tabsEl` and toggles the `is-visible`\n * class on the left and right shadow overlays accordingly.\n *\n * - Left shadow is visible when `scrollLeft > 0`.\n * - Right shadow is visible when `scrollLeft + clientWidth < scrollWidth`\n * (i.e. content exists beyond the right edge).\n *\n * Defined as an arrow function so it can be passed directly as an event\n * listener without losing `this` context.\n *\n * @returns void\n */\n private _updateScrollShadows = (): void => {\n const { scrollLeft, scrollWidth, clientWidth } = this._tabsEl;\n\n const canScrollLeft = scrollLeft > 0;\n const canScrollRight = scrollLeft + clientWidth < scrollWidth;\n\n this._shadowLeft.classList.toggle(\"is-visible\", canScrollLeft);\n this._shadowRight.classList.toggle(\"is-visible\", canScrollRight);\n };\n\n /**\n * Returns all `<nys-tab>` elements currently residing in the shadow-DOM\n * tabs container, in DOM order.\n *\n * @returns An array of `HTMLElement` references to every `<nys-tab>` child.\n */\n private _getTabs(): HTMLElement[] {\n return Array.from(\n this.shadowRoot\n ?.querySelector(\".nys-tabgroup__tabs\")\n ?.querySelectorAll(\"nys-tab\") ?? [],\n ) as HTMLElement[];\n }\n\n /**\n * Returns all `<nys-tabpanel>` elements currently residing in the\n * shadow-DOM panels container, in DOM order.\n *\n * @returns An array of `HTMLElement` references to every `<nys-tabpanel>` child.\n */\n private _getPanels(): HTMLElement[] {\n return Array.from(\n this.shadowRoot\n ?.querySelector(\".nys-tabgroup__panels\")\n ?.querySelectorAll(\"nys-tabpanel\") ?? [],\n ) as HTMLElement[];\n }\n\n /**\n * Single source of truth for ARIA wiring, `tabindex`, and panel visibility.\n *\n * For each index `i`:\n * - Sets `selected` / removes `selected` attribute on `tabs[i]`.\n * - Sets `aria-controls` on `tabs[i]` to the `id` of `panels[i]`.\n * - Sets `aria-labelledby` on `panels[i]` to the `id` of `tabs[i]`.\n * - Removes `hidden` from `panels[selectedIndex]`; adds it to all others.\n *\n * Must be called any time the selected tab changes (initial render and\n * subsequent user interactions).\n *\n * @param tabs - Ordered array of `<nys-tab>` elements to update.\n * @param panels - Ordered array of `<nys-tabpanel>` elements to update.\n * Must be the same length as `tabs` for correct pairing.\n * @param selectedIndex - Zero-based index of the tab/panel pair to activate.\n * @returns void\n */\n private _applySelection(\n tabs: HTMLElement[],\n panels: HTMLElement[],\n selectedIndex: number,\n ): void {\n tabs.forEach((tab, i) => {\n const isSelected = i === selectedIndex;\n const panel = panels[i];\n tab.setAttribute(\"aria-selected\", isSelected ? \"true\" : \"false\");\n tab.setAttribute(\"tabindex\", isSelected ? \"0\" : \"-1\");\n if (panel?.id) {\n tab.setAttribute(\"aria-controls\", panel.id);\n }\n if (isSelected) {\n tab.setAttribute(\"selected\", \"\");\n } else {\n tab.removeAttribute(\"selected\");\n }\n });\n\n panels.forEach((panel, i) => {\n const isSelected = i === selectedIndex;\n const tab = tabs[i];\n if (tab) {\n panel.setAttribute(\"aria-labelledby\", tab.id);\n }\n if (isSelected) {\n panel.removeAttribute(\"hidden\");\n } else {\n panel.setAttribute(\"hidden\", \"\");\n }\n });\n }\n\n // ---------------------------------------------------------------------------\n // Event Handlers\n // ---------------------------------------------------------------------------\n\n /**\n * Handles `slotchange` on the default slot.\n *\n * Iterates over all assigned elements and moves each `<nys-tab>` into\n * `.nys-tabgroup__tabs` and each `<nys-tabpanel>` into\n * `.nys-tabgroup__panels`, preserving relative order. After sorting,\n * calls `_applySelection` using the first element that already has a\n * `selected` attribute, or index `0` if none is found.\n *\n * @param e - The `Event` fired by the `<slot>` element on slot change.\n * @returns void\n */\n private _sortChildren(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const assigned = slot.assignedElements();\n\n const tabsContainer = this.shadowRoot?.querySelector(\".nys-tabgroup__tabs\");\n const panelsContainer = this.shadowRoot?.querySelector(\n \".nys-tabgroup__panels\",\n );\n if (!tabsContainer || !panelsContainer) return;\n\n const tabs: HTMLElement[] = [];\n const panels: HTMLElement[] = [];\n\n assigned.forEach((child) => {\n const tag = child.tagName.toLowerCase();\n if (tag === \"nys-tab\") {\n tabsContainer.appendChild(child);\n tabs.push(child as HTMLElement);\n } else if (tag === \"nys-tabpanel\") {\n panelsContainer.appendChild(child);\n panels.push(child as HTMLElement);\n }\n });\n\n // Honor the first selected tab; ignore any others\n const declaredSelectedIndex = tabs.findIndex((t) =>\n t.hasAttribute(\"selected\"),\n );\n const selectedIndex =\n declaredSelectedIndex !== -1 ? declaredSelectedIndex : 0;\n\n this._applySelection(tabs, panels, selectedIndex);\n }\n\n /**\n * Handles the `nys-tab-select` custom event bubbled up from a child\n * `<nys-tab>`.\n *\n * Resolves the originating `<nys-tab>` via `composedPath()` (required\n * because the event crosses shadow DOM boundaries), determines its index\n * among the current tab list, and delegates to `_applySelection`.\n *\n * @param e - The `Event` (cast to `CustomEvent`) dispatched by `<nys-tab>`.\n * @returns void\n */\n private _handleTabSelect(e: Event): void {\n const selectedTab = (e as CustomEvent)\n .composedPath()\n .find(\n (el) => (el as HTMLElement).tagName?.toLowerCase() === \"nys-tab\",\n ) as HTMLElement | undefined;\n if (!selectedTab) return;\n\n const tabs = this._getTabs();\n const panels = this._getPanels();\n const selectedIndex = tabs.indexOf(selectedTab);\n if (selectedIndex === -1) return;\n\n this._applySelection(tabs, panels, selectedIndex);\n }\n\n /**\n * Implements the ARIA radio-button keyboard pattern:\n * - `ArrowRight` — moves focus to the next enabled tab (wraps).\n * - `ArrowLeft` — moves focus to the previous enabled tab (wraps).\n *\n * Focus is moved without changing selection; Enter / Space on the newly\n * focused tab (handled by `<nys-tab>._handleKeydown`) confirm selection.\n *\n * The currently focused tab is resolved via `composedPath()` because focus\n * may sit on a shadow-DOM descendant of `<nys-tab>` rather than the host\n * itself.\n *\n * Disabled tabs are excluded from navigation and will never receive focus\n * via arrow keys.\n *\n * @param e - The `KeyboardEvent` from the tablist `keydown` listener.\n * @returns void\n */\n private _handleKeydown(e: KeyboardEvent): void {\n const tabs = this._getTabs().filter((t) => !t.hasAttribute(\"disabled\"));\n if (tabs.length === 0) return;\n\n const focusedTab = (e.composedPath() as HTMLElement[]).find(\n (el) => el.tagName?.toLowerCase() === \"nys-tab\",\n );\n const currentIndex = focusedTab ? tabs.indexOf(focusedTab) : -1;\n\n if (currentIndex === -1) return;\n\n const prevKey = \"ArrowLeft\";\n const nextKey = \"ArrowRight\";\n\n let newIndex = currentIndex;\n\n switch (e.key) {\n case prevKey:\n newIndex = (currentIndex - 1 + tabs.length) % tabs.length;\n break;\n case nextKey:\n newIndex = (currentIndex + 1) % tabs.length;\n break;\n default:\n return;\n }\n\n if (newIndex === currentIndex) return;\n\n // Move focus only — do not change selection\n (tabs[newIndex] as HTMLElement & { focus?: () => void }).focus?.();\n }\n\n /*\n * handles the horizontal scroll of the tab list when the user scrolls on the mouse wheel.\n */\n private _handleWheel = (e: WheelEvent): void => {\n if (e.deltaY === 0) return;\n e.preventDefault();\n this._tabsEl.scrollLeft += e.deltaY;\n };\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n\n render() {\n return html`\n <div class=\"nys-tabgroup\" @nys-tab-select=${this._handleTabSelect}>\n <div class=\"nys-tabgroup__tabs-container\">\n <div class=\"nys-tabgroup__tabs-background\"></div>\n <div class=\"scroll-shadow scroll-shadow--left\"></div>\n <div\n class=\"nys-tabgroup__tabs\"\n role=\"tablist\"\n aria-label=${this.name}\n @keydown=${this._handleKeydown}\n ></div>\n <div class=\"scroll-shadow scroll-shadow--right\"></div>\n </div>\n <div class=\"nys-tabgroup__panels\"></div>\n <slot @slotchange=${this._sortChildren}></slot>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"nys-tabgroup\")) {\n customElements.define(\"nys-tabgroup\", NysTabgroup);\n}\n","import { LitElement, html, unsafeCSS } from \"lit\";\nimport { property } from \"lit/decorators.js\";\n// @ts-ignore: SCSS module imported via bundler as inline\nimport styles from \"./nys-tab.scss?inline\";\n\n/** @internal Monotonically increasing counter used to generate unique element IDs. */\nlet componentIdCounter = 0;\n\n/**\n * `<nys-tabpanel>` is a content panel paired with a `<nys-tab>` inside a\n * `<nys-tabgroup>`.\n *\n * Pairing is determined by render order: the Nth `<nys-tabpanel>` child of a\n * `<nys-tabgroup>` corresponds to the Nth `<nys-tab>` child.\n * `aria-labelledby` and the `hidden` attribute are managed externally by\n * `<nys-tabgroup>` via `_applySelection`; do not set them directly.\n *\n * @element nys-tabpanel\n *\n * @slot - Default slot for panel content. Rendered inside a wrapper `<div>`\n * with the `.nys-tabpanel` class for styling.\n *\n * @example Panel content is wrapped by `<nys-tabpanel>`.\n * ```html\n * <!-- Panels are paired by position with <nys-tab> elements in the same <nys-tabgroup>. -->\n * <nys-tabgroup name=\"Steps\">\n * <nys-tab label=\"Step 1\"></nys-tab>\n * <nys-tab label=\"Step 2\"></nys-tab>\n * <nys-tabpanel>\n * <h2>Step 1: Enter your information</h2>\n * <p>Fill out the form below.</p>\n * </nys-tabpanel>\n * <nys-tabpanel>\n * <h2>Step 2: Review and submit</h2>\n * <p>Confirm your details before submitting.</p>\n * </nys-tabpanel>\n * </nys-tabgroup>\n * ```\n */\nexport class NysTabpanel extends LitElement {\n static styles = unsafeCSS(styles);\n\n /**\n * Unique identifier for the panel element.\n * If not provided, one is auto-generated in `connectedCallback`.\n * Reflected to the DOM attribute so `aria-controls` references on sibling\n * `<nys-tab>` elements resolve correctly.\n *\n * @attr id\n */\n @property({ type: String, reflect: true }) id = \"\";\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n connectedCallback() {\n super.connectedCallback();\n if (!this.id) {\n this.id = `nys-tabpanel-${Date.now()}-${componentIdCounter++}`;\n }\n this.setAttribute(\"role\", \"tabpanel\");\n }\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n\n render() {\n return html`\n <div class=\"nys-tabpanel\" tabindex=\"0\">\n <slot></slot>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"nys-tabpanel\")) {\n customElements.define(\"nys-tabpanel\", NysTabpanel);\n}\n"],"names":["componentIdCounter","_NysTab","LitElement","e","changed","options","html","unsafeCSS","styles","NysTab","__decorateClass","property","_NysTabgroup","scrollLeft","scrollWidth","clientWidth","canScrollLeft","canScrollRight","root","tabs","panels","selectedIndex","tab","i","isSelected","panel","assigned","tabsContainer","panelsContainer","child","tag","declaredSelectedIndex","t","selectedTab","el","focusedTab","currentIndex","prevKey","nextKey","newIndex","NysTabgroup","_NysTabpanel","NysTabpanel"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nys-tab.js","sources":["../src/nys-tab.ts","../src/nys-tabgroup.ts","../src/nys-tabpanel.ts"],"sourcesContent":["import { LitElement, html, unsafeCSS } from \"lit\";\nimport { property } from \"lit/decorators.js\";\n// @ts-ignore: SCSS module imported via bundler as inline\nimport styles from \"./nys-tab.scss?inline\";\n\n/** @internal Monotonically increasing counter used to generate unique element IDs. */\nlet componentIdCounter = 0;\n\n/**\n * `<nys-tab>` is a single tab within a `<nys-tabgroup>`.\n *\n * The host element carries `role=\"tab\"`, `tabindex`, `aria-selected`,\n * `aria-controls`, and `aria-disabled` so assistive technologies see the\n * correct ARIA tab semantics on the element that is actually focused.\n * `<nys-tabgroup>` manages `tabindex`, `aria-selected`, and `aria-controls`\n * via `_applySelection`; do not set them directly on this element.\n *\n * @element nys-tab\n *\n * @fires nys-tab-select - Dispatched when the tab is activated via click or\n * Enter / Space. Bubbles and crosses shadow DOM boundaries.\n * `detail: { id: string, label: string }`\n * @fires nys-tab-focus - Dispatched when the host receives focus. Bubbles and\n * crosses shadow DOM boundaries. `detail: { id: string }`\n * @fires nys-tab-blur - Dispatched when the host loses focus. Bubbles and\n * crosses shadow DOM boundaries. `detail: { id: string }`\n *\n * @slot - No slots; content is derived from the `label` property.\n *\n * @example `<nys-tab>` and `<nys-tabpanel>` should always be wrapped by `<nys-tabgroup>`\n * ```html\n * <!-- Always place <nys-tab> elements inside a <nys-tabgroup>. -->\n * <nys-tabgroup name=\"My Tabs\">\n * <nys-tab label=\"Overview\"></nys-tab>\n * <nys-tab label=\"Details\" selected></nys-tab>\n * <nys-tab label=\"Archived\" disabled></nys-tab>\n * <nys-tabpanel><p>Overview content</p></nys-tabpanel>\n * <nys-tabpanel><p>Details content (shown by default)</p></nys-tabpanel>\n * <nys-tabpanel><p>Archived content</p></nys-tabpanel>\n * </nys-tabgroup>\n * ```\n */\nexport class NysTab extends LitElement {\n static styles = unsafeCSS(styles);\n\n /**\n * Unique identifier for the tab element.\n * Reflected to the DOM attribute so `aria-controls` references resolve.\n *\n * @attr id\n */\n @property({ type: String, reflect: true }) id = \"\";\n\n /**\n * Visible text label rendered inside the inner `<span>`.\n *\n * @attr label\n */\n @property({ type: String }) label = \"\";\n\n /**\n * Whether this tab is the currently active tab.\n * Managed by `<nys-tabgroup>`; reflected for CSS attribute selectors.\n *\n * @attr selected\n */\n @property({ type: Boolean, reflect: true }) selected = false;\n\n /**\n * Whether this tab is disabled.\n * Reflected to the DOM attribute for CSS styling.\n *\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true }) disabled = false;\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Sets `role=\"tab\"` and `tabindex=\"-1\"` on the host (the element that AT\n * will read and that receives keyboard focus). Attaches host-level listeners\n * for keydown, focus, blur, and click so that interaction events work\n * correctly on the host element itself.\n *\n * Click is handled at the host level so iOS VoiceOver double-tap (which\n * dispatches `click` directly on the host because of `role=\"tab\"`, bypassing\n * shadow-DOM children) activates the tab. Normal taps land on the inner\n * `<span>` and bubble up to this listener.\n *\n * `<nys-tabgroup>` overrides `tabindex` to `\"0\"` on the selected tab.\n */\n connectedCallback() {\n super.connectedCallback();\n if (!this.id) {\n this.id = `nys-tab-${Date.now()}-${componentIdCounter++}`;\n }\n this.setAttribute(\"role\", \"tab\");\n this.setAttribute(\"tabindex\", \"-1\");\n this.addEventListener(\"keydown\", this._onKeydown);\n this.addEventListener(\"focus\", this._onFocus);\n this.addEventListener(\"blur\", this._onBlur);\n this.addEventListener(\"click\", this._onClick);\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener(\"keydown\", this._onKeydown);\n this.removeEventListener(\"focus\", this._onFocus);\n this.removeEventListener(\"blur\", this._onBlur);\n this.removeEventListener(\"click\", this._onClick);\n }\n\n /**\n * Keeps `aria-disabled` on the host in sync with the `disabled` property so\n * AT perceives the disabled state on the element it actually focuses.\n */\n updated(changed: Map<string, unknown>) {\n if (changed.has(\"disabled\")) {\n if (this.disabled) {\n this.setAttribute(\"aria-disabled\", \"true\");\n } else {\n this.removeAttribute(\"aria-disabled\");\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------------------\n\n /**\n * Focuses the host element. The host carries `role=\"tab\"` and `tabindex`,\n * so it is the correct element for AT to land on.\n */\n public focus(options?: FocusOptions): void {\n super.focus(options);\n }\n\n // ---------------------------------------------------------------------------\n // Event Handlers\n // ---------------------------------------------------------------------------\n\n /**\n * Enter / Space on the focused host activate the tab.\n * Arrow-key navigation is handled one level up by `<nys-tabgroup>`.\n */\n private _onKeydown = (e: KeyboardEvent): void => {\n if (this.disabled) return;\n if (e.key !== \"Enter\" && e.key !== \" \") return;\n e.preventDefault();\n this._handleClick();\n };\n\n /**\n * Host focus → dispatch `nys-tab-focus` for external observers.\n */\n private _onFocus = (): void => {\n this.dispatchEvent(\n new CustomEvent(\"nys-tab-focus\", {\n bubbles: true,\n composed: true,\n detail: { id: this.id },\n }),\n );\n };\n\n /**\n * Host blur → dispatch `nys-tab-blur` for external observers.\n */\n private _onBlur = (): void => {\n this.dispatchEvent(\n new CustomEvent(\"nys-tab-blur\", {\n bubbles: true,\n composed: true,\n detail: { id: this.id },\n }),\n );\n };\n\n /**\n * Host-level click handler. Activates the tab regardless of whether the\n * click landed on the inner element (normal pointer/keyboard tap, which\n * bubbles up) or directly on the host (iOS VoiceOver double-tap dispatches\n * `click` on the element with `role=\"tab\"`, bypassing shadow-DOM children).\n */\n private _onClick = (): void => {\n this._handleClick();\n };\n\n /**\n * Focuses the host then dispatches `nys-tab-select`. Called from both the\n * click handler and the keydown handler.\n */\n private _handleClick(): void {\n if (this.disabled) return;\n this.focus();\n this.dispatchEvent(\n new CustomEvent(\"nys-tab-select\", {\n bubbles: true,\n composed: true,\n detail: { id: this.id, label: this.label },\n }),\n );\n }\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n\n render() {\n // Inner element is a non-interactive `<span>` (not `<button>`) so that\n // axe-core's `nested-interactive` rule does not fire — the host already\n // carries `role=\"tab\"` + `tabindex` and is the interactive control.\n // Disabled gating, click activation, and keyboard activation all happen\n // on the host; the span is purely a styling/labeling target.\n return html`<span class=\"nys-tab\">${this.label}</span>`;\n }\n}\n\nif (!customElements.get(\"nys-tab\")) {\n customElements.define(\"nys-tab\", NysTab);\n}\n","import { LitElement, html, unsafeCSS } from \"lit\";\nimport { property } from \"lit/decorators.js\";\n// @ts-ignore: SCSS module imported via bundler as inline\nimport styles from \"./nys-tab.scss?inline\";\n\n/** @internal Monotonically increasing counter used to generate unique element IDs. */\nlet componentIdCounter = 0;\n\n/**\n * `<nys-tabgroup>` is the container for `<nys-tab>` and `<nys-tabpanel>`\n * elements.\n *\n * Accepts tabs and panels as flat light-DOM children in any order (interleaved\n * or grouped). On slot change, children are sorted into dedicated shadow-DOM\n * containers, ARIA relationships are wired, and the first selected (or first)\n * tab is activated.\n *\n * Scroll shadows are rendered on either side of the tab list and toggled via\n * `ResizeObserver` and a `scroll` listener so they accurately reflect whether\n * overflow content exists in each direction.\n *\n * Keyboard navigation follows the\n * {@link https://www.w3.org/WAI/ARIA/apg/patterns/tabs/ ARIA Tabs Pattern}:\n * - Arrow keys move focus without changing selection.\n * - Enter / Space confirm selection on the focused tab.\n *\n * @element nys-tabgroup\n *\n * @slot - Accepts `<nys-tab>` and `<nys-tabpanel>` children. Elements are\n * moved into internal shadow-DOM containers on `slotchange`; the slot\n * itself is not rendered visibly.\n *\n * @example Disable a tab using the `disabled` attribute on `<nys-tab>`.\n * ```html\n * <nys-tabgroup name=\"Account Settings\">\n * <nys-tab label=\"Profile\"></nys-tab>\n * <nys-tab label=\"Security\"></nys-tab>\n * <nys-tab label=\"Notifications\" disabled></nys-tab>\n * <nys-tabpanel><p>Manage your profile information.</p></nys-tabpanel>\n * <nys-tabpanel><p>Update your password and 2FA settings.</p></nys-tabpanel>\n * <nys-tabpanel><p>Notification preferences (coming soon).</p></nys-tabpanel>\n * </nys-tabgroup>\n * ```\n *\n * @example Pre-select a tab using the `selected` attribute on `<nys-tab>`.\n * ```html\n * <nys-tabgroup name=\"Reports\">\n * <nys-tab label=\"Summary\"></nys-tab>\n * <nys-tab label=\"Details\" selected></nys-tab>\n * <nys-tabpanel><p>Summary view</p></nys-tabpanel>\n * <nys-tabpanel><p>Detailed view (shown by default)</p></nys-tabpanel>\n * </nys-tabgroup>\n * ```\n */\nexport class NysTabgroup extends LitElement {\n static styles = unsafeCSS(styles);\n\n /**\n * Unique identifier for the tabgroup element.\n * If not provided, one is auto-generated in `connectedCallback`.\n * Reflected to the DOM attribute.\n *\n * @attr id\n */\n @property({ type: String, reflect: true }) id = \"\";\n\n /**\n * The name of the tab group.\n * Used for form submission and accessibility purposes.\n *\n * @attr name\n */\n @property({ type: String }) name = \"\";\n\n /**\n * Cached in `firstUpdated` and used by `_updateScrollShadows` to read\n * scroll position and dimensions.\n */\n private _tabsEl!: HTMLElement;\n\n /**\n * Reference to the left scroll-shadow overlay element.\n * Receives the `is-visible` class when the tab list is scrolled away from\n * its leftmost position.\n */\n private _shadowLeft!: HTMLElement;\n\n /**\n * Reference to the right scroll-shadow overlay element.\n * Receives the `is-visible` class when overflow content exists to the right\n * of the current scroll position.\n */\n private _shadowRight!: HTMLElement;\n\n /**\n * `ResizeObserver` instance watching `_tabsEl` for size changes.\n * Re-evaluates scroll shadow visibility whenever the tab list is resized\n * (e.g. viewport resize, dynamic tab additions).\n * Stored so it can be disconnected if needed.\n */\n private _resizeObserver?: ResizeObserver;\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Called when the element is inserted into the document.\n * Auto-generates a unique `id` if one was not provided.\n */\n connectedCallback() {\n super.connectedCallback();\n if (!this.id) {\n this.id = `nys-tabgroup-${Date.now()}-${componentIdCounter++}`;\n }\n }\n\n /**\n * Called after the element's shadow DOM has been rendered for the first time.\n *\n * Caches references to the tab list and scroll-shadow elements, performs an\n * initial scroll-shadow evaluation, and attaches:\n * - A `scroll` event listener on `_tabsEl` to update shadows on scroll.\n * - A `ResizeObserver` on `_tabsEl` to update shadows when the container\n * is resized.\n */\n firstUpdated() {\n const root = this.shadowRoot!;\n this._tabsEl = root.querySelector(\".nys-tabgroup__tabs\")!;\n this._shadowLeft = root.querySelector(\".scroll-shadow--left\")!;\n this._shadowRight = root.querySelector(\".scroll-shadow--right\")!;\n\n this._updateScrollShadows();\n\n this._tabsEl.addEventListener(\"scroll\", this._updateScrollShadows);\n this._tabsEl.addEventListener(\"wheel\", this._handleWheel, {\n passive: false,\n });\n\n this._resizeObserver = new ResizeObserver(() =>\n this._updateScrollShadows(),\n );\n this._resizeObserver.observe(this._tabsEl);\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this._tabsEl?.removeEventListener(\"scroll\", this._updateScrollShadows);\n this._tabsEl?.removeEventListener(\"wheel\", this._handleWheel);\n\n this._resizeObserver?.disconnect();\n this._resizeObserver = undefined;\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Reads the current scroll state of `_tabsEl` and toggles the `is-visible`\n * class on the left and right shadow overlays accordingly.\n *\n * - Left shadow is visible when `scrollLeft > 0`.\n * - Right shadow is visible when `scrollLeft + clientWidth < scrollWidth`\n * (i.e. content exists beyond the right edge).\n *\n * Defined as an arrow function so it can be passed directly as an event\n * listener without losing `this` context.\n *\n * @returns void\n */\n private _updateScrollShadows = (): void => {\n const { scrollLeft, scrollWidth, clientWidth } = this._tabsEl;\n\n const canScrollLeft = scrollLeft > 0;\n const canScrollRight = scrollLeft + clientWidth < scrollWidth;\n\n this._shadowLeft.classList.toggle(\"is-visible\", canScrollLeft);\n this._shadowRight.classList.toggle(\"is-visible\", canScrollRight);\n };\n\n /**\n * Returns all `<nys-tab>` elements currently residing in the shadow-DOM\n * tabs container, in DOM order.\n *\n * @returns An array of `HTMLElement` references to every `<nys-tab>` child.\n */\n private _getTabs(): HTMLElement[] {\n return Array.from(\n this.shadowRoot\n ?.querySelector(\".nys-tabgroup__tabs\")\n ?.querySelectorAll(\"nys-tab\") ?? [],\n ) as HTMLElement[];\n }\n\n /**\n * Returns all `<nys-tabpanel>` elements currently residing in the\n * shadow-DOM panels container, in DOM order.\n *\n * @returns An array of `HTMLElement` references to every `<nys-tabpanel>` child.\n */\n private _getPanels(): HTMLElement[] {\n return Array.from(\n this.shadowRoot\n ?.querySelector(\".nys-tabgroup__panels\")\n ?.querySelectorAll(\"nys-tabpanel\") ?? [],\n ) as HTMLElement[];\n }\n\n /**\n * Single source of truth for ARIA wiring, `tabindex`, and panel visibility.\n *\n * For each index `i`:\n * - Sets `selected` / removes `selected` attribute on `tabs[i]`.\n * - Sets `aria-controls` on `tabs[i]` to the `id` of `panels[i]`.\n * - Sets `aria-labelledby` on `panels[i]` to the `id` of `tabs[i]`.\n * - Removes `hidden` from `panels[selectedIndex]`; adds it to all others.\n *\n * Must be called any time the selected tab changes (initial render and\n * subsequent user interactions).\n *\n * @param tabs - Ordered array of `<nys-tab>` elements to update.\n * @param panels - Ordered array of `<nys-tabpanel>` elements to update.\n * Must be the same length as `tabs` for correct pairing.\n * @param selectedIndex - Zero-based index of the tab/panel pair to activate.\n * @returns void\n */\n private _applySelection(\n tabs: HTMLElement[],\n panels: HTMLElement[],\n selectedIndex: number,\n ): void {\n tabs.forEach((tab, i) => {\n const isSelected = i === selectedIndex;\n const panel = panels[i];\n tab.setAttribute(\"aria-selected\", isSelected ? \"true\" : \"false\");\n tab.setAttribute(\"tabindex\", isSelected ? \"0\" : \"-1\");\n if (panel?.id) {\n tab.setAttribute(\"aria-controls\", panel.id);\n }\n if (isSelected) {\n tab.setAttribute(\"selected\", \"\");\n } else {\n tab.removeAttribute(\"selected\");\n }\n });\n\n panels.forEach((panel, i) => {\n const isSelected = i === selectedIndex;\n const tab = tabs[i];\n if (tab) {\n panel.setAttribute(\"aria-labelledby\", tab.id);\n }\n if (isSelected) {\n panel.removeAttribute(\"hidden\");\n } else {\n panel.setAttribute(\"hidden\", \"\");\n }\n });\n }\n\n // ---------------------------------------------------------------------------\n // Event Handlers\n // ---------------------------------------------------------------------------\n\n /**\n * Handles `slotchange` on the default slot.\n *\n * Iterates over all assigned elements and moves each `<nys-tab>` into\n * `.nys-tabgroup__tabs` and each `<nys-tabpanel>` into\n * `.nys-tabgroup__panels`. If a panel has an `aria-labelledby` attribute,\n * it is explicitly paired with the tab it references; otherwise panels are\n * paired with tabs by index order. After sorting, calls `_applySelection`\n * using the first element that already has a `selected` attribute, or\n * index `0` if none is found.\n *\n * @param e - The `Event` fired by the `<slot>` element on slot change.\n * @returns void\n */\n private _sortChildren(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const assigned = slot.assignedElements();\n\n const tabsContainer = this.shadowRoot?.querySelector(\".nys-tabgroup__tabs\");\n const panelsContainer = this.shadowRoot?.querySelector(\n \".nys-tabgroup__panels\",\n );\n if (!tabsContainer || !panelsContainer) return;\n\n const tabs: HTMLElement[] = [];\n const panelsByRef = new Map<string, HTMLElement>();\n const panelsWithoutRef: HTMLElement[] = [];\n\n assigned.forEach((child) => {\n const tag = child.tagName.toLowerCase();\n if (tag === \"nys-tab\") {\n tabsContainer.appendChild(child);\n tabs.push(child as HTMLElement);\n } else if (tag === \"nys-tabpanel\") {\n panelsContainer.appendChild(child);\n const panel = child as HTMLElement;\n const ariaLabelledBy = panel.getAttribute(\"aria-labelledby\");\n if (ariaLabelledBy) {\n panelsByRef.set(ariaLabelledBy, panel);\n } else {\n panelsWithoutRef.push(panel);\n }\n }\n });\n\n // Pair panels with tabs: explicit refs first, then remaining panels by index\n const panels: HTMLElement[] = [];\n tabs.forEach((tab) => {\n const tabId = tab.id;\n if (tabId && panelsByRef.has(tabId)) {\n panels.push(panelsByRef.get(tabId)!);\n panelsByRef.delete(tabId);\n } else if (panelsWithoutRef.length > 0) {\n panels.push(panelsWithoutRef.shift()!);\n }\n });\n\n // Append any remaining panels with unresolved references\n panelsByRef.forEach((panel) => panels.push(panel));\n\n // Re-append panels in correct order so _getPanels() reads them in tab order\n panels.forEach((panel) => panelsContainer.appendChild(panel));\n\n // Honor the first selected tab; ignore any others\n const declaredSelectedIndex = tabs.findIndex((t) =>\n t.hasAttribute(\"selected\"),\n );\n const selectedIndex =\n declaredSelectedIndex !== -1 ? declaredSelectedIndex : 0;\n\n this._applySelection(tabs, panels, selectedIndex);\n }\n\n /**\n * Handles the `nys-tab-select` custom event bubbled up from a child\n * `<nys-tab>`.\n *\n * Resolves the originating `<nys-tab>` via `composedPath()` (required\n * because the event crosses shadow DOM boundaries), determines its index\n * among the current tab list, and delegates to `_applySelection`.\n *\n * @param e - The `Event` (cast to `CustomEvent`) dispatched by `<nys-tab>`.\n * @returns void\n */\n private _handleTabSelect(e: Event): void {\n const selectedTab = (e as CustomEvent)\n .composedPath()\n .find(\n (el) => (el as HTMLElement).tagName?.toLowerCase() === \"nys-tab\",\n ) as HTMLElement | undefined;\n if (!selectedTab) return;\n\n const tabs = this._getTabs();\n const panels = this._getPanels();\n const selectedIndex = tabs.indexOf(selectedTab);\n if (selectedIndex === -1) return;\n\n this._applySelection(tabs, panels, selectedIndex);\n }\n\n /**\n * Implements the ARIA radio-button keyboard pattern:\n * - `ArrowRight` — moves focus to the next enabled tab (wraps).\n * - `ArrowLeft` — moves focus to the previous enabled tab (wraps).\n *\n * Focus is moved without changing selection; Enter / Space on the newly\n * focused tab (handled by `<nys-tab>._handleKeydown`) confirm selection.\n *\n * The currently focused tab is resolved via `composedPath()` because focus\n * may sit on a shadow-DOM descendant of `<nys-tab>` rather than the host\n * itself.\n *\n * Disabled tabs are excluded from navigation and will never receive focus\n * via arrow keys.\n *\n * @param e - The `KeyboardEvent` from the tablist `keydown` listener.\n * @returns void\n */\n private _handleKeydown(e: KeyboardEvent): void {\n const tabs = this._getTabs().filter((t) => !t.hasAttribute(\"disabled\"));\n if (tabs.length === 0) return;\n\n const focusedTab = (e.composedPath() as HTMLElement[]).find(\n (el) => el.tagName?.toLowerCase() === \"nys-tab\",\n );\n const currentIndex = focusedTab ? tabs.indexOf(focusedTab) : -1;\n\n if (currentIndex === -1) return;\n\n const prevKey = \"ArrowLeft\";\n const nextKey = \"ArrowRight\";\n\n let newIndex = currentIndex;\n\n switch (e.key) {\n case prevKey:\n newIndex = (currentIndex - 1 + tabs.length) % tabs.length;\n break;\n case nextKey:\n newIndex = (currentIndex + 1) % tabs.length;\n break;\n default:\n return;\n }\n\n if (newIndex === currentIndex) return;\n\n // Move focus only — do not change selection\n (tabs[newIndex] as HTMLElement & { focus?: () => void }).focus?.();\n }\n\n /*\n * handles the horizontal scroll of the tab list when the user scrolls on the mouse wheel.\n */\n private _handleWheel = (e: WheelEvent): void => {\n if (e.deltaY === 0) return;\n e.preventDefault();\n this._tabsEl.scrollLeft += e.deltaY;\n };\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n\n render() {\n return html`\n <div class=\"nys-tabgroup\" @nys-tab-select=${this._handleTabSelect}>\n <div class=\"nys-tabgroup__tabs-container\">\n <div class=\"nys-tabgroup__tabs-background\"></div>\n <div class=\"scroll-shadow scroll-shadow--left\"></div>\n <div\n class=\"nys-tabgroup__tabs\"\n role=\"tablist\"\n aria-label=${this.name}\n @keydown=${this._handleKeydown}\n ></div>\n <div class=\"scroll-shadow scroll-shadow--right\"></div>\n </div>\n <div class=\"nys-tabgroup__panels\"></div>\n <slot @slotchange=${this._sortChildren}></slot>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"nys-tabgroup\")) {\n customElements.define(\"nys-tabgroup\", NysTabgroup);\n}\n","import { LitElement, html, unsafeCSS } from \"lit\";\nimport { property } from \"lit/decorators.js\";\n// @ts-ignore: SCSS module imported via bundler as inline\nimport styles from \"./nys-tab.scss?inline\";\n\n/** @internal Monotonically increasing counter used to generate unique element IDs. */\nlet componentIdCounter = 0;\n\n/**\n * `<nys-tabpanel>` is a content panel paired with a `<nys-tab>` inside a\n * `<nys-tabgroup>`.\n *\n * Pairing is determined by render order: the Nth `<nys-tabpanel>` child of a\n * `<nys-tabgroup>` corresponds to the Nth `<nys-tab>` child.\n * `aria-labelledby` and the `hidden` attribute are managed externally by\n * `<nys-tabgroup>` via `_applySelection`; do not set them directly.\n *\n * @element nys-tabpanel\n *\n * @slot - Default slot for panel content. Rendered inside a wrapper `<div>`\n * with the `.nys-tabpanel` class for styling.\n *\n * @example Panel content is wrapped by `<nys-tabpanel>`.\n * ```html\n * <!-- Panels are paired by position with <nys-tab> elements in the same <nys-tabgroup>. -->\n * <nys-tabgroup name=\"Steps\">\n * <nys-tab label=\"Step 1\"></nys-tab>\n * <nys-tab label=\"Step 2\"></nys-tab>\n * <nys-tabpanel>\n * <h2>Step 1: Enter your information</h2>\n * <p>Fill out the form below.</p>\n * </nys-tabpanel>\n * <nys-tabpanel>\n * <h2>Step 2: Review and submit</h2>\n * <p>Confirm your details before submitting.</p>\n * </nys-tabpanel>\n * </nys-tabgroup>\n * ```\n */\nexport class NysTabpanel extends LitElement {\n static styles = unsafeCSS(styles);\n\n /**\n * Unique identifier for the panel element.\n * If not provided, one is auto-generated in `connectedCallback`.\n * Reflected to the DOM attribute so `aria-controls` references on sibling\n * `<nys-tab>` elements resolve correctly.\n *\n * @attr id\n */\n @property({ type: String, reflect: true }) id = \"\";\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n connectedCallback() {\n super.connectedCallback();\n if (!this.id) {\n this.id = `nys-tabpanel-${Date.now()}-${componentIdCounter++}`;\n }\n this.setAttribute(\"role\", \"tabpanel\");\n }\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n\n render() {\n return html`\n <div class=\"nys-tabpanel\" tabindex=\"0\">\n <slot></slot>\n </div>\n `;\n }\n}\n\nif (!customElements.get(\"nys-tabpanel\")) {\n customElements.define(\"nys-tabpanel\", NysTabpanel);\n}\n"],"names":["componentIdCounter","_NysTab","LitElement","e","changed","options","html","unsafeCSS","styles","NysTab","__decorateClass","property","_NysTabgroup","scrollLeft","scrollWidth","clientWidth","canScrollLeft","canScrollRight","root","tabs","panels","selectedIndex","tab","i","isSelected","panel","assigned","tabsContainer","panelsContainer","panelsByRef","panelsWithoutRef","child","tag","ariaLabelledBy","tabId","declaredSelectedIndex","t","selectedTab","el","focusedTab","currentIndex","prevKey","nextKey","newIndex","NysTabgroup","_NysTabpanel","NysTabpanel"],"mappings":"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"}
|
package/dist/nys-tabgroup.d.ts
CHANGED
|
@@ -101,6 +101,7 @@ export declare class NysTabgroup extends LitElement {
|
|
|
101
101
|
* is resized.
|
|
102
102
|
*/
|
|
103
103
|
firstUpdated(): void;
|
|
104
|
+
disconnectedCallback(): void;
|
|
104
105
|
/**
|
|
105
106
|
* Reads the current scroll state of `_tabsEl` and toggles the `is-visible`
|
|
106
107
|
* class on the left and right shadow overlays accordingly.
|
|
@@ -153,9 +154,11 @@ export declare class NysTabgroup extends LitElement {
|
|
|
153
154
|
*
|
|
154
155
|
* Iterates over all assigned elements and moves each `<nys-tab>` into
|
|
155
156
|
* `.nys-tabgroup__tabs` and each `<nys-tabpanel>` into
|
|
156
|
-
* `.nys-tabgroup__panels
|
|
157
|
-
*
|
|
158
|
-
*
|
|
157
|
+
* `.nys-tabgroup__panels`. If a panel has an `aria-labelledby` attribute,
|
|
158
|
+
* it is explicitly paired with the tab it references; otherwise panels are
|
|
159
|
+
* paired with tabs by index order. After sorting, calls `_applySelection`
|
|
160
|
+
* using the first element that already has a `selected` attribute, or
|
|
161
|
+
* index `0` if none is found.
|
|
159
162
|
*
|
|
160
163
|
* @param e - The `Event` fired by the `<slot>` element on slot change.
|
|
161
164
|
* @returns void
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nysds/nys-tab",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.3",
|
|
4
4
|
"description": "The Tab component from the NYS Design System.",
|
|
5
5
|
"module": "dist/nys-tab.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"lit-analyze": "lit-analyzer '*.ts'"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@nysds/nys-button": "1.18.
|
|
26
|
+
"@nysds/nys-button": "1.18.3"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"lit": "^3.3.1",
|