File

projects/storefrontlib/layout/a11y/keyboard-focus/tab/tab-focus.service.ts

Extends

AutoFocusService

Index

Properties
Methods

Methods

findFocusable
findFocusable(host: HTMLElement, locked, invisible)

Returns all focusable child elements of the host element.

Parameters :
Name Type Optional Default value Description
host HTMLElement No

The host element is used to query child focusable elements.

locked No false

Indicates if locked elements (tabindex=-1) should be returned, defaults to false.

invisible No false

Indicates if invisible child elements should be returned, defaults to false.

Returns : HTMLElement[]
Protected findNext
findNext(host: HTMLElement, config: TabFocusConfig, increment: MOVE_FOCUS)
Parameters :
Name Type Optional
host HTMLElement No
config TabFocusConfig No
increment MOVE_FOCUS No
Returns : HTMLElement
Protected findNextScrollable
findNextScrollable(host: HTMLElement, config: TabFocusConfig, increment: MOVE_FOCUS)

builds out virtual slides out of the full scrollable area, to allow for maximum flexibility for the underlying layout without using hardcoded slide sizes.

Parameters :
Name Type Optional
host HTMLElement No
config TabFocusConfig No
increment MOVE_FOCUS No
Returns : HTMLElement
Protected getActiveChild
getActiveChild(host: HTMLElement, config: TabFocusConfig)

Returns the active focusable child element. If there's no active focusable child element, the first focusable child is returned.

Parameters :
Name Type Optional
host HTMLElement No
config TabFocusConfig No
Returns : HTMLElement
Protected getChildren
getChildren(host: HTMLElement, config: TabFocusConfig)
Parameters :
Name Type Optional
host HTMLElement No
config TabFocusConfig No
Returns : HTMLElement[]
Protected isActive
isActive(el: HTMLElement)
Parameters :
Name Type Optional
el HTMLElement No
Returns : boolean
moveTab
moveTab(host: HTMLElement, config: TabFocusConfig, increment: MOVE_FOCUS, event: KeyboardEvent)

Moves to the next (or previous) tab.

Parameters :
Name Type Optional
host HTMLElement No
config TabFocusConfig No
increment MOVE_FOCUS No
event KeyboardEvent No
Returns : void
findFirstFocusable
findFirstFocusable(host: HTMLElement, config: AutoFocusConfig)
Inherited from AutoFocusService

Returns the first focusable child element of the host element.

Parameters :
Name Type Optional Default value
host HTMLElement No
config AutoFocusConfig No { autofocus: true }
Returns : HTMLElement
Protected getPersisted
getPersisted(host: HTMLElement, group?: string)
Inherited from AutoFocusService

Returns the element that has a persisted focus state.

groups and remain the persistence

Parameters :
Name Type Optional Description
host HTMLElement No

the HTMLElement used to query for focusable children

group string Yes

the optional group for the persistent state, to separate different focus groups and remain the persistence

Returns : HTMLElement
hasPersistedFocus
hasPersistedFocus(host: HTMLElement, config: PersistFocusConfig)
Inherited from AutoFocusService

Indicates whether any of the focusable child elements is focused.

Parameters :
Name Type Optional
host HTMLElement No
config PersistFocusConfig No
Returns : boolean
handleEscape
handleEscape(host: HTMLElement, config: EscapeFocusConfig, event: KeyboardEvent)
Inherited from EscapeFocusService
Parameters :
Name Type Optional
host HTMLElement No
config EscapeFocusConfig No
event KeyboardEvent No
Returns : void
shouldFocus
shouldFocus(config: EscapeFocusConfig)
Inherited from EscapeFocusService
Parameters :
Name Type Optional
config EscapeFocusConfig No
Returns : boolean
clear
clear(group?: string)
Inherited from PersistFocusService

Clears the persisted keyboard focus state globally or for the given group.

Parameters :
Name Type Optional
group string Yes
Returns : void
get
get(group?: string)
Inherited from PersistFocusService
Parameters :
Name Type Optional
group string Yes
Returns : string
getPersistenceGroup
getPersistenceGroup(host: HTMLElement, config?: PersistFocusConfig)
Inherited from PersistFocusService

Returns the group for the host element based on the configured group or by the data-cx-focus-group attribute stored on the host.

Parameters :
Name Type Optional
host HTMLElement No
config PersistFocusConfig Yes
Returns : string
set
set(key: string, group?: string)
Inherited from PersistFocusService

Persist the keyboard focus state for the given key. The focus is stored globally or for the given group.

Parameters :
Name Type Optional
key string No
group string Yes
Returns : void

Properties

Protected focus
Default value : new Map<string, string>()
Inherited from PersistFocusService
import { Injectable } from '@angular/core';
import { AutoFocusService } from '../autofocus/auto-focus.service';
import { MOVE_FOCUS, TabFocusConfig } from '../keyboard-focus.model';

@Injectable({
  providedIn: 'root',
})
export class TabFocusService extends AutoFocusService {
  /**
   * Moves to the next (or previous) tab.
   */
  moveTab(
    host: HTMLElement,
    config: TabFocusConfig,
    increment: MOVE_FOCUS,
    event: KeyboardEvent
  ): void {
    if (config?.tab) {
      const next =
        config.tab === 'scroll'
          ? this.findNextScrollable(host, config, increment)
          : this.findNext(host, config, increment);

      next?.focus();

      event.preventDefault();
      event.stopPropagation();
    }
  }

  /**
   * builds out virtual slides out of the full scrollable area, to allow
   * for maximum flexibility for the underlying layout without using hardcoded
   * slide sizes.
   */
  protected findNextScrollable(
    host: HTMLElement,
    config: TabFocusConfig,
    increment: MOVE_FOCUS
  ): HTMLElement {
    const active = this.getActiveChild(host, config);

    if (!active) {
      return;
    }
    // slide count
    const virtualSlideCount = Math.round(host.scrollWidth / host.clientWidth);

    // find current virtual slide
    const currentVirtualSlide = Math.round(
      active.offsetLeft / (host.scrollWidth / virtualSlideCount)
    );

    let nextVirtualSlide = currentVirtualSlide + increment;
    if (
      increment === MOVE_FOCUS.NEXT &&
      nextVirtualSlide >= virtualSlideCount
    ) {
      nextVirtualSlide = 0;
    }
    if (increment === MOVE_FOCUS.PREV && nextVirtualSlide < 0) {
      nextVirtualSlide = virtualSlideCount - 1;
    }

    const firstItemOnNextSlide = this.getChildren(host, config)?.find(
      (tab) =>
        tab.offsetLeft >=
        (host.scrollWidth / virtualSlideCount) * nextVirtualSlide
    );

    return firstItemOnNextSlide;
  }

  protected findNext(
    host: HTMLElement,
    config: TabFocusConfig,
    increment: MOVE_FOCUS
  ): HTMLElement {
    const childs = this.getChildren(host, config);
    let activeIndex = childs?.findIndex(
      (c) => c === this.getActiveChild(host, config)
    );

    if (!activeIndex || activeIndex === -1) {
      activeIndex = 0;
    }
    activeIndex += increment;

    if (increment === MOVE_FOCUS.NEXT && activeIndex >= childs?.length) {
      activeIndex = childs.length - 1;
    }
    if (increment === MOVE_FOCUS.PREV && activeIndex < 0) {
      activeIndex = 0;
    }
    return childs ? childs[activeIndex] : undefined;
  }

  /**
   * Returns the active focusable child element. If there's no active
   * focusable child element, the first focusable child is returned.
   */
  protected getActiveChild(
    host: HTMLElement,
    config: TabFocusConfig
  ): HTMLElement {
    const persisted = this.getPersisted(host, config?.group);
    if (persisted) {
      return persisted;
    }
    const children = this.getChildren(host, config);
    let index = children.findIndex((tab) => this.isActive(tab));
    if (!index || index === -1) {
      index = 0;
    }
    return children[index];
  }

  protected getChildren(
    host: HTMLElement,
    config: TabFocusConfig
  ): HTMLElement[] {
    if (typeof config.tab === 'string' && config.tab !== 'scroll') {
      return this.selectFocusUtil.query(host, config.tab);
    } else {
      return this.findFocusable(host, true);
    }
  }

  /**
   * Returns all focusable child elements of the host element.
   *
   * @param host The host element is used to query child focusable elements.
   * @param locked Indicates if locked elements (tabindex=-1) should be returned, defaults to false.
   * @param invisible Indicates if invisible child elements should be returned, defaults to false.
   */
  findFocusable(
    host: HTMLElement,
    locked = false,
    invisible = false
  ): HTMLElement[] {
    return this.selectFocusUtil.findFocusable(host, locked, invisible);
  }

  protected isActive(el: HTMLElement): boolean {
    const child = document.activeElement;
    const selector = child.tagName;

    return (
      el === child ||
      !!Array.from(el.querySelectorAll(selector)).find((e) => e === child)
    );
  }
}

result-matching ""

    No results matching ""