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.
144 lines • 4.62 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 { LitElement, css, html, nothing } from 'lit';
import { property, state } from 'lit/decorators.js';
import { registerComponent } from '../common/definitions/register.js';
import { isDefined } from '../common/util.js';
class IgcFocusTrapComponent extends LitElement {
static register() {
registerComponent(IgcFocusTrapComponent);
}
get focused() {
return this._focused;
}
get focusableElements() {
return Array.from(getFocusableElements(this));
}
constructor() {
super();
this._focused = false;
this.disabled = false;
this.addEventListener('focusin', this.onFocusIn);
this.addEventListener('focusout', this.onFocusOut);
}
onFocusIn() {
this._focused = true;
}
onFocusOut() {
this._focused = false;
}
focusFirstElement() {
this.focusableElements.at(0)?.focus();
}
focusLastElement() {
this.focusableElements.at(-1)?.focus();
}
render() {
const tabStop = !this.focused || this.disabled ? -1 : 0;
return html `
<div
id="start"
tabindex=${tabStop}
@focus=${this.disabled ? nothing : this.focusLastElement}
></div>
<slot></slot>
<div
id="end"
tabindex=${tabStop}
@focus=${this.disabled ? nothing : this.focusFirstElement}
></div>
`;
}
}
IgcFocusTrapComponent.tagName = 'igc-focus-trap';
IgcFocusTrapComponent.styles = css `
:host {
display: contents;
}
`;
export default IgcFocusTrapComponent;
__decorate([
state()
], IgcFocusTrapComponent.prototype, "_focused", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], IgcFocusTrapComponent.prototype, "disabled", void 0);
const defaultSelectors = [
'[tabindex]',
'a[href]',
'button',
'input',
'select',
'textarea',
];
function isHidden(node) {
return (node.hasAttribute('hidden') ||
node.hasAttribute('inert') ||
(node.hasAttribute('aria-hidden') &&
node.getAttribute('aria-hidden') !== 'false'));
}
function isDisabled(node) {
return node.hasAttribute('disabled') || node.hasAttribute('inert');
}
function isContentEditable(node) {
return (node.hasAttribute('contenteditable') &&
node.getAttribute('contenteditable') !== 'false');
}
function isFocusable(node) {
if (isHidden(node) || isDisabled(node)) {
return false;
}
if (isContentEditable(node)) {
return true;
}
if (node.tabIndex === -1) {
return false;
}
return defaultSelectors.some((selector) => node.matches(selector));
}
function shouldSkipElements(node, cache) {
const element = node;
return isHidden(element) || isDisabled(element) || cache?.has(element)
? NodeFilter.FILTER_REJECT
: NodeFilter.FILTER_ACCEPT;
}
function getSlottedElements(node) {
const slot = node;
const elements = slot.assignedElements();
return { elements, parent: elements.at(0)?.parentElement };
}
function* getFocusableElements(root, cache) {
if (!isDefined(globalThis.document)) {
return;
}
let node;
const _cache = cache ?? new WeakSet();
const visitor = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, (node) => shouldSkipElements(node, _cache));
while ((node = visitor.nextNode())) {
if (_cache.has(node)) {
continue;
}
if (node.shadowRoot) {
yield* getFocusableElements(node.shadowRoot, _cache);
continue;
}
if (node.tagName === 'SLOT') {
const { elements, parent } = getSlottedElements(node);
if (elements.length > 0) {
for (const element of elements) {
yield* getFocusableElements(parent, _cache);
_cache.add(element);
}
}
continue;
}
if (isFocusable(node)) {
yield node;
}
}
}
//# sourceMappingURL=focus-trap.js.map