igniteui-webcomponents
Version:
Ignite UI for Web Components is a complete library of UI components, giving you the ability to build modern web applications using encapsulation and the concept of reusable components in a dependency-free approach.
276 lines • 10.8 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { html, LitElement, nothing } from 'lit';
import { eventOptions, property, queryAssignedElements, state, } from 'lit/decorators.js';
import { cache } from 'lit/directives/cache.js';
import { createRef, ref } from 'lit/directives/ref.js';
import { styleMap } from 'lit/directives/style-map.js';
import { addThemingController } from '../../theming/theming-controller.js';
import IgcIconButtonComponent from '../button/icon-button.js';
import { addKeybindings, arrowLeft, arrowRight, endKey, homeKey, } from '../common/controllers/key-bindings.js';
import { createMutationController, } from '../common/controllers/mutation-observer.js';
import { createResizeObserverController } from '../common/controllers/resize-observer.js';
import { watch } from '../common/decorators/watch.js';
import { registerComponent } from '../common/definitions/register.js';
import { EventEmitterMixin } from '../common/mixins/event-emitter.js';
import { partMap } from '../common/part-map.js';
import { findElementFromEventPath, first, getRoot, isEmpty, isLTR, isString, last, scrollIntoView, wrap, } from '../common/util.js';
import IgcTabComponent from './tab.js';
import { createTabHelpers, getTabHeader } from './tab-dom.js';
import { styles as shared } from './themes/shared/tabs/tabs.common.css.js';
import { styles } from './themes/tabs.base.css.js';
import { all } from './themes/tabs-themes.js';
class IgcTabsComponent extends EventEmitterMixin(LitElement) {
static register() {
registerComponent(IgcTabsComponent, IgcTabComponent, IgcIconButtonComponent);
}
get _enabledTabs() {
return this._tabs.filter((tab) => !tab.disabled);
}
get tabs() {
return this._tabs;
}
get selected() {
if (this._activeTab) {
return this._activeTab.label || this._activeTab.id;
}
return '';
}
_alignmentChanged() {
this._domHelpers.setIndicator(this._activeTab);
}
constructor() {
super();
this._resizeController = createResizeObserverController(this, {
callback: this._resizeCallback,
options: { box: 'border-box' },
target: null,
});
this._headerRef = createRef();
this._indicatorRef = createRef();
this._domHelpers = createTabHelpers(this, this._headerRef, this._indicatorRef);
this.alignment = 'start';
this.activation = 'auto';
addThemingController(this, all);
addKeybindings(this, {
ref: this._headerRef,
skip: this._skipKeyboard,
bindingDefaults: { preventDefault: true },
})
.set(arrowLeft, () => this._handleArrowKeys(isLTR(this) ? -1 : 1))
.set(arrowRight, () => this._handleArrowKeys(isLTR(this) ? 1 : -1))
.set(homeKey, this._handleHomeKey)
.set(endKey, this._handleEndKey)
.setActivateHandler(this._handleActivationKeys, {
preventDefault: false,
});
createMutationController(this, {
callback: this._mutationCallback,
config: {
attributeFilter: ['selected'],
childList: true,
subtree: true,
},
filter: [IgcTabComponent.tagName],
});
}
async firstUpdated() {
await this.updateComplete;
const selectedTab = this._tabs.findLast((tab) => tab.selected) ?? first(this._enabledTabs);
this._domHelpers.setStyleProperties();
this._domHelpers.setScrollButtonState();
this._setSelectedTab(selectedTab, false);
this._resizeController.observe(this._headerRef.value);
}
connectedCallback() {
super.connectedCallback();
this.role = 'tablist';
}
updated() {
if (this._domHelpers.isLeftToRightChanged) {
this._domHelpers.setIndicator(this._activeTab);
}
}
_resizeCallback() {
this._domHelpers.setStyleProperties();
this._domHelpers.setScrollButtonState();
this._domHelpers.setIndicator(this._activeTab);
}
_mutationCallback(parameters) {
this._selectedAttributeChanged(parameters);
this._handleTabsRemoved(parameters);
this._handleTabsAdded(parameters);
this._domHelpers.setStyleProperties();
this._domHelpers.setScrollButtonState();
this._domHelpers.setIndicator(this._activeTab);
}
_selectedAttributeChanged({ changes, }) {
const selected = changes.attributes.find(({ node: tab }) => this._tabs.includes(tab) && tab.selected)?.node;
this._setSelectedTab(selected, false);
}
_handleTabsAdded({ changes, }) {
if (!isEmpty(changes.added)) {
const lastAdded = changes.added.findLast((change) => change.target.closest(this.tagName) === this && change.node.selected)?.node;
this._setSelectedTab(lastAdded, false);
}
}
_handleTabsRemoved({ changes, }) {
if (!isEmpty(changes.removed)) {
let nextSelectedTab = null;
const removed = changes.removed.filter((change) => change.target.closest(this.tagName) === this);
for (const each of removed) {
if (each.node.selected && each.node === this._activeTab) {
nextSelectedTab = first(this._enabledTabs);
break;
}
}
if (nextSelectedTab) {
this._setSelectedTab(nextSelectedTab, false);
}
}
}
_getClosestActiveTabIndex() {
const active = getRoot(this).activeElement;
const tab = active ? active.closest(IgcTabComponent.tagName) : null;
return tab ? this._enabledTabs.indexOf(tab) : -1;
}
_setSelectedTab(tab, shouldEmit = true) {
if (!tab || tab === this._activeTab) {
return;
}
if (this._activeTab) {
this._activeTab.selected = false;
}
tab.selected = true;
this._activeTab = tab;
scrollIntoView(getTabHeader(tab));
this._domHelpers.setIndicator(this._activeTab);
if (shouldEmit) {
this.emitEvent('igcChange', { detail: this._activeTab });
}
}
_keyboardActivateTab(tab) {
const header = getTabHeader(tab);
this._domHelpers.setScrollSnap();
scrollIntoView(header);
header.focus({ preventScroll: true });
if (this.activation === 'auto') {
this._setSelectedTab(tab);
}
}
_skipKeyboard(node, event) {
return !(this._isEventFromTabHeader(event) &&
this._tabs.includes(node.closest(IgcTabComponent.tagName)));
}
_isEventFromTabHeader(event) {
return findElementFromEventPath('[part~="tab-header"]', event);
}
_handleArrowKeys(delta) {
const tabs = this._enabledTabs;
this._keyboardActivateTab(tabs[wrap(0, tabs.length - 1, this._getClosestActiveTabIndex() + delta)]);
}
_handleHomeKey() {
this._keyboardActivateTab(first(this._enabledTabs));
}
_handleEndKey() {
this._keyboardActivateTab(last(this._enabledTabs));
}
_handleActivationKeys() {
const tabs = this._enabledTabs;
const index = this._getClosestActiveTabIndex();
if (index > -1) {
this._setSelectedTab(tabs[index], false);
this._keyboardActivateTab(tabs[index]);
}
}
_handleClick(event) {
if (!this._isEventFromTabHeader(event)) {
return;
}
const tab = findElementFromEventPath(IgcTabComponent.tagName, event);
if (!(tab && this._tabs.includes(tab)) || tab?.disabled) {
return;
}
this._domHelpers.setScrollSnap();
getTabHeader(tab).focus();
this._setSelectedTab(tab);
}
_handleScroll() {
this._domHelpers.setScrollButtonState();
}
select(ref) {
const tab = isString(ref) ? this._tabs.find((t) => t.id === ref) : ref;
if (tab) {
this._setSelectedTab(tab, false);
}
}
_renderScrollButton(direction) {
const isStart = direction === 'start';
const { start, end } = this._domHelpers.scrollButtonsDisabled;
return html `${cache(this._domHelpers.hasScrollButtons
? html `
<igc-icon-button
tabindex="-1"
variant="flat"
collection="default"
part="${direction}-scroll-button"
exportparts="icon"
name=${isStart ? 'prev' : 'next'}
?disabled=${isStart ? start : end}
=${() => this._domHelpers.scrollTabs(direction)}
>
</igc-icon-button>
`
: nothing)}`;
}
render() {
return html `
<div
${ref(this._headerRef)}
part="tabs"
style=${styleMap(this._domHelpers.styleProperties)}
=${this._handleScroll}
>
<div
part=${partMap({
inner: true,
scrollable: this._domHelpers.hasScrollButtons,
})}
>
${this._renderScrollButton('start')}
<slot =${this._handleClick}></slot>
${this._renderScrollButton('end')}
<div part="selected-indicator">
<span ${ref(this._indicatorRef)}></span>
</div>
</div>
</div>
`;
}
}
IgcTabsComponent.tagName = 'igc-tabs';
IgcTabsComponent.styles = [styles, shared];
export default IgcTabsComponent;
__decorate([
queryAssignedElements({ selector: IgcTabComponent.tagName })
], IgcTabsComponent.prototype, "_tabs", void 0);
__decorate([
state()
], IgcTabsComponent.prototype, "_activeTab", void 0);
__decorate([
property({ reflect: true })
], IgcTabsComponent.prototype, "alignment", void 0);
__decorate([
property()
], IgcTabsComponent.prototype, "activation", void 0);
__decorate([
watch('alignment', { waitUntilFirstUpdate: true })
], IgcTabsComponent.prototype, "_alignmentChanged", null);
__decorate([
eventOptions({ passive: true })
], IgcTabsComponent.prototype, "_handleScroll", null);
//# sourceMappingURL=tabs.js.map