ember-aria-tabs
Version:
An accessible and easy tab component for Ember.js
151 lines (134 loc) • 3.52 kB
JavaScript
import Component from '@glimmer/component';
import { cached, tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { guidFor } from '@ember/object/internals';
import { next } from '@ember/runloop';
const DEFAULT_CLASS = 'ember-tabs__tab';
/**
* A tab component rendered as `<li />`.
*
* If you specify additional props on the `<AriaTab />` component they will be forwarded to the rendered `<li />`.
*
* Default CSS class: `ember-tabs__tab`
*
* @class AriaTab
* @public
*/
export default class AriaTabComponent extends Component {
/**
* Defaults to `false`.
*
* Disable this tab which will make it not do anything when clicked. Also a disabled class name will be added (see `disabledClassName`)
*
* @argument disabled
* @type Boolean
* @default false
*/
/**
* Defaults to `"ember-tabs__tab--disabled"`.
*
* Provide a custom class name for disabled tabs.
*
* > This option can also be set for all `<AriaTab />` components with the prop `disabledTabClassName` on `<AriaTabs />`.
*
* @argument disabledClassName
* @type String
* @default "ember-tabs__tab--disabled"
*/
get disabledClassName() {
return (
this.args.disabledClassName ??
this.args.disabledTabClassName ??
`${DEFAULT_CLASS}--disabled`
);
}
/**
* Defaults to `"ember-tabs__tab--selected"`.
*
* > This option can also be set for all `<AriaTab />` components with the prop `disabledTabClassName` on `<AriaTabs />`.
*
* @argument selectedClassName
* @type String
* @default "ember-tabs__tab--selected"
*/
get selectedClassName() {
return (
this.args.selectedClassName ??
this.args.selectedTabClassName ??
`${DEFAULT_CLASS}--selected`
);
}
/**
* Default to `"0"` if selected, `null` otherwise.
*
* Overrides the tabIndex to enabled tabbing between tabs.
*
* @argument tabIndex
* @type String
* @default "0"|null
**/
elementId = guidFor(this);
get classNames() {
let classNames = [DEFAULT_CLASS];
if (this.selected) {
classNames.push(this.selectedClassName);
}
if (this.args.disabled) {
classNames.push(this.disabledClassName);
}
return classNames.join(' ');
}
get nodeIndex() {
return (this.args.tabIds ?? []).indexOf(this.elementId);
}
get panelId() {
return (this.args.panelIds ?? [])[this.nodeIndex];
}
get selected() {
return this.nodeIndex === this.args.selectedIndex;
}
get tabIndex() {
return this.args.tabIndex ?? (this.selected ? '0' : undefined);
}
checkFocus() {
if (this.selected && this.args.focus) {
// We need to wait the selected rendering state
next(() => {
this.element.focus();
});
}
}
didInsertNode(element) {
this.elementId = element.id;
if (typeof this.args.didInsertNode === 'function') {
this.args.didInsertNode(this.elementId, ...arguments);
}
}
willDestroyNode() {
if (typeof this.args.willDestroyNode === 'function') {
this.args.willDestroyNode(this.elementId, ...arguments);
}
}
onClick() {
if (typeof this.args.onClick === 'function') {
this.args.onClick(this.nodeIndex, ...arguments);
}
}
onKeyUp() {
if (typeof this.args.onKeyUp === 'function') {
this.args.onKeyUp(this.nodeIndex, ...arguments);
}
}
}