@u-elements/u-tabs 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/u-tabs.cjs +97 -60
- package/dist/u-tabs.d.cts +4 -8
- package/dist/u-tabs.d.ts +4 -8
- package/dist/u-tabs.js +97 -60
- package/dist/u-tabs.manifest.json +2 -4
- package/dist/u-tabs.vscode.json +2 -5
- package/package.json +1 -1
package/dist/u-tabs.cjs
CHANGED
|
@@ -3,12 +3,20 @@
|
|
|
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
|
+
var _a;
|
|
6
7
|
IS_BROWSER && // @ts-expect-error Typescript has not implemented userAgentData yet https://stackoverflow.com/a/71392474
|
|
7
|
-
/^Mac/i.test(navigator.userAgentData
|
|
8
|
+
/^Mac/i.test(((_a = navigator.userAgentData) == null ? void 0 : _a.platform) || navigator.platform);
|
|
8
9
|
var SAFE_LABELLEDBY = `${IS_ANDROID ? "data" : "aria"}-labelledby`;
|
|
9
10
|
var DISPLAY_BLOCK = ":host(:not([hidden])) { display: block }";
|
|
10
11
|
var UHTMLElement = typeof HTMLElement === "undefined" ? class {
|
|
11
12
|
} : HTMLElement;
|
|
13
|
+
function attr(el, name, value) {
|
|
14
|
+
var _a2;
|
|
15
|
+
if (value === void 0) return (_a2 = el.getAttribute(name)) != null ? _a2 : null;
|
|
16
|
+
if (value === null) el.removeAttribute(name);
|
|
17
|
+
else if (el.getAttribute(name) !== value) el.setAttribute(name, value);
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
12
20
|
var events = (action, element, rest) => {
|
|
13
21
|
for (const type of rest[0].split(",")) {
|
|
14
22
|
rest[0] = type;
|
|
@@ -20,28 +28,53 @@ var off = (element, ...rest) => events("remove", element, rest);
|
|
|
20
28
|
var attachStyle = (element, css) => element.attachShadow({ mode: "open" }).append(
|
|
21
29
|
createElement("slot"),
|
|
22
30
|
// Unnamed slot does automatically render all top element nodes
|
|
23
|
-
createElement("style",
|
|
31
|
+
createElement("style", css)
|
|
24
32
|
);
|
|
33
|
+
var observers = /* @__PURE__ */ new WeakMap();
|
|
34
|
+
var mutationObserver = (element, options) => {
|
|
35
|
+
if (options === void 0) return observers.get(element);
|
|
36
|
+
try {
|
|
37
|
+
observers.get(element).disconnect();
|
|
38
|
+
observers.delete(element);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
}
|
|
41
|
+
if (options) {
|
|
42
|
+
const observer = new MutationObserver(
|
|
43
|
+
(detail) => element.handleEvent({ type: "mutation", detail })
|
|
44
|
+
);
|
|
45
|
+
observer.observe(element, options);
|
|
46
|
+
observers.set(element, observer);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
25
49
|
var asButton = (event) => {
|
|
26
50
|
const isClick = "key" in event && (event.key === " " || event.key === "Enter");
|
|
27
51
|
if (isClick) event.preventDefault();
|
|
28
52
|
if (isClick && event.target instanceof HTMLElement) event.target.click();
|
|
29
53
|
return isClick;
|
|
30
54
|
};
|
|
31
|
-
var getRoot = (node) =>
|
|
55
|
+
var getRoot = (node) => {
|
|
56
|
+
var _a2;
|
|
57
|
+
const root = ((_a2 = node.getRootNode) == null ? void 0 : _a2.call(node)) || node.ownerDocument;
|
|
58
|
+
return root instanceof Document || root instanceof ShadowRoot ? root : document;
|
|
59
|
+
};
|
|
32
60
|
var id = 0;
|
|
33
61
|
var useId = (el) => {
|
|
34
62
|
if (!el) return "";
|
|
35
63
|
if (!el.id) el.id = `:${el.nodeName.toLowerCase()}${(++id).toString(32)}`;
|
|
36
64
|
return el.id;
|
|
37
65
|
};
|
|
38
|
-
var createElement = (tagName,
|
|
66
|
+
var createElement = (tagName, text, attrs) => {
|
|
67
|
+
const el = document.createElement(tagName);
|
|
68
|
+
if (text) el.textContent = text;
|
|
69
|
+
return el;
|
|
70
|
+
};
|
|
39
71
|
var customElements = {
|
|
40
72
|
define: (name, instance) => !IS_BROWSER || window.customElements.get(name) || window.customElements.define(name, instance)
|
|
41
73
|
};
|
|
42
74
|
|
|
43
75
|
// u-tabs.ts
|
|
44
76
|
var ARIA_CONTROLS = "aria-controls";
|
|
77
|
+
var ARIA_SELECTED = "aria-selected";
|
|
45
78
|
var UHTMLTabsElement = class extends UHTMLElement {
|
|
46
79
|
constructor() {
|
|
47
80
|
super();
|
|
@@ -54,7 +87,7 @@ var UHTMLTabsElement = class extends UHTMLElement {
|
|
|
54
87
|
return getSelectedIndex(this.tabs);
|
|
55
88
|
}
|
|
56
89
|
set selectedIndex(index) {
|
|
57
|
-
|
|
90
|
+
setSelected(this.tabs[index]);
|
|
58
91
|
}
|
|
59
92
|
get tabs() {
|
|
60
93
|
return queryWithoutNested("u-tab", this);
|
|
@@ -69,19 +102,26 @@ var UHTMLTabListElement = class extends UHTMLElement {
|
|
|
69
102
|
attachStyle(this, DISPLAY_BLOCK);
|
|
70
103
|
}
|
|
71
104
|
connectedCallback() {
|
|
72
|
-
this
|
|
105
|
+
attr(this, "role", "tablist");
|
|
73
106
|
on(this, "click,keydown", this);
|
|
107
|
+
mutationObserver(this, { childList: true });
|
|
108
|
+
if (this.tabs.length) this.handleEvent();
|
|
74
109
|
}
|
|
75
110
|
disconnectedCallback() {
|
|
76
111
|
off(this, "click,keydown", this);
|
|
112
|
+
mutationObserver(this, false);
|
|
77
113
|
}
|
|
78
114
|
handleEvent(event) {
|
|
115
|
+
if (!event || event.type === "mutation") {
|
|
116
|
+
const tab = this.tabs[Math.max(this.selectedIndex, 0)];
|
|
117
|
+
return tab == null ? void 0 : tab.setAttribute(ARIA_SELECTED, "true");
|
|
118
|
+
}
|
|
79
119
|
const { key } = event;
|
|
80
|
-
const tabs = [...this.
|
|
120
|
+
const tabs = [...this.tabs];
|
|
81
121
|
const prev = tabs.findIndex((tab) => tab.contains(event.target));
|
|
82
122
|
let next = prev;
|
|
83
123
|
if (event.defaultPrevented || prev === -1) return;
|
|
84
|
-
if (event.type === "click") tabs[prev]
|
|
124
|
+
if (event.type === "click") setSelected(tabs[prev]);
|
|
85
125
|
if (event.type === "keydown" && !asButton(event)) {
|
|
86
126
|
if (key === "ArrowDown" || key === "ArrowRight")
|
|
87
127
|
next = (prev + 1) % tabs.length;
|
|
@@ -105,16 +145,21 @@ var UHTMLTabListElement = class extends UHTMLElement {
|
|
|
105
145
|
return this.closest("u-tabs");
|
|
106
146
|
}
|
|
107
147
|
get tabs() {
|
|
108
|
-
return
|
|
148
|
+
return this.querySelectorAll("u-tab");
|
|
109
149
|
}
|
|
110
150
|
get selectedIndex() {
|
|
111
151
|
return getSelectedIndex(this.tabs);
|
|
112
152
|
}
|
|
113
153
|
set selectedIndex(index) {
|
|
114
|
-
|
|
154
|
+
setSelected(this.tabs[index]);
|
|
115
155
|
}
|
|
116
156
|
};
|
|
157
|
+
var SKIP_ATTR_CHANGE = false;
|
|
117
158
|
var UHTMLTabElement = class extends UHTMLElement {
|
|
159
|
+
// Using ES2015 syntax for backwards compatibility
|
|
160
|
+
static get observedAttributes() {
|
|
161
|
+
return ["id", ARIA_SELECTED, ARIA_CONTROLS];
|
|
162
|
+
}
|
|
118
163
|
constructor() {
|
|
119
164
|
super();
|
|
120
165
|
attachStyle(
|
|
@@ -123,68 +168,65 @@ var UHTMLTabElement = class extends UHTMLElement {
|
|
|
123
168
|
);
|
|
124
169
|
}
|
|
125
170
|
connectedCallback() {
|
|
126
|
-
|
|
127
|
-
this.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (!this.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (name === ARIA_CONTROLS && prev)
|
|
146
|
-
getPanel(this, prev)?.setAttribute("hidden", "");
|
|
147
|
-
if (nextPanel && this.getAttribute(ARIA_CONTROLS) !== nextPanelId)
|
|
148
|
-
this.setAttribute(ARIA_CONTROLS, nextPanelId);
|
|
149
|
-
this.tabIndex = 0;
|
|
150
|
-
nextPanel?.setAttribute(SAFE_LABELLEDBY, useId(this));
|
|
151
|
-
nextPanel?.removeAttribute("hidden");
|
|
171
|
+
attr(this, "role", "tab");
|
|
172
|
+
this.tabIndex = this.selected ? 0 : -1;
|
|
173
|
+
}
|
|
174
|
+
attributeChangedCallback() {
|
|
175
|
+
if (!SKIP_ATTR_CHANGE && this.selected && this.tabList) {
|
|
176
|
+
SKIP_ATTR_CHANGE = true;
|
|
177
|
+
const tabs = [...this.tabList.querySelectorAll("u-tab")];
|
|
178
|
+
const panels = queryWithoutNested("u-tabpanel", this.tabsElement || this);
|
|
179
|
+
const nextPanel = getPanel(this, panels[tabs.indexOf(this)]);
|
|
180
|
+
if (nextPanel) attr(nextPanel, SAFE_LABELLEDBY, useId(this));
|
|
181
|
+
tabs.forEach((tab, index) => {
|
|
182
|
+
const panel = getPanel(tab, panels[index]);
|
|
183
|
+
tab.tabIndex = tab === this ? 0 : -1;
|
|
184
|
+
attr(tab, ARIA_SELECTED, `${tab === this}`);
|
|
185
|
+
if (panel) panel.hidden = panel !== nextPanel;
|
|
186
|
+
if (panel) attr(tab, ARIA_CONTROLS, panel.id);
|
|
187
|
+
});
|
|
188
|
+
SKIP_ATTR_CHANGE = false;
|
|
189
|
+
}
|
|
152
190
|
}
|
|
153
191
|
get tabsElement() {
|
|
154
192
|
return this.closest("u-tabs");
|
|
155
193
|
}
|
|
156
194
|
get tabList() {
|
|
157
|
-
|
|
195
|
+
const tablist = this.parentElement;
|
|
196
|
+
return (tablist == null ? void 0 : tablist.nodeName) === "U-TABLIST" ? tablist : null;
|
|
158
197
|
}
|
|
159
198
|
get selected() {
|
|
160
|
-
return
|
|
199
|
+
return attr(this, ARIA_SELECTED) === "true";
|
|
161
200
|
}
|
|
162
201
|
set selected(value) {
|
|
163
|
-
this
|
|
202
|
+
attr(this, ARIA_SELECTED, `${!!value}`);
|
|
164
203
|
}
|
|
165
204
|
/** Retrieves the ordinal position of an tab in a tablist. */
|
|
166
205
|
get index() {
|
|
167
206
|
const tabList = this.tabList;
|
|
168
|
-
return tabList ? [...
|
|
207
|
+
return tabList ? [...tabList.querySelectorAll("u-tab")].indexOf(this) : 0;
|
|
169
208
|
}
|
|
170
209
|
get panel() {
|
|
171
210
|
return getPanel(this);
|
|
172
211
|
}
|
|
173
212
|
};
|
|
174
|
-
UHTMLTabElement.observedAttributes = ["id", "aria-selected", ARIA_CONTROLS];
|
|
175
213
|
var UHTMLTabPanelElement = class extends UHTMLElement {
|
|
214
|
+
// Using ES2015 syntax for backwards compatibility
|
|
215
|
+
static get observedAttributes() {
|
|
216
|
+
return ["hidden"];
|
|
217
|
+
}
|
|
176
218
|
constructor() {
|
|
177
219
|
super();
|
|
178
220
|
attachStyle(this, DISPLAY_BLOCK);
|
|
179
221
|
}
|
|
180
222
|
connectedCallback() {
|
|
223
|
+
attr(this, "role", "tabpanel");
|
|
181
224
|
this.hidden = getSelectedIndex(this.tabs) === -1;
|
|
182
|
-
this.role = "tabpanel";
|
|
183
225
|
this.attributeChangedCallback();
|
|
184
226
|
}
|
|
185
227
|
attributeChangedCallback() {
|
|
186
|
-
if (this.hidden || isFocusable(this.
|
|
187
|
-
this
|
|
228
|
+
if (this.hidden || isFocusable(this.firstChild))
|
|
229
|
+
attr(this, "tabindex", null);
|
|
188
230
|
else this.tabIndex = 0;
|
|
189
231
|
}
|
|
190
232
|
get tabsElement() {
|
|
@@ -192,25 +234,20 @@ var UHTMLTabPanelElement = class extends UHTMLElement {
|
|
|
192
234
|
}
|
|
193
235
|
get tabs() {
|
|
194
236
|
const css = `u-tab[${ARIA_CONTROLS}="${this.id}"]`;
|
|
195
|
-
|
|
196
|
-
return root.length ? root : document.querySelectorAll(css);
|
|
237
|
+
return getRoot(this).querySelectorAll(css);
|
|
197
238
|
}
|
|
198
239
|
};
|
|
199
|
-
|
|
200
|
-
var
|
|
201
|
-
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
var getSelectedIndex = (tabs) => [...tabs].findIndex(isSelected);
|
|
205
|
-
var isFocusable = (el) => el instanceof Element && el.matches(
|
|
206
|
-
`:is([contenteditable],[controls],[href],[tabindex],input:not([type="hidden"]),select,textarea,button,summary,iframe):not(:disabled,[tabindex^="-"])`
|
|
207
|
-
);
|
|
208
|
-
var getPanel = (tab, id2) => {
|
|
209
|
-
const panelId = id2 || tab.getAttribute(ARIA_CONTROLS);
|
|
210
|
-
const panelSelector = `u-tabpanel[id="${panelId}"]`;
|
|
211
|
-
const tabsElement = tab.closest("u-tabs");
|
|
212
|
-
return panelId && getRoot(tab).querySelector(panelSelector) || panelId && getRoot(tab).querySelector(panelSelector) || tabsElement && queryWithoutNested("u-tabpanel", tabsElement)[[...queryWithoutNested("u-tab", tabsElement)].indexOf(tab)] || null;
|
|
240
|
+
var queryWithoutNested = (tag, self) => self.querySelectorAll(`${tag}:not(:scope u-tabpanel ${tag})`);
|
|
241
|
+
var getPanel = (tab, panel) => {
|
|
242
|
+
const id2 = attr(tab, ARIA_CONTROLS) || useId(panel);
|
|
243
|
+
const el = getRoot(tab).getElementById(id2);
|
|
244
|
+
return (el == null ? void 0 : el.nodeName) === "U-TABPANEL" ? el : null;
|
|
213
245
|
};
|
|
246
|
+
var getSelectedIndex = (tabs) => [...tabs].findIndex((tab) => attr(tab, ARIA_SELECTED) === "true");
|
|
247
|
+
var setSelected = (tab) => tab && attr(tab, "aria-selected", "true");
|
|
248
|
+
var isFocusable = (el) => el instanceof Element && !el.matches(':disabled,[tabindex^="-"]') && el.matches(
|
|
249
|
+
`[contenteditable],[controls],[href],[tabindex],input:not([type="hidden"]),select,textarea,button,summary,iframe`
|
|
250
|
+
);
|
|
214
251
|
customElements.define("u-tabs", UHTMLTabsElement);
|
|
215
252
|
customElements.define("u-tablist", UHTMLTabListElement);
|
|
216
253
|
customElements.define("u-tab", UHTMLTabElement);
|
package/dist/u-tabs.d.cts
CHANGED
|
@@ -31,21 +31,17 @@ declare class UHTMLTabListElement extends UHTMLElement {
|
|
|
31
31
|
constructor();
|
|
32
32
|
connectedCallback(): void;
|
|
33
33
|
disconnectedCallback(): void;
|
|
34
|
-
handleEvent(event
|
|
34
|
+
handleEvent(event?: Event): void;
|
|
35
35
|
get tabsElement(): UHTMLTabsElement | null;
|
|
36
36
|
get tabs(): NodeListOf<UHTMLTabElement>;
|
|
37
37
|
get selectedIndex(): number;
|
|
38
38
|
set selectedIndex(index: number);
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
41
|
-
* The `<u-tab>` HTML element is an interactive element inside a `<u-tablist>` that, when activated, displays its associated `<u-tabpanel>`.
|
|
42
|
-
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tab_role)
|
|
43
|
-
*/
|
|
44
40
|
declare class UHTMLTabElement extends UHTMLElement {
|
|
45
|
-
static observedAttributes: string[];
|
|
41
|
+
static get observedAttributes(): string[];
|
|
46
42
|
constructor();
|
|
47
43
|
connectedCallback(): void;
|
|
48
|
-
attributeChangedCallback(
|
|
44
|
+
attributeChangedCallback(): void;
|
|
49
45
|
get tabsElement(): UHTMLTabsElement | null;
|
|
50
46
|
get tabList(): UHTMLTabListElement | null;
|
|
51
47
|
get selected(): boolean;
|
|
@@ -59,7 +55,7 @@ declare class UHTMLTabElement extends UHTMLElement {
|
|
|
59
55
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tabpanel_role)
|
|
60
56
|
*/
|
|
61
57
|
declare class UHTMLTabPanelElement extends UHTMLElement {
|
|
62
|
-
static observedAttributes: string[];
|
|
58
|
+
static get observedAttributes(): string[];
|
|
63
59
|
constructor();
|
|
64
60
|
connectedCallback(): void;
|
|
65
61
|
attributeChangedCallback(): void;
|
package/dist/u-tabs.d.ts
CHANGED
|
@@ -31,21 +31,17 @@ declare class UHTMLTabListElement extends UHTMLElement {
|
|
|
31
31
|
constructor();
|
|
32
32
|
connectedCallback(): void;
|
|
33
33
|
disconnectedCallback(): void;
|
|
34
|
-
handleEvent(event
|
|
34
|
+
handleEvent(event?: Event): void;
|
|
35
35
|
get tabsElement(): UHTMLTabsElement | null;
|
|
36
36
|
get tabs(): NodeListOf<UHTMLTabElement>;
|
|
37
37
|
get selectedIndex(): number;
|
|
38
38
|
set selectedIndex(index: number);
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
41
|
-
* The `<u-tab>` HTML element is an interactive element inside a `<u-tablist>` that, when activated, displays its associated `<u-tabpanel>`.
|
|
42
|
-
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tab_role)
|
|
43
|
-
*/
|
|
44
40
|
declare class UHTMLTabElement extends UHTMLElement {
|
|
45
|
-
static observedAttributes: string[];
|
|
41
|
+
static get observedAttributes(): string[];
|
|
46
42
|
constructor();
|
|
47
43
|
connectedCallback(): void;
|
|
48
|
-
attributeChangedCallback(
|
|
44
|
+
attributeChangedCallback(): void;
|
|
49
45
|
get tabsElement(): UHTMLTabsElement | null;
|
|
50
46
|
get tabList(): UHTMLTabListElement | null;
|
|
51
47
|
get selected(): boolean;
|
|
@@ -59,7 +55,7 @@ declare class UHTMLTabElement extends UHTMLElement {
|
|
|
59
55
|
* [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tabpanel_role)
|
|
60
56
|
*/
|
|
61
57
|
declare class UHTMLTabPanelElement extends UHTMLElement {
|
|
62
|
-
static observedAttributes: string[];
|
|
58
|
+
static get observedAttributes(): string[];
|
|
63
59
|
constructor();
|
|
64
60
|
connectedCallback(): void;
|
|
65
61
|
attributeChangedCallback(): void;
|
package/dist/u-tabs.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
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
|
+
var _a;
|
|
4
5
|
IS_BROWSER && // @ts-expect-error Typescript has not implemented userAgentData yet https://stackoverflow.com/a/71392474
|
|
5
|
-
/^Mac/i.test(navigator.userAgentData
|
|
6
|
+
/^Mac/i.test(((_a = navigator.userAgentData) == null ? void 0 : _a.platform) || navigator.platform);
|
|
6
7
|
var SAFE_LABELLEDBY = `${IS_ANDROID ? "data" : "aria"}-labelledby`;
|
|
7
8
|
var DISPLAY_BLOCK = ":host(:not([hidden])) { display: block }";
|
|
8
9
|
var UHTMLElement = typeof HTMLElement === "undefined" ? class {
|
|
9
10
|
} : HTMLElement;
|
|
11
|
+
function attr(el, name, value) {
|
|
12
|
+
var _a2;
|
|
13
|
+
if (value === void 0) return (_a2 = el.getAttribute(name)) != null ? _a2 : null;
|
|
14
|
+
if (value === null) el.removeAttribute(name);
|
|
15
|
+
else if (el.getAttribute(name) !== value) el.setAttribute(name, value);
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
10
18
|
var events = (action, element, rest) => {
|
|
11
19
|
for (const type of rest[0].split(",")) {
|
|
12
20
|
rest[0] = type;
|
|
@@ -18,28 +26,53 @@ var off = (element, ...rest) => events("remove", element, rest);
|
|
|
18
26
|
var attachStyle = (element, css) => element.attachShadow({ mode: "open" }).append(
|
|
19
27
|
createElement("slot"),
|
|
20
28
|
// Unnamed slot does automatically render all top element nodes
|
|
21
|
-
createElement("style",
|
|
29
|
+
createElement("style", css)
|
|
22
30
|
);
|
|
31
|
+
var observers = /* @__PURE__ */ new WeakMap();
|
|
32
|
+
var mutationObserver = (element, options) => {
|
|
33
|
+
if (options === void 0) return observers.get(element);
|
|
34
|
+
try {
|
|
35
|
+
observers.get(element).disconnect();
|
|
36
|
+
observers.delete(element);
|
|
37
|
+
} catch (err) {
|
|
38
|
+
}
|
|
39
|
+
if (options) {
|
|
40
|
+
const observer = new MutationObserver(
|
|
41
|
+
(detail) => element.handleEvent({ type: "mutation", detail })
|
|
42
|
+
);
|
|
43
|
+
observer.observe(element, options);
|
|
44
|
+
observers.set(element, observer);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
23
47
|
var asButton = (event) => {
|
|
24
48
|
const isClick = "key" in event && (event.key === " " || event.key === "Enter");
|
|
25
49
|
if (isClick) event.preventDefault();
|
|
26
50
|
if (isClick && event.target instanceof HTMLElement) event.target.click();
|
|
27
51
|
return isClick;
|
|
28
52
|
};
|
|
29
|
-
var getRoot = (node) =>
|
|
53
|
+
var getRoot = (node) => {
|
|
54
|
+
var _a2;
|
|
55
|
+
const root = ((_a2 = node.getRootNode) == null ? void 0 : _a2.call(node)) || node.ownerDocument;
|
|
56
|
+
return root instanceof Document || root instanceof ShadowRoot ? root : document;
|
|
57
|
+
};
|
|
30
58
|
var id = 0;
|
|
31
59
|
var useId = (el) => {
|
|
32
60
|
if (!el) return "";
|
|
33
61
|
if (!el.id) el.id = `:${el.nodeName.toLowerCase()}${(++id).toString(32)}`;
|
|
34
62
|
return el.id;
|
|
35
63
|
};
|
|
36
|
-
var createElement = (tagName,
|
|
64
|
+
var createElement = (tagName, text, attrs) => {
|
|
65
|
+
const el = document.createElement(tagName);
|
|
66
|
+
if (text) el.textContent = text;
|
|
67
|
+
return el;
|
|
68
|
+
};
|
|
37
69
|
var customElements = {
|
|
38
70
|
define: (name, instance) => !IS_BROWSER || window.customElements.get(name) || window.customElements.define(name, instance)
|
|
39
71
|
};
|
|
40
72
|
|
|
41
73
|
// u-tabs.ts
|
|
42
74
|
var ARIA_CONTROLS = "aria-controls";
|
|
75
|
+
var ARIA_SELECTED = "aria-selected";
|
|
43
76
|
var UHTMLTabsElement = class extends UHTMLElement {
|
|
44
77
|
constructor() {
|
|
45
78
|
super();
|
|
@@ -52,7 +85,7 @@ var UHTMLTabsElement = class extends UHTMLElement {
|
|
|
52
85
|
return getSelectedIndex(this.tabs);
|
|
53
86
|
}
|
|
54
87
|
set selectedIndex(index) {
|
|
55
|
-
|
|
88
|
+
setSelected(this.tabs[index]);
|
|
56
89
|
}
|
|
57
90
|
get tabs() {
|
|
58
91
|
return queryWithoutNested("u-tab", this);
|
|
@@ -67,19 +100,26 @@ var UHTMLTabListElement = class extends UHTMLElement {
|
|
|
67
100
|
attachStyle(this, DISPLAY_BLOCK);
|
|
68
101
|
}
|
|
69
102
|
connectedCallback() {
|
|
70
|
-
this
|
|
103
|
+
attr(this, "role", "tablist");
|
|
71
104
|
on(this, "click,keydown", this);
|
|
105
|
+
mutationObserver(this, { childList: true });
|
|
106
|
+
if (this.tabs.length) this.handleEvent();
|
|
72
107
|
}
|
|
73
108
|
disconnectedCallback() {
|
|
74
109
|
off(this, "click,keydown", this);
|
|
110
|
+
mutationObserver(this, false);
|
|
75
111
|
}
|
|
76
112
|
handleEvent(event) {
|
|
113
|
+
if (!event || event.type === "mutation") {
|
|
114
|
+
const tab = this.tabs[Math.max(this.selectedIndex, 0)];
|
|
115
|
+
return tab == null ? void 0 : tab.setAttribute(ARIA_SELECTED, "true");
|
|
116
|
+
}
|
|
77
117
|
const { key } = event;
|
|
78
|
-
const tabs = [...this.
|
|
118
|
+
const tabs = [...this.tabs];
|
|
79
119
|
const prev = tabs.findIndex((tab) => tab.contains(event.target));
|
|
80
120
|
let next = prev;
|
|
81
121
|
if (event.defaultPrevented || prev === -1) return;
|
|
82
|
-
if (event.type === "click") tabs[prev]
|
|
122
|
+
if (event.type === "click") setSelected(tabs[prev]);
|
|
83
123
|
if (event.type === "keydown" && !asButton(event)) {
|
|
84
124
|
if (key === "ArrowDown" || key === "ArrowRight")
|
|
85
125
|
next = (prev + 1) % tabs.length;
|
|
@@ -103,16 +143,21 @@ var UHTMLTabListElement = class extends UHTMLElement {
|
|
|
103
143
|
return this.closest("u-tabs");
|
|
104
144
|
}
|
|
105
145
|
get tabs() {
|
|
106
|
-
return
|
|
146
|
+
return this.querySelectorAll("u-tab");
|
|
107
147
|
}
|
|
108
148
|
get selectedIndex() {
|
|
109
149
|
return getSelectedIndex(this.tabs);
|
|
110
150
|
}
|
|
111
151
|
set selectedIndex(index) {
|
|
112
|
-
|
|
152
|
+
setSelected(this.tabs[index]);
|
|
113
153
|
}
|
|
114
154
|
};
|
|
155
|
+
var SKIP_ATTR_CHANGE = false;
|
|
115
156
|
var UHTMLTabElement = class extends UHTMLElement {
|
|
157
|
+
// Using ES2015 syntax for backwards compatibility
|
|
158
|
+
static get observedAttributes() {
|
|
159
|
+
return ["id", ARIA_SELECTED, ARIA_CONTROLS];
|
|
160
|
+
}
|
|
116
161
|
constructor() {
|
|
117
162
|
super();
|
|
118
163
|
attachStyle(
|
|
@@ -121,68 +166,65 @@ var UHTMLTabElement = class extends UHTMLElement {
|
|
|
121
166
|
);
|
|
122
167
|
}
|
|
123
168
|
connectedCallback() {
|
|
124
|
-
|
|
125
|
-
this.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (!this.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (name === ARIA_CONTROLS && prev)
|
|
144
|
-
getPanel(this, prev)?.setAttribute("hidden", "");
|
|
145
|
-
if (nextPanel && this.getAttribute(ARIA_CONTROLS) !== nextPanelId)
|
|
146
|
-
this.setAttribute(ARIA_CONTROLS, nextPanelId);
|
|
147
|
-
this.tabIndex = 0;
|
|
148
|
-
nextPanel?.setAttribute(SAFE_LABELLEDBY, useId(this));
|
|
149
|
-
nextPanel?.removeAttribute("hidden");
|
|
169
|
+
attr(this, "role", "tab");
|
|
170
|
+
this.tabIndex = this.selected ? 0 : -1;
|
|
171
|
+
}
|
|
172
|
+
attributeChangedCallback() {
|
|
173
|
+
if (!SKIP_ATTR_CHANGE && this.selected && this.tabList) {
|
|
174
|
+
SKIP_ATTR_CHANGE = true;
|
|
175
|
+
const tabs = [...this.tabList.querySelectorAll("u-tab")];
|
|
176
|
+
const panels = queryWithoutNested("u-tabpanel", this.tabsElement || this);
|
|
177
|
+
const nextPanel = getPanel(this, panels[tabs.indexOf(this)]);
|
|
178
|
+
if (nextPanel) attr(nextPanel, SAFE_LABELLEDBY, useId(this));
|
|
179
|
+
tabs.forEach((tab, index) => {
|
|
180
|
+
const panel = getPanel(tab, panels[index]);
|
|
181
|
+
tab.tabIndex = tab === this ? 0 : -1;
|
|
182
|
+
attr(tab, ARIA_SELECTED, `${tab === this}`);
|
|
183
|
+
if (panel) panel.hidden = panel !== nextPanel;
|
|
184
|
+
if (panel) attr(tab, ARIA_CONTROLS, panel.id);
|
|
185
|
+
});
|
|
186
|
+
SKIP_ATTR_CHANGE = false;
|
|
187
|
+
}
|
|
150
188
|
}
|
|
151
189
|
get tabsElement() {
|
|
152
190
|
return this.closest("u-tabs");
|
|
153
191
|
}
|
|
154
192
|
get tabList() {
|
|
155
|
-
|
|
193
|
+
const tablist = this.parentElement;
|
|
194
|
+
return (tablist == null ? void 0 : tablist.nodeName) === "U-TABLIST" ? tablist : null;
|
|
156
195
|
}
|
|
157
196
|
get selected() {
|
|
158
|
-
return
|
|
197
|
+
return attr(this, ARIA_SELECTED) === "true";
|
|
159
198
|
}
|
|
160
199
|
set selected(value) {
|
|
161
|
-
this
|
|
200
|
+
attr(this, ARIA_SELECTED, `${!!value}`);
|
|
162
201
|
}
|
|
163
202
|
/** Retrieves the ordinal position of an tab in a tablist. */
|
|
164
203
|
get index() {
|
|
165
204
|
const tabList = this.tabList;
|
|
166
|
-
return tabList ? [...
|
|
205
|
+
return tabList ? [...tabList.querySelectorAll("u-tab")].indexOf(this) : 0;
|
|
167
206
|
}
|
|
168
207
|
get panel() {
|
|
169
208
|
return getPanel(this);
|
|
170
209
|
}
|
|
171
210
|
};
|
|
172
|
-
UHTMLTabElement.observedAttributes = ["id", "aria-selected", ARIA_CONTROLS];
|
|
173
211
|
var UHTMLTabPanelElement = class extends UHTMLElement {
|
|
212
|
+
// Using ES2015 syntax for backwards compatibility
|
|
213
|
+
static get observedAttributes() {
|
|
214
|
+
return ["hidden"];
|
|
215
|
+
}
|
|
174
216
|
constructor() {
|
|
175
217
|
super();
|
|
176
218
|
attachStyle(this, DISPLAY_BLOCK);
|
|
177
219
|
}
|
|
178
220
|
connectedCallback() {
|
|
221
|
+
attr(this, "role", "tabpanel");
|
|
179
222
|
this.hidden = getSelectedIndex(this.tabs) === -1;
|
|
180
|
-
this.role = "tabpanel";
|
|
181
223
|
this.attributeChangedCallback();
|
|
182
224
|
}
|
|
183
225
|
attributeChangedCallback() {
|
|
184
|
-
if (this.hidden || isFocusable(this.
|
|
185
|
-
this
|
|
226
|
+
if (this.hidden || isFocusable(this.firstChild))
|
|
227
|
+
attr(this, "tabindex", null);
|
|
186
228
|
else this.tabIndex = 0;
|
|
187
229
|
}
|
|
188
230
|
get tabsElement() {
|
|
@@ -190,25 +232,20 @@ var UHTMLTabPanelElement = class extends UHTMLElement {
|
|
|
190
232
|
}
|
|
191
233
|
get tabs() {
|
|
192
234
|
const css = `u-tab[${ARIA_CONTROLS}="${this.id}"]`;
|
|
193
|
-
|
|
194
|
-
return root.length ? root : document.querySelectorAll(css);
|
|
235
|
+
return getRoot(this).querySelectorAll(css);
|
|
195
236
|
}
|
|
196
237
|
};
|
|
197
|
-
|
|
198
|
-
var
|
|
199
|
-
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
var getSelectedIndex = (tabs) => [...tabs].findIndex(isSelected);
|
|
203
|
-
var isFocusable = (el) => el instanceof Element && el.matches(
|
|
204
|
-
`:is([contenteditable],[controls],[href],[tabindex],input:not([type="hidden"]),select,textarea,button,summary,iframe):not(:disabled,[tabindex^="-"])`
|
|
205
|
-
);
|
|
206
|
-
var getPanel = (tab, id2) => {
|
|
207
|
-
const panelId = id2 || tab.getAttribute(ARIA_CONTROLS);
|
|
208
|
-
const panelSelector = `u-tabpanel[id="${panelId}"]`;
|
|
209
|
-
const tabsElement = tab.closest("u-tabs");
|
|
210
|
-
return panelId && getRoot(tab).querySelector(panelSelector) || panelId && getRoot(tab).querySelector(panelSelector) || tabsElement && queryWithoutNested("u-tabpanel", tabsElement)[[...queryWithoutNested("u-tab", tabsElement)].indexOf(tab)] || null;
|
|
238
|
+
var queryWithoutNested = (tag, self) => self.querySelectorAll(`${tag}:not(:scope u-tabpanel ${tag})`);
|
|
239
|
+
var getPanel = (tab, panel) => {
|
|
240
|
+
const id2 = attr(tab, ARIA_CONTROLS) || useId(panel);
|
|
241
|
+
const el = getRoot(tab).getElementById(id2);
|
|
242
|
+
return (el == null ? void 0 : el.nodeName) === "U-TABPANEL" ? el : null;
|
|
211
243
|
};
|
|
244
|
+
var getSelectedIndex = (tabs) => [...tabs].findIndex((tab) => attr(tab, ARIA_SELECTED) === "true");
|
|
245
|
+
var setSelected = (tab) => tab && attr(tab, "aria-selected", "true");
|
|
246
|
+
var isFocusable = (el) => el instanceof Element && !el.matches(':disabled,[tabindex^="-"]') && el.matches(
|
|
247
|
+
`[contenteditable],[controls],[href],[tabindex],input:not([type="hidden"]),select,textarea,button,summary,iframe`
|
|
248
|
+
);
|
|
212
249
|
customElements.define("u-tabs", UHTMLTabsElement);
|
|
213
250
|
customElements.define("u-tablist", UHTMLTabListElement);
|
|
214
251
|
customElements.define("u-tab", UHTMLTabElement);
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"parameters": [
|
|
62
62
|
{
|
|
63
63
|
"name": "event",
|
|
64
|
+
"optional": true,
|
|
64
65
|
"type": {
|
|
65
66
|
"text": "Event"
|
|
66
67
|
}
|
|
@@ -100,7 +101,7 @@
|
|
|
100
101
|
},
|
|
101
102
|
{
|
|
102
103
|
"kind": "class",
|
|
103
|
-
"description": "
|
|
104
|
+
"description": "",
|
|
104
105
|
"name": "UHTMLTabElement",
|
|
105
106
|
"members": [
|
|
106
107
|
{
|
|
@@ -147,9 +148,6 @@
|
|
|
147
148
|
"attributes": [
|
|
148
149
|
{
|
|
149
150
|
"name": "id"
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
"name": "aria-selected"
|
|
153
151
|
}
|
|
154
152
|
],
|
|
155
153
|
"superclass": {
|
package/dist/u-tabs.vscode.json
CHANGED
|
@@ -16,11 +16,8 @@
|
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
"name": "u-tab",
|
|
19
|
-
"description": "
|
|
20
|
-
"attributes": [
|
|
21
|
-
{ "name": "id", "values": [] },
|
|
22
|
-
{ "name": "aria-selected", "values": [] }
|
|
23
|
-
],
|
|
19
|
+
"description": "\n---\n",
|
|
20
|
+
"attributes": [{ "name": "id", "values": [] }],
|
|
24
21
|
"references": []
|
|
25
22
|
},
|
|
26
23
|
{
|