@u-elements/u-tabs 0.0.3 → 0.0.4

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 CHANGED
@@ -43,7 +43,7 @@ var UHTMLTabsElement = class extends UHTMLElement {
43
43
  return queryWithoutNested("u-tablist", this)[0] || null;
44
44
  }
45
45
  get selectedIndex() {
46
- return [...this.tabs].findIndex((tab) => tab.ariaSelected === "true");
46
+ return getSelectedIndex(this.tabs);
47
47
  }
48
48
  set selectedIndex(index) {
49
49
  if (this.tabs[index]) this.tabs[index].ariaSelected = "true";
@@ -70,26 +70,42 @@ var UHTMLTabListElement = class extends UHTMLElement {
70
70
  handleEvent(event) {
71
71
  const { key } = event;
72
72
  const tabs = [...this.getElementsByTagName("u-tab")];
73
- let index = tabs.findIndex((tab) => tab.contains(event.target));
74
- if (event.defaultPrevented || index === -1) return;
75
- if (event.type === "click") tabs[index].selected = true;
73
+ const prev = tabs.findIndex((tab) => tab.contains(event.target));
74
+ let next = prev;
75
+ if (event.defaultPrevented || prev === -1) return;
76
+ if (event.type === "click") tabs[prev].selected = true;
76
77
  if (event.type === "keydown" && !asButton(event)) {
77
78
  if (key === "ArrowDown" || key === "ArrowRight")
78
- index = ++index % tabs.length;
79
+ next = (prev + 1) % tabs.length;
79
80
  else if (key === "ArrowUp" || key === "ArrowLeft")
80
- index = (index || tabs.length) - 1;
81
- else if (key === "End") index = tabs.length - 1;
82
- else if (key === "Home") index = 0;
81
+ next = (prev || tabs.length) - 1;
82
+ else if (key === "End") next = tabs.length - 1;
83
+ else if (key === "Home") next = 0;
84
+ else if (key === "Tab") next = getSelectedIndex(tabs);
83
85
  else return;
84
- event.preventDefault();
85
- tabs[index].focus();
86
+ setTimeout(() => {
87
+ tabs[prev].tabIndex = -1;
88
+ tabs[next].tabIndex = 0;
89
+ });
90
+ if (key !== "Tab") {
91
+ event.preventDefault();
92
+ tabs[next].focus();
93
+ }
86
94
  }
87
95
  }
88
96
  get tabsElement() {
89
97
  return this.closest("u-tabs");
90
98
  }
99
+ get tabs() {
100
+ return queryWithoutNested("u-tab", this);
101
+ }
102
+ get selectedIndex() {
103
+ return getSelectedIndex(this.tabs);
104
+ }
105
+ set selectedIndex(index) {
106
+ if (this.tabs[index]) this.tabs[index].ariaSelected = "true";
107
+ }
91
108
  };
92
- var SKIP_ATTR_CHANGE = false;
93
109
  var UHTMLTabElement = class extends UHTMLElement {
94
110
  constructor() {
95
111
  super();
@@ -99,32 +115,33 @@ var UHTMLTabElement = class extends UHTMLElement {
99
115
  );
100
116
  }
101
117
  connectedCallback() {
102
- this.selected = !!this.selected;
103
- }
104
- attributeChangedCallback(_name, prev, next) {
105
- if (!SKIP_ATTR_CHANGE && prev !== next && (SKIP_ATTR_CHANGE = true)) {
106
- const { tabs = [], panels = [], selectedIndex } = this.tabsElement || {};
107
- const selected = this.selected ? this : tabs[selectedIndex || 0] || this;
108
- let selectedPanel;
109
- panels.forEach((panel) => {
110
- panel.removeAttribute(SAFE_LABELLEDBY);
111
- panel.hidden = true;
112
- });
113
- tabs.forEach((tab, index) => {
114
- const panel = getPanel(tab) || panels[index] || null;
115
- if (selected === tab && panel) selectedPanel = panel;
116
- tab.role = "tab";
117
- tab.tabIndex = selected === tab ? 0 : -1;
118
- tab.ariaSelected = `${selected === tab}`;
119
- tab.setAttribute(ARIA_CONTROLS, useId(panel));
120
- panel?.toggleAttribute("hidden", selectedPanel !== panel);
121
- panel?.setAttribute(
122
- SAFE_LABELLEDBY,
123
- useId(selectedPanel === panel ? selected : tab)
124
- );
118
+ const selected = this.selected || [...queryWithoutNested("u-tab", this.tabList || this)].every(
119
+ (tab) => tab.ariaSelected !== "true"
120
+ );
121
+ this.role = "tab";
122
+ this.tabIndex = selected ? 0 : -1;
123
+ this.ariaSelected = `${selected}`;
124
+ }
125
+ attributeChangedCallback(name, prev) {
126
+ if (!this.selected) return;
127
+ const nextPanel = getPanel(this);
128
+ const nextPanelId = useId(nextPanel);
129
+ if (this.tabList)
130
+ queryWithoutNested("u-tab", this.tabList).forEach((tab) => {
131
+ const isUnselect = tab !== this && tab.ariaSelected === "true";
132
+ const prevPanel = isUnselect && getPanel(tab);
133
+ if (prevPanel && prevPanel !== nextPanel) prevPanel.hidden = true;
134
+ if (isUnselect) {
135
+ tab.ariaSelected = "false";
136
+ tab.tabIndex = -1;
137
+ }
125
138
  });
126
- SKIP_ATTR_CHANGE = false;
127
- }
139
+ if (name === ARIA_CONTROLS) getPanel(this, prev)?.setAttribute("hidden", "");
140
+ if (this.getAttribute(ARIA_CONTROLS) !== nextPanelId)
141
+ this.setAttribute(ARIA_CONTROLS, nextPanelId);
142
+ this.tabIndex = 0;
143
+ nextPanel?.setAttribute(SAFE_LABELLEDBY, useId(this));
144
+ nextPanel?.removeAttribute("hidden");
128
145
  }
129
146
  get tabsElement() {
130
147
  return this.closest("u-tabs");
@@ -136,11 +153,12 @@ var UHTMLTabElement = class extends UHTMLElement {
136
153
  return this.ariaSelected === "true";
137
154
  }
138
155
  set selected(value) {
139
- this.ariaSelected = `${value}`;
156
+ this.ariaSelected = `${!!value}`;
140
157
  }
141
158
  /** Retrieves the ordinal position of an tab in a tablist. */
142
159
  get index() {
143
- return Array.from(this.tabsElement?.tabs || []).indexOf(this);
160
+ const tabList = this.tabList;
161
+ return tabList ? [...queryWithoutNested("u-tab", tabList)].indexOf(this) : 0;
144
162
  }
145
163
  get panel() {
146
164
  return getPanel(this);
@@ -153,32 +171,27 @@ var UHTMLTabPanelElement = class extends UHTMLElement {
153
171
  attachStyle(this, DISPLAY_BLOCK);
154
172
  }
155
173
  connectedCallback() {
174
+ this.hidden = [...this.tabs].every((tab) => tab.ariaSelected !== "true");
156
175
  this.role = "tabpanel";
157
- this.hidden = Array.from(this.tabs).every((tab) => !tab.selected);
158
- }
159
- attributeChangedCallback(_name, prev, next) {
160
- if (SKIP_ATTR_CHANGE || prev === next) return;
161
- getTabs(this, prev).forEach((tab) => tab.setAttribute(ARIA_CONTROLS, next));
162
176
  }
163
177
  get tabsElement() {
164
178
  return this.closest("u-tabs");
165
179
  }
166
180
  get tabs() {
167
- return getTabs(this, this.id);
181
+ const css = `u-tab[${ARIA_CONTROLS}="${this.id}"]`;
182
+ const root = getRoot(this).querySelectorAll(css);
183
+ return root.length ? root : document.querySelectorAll(css);
168
184
  }
169
185
  };
170
- UHTMLTabPanelElement.observedAttributes = ["id"];
171
186
  var queryWithoutNested = (tag, self) => {
172
- const selector = `${tag}:not(:scope ${self.nodeName}:not(:scope) ${tag})`;
173
- return self.querySelectorAll(selector);
174
- };
175
- var getPanel = (self) => {
176
- const css = `u-tabpanel[id="${self.getAttribute(ARIA_CONTROLS)}"]`;
177
- return getRoot(self).querySelector(css) || document.querySelector(css);
187
+ const css = `${tag}:not(:scope ${self.nodeName}:not(:scope) ${tag})`;
188
+ return self.querySelectorAll(css);
178
189
  };
179
- var getTabs = (self, id2) => {
180
- const css = `u-tab[${ARIA_CONTROLS}="${id2}"]`;
181
- return getRoot(self).querySelectorAll(css);
190
+ var getSelectedIndex = (tabs) => [...tabs].findIndex((tab) => tab.ariaSelected === "true");
191
+ var getPanel = (self, id2) => {
192
+ const css = `u-tabpanel[id="${id2 || self.getAttribute(ARIA_CONTROLS)}"]`;
193
+ const tabsElement = self.closest("u-tabs");
194
+ return getRoot(self).querySelector(css) || document.querySelector(css) || tabsElement && queryWithoutNested("u-tabpanel", tabsElement)[[...queryWithoutNested("u-tab", tabsElement)].indexOf(self)] || null;
182
195
  };
183
196
  customElements.define("u-tabs", UHTMLTabsElement);
184
197
  customElements.define("u-tablist", UHTMLTabListElement);
package/dist/u-tabs.d.cts CHANGED
@@ -33,6 +33,9 @@ declare class UHTMLTabListElement extends UHTMLElement {
33
33
  disconnectedCallback(): void;
34
34
  handleEvent(event: Event): void;
35
35
  get tabsElement(): UHTMLTabsElement | null;
36
+ get tabs(): NodeListOf<UHTMLTabElement>;
37
+ get selectedIndex(): number;
38
+ set selectedIndex(index: number);
36
39
  }
37
40
  /**
38
41
  * The `<u-tab>` HTML element is an interactive element inside a `<u-tablist>` that, when activated, displays its associated `<u-tabpanel>`.
@@ -42,7 +45,7 @@ declare class UHTMLTabElement extends UHTMLElement {
42
45
  static observedAttributes: string[];
43
46
  constructor();
44
47
  connectedCallback(): void;
45
- attributeChangedCallback(_name: string, prev: string, next: string): void;
48
+ attributeChangedCallback(name: string, prev: string): void;
46
49
  get tabsElement(): UHTMLTabsElement | null;
47
50
  get tabList(): UHTMLTabListElement | null;
48
51
  get selected(): boolean;
@@ -56,66 +59,95 @@ declare class UHTMLTabElement extends UHTMLElement {
56
59
  * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tabpanel_role)
57
60
  */
58
61
  declare class UHTMLTabPanelElement extends UHTMLElement {
59
- static observedAttributes: string[];
60
62
  constructor();
61
63
  connectedCallback(): void;
62
- attributeChangedCallback(_name: string, prev: string, next: string): void;
63
64
  get tabsElement(): UHTMLTabsElement | null;
64
65
  get tabs(): NodeListOf<UHTMLTabElement>;
65
66
  }
66
67
 
67
68
  export { UHTMLTabElement, UHTMLTabListElement, UHTMLTabPanelElement, UHTMLTabsElement };
69
+
70
+ import type * as PreactTypes from 'preact'
71
+ import type * as ReactTypes from 'react'
72
+ import type * as SvelteTypes from 'svelte/elements'
68
73
  import type * as VueJSX from '@vue/runtime-dom'
69
74
  import type { JSX as QwikJSX } from '@builder.io/qwik/jsx-runtime'
70
- import type { JSX as ReactJSX } from 'react'
71
75
  import type { JSX as SolidJSX } from 'solid-js'
72
- import type { SvelteHTMLElements } from 'svelte/elements'
73
76
 
74
- export type VueTabs = VueJSX.IntrinsicElementAttributes['div']
75
- export type QwikTabs = QwikJSX.IntrinsicElements['div']
76
- export type ReactTabs = ReactJSX.IntrinsicElements['div'] & { class?: string }
77
- export type SolidJSTabs = SolidJSX.HTMLElementTags['div']
78
- export type SvelteTabs = SvelteHTMLElements['div']
77
+
78
+ export type PreactUtabs = PreactTypes.JSX.HTMLAttributes<UHTMLTagsElement> & { }
79
+ export type ReactUtabs = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<UHTMLTabsElement>, UHTMLTabsElement> & { class?: string }
80
+ export type QwikUtabs = QwikJSX.IntrinsicElements['div']
81
+ export type VueUtabs = VueJSX.HTMLAttributes
82
+ export type SvelteUtabs = SvelteTypes.HTMLAttributes<UHTMLTabsElement> & { }
83
+ export type SolidUtabs = SolidJSX.HTMLAttributes<UHTMLTabsElement>
79
84
 
80
85
  // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
81
- declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tabs': VueTabs } }
82
- declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tabs': QwikTabs } } }
83
- declare global { namespace React.JSX { interface IntrinsicElements { 'u-tabs': ReactTabs } } }
84
- declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tabs': SolidJSTabs } } }
85
- declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tabs': SvelteTabs } }
86
- export type VueTablist = VueJSX.IntrinsicElementAttributes['div']
87
- export type QwikTablist = QwikJSX.IntrinsicElements['div']
88
- export type ReactTablist = ReactJSX.IntrinsicElements['div'] & { class?: string }
89
- export type SolidJSTablist = SolidJSX.HTMLElementTags['div']
90
- export type SvelteTablist = SvelteHTMLElements['div']
86
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tabs': ReactUtabs } } }
87
+ declare global { namespace preact.JSX { interface IntrinsicElements { 'u-tabs': PreactUtabs } } }
88
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tabs': QwikUtabs } } }
89
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tabs': VueUtabs } }
90
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tabs': SvelteUtabs } }
91
+ declare module 'solid-js' {
92
+ namespace JSX {
93
+ interface IntrinsicElements { 'u-tabs': SolidUtabs }
94
+ interface CustomEvents { }
95
+ }
96
+ }
97
+ export type PreactUtablist = PreactTypes.JSX.HTMLAttributes<UHTMLTagsElement> & { }
98
+ export type ReactUtablist = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<UHTMLTabListElement>, UHTMLTabListElement> & { class?: string }
99
+ export type QwikUtablist = QwikJSX.IntrinsicElements['div']
100
+ export type VueUtablist = VueJSX.HTMLAttributes
101
+ export type SvelteUtablist = SvelteTypes.HTMLAttributes<UHTMLTabListElement> & { }
102
+ export type SolidUtablist = SolidJSX.HTMLAttributes<UHTMLTabListElement>
91
103
 
92
104
  // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
93
- declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tablist': VueTablist } }
94
- declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tablist': QwikTablist } } }
95
- declare global { namespace React.JSX { interface IntrinsicElements { 'u-tablist': ReactTablist } } }
96
- declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tablist': SolidJSTablist } } }
97
- declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tablist': SvelteTablist } }
98
- export type VueTab = VueJSX.IntrinsicElementAttributes['div']
99
- export type QwikTab = QwikJSX.IntrinsicElements['div']
100
- export type ReactTab = ReactJSX.IntrinsicElements['div'] & { class?: string }
101
- export type SolidJSTab = SolidJSX.HTMLElementTags['div']
102
- export type SvelteTab = SvelteHTMLElements['div']
105
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tablist': ReactUtablist } } }
106
+ declare global { namespace preact.JSX { interface IntrinsicElements { 'u-tablist': PreactUtablist } } }
107
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tablist': QwikUtablist } } }
108
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tablist': VueUtablist } }
109
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tablist': SvelteUtablist } }
110
+ declare module 'solid-js' {
111
+ namespace JSX {
112
+ interface IntrinsicElements { 'u-tablist': SolidUtablist }
113
+ interface CustomEvents { }
114
+ }
115
+ }
116
+ export type PreactUtab = PreactTypes.JSX.HTMLAttributes<UHTMLTagsElement> & { }
117
+ export type ReactUtab = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<UHTMLTabElement>, UHTMLTabElement> & { class?: string }
118
+ export type QwikUtab = QwikJSX.IntrinsicElements['div']
119
+ export type VueUtab = VueJSX.HTMLAttributes
120
+ export type SvelteUtab = SvelteTypes.HTMLAttributes<UHTMLTabElement> & { }
121
+ export type SolidUtab = SolidJSX.HTMLAttributes<UHTMLTabElement>
103
122
 
104
123
  // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
105
- declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tab': VueTab } }
106
- declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tab': QwikTab } } }
107
- declare global { namespace React.JSX { interface IntrinsicElements { 'u-tab': ReactTab } } }
108
- declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tab': SolidJSTab } } }
109
- declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tab': SvelteTab } }
110
- export type VueTabpanel = VueJSX.IntrinsicElementAttributes['div']
111
- export type QwikTabpanel = QwikJSX.IntrinsicElements['div']
112
- export type ReactTabpanel = ReactJSX.IntrinsicElements['div'] & { class?: string }
113
- export type SolidJSTabpanel = SolidJSX.HTMLElementTags['div']
114
- export type SvelteTabpanel = SvelteHTMLElements['div']
124
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tab': ReactUtab } } }
125
+ declare global { namespace preact.JSX { interface IntrinsicElements { 'u-tab': PreactUtab } } }
126
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tab': QwikUtab } } }
127
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tab': VueUtab } }
128
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tab': SvelteUtab } }
129
+ declare module 'solid-js' {
130
+ namespace JSX {
131
+ interface IntrinsicElements { 'u-tab': SolidUtab }
132
+ interface CustomEvents { }
133
+ }
134
+ }
135
+ export type PreactUtabpanel = PreactTypes.JSX.HTMLAttributes<UHTMLTagsElement> & { }
136
+ export type ReactUtabpanel = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<UHTMLTabPanelElement>, UHTMLTabPanelElement> & { class?: string }
137
+ export type QwikUtabpanel = QwikJSX.IntrinsicElements['div']
138
+ export type VueUtabpanel = VueJSX.HTMLAttributes
139
+ export type SvelteUtabpanel = SvelteTypes.HTMLAttributes<UHTMLTabPanelElement> & { }
140
+ export type SolidUtabpanel = SolidJSX.HTMLAttributes<UHTMLTabPanelElement>
115
141
 
116
142
  // 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 } }
143
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tabpanel': ReactUtabpanel } } }
144
+ declare global { namespace preact.JSX { interface IntrinsicElements { 'u-tabpanel': PreactUtabpanel } } }
145
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tabpanel': QwikUtabpanel } } }
146
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tabpanel': VueUtabpanel } }
147
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tabpanel': SvelteUtabpanel } }
148
+ declare module 'solid-js' {
149
+ namespace JSX {
150
+ interface IntrinsicElements { 'u-tabpanel': SolidUtabpanel }
151
+ interface CustomEvents { }
152
+ }
153
+ }
package/dist/u-tabs.d.ts CHANGED
@@ -33,6 +33,9 @@ declare class UHTMLTabListElement extends UHTMLElement {
33
33
  disconnectedCallback(): void;
34
34
  handleEvent(event: Event): void;
35
35
  get tabsElement(): UHTMLTabsElement | null;
36
+ get tabs(): NodeListOf<UHTMLTabElement>;
37
+ get selectedIndex(): number;
38
+ set selectedIndex(index: number);
36
39
  }
37
40
  /**
38
41
  * The `<u-tab>` HTML element is an interactive element inside a `<u-tablist>` that, when activated, displays its associated `<u-tabpanel>`.
@@ -42,7 +45,7 @@ declare class UHTMLTabElement extends UHTMLElement {
42
45
  static observedAttributes: string[];
43
46
  constructor();
44
47
  connectedCallback(): void;
45
- attributeChangedCallback(_name: string, prev: string, next: string): void;
48
+ attributeChangedCallback(name: string, prev: string): void;
46
49
  get tabsElement(): UHTMLTabsElement | null;
47
50
  get tabList(): UHTMLTabListElement | null;
48
51
  get selected(): boolean;
@@ -56,66 +59,95 @@ declare class UHTMLTabElement extends UHTMLElement {
56
59
  * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tabpanel_role)
57
60
  */
58
61
  declare class UHTMLTabPanelElement extends UHTMLElement {
59
- static observedAttributes: string[];
60
62
  constructor();
61
63
  connectedCallback(): void;
62
- attributeChangedCallback(_name: string, prev: string, next: string): void;
63
64
  get tabsElement(): UHTMLTabsElement | null;
64
65
  get tabs(): NodeListOf<UHTMLTabElement>;
65
66
  }
66
67
 
67
68
  export { UHTMLTabElement, UHTMLTabListElement, UHTMLTabPanelElement, UHTMLTabsElement };
69
+
70
+ import type * as PreactTypes from 'preact'
71
+ import type * as ReactTypes from 'react'
72
+ import type * as SvelteTypes from 'svelte/elements'
68
73
  import type * as VueJSX from '@vue/runtime-dom'
69
74
  import type { JSX as QwikJSX } from '@builder.io/qwik/jsx-runtime'
70
- import type { JSX as ReactJSX } from 'react'
71
75
  import type { JSX as SolidJSX } from 'solid-js'
72
- import type { SvelteHTMLElements } from 'svelte/elements'
73
76
 
74
- export type VueTabs = VueJSX.IntrinsicElementAttributes['div']
75
- export type QwikTabs = QwikJSX.IntrinsicElements['div']
76
- export type ReactTabs = ReactJSX.IntrinsicElements['div'] & { class?: string }
77
- export type SolidJSTabs = SolidJSX.HTMLElementTags['div']
78
- export type SvelteTabs = SvelteHTMLElements['div']
77
+
78
+ export type PreactUtabs = PreactTypes.JSX.HTMLAttributes<UHTMLTagsElement> & { }
79
+ export type ReactUtabs = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<UHTMLTabsElement>, UHTMLTabsElement> & { class?: string }
80
+ export type QwikUtabs = QwikJSX.IntrinsicElements['div']
81
+ export type VueUtabs = VueJSX.HTMLAttributes
82
+ export type SvelteUtabs = SvelteTypes.HTMLAttributes<UHTMLTabsElement> & { }
83
+ export type SolidUtabs = SolidJSX.HTMLAttributes<UHTMLTabsElement>
79
84
 
80
85
  // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
81
- declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tabs': VueTabs } }
82
- declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tabs': QwikTabs } } }
83
- declare global { namespace React.JSX { interface IntrinsicElements { 'u-tabs': ReactTabs } } }
84
- declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tabs': SolidJSTabs } } }
85
- declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tabs': SvelteTabs } }
86
- export type VueTablist = VueJSX.IntrinsicElementAttributes['div']
87
- export type QwikTablist = QwikJSX.IntrinsicElements['div']
88
- export type ReactTablist = ReactJSX.IntrinsicElements['div'] & { class?: string }
89
- export type SolidJSTablist = SolidJSX.HTMLElementTags['div']
90
- export type SvelteTablist = SvelteHTMLElements['div']
86
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tabs': ReactUtabs } } }
87
+ declare global { namespace preact.JSX { interface IntrinsicElements { 'u-tabs': PreactUtabs } } }
88
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tabs': QwikUtabs } } }
89
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tabs': VueUtabs } }
90
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tabs': SvelteUtabs } }
91
+ declare module 'solid-js' {
92
+ namespace JSX {
93
+ interface IntrinsicElements { 'u-tabs': SolidUtabs }
94
+ interface CustomEvents { }
95
+ }
96
+ }
97
+ export type PreactUtablist = PreactTypes.JSX.HTMLAttributes<UHTMLTagsElement> & { }
98
+ export type ReactUtablist = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<UHTMLTabListElement>, UHTMLTabListElement> & { class?: string }
99
+ export type QwikUtablist = QwikJSX.IntrinsicElements['div']
100
+ export type VueUtablist = VueJSX.HTMLAttributes
101
+ export type SvelteUtablist = SvelteTypes.HTMLAttributes<UHTMLTabListElement> & { }
102
+ export type SolidUtablist = SolidJSX.HTMLAttributes<UHTMLTabListElement>
91
103
 
92
104
  // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
93
- declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tablist': VueTablist } }
94
- declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tablist': QwikTablist } } }
95
- declare global { namespace React.JSX { interface IntrinsicElements { 'u-tablist': ReactTablist } } }
96
- declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tablist': SolidJSTablist } } }
97
- declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tablist': SvelteTablist } }
98
- export type VueTab = VueJSX.IntrinsicElementAttributes['div']
99
- export type QwikTab = QwikJSX.IntrinsicElements['div']
100
- export type ReactTab = ReactJSX.IntrinsicElements['div'] & { class?: string }
101
- export type SolidJSTab = SolidJSX.HTMLElementTags['div']
102
- export type SvelteTab = SvelteHTMLElements['div']
105
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tablist': ReactUtablist } } }
106
+ declare global { namespace preact.JSX { interface IntrinsicElements { 'u-tablist': PreactUtablist } } }
107
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tablist': QwikUtablist } } }
108
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tablist': VueUtablist } }
109
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tablist': SvelteUtablist } }
110
+ declare module 'solid-js' {
111
+ namespace JSX {
112
+ interface IntrinsicElements { 'u-tablist': SolidUtablist }
113
+ interface CustomEvents { }
114
+ }
115
+ }
116
+ export type PreactUtab = PreactTypes.JSX.HTMLAttributes<UHTMLTagsElement> & { }
117
+ export type ReactUtab = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<UHTMLTabElement>, UHTMLTabElement> & { class?: string }
118
+ export type QwikUtab = QwikJSX.IntrinsicElements['div']
119
+ export type VueUtab = VueJSX.HTMLAttributes
120
+ export type SvelteUtab = SvelteTypes.HTMLAttributes<UHTMLTabElement> & { }
121
+ export type SolidUtab = SolidJSX.HTMLAttributes<UHTMLTabElement>
103
122
 
104
123
  // Augmenting @vue/runtime-dom instead of vue directly to avoid interfering with React JSX
105
- declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tab': VueTab } }
106
- declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tab': QwikTab } } }
107
- declare global { namespace React.JSX { interface IntrinsicElements { 'u-tab': ReactTab } } }
108
- declare module 'solid-js' { namespace JSX { interface IntrinsicElements { 'u-tab': SolidJSTab } } }
109
- declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tab': SvelteTab } }
110
- export type VueTabpanel = VueJSX.IntrinsicElementAttributes['div']
111
- export type QwikTabpanel = QwikJSX.IntrinsicElements['div']
112
- export type ReactTabpanel = ReactJSX.IntrinsicElements['div'] & { class?: string }
113
- export type SolidJSTabpanel = SolidJSX.HTMLElementTags['div']
114
- export type SvelteTabpanel = SvelteHTMLElements['div']
124
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tab': ReactUtab } } }
125
+ declare global { namespace preact.JSX { interface IntrinsicElements { 'u-tab': PreactUtab } } }
126
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tab': QwikUtab } } }
127
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tab': VueUtab } }
128
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tab': SvelteUtab } }
129
+ declare module 'solid-js' {
130
+ namespace JSX {
131
+ interface IntrinsicElements { 'u-tab': SolidUtab }
132
+ interface CustomEvents { }
133
+ }
134
+ }
135
+ export type PreactUtabpanel = PreactTypes.JSX.HTMLAttributes<UHTMLTagsElement> & { }
136
+ export type ReactUtabpanel = ReactTypes.DetailedHTMLProps<ReactTypes.HTMLAttributes<UHTMLTabPanelElement>, UHTMLTabPanelElement> & { class?: string }
137
+ export type QwikUtabpanel = QwikJSX.IntrinsicElements['div']
138
+ export type VueUtabpanel = VueJSX.HTMLAttributes
139
+ export type SvelteUtabpanel = SvelteTypes.HTMLAttributes<UHTMLTabPanelElement> & { }
140
+ export type SolidUtabpanel = SolidJSX.HTMLAttributes<UHTMLTabPanelElement>
115
141
 
116
142
  // 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 } }
143
+ declare global { namespace React.JSX { interface IntrinsicElements { 'u-tabpanel': ReactUtabpanel } } }
144
+ declare global { namespace preact.JSX { interface IntrinsicElements { 'u-tabpanel': PreactUtabpanel } } }
145
+ declare module '@builder.io/qwik/jsx-runtime' { export namespace JSX { export interface IntrinsicElements { 'u-tabpanel': QwikUtabpanel } } }
146
+ declare module '@vue/runtime-dom' { export interface GlobalComponents { 'u-tabpanel': VueUtabpanel } }
147
+ declare module 'svelte/elements' { interface SvelteHTMLElements { 'u-tabpanel': SvelteUtabpanel } }
148
+ declare module 'solid-js' {
149
+ namespace JSX {
150
+ interface IntrinsicElements { 'u-tabpanel': SolidUtabpanel }
151
+ interface CustomEvents { }
152
+ }
153
+ }
package/dist/u-tabs.js CHANGED
@@ -41,7 +41,7 @@ var UHTMLTabsElement = class extends UHTMLElement {
41
41
  return queryWithoutNested("u-tablist", this)[0] || null;
42
42
  }
43
43
  get selectedIndex() {
44
- return [...this.tabs].findIndex((tab) => tab.ariaSelected === "true");
44
+ return getSelectedIndex(this.tabs);
45
45
  }
46
46
  set selectedIndex(index) {
47
47
  if (this.tabs[index]) this.tabs[index].ariaSelected = "true";
@@ -68,26 +68,42 @@ var UHTMLTabListElement = class extends UHTMLElement {
68
68
  handleEvent(event) {
69
69
  const { key } = event;
70
70
  const tabs = [...this.getElementsByTagName("u-tab")];
71
- let index = tabs.findIndex((tab) => tab.contains(event.target));
72
- if (event.defaultPrevented || index === -1) return;
73
- if (event.type === "click") tabs[index].selected = true;
71
+ const prev = tabs.findIndex((tab) => tab.contains(event.target));
72
+ let next = prev;
73
+ if (event.defaultPrevented || prev === -1) return;
74
+ if (event.type === "click") tabs[prev].selected = true;
74
75
  if (event.type === "keydown" && !asButton(event)) {
75
76
  if (key === "ArrowDown" || key === "ArrowRight")
76
- index = ++index % tabs.length;
77
+ next = (prev + 1) % tabs.length;
77
78
  else if (key === "ArrowUp" || key === "ArrowLeft")
78
- index = (index || tabs.length) - 1;
79
- else if (key === "End") index = tabs.length - 1;
80
- else if (key === "Home") index = 0;
79
+ next = (prev || tabs.length) - 1;
80
+ else if (key === "End") next = tabs.length - 1;
81
+ else if (key === "Home") next = 0;
82
+ else if (key === "Tab") next = getSelectedIndex(tabs);
81
83
  else return;
82
- event.preventDefault();
83
- tabs[index].focus();
84
+ setTimeout(() => {
85
+ tabs[prev].tabIndex = -1;
86
+ tabs[next].tabIndex = 0;
87
+ });
88
+ if (key !== "Tab") {
89
+ event.preventDefault();
90
+ tabs[next].focus();
91
+ }
84
92
  }
85
93
  }
86
94
  get tabsElement() {
87
95
  return this.closest("u-tabs");
88
96
  }
97
+ get tabs() {
98
+ return queryWithoutNested("u-tab", this);
99
+ }
100
+ get selectedIndex() {
101
+ return getSelectedIndex(this.tabs);
102
+ }
103
+ set selectedIndex(index) {
104
+ if (this.tabs[index]) this.tabs[index].ariaSelected = "true";
105
+ }
89
106
  };
90
- var SKIP_ATTR_CHANGE = false;
91
107
  var UHTMLTabElement = class extends UHTMLElement {
92
108
  constructor() {
93
109
  super();
@@ -97,32 +113,33 @@ var UHTMLTabElement = class extends UHTMLElement {
97
113
  );
98
114
  }
99
115
  connectedCallback() {
100
- this.selected = !!this.selected;
101
- }
102
- attributeChangedCallback(_name, prev, next) {
103
- if (!SKIP_ATTR_CHANGE && prev !== next && (SKIP_ATTR_CHANGE = true)) {
104
- const { tabs = [], panels = [], selectedIndex } = this.tabsElement || {};
105
- const selected = this.selected ? this : tabs[selectedIndex || 0] || this;
106
- let selectedPanel;
107
- panels.forEach((panel) => {
108
- panel.removeAttribute(SAFE_LABELLEDBY);
109
- panel.hidden = true;
110
- });
111
- tabs.forEach((tab, index) => {
112
- const panel = getPanel(tab) || panels[index] || null;
113
- if (selected === tab && panel) selectedPanel = panel;
114
- tab.role = "tab";
115
- tab.tabIndex = selected === tab ? 0 : -1;
116
- tab.ariaSelected = `${selected === tab}`;
117
- tab.setAttribute(ARIA_CONTROLS, useId(panel));
118
- panel?.toggleAttribute("hidden", selectedPanel !== panel);
119
- panel?.setAttribute(
120
- SAFE_LABELLEDBY,
121
- useId(selectedPanel === panel ? selected : tab)
122
- );
116
+ const selected = this.selected || [...queryWithoutNested("u-tab", this.tabList || this)].every(
117
+ (tab) => tab.ariaSelected !== "true"
118
+ );
119
+ this.role = "tab";
120
+ this.tabIndex = selected ? 0 : -1;
121
+ this.ariaSelected = `${selected}`;
122
+ }
123
+ attributeChangedCallback(name, prev) {
124
+ if (!this.selected) return;
125
+ const nextPanel = getPanel(this);
126
+ const nextPanelId = useId(nextPanel);
127
+ if (this.tabList)
128
+ queryWithoutNested("u-tab", this.tabList).forEach((tab) => {
129
+ const isUnselect = tab !== this && tab.ariaSelected === "true";
130
+ const prevPanel = isUnselect && getPanel(tab);
131
+ if (prevPanel && prevPanel !== nextPanel) prevPanel.hidden = true;
132
+ if (isUnselect) {
133
+ tab.ariaSelected = "false";
134
+ tab.tabIndex = -1;
135
+ }
123
136
  });
124
- SKIP_ATTR_CHANGE = false;
125
- }
137
+ if (name === ARIA_CONTROLS) getPanel(this, prev)?.setAttribute("hidden", "");
138
+ if (this.getAttribute(ARIA_CONTROLS) !== nextPanelId)
139
+ this.setAttribute(ARIA_CONTROLS, nextPanelId);
140
+ this.tabIndex = 0;
141
+ nextPanel?.setAttribute(SAFE_LABELLEDBY, useId(this));
142
+ nextPanel?.removeAttribute("hidden");
126
143
  }
127
144
  get tabsElement() {
128
145
  return this.closest("u-tabs");
@@ -134,11 +151,12 @@ var UHTMLTabElement = class extends UHTMLElement {
134
151
  return this.ariaSelected === "true";
135
152
  }
136
153
  set selected(value) {
137
- this.ariaSelected = `${value}`;
154
+ this.ariaSelected = `${!!value}`;
138
155
  }
139
156
  /** Retrieves the ordinal position of an tab in a tablist. */
140
157
  get index() {
141
- return Array.from(this.tabsElement?.tabs || []).indexOf(this);
158
+ const tabList = this.tabList;
159
+ return tabList ? [...queryWithoutNested("u-tab", tabList)].indexOf(this) : 0;
142
160
  }
143
161
  get panel() {
144
162
  return getPanel(this);
@@ -151,32 +169,27 @@ var UHTMLTabPanelElement = class extends UHTMLElement {
151
169
  attachStyle(this, DISPLAY_BLOCK);
152
170
  }
153
171
  connectedCallback() {
172
+ this.hidden = [...this.tabs].every((tab) => tab.ariaSelected !== "true");
154
173
  this.role = "tabpanel";
155
- this.hidden = Array.from(this.tabs).every((tab) => !tab.selected);
156
- }
157
- attributeChangedCallback(_name, prev, next) {
158
- if (SKIP_ATTR_CHANGE || prev === next) return;
159
- getTabs(this, prev).forEach((tab) => tab.setAttribute(ARIA_CONTROLS, next));
160
174
  }
161
175
  get tabsElement() {
162
176
  return this.closest("u-tabs");
163
177
  }
164
178
  get tabs() {
165
- return getTabs(this, this.id);
179
+ const css = `u-tab[${ARIA_CONTROLS}="${this.id}"]`;
180
+ const root = getRoot(this).querySelectorAll(css);
181
+ return root.length ? root : document.querySelectorAll(css);
166
182
  }
167
183
  };
168
- UHTMLTabPanelElement.observedAttributes = ["id"];
169
184
  var queryWithoutNested = (tag, self) => {
170
- const selector = `${tag}:not(:scope ${self.nodeName}:not(:scope) ${tag})`;
171
- return self.querySelectorAll(selector);
172
- };
173
- var getPanel = (self) => {
174
- const css = `u-tabpanel[id="${self.getAttribute(ARIA_CONTROLS)}"]`;
175
- return getRoot(self).querySelector(css) || document.querySelector(css);
185
+ const css = `${tag}:not(:scope ${self.nodeName}:not(:scope) ${tag})`;
186
+ return self.querySelectorAll(css);
176
187
  };
177
- var getTabs = (self, id2) => {
178
- const css = `u-tab[${ARIA_CONTROLS}="${id2}"]`;
179
- return getRoot(self).querySelectorAll(css);
188
+ var getSelectedIndex = (tabs) => [...tabs].findIndex((tab) => tab.ariaSelected === "true");
189
+ var getPanel = (self, id2) => {
190
+ const css = `u-tabpanel[id="${id2 || self.getAttribute(ARIA_CONTROLS)}"]`;
191
+ const tabsElement = self.closest("u-tabs");
192
+ return getRoot(self).querySelector(css) || document.querySelector(css) || tabsElement && queryWithoutNested("u-tabpanel", tabsElement)[[...queryWithoutNested("u-tab", tabsElement)].indexOf(self)] || null;
180
193
  };
181
194
  customElements.define("u-tabs", UHTMLTabsElement);
182
195
  customElements.define("u-tablist", UHTMLTabListElement);
@@ -74,6 +74,21 @@
74
74
  "text": "UHTMLTabsElement | null"
75
75
  },
76
76
  "readonly": true
77
+ },
78
+ {
79
+ "kind": "field",
80
+ "name": "tabs",
81
+ "type": {
82
+ "text": "NodeListOf<UHTMLTabElement>"
83
+ },
84
+ "readonly": true
85
+ },
86
+ {
87
+ "kind": "field",
88
+ "name": "selectedIndex",
89
+ "type": {
90
+ "text": "number"
91
+ }
77
92
  }
78
93
  ],
79
94
  "superclass": {
@@ -166,11 +181,6 @@
166
181
  "readonly": true
167
182
  }
168
183
  ],
169
- "attributes": [
170
- {
171
- "name": "id"
172
- }
173
- ],
174
184
  "superclass": {
175
185
  "name": "UHTMLElement",
176
186
  "module": "//Users/eirikbacker/Library/Mobile%20Documents/com~apple~CloudDocs/5-capra/u-elements/packages/utils"
@@ -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": [{ "name": "id", "values": [] }],
29
+ "attributes": [],
30
30
  "references": []
31
31
  }
32
32
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@u-elements/u-tabs",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "license": "MIT",
5
5
  "description": "HTML tags, just truly accessible",
6
6
  "homepage": "https://u-elements.github.io/u-elements/",