Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions packages/core/makeup-active-descendant/dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/**
* Implements ARIA active descendant keyboard navigation.
*
* @example
* ```ts
* import * as ActiveDescendant from "makeup-active-descendant";
*
* const widgetEl = document.querySelector(".widget");
* const focusEl = widgetEl.querySelector("input");
* const containerEl = widgetEl.querySelector("ul");
*
* const activeDescendant = ActiveDescendant.createLinear(widgetEl, focusEl, containerEl, "li");
*
* widgetEl.addEventListener("activeDescendantChange", function (e) {
* console.log(e.detail);
* });
* ```
*/

import type { AutoInitOption, AutoResetOption, AxisOption } from "makeup-navigation-emitter";

/**
* Options for creating a linear active descendant
*/
export interface ActiveDescendantOptions {
/**
* The HTML class name that will be applied to the ARIA active descendant element (default: 'active-descendant')
*/
activeDescendantClassName?: string;
/**
* Declares the initial active descendant item (default: "none")
* - "none": no index position is set (useful in programmatic active-descendant)
* - "interactive": first non aria-disabled or hidden element
* - "ariaChecked": first element with aria-checked=true (useful in ARIA menu)
* - "ariaSelected": first element with aria-selected=true (useful in ARIA tabs)
* - "ariaSelectedOrInteractive": first element with aria-selected=true, falling back to "interactive" if not found (useful in ARIA listbox)
* - number: specific index position of items (throws error if non-interactive)
*/
autoInit?: AutoInitOption;
/**
* Declares the active descendant item after a reset and/or when keyboard focus exits the widget (default: "none")
* - "none": no index position is set (useful in programmatic active-descendant)
* - "current": index remains current (radio button like behaviour)
* - "interactive": index moves to first non aria-disabled or hidden element
* - "ariaChecked": index moves to first element with aria-checked=true
* - "ariaSelected": index moves to first element with aria-selected=true
* - number: specific index position of items (throws error if non-interactive)
*/
autoReset?: AutoResetOption;
/**
* Specify true to scroll the container as activeDescendant changes (default: false)
*/
autoScroll?: boolean;
/**
* Specify 'x' for left/right arrow keys, 'y' for up/down arrow keys, or 'both' (default: 'both')
*/
axis?: AxisOption;
/**
* CSS selector of descendant elements that will be ignored by the navigation emitters key event delegation
* (i.e. these elements will _not_ operate the active descendant) (default: null)
*/
ignoreByDelegateSelector?: string | null;
/**
* Specify whether arrow keys should wrap/loop (default: false)
*/
wrap?: boolean;
}

/**
* Event detail for activeDescendantInit event
*/
export interface ActiveDescendantInitEventDetail {
/** All items that match item selector */
items: HTMLElement[];
/** Index position before initialization */
fromIndex: number | null;
/** Index position after initialization */
toIndex: number | null;
}

/**
* Event detail for activeDescendantChange event
*/
export interface ActiveDescendantChangeEventDetail {
/** Index position before change */
fromIndex: number | null;
/** Index position after change */
toIndex: number | null;
}

/**
* Event detail for activeDescendantReset event
*/
export interface ActiveDescendantResetEventDetail {
/** Index position before reset */
fromIndex: number | null;
/** Index position after reset */
toIndex: number | null;
}

/**
* Event detail for activeDescendantMutation event
*/
export interface ActiveDescendantMutationEventDetail {
/** Index position before mutation */
fromIndex: number | null;
/** Index position after mutation */
toIndex: number | null;
}

/**
* Active descendant instance
*/
export interface LinearActiveDescendant {
/** The index position of the current active descendant */
index: number | null;
/** The current item at the index position */
currentItem: HTMLElement | undefined;
/** All items that match item selector */
items: HTMLElement[];
/** Whether arrow keys should wrap/loop */
wrap: boolean;
/**
* Will force a reset to the value specified by `autoReset`
*/
reset(): void;
/**
* Destroys all event listeners
*/
destroy(): void;
}

/**
* Creates a linear active descendant instance
* @param el - Root widget element
* @param focusEl - The focusable element that will have aria-activedescendant set
* @param itemContainerEl - The element that contains the "descendant" items
* @param itemSelector - CSS selector for navigation items
* @param selectedOptions - Optional configuration
* @returns Active descendant instance
*/
export function createLinear(
el: HTMLElement,
focusEl: HTMLElement,
itemContainerEl: HTMLElement,
itemSelector: string,
selectedOptions?: ActiveDescendantOptions
): LinearActiveDescendant;

3 changes: 3 additions & 0 deletions packages/core/makeup-active-descendant/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
"version": "0.7.10",
"main": "./dist/cjs/index.js",
"module": "./dist/mjs/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/mjs/index.js",
"require": "./dist/cjs/index.js"
}
Expand All @@ -30,6 +32,7 @@
"makeup-next-id": "^0.5.7"
},
"files": [
"dist/index.d.ts",
"dist/cjs/index.js",
"dist/mjs/index.js",
"dist/mjs/package.json",
Expand Down
53 changes: 53 additions & 0 deletions packages/core/makeup-exit-emitter/dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Emits custom 'focusExit' event when keyboard focus has exited an element and all of its descendants.
*
* @example
* ```ts
* import * as ExitEmitter from "makeup-exit-emitter";
*
* const el = document.getElementById("widget1");
*
* ExitEmitter.addFocusExit(el);
*
* el.addEventListener("focusExit", function (e) {
* console.log(this, e);
* });
* ```
*/

/**
* Event detail for focusExit event
*/
export interface FocusExitEventDetail {
/** The element that previously had focus */
fromElement: HTMLElement | null;
/** The element that now has focus (undefined if focus left the window) */
toElement: HTMLElement | undefined;
}

/**
* Adds focus exit tracking to an element
* @param el - Element to track focus exit for
* @returns The exit emitter instance (or null if already exists)
*/
export function addFocusExit(el: HTMLElement): FocusExitEmitter | null;

/**
* Removes focus exit tracking from an element
* @param el - Element to remove focus exit tracking from
*/
export function removeFocusExit(el: HTMLElement): void;

/**
* Focus exit emitter instance (internal, returned by addFocusExit)
* @internal
*/
export interface FocusExitEmitter {
/** The element being tracked */
el: HTMLElement;
/** The currently focused element within the tracked element */
currentFocusElement: HTMLElement | null;
/** Removes all event listeners */
removeEventListeners(): void;
}

3 changes: 3 additions & 0 deletions packages/core/makeup-exit-emitter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
"version": "0.5.7",
"main": "./dist/cjs/index.js",
"module": "./dist/mjs/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/mjs/index.js",
"require": "./dist/cjs/index.js"
}
Expand All @@ -29,6 +31,7 @@
"makeup-next-id": "^0.5.7"
},
"files": [
"dist/index.d.ts",
"dist/cjs/index.js",
"dist/mjs/index.js",
"dist/mjs/package.json",
Expand Down
Loading