@u-elements/u-tabs 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/u-tabs.cjs CHANGED
@@ -9,6 +9,12 @@ var SAFE_LABELLEDBY = `${IS_ANDROID ? "data" : "aria"}-labelledby`;
9
9
  var DISPLAY_BLOCK = ":host(:not([hidden])) { display: block }";
10
10
  var UHTMLElement = typeof HTMLElement === "undefined" ? class {
11
11
  } : HTMLElement;
12
+ function attr(el, name, value) {
13
+ if (value === void 0) return el?.getAttribute(name) ?? null;
14
+ if (value === null) el?.removeAttribute(name);
15
+ else if (el?.getAttribute(name) !== value) el?.setAttribute(name, value);
16
+ return null;
17
+ }
12
18
  var events = (action, element, rest) => {
13
19
  for (const type of rest[0].split(",")) {
14
20
  rest[0] = type;
@@ -20,7 +26,7 @@ var off = (element, ...rest) => events("remove", element, rest);
20
26
  var attachStyle = (element, css) => element.attachShadow({ mode: "open" }).append(
21
27
  createElement("slot"),
22
28
  // Unnamed slot does automatically render all top element nodes
23
- createElement("style", { textContent: css })
29
+ createElement("style", css)
24
30
  );
25
31
  var asButton = (event) => {
26
32
  const isClick = "key" in event && (event.key === " " || event.key === "Enter");
@@ -28,14 +34,21 @@ var asButton = (event) => {
28
34
  if (isClick && event.target instanceof HTMLElement) event.target.click();
29
35
  return isClick;
30
36
  };
31
- var getRoot = (node) => node.getRootNode();
37
+ var getRoot = (node) => {
38
+ const root = node.getRootNode?.() || node.ownerDocument;
39
+ return root instanceof Document || root instanceof ShadowRoot ? root : document;
40
+ };
32
41
  var id = 0;
33
42
  var useId = (el) => {
34
43
  if (!el) return "";
35
44
  if (!el.id) el.id = `:${el.nodeName.toLowerCase()}${(++id).toString(32)}`;
36
45
  return el.id;
37
46
  };
38
- var createElement = (tagName, props) => Object.assign(document.createElement(tagName), props);
47
+ var createElement = (tagName, text, attrs) => {
48
+ const el = document.createElement(tagName);
49
+ if (text) el.textContent = text;
50
+ return el;
51
+ };
39
52
  var customElements = {
40
53
  define: (name, instance) => !IS_BROWSER || window.customElements.get(name) || window.customElements.define(name, instance)
41
54
  };
@@ -54,7 +67,7 @@ var UHTMLTabsElement = class extends UHTMLElement {
54
67
  return getSelectedIndex(this.tabs);
55
68
  }
56
69
  set selectedIndex(index) {
57
- if (this.tabs[index]) this.tabs[index].ariaSelected = "true";
70
+ if (this.tabs[index]) attr(this.tabs[index], "aria-selected", "true");
58
71
  }
59
72
  get tabs() {
60
73
  return queryWithoutNested("u-tab", this);
@@ -69,7 +82,7 @@ var UHTMLTabListElement = class extends UHTMLElement {
69
82
  attachStyle(this, DISPLAY_BLOCK);
70
83
  }
71
84
  connectedCallback() {
72
- this.role = "tablist";
85
+ attr(this, "role", "tablist");
73
86
  on(this, "click,keydown", this);
74
87
  }
75
88
  disconnectedCallback() {
@@ -111,10 +124,14 @@ var UHTMLTabListElement = class extends UHTMLElement {
111
124
  return getSelectedIndex(this.tabs);
112
125
  }
113
126
  set selectedIndex(index) {
114
- if (this.tabs[index]) this.tabs[index].ariaSelected = "true";
127
+ if (this.tabs[index]) attr(this.tabs[index], "aria-selected", "true");
115
128
  }
116
129
  };
117
130
  var UHTMLTabElement = class extends UHTMLElement {
131
+ // Using ES2015 syntax for backwards compatibility
132
+ static get observedAttributes() {
133
+ return ["id", "aria-selected", ARIA_CONTROLS];
134
+ }
118
135
  constructor() {
119
136
  super();
120
137
  attachStyle(
@@ -123,12 +140,12 @@ var UHTMLTabElement = class extends UHTMLElement {
123
140
  );
124
141
  }
125
142
  connectedCallback() {
143
+ const panelId = !attr(this, ARIA_CONTROLS) && useId(getPanel(this));
126
144
  const selected = this.selected || ![...queryWithoutNested("u-tab", this.tabList || this)].some(isSelected);
127
- this.role = "tab";
145
+ attr(this, "aria-selected", `${selected}`);
146
+ attr(this, "role", "tab");
128
147
  this.tabIndex = selected ? 0 : -1;
129
- this.ariaSelected = `${selected}`;
130
- if (!this.hasAttribute(ARIA_CONTROLS))
131
- this.setAttribute(ARIA_CONTROLS, useId(getPanel(this)));
148
+ if (panelId) attr(this, ARIA_CONTROLS, panelId);
132
149
  }
133
150
  attributeChangedCallback(name, prev) {
134
151
  if (!this.selected) return;
@@ -137,18 +154,19 @@ var UHTMLTabElement = class extends UHTMLElement {
137
154
  if (name === "aria-selected" && this.tabList)
138
155
  for (const tab of queryWithoutNested("u-tab", this.tabList)) {
139
156
  if (tab !== this && isSelected(tab)) {
140
- getPanel(tab)?.setAttribute("hidden", "");
141
- tab.ariaSelected = "false";
157
+ const panel = getPanel(tab);
158
+ if (panel) panel.hidden = true;
159
+ attr(tab, "aria-selected", "false");
142
160
  tab.tabIndex = -1;
143
161
  }
144
162
  }
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);
163
+ const prevPanel = name === ARIA_CONTROLS && prev && getPanel(this, prev);
164
+ if (prevPanel) prevPanel.hidden = true;
165
+ if (nextPanelId && attr(this, ARIA_CONTROLS) !== nextPanelId)
166
+ attr(this, ARIA_CONTROLS, nextPanelId);
149
167
  this.tabIndex = 0;
150
- nextPanel?.setAttribute(SAFE_LABELLEDBY, useId(this));
151
- nextPanel?.removeAttribute("hidden");
168
+ if (nextPanel) attr(nextPanel, SAFE_LABELLEDBY, useId(this));
169
+ if (nextPanel) nextPanel.hidden = false;
152
170
  }
153
171
  get tabsElement() {
154
172
  return this.closest("u-tabs");
@@ -160,7 +178,7 @@ var UHTMLTabElement = class extends UHTMLElement {
160
178
  return isSelected(this);
161
179
  }
162
180
  set selected(value) {
163
- this.ariaSelected = `${!!value}`;
181
+ attr(this, "aria-selected", `${!!value}`);
164
182
  }
165
183
  /** Retrieves the ordinal position of an tab in a tablist. */
166
184
  get index() {
@@ -171,20 +189,23 @@ var UHTMLTabElement = class extends UHTMLElement {
171
189
  return getPanel(this);
172
190
  }
173
191
  };
174
- UHTMLTabElement.observedAttributes = ["id", "aria-selected", ARIA_CONTROLS];
175
192
  var UHTMLTabPanelElement = class extends UHTMLElement {
193
+ // Using ES2015 syntax for backwards compatibility
194
+ static get observedAttributes() {
195
+ return ["hidden"];
196
+ }
176
197
  constructor() {
177
198
  super();
178
199
  attachStyle(this, DISPLAY_BLOCK);
179
200
  }
180
201
  connectedCallback() {
202
+ attr(this, "role", "tabpanel");
181
203
  this.hidden = getSelectedIndex(this.tabs) === -1;
182
- this.role = "tabpanel";
183
204
  this.attributeChangedCallback();
184
205
  }
185
206
  attributeChangedCallback() {
186
- if (this.hidden || isFocusable(this.firstElementChild))
187
- this.removeAttribute("tabindex");
207
+ if (this.hidden || isFocusable(this.firstChild))
208
+ attr(this, "tabindex", null);
188
209
  else this.tabIndex = 0;
189
210
  }
190
211
  get tabsElement() {
@@ -196,17 +217,16 @@ var UHTMLTabPanelElement = class extends UHTMLElement {
196
217
  return root.length ? root : document.querySelectorAll(css);
197
218
  }
198
219
  };
199
- UHTMLTabPanelElement.observedAttributes = ["hidden"];
200
220
  var queryWithoutNested = (tag, self) => self.querySelectorAll(
201
221
  `${tag}:not(:scope ${self.nodeName}:not(:scope) ${tag})`
202
222
  );
203
- var isSelected = (tab) => tab.ariaSelected === "true";
223
+ var isSelected = (tab) => attr(tab, "aria-selected") === "true";
204
224
  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^="-"])`
225
+ var isFocusable = (el) => el instanceof Element && !el.matches(':disabled,[tabindex^="-"]') && el.matches(
226
+ `[contenteditable],[controls],[href],[tabindex],input:not([type="hidden"]),select,textarea,button,summary,iframe`
207
227
  );
208
228
  var getPanel = (tab, id2) => {
209
- const panelId = id2 || tab.getAttribute(ARIA_CONTROLS);
229
+ const panelId = id2 || attr(tab, ARIA_CONTROLS);
210
230
  const panelSelector = `u-tabpanel[id="${panelId}"]`;
211
231
  const tabsElement = tab.closest("u-tabs");
212
232
  return panelId && getRoot(tab).querySelector(panelSelector) || panelId && getRoot(tab).querySelector(panelSelector) || tabsElement && queryWithoutNested("u-tabpanel", tabsElement)[[...queryWithoutNested("u-tab", tabsElement)].indexOf(tab)] || null;
package/dist/u-tabs.d.cts CHANGED
@@ -42,7 +42,7 @@ declare class UHTMLTabListElement extends UHTMLElement {
42
42
  * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tab_role)
43
43
  */
44
44
  declare class UHTMLTabElement extends UHTMLElement {
45
- static observedAttributes: string[];
45
+ static get observedAttributes(): string[];
46
46
  constructor();
47
47
  connectedCallback(): void;
48
48
  attributeChangedCallback(name: string, prev: string): void;
@@ -59,7 +59,7 @@ declare class UHTMLTabElement extends UHTMLElement {
59
59
  * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tabpanel_role)
60
60
  */
61
61
  declare class UHTMLTabPanelElement extends UHTMLElement {
62
- static observedAttributes: string[];
62
+ static get observedAttributes(): string[];
63
63
  constructor();
64
64
  connectedCallback(): void;
65
65
  attributeChangedCallback(): void;
package/dist/u-tabs.d.ts CHANGED
@@ -42,7 +42,7 @@ declare class UHTMLTabListElement extends UHTMLElement {
42
42
  * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tab_role)
43
43
  */
44
44
  declare class UHTMLTabElement extends UHTMLElement {
45
- static observedAttributes: string[];
45
+ static get observedAttributes(): string[];
46
46
  constructor();
47
47
  connectedCallback(): void;
48
48
  attributeChangedCallback(name: string, prev: string): void;
@@ -59,7 +59,7 @@ declare class UHTMLTabElement extends UHTMLElement {
59
59
  * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tabpanel_role)
60
60
  */
61
61
  declare class UHTMLTabPanelElement extends UHTMLElement {
62
- static observedAttributes: string[];
62
+ static get observedAttributes(): string[];
63
63
  constructor();
64
64
  connectedCallback(): void;
65
65
  attributeChangedCallback(): void;
package/dist/u-tabs.js CHANGED
@@ -7,6 +7,12 @@ var SAFE_LABELLEDBY = `${IS_ANDROID ? "data" : "aria"}-labelledby`;
7
7
  var DISPLAY_BLOCK = ":host(:not([hidden])) { display: block }";
8
8
  var UHTMLElement = typeof HTMLElement === "undefined" ? class {
9
9
  } : HTMLElement;
10
+ function attr(el, name, value) {
11
+ if (value === void 0) return el?.getAttribute(name) ?? null;
12
+ if (value === null) el?.removeAttribute(name);
13
+ else if (el?.getAttribute(name) !== value) el?.setAttribute(name, value);
14
+ return null;
15
+ }
10
16
  var events = (action, element, rest) => {
11
17
  for (const type of rest[0].split(",")) {
12
18
  rest[0] = type;
@@ -18,7 +24,7 @@ var off = (element, ...rest) => events("remove", element, rest);
18
24
  var attachStyle = (element, css) => element.attachShadow({ mode: "open" }).append(
19
25
  createElement("slot"),
20
26
  // Unnamed slot does automatically render all top element nodes
21
- createElement("style", { textContent: css })
27
+ createElement("style", css)
22
28
  );
23
29
  var asButton = (event) => {
24
30
  const isClick = "key" in event && (event.key === " " || event.key === "Enter");
@@ -26,14 +32,21 @@ var asButton = (event) => {
26
32
  if (isClick && event.target instanceof HTMLElement) event.target.click();
27
33
  return isClick;
28
34
  };
29
- var getRoot = (node) => node.getRootNode();
35
+ var getRoot = (node) => {
36
+ const root = node.getRootNode?.() || node.ownerDocument;
37
+ return root instanceof Document || root instanceof ShadowRoot ? root : document;
38
+ };
30
39
  var id = 0;
31
40
  var useId = (el) => {
32
41
  if (!el) return "";
33
42
  if (!el.id) el.id = `:${el.nodeName.toLowerCase()}${(++id).toString(32)}`;
34
43
  return el.id;
35
44
  };
36
- var createElement = (tagName, props) => Object.assign(document.createElement(tagName), props);
45
+ var createElement = (tagName, text, attrs) => {
46
+ const el = document.createElement(tagName);
47
+ if (text) el.textContent = text;
48
+ return el;
49
+ };
37
50
  var customElements = {
38
51
  define: (name, instance) => !IS_BROWSER || window.customElements.get(name) || window.customElements.define(name, instance)
39
52
  };
@@ -52,7 +65,7 @@ var UHTMLTabsElement = class extends UHTMLElement {
52
65
  return getSelectedIndex(this.tabs);
53
66
  }
54
67
  set selectedIndex(index) {
55
- if (this.tabs[index]) this.tabs[index].ariaSelected = "true";
68
+ if (this.tabs[index]) attr(this.tabs[index], "aria-selected", "true");
56
69
  }
57
70
  get tabs() {
58
71
  return queryWithoutNested("u-tab", this);
@@ -67,7 +80,7 @@ var UHTMLTabListElement = class extends UHTMLElement {
67
80
  attachStyle(this, DISPLAY_BLOCK);
68
81
  }
69
82
  connectedCallback() {
70
- this.role = "tablist";
83
+ attr(this, "role", "tablist");
71
84
  on(this, "click,keydown", this);
72
85
  }
73
86
  disconnectedCallback() {
@@ -109,10 +122,14 @@ var UHTMLTabListElement = class extends UHTMLElement {
109
122
  return getSelectedIndex(this.tabs);
110
123
  }
111
124
  set selectedIndex(index) {
112
- if (this.tabs[index]) this.tabs[index].ariaSelected = "true";
125
+ if (this.tabs[index]) attr(this.tabs[index], "aria-selected", "true");
113
126
  }
114
127
  };
115
128
  var UHTMLTabElement = class extends UHTMLElement {
129
+ // Using ES2015 syntax for backwards compatibility
130
+ static get observedAttributes() {
131
+ return ["id", "aria-selected", ARIA_CONTROLS];
132
+ }
116
133
  constructor() {
117
134
  super();
118
135
  attachStyle(
@@ -121,12 +138,12 @@ var UHTMLTabElement = class extends UHTMLElement {
121
138
  );
122
139
  }
123
140
  connectedCallback() {
141
+ const panelId = !attr(this, ARIA_CONTROLS) && useId(getPanel(this));
124
142
  const selected = this.selected || ![...queryWithoutNested("u-tab", this.tabList || this)].some(isSelected);
125
- this.role = "tab";
143
+ attr(this, "aria-selected", `${selected}`);
144
+ attr(this, "role", "tab");
126
145
  this.tabIndex = selected ? 0 : -1;
127
- this.ariaSelected = `${selected}`;
128
- if (!this.hasAttribute(ARIA_CONTROLS))
129
- this.setAttribute(ARIA_CONTROLS, useId(getPanel(this)));
146
+ if (panelId) attr(this, ARIA_CONTROLS, panelId);
130
147
  }
131
148
  attributeChangedCallback(name, prev) {
132
149
  if (!this.selected) return;
@@ -135,18 +152,19 @@ var UHTMLTabElement = class extends UHTMLElement {
135
152
  if (name === "aria-selected" && this.tabList)
136
153
  for (const tab of queryWithoutNested("u-tab", this.tabList)) {
137
154
  if (tab !== this && isSelected(tab)) {
138
- getPanel(tab)?.setAttribute("hidden", "");
139
- tab.ariaSelected = "false";
155
+ const panel = getPanel(tab);
156
+ if (panel) panel.hidden = true;
157
+ attr(tab, "aria-selected", "false");
140
158
  tab.tabIndex = -1;
141
159
  }
142
160
  }
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);
161
+ const prevPanel = name === ARIA_CONTROLS && prev && getPanel(this, prev);
162
+ if (prevPanel) prevPanel.hidden = true;
163
+ if (nextPanelId && attr(this, ARIA_CONTROLS) !== nextPanelId)
164
+ attr(this, ARIA_CONTROLS, nextPanelId);
147
165
  this.tabIndex = 0;
148
- nextPanel?.setAttribute(SAFE_LABELLEDBY, useId(this));
149
- nextPanel?.removeAttribute("hidden");
166
+ if (nextPanel) attr(nextPanel, SAFE_LABELLEDBY, useId(this));
167
+ if (nextPanel) nextPanel.hidden = false;
150
168
  }
151
169
  get tabsElement() {
152
170
  return this.closest("u-tabs");
@@ -158,7 +176,7 @@ var UHTMLTabElement = class extends UHTMLElement {
158
176
  return isSelected(this);
159
177
  }
160
178
  set selected(value) {
161
- this.ariaSelected = `${!!value}`;
179
+ attr(this, "aria-selected", `${!!value}`);
162
180
  }
163
181
  /** Retrieves the ordinal position of an tab in a tablist. */
164
182
  get index() {
@@ -169,20 +187,23 @@ var UHTMLTabElement = class extends UHTMLElement {
169
187
  return getPanel(this);
170
188
  }
171
189
  };
172
- UHTMLTabElement.observedAttributes = ["id", "aria-selected", ARIA_CONTROLS];
173
190
  var UHTMLTabPanelElement = class extends UHTMLElement {
191
+ // Using ES2015 syntax for backwards compatibility
192
+ static get observedAttributes() {
193
+ return ["hidden"];
194
+ }
174
195
  constructor() {
175
196
  super();
176
197
  attachStyle(this, DISPLAY_BLOCK);
177
198
  }
178
199
  connectedCallback() {
200
+ attr(this, "role", "tabpanel");
179
201
  this.hidden = getSelectedIndex(this.tabs) === -1;
180
- this.role = "tabpanel";
181
202
  this.attributeChangedCallback();
182
203
  }
183
204
  attributeChangedCallback() {
184
- if (this.hidden || isFocusable(this.firstElementChild))
185
- this.removeAttribute("tabindex");
205
+ if (this.hidden || isFocusable(this.firstChild))
206
+ attr(this, "tabindex", null);
186
207
  else this.tabIndex = 0;
187
208
  }
188
209
  get tabsElement() {
@@ -194,17 +215,16 @@ var UHTMLTabPanelElement = class extends UHTMLElement {
194
215
  return root.length ? root : document.querySelectorAll(css);
195
216
  }
196
217
  };
197
- UHTMLTabPanelElement.observedAttributes = ["hidden"];
198
218
  var queryWithoutNested = (tag, self) => self.querySelectorAll(
199
219
  `${tag}:not(:scope ${self.nodeName}:not(:scope) ${tag})`
200
220
  );
201
- var isSelected = (tab) => tab.ariaSelected === "true";
221
+ var isSelected = (tab) => attr(tab, "aria-selected") === "true";
202
222
  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^="-"])`
223
+ var isFocusable = (el) => el instanceof Element && !el.matches(':disabled,[tabindex^="-"]') && el.matches(
224
+ `[contenteditable],[controls],[href],[tabindex],input:not([type="hidden"]),select,textarea,button,summary,iframe`
205
225
  );
206
226
  var getPanel = (tab, id2) => {
207
- const panelId = id2 || tab.getAttribute(ARIA_CONTROLS);
227
+ const panelId = id2 || attr(tab, ARIA_CONTROLS);
208
228
  const panelSelector = `u-tabpanel[id="${panelId}"]`;
209
229
  const tabsElement = tab.closest("u-tabs");
210
230
  return panelId && getRoot(tab).querySelector(panelSelector) || panelId && getRoot(tab).querySelector(panelSelector) || tabsElement && queryWithoutNested("u-tabpanel", tabsElement)[[...queryWithoutNested("u-tab", tabsElement)].indexOf(tab)] || null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@u-elements/u-tabs",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "license": "MIT",
5
5
  "description": "HTML tags, just truly accessible",
6
6
  "homepage": "https://u-elements.github.io/u-elements/",