@u-elements/u-tabs 0.0.5 → 0.0.7
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/u-tabs.cjs +77 -39
- package/dist/u-tabs.d.cts +7 -5
- package/dist/u-tabs.d.ts +7 -5
- package/dist/u-tabs.js +77 -39
- package/dist/u-tabs.manifest.json +5 -0
- package/dist/u-tabs.vscode.json +1 -1
- package/package.json +23 -23
package/dist/u-tabs.cjs
CHANGED
|
@@ -3,20 +3,30 @@
|
|
|
3
3
|
// ../utils.ts
|
|
4
4
|
var IS_BROWSER = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.navigator !== "undefined";
|
|
5
5
|
var IS_ANDROID = IS_BROWSER && /android/i.test(navigator.userAgent);
|
|
6
|
+
IS_BROWSER && // @ts-expect-error Typescript has not implemented userAgentData yet https://stackoverflow.com/a/71392474
|
|
7
|
+
/^Mac/i.test(navigator.userAgentData?.platform || navigator.platform);
|
|
6
8
|
var SAFE_LABELLEDBY = `${IS_ANDROID ? "data" : "aria"}-labelledby`;
|
|
7
9
|
var DISPLAY_BLOCK = ":host(:not([hidden])) { display: block }";
|
|
8
10
|
var UHTMLElement = typeof HTMLElement === "undefined" ? class {
|
|
9
11
|
} : HTMLElement;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
function attr(el, name, value) {
|
|
13
|
+
if (value === void 0) return el?.getAttribute(name) ?? null;
|
|
14
|
+
if (value === null) el?.removeAttribute(name);
|
|
15
|
+
else if (el?.getAttribute(name) !== value) el?.setAttribute(name, value);
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
var events = (action, element, rest) => {
|
|
19
|
+
for (const type of rest[0].split(",")) {
|
|
20
|
+
rest[0] = type;
|
|
21
|
+
Element.prototype[`${action}EventListener`].apply(element, rest);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
14
24
|
var on = (element, ...rest) => events("add", element, rest);
|
|
15
25
|
var off = (element, ...rest) => events("remove", element, rest);
|
|
16
|
-
var attachStyle = (element, css) => element.attachShadow({ mode: "
|
|
26
|
+
var attachStyle = (element, css) => element.attachShadow({ mode: "open" }).append(
|
|
17
27
|
createElement("slot"),
|
|
18
28
|
// Unnamed slot does automatically render all top element nodes
|
|
19
|
-
createElement("style",
|
|
29
|
+
createElement("style", css)
|
|
20
30
|
);
|
|
21
31
|
var asButton = (event) => {
|
|
22
32
|
const isClick = "key" in event && (event.key === " " || event.key === "Enter");
|
|
@@ -24,10 +34,21 @@ var asButton = (event) => {
|
|
|
24
34
|
if (isClick && event.target instanceof HTMLElement) event.target.click();
|
|
25
35
|
return isClick;
|
|
26
36
|
};
|
|
27
|
-
var getRoot = (node) =>
|
|
37
|
+
var getRoot = (node) => {
|
|
38
|
+
const root = node.getRootNode?.() || node.ownerDocument;
|
|
39
|
+
return root instanceof Document || root instanceof ShadowRoot ? root : document;
|
|
40
|
+
};
|
|
28
41
|
var id = 0;
|
|
29
|
-
var useId = (el) =>
|
|
30
|
-
|
|
42
|
+
var useId = (el) => {
|
|
43
|
+
if (!el) return "";
|
|
44
|
+
if (!el.id) el.id = `:${el.nodeName.toLowerCase()}${(++id).toString(32)}`;
|
|
45
|
+
return el.id;
|
|
46
|
+
};
|
|
47
|
+
var createElement = (tagName, text, attrs) => {
|
|
48
|
+
const el = document.createElement(tagName);
|
|
49
|
+
if (text) el.textContent = text;
|
|
50
|
+
return el;
|
|
51
|
+
};
|
|
31
52
|
var customElements = {
|
|
32
53
|
define: (name, instance) => !IS_BROWSER || window.customElements.get(name) || window.customElements.define(name, instance)
|
|
33
54
|
};
|
|
@@ -46,7 +67,7 @@ var UHTMLTabsElement = class extends UHTMLElement {
|
|
|
46
67
|
return getSelectedIndex(this.tabs);
|
|
47
68
|
}
|
|
48
69
|
set selectedIndex(index) {
|
|
49
|
-
if (this.tabs[index]) this.tabs[index]
|
|
70
|
+
if (this.tabs[index]) attr(this.tabs[index], "aria-selected", "true");
|
|
50
71
|
}
|
|
51
72
|
get tabs() {
|
|
52
73
|
return queryWithoutNested("u-tab", this);
|
|
@@ -61,7 +82,7 @@ var UHTMLTabListElement = class extends UHTMLElement {
|
|
|
61
82
|
attachStyle(this, DISPLAY_BLOCK);
|
|
62
83
|
}
|
|
63
84
|
connectedCallback() {
|
|
64
|
-
this
|
|
85
|
+
attr(this, "role", "tablist");
|
|
65
86
|
on(this, "click,keydown", this);
|
|
66
87
|
}
|
|
67
88
|
disconnectedCallback() {
|
|
@@ -103,44 +124,49 @@ var UHTMLTabListElement = class extends UHTMLElement {
|
|
|
103
124
|
return getSelectedIndex(this.tabs);
|
|
104
125
|
}
|
|
105
126
|
set selectedIndex(index) {
|
|
106
|
-
if (this.tabs[index]) this.tabs[index]
|
|
127
|
+
if (this.tabs[index]) attr(this.tabs[index], "aria-selected", "true");
|
|
107
128
|
}
|
|
108
129
|
};
|
|
109
130
|
var UHTMLTabElement = class extends UHTMLElement {
|
|
131
|
+
// Using ES2015 syntax for backwards compatibility
|
|
132
|
+
static get observedAttributes() {
|
|
133
|
+
return ["id", "aria-selected", ARIA_CONTROLS];
|
|
134
|
+
}
|
|
110
135
|
constructor() {
|
|
111
136
|
super();
|
|
112
137
|
attachStyle(
|
|
113
138
|
this,
|
|
114
|
-
|
|
139
|
+
":host(:not([hidden])) { cursor: pointer; display: inline-block }"
|
|
115
140
|
);
|
|
116
141
|
}
|
|
117
142
|
connectedCallback() {
|
|
143
|
+
const panelId = !attr(this, ARIA_CONTROLS) && useId(getPanel(this));
|
|
118
144
|
const selected = this.selected || ![...queryWithoutNested("u-tab", this.tabList || this)].some(isSelected);
|
|
119
|
-
this
|
|
145
|
+
attr(this, "aria-selected", `${selected}`);
|
|
146
|
+
attr(this, "role", "tab");
|
|
120
147
|
this.tabIndex = selected ? 0 : -1;
|
|
121
|
-
this
|
|
122
|
-
if (!this.hasAttribute(ARIA_CONTROLS))
|
|
123
|
-
this.setAttribute(ARIA_CONTROLS, useId(getPanel(this)));
|
|
148
|
+
if (panelId) attr(this, ARIA_CONTROLS, panelId);
|
|
124
149
|
}
|
|
125
150
|
attributeChangedCallback(name, prev) {
|
|
126
151
|
if (!this.selected) return;
|
|
127
152
|
const nextPanel = getPanel(this);
|
|
128
153
|
const nextPanelId = useId(nextPanel);
|
|
129
154
|
if (name === "aria-selected" && this.tabList)
|
|
130
|
-
queryWithoutNested("u-tab", this.tabList)
|
|
155
|
+
for (const tab of queryWithoutNested("u-tab", this.tabList)) {
|
|
131
156
|
if (tab !== this && isSelected(tab)) {
|
|
132
|
-
getPanel(tab)
|
|
133
|
-
|
|
157
|
+
const panel = getPanel(tab);
|
|
158
|
+
if (panel) panel.hidden = true;
|
|
159
|
+
attr(tab, "aria-selected", "false");
|
|
134
160
|
tab.tabIndex = -1;
|
|
135
161
|
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if (this
|
|
140
|
-
this
|
|
162
|
+
}
|
|
163
|
+
const prevPanel = name === ARIA_CONTROLS && prev && getPanel(this, prev);
|
|
164
|
+
if (prevPanel) prevPanel.hidden = true;
|
|
165
|
+
if (nextPanelId && attr(this, ARIA_CONTROLS) !== nextPanelId)
|
|
166
|
+
attr(this, ARIA_CONTROLS, nextPanelId);
|
|
141
167
|
this.tabIndex = 0;
|
|
142
|
-
nextPanel
|
|
143
|
-
nextPanel
|
|
168
|
+
if (nextPanel) attr(nextPanel, SAFE_LABELLEDBY, useId(this));
|
|
169
|
+
if (nextPanel) nextPanel.hidden = false;
|
|
144
170
|
}
|
|
145
171
|
get tabsElement() {
|
|
146
172
|
return this.closest("u-tabs");
|
|
@@ -152,7 +178,7 @@ var UHTMLTabElement = class extends UHTMLElement {
|
|
|
152
178
|
return isSelected(this);
|
|
153
179
|
}
|
|
154
180
|
set selected(value) {
|
|
155
|
-
this
|
|
181
|
+
attr(this, "aria-selected", `${!!value}`);
|
|
156
182
|
}
|
|
157
183
|
/** Retrieves the ordinal position of an tab in a tablist. */
|
|
158
184
|
get index() {
|
|
@@ -163,15 +189,24 @@ var UHTMLTabElement = class extends UHTMLElement {
|
|
|
163
189
|
return getPanel(this);
|
|
164
190
|
}
|
|
165
191
|
};
|
|
166
|
-
UHTMLTabElement.observedAttributes = ["id", "aria-selected", ARIA_CONTROLS];
|
|
167
192
|
var UHTMLTabPanelElement = class extends UHTMLElement {
|
|
193
|
+
// Using ES2015 syntax for backwards compatibility
|
|
194
|
+
static get observedAttributes() {
|
|
195
|
+
return ["hidden"];
|
|
196
|
+
}
|
|
168
197
|
constructor() {
|
|
169
198
|
super();
|
|
170
199
|
attachStyle(this, DISPLAY_BLOCK);
|
|
171
200
|
}
|
|
172
201
|
connectedCallback() {
|
|
202
|
+
attr(this, "role", "tabpanel");
|
|
173
203
|
this.hidden = getSelectedIndex(this.tabs) === -1;
|
|
174
|
-
this.
|
|
204
|
+
this.attributeChangedCallback();
|
|
205
|
+
}
|
|
206
|
+
attributeChangedCallback() {
|
|
207
|
+
if (this.hidden || isFocusable(this.firstChild))
|
|
208
|
+
attr(this, "tabindex", null);
|
|
209
|
+
else this.tabIndex = 0;
|
|
175
210
|
}
|
|
176
211
|
get tabsElement() {
|
|
177
212
|
return this.closest("u-tabs");
|
|
@@ -182,16 +217,19 @@ var UHTMLTabPanelElement = class extends UHTMLElement {
|
|
|
182
217
|
return root.length ? root : document.querySelectorAll(css);
|
|
183
218
|
}
|
|
184
219
|
};
|
|
185
|
-
var queryWithoutNested = (tag, self) =>
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
var isSelected = (tab) => tab.ariaSelected === "true";
|
|
220
|
+
var queryWithoutNested = (tag, self) => self.querySelectorAll(
|
|
221
|
+
`${tag}:not(:scope ${self.nodeName}:not(:scope) ${tag})`
|
|
222
|
+
);
|
|
223
|
+
var isSelected = (tab) => attr(tab, "aria-selected") === "true";
|
|
190
224
|
var getSelectedIndex = (tabs) => [...tabs].findIndex(isSelected);
|
|
191
|
-
var
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
225
|
+
var isFocusable = (el) => el instanceof Element && !el.matches(':disabled,[tabindex^="-"]') && el.matches(
|
|
226
|
+
`[contenteditable],[controls],[href],[tabindex],input:not([type="hidden"]),select,textarea,button,summary,iframe`
|
|
227
|
+
);
|
|
228
|
+
var getPanel = (tab, id2) => {
|
|
229
|
+
const panelId = id2 || attr(tab, ARIA_CONTROLS);
|
|
230
|
+
const panelSelector = `u-tabpanel[id="${panelId}"]`;
|
|
231
|
+
const tabsElement = tab.closest("u-tabs");
|
|
232
|
+
return panelId && getRoot(tab).querySelector(panelSelector) || panelId && getRoot(tab).querySelector(panelSelector) || tabsElement && queryWithoutNested("u-tabpanel", tabsElement)[[...queryWithoutNested("u-tab", tabsElement)].indexOf(tab)] || null;
|
|
195
233
|
};
|
|
196
234
|
customElements.define("u-tabs", UHTMLTabsElement);
|
|
197
235
|
customElements.define("u-tablist", UHTMLTabListElement);
|
package/dist/u-tabs.d.cts
CHANGED
|
@@ -5,10 +5,10 @@ declare const UHTMLElement: {
|
|
|
5
5
|
|
|
6
6
|
declare global {
|
|
7
7
|
interface HTMLElementTagNameMap {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
"u-tabs": UHTMLTabsElement;
|
|
9
|
+
"u-tablist": UHTMLTabListElement;
|
|
10
|
+
"u-tab": UHTMLTabElement;
|
|
11
|
+
"u-tabpanel": UHTMLTabPanelElement;
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
@@ -42,7 +42,7 @@ declare class UHTMLTabListElement extends UHTMLElement {
|
|
|
42
42
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tab_role)
|
|
43
43
|
*/
|
|
44
44
|
declare class UHTMLTabElement extends UHTMLElement {
|
|
45
|
-
static observedAttributes: string[];
|
|
45
|
+
static get observedAttributes(): string[];
|
|
46
46
|
constructor();
|
|
47
47
|
connectedCallback(): void;
|
|
48
48
|
attributeChangedCallback(name: string, prev: string): void;
|
|
@@ -59,8 +59,10 @@ declare class UHTMLTabElement extends UHTMLElement {
|
|
|
59
59
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tabpanel_role)
|
|
60
60
|
*/
|
|
61
61
|
declare class UHTMLTabPanelElement extends UHTMLElement {
|
|
62
|
+
static get observedAttributes(): string[];
|
|
62
63
|
constructor();
|
|
63
64
|
connectedCallback(): void;
|
|
65
|
+
attributeChangedCallback(): void;
|
|
64
66
|
get tabsElement(): UHTMLTabsElement | null;
|
|
65
67
|
get tabs(): NodeListOf<UHTMLTabElement>;
|
|
66
68
|
}
|
package/dist/u-tabs.d.ts
CHANGED
|
@@ -5,10 +5,10 @@ declare const UHTMLElement: {
|
|
|
5
5
|
|
|
6
6
|
declare global {
|
|
7
7
|
interface HTMLElementTagNameMap {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
"u-tabs": UHTMLTabsElement;
|
|
9
|
+
"u-tablist": UHTMLTabListElement;
|
|
10
|
+
"u-tab": UHTMLTabElement;
|
|
11
|
+
"u-tabpanel": UHTMLTabPanelElement;
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
@@ -42,7 +42,7 @@ declare class UHTMLTabListElement extends UHTMLElement {
|
|
|
42
42
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tab_role)
|
|
43
43
|
*/
|
|
44
44
|
declare class UHTMLTabElement extends UHTMLElement {
|
|
45
|
-
static observedAttributes: string[];
|
|
45
|
+
static get observedAttributes(): string[];
|
|
46
46
|
constructor();
|
|
47
47
|
connectedCallback(): void;
|
|
48
48
|
attributeChangedCallback(name: string, prev: string): void;
|
|
@@ -59,8 +59,10 @@ declare class UHTMLTabElement extends UHTMLElement {
|
|
|
59
59
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tabpanel_role)
|
|
60
60
|
*/
|
|
61
61
|
declare class UHTMLTabPanelElement extends UHTMLElement {
|
|
62
|
+
static get observedAttributes(): string[];
|
|
62
63
|
constructor();
|
|
63
64
|
connectedCallback(): void;
|
|
65
|
+
attributeChangedCallback(): void;
|
|
64
66
|
get tabsElement(): UHTMLTabsElement | null;
|
|
65
67
|
get tabs(): NodeListOf<UHTMLTabElement>;
|
|
66
68
|
}
|
package/dist/u-tabs.js
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
// ../utils.ts
|
|
2
2
|
var IS_BROWSER = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.navigator !== "undefined";
|
|
3
3
|
var IS_ANDROID = IS_BROWSER && /android/i.test(navigator.userAgent);
|
|
4
|
+
IS_BROWSER && // @ts-expect-error Typescript has not implemented userAgentData yet https://stackoverflow.com/a/71392474
|
|
5
|
+
/^Mac/i.test(navigator.userAgentData?.platform || navigator.platform);
|
|
4
6
|
var SAFE_LABELLEDBY = `${IS_ANDROID ? "data" : "aria"}-labelledby`;
|
|
5
7
|
var DISPLAY_BLOCK = ":host(:not([hidden])) { display: block }";
|
|
6
8
|
var UHTMLElement = typeof HTMLElement === "undefined" ? class {
|
|
7
9
|
} : HTMLElement;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
function attr(el, name, value) {
|
|
11
|
+
if (value === void 0) return el?.getAttribute(name) ?? null;
|
|
12
|
+
if (value === null) el?.removeAttribute(name);
|
|
13
|
+
else if (el?.getAttribute(name) !== value) el?.setAttribute(name, value);
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
var events = (action, element, rest) => {
|
|
17
|
+
for (const type of rest[0].split(",")) {
|
|
18
|
+
rest[0] = type;
|
|
19
|
+
Element.prototype[`${action}EventListener`].apply(element, rest);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
12
22
|
var on = (element, ...rest) => events("add", element, rest);
|
|
13
23
|
var off = (element, ...rest) => events("remove", element, rest);
|
|
14
|
-
var attachStyle = (element, css) => element.attachShadow({ mode: "
|
|
24
|
+
var attachStyle = (element, css) => element.attachShadow({ mode: "open" }).append(
|
|
15
25
|
createElement("slot"),
|
|
16
26
|
// Unnamed slot does automatically render all top element nodes
|
|
17
|
-
createElement("style",
|
|
27
|
+
createElement("style", css)
|
|
18
28
|
);
|
|
19
29
|
var asButton = (event) => {
|
|
20
30
|
const isClick = "key" in event && (event.key === " " || event.key === "Enter");
|
|
@@ -22,10 +32,21 @@ var asButton = (event) => {
|
|
|
22
32
|
if (isClick && event.target instanceof HTMLElement) event.target.click();
|
|
23
33
|
return isClick;
|
|
24
34
|
};
|
|
25
|
-
var getRoot = (node) =>
|
|
35
|
+
var getRoot = (node) => {
|
|
36
|
+
const root = node.getRootNode?.() || node.ownerDocument;
|
|
37
|
+
return root instanceof Document || root instanceof ShadowRoot ? root : document;
|
|
38
|
+
};
|
|
26
39
|
var id = 0;
|
|
27
|
-
var useId = (el) =>
|
|
28
|
-
|
|
40
|
+
var useId = (el) => {
|
|
41
|
+
if (!el) return "";
|
|
42
|
+
if (!el.id) el.id = `:${el.nodeName.toLowerCase()}${(++id).toString(32)}`;
|
|
43
|
+
return el.id;
|
|
44
|
+
};
|
|
45
|
+
var createElement = (tagName, text, attrs) => {
|
|
46
|
+
const el = document.createElement(tagName);
|
|
47
|
+
if (text) el.textContent = text;
|
|
48
|
+
return el;
|
|
49
|
+
};
|
|
29
50
|
var customElements = {
|
|
30
51
|
define: (name, instance) => !IS_BROWSER || window.customElements.get(name) || window.customElements.define(name, instance)
|
|
31
52
|
};
|
|
@@ -44,7 +65,7 @@ var UHTMLTabsElement = class extends UHTMLElement {
|
|
|
44
65
|
return getSelectedIndex(this.tabs);
|
|
45
66
|
}
|
|
46
67
|
set selectedIndex(index) {
|
|
47
|
-
if (this.tabs[index]) this.tabs[index]
|
|
68
|
+
if (this.tabs[index]) attr(this.tabs[index], "aria-selected", "true");
|
|
48
69
|
}
|
|
49
70
|
get tabs() {
|
|
50
71
|
return queryWithoutNested("u-tab", this);
|
|
@@ -59,7 +80,7 @@ var UHTMLTabListElement = class extends UHTMLElement {
|
|
|
59
80
|
attachStyle(this, DISPLAY_BLOCK);
|
|
60
81
|
}
|
|
61
82
|
connectedCallback() {
|
|
62
|
-
this
|
|
83
|
+
attr(this, "role", "tablist");
|
|
63
84
|
on(this, "click,keydown", this);
|
|
64
85
|
}
|
|
65
86
|
disconnectedCallback() {
|
|
@@ -101,44 +122,49 @@ var UHTMLTabListElement = class extends UHTMLElement {
|
|
|
101
122
|
return getSelectedIndex(this.tabs);
|
|
102
123
|
}
|
|
103
124
|
set selectedIndex(index) {
|
|
104
|
-
if (this.tabs[index]) this.tabs[index]
|
|
125
|
+
if (this.tabs[index]) attr(this.tabs[index], "aria-selected", "true");
|
|
105
126
|
}
|
|
106
127
|
};
|
|
107
128
|
var UHTMLTabElement = class extends UHTMLElement {
|
|
129
|
+
// Using ES2015 syntax for backwards compatibility
|
|
130
|
+
static get observedAttributes() {
|
|
131
|
+
return ["id", "aria-selected", ARIA_CONTROLS];
|
|
132
|
+
}
|
|
108
133
|
constructor() {
|
|
109
134
|
super();
|
|
110
135
|
attachStyle(
|
|
111
136
|
this,
|
|
112
|
-
|
|
137
|
+
":host(:not([hidden])) { cursor: pointer; display: inline-block }"
|
|
113
138
|
);
|
|
114
139
|
}
|
|
115
140
|
connectedCallback() {
|
|
141
|
+
const panelId = !attr(this, ARIA_CONTROLS) && useId(getPanel(this));
|
|
116
142
|
const selected = this.selected || ![...queryWithoutNested("u-tab", this.tabList || this)].some(isSelected);
|
|
117
|
-
this
|
|
143
|
+
attr(this, "aria-selected", `${selected}`);
|
|
144
|
+
attr(this, "role", "tab");
|
|
118
145
|
this.tabIndex = selected ? 0 : -1;
|
|
119
|
-
this
|
|
120
|
-
if (!this.hasAttribute(ARIA_CONTROLS))
|
|
121
|
-
this.setAttribute(ARIA_CONTROLS, useId(getPanel(this)));
|
|
146
|
+
if (panelId) attr(this, ARIA_CONTROLS, panelId);
|
|
122
147
|
}
|
|
123
148
|
attributeChangedCallback(name, prev) {
|
|
124
149
|
if (!this.selected) return;
|
|
125
150
|
const nextPanel = getPanel(this);
|
|
126
151
|
const nextPanelId = useId(nextPanel);
|
|
127
152
|
if (name === "aria-selected" && this.tabList)
|
|
128
|
-
queryWithoutNested("u-tab", this.tabList)
|
|
153
|
+
for (const tab of queryWithoutNested("u-tab", this.tabList)) {
|
|
129
154
|
if (tab !== this && isSelected(tab)) {
|
|
130
|
-
getPanel(tab)
|
|
131
|
-
|
|
155
|
+
const panel = getPanel(tab);
|
|
156
|
+
if (panel) panel.hidden = true;
|
|
157
|
+
attr(tab, "aria-selected", "false");
|
|
132
158
|
tab.tabIndex = -1;
|
|
133
159
|
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (this
|
|
138
|
-
this
|
|
160
|
+
}
|
|
161
|
+
const prevPanel = name === ARIA_CONTROLS && prev && getPanel(this, prev);
|
|
162
|
+
if (prevPanel) prevPanel.hidden = true;
|
|
163
|
+
if (nextPanelId && attr(this, ARIA_CONTROLS) !== nextPanelId)
|
|
164
|
+
attr(this, ARIA_CONTROLS, nextPanelId);
|
|
139
165
|
this.tabIndex = 0;
|
|
140
|
-
nextPanel
|
|
141
|
-
nextPanel
|
|
166
|
+
if (nextPanel) attr(nextPanel, SAFE_LABELLEDBY, useId(this));
|
|
167
|
+
if (nextPanel) nextPanel.hidden = false;
|
|
142
168
|
}
|
|
143
169
|
get tabsElement() {
|
|
144
170
|
return this.closest("u-tabs");
|
|
@@ -150,7 +176,7 @@ var UHTMLTabElement = class extends UHTMLElement {
|
|
|
150
176
|
return isSelected(this);
|
|
151
177
|
}
|
|
152
178
|
set selected(value) {
|
|
153
|
-
this
|
|
179
|
+
attr(this, "aria-selected", `${!!value}`);
|
|
154
180
|
}
|
|
155
181
|
/** Retrieves the ordinal position of an tab in a tablist. */
|
|
156
182
|
get index() {
|
|
@@ -161,15 +187,24 @@ var UHTMLTabElement = class extends UHTMLElement {
|
|
|
161
187
|
return getPanel(this);
|
|
162
188
|
}
|
|
163
189
|
};
|
|
164
|
-
UHTMLTabElement.observedAttributes = ["id", "aria-selected", ARIA_CONTROLS];
|
|
165
190
|
var UHTMLTabPanelElement = class extends UHTMLElement {
|
|
191
|
+
// Using ES2015 syntax for backwards compatibility
|
|
192
|
+
static get observedAttributes() {
|
|
193
|
+
return ["hidden"];
|
|
194
|
+
}
|
|
166
195
|
constructor() {
|
|
167
196
|
super();
|
|
168
197
|
attachStyle(this, DISPLAY_BLOCK);
|
|
169
198
|
}
|
|
170
199
|
connectedCallback() {
|
|
200
|
+
attr(this, "role", "tabpanel");
|
|
171
201
|
this.hidden = getSelectedIndex(this.tabs) === -1;
|
|
172
|
-
this.
|
|
202
|
+
this.attributeChangedCallback();
|
|
203
|
+
}
|
|
204
|
+
attributeChangedCallback() {
|
|
205
|
+
if (this.hidden || isFocusable(this.firstChild))
|
|
206
|
+
attr(this, "tabindex", null);
|
|
207
|
+
else this.tabIndex = 0;
|
|
173
208
|
}
|
|
174
209
|
get tabsElement() {
|
|
175
210
|
return this.closest("u-tabs");
|
|
@@ -180,16 +215,19 @@ var UHTMLTabPanelElement = class extends UHTMLElement {
|
|
|
180
215
|
return root.length ? root : document.querySelectorAll(css);
|
|
181
216
|
}
|
|
182
217
|
};
|
|
183
|
-
var queryWithoutNested = (tag, self) =>
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
var isSelected = (tab) => tab.ariaSelected === "true";
|
|
218
|
+
var queryWithoutNested = (tag, self) => self.querySelectorAll(
|
|
219
|
+
`${tag}:not(:scope ${self.nodeName}:not(:scope) ${tag})`
|
|
220
|
+
);
|
|
221
|
+
var isSelected = (tab) => attr(tab, "aria-selected") === "true";
|
|
188
222
|
var getSelectedIndex = (tabs) => [...tabs].findIndex(isSelected);
|
|
189
|
-
var
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
223
|
+
var isFocusable = (el) => el instanceof Element && !el.matches(':disabled,[tabindex^="-"]') && el.matches(
|
|
224
|
+
`[contenteditable],[controls],[href],[tabindex],input:not([type="hidden"]),select,textarea,button,summary,iframe`
|
|
225
|
+
);
|
|
226
|
+
var getPanel = (tab, id2) => {
|
|
227
|
+
const panelId = id2 || attr(tab, ARIA_CONTROLS);
|
|
228
|
+
const panelSelector = `u-tabpanel[id="${panelId}"]`;
|
|
229
|
+
const tabsElement = tab.closest("u-tabs");
|
|
230
|
+
return panelId && getRoot(tab).querySelector(panelSelector) || panelId && getRoot(tab).querySelector(panelSelector) || tabsElement && queryWithoutNested("u-tabpanel", tabsElement)[[...queryWithoutNested("u-tab", tabsElement)].indexOf(tab)] || null;
|
|
193
231
|
};
|
|
194
232
|
customElements.define("u-tabs", UHTMLTabsElement);
|
|
195
233
|
customElements.define("u-tablist", UHTMLTabListElement);
|
|
@@ -181,6 +181,11 @@
|
|
|
181
181
|
"readonly": true
|
|
182
182
|
}
|
|
183
183
|
],
|
|
184
|
+
"attributes": [
|
|
185
|
+
{
|
|
186
|
+
"name": "hidden"
|
|
187
|
+
}
|
|
188
|
+
],
|
|
184
189
|
"superclass": {
|
|
185
190
|
"name": "UHTMLElement",
|
|
186
191
|
"module": "//Users/eirikbacker/Library/Mobile%20Documents/com~apple~CloudDocs/5-capra/u-elements/packages/utils"
|
package/dist/u-tabs.vscode.json
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
{
|
|
27
27
|
"name": "u-tabpanel",
|
|
28
28
|
"description": "The `<u-tabpanel>` HTML element is a container for the resources of layered content associated with a `<u-tab>`.\n[MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tabpanel_role)\n---\n",
|
|
29
|
-
"attributes": [],
|
|
29
|
+
"attributes": [{ "name": "hidden", "values": [] }],
|
|
30
30
|
"references": []
|
|
31
31
|
}
|
|
32
32
|
]
|
package/package.json
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
2
|
+
"name": "@u-elements/u-tabs",
|
|
3
|
+
"version": "0.0.7",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "HTML tags, just truly accessible",
|
|
6
|
+
"homepage": "https://u-elements.github.io/u-elements/",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/u-tabs.cjs",
|
|
9
|
+
"module": "dist/u-tabs.js",
|
|
10
|
+
"types": "dist/u-tabs.d.ts",
|
|
11
|
+
"customElements": "dist/u-tabs.manifest.json",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/u-elements/u-elements.git"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/u-elements/u-elements/issues"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup --config ../../tsup.config.ts"
|
|
24
|
+
}
|
|
25
25
|
}
|