@agnos-ui/core
Version:
Framework-agnostic headless component library.
145 lines (144 loc) • 5.92 kB
TypeScript
import { type ReadableSignal } from '@amadeus-it-group/tansu';
import type { Directive, SSRHTMLElement } from '../types';
/**
* A type representing a function that determines the neighboring element to focus on.
* @returns The next HTMLElement to focus on, or null if no suitable element is found.
*/
export type FocusNeighbour = (arg?: {
event?: Event;
referenceElement?: HTMLElement | null;
}) => HTMLElement | null;
/**
* A type representing a function that focuses on the end element.
* @returns The HTMLElement that was focused, or null if no element was focused.
*/
export type FocusEnd = (arg?: {
event?: Event;
}) => HTMLElement | null;
/**
* Represents a navigation manager that handles focusable elements in the DOM.
*
* @template T - The type of the configuration for the navigation manager items.
*/
export type NavManager<T> = {
/**
* Store containing the navigable elements in DOM order
*/
elementsInDomOrder$: ReadableSignal<HTMLElement[]>;
/**
* Directive to attach the nav manager
*/
directive: Directive<NavManagerItemConfig<T>, SSRHTMLElement>;
/**
* Refresh the elements list.
* @param now force the instant refresh of the elements
*/
refreshElements: (now?: boolean) => void;
/**
* Focus the element at the given idex.
* If the element at the given index is not focusable, use the moveDirection to step into the next focusable element.
* @param index the index of the element to focus
* @param moveDirection a move direction
* @returns the new focusable element if found, null otherwise
*/
focusIndex: (index: number, moveDirection: -1 | 0 | 1) => HTMLElement | null;
/**
* Focus the previous element, respecting the ancestor direction.
*/
focusPrevious: FocusNeighbour;
/**
* Focus the next element, respecting the ancestor direction.
*/
focusNext: FocusNeighbour;
/**
* Focus the first element, respecting the ancestor direction.
*/
focusFirst: FocusEnd;
/**
* Focus the element at the left-end of the list.
*/
focusFirstLeft: FocusEnd;
/**
* Focus the element at the right-end of the list.
*/
focusFirstRight: FocusEnd;
/**
* Focus the last element, respecting the ancestor direction.
*/
focusLast: FocusEnd;
/**
* Focus the next focusable element to the left of the currently focused element.
*/
focusLeft: FocusNeighbour;
/**
* Focus the next focusable element to the right of the currently focused element.
*/
focusRight: FocusNeighbour;
};
/**
* Returns the key name given the keyboard event. The key name is built using event.key (such as ArrowLeft, PageDown...),
* prefixed with the modifiers. If present, modifiers are always in the same order: Meta+Ctrl+Alt+Shift+...
* @param event - keyboard event
* @returns the name of the key, including modifiers
*/
export declare const getKeyName: (event: KeyboardEvent) => string;
/**
* Returns true if the keyboard event is an ArrowLeft, ArrowRight, Home or End key press that should make the cursor move inside
* the input and false otherwise (i.e. the key is not ArrowLeft, ArrowRight, Home or End key, or that would not make the cursor move
* because it is already at one end of the input)
* @param event - keyboard event
* @returns true if the keyboard event is an ArrowLeft, ArrowRight, Home or End key press that should make the cursor move inside
* the input and false otherwise.
*/
export declare const isInternalInputNavigation: (event: KeyboardEvent) => boolean;
/**
* Type of a key handler of the navigation manager.
* A key handler receives an object as its parameter, with the following properties:
* - event: key event
* - directiveElement: DOM element which has the navigation manager directive
* - navManager: navigation manager instance
* @template T - The type of the context object, defaults to `any`.
*/
export type NavManagerKeyHandler<T = any> = (info: {
directiveElement: HTMLElement;
event: Event;
navManager: NavManager<T>;
context?: T;
}) => void;
/**
* Configuration object for a navigation manager item.
*
* @template T - The type of the context object.
*/
export interface NavManagerItemConfig<T = any> {
/**
* Map of key handlers.
* The key in the map should match the result of calling {@link getKeyName} on the key event (for example "ArrowLeft" or "Ctrl+PageDown").
* The value in the map is the corresponding key handler.
*/
keys?: Record<string, NavManagerKeyHandler<T>>;
/**
* Function returning DOM elements to include in the navigation manager.
* It receives as a parameter the DOM element on which the navigation manager directive is used.
* If not specified, the default selector function only returns the element on which the navigation manager directive is used.
*/
selector?: (directiveElement: HTMLElement) => Iterable<HTMLElement>;
/**
*
*/
context?: T;
}
/**
* Returns a new instance of the navigation manager.
*
* The navigation manager simplifies keyboard navigation for a set of DOM elements.
* It provides a directive to use on some DOM elements, both to add the keydown event handler and to specify which elements should be managed
* (either by directly putting the directive on those elements, or by putting the directive on a parent element and
* specifying which child elements should be included through a selector function).
*
* It provides some utilities to move the focus between those elements (focusFirst/focusLast, focusLeft/focusRight, focusPrevious/focusNext).
*
* @template T - The type of the context object used in the navigation manager.
* @returns An object containing methods and properties for managing focus navigation.
*/
export declare const createNavManager: <T>() => NavManager<T>;