@ariakit/core 0.0.1 → 0.1.0
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/.eslintignore +6 -0
- package/CHANGELOG.md +18 -0
- package/checkbox/checkbox-store/package.json +7 -0
- package/cjs/__chunks/2YFRPUZP.cjs +30 -0
- package/cjs/__chunks/3BBA3Z5G.cjs +143 -0
- package/cjs/__chunks/3KP2MDG6.cjs +1491 -0
- package/cjs/__chunks/5D5Y5EI4.cjs +146 -0
- package/cjs/__chunks/7ZXWQTAY.cjs +71 -0
- package/cjs/__chunks/AZVDLKO3.cjs +286 -0
- package/cjs/__chunks/EFEGT32M.cjs +12 -0
- package/cjs/__chunks/EIDN2CWH.cjs +57 -0
- package/cjs/__chunks/GDZQUFNP.cjs +30 -0
- package/cjs/__chunks/NX5OHIMM.cjs +169 -0
- package/cjs/__chunks/OFNGELMA.cjs +182 -0
- package/cjs/checkbox/checkbox-store.cjs +27 -0
- package/cjs/checkbox/checkbox-store.d.ts +34 -0
- package/cjs/collection/collection-store.cjs +9 -0
- package/cjs/collection/collection-store.d.ts +65 -0
- package/cjs/combobox/combobox-store.cjs +163 -0
- package/cjs/combobox/combobox-store.d.ts +67 -0
- package/cjs/composite/composite-overflow-store.cjs +15 -0
- package/cjs/composite/composite-overflow-store.d.ts +10 -0
- package/cjs/composite/composite-store.cjs +11 -0
- package/cjs/composite/composite-store.d.ts +202 -0
- package/cjs/dialog/dialog-store.cjs +9 -0
- package/cjs/dialog/dialog-store.d.ts +10 -0
- package/cjs/disclosure/disclosure-store.cjs +8 -0
- package/cjs/disclosure/disclosure-store.d.ts +87 -0
- package/cjs/form/form-store.cjs +241 -0
- package/cjs/form/form-store.d.ts +236 -0
- package/cjs/form/types.cjs +1 -0
- package/cjs/form/types.d.ts +38 -0
- package/cjs/hovercard/hovercard-store.cjs +11 -0
- package/cjs/hovercard/hovercard-store.d.ts +45 -0
- package/cjs/index.cjs +5 -0
- package/cjs/index.d.ts +2 -0
- package/cjs/menu/menu-bar-store.cjs +27 -0
- package/cjs/menu/menu-bar-store.d.ts +10 -0
- package/cjs/menu/menu-store.cjs +108 -0
- package/cjs/menu/menu-store.d.ts +70 -0
- package/cjs/popover/popover-store.cjs +10 -0
- package/cjs/popover/popover-store.d.ts +150 -0
- package/cjs/radio/radio-store.cjs +36 -0
- package/cjs/radio/radio-store.d.ts +31 -0
- package/cjs/select/select-store.cjs +164 -0
- package/cjs/select/select-store.d.ts +87 -0
- package/cjs/tab/tab-store.cjs +126 -0
- package/cjs/tab/tab-store.d.ts +78 -0
- package/cjs/toolbar/toolbar-store.cjs +27 -0
- package/cjs/toolbar/toolbar-store.d.ts +21 -0
- package/cjs/tooltip/tooltip-store.cjs +98 -0
- package/cjs/tooltip/tooltip-store.d.ts +28 -0
- package/cjs/tsconfig.build.tsbuildinfo +1 -0
- package/cjs/utils/array.cjs +12 -0
- package/cjs/utils/array.d.ts +29 -0
- package/cjs/utils/dom.cjs +38 -0
- package/cjs/utils/dom.d.ts +105 -0
- package/cjs/utils/events.cjs +132 -0
- package/cjs/utils/events.d.ts +73 -0
- package/cjs/utils/focus.cjs +222 -0
- package/cjs/utils/focus.d.ts +117 -0
- package/cjs/utils/misc.cjs +40 -0
- package/cjs/utils/misc.d.ts +111 -0
- package/cjs/utils/platform.cjs +15 -0
- package/cjs/utils/platform.d.ts +20 -0
- package/cjs/utils/store.cjs +9 -0
- package/cjs/utils/store.d.ts +99 -0
- package/cjs/utils/types.cjs +1 -0
- package/cjs/utils/types.d.ts +72 -0
- package/collection/collection-store/package.json +7 -0
- package/combobox/combobox-store/package.json +7 -0
- package/composite/composite-overflow-store/package.json +7 -0
- package/composite/composite-store/package.json +7 -0
- package/dialog/dialog-store/package.json +7 -0
- package/disclosure/disclosure-store/package.json +7 -0
- package/esm/__chunks/5XEKIOCW.js +30 -0
- package/esm/__chunks/6U25WEDX.js +286 -0
- package/esm/__chunks/6UPCMUXT.js +1491 -0
- package/esm/__chunks/ADRUFBEO.js +12 -0
- package/esm/__chunks/DXA3K2FY.js +30 -0
- package/esm/__chunks/HCKYJLMC.js +71 -0
- package/esm/__chunks/KLKI3AIB.js +146 -0
- package/esm/__chunks/L7KN5AYP.js +169 -0
- package/esm/__chunks/RX3ZUQ6U.js +57 -0
- package/esm/__chunks/UOJSZ35L.js +143 -0
- package/esm/__chunks/UVCATTRC.js +182 -0
- package/esm/checkbox/checkbox-store.d.ts +34 -0
- package/esm/checkbox/checkbox-store.js +27 -0
- package/esm/collection/collection-store.d.ts +65 -0
- package/esm/collection/collection-store.js +9 -0
- package/esm/combobox/combobox-store.d.ts +67 -0
- package/esm/combobox/combobox-store.js +163 -0
- package/esm/composite/composite-overflow-store.d.ts +10 -0
- package/esm/composite/composite-overflow-store.js +15 -0
- package/esm/composite/composite-store.d.ts +202 -0
- package/esm/composite/composite-store.js +11 -0
- package/esm/dialog/dialog-store.d.ts +10 -0
- package/esm/dialog/dialog-store.js +9 -0
- package/esm/disclosure/disclosure-store.d.ts +87 -0
- package/esm/disclosure/disclosure-store.js +8 -0
- package/esm/form/form-store.d.ts +236 -0
- package/esm/form/form-store.js +241 -0
- package/esm/form/types.d.ts +38 -0
- package/esm/form/types.js +0 -0
- package/esm/hovercard/hovercard-store.d.ts +45 -0
- package/esm/hovercard/hovercard-store.js +11 -0
- package/esm/index.d.ts +2 -0
- package/esm/index.js +5 -0
- package/esm/menu/menu-bar-store.d.ts +10 -0
- package/esm/menu/menu-bar-store.js +27 -0
- package/esm/menu/menu-store.d.ts +70 -0
- package/esm/menu/menu-store.js +108 -0
- package/esm/popover/popover-store.d.ts +150 -0
- package/esm/popover/popover-store.js +10 -0
- package/esm/radio/radio-store.d.ts +31 -0
- package/esm/radio/radio-store.js +36 -0
- package/esm/select/select-store.d.ts +87 -0
- package/esm/select/select-store.js +164 -0
- package/esm/tab/tab-store.d.ts +78 -0
- package/esm/tab/tab-store.js +126 -0
- package/esm/toolbar/toolbar-store.d.ts +21 -0
- package/esm/toolbar/toolbar-store.js +27 -0
- package/esm/tooltip/tooltip-store.d.ts +28 -0
- package/esm/tooltip/tooltip-store.js +98 -0
- package/esm/tsconfig.build.tsbuildinfo +1 -0
- package/esm/utils/array.d.ts +29 -0
- package/esm/utils/array.js +12 -0
- package/esm/utils/dom.d.ts +105 -0
- package/esm/utils/dom.js +38 -0
- package/esm/utils/events.d.ts +73 -0
- package/esm/utils/events.js +132 -0
- package/esm/utils/focus.d.ts +117 -0
- package/esm/utils/focus.js +222 -0
- package/esm/utils/misc.d.ts +111 -0
- package/esm/utils/misc.js +40 -0
- package/esm/utils/platform.d.ts +20 -0
- package/esm/utils/platform.js +15 -0
- package/esm/utils/store.d.ts +99 -0
- package/esm/utils/store.js +9 -0
- package/esm/utils/types.d.ts +72 -0
- package/esm/utils/types.js +0 -0
- package/form/form-store/package.json +7 -0
- package/form/types/package.json +7 -0
- package/hovercard/hovercard-store/package.json +7 -0
- package/license +21 -0
- package/menu/menu-bar-store/package.json +7 -0
- package/menu/menu-store/package.json +7 -0
- package/package.json +137 -6
- package/popover/popover-store/package.json +7 -0
- package/radio/radio-store/package.json +7 -0
- package/select/select-store/package.json +7 -0
- package/tab/tab-store/package.json +7 -0
- package/toolbar/toolbar-store/package.json +7 -0
- package/tooltip/tooltip-store/package.json +7 -0
- package/tsconfig.build.json +4 -0
- package/utils/array/package.json +7 -0
- package/utils/dom/package.json +7 -0
- package/utils/events/package.json +7 -0
- package/utils/focus/package.json +7 -0
- package/utils/misc/package.json +7 -0
- package/utils/platform/package.json +7 -0
- package/utils/store/package.json +7 -0
- package/utils/types/package.json +7 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { AnyObject, SetStateAction } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a store.
|
|
4
|
+
* @param initialState Initial state.
|
|
5
|
+
* @param stores Stores to extend.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createStore<S extends State>(initialState: S, ...stores: Array<Partial<Store<Partial<S>>> | undefined>): Store<S>;
|
|
8
|
+
/**
|
|
9
|
+
* Merges multiple stores into a single store.
|
|
10
|
+
*/
|
|
11
|
+
export declare function mergeStore<S extends State>(...stores: Array<Partial<Store<S>> | undefined>): Store<S>;
|
|
12
|
+
/**
|
|
13
|
+
* Store state type.
|
|
14
|
+
*/
|
|
15
|
+
export type State = AnyObject;
|
|
16
|
+
/**
|
|
17
|
+
* Initial state that can be passed to a store creator function.
|
|
18
|
+
* @template S State type.
|
|
19
|
+
* @template K Key type.
|
|
20
|
+
*/
|
|
21
|
+
export type StoreOptions<S extends State, K extends keyof S> = Partial<Pick<S, K>>;
|
|
22
|
+
/**
|
|
23
|
+
* Props that can be passed to a store creator function.
|
|
24
|
+
* @template S State type.
|
|
25
|
+
*/
|
|
26
|
+
export type StoreProps<S extends State = State> = {
|
|
27
|
+
store?: Store<Partial<S>>;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Extracts the state type from a store type.
|
|
31
|
+
* @template T Store type.
|
|
32
|
+
*/
|
|
33
|
+
export type StoreState<T> = T extends {
|
|
34
|
+
getState(): infer S;
|
|
35
|
+
} ? S : never;
|
|
36
|
+
/**
|
|
37
|
+
* Store listener type.
|
|
38
|
+
* @template S State type.
|
|
39
|
+
*/
|
|
40
|
+
export type Listener<S> = (state: S, prevState: S) => void | (() => void);
|
|
41
|
+
/**
|
|
42
|
+
* Subscriber function type used by `sync`, `subscribe` and `effect`.
|
|
43
|
+
* @template S State type.
|
|
44
|
+
*/
|
|
45
|
+
export type Sync<S = State> = {
|
|
46
|
+
/**
|
|
47
|
+
* @param listener The listener function. It's called with the current state
|
|
48
|
+
* and the previous state as arguments and may return a cleanup function.
|
|
49
|
+
* @param keys Optional array of state keys to listen to.
|
|
50
|
+
*/
|
|
51
|
+
<K extends keyof S = keyof S>(listener: Listener<Pick<S, K>>, keys?: K[]): () => void;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Store.
|
|
55
|
+
* @template S State type.
|
|
56
|
+
*/
|
|
57
|
+
export interface Store<S = State> {
|
|
58
|
+
/**
|
|
59
|
+
* Returns the current store state.
|
|
60
|
+
*/
|
|
61
|
+
getState(): S;
|
|
62
|
+
/**
|
|
63
|
+
* Sets a state value.
|
|
64
|
+
*/
|
|
65
|
+
setState<K extends keyof S>(key: K, value: SetStateAction<S[K]>): void;
|
|
66
|
+
/**
|
|
67
|
+
* Register a callback function that's called when the store is initialized.
|
|
68
|
+
*/
|
|
69
|
+
setup: (callback: () => void | (() => void)) => () => void;
|
|
70
|
+
/**
|
|
71
|
+
* Function that should be called when the store is initialized.
|
|
72
|
+
*/
|
|
73
|
+
init: () => () => void;
|
|
74
|
+
/**
|
|
75
|
+
* Registers a listener function that's called immediately and synchronously
|
|
76
|
+
* whenever the store state changes.
|
|
77
|
+
*/
|
|
78
|
+
sync: Sync<S>;
|
|
79
|
+
/**
|
|
80
|
+
* Registers a listener function that's called after state changes in the
|
|
81
|
+
* store.
|
|
82
|
+
*/
|
|
83
|
+
subscribe: Sync<S>;
|
|
84
|
+
/**
|
|
85
|
+
* Registers a listener function that's called immediately and after a batch
|
|
86
|
+
* of state changes in the store.
|
|
87
|
+
*/
|
|
88
|
+
syncBatch: Sync<S>;
|
|
89
|
+
/**
|
|
90
|
+
* Creates a new store with a subset of the current store state and keeps them
|
|
91
|
+
* in sync.
|
|
92
|
+
*/
|
|
93
|
+
pick<K extends Array<keyof S>>(...keys: K): Store<Pick<S, K[number]>>;
|
|
94
|
+
/**
|
|
95
|
+
* Creates a new store with a subset of the current store state and keeps them
|
|
96
|
+
* in sync.
|
|
97
|
+
*/
|
|
98
|
+
omit<K extends Array<keyof S>>(...keys: K): Store<Omit<S, K[number]>>;
|
|
99
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Any object.
|
|
3
|
+
*/
|
|
4
|
+
export type AnyObject = Record<string, any>;
|
|
5
|
+
/**
|
|
6
|
+
* Any function.
|
|
7
|
+
*/
|
|
8
|
+
export type AnyFunction = (...args: any) => any;
|
|
9
|
+
/**
|
|
10
|
+
* Workaround for variance issues.
|
|
11
|
+
* @template T The type of the callback.
|
|
12
|
+
*/
|
|
13
|
+
export type BivariantCallback<T extends AnyFunction> = {
|
|
14
|
+
bivarianceHack(...args: Parameters<T>): ReturnType<T>;
|
|
15
|
+
}["bivarianceHack"];
|
|
16
|
+
/**
|
|
17
|
+
* @template T The state type.
|
|
18
|
+
*/
|
|
19
|
+
export type SetStateAction<T> = T | BivariantCallback<(prevState: T) => T>;
|
|
20
|
+
/**
|
|
21
|
+
* The type of the `setState` function in `[state, setState] = useState()`.
|
|
22
|
+
* @template T The type of the state.
|
|
23
|
+
*/
|
|
24
|
+
export type SetState<T> = BivariantCallback<(value: SetStateAction<T>) => void>;
|
|
25
|
+
/**
|
|
26
|
+
* A boolean value or a callback that returns a boolean value.
|
|
27
|
+
* @template T The type of the callback parameter.
|
|
28
|
+
*/
|
|
29
|
+
export type BooleanOrCallback<T> = boolean | BivariantCallback<(arg: T) => boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* A string that will provide autocomplete for specific strings.
|
|
32
|
+
* @template T The specific strings.
|
|
33
|
+
*/
|
|
34
|
+
export type StringWithValue<T extends string> = T | (string & {
|
|
35
|
+
[key in symbol]: never;
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Transforms a type into a primitive type.
|
|
39
|
+
* @template T The type to transform.
|
|
40
|
+
* @example
|
|
41
|
+
* // string
|
|
42
|
+
* ToPrimitive<"a">;
|
|
43
|
+
* // number
|
|
44
|
+
* ToPrimitive<1>;
|
|
45
|
+
*/
|
|
46
|
+
export type ToPrimitive<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T extends AnyFunction ? (...args: Parameters<T>) => ReturnType<T> : T;
|
|
47
|
+
/**
|
|
48
|
+
* Picks only the properties from a type that have a specific value.
|
|
49
|
+
* @template T The type to pick from.
|
|
50
|
+
* @template Value The value to pick.
|
|
51
|
+
*/
|
|
52
|
+
export type PickByValue<T, Value> = {
|
|
53
|
+
[K in keyof T as [Value] extends [T[K]] ? T[K] extends Value | undefined ? K : never : never]: T[K];
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Picks only the required properties from a type.
|
|
57
|
+
* @template T The type to pick from.
|
|
58
|
+
* @template P The properties to pick.
|
|
59
|
+
*/
|
|
60
|
+
export type PickRequired<T, P extends keyof T> = T & {
|
|
61
|
+
[K in keyof T]: Pick<Required<T>, K>;
|
|
62
|
+
}[P];
|
|
63
|
+
/**
|
|
64
|
+
* Indicates the availability and type of interactive popup element, such as
|
|
65
|
+
* menu or dialog, that can be triggered by an element.
|
|
66
|
+
*/
|
|
67
|
+
export type AriaHasPopup = boolean | "false" | "true" | "menu" | "listbox" | "tree" | "grid" | "dialog" | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* All the WAI-ARIA 1.1 role attribute values from
|
|
70
|
+
* https://www.w3.org/TR/wai-aria-1.1/#role_definitions
|
|
71
|
+
*/
|
|
72
|
+
export type AriaRole = "alert" | "alertdialog" | "application" | "article" | "banner" | "button" | "cell" | "checkbox" | "columnheader" | "combobox" | "complementary" | "contentinfo" | "definition" | "dialog" | "directory" | "document" | "feed" | "figure" | "form" | "grid" | "gridcell" | "group" | "heading" | "img" | "link" | "list" | "listbox" | "listitem" | "log" | "main" | "marquee" | "math" | "menu" | "menubar" | "menuitem" | "menuitemcheckbox" | "menuitemradio" | "navigation" | "none" | "note" | "option" | "presentation" | "progressbar" | "radio" | "radiogroup" | "region" | "row" | "rowgroup" | "rowheader" | "scrollbar" | "search" | "searchbox" | "separator" | "slider" | "spinbutton" | "status" | "switch" | "tab" | "table" | "tablist" | "tabpanel" | "term" | "textbox" | "timer" | "toolbar" | "tooltip" | "tree" | "treegrid" | "treeitem" | (string & {});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// src/utils/array.ts
|
|
2
|
+
function toArray(arg) {
|
|
3
|
+
if (Array.isArray(arg)) {
|
|
4
|
+
return arg;
|
|
5
|
+
}
|
|
6
|
+
return typeof arg !== "undefined" ? [arg] : [];
|
|
7
|
+
}
|
|
8
|
+
function addItemToArray(array, item, index = -1) {
|
|
9
|
+
if (!(index in array)) {
|
|
10
|
+
return [...array, item];
|
|
11
|
+
}
|
|
12
|
+
return [...array.slice(0, index), item, ...array.slice(index)];
|
|
13
|
+
}
|
|
14
|
+
function flatten2DArray(array) {
|
|
15
|
+
const flattened = [];
|
|
16
|
+
for (const row of array) {
|
|
17
|
+
flattened.push(...row);
|
|
18
|
+
}
|
|
19
|
+
return flattened;
|
|
20
|
+
}
|
|
21
|
+
function reverseArray(array) {
|
|
22
|
+
return array.slice().reverse();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
toArray,
|
|
27
|
+
addItemToArray,
|
|
28
|
+
flatten2DArray,
|
|
29
|
+
reverseArray
|
|
30
|
+
};
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createCollectionStore
|
|
3
|
+
} from "./L7KN5AYP.js";
|
|
4
|
+
import {
|
|
5
|
+
createStore
|
|
6
|
+
} from "./UOJSZ35L.js";
|
|
7
|
+
import {
|
|
8
|
+
defaultValue
|
|
9
|
+
} from "./KLKI3AIB.js";
|
|
10
|
+
import {
|
|
11
|
+
flatten2DArray,
|
|
12
|
+
reverseArray
|
|
13
|
+
} from "./5XEKIOCW.js";
|
|
14
|
+
|
|
15
|
+
// src/composite/composite-store.ts
|
|
16
|
+
var NULL_ITEM = { id: null };
|
|
17
|
+
function findFirstEnabledItem(items, excludeId) {
|
|
18
|
+
return items.find((item) => {
|
|
19
|
+
if (excludeId) {
|
|
20
|
+
return !item.disabled && item.id !== excludeId;
|
|
21
|
+
}
|
|
22
|
+
return !item.disabled;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function getEnabledItems(items, excludeId) {
|
|
26
|
+
return items.filter((item) => {
|
|
27
|
+
if (excludeId) {
|
|
28
|
+
return !item.disabled && item.id !== excludeId;
|
|
29
|
+
}
|
|
30
|
+
return !item.disabled;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function getOppositeOrientation(orientation) {
|
|
34
|
+
if (orientation === "vertical")
|
|
35
|
+
return "horizontal";
|
|
36
|
+
if (orientation === "horizontal")
|
|
37
|
+
return "vertical";
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
function getItemsInRow(items, rowId) {
|
|
41
|
+
return items.filter((item) => item.rowId === rowId);
|
|
42
|
+
}
|
|
43
|
+
function flipItems(items, activeId, shouldInsertNullItem = false) {
|
|
44
|
+
const index = items.findIndex((item) => item.id === activeId);
|
|
45
|
+
return [
|
|
46
|
+
...items.slice(index + 1),
|
|
47
|
+
...shouldInsertNullItem ? [NULL_ITEM] : [],
|
|
48
|
+
...items.slice(0, index)
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
function groupItemsByRows(items) {
|
|
52
|
+
const rows = [];
|
|
53
|
+
for (const item of items) {
|
|
54
|
+
const row = rows.find((currentRow) => currentRow[0]?.rowId === item.rowId);
|
|
55
|
+
if (row) {
|
|
56
|
+
row.push(item);
|
|
57
|
+
} else {
|
|
58
|
+
rows.push([item]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return rows;
|
|
62
|
+
}
|
|
63
|
+
function getMaxRowLength(array) {
|
|
64
|
+
let maxLength = 0;
|
|
65
|
+
for (const { length } of array) {
|
|
66
|
+
if (length > maxLength) {
|
|
67
|
+
maxLength = length;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return maxLength;
|
|
71
|
+
}
|
|
72
|
+
function createEmptyItem(rowId) {
|
|
73
|
+
return {
|
|
74
|
+
id: "__EMPTY_ITEM__",
|
|
75
|
+
disabled: true,
|
|
76
|
+
rowId
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function normalizeRows(rows, activeId, focusShift) {
|
|
80
|
+
const maxLength = getMaxRowLength(rows);
|
|
81
|
+
for (const row of rows) {
|
|
82
|
+
for (let i = 0; i < maxLength; i += 1) {
|
|
83
|
+
const item = row[i];
|
|
84
|
+
if (!item || focusShift && item.disabled) {
|
|
85
|
+
const isFirst = i === 0;
|
|
86
|
+
const previousItem = isFirst && focusShift ? findFirstEnabledItem(row) : row[i - 1];
|
|
87
|
+
row[i] = previousItem && activeId !== previousItem.id && focusShift ? previousItem : createEmptyItem(previousItem?.rowId);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return rows;
|
|
92
|
+
}
|
|
93
|
+
function verticalizeItems(items) {
|
|
94
|
+
const rows = groupItemsByRows(items);
|
|
95
|
+
const maxLength = getMaxRowLength(rows);
|
|
96
|
+
const verticalized = [];
|
|
97
|
+
for (let i = 0; i < maxLength; i += 1) {
|
|
98
|
+
for (const row of rows) {
|
|
99
|
+
const item = row[i];
|
|
100
|
+
if (item) {
|
|
101
|
+
verticalized.push({
|
|
102
|
+
...item,
|
|
103
|
+
// If there's no rowId, it means that it's not a grid composite, but
|
|
104
|
+
// a single row instead. So, instead of verticalizing it, that is,
|
|
105
|
+
// assigning a different rowId based on the column index, we keep it
|
|
106
|
+
// undefined so they will be part of the same row. This is useful
|
|
107
|
+
// when using up/down on one-dimensional composites.
|
|
108
|
+
rowId: item.rowId ? `${i}` : void 0
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return verticalized;
|
|
114
|
+
}
|
|
115
|
+
function createCompositeStore(props = {}) {
|
|
116
|
+
const syncState = props.store?.getState();
|
|
117
|
+
const collection = createCollectionStore(props);
|
|
118
|
+
const activeId = defaultValue(
|
|
119
|
+
props.activeId,
|
|
120
|
+
syncState?.activeId,
|
|
121
|
+
props.defaultActiveId
|
|
122
|
+
);
|
|
123
|
+
const initialState = {
|
|
124
|
+
...collection.getState(),
|
|
125
|
+
activeId,
|
|
126
|
+
baseElement: defaultValue(syncState?.baseElement, null),
|
|
127
|
+
includesBaseElement: defaultValue(
|
|
128
|
+
props.includesBaseElement,
|
|
129
|
+
syncState?.includesBaseElement,
|
|
130
|
+
activeId === null
|
|
131
|
+
),
|
|
132
|
+
moves: defaultValue(syncState?.moves, 0),
|
|
133
|
+
orientation: defaultValue(
|
|
134
|
+
props.orientation,
|
|
135
|
+
syncState?.orientation,
|
|
136
|
+
"both"
|
|
137
|
+
),
|
|
138
|
+
rtl: defaultValue(props.rtl, syncState?.rtl, false),
|
|
139
|
+
virtualFocus: defaultValue(
|
|
140
|
+
props.virtualFocus,
|
|
141
|
+
syncState?.virtualFocus,
|
|
142
|
+
false
|
|
143
|
+
),
|
|
144
|
+
focusLoop: defaultValue(props.focusLoop, syncState?.focusLoop, false),
|
|
145
|
+
focusWrap: defaultValue(props.focusWrap, syncState?.focusWrap, false),
|
|
146
|
+
focusShift: defaultValue(props.focusShift, syncState?.focusShift, false)
|
|
147
|
+
};
|
|
148
|
+
const composite = createStore(initialState, collection, props.store);
|
|
149
|
+
composite.setup(
|
|
150
|
+
() => composite.sync(
|
|
151
|
+
(state) => {
|
|
152
|
+
composite.setState("activeId", (activeId2) => {
|
|
153
|
+
if (activeId2 !== void 0)
|
|
154
|
+
return activeId2;
|
|
155
|
+
return findFirstEnabledItem(state.renderedItems)?.id;
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
["renderedItems", "activeId"]
|
|
159
|
+
)
|
|
160
|
+
);
|
|
161
|
+
const getNextId = (items, orientation, hasNullItem, skip) => {
|
|
162
|
+
const { activeId: activeId2, rtl, focusLoop, focusWrap, includesBaseElement } = composite.getState();
|
|
163
|
+
const isHorizontal = orientation !== "vertical";
|
|
164
|
+
const isRTL = rtl && isHorizontal;
|
|
165
|
+
const allItems = isRTL ? reverseArray(items) : items;
|
|
166
|
+
if (activeId2 == null) {
|
|
167
|
+
return findFirstEnabledItem(allItems)?.id;
|
|
168
|
+
}
|
|
169
|
+
const activeItem = allItems.find((item) => item.id === activeId2);
|
|
170
|
+
if (!activeItem) {
|
|
171
|
+
return findFirstEnabledItem(allItems)?.id;
|
|
172
|
+
}
|
|
173
|
+
const isGrid = !!activeItem.rowId;
|
|
174
|
+
const activeIndex = allItems.indexOf(activeItem);
|
|
175
|
+
const nextItems = allItems.slice(activeIndex + 1);
|
|
176
|
+
const nextItemsInRow = getItemsInRow(nextItems, activeItem.rowId);
|
|
177
|
+
if (skip !== void 0) {
|
|
178
|
+
const nextEnabledItemsInRow = getEnabledItems(nextItemsInRow, activeId2);
|
|
179
|
+
const nextItem2 = nextEnabledItemsInRow.slice(skip)[0] || // If we can't find an item, just return the last one.
|
|
180
|
+
nextEnabledItemsInRow[nextEnabledItemsInRow.length - 1];
|
|
181
|
+
return nextItem2?.id;
|
|
182
|
+
}
|
|
183
|
+
const oppositeOrientation = getOppositeOrientation(
|
|
184
|
+
// If it's a grid and orientation is not set, it's a next/previous call,
|
|
185
|
+
// which is inherently horizontal. up/down will call next with orientation
|
|
186
|
+
// set to vertical by default (see below on up/down methods).
|
|
187
|
+
isGrid ? orientation || "horizontal" : orientation
|
|
188
|
+
);
|
|
189
|
+
const canLoop = focusLoop && focusLoop !== oppositeOrientation;
|
|
190
|
+
const canWrap = isGrid && focusWrap && focusWrap !== oppositeOrientation;
|
|
191
|
+
hasNullItem = hasNullItem || !isGrid && canLoop && includesBaseElement;
|
|
192
|
+
if (canLoop) {
|
|
193
|
+
const loopItems = canWrap && !hasNullItem ? allItems : getItemsInRow(allItems, activeItem.rowId);
|
|
194
|
+
const sortedItems = flipItems(loopItems, activeId2, hasNullItem);
|
|
195
|
+
const nextItem2 = findFirstEnabledItem(sortedItems, activeId2);
|
|
196
|
+
return nextItem2?.id;
|
|
197
|
+
}
|
|
198
|
+
if (canWrap) {
|
|
199
|
+
const nextItem2 = findFirstEnabledItem(
|
|
200
|
+
// We can use nextItems, which contains all the next items, including
|
|
201
|
+
// items from other rows, to wrap between rows. However, if there is a
|
|
202
|
+
// null item (the composite container), we'll only use the next items in
|
|
203
|
+
// the row. So moving next from the last item will focus on the
|
|
204
|
+
// composite container. On grid composites, horizontal navigation never
|
|
205
|
+
// focuses on the composite container, only vertical.
|
|
206
|
+
hasNullItem ? nextItemsInRow : nextItems,
|
|
207
|
+
activeId2
|
|
208
|
+
);
|
|
209
|
+
const nextId = hasNullItem ? nextItem2?.id || null : nextItem2?.id;
|
|
210
|
+
return nextId;
|
|
211
|
+
}
|
|
212
|
+
const nextItem = findFirstEnabledItem(nextItemsInRow, activeId2);
|
|
213
|
+
if (!nextItem && hasNullItem) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
return nextItem?.id;
|
|
217
|
+
};
|
|
218
|
+
return {
|
|
219
|
+
...collection,
|
|
220
|
+
...composite,
|
|
221
|
+
setBaseElement: (element) => composite.setState("baseElement", element),
|
|
222
|
+
setActiveId: (id) => composite.setState("activeId", id),
|
|
223
|
+
move: (id) => {
|
|
224
|
+
if (id === void 0)
|
|
225
|
+
return;
|
|
226
|
+
composite.setState("activeId", id);
|
|
227
|
+
composite.setState("moves", (moves) => moves + 1);
|
|
228
|
+
},
|
|
229
|
+
first: () => findFirstEnabledItem(composite.getState().renderedItems)?.id,
|
|
230
|
+
last: () => findFirstEnabledItem(reverseArray(composite.getState().renderedItems))?.id,
|
|
231
|
+
next: (skip) => {
|
|
232
|
+
const { renderedItems, orientation } = composite.getState();
|
|
233
|
+
return getNextId(renderedItems, orientation, false, skip);
|
|
234
|
+
},
|
|
235
|
+
previous: (skip) => {
|
|
236
|
+
const { renderedItems, orientation, includesBaseElement } = composite.getState();
|
|
237
|
+
const isGrid = !!findFirstEnabledItem(renderedItems)?.rowId;
|
|
238
|
+
const hasNullItem = !isGrid && includesBaseElement;
|
|
239
|
+
return getNextId(
|
|
240
|
+
reverseArray(renderedItems),
|
|
241
|
+
orientation,
|
|
242
|
+
hasNullItem,
|
|
243
|
+
skip
|
|
244
|
+
);
|
|
245
|
+
},
|
|
246
|
+
down: (skip) => {
|
|
247
|
+
const {
|
|
248
|
+
activeId: activeId2,
|
|
249
|
+
renderedItems,
|
|
250
|
+
focusShift,
|
|
251
|
+
focusLoop,
|
|
252
|
+
includesBaseElement
|
|
253
|
+
} = composite.getState();
|
|
254
|
+
const shouldShift = focusShift && !skip;
|
|
255
|
+
const verticalItems = verticalizeItems(
|
|
256
|
+
flatten2DArray(
|
|
257
|
+
normalizeRows(groupItemsByRows(renderedItems), activeId2, shouldShift)
|
|
258
|
+
)
|
|
259
|
+
);
|
|
260
|
+
const canLoop = focusLoop && focusLoop !== "horizontal";
|
|
261
|
+
const hasNullItem = canLoop && includesBaseElement;
|
|
262
|
+
return getNextId(verticalItems, "vertical", hasNullItem, skip);
|
|
263
|
+
},
|
|
264
|
+
up: (skip) => {
|
|
265
|
+
const { activeId: activeId2, renderedItems, focusShift, includesBaseElement } = composite.getState();
|
|
266
|
+
const shouldShift = focusShift && !skip;
|
|
267
|
+
const verticalItems = verticalizeItems(
|
|
268
|
+
reverseArray(
|
|
269
|
+
flatten2DArray(
|
|
270
|
+
normalizeRows(
|
|
271
|
+
groupItemsByRows(renderedItems),
|
|
272
|
+
activeId2,
|
|
273
|
+
shouldShift
|
|
274
|
+
)
|
|
275
|
+
)
|
|
276
|
+
)
|
|
277
|
+
);
|
|
278
|
+
const hasNullItem = includesBaseElement;
|
|
279
|
+
return getNextId(verticalItems, "vertical", hasNullItem, skip);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export {
|
|
285
|
+
createCompositeStore
|
|
286
|
+
};
|