Socket
Socket
Sign inDemoInstall

@github/tab-container-element

Package Overview
Dependencies
Maintainers
20
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@github/tab-container-element - npm Package Compare versions

Comparing version 3.2.0 to 3.3.0

dist/bundle.js

15

dist/index.d.ts

@@ -1,11 +0,4 @@

export default class TabContainerElement extends HTMLElement {
constructor();
connectedCallback(): void;
selectTab(index: number): void;
}
declare global {
interface Window {
TabContainerElement: typeof TabContainerElement;
}
}
//# sourceMappingURL=index.d.ts.map
import { TabContainerElement } from './tab-container-element.js';
export { TabContainerElement };
export default TabContainerElement;
export * from './tab-container-element-define.js';

@@ -1,120 +0,4 @@

function getTabs(el) {
return Array.from(el.querySelectorAll('[role="tablist"] [role="tab"]')).filter(tab => tab instanceof HTMLElement && tab.closest(el.tagName) === el);
}
function getNavigationKeyCodes(vertical) {
if (vertical) {
return [
['ArrowDown', 'ArrowRight'],
['ArrowUp', 'ArrowLeft']
];
}
else {
return [['ArrowRight'], ['ArrowLeft']];
}
}
export default class TabContainerElement extends HTMLElement {
constructor() {
super();
this.addEventListener('keydown', (event) => {
const target = event.target;
if (!(target instanceof HTMLElement))
return;
if (target.closest(this.tagName) !== this)
return;
if (target.getAttribute('role') !== 'tab' && !target.closest('[role="tablist"]'))
return;
const tabs = getTabs(this);
const currentIndex = tabs.indexOf(tabs.find(tab => tab.matches('[aria-selected="true"]')));
const [incrementKeys, decrementKeys] = getNavigationKeyCodes(target.closest('[role="tablist"]')?.getAttribute('aria-orientation') === 'vertical');
if (incrementKeys.some(code => event.code === code)) {
let index = currentIndex + 1;
if (index >= tabs.length)
index = 0;
this.selectTab(index);
}
else if (decrementKeys.some(code => event.code === code)) {
let index = currentIndex - 1;
if (index < 0)
index = tabs.length - 1;
this.selectTab(index);
}
else if (event.code === 'Home') {
this.selectTab(0);
event.preventDefault();
}
else if (event.code === 'End') {
this.selectTab(tabs.length - 1);
event.preventDefault();
}
});
this.addEventListener('click', (event) => {
const tabs = getTabs(this);
if (!(event.target instanceof Element))
return;
if (event.target.closest(this.tagName) !== this)
return;
const tab = event.target.closest('[role="tab"]');
if (!(tab instanceof HTMLElement) || !tab.closest('[role="tablist"]'))
return;
const index = tabs.indexOf(tab);
this.selectTab(index);
});
}
connectedCallback() {
for (const tab of getTabs(this)) {
if (!tab.hasAttribute('aria-selected')) {
tab.setAttribute('aria-selected', 'false');
}
if (!tab.hasAttribute('tabindex')) {
if (tab.getAttribute('aria-selected') === 'true') {
tab.setAttribute('tabindex', '0');
}
else {
tab.setAttribute('tabindex', '-1');
}
}
}
}
selectTab(index) {
const tabs = getTabs(this);
const panels = Array.from(this.querySelectorAll('[role="tabpanel"]')).filter(panel => panel.closest(this.tagName) === this);
/**
* Out of bounds index
*/
if (index > tabs.length - 1) {
throw new RangeError(`Index "${index}" out of bounds`);
}
const selectedTab = tabs[index];
const selectedPanel = panels[index];
const cancelled = !this.dispatchEvent(new CustomEvent('tab-container-change', {
bubbles: true,
cancelable: true,
detail: { relatedTarget: selectedPanel }
}));
if (cancelled)
return;
for (const tab of tabs) {
tab.setAttribute('aria-selected', 'false');
tab.setAttribute('tabindex', '-1');
}
for (const panel of panels) {
panel.hidden = true;
if (!panel.hasAttribute('tabindex') && !panel.hasAttribute('data-tab-container-no-tabstop')) {
panel.setAttribute('tabindex', '0');
}
}
selectedTab.setAttribute('aria-selected', 'true');
selectedTab.setAttribute('tabindex', '0');
selectedTab.focus();
selectedPanel.hidden = false;
this.dispatchEvent(new CustomEvent('tab-container-changed', {
bubbles: true,
detail: { relatedTarget: selectedPanel }
}));
}
}
if (!window.customElements.get('tab-container')) {
window.TabContainerElement = TabContainerElement;
window.customElements.define('tab-container', TabContainerElement);
}
//# sourceMappingURL=index.js.map
import { TabContainerElement } from './tab-container-element.js';
export { TabContainerElement };
export default TabContainerElement;
export * from './tab-container-element-define.js';
{
"name": "@github/tab-container-element",
"version": "3.2.0",
"version": "3.3.0",
"description": "Tab container element",
"type": "module",
"main": "dist/index.js",

@@ -13,27 +14,36 @@ "module": "dist/index.js",

],
"exports": {
".": "./dist/index.js",
"./define": "./dist/index.js",
"./tab-container": "./dist/tab-container-element.js",
"./tab-container/define": "./dist/tab-container-element-define.js"
},
"scripts": {
"clean": "rm -rf dist",
"lint": "eslint src/*.ts test/*.js",
"lint": "eslint . --ext .js,.ts && tsc --noEmit",
"lint:fix": "eslint --fix . --ext .js,.ts",
"prebuild": "npm run clean && npm run lint && mkdir dist",
"build": "tsc",
"bundle": "esbuild --bundle dist/index.js --keep-names --outfile=dist/bundle.js --format=esm",
"build": "tsc && npm run bundle && npm run manifest",
"pretest": "npm run build",
"test": "karma start test/karma.config.js",
"test": "web-test-runner",
"prepublishOnly": "npm run build",
"postpublish": "npm publish --ignore-scripts --@github:registry='https://npm.pkg.github.com'"
"postpublish": "npm publish --ignore-scripts --@github:registry='https://npm.pkg.github.com'",
"manifest": "custom-elements-manifest analyze"
},
"prettier": "@github/prettier-config",
"devDependencies": {
"@github/prettier-config": "0.0.4",
"chai": "^4.3.4",
"chromium": "^3.0.3",
"eslint": "^7.32.0",
"eslint-plugin-github": "^4.3.0",
"karma": "^6.3.4",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^3.1.0",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"mocha": "^9.1.1",
"typescript": "^4.4.3"
"@custom-elements-manifest/analyzer": "^0.8.3",
"@github/prettier-config": "^0.0.6",
"@open-wc/testing": "^3.2.0",
"@web/dev-server-esbuild": "^0.4.1",
"@web/test-runner": "^0.16.1",
"@web/test-runner-playwright": "^0.10.1",
"esbuild": "^0.18.3",
"eslint": "^8.42.0",
"eslint-plugin-custom-elements": "^0.0.8",
"eslint-plugin-github": "^4.8.0",
"typescript": "^5.1.3"
},
"customElements": "custom-elements.json",
"eslintIgnore": [

@@ -40,0 +50,0 @@ "dist/"

# &lt;tab-container&gt; element
A accessible tab container element with keyboard support. Follows the [ARIA best practices guide on tabs](https://www.w3.org/TR/wai-aria-practices/#tabpanel).
A accessible tab container element with keyboard support. Follows the [ARIA best practices guide on tabs](https://www.w3.org/WAI/ARIA/apg/patterns/tabpanel/).

@@ -41,2 +41,29 @@ ## Installation

### When tab panel contents are controls
When activated, the whole tab panel will receive focus. This may be undesirable, in the case where the tab panel is itself composed of interactive elements, such as an action list or radio buttons.
In those cases, apply `data-tab-container-no-tabstop` to the `tabpanel` element.
```html
<tab-container>
<div role="tablist">
<button type="button" id="tab-one" role="tab" aria-selected="true">Tab one</button>
<button type="button" id="tab-two" role="tab" tabindex="-1">Tab two</button>
</div>
<div role="tabpanel" aria-labelledby="tab-one" data-tab-container-no-tabstop>
<ul role="menu" aria-label="Branches">
<li tabindex="0">branch-one</li>
<li tabindex="0">branch-two</li>
</ul>
</div>
<div role="tabpanel" aria-labelledby="tab-two" data-tab-container-no-tabstop hidden>
<ul role="menu" aria-label="Commits">
<li tabindex="0">Commit One</li>
<li tabindex="0">Commit Two</li>
</ul>
</div>
</tab-container>
```
## Browser support

@@ -43,0 +70,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc