@lumx/core 4.16.0-alpha.4 → 4.16.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/js/components/Combobox/ComboboxOptionTests.d.ts +1 -1
- package/js/components/Combobox/TestStories.d.ts +65 -36
- package/js/components/Combobox/Tests.d.ts +1 -0
- package/js/components/Combobox/types.d.ts +7 -0
- package/js/components/Combobox/utils.d.ts +9 -6
- package/js/components/SelectButton/TestStories.d.ts +8 -0
- package/js/utils/browser/lastDescendant.d.ts +2 -0
- package/js/utils/focusNavigation/createGridFocusNavigation.d.ts +6 -0
- package/js/utils/focusNavigation/createGridSelectors.d.ts +25 -0
- package/js/utils/focusNavigation/createListFocusNavigation.d.ts +6 -0
- package/js/utils/focusNavigation/createListSelectors.d.ts +21 -0
- package/js/utils/focusNavigation/createPendingNavigation.d.ts +7 -0
- package/js/utils/focusNavigation/index.d.ts +1 -1
- package/js/utils/focusNavigation/types.d.ts +36 -92
- package/js/utils/iterable/first.d.ts +2 -0
- package/js/utils/typeahead/index.d.ts +8 -0
- package/package.json +2 -2
|
@@ -9,7 +9,7 @@ type RenderResult = {
|
|
|
9
9
|
*/
|
|
10
10
|
export interface ComboboxOptionTestSetup {
|
|
11
11
|
/** Combobox compound component namespace */
|
|
12
|
-
Combobox: Pick<ComboboxNamespace, 'Provider' | 'List' | 'Option'>;
|
|
12
|
+
Combobox: Pick<ComboboxNamespace, 'Provider' | 'Input' | 'List' | 'Option'>;
|
|
13
13
|
/**
|
|
14
14
|
* Render a JSX template and return a result with a container.
|
|
15
15
|
* The template is a zero-argument function returning a JSX element.
|
|
@@ -17,42 +17,6 @@ export declare function setup({ components: { Combobox, IconButton, Button }, de
|
|
|
17
17
|
};
|
|
18
18
|
};
|
|
19
19
|
};
|
|
20
|
-
AutoFilterOptions: {
|
|
21
|
-
play: ({ canvasElement }: any) => Promise<void>;
|
|
22
|
-
args: {
|
|
23
|
-
value: string;
|
|
24
|
-
};
|
|
25
|
-
decorators: ((story: any, context: any) => any)[];
|
|
26
|
-
render: ({ value, onChange, onSelect, }: {
|
|
27
|
-
value: string;
|
|
28
|
-
onChange: (v: string) => void;
|
|
29
|
-
onSelect?: (option: {
|
|
30
|
-
value: string;
|
|
31
|
-
}) => void;
|
|
32
|
-
}) => import("react").JSX.Element;
|
|
33
|
-
};
|
|
34
|
-
FilterOffOpenOnFocus: {
|
|
35
|
-
play: ({ canvasElement }: any) => Promise<void>;
|
|
36
|
-
args: {
|
|
37
|
-
value: string;
|
|
38
|
-
};
|
|
39
|
-
decorators: ((story: any, context: any) => any)[];
|
|
40
|
-
render: ({ value, onChange, onSelect }: any) => import("react").JSX.Element;
|
|
41
|
-
};
|
|
42
|
-
SelectOptionUpdatesInput: {
|
|
43
|
-
play: ({ canvasElement }: any) => Promise<void>;
|
|
44
|
-
args: {
|
|
45
|
-
value: string;
|
|
46
|
-
};
|
|
47
|
-
decorators: ((story: any, context: any) => any)[];
|
|
48
|
-
render: ({ value, onChange, onSelect, }: {
|
|
49
|
-
value: string;
|
|
50
|
-
onChange: (v: string) => void;
|
|
51
|
-
onSelect?: (option: {
|
|
52
|
-
value: string;
|
|
53
|
-
}) => void;
|
|
54
|
-
}) => import("react").JSX.Element;
|
|
55
|
-
};
|
|
56
20
|
MouseHoverDoesNotActivateOption: {
|
|
57
21
|
play: ({ canvasElement }: any) => Promise<void>;
|
|
58
22
|
args: {
|
|
@@ -140,4 +104,69 @@ export declare function setup({ components: { Combobox, IconButton, Button }, de
|
|
|
140
104
|
onToggle?: (isOpen: boolean) => void;
|
|
141
105
|
}) => import("react").JSX.Element;
|
|
142
106
|
};
|
|
107
|
+
ButtonTypeaheadFromClosed: {
|
|
108
|
+
play: ({ canvasElement }: any) => Promise<void>;
|
|
109
|
+
args: {
|
|
110
|
+
value: string;
|
|
111
|
+
};
|
|
112
|
+
decorators: ((story: any, context: any) => any)[];
|
|
113
|
+
render: ({ value, onSelect }: {
|
|
114
|
+
value: string;
|
|
115
|
+
onSelect: (option: {
|
|
116
|
+
value: string;
|
|
117
|
+
}) => void;
|
|
118
|
+
}) => import("react").JSX.Element;
|
|
119
|
+
};
|
|
120
|
+
ButtonTypeaheadWhileOpen: {
|
|
121
|
+
play: ({ canvasElement }: any) => Promise<void>;
|
|
122
|
+
args: {
|
|
123
|
+
value: string;
|
|
124
|
+
};
|
|
125
|
+
decorators: ((story: any, context: any) => any)[];
|
|
126
|
+
render: ({ value, onSelect }: {
|
|
127
|
+
value: string;
|
|
128
|
+
onSelect: (option: {
|
|
129
|
+
value: string;
|
|
130
|
+
}) => void;
|
|
131
|
+
}) => import("react").JSX.Element;
|
|
132
|
+
};
|
|
133
|
+
ButtonEndFromClosed: {
|
|
134
|
+
play: ({ canvasElement }: any) => Promise<void>;
|
|
135
|
+
args: {
|
|
136
|
+
value: string;
|
|
137
|
+
};
|
|
138
|
+
decorators: ((story: any, context: any) => any)[];
|
|
139
|
+
render: ({ value, onSelect }: {
|
|
140
|
+
value: string;
|
|
141
|
+
onSelect: (option: {
|
|
142
|
+
value: string;
|
|
143
|
+
}) => void;
|
|
144
|
+
}) => import("react").JSX.Element;
|
|
145
|
+
};
|
|
146
|
+
ButtonHomeFromClosed: {
|
|
147
|
+
play: ({ canvasElement }: any) => Promise<void>;
|
|
148
|
+
args: {
|
|
149
|
+
value: string;
|
|
150
|
+
};
|
|
151
|
+
decorators: ((story: any, context: any) => any)[];
|
|
152
|
+
render: ({ value, onSelect }: {
|
|
153
|
+
value: string;
|
|
154
|
+
onSelect: (option: {
|
|
155
|
+
value: string;
|
|
156
|
+
}) => void;
|
|
157
|
+
}) => import("react").JSX.Element;
|
|
158
|
+
};
|
|
159
|
+
ButtonArrowDownFromClosed: {
|
|
160
|
+
play: ({ canvasElement }: any) => Promise<void>;
|
|
161
|
+
args: {
|
|
162
|
+
value: string;
|
|
163
|
+
};
|
|
164
|
+
decorators: ((story: any, context: any) => any)[];
|
|
165
|
+
render: ({ value, onSelect }: {
|
|
166
|
+
value: string;
|
|
167
|
+
onSelect: (option: {
|
|
168
|
+
value: string;
|
|
169
|
+
}) => void;
|
|
170
|
+
}) => import("react").JSX.Element;
|
|
171
|
+
};
|
|
143
172
|
};
|
|
@@ -39,6 +39,7 @@ export interface ComboboxTestSetup {
|
|
|
39
39
|
valueExtract?: (v: any) => any;
|
|
40
40
|
}) => RenderResult;
|
|
41
41
|
}
|
|
42
|
+
export declare function getActiveOption(): HTMLElement | null;
|
|
42
43
|
/**
|
|
43
44
|
* Create framework-agnostic JSX templates for combobox test fixtures.
|
|
44
45
|
* Exported so TestStories.tsx can reuse the same templates for browser-only tests.
|
|
@@ -96,6 +96,13 @@ export interface ComboboxHandle {
|
|
|
96
96
|
setIsOpen(isOpen: boolean): void;
|
|
97
97
|
/** Select an option (or null to clear), fire callback. */
|
|
98
98
|
select(option: HTMLElement | null): void;
|
|
99
|
+
/**
|
|
100
|
+
* Replay the pending navigation intent stored on the focus navigation controller via
|
|
101
|
+
* its `goTo` resolver. Called by the framework wrapper after the option children
|
|
102
|
+
* commit (keyboard opens from the closed state defer navigation until then). No-op
|
|
103
|
+
* when nothing is pending.
|
|
104
|
+
*/
|
|
105
|
+
flushPendingNavigation(): void;
|
|
99
106
|
/**
|
|
100
107
|
* Register an option DOM element for filter notifications.
|
|
101
108
|
* The element's textContent is used as the searchable text.
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
import type { FocusNavigationController } from '../../utils/focusNavigation';
|
|
2
1
|
import type { OptionRegistration, SectionRegistration } from './types';
|
|
3
2
|
/**
|
|
4
3
|
* Get the value for a combobox option element.
|
|
5
4
|
* Uses `data-value` when set; falls back to the element's trimmed `textContent`.
|
|
5
|
+
*
|
|
6
|
+
* This is the *selection* value , which may differ from the visible label
|
|
6
7
|
*/
|
|
7
8
|
export declare function getOptionValue(option: HTMLElement): string;
|
|
9
|
+
/**
|
|
10
|
+
* Get the visible label for a combobox option element (its trimmed `textContent`).
|
|
11
|
+
*
|
|
12
|
+
* Used for typeahead matching: the user types the characters they see, which is the
|
|
13
|
+
* option's label — not its `data-value` (which can be an unrelated id).
|
|
14
|
+
*/
|
|
15
|
+
export declare function getOptionLabel(option: HTMLElement): string;
|
|
8
16
|
/** Returns true when an option carries aria-disabled="true". */
|
|
9
17
|
export declare function isOptionDisabled(option: HTMLElement): boolean;
|
|
10
18
|
/** Returns true when the cell is NOT the first gridcell in its row (i.e., it's an action cell). */
|
|
11
19
|
export declare function isActionCell(cell: HTMLElement): boolean;
|
|
12
|
-
/** Predicate matching an option element that carries `aria-selected="true"`. */
|
|
13
20
|
export declare const isSelected: (el: Element) => boolean;
|
|
14
|
-
/** Navigate to the selected option, or to the first option if none is selected. */
|
|
15
|
-
export declare function goToSelectedOrFirst(nav: FocusNavigationController): void;
|
|
16
|
-
/** Navigate to the selected option, or to the last option if none is selected. */
|
|
17
|
-
export declare function goToSelectedOrLast(nav: FocusNavigationController): void;
|
|
18
21
|
/**
|
|
19
22
|
* Compute the current state of a section and notify when it changed.
|
|
20
23
|
*
|
|
@@ -34,4 +34,12 @@ export declare function setup({ components: { SelectButton }, renderWithState, }
|
|
|
34
34
|
WithInfiniteScroll: {
|
|
35
35
|
play({ canvasElement }: any): Promise<void>;
|
|
36
36
|
};
|
|
37
|
+
TypeaheadWhileOpen: {
|
|
38
|
+
render: () => any;
|
|
39
|
+
play: ({ canvasElement }: any) => Promise<void>;
|
|
40
|
+
};
|
|
41
|
+
TypeaheadFromClosed: {
|
|
42
|
+
render: () => any;
|
|
43
|
+
play: ({ canvasElement }: any) => Promise<void>;
|
|
44
|
+
};
|
|
37
45
|
};
|
|
@@ -2,6 +2,12 @@ import type { FocusNavigationCallbacks, FocusNavigationController, GridNavigatio
|
|
|
2
2
|
/**
|
|
3
3
|
* Create a focus navigation controller for a 2D grid.
|
|
4
4
|
*
|
|
5
|
+
* The controller is composed of two layers:
|
|
6
|
+
* - a pure, side-effect-free **selection** layer ({@link createGridSelectors}) that only
|
|
7
|
+
* resolves/reports rows and cells by querying the DOM, and
|
|
8
|
+
* - a **mover** layer (this function) that commits focus by updating the active-item state
|
|
9
|
+
* (which fires {@link FocusNavigationCallbacks}) on top of the selectors.
|
|
10
|
+
*
|
|
5
11
|
* Supports Up/Down between rows (with column memory) and Left/Right between cells
|
|
6
12
|
* (with wrapping across rows).
|
|
7
13
|
*
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FocusNavigationSelectors, GridNavigationOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Create the pure selection layer for a 2D grid.
|
|
4
|
+
*
|
|
5
|
+
* Everything here is side-effect-free: it only *queries* the DOM to resolve and report
|
|
6
|
+
* rows/cells. No focus is moved and no {@link FocusNavigationCallbacks} are invoked — that
|
|
7
|
+
* is the job of the mover layer built on top of this.
|
|
8
|
+
*
|
|
9
|
+
* @param options Grid navigation options (container, rowSelector, cellSelector).
|
|
10
|
+
* @param getActive Reader for the currently active cell (owned by the mover's active-item state).
|
|
11
|
+
* @param isVisible Predicate deciding whether a row is visible (derived from `isRowVisible`).
|
|
12
|
+
* @returns The public {@link FocusNavigationSelectors} plus the internal
|
|
13
|
+
* {@link GridSelectorHelpers} the mover layer consumes.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createGridSelectors(options: GridNavigationOptions, getActive: () => HTMLElement | null, isVisible: (row: HTMLElement) => boolean): {
|
|
16
|
+
selectors: FocusNavigationSelectors;
|
|
17
|
+
helpers: {
|
|
18
|
+
findFirstVisibleRow: () => HTMLElement | null;
|
|
19
|
+
findLastVisibleRow: () => HTMLElement | null;
|
|
20
|
+
findAllVisibleRows: () => HTMLElement[];
|
|
21
|
+
getRowCells: (row: HTMLElement) => HTMLElement[];
|
|
22
|
+
findParentRow: (cell: HTMLElement) => HTMLElement | null;
|
|
23
|
+
findAdjacentVisibleRow: (fromRow: HTMLElement, direction: "next" | "prev") => HTMLElement | null;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
@@ -2,6 +2,12 @@ import type { FocusNavigationCallbacks, ListFocusNavigationController, ListNavig
|
|
|
2
2
|
/**
|
|
3
3
|
* Create a focus navigation controller for a 1D list.
|
|
4
4
|
*
|
|
5
|
+
* The controller is composed of two layers:
|
|
6
|
+
* - a pure, side-effect-free **selection** layer ({@link createListSelectors}) that only
|
|
7
|
+
* resolves/reports items by querying the DOM, and
|
|
8
|
+
* - a **mover** layer (this function) that commits focus by calling
|
|
9
|
+
* {@link FocusNavigationCallbacks} on top of the selectors.
|
|
10
|
+
*
|
|
5
11
|
* This controller is **stateless** — it does not maintain an internal reference to
|
|
6
12
|
* the active item. Instead it reads the active item from the DOM each time via the
|
|
7
13
|
* `getActiveItem` callback provided in the options. This avoids any desync between
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ListFocusNavigationSelectors, ListNavigationOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Create the pure selection layer for a 1D list.
|
|
4
|
+
*
|
|
5
|
+
* Everything here is side-effect-free: it only *queries* the DOM to resolve and report
|
|
6
|
+
* items. No focus is moved and no {@link FocusNavigationCallbacks} are invoked — that is
|
|
7
|
+
* the job of the mover layer built on top of this (`createListFocusNavigation`).
|
|
8
|
+
*
|
|
9
|
+
* @param options List navigation options (container, itemSelector, itemDisabledSelector, getActiveItem).
|
|
10
|
+
* @returns The public {@link ListFocusNavigationSelectors} plus the internal
|
|
11
|
+
* {@link ListSelectorHelpers} the mover layer consumes.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createListSelectors(options: ListNavigationOptions): {
|
|
14
|
+
selectors: ListFocusNavigationSelectors;
|
|
15
|
+
helpers: {
|
|
16
|
+
createItemWalker: (enabledOnly?: boolean) => TreeWalker;
|
|
17
|
+
findFirstEnabled: () => HTMLElement | null;
|
|
18
|
+
findLastEnabled: () => HTMLElement | null;
|
|
19
|
+
getActiveItem: () => HTMLElement | null;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { FocusNavigationCallbacks, FocusNavigationController, GridNavigationOptions, ListFocusNavigationController,
|
|
1
|
+
export type { FocusNavigationCallbacks, FocusNavigationController, FocusNavigationSelectors, GridNavigationOptions, ListFocusNavigationController, ListFocusNavigationSelectors, ListNavigationOptions, } from './types';
|
|
2
2
|
export type { RovingTabIndexOptions } from './setupRovingTabIndex';
|
|
3
3
|
export { createListFocusNavigation } from './createListFocusNavigation';
|
|
4
4
|
export { createGridFocusNavigation } from './createGridFocusNavigation';
|
|
@@ -1,126 +1,70 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Callbacks for focus state changes.
|
|
3
|
-
* The consumer decides how to manifest focus (roving tabindex, aria-activedescendant, etc.).
|
|
4
|
-
*/
|
|
5
1
|
export interface FocusNavigationCallbacks {
|
|
6
|
-
/** Called when an item becomes the active (focused) item. */
|
|
7
2
|
onActivate(item: HTMLElement): void;
|
|
8
|
-
/** Called when an item is no longer the active item (being replaced or cleared). */
|
|
9
3
|
onDeactivate(item: HTMLElement): void;
|
|
10
|
-
/** Called when focus is completely cleared (no active item). */
|
|
11
4
|
onClear?(): void;
|
|
12
5
|
}
|
|
13
|
-
/** Options for 1D list navigation. */
|
|
14
6
|
export interface ListNavigationOptions {
|
|
15
7
|
type: 'list';
|
|
16
|
-
/** The container element to scan for items. */
|
|
17
8
|
container: HTMLElement;
|
|
18
|
-
/** CSS selector to identify navigable items within the container. */
|
|
19
9
|
itemSelector: string;
|
|
20
|
-
/**
|
|
21
|
-
* Primary navigation axis — determines which arrow keys navigate the list.
|
|
22
|
-
* - `'vertical'` (default): Up/Down navigate, Left/Right are no-ops.
|
|
23
|
-
* - `'horizontal'`: Left/Right navigate, Up/Down are no-ops.
|
|
24
|
-
*/
|
|
25
10
|
direction?: 'vertical' | 'horizontal';
|
|
26
|
-
/** Whether navigation wraps at boundaries (last→first, first→last). Default: false. */
|
|
27
11
|
wrap?: boolean;
|
|
28
|
-
/**
|
|
29
|
-
* CSS selector matching disabled items within the container.
|
|
30
|
-
* Disabled items are skipped during navigation (goUp/goDown/goLeft/goRight/goToFirst/goToLast)
|
|
31
|
-
* but can still be navigated to directly via `goToItem`.
|
|
32
|
-
* Default: no items are disabled.
|
|
33
|
-
*/
|
|
34
12
|
itemDisabledSelector?: string;
|
|
35
|
-
/**
|
|
36
|
-
* Callback returning the currently active item from the DOM.
|
|
37
|
-
*
|
|
38
|
-
* The list navigation controller does **not** maintain an internal active-item
|
|
39
|
-
* reference; instead it delegates to this callback every time it needs the current
|
|
40
|
-
* active item (e.g. before navigating by offset).
|
|
41
|
-
*
|
|
42
|
-
* The callback is expected to read from the DOM (e.g. query `[tabindex="0"]` for
|
|
43
|
-
* roving tabindex, or read `aria-activedescendant` for combobox patterns).
|
|
44
|
-
*
|
|
45
|
-
* Default: `() => null` (no active item).
|
|
46
|
-
*/
|
|
47
13
|
getActiveItem?: () => HTMLElement | null;
|
|
48
14
|
}
|
|
49
|
-
/** Options for 2D grid navigation. */
|
|
50
15
|
export interface GridNavigationOptions {
|
|
51
16
|
type: 'grid';
|
|
52
|
-
/** The container element (grid root) to scan for rows and cells. */
|
|
53
17
|
container: HTMLElement;
|
|
54
|
-
/** CSS selector to identify row elements within the container. */
|
|
55
18
|
rowSelector: string;
|
|
56
|
-
/** CSS selector to identify cell elements within each row. */
|
|
57
19
|
cellSelector: string;
|
|
58
|
-
/**
|
|
59
|
-
* Predicate to determine if a row should be included in navigation.
|
|
60
|
-
* Rows for which this returns `false` are skipped.
|
|
61
|
-
* Default: all rows are visible.
|
|
62
|
-
*/
|
|
63
20
|
isRowVisible?: (row: HTMLElement) => boolean;
|
|
64
|
-
/** Whether navigation wraps at boundaries. Default: false. */
|
|
65
21
|
wrap?: boolean;
|
|
66
22
|
}
|
|
67
|
-
/**
|
|
68
|
-
export
|
|
69
|
-
/** Focus navigation controller interface — works for both 1D lists and 2D grids. */
|
|
70
|
-
export interface FocusNavigationController {
|
|
71
|
-
/** The navigation structure type. */
|
|
72
|
-
readonly type: 'list' | 'grid';
|
|
73
|
-
/** The currently active item, or null if no item is active. */
|
|
23
|
+
/** Pure, side-effect-free selection layer for focus navigation. */
|
|
24
|
+
export interface FocusNavigationSelectors {
|
|
74
25
|
readonly activeItem: HTMLElement | null;
|
|
75
|
-
/** Whether an item is currently active. */
|
|
76
|
-
readonly hasActiveItem: boolean;
|
|
77
|
-
/** Whether there are any navigable items in the container. */
|
|
78
26
|
readonly hasNavigableItems: boolean;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
27
|
+
getFirst(): HTMLElement | null;
|
|
28
|
+
getLast(): HTMLElement | null;
|
|
29
|
+
getMatching(predicate: (item: HTMLElement) => boolean): HTMLElement | null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* List-specific selection layer.
|
|
33
|
+
* Adds {@link findNearestEnabled} and the combined enabled-item selector string.
|
|
34
|
+
*/
|
|
35
|
+
export interface ListFocusNavigationSelectors extends FocusNavigationSelectors {
|
|
36
|
+
readonly enabledItemSelector: string;
|
|
37
|
+
findNearestEnabled(anchor: Node): HTMLElement | null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Focus navigation controller — the mover layer. Every method commits focus via
|
|
41
|
+
* {@link FocusNavigationCallbacks}. The pure read layer lives behind {@link selectors}.
|
|
42
|
+
*
|
|
43
|
+
* To move focus to the first/last navigable item:
|
|
44
|
+
* `goTo((s) => s.getFirst())` / `goTo((s) => s.getLast())`.
|
|
45
|
+
*/
|
|
46
|
+
export interface FocusNavigationController<Selectors extends FocusNavigationSelectors = FocusNavigationSelectors> {
|
|
47
|
+
readonly type: 'list' | 'grid';
|
|
48
|
+
readonly selectors: Selectors;
|
|
87
49
|
goToItem(item: HTMLElement): boolean;
|
|
88
|
-
/**
|
|
89
|
-
* Navigate by offset from the current item.
|
|
90
|
-
* In list mode, moves by items. In grid mode, moves by rows.
|
|
91
|
-
* Positive offsets move forward/down, negative move backward/up.
|
|
92
|
-
*/
|
|
93
50
|
goToOffset(offset: number): boolean;
|
|
94
|
-
/**
|
|
95
|
-
* Navigate to the first item matching a predicate.
|
|
96
|
-
* @returns true if a matching item was found and focused.
|
|
97
|
-
*/
|
|
98
|
-
goToItemMatching(predicate: (item: HTMLElement) => boolean): boolean;
|
|
99
|
-
/** Clear the active item — no item is active after this call. */
|
|
100
51
|
clear(): void;
|
|
101
|
-
/** Navigate up (previous item in vertical list, previous row in grid). */
|
|
102
52
|
goUp(): boolean;
|
|
103
|
-
/** Navigate down (next item in vertical list, next row in grid). */
|
|
104
53
|
goDown(): boolean;
|
|
105
|
-
/** Navigate left (previous item in horizontal list, previous cell in grid). */
|
|
106
54
|
goLeft(): boolean;
|
|
107
|
-
/** Navigate right (next item in horizontal list, next cell in grid). */
|
|
108
55
|
goRight(): boolean;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Extended controller for 1D list navigation.
|
|
112
|
-
* Adds list-specific methods that don't apply to grid navigation.
|
|
113
|
-
*/
|
|
114
|
-
export interface ListFocusNavigationController extends FocusNavigationController {
|
|
115
|
-
/** Combined CSS selector matching enabled (non-disabled) items. */
|
|
116
|
-
readonly enabledItemSelector: string;
|
|
117
56
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* @returns The nearest enabled item, or null if no enabled items exist.
|
|
57
|
+
* Navigate via a resolver, deferring when the target is not yet in the DOM.
|
|
58
|
+
* ```ts
|
|
59
|
+
* nav.goTo((sel) => sel.getMatching(isSelected) ?? sel.getFirst());
|
|
60
|
+
* ```
|
|
124
61
|
*/
|
|
125
|
-
|
|
62
|
+
goTo(resolve: (selectors: Selectors) => HTMLElement | null): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Replay the pending navigation intent stored by {@link goTo}.
|
|
65
|
+
* No-op when nothing is pending.
|
|
66
|
+
*/
|
|
67
|
+
flushPendingNavigation(): void;
|
|
68
|
+
}
|
|
69
|
+
export interface ListFocusNavigationController extends FocusNavigationController<ListFocusNavigationSelectors> {
|
|
126
70
|
}
|
|
@@ -7,6 +7,14 @@ export interface Typeahead {
|
|
|
7
7
|
* @returns The matched item, or null.
|
|
8
8
|
*/
|
|
9
9
|
handle(key: string, currentItem: HTMLElement | null): HTMLElement | null;
|
|
10
|
+
/**
|
|
11
|
+
* Re-run the match for the *current* accumulated search string against the
|
|
12
|
+
* live DOM, without appending a new character or resetting the timeout.
|
|
13
|
+
|
|
14
|
+
* @param currentItem The currently active item.
|
|
15
|
+
* @returns The matched item, or null.
|
|
16
|
+
*/
|
|
17
|
+
rematch(currentItem: HTMLElement | null): HTMLElement | null;
|
|
10
18
|
/** Reset the accumulated search string. */
|
|
11
19
|
reset(): void;
|
|
12
20
|
}
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@floating-ui/dom": "^1.7.5",
|
|
10
|
-
"@lumx/icons": "^4.16.0-alpha.
|
|
10
|
+
"@lumx/icons": "^4.16.0-alpha.5",
|
|
11
11
|
"classnames": "^2.3.2",
|
|
12
12
|
"focus-visible": "^5.0.2",
|
|
13
13
|
"lodash": "4.18.1",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"update-version-changelog": "yarn version-changelog ../../CHANGELOG.md"
|
|
70
70
|
},
|
|
71
71
|
"sideEffects": false,
|
|
72
|
-
"version": "4.16.0-alpha.
|
|
72
|
+
"version": "4.16.0-alpha.5",
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
75
75
|
"@testing-library/dom": "^10.4.1",
|