@u-elements/u-tabs 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,202 @@
1
+ 'use strict';
2
+
3
+ // ../utils.ts
4
+ var IS_BROWSER = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.navigator !== "undefined";
5
+ var IS_ANDROID = IS_BROWSER && /android/i.test(window.navigator.userAgent);
6
+ var ARIA_CONTROLS = "aria-controls";
7
+ var ARIA_LABELLEDBY = IS_ANDROID ? "data-labelledby" : "aria-labelledby";
8
+ var ARIA_SELECTED = "aria-selected";
9
+ var DISPLAY_BLOCK = ":host(:not([hidden])) { display: block }";
10
+ var UHTMLElement = typeof HTMLElement === "undefined" ? class {
11
+ } : HTMLElement;
12
+ var bind = (element, rest, action) => rest[0].split(",").forEach((type) => {
13
+ rest[0] = type;
14
+ Element.prototype[`${action}EventListener`].apply(element, rest);
15
+ });
16
+ var on = (element, ...rest) => bind(element, rest, "add");
17
+ var off = (element, ...rest) => bind(element, rest, "remove");
18
+ var style = (element, css) => {
19
+ const shadow = element.attachShadow({ mode: "open" });
20
+ shadow.appendChild(document.createElement("style")).textContent = css;
21
+ shadow.appendChild(document.createElement("slot"));
22
+ };
23
+ function attr(element, name, value) {
24
+ if (element instanceof Element) {
25
+ if (typeof name === "object")
26
+ Object.entries(name).map(([name2, value2]) => attr(element, name2, value2));
27
+ else if (value === void 0)
28
+ return element.getAttribute(name);
29
+ else if (value === null)
30
+ element.removeAttribute(name);
31
+ else if (element.getAttribute(name) !== `${value}`)
32
+ element.setAttribute(name, `${value}`);
33
+ }
34
+ }
35
+ var asButton = (event) => {
36
+ const isClick = "key" in event && (event.key === " " || event.key === "Enter");
37
+ if (isClick)
38
+ event.preventDefault();
39
+ if (isClick && event.target instanceof HTMLElement)
40
+ event.target.click();
41
+ return isClick;
42
+ };
43
+ var getRoot = (node) => node.getRootNode();
44
+ var id = Date.now();
45
+ var useId = (el) => el ? el.id || (el.id = `:${el.nodeName.toLowerCase()}${(++id).toString(32)}`) : void 0;
46
+ var customElements = {
47
+ define: (name, instance) => !IS_BROWSER || window.customElements.get(name) || window.customElements.define(name, instance)
48
+ };
49
+
50
+ // u-tabs.ts
51
+ var UHTMLTabsElement = class extends UHTMLElement {
52
+ connectedCallback() {
53
+ style(this, DISPLAY_BLOCK);
54
+ }
55
+ get tabList() {
56
+ return queryWithoutNested("u-tablist", this)[0] || null;
57
+ }
58
+ get selectedIndex() {
59
+ return [...this.tabs].findIndex((tab) => attr(tab, ARIA_SELECTED) === "true");
60
+ }
61
+ set selectedIndex(index) {
62
+ attr(this.tabs[index], ARIA_SELECTED, true);
63
+ }
64
+ get tabs() {
65
+ return queryWithoutNested("u-tab", this);
66
+ }
67
+ get panels() {
68
+ return queryWithoutNested("u-tabpanel", this);
69
+ }
70
+ };
71
+ var UHTMLTabListElement = class extends UHTMLElement {
72
+ connectedCallback() {
73
+ style(this, ":host(:not([hidden])) { display: flex; flex-wrap: wrap }");
74
+ attr(this, "role", "tablist");
75
+ on(this, "click,keydown", this);
76
+ }
77
+ disconnectedCallback() {
78
+ off(this, "click,keydown", this);
79
+ }
80
+ handleEvent(event) {
81
+ const { key } = event;
82
+ const tabs = [...this.getElementsByTagName("u-tab")];
83
+ let index = tabs.findIndex((tab) => tab.contains(event.target));
84
+ if (event.defaultPrevented || index === -1)
85
+ return;
86
+ if (event.type === "click")
87
+ tabs[index].selected = true;
88
+ if (event.type === "keydown" && !asButton(event)) {
89
+ if (key === "ArrowDown" || key === "ArrowRight")
90
+ index = ++index % tabs.length;
91
+ else if (key === "ArrowUp" || key === "ArrowLeft")
92
+ index = (index || tabs.length) - 1;
93
+ else if (key === "End")
94
+ index = tabs.length - 1;
95
+ else if (key === "Home")
96
+ index = 0;
97
+ else
98
+ return;
99
+ event.preventDefault();
100
+ tabs[index].focus();
101
+ }
102
+ }
103
+ get tabsElement() {
104
+ return this.closest("u-tabs");
105
+ }
106
+ };
107
+ var skipAttrChange = false;
108
+ var UHTMLTabElement = class extends UHTMLElement {
109
+ static get observedAttributes() {
110
+ return ["id", ARIA_SELECTED, ARIA_CONTROLS];
111
+ }
112
+ connectedCallback() {
113
+ style(this, `${DISPLAY_BLOCK}:host { cursor: pointer }`);
114
+ this.selected = !!this.selected;
115
+ }
116
+ attributeChangedCallback(_name, prev, next) {
117
+ if (!skipAttrChange && prev !== next && (skipAttrChange = true)) {
118
+ const { tabs = [], panels = [], selectedIndex } = this.tabsElement || {};
119
+ const selected = this.selected ? this : tabs[selectedIndex || 0] || this;
120
+ let selectedPanel;
121
+ panels.forEach((panel) => attr(panel, { [ARIA_LABELLEDBY]: null, hidden: "" }));
122
+ tabs.forEach((tab, index) => {
123
+ const tabindex = selected === tab ? 0 : -1;
124
+ const panel = getPanel(tab) || panels[index] || null;
125
+ if (!tabindex && panel)
126
+ selectedPanel = panel;
127
+ attr(tab, {
128
+ [ARIA_SELECTED]: !tabindex,
129
+ [ARIA_CONTROLS]: useId(panel),
130
+ role: "tab",
131
+ tabindex
132
+ });
133
+ attr(panel, {
134
+ [ARIA_LABELLEDBY]: useId(selectedPanel === panel ? selected : tab),
135
+ hidden: selectedPanel === panel ? null : ""
136
+ });
137
+ });
138
+ skipAttrChange = false;
139
+ }
140
+ }
141
+ get tabsElement() {
142
+ return this.closest("u-tabs");
143
+ }
144
+ get tabList() {
145
+ return this.closest("u-tablist");
146
+ }
147
+ get selected() {
148
+ return attr(this, ARIA_SELECTED) === "true";
149
+ }
150
+ set selected(value) {
151
+ attr(this, ARIA_SELECTED, !!value);
152
+ }
153
+ /** Retrieves the ordinal position of an tab in a tablist. */
154
+ get index() {
155
+ return Array.from(this.tabsElement?.tabs || []).indexOf(this);
156
+ }
157
+ get panel() {
158
+ return getPanel(this);
159
+ }
160
+ };
161
+ var UHTMLTabPanelElement = class extends UHTMLElement {
162
+ static get observedAttributes() {
163
+ return ["id"];
164
+ }
165
+ connectedCallback() {
166
+ style(this, DISPLAY_BLOCK);
167
+ attr(this, "role", "tabpanel");
168
+ this.hidden = Array.from(this.tabs).every((tab) => !tab.selected);
169
+ }
170
+ attributeChangedCallback(_name, prev, next) {
171
+ if (!skipAttrChange && prev !== next) {
172
+ Array.from(getTabs(this, prev), (tab) => attr(tab, ARIA_CONTROLS, next));
173
+ }
174
+ }
175
+ get tabsElement() {
176
+ return this.closest("u-tabs");
177
+ }
178
+ get tabs() {
179
+ return getTabs(this, this.id);
180
+ }
181
+ };
182
+ var queryWithoutNested = (tag, self) => {
183
+ const selector = `${tag}:not(:scope ${self.nodeName}:not(:scope) ${tag})`;
184
+ return self.querySelectorAll(selector);
185
+ };
186
+ var getPanel = (self) => {
187
+ const css = `u-tabpanel[id="${attr(self, ARIA_CONTROLS)}"]`;
188
+ return getRoot(self).querySelector(css) || document.querySelector(css);
189
+ };
190
+ var getTabs = (self, id2) => {
191
+ const css = `u-tab[${ARIA_CONTROLS}="${id2}"]`;
192
+ return getRoot(self).querySelectorAll(css);
193
+ };
194
+ customElements.define("u-tabs", UHTMLTabsElement);
195
+ customElements.define("u-tablist", UHTMLTabListElement);
196
+ customElements.define("u-tab", UHTMLTabElement);
197
+ customElements.define("u-tabpanel", UHTMLTabPanelElement);
198
+
199
+ exports.UHTMLTabElement = UHTMLTabElement;
200
+ exports.UHTMLTabListElement = UHTMLTabListElement;
201
+ exports.UHTMLTabPanelElement = UHTMLTabPanelElement;
202
+ exports.UHTMLTabsElement = UHTMLTabsElement;
@@ -0,0 +1,121 @@
1
+ declare const UHTMLElement: {
2
+ new (): HTMLElement;
3
+ prototype: HTMLElement;
4
+ };
5
+
6
+ declare global {
7
+ interface HTMLElementTagNameMap {
8
+ 'u-tabs': UHTMLTabsElement;
9
+ 'u-tablist': UHTMLTabListElement;
10
+ 'u-tab': UHTMLTabElement;
11
+ 'u-tabpanel': UHTMLTabPanelElement;
12
+ }
13
+ }
14
+ /**
15
+ * The `<u-tabs>` HTML element is used to group a `<u-tablist>` and several `<u-tabpanel>` elements.
16
+ * No MDN reference available.
17
+ */
18
+ declare class UHTMLTabsElement extends UHTMLElement {
19
+ connectedCallback(): void;
20
+ get tabList(): UHTMLTabListElement | null;
21
+ get selectedIndex(): number;
22
+ set selectedIndex(index: number);
23
+ get tabs(): NodeListOf<UHTMLTabElement>;
24
+ get panels(): NodeListOf<UHTMLTabPanelElement>;
25
+ }
26
+ /**
27
+ * The `<u-tablist>` HTML element serves as the container for a set of `<u-tab>` elements. The `<u-tab>` content are referred to as `<u-tabpanel>` elements.
28
+ * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tablist_role)
29
+ */
30
+ declare class UHTMLTabListElement extends UHTMLElement {
31
+ connectedCallback(): void;
32
+ disconnectedCallback(): void;
33
+ handleEvent(event: Event): void;
34
+ get tabsElement(): UHTMLTabsElement | null;
35
+ }
36
+ /**
37
+ * The `<u-tab>` HTML element is an interactive element inside a `<u-tablist>` that, when activated, displays its associated `<u-tabpanel>`.
38
+ * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tab_role)
39
+ */
40
+ declare class UHTMLTabElement extends UHTMLElement {
41
+ static get observedAttributes(): string[];
42
+ connectedCallback(): void;
43
+ attributeChangedCallback(_name: string, prev: string, next: string): void;
44
+ get tabsElement(): UHTMLTabsElement | null;
45
+ get tabList(): UHTMLTabListElement | null;
46
+ get selected(): boolean;
47
+ set selected(value: boolean);
48
+ /** Retrieves the ordinal position of an tab in a tablist. */
49
+ get index(): number;
50
+ get panel(): UHTMLTabPanelElement | null;
51
+ }
52
+ /**
53
+ * The `<u-tabpanel>` HTML element is a container for the resources of layered content associated with a `<u-tab>`.
54
+ * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tabpanel_role)
55
+ */
56
+ declare class UHTMLTabPanelElement extends UHTMLElement {
57
+ static get observedAttributes(): string[];
58
+ connectedCallback(): void;
59
+ attributeChangedCallback(_name: string, prev: string, next: string): void;
60
+ get tabsElement(): UHTMLTabsElement | null;
61
+ get tabs(): NodeListOf<UHTMLTabElement>;
62
+ }
63
+
64
+ export { UHTMLTabElement, UHTMLTabListElement, UHTMLTabPanelElement, UHTMLTabsElement };
65
+
66
+ import type * as VueJSX from '@vue/runtime-dom'
67
+ import type { JSX as QwikJSX } from '@builder.io/qwik/jsx-runtime'
68
+ import type { JSX as ReactJSX } from 'react'
69
+ import type { JSX as SolidJSX } from 'solid-js'
70
+ import type { SvelteHTMLElements } from 'svelte/elements'
71
+ export type VueTabs = VueJSX.IntrinsicElementAttributes['div']
72
+ export type QwikTabs = QwikJSX.IntrinsicElements['div']
73
+ export type ReactTabs = ReactJSX.IntrinsicElements['div']
74
+ export type SolidJSTabs = SolidJSX.HTMLElementTags['div']
75
+ export type SvelteTabs = SvelteHTMLElements['div']
76
+
77
+ // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
78
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tabs': VueTabs } }
79
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tabs': QwikTabs } } }
80
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tabs': ReactTabs } } }
81
+ declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tabs': SolidJSTabs } } }
82
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tabs': SvelteTabs } }
83
+
84
+ export type VueTablist = VueJSX.IntrinsicElementAttributes['div']
85
+ export type QwikTablist = QwikJSX.IntrinsicElements['div']
86
+ export type ReactTablist = ReactJSX.IntrinsicElements['div']
87
+ export type SolidJSTablist = SolidJSX.HTMLElementTags['div']
88
+ export type SvelteTablist = SvelteHTMLElements['div']
89
+
90
+ // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
91
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tablist': VueTablist } }
92
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tablist': QwikTablist } } }
93
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tablist': ReactTablist } } }
94
+ declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tablist': SolidJSTablist } } }
95
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tablist': SvelteTablist } }
96
+
97
+ export type VueTab = VueJSX.IntrinsicElementAttributes['div']
98
+ export type QwikTab = QwikJSX.IntrinsicElements['div']
99
+ export type ReactTab = ReactJSX.IntrinsicElements['div']
100
+ export type SolidJSTab = SolidJSX.HTMLElementTags['div']
101
+ export type SvelteTab = SvelteHTMLElements['div']
102
+
103
+ // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
104
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tab': VueTab } }
105
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tab': QwikTab } } }
106
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tab': ReactTab } } }
107
+ declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tab': SolidJSTab } } }
108
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tab': SvelteTab } }
109
+
110
+ export type VueTabpanel = VueJSX.IntrinsicElementAttributes['div']
111
+ export type QwikTabpanel = QwikJSX.IntrinsicElements['div']
112
+ export type ReactTabpanel = ReactJSX.IntrinsicElements['div']
113
+ export type SolidJSTabpanel = SolidJSX.HTMLElementTags['div']
114
+ export type SvelteTabpanel = SvelteHTMLElements['div']
115
+
116
+ // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
117
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tabpanel': VueTabpanel } }
118
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tabpanel': QwikTabpanel } } }
119
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tabpanel': ReactTabpanel } } }
120
+ declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tabpanel': SolidJSTabpanel } } }
121
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tabpanel': SvelteTabpanel } }
@@ -0,0 +1,121 @@
1
+ declare const UHTMLElement: {
2
+ new (): HTMLElement;
3
+ prototype: HTMLElement;
4
+ };
5
+
6
+ declare global {
7
+ interface HTMLElementTagNameMap {
8
+ 'u-tabs': UHTMLTabsElement;
9
+ 'u-tablist': UHTMLTabListElement;
10
+ 'u-tab': UHTMLTabElement;
11
+ 'u-tabpanel': UHTMLTabPanelElement;
12
+ }
13
+ }
14
+ /**
15
+ * The `<u-tabs>` HTML element is used to group a `<u-tablist>` and several `<u-tabpanel>` elements.
16
+ * No MDN reference available.
17
+ */
18
+ declare class UHTMLTabsElement extends UHTMLElement {
19
+ connectedCallback(): void;
20
+ get tabList(): UHTMLTabListElement | null;
21
+ get selectedIndex(): number;
22
+ set selectedIndex(index: number);
23
+ get tabs(): NodeListOf<UHTMLTabElement>;
24
+ get panels(): NodeListOf<UHTMLTabPanelElement>;
25
+ }
26
+ /**
27
+ * The `<u-tablist>` HTML element serves as the container for a set of `<u-tab>` elements. The `<u-tab>` content are referred to as `<u-tabpanel>` elements.
28
+ * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tablist_role)
29
+ */
30
+ declare class UHTMLTabListElement extends UHTMLElement {
31
+ connectedCallback(): void;
32
+ disconnectedCallback(): void;
33
+ handleEvent(event: Event): void;
34
+ get tabsElement(): UHTMLTabsElement | null;
35
+ }
36
+ /**
37
+ * The `<u-tab>` HTML element is an interactive element inside a `<u-tablist>` that, when activated, displays its associated `<u-tabpanel>`.
38
+ * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tab_role)
39
+ */
40
+ declare class UHTMLTabElement extends UHTMLElement {
41
+ static get observedAttributes(): string[];
42
+ connectedCallback(): void;
43
+ attributeChangedCallback(_name: string, prev: string, next: string): void;
44
+ get tabsElement(): UHTMLTabsElement | null;
45
+ get tabList(): UHTMLTabListElement | null;
46
+ get selected(): boolean;
47
+ set selected(value: boolean);
48
+ /** Retrieves the ordinal position of an tab in a tablist. */
49
+ get index(): number;
50
+ get panel(): UHTMLTabPanelElement | null;
51
+ }
52
+ /**
53
+ * The `<u-tabpanel>` HTML element is a container for the resources of layered content associated with a `<u-tab>`.
54
+ * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tabpanel_role)
55
+ */
56
+ declare class UHTMLTabPanelElement extends UHTMLElement {
57
+ static get observedAttributes(): string[];
58
+ connectedCallback(): void;
59
+ attributeChangedCallback(_name: string, prev: string, next: string): void;
60
+ get tabsElement(): UHTMLTabsElement | null;
61
+ get tabs(): NodeListOf<UHTMLTabElement>;
62
+ }
63
+
64
+ export { UHTMLTabElement, UHTMLTabListElement, UHTMLTabPanelElement, UHTMLTabsElement };
65
+
66
+ import type * as VueJSX from '@vue/runtime-dom'
67
+ import type { JSX as QwikJSX } from '@builder.io/qwik/jsx-runtime'
68
+ import type { JSX as ReactJSX } from 'react'
69
+ import type { JSX as SolidJSX } from 'solid-js'
70
+ import type { SvelteHTMLElements } from 'svelte/elements'
71
+ export type VueTabs = VueJSX.IntrinsicElementAttributes['div']
72
+ export type QwikTabs = QwikJSX.IntrinsicElements['div']
73
+ export type ReactTabs = ReactJSX.IntrinsicElements['div']
74
+ export type SolidJSTabs = SolidJSX.HTMLElementTags['div']
75
+ export type SvelteTabs = SvelteHTMLElements['div']
76
+
77
+ // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
78
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tabs': VueTabs } }
79
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tabs': QwikTabs } } }
80
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tabs': ReactTabs } } }
81
+ declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tabs': SolidJSTabs } } }
82
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tabs': SvelteTabs } }
83
+
84
+ export type VueTablist = VueJSX.IntrinsicElementAttributes['div']
85
+ export type QwikTablist = QwikJSX.IntrinsicElements['div']
86
+ export type ReactTablist = ReactJSX.IntrinsicElements['div']
87
+ export type SolidJSTablist = SolidJSX.HTMLElementTags['div']
88
+ export type SvelteTablist = SvelteHTMLElements['div']
89
+
90
+ // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
91
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tablist': VueTablist } }
92
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tablist': QwikTablist } } }
93
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tablist': ReactTablist } } }
94
+ declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tablist': SolidJSTablist } } }
95
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tablist': SvelteTablist } }
96
+
97
+ export type VueTab = VueJSX.IntrinsicElementAttributes['div']
98
+ export type QwikTab = QwikJSX.IntrinsicElements['div']
99
+ export type ReactTab = ReactJSX.IntrinsicElements['div']
100
+ export type SolidJSTab = SolidJSX.HTMLElementTags['div']
101
+ export type SvelteTab = SvelteHTMLElements['div']
102
+
103
+ // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
104
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tab': VueTab } }
105
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tab': QwikTab } } }
106
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tab': ReactTab } } }
107
+ declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tab': SolidJSTab } } }
108
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tab': SvelteTab } }
109
+
110
+ export type VueTabpanel = VueJSX.IntrinsicElementAttributes['div']
111
+ export type QwikTabpanel = QwikJSX.IntrinsicElements['div']
112
+ export type ReactTabpanel = ReactJSX.IntrinsicElements['div']
113
+ export type SolidJSTabpanel = SolidJSX.HTMLElementTags['div']
114
+ export type SvelteTabpanel = SvelteHTMLElements['div']
115
+
116
+ // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
117
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tabpanel': VueTabpanel } }
118
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tabpanel': QwikTabpanel } } }
119
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tabpanel': ReactTabpanel } } }
120
+ declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tabpanel': SolidJSTabpanel } } }
121
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tabpanel': SvelteTabpanel } }
package/dist/u-tabs.js ADDED
@@ -0,0 +1,197 @@
1
+ // ../utils.ts
2
+ var IS_BROWSER = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.navigator !== "undefined";
3
+ var IS_ANDROID = IS_BROWSER && /android/i.test(window.navigator.userAgent);
4
+ var ARIA_CONTROLS = "aria-controls";
5
+ var ARIA_LABELLEDBY = IS_ANDROID ? "data-labelledby" : "aria-labelledby";
6
+ var ARIA_SELECTED = "aria-selected";
7
+ var DISPLAY_BLOCK = ":host(:not([hidden])) { display: block }";
8
+ var UHTMLElement = typeof HTMLElement === "undefined" ? class {
9
+ } : HTMLElement;
10
+ var bind = (element, rest, action) => rest[0].split(",").forEach((type) => {
11
+ rest[0] = type;
12
+ Element.prototype[`${action}EventListener`].apply(element, rest);
13
+ });
14
+ var on = (element, ...rest) => bind(element, rest, "add");
15
+ var off = (element, ...rest) => bind(element, rest, "remove");
16
+ var style = (element, css) => {
17
+ const shadow = element.attachShadow({ mode: "open" });
18
+ shadow.appendChild(document.createElement("style")).textContent = css;
19
+ shadow.appendChild(document.createElement("slot"));
20
+ };
21
+ function attr(element, name, value) {
22
+ if (element instanceof Element) {
23
+ if (typeof name === "object")
24
+ Object.entries(name).map(([name2, value2]) => attr(element, name2, value2));
25
+ else if (value === void 0)
26
+ return element.getAttribute(name);
27
+ else if (value === null)
28
+ element.removeAttribute(name);
29
+ else if (element.getAttribute(name) !== `${value}`)
30
+ element.setAttribute(name, `${value}`);
31
+ }
32
+ }
33
+ var asButton = (event) => {
34
+ const isClick = "key" in event && (event.key === " " || event.key === "Enter");
35
+ if (isClick)
36
+ event.preventDefault();
37
+ if (isClick && event.target instanceof HTMLElement)
38
+ event.target.click();
39
+ return isClick;
40
+ };
41
+ var getRoot = (node) => node.getRootNode();
42
+ var id = Date.now();
43
+ var useId = (el) => el ? el.id || (el.id = `:${el.nodeName.toLowerCase()}${(++id).toString(32)}`) : void 0;
44
+ var customElements = {
45
+ define: (name, instance) => !IS_BROWSER || window.customElements.get(name) || window.customElements.define(name, instance)
46
+ };
47
+
48
+ // u-tabs.ts
49
+ var UHTMLTabsElement = class extends UHTMLElement {
50
+ connectedCallback() {
51
+ style(this, DISPLAY_BLOCK);
52
+ }
53
+ get tabList() {
54
+ return queryWithoutNested("u-tablist", this)[0] || null;
55
+ }
56
+ get selectedIndex() {
57
+ return [...this.tabs].findIndex((tab) => attr(tab, ARIA_SELECTED) === "true");
58
+ }
59
+ set selectedIndex(index) {
60
+ attr(this.tabs[index], ARIA_SELECTED, true);
61
+ }
62
+ get tabs() {
63
+ return queryWithoutNested("u-tab", this);
64
+ }
65
+ get panels() {
66
+ return queryWithoutNested("u-tabpanel", this);
67
+ }
68
+ };
69
+ var UHTMLTabListElement = class extends UHTMLElement {
70
+ connectedCallback() {
71
+ style(this, ":host(:not([hidden])) { display: flex; flex-wrap: wrap }");
72
+ attr(this, "role", "tablist");
73
+ on(this, "click,keydown", this);
74
+ }
75
+ disconnectedCallback() {
76
+ off(this, "click,keydown", this);
77
+ }
78
+ handleEvent(event) {
79
+ const { key } = event;
80
+ const tabs = [...this.getElementsByTagName("u-tab")];
81
+ let index = tabs.findIndex((tab) => tab.contains(event.target));
82
+ if (event.defaultPrevented || index === -1)
83
+ return;
84
+ if (event.type === "click")
85
+ tabs[index].selected = true;
86
+ if (event.type === "keydown" && !asButton(event)) {
87
+ if (key === "ArrowDown" || key === "ArrowRight")
88
+ index = ++index % tabs.length;
89
+ else if (key === "ArrowUp" || key === "ArrowLeft")
90
+ index = (index || tabs.length) - 1;
91
+ else if (key === "End")
92
+ index = tabs.length - 1;
93
+ else if (key === "Home")
94
+ index = 0;
95
+ else
96
+ return;
97
+ event.preventDefault();
98
+ tabs[index].focus();
99
+ }
100
+ }
101
+ get tabsElement() {
102
+ return this.closest("u-tabs");
103
+ }
104
+ };
105
+ var skipAttrChange = false;
106
+ var UHTMLTabElement = class extends UHTMLElement {
107
+ static get observedAttributes() {
108
+ return ["id", ARIA_SELECTED, ARIA_CONTROLS];
109
+ }
110
+ connectedCallback() {
111
+ style(this, `${DISPLAY_BLOCK}:host { cursor: pointer }`);
112
+ this.selected = !!this.selected;
113
+ }
114
+ attributeChangedCallback(_name, prev, next) {
115
+ if (!skipAttrChange && prev !== next && (skipAttrChange = true)) {
116
+ const { tabs = [], panels = [], selectedIndex } = this.tabsElement || {};
117
+ const selected = this.selected ? this : tabs[selectedIndex || 0] || this;
118
+ let selectedPanel;
119
+ panels.forEach((panel) => attr(panel, { [ARIA_LABELLEDBY]: null, hidden: "" }));
120
+ tabs.forEach((tab, index) => {
121
+ const tabindex = selected === tab ? 0 : -1;
122
+ const panel = getPanel(tab) || panels[index] || null;
123
+ if (!tabindex && panel)
124
+ selectedPanel = panel;
125
+ attr(tab, {
126
+ [ARIA_SELECTED]: !tabindex,
127
+ [ARIA_CONTROLS]: useId(panel),
128
+ role: "tab",
129
+ tabindex
130
+ });
131
+ attr(panel, {
132
+ [ARIA_LABELLEDBY]: useId(selectedPanel === panel ? selected : tab),
133
+ hidden: selectedPanel === panel ? null : ""
134
+ });
135
+ });
136
+ skipAttrChange = false;
137
+ }
138
+ }
139
+ get tabsElement() {
140
+ return this.closest("u-tabs");
141
+ }
142
+ get tabList() {
143
+ return this.closest("u-tablist");
144
+ }
145
+ get selected() {
146
+ return attr(this, ARIA_SELECTED) === "true";
147
+ }
148
+ set selected(value) {
149
+ attr(this, ARIA_SELECTED, !!value);
150
+ }
151
+ /** Retrieves the ordinal position of an tab in a tablist. */
152
+ get index() {
153
+ return Array.from(this.tabsElement?.tabs || []).indexOf(this);
154
+ }
155
+ get panel() {
156
+ return getPanel(this);
157
+ }
158
+ };
159
+ var UHTMLTabPanelElement = class extends UHTMLElement {
160
+ static get observedAttributes() {
161
+ return ["id"];
162
+ }
163
+ connectedCallback() {
164
+ style(this, DISPLAY_BLOCK);
165
+ attr(this, "role", "tabpanel");
166
+ this.hidden = Array.from(this.tabs).every((tab) => !tab.selected);
167
+ }
168
+ attributeChangedCallback(_name, prev, next) {
169
+ if (!skipAttrChange && prev !== next) {
170
+ Array.from(getTabs(this, prev), (tab) => attr(tab, ARIA_CONTROLS, next));
171
+ }
172
+ }
173
+ get tabsElement() {
174
+ return this.closest("u-tabs");
175
+ }
176
+ get tabs() {
177
+ return getTabs(this, this.id);
178
+ }
179
+ };
180
+ var queryWithoutNested = (tag, self) => {
181
+ const selector = `${tag}:not(:scope ${self.nodeName}:not(:scope) ${tag})`;
182
+ return self.querySelectorAll(selector);
183
+ };
184
+ var getPanel = (self) => {
185
+ const css = `u-tabpanel[id="${attr(self, ARIA_CONTROLS)}"]`;
186
+ return getRoot(self).querySelector(css) || document.querySelector(css);
187
+ };
188
+ var getTabs = (self, id2) => {
189
+ const css = `u-tab[${ARIA_CONTROLS}="${id2}"]`;
190
+ return getRoot(self).querySelectorAll(css);
191
+ };
192
+ customElements.define("u-tabs", UHTMLTabsElement);
193
+ customElements.define("u-tablist", UHTMLTabListElement);
194
+ customElements.define("u-tab", UHTMLTabElement);
195
+ customElements.define("u-tabpanel", UHTMLTabPanelElement);
196
+
197
+ export { UHTMLTabElement, UHTMLTabListElement, UHTMLTabPanelElement, UHTMLTabsElement };
@@ -0,0 +1,247 @@
1
+ {
2
+ "schemaVersion": "1.0.0",
3
+ "readme": "",
4
+ "modules": [
5
+ {
6
+ "kind": "javascript-module",
7
+ "path": "u-tabs.ts",
8
+ "declarations": [
9
+ {
10
+ "kind": "class",
11
+ "description": "The `<u-tabs>` HTML element is used to group a `<u-tablist>` and several `<u-tabpanel>` elements.\nNo MDN reference available.",
12
+ "name": "UHTMLTabsElement",
13
+ "members": [
14
+ {
15
+ "kind": "field",
16
+ "name": "tabList",
17
+ "type": {
18
+ "text": "UHTMLTabListElement | null"
19
+ },
20
+ "readonly": true
21
+ },
22
+ {
23
+ "kind": "field",
24
+ "name": "selectedIndex",
25
+ "type": {
26
+ "text": "number"
27
+ }
28
+ },
29
+ {
30
+ "kind": "field",
31
+ "name": "tabs",
32
+ "type": {
33
+ "text": "NodeListOf<UHTMLTabElement>"
34
+ },
35
+ "readonly": true
36
+ },
37
+ {
38
+ "kind": "field",
39
+ "name": "panels",
40
+ "type": {
41
+ "text": "NodeListOf<UHTMLTabPanelElement>"
42
+ },
43
+ "readonly": true
44
+ }
45
+ ],
46
+ "superclass": {
47
+ "name": "UHTMLElement",
48
+ "module": "/utils"
49
+ },
50
+ "tagName": "u-tabs",
51
+ "customElement": true
52
+ },
53
+ {
54
+ "kind": "class",
55
+ "description": "The `<u-tablist>` HTML element serves as the container for a set of `<u-tab>` elements. The `<u-tab>` content are referred to as `<u-tabpanel>` elements.\n[MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tablist_role)",
56
+ "name": "UHTMLTabListElement",
57
+ "members": [
58
+ {
59
+ "kind": "method",
60
+ "name": "handleEvent",
61
+ "parameters": [
62
+ {
63
+ "name": "event",
64
+ "type": {
65
+ "text": "Event"
66
+ }
67
+ }
68
+ ]
69
+ },
70
+ {
71
+ "kind": "field",
72
+ "name": "tabsElement",
73
+ "type": {
74
+ "text": "UHTMLTabsElement | null"
75
+ },
76
+ "readonly": true
77
+ }
78
+ ],
79
+ "superclass": {
80
+ "name": "UHTMLElement",
81
+ "module": "/utils"
82
+ },
83
+ "tagName": "u-tablist",
84
+ "customElement": true
85
+ },
86
+ {
87
+ "kind": "class",
88
+ "description": "The `<u-tab>` HTML element is an interactive element inside a `<u-tablist>` that, when activated, displays its associated `<u-tabpanel>`.\n[MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tab_role)",
89
+ "name": "UHTMLTabElement",
90
+ "members": [
91
+ {
92
+ "kind": "field",
93
+ "name": "tabsElement",
94
+ "type": {
95
+ "text": "UHTMLTabsElement | null"
96
+ },
97
+ "readonly": true
98
+ },
99
+ {
100
+ "kind": "field",
101
+ "name": "tabList",
102
+ "type": {
103
+ "text": "UHTMLTabListElement | null"
104
+ },
105
+ "readonly": true
106
+ },
107
+ {
108
+ "kind": "field",
109
+ "name": "selected",
110
+ "type": {
111
+ "text": "boolean"
112
+ }
113
+ },
114
+ {
115
+ "kind": "field",
116
+ "name": "index",
117
+ "type": {
118
+ "text": "number"
119
+ },
120
+ "description": "Retrieves the ordinal position of an tab in a tablist.",
121
+ "readonly": true
122
+ },
123
+ {
124
+ "kind": "field",
125
+ "name": "panel",
126
+ "type": {
127
+ "text": "UHTMLTabPanelElement | null"
128
+ },
129
+ "readonly": true
130
+ }
131
+ ],
132
+ "attributes": [
133
+ {
134
+ "name": "id"
135
+ }
136
+ ],
137
+ "superclass": {
138
+ "name": "UHTMLElement",
139
+ "module": "/utils"
140
+ },
141
+ "tagName": "u-tab",
142
+ "customElement": true
143
+ },
144
+ {
145
+ "kind": "class",
146
+ "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)",
147
+ "name": "UHTMLTabPanelElement",
148
+ "members": [
149
+ {
150
+ "kind": "field",
151
+ "name": "tabsElement",
152
+ "type": {
153
+ "text": "UHTMLTabsElement | null"
154
+ },
155
+ "readonly": true
156
+ },
157
+ {
158
+ "kind": "field",
159
+ "name": "tabs",
160
+ "type": {
161
+ "text": "NodeListOf<UHTMLTabElement>"
162
+ },
163
+ "readonly": true
164
+ }
165
+ ],
166
+ "attributes": [
167
+ {
168
+ "name": "id"
169
+ }
170
+ ],
171
+ "superclass": {
172
+ "name": "UHTMLElement",
173
+ "module": "/utils"
174
+ },
175
+ "tagName": "u-tabpanel",
176
+ "customElement": true
177
+ }
178
+ ],
179
+ "exports": [
180
+ {
181
+ "kind": "js",
182
+ "name": "UHTMLTabsElement",
183
+ "declaration": {
184
+ "name": "UHTMLTabsElement",
185
+ "module": "u-tabs.ts"
186
+ }
187
+ },
188
+ {
189
+ "kind": "js",
190
+ "name": "UHTMLTabListElement",
191
+ "declaration": {
192
+ "name": "UHTMLTabListElement",
193
+ "module": "u-tabs.ts"
194
+ }
195
+ },
196
+ {
197
+ "kind": "js",
198
+ "name": "UHTMLTabElement",
199
+ "declaration": {
200
+ "name": "UHTMLTabElement",
201
+ "module": "u-tabs.ts"
202
+ }
203
+ },
204
+ {
205
+ "kind": "js",
206
+ "name": "UHTMLTabPanelElement",
207
+ "declaration": {
208
+ "name": "UHTMLTabPanelElement",
209
+ "module": "u-tabs.ts"
210
+ }
211
+ },
212
+ {
213
+ "kind": "custom-element-definition",
214
+ "name": "u-tabs",
215
+ "declaration": {
216
+ "name": "UHTMLTabsElement",
217
+ "module": "u-tabs.ts"
218
+ }
219
+ },
220
+ {
221
+ "kind": "custom-element-definition",
222
+ "name": "u-tablist",
223
+ "declaration": {
224
+ "name": "UHTMLTabListElement",
225
+ "module": "u-tabs.ts"
226
+ }
227
+ },
228
+ {
229
+ "kind": "custom-element-definition",
230
+ "name": "u-tab",
231
+ "declaration": {
232
+ "name": "UHTMLTabElement",
233
+ "module": "u-tabs.ts"
234
+ }
235
+ },
236
+ {
237
+ "kind": "custom-element-definition",
238
+ "name": "u-tabpanel",
239
+ "declaration": {
240
+ "name": "UHTMLTabPanelElement",
241
+ "module": "u-tabs.ts"
242
+ }
243
+ }
244
+ ]
245
+ }
246
+ ]
247
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/microsoft/vscode-html-languageservice/main/docs/customData.schema.json",
3
+ "version": 1.1,
4
+ "tags": [
5
+ {
6
+ "name": "u-tabs",
7
+ "description": "The `<u-tabs>` HTML element is used to group a `<u-tablist>` and several `<u-tabpanel>` elements.\nNo MDN reference available.\n---\n",
8
+ "attributes": [],
9
+ "references": []
10
+ },
11
+ {
12
+ "name": "u-tablist",
13
+ "description": "The `<u-tablist>` HTML element serves as the container for a set of `<u-tab>` elements. The `<u-tab>` content are referred to as `<u-tabpanel>` elements.\n[MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tablist_role)\n---\n",
14
+ "attributes": [],
15
+ "references": []
16
+ },
17
+ {
18
+ "name": "u-tab",
19
+ "description": "The `<u-tab>` HTML element is an interactive element inside a `<u-tablist>` that, when activated, displays its associated `<u-tabpanel>`.\n[MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tab_role)\n---\n",
20
+ "attributes": [{ "name": "id", "values": [] }],
21
+ "references": []
22
+ },
23
+ {
24
+ "name": "u-tabpanel",
25
+ "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",
26
+ "attributes": [{ "name": "id", "values": [] }],
27
+ "references": []
28
+ }
29
+ ]
30
+ }
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@u-elements/u-tabs",
3
+ "version": "0.0.0",
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
+ }
package/readme.md ADDED
@@ -0,0 +1,4 @@
1
+ # &lt;u-tabs&gt;
2
+ `<u-tabs>` is not a native HTML element, but follows [ARIA best practice for tabs](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/). It lets you navigate between groups of information that appear in the same context.
3
+
4
+ [See more about accessible u-elements](https://u-elements.github.io/u-elements/)