UNPKG

reakit

Version:

Toolkit for building accessible rich web apps with React

288 lines (287 loc) 11 kB
import * as React from "react"; import { SealedInitialState } from "reakit-utils/useSealedState"; import { unstable_IdState, unstable_IdActions, unstable_IdInitialState, unstable_IdStateReturn } from "../Id/IdState"; import { Item, Group, Orientation } from "./__utils/types"; export declare function useCompositeState(initialState?: SealedInitialState<CompositeInitialState>): CompositeStateReturn; export declare type CompositeState = unstable_IdState & { /** * If enabled, the composite element will act as an * [aria-activedescendant](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_focus_activedescendant) * container instead of * [roving tabindex](https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex). * DOM focus will remain on the composite while its items receive virtual focus. * @default false */ unstable_virtual: boolean; /** * Determines how `next` and `previous` functions will behave. If `rtl` is * set to `true`, they will be inverted. This only affects the composite * widget behavior. You still need to set `dir="rtl"` on HTML/CSS. * @default false */ rtl: boolean; /** * Defines the orientation of the composite widget. If the composite has a * single row or column (one-dimensional), the `orientation` value determines * which arrow keys can be used to move focus: * - `undefined`: all arrow keys work. * - `horizontal`: only left and right arrow keys work. * - `vertical`: only up and down arrow keys work. * * It doesn't have any effect on two-dimensional composites. * @default undefined */ orientation?: Orientation; /** * Lists all the composite items with their `id`, DOM `ref`, `disabled` state * and `groupId` if any. This state is automatically updated when * `registerItem` and `unregisterItem` are called. * @example * const composite = useCompositeState(); * composite.items.forEach((item) => { * const { id, ref, disabled, groupId } = item; * ... * }); */ items: Item[]; /** * Lists all the composite groups with their `id` and DOM `ref`. This state * is automatically updated when `registerGroup` and `unregisterGroup` are * called. * @example * const composite = useCompositeState(); * composite.groups.forEach((group) => { * const { id, ref } = group; * ... * }); */ groups: Group[]; /** * The current focused item `id`. * - `undefined` will automatically focus the first enabled composite item. * - `null` will focus the base composite element and users will be able to * navigate out of it using arrow keys. * - If `currentId` is initially set to `null`, the base composite element * itself will have focus and users will be able to navigate to it using * arrow keys. * @default undefined * @example * // First enabled item has initial focus * useCompositeState(); * // Base composite element has initial focus * useCompositeState({ currentId: null }); * // Specific composite item element has initial focus * useCompositeState({ currentId: "item-id" }); */ currentId?: string | null; /** * On one-dimensional composites: * - `true` loops from the last item to the first item and vice-versa. * - `horizontal` loops only if `orientation` is `horizontal` or not set. * - `vertical` loops only if `orientation` is `vertical` or not set. * - If `currentId` is initially set to `null`, the composite element will * be focused in between the last and first items. * * On two-dimensional composites: * - `true` loops from the last row/column item to the first item in the * same row/column and vice-versa. If it's the last item in the last row, it * moves to the first item in the first row and vice-versa. * - `horizontal` loops only from the last row item to the first item in * the same row. * - `vertical` loops only from the last column item to the first item in * the column row. * - If `currentId` is initially set to `null`, vertical loop will have no * effect as moving down from the last row or up from the first row will * focus the composite element. * - If `wrap` matches the value of `loop`, it'll wrap between the last * item in the last row or column and the first item in the first row or * column and vice-versa. * @default false */ loop: boolean | Orientation; /** * **Has effect only on two-dimensional composites**. If enabled, moving to * the next item from the last one in a row or column will focus the first * item in the next row or column and vice-versa. * - `true` wraps between rows and columns. * - `horizontal` wraps only between rows. * - `vertical` wraps only between columns. * - If `loop` matches the value of `wrap`, it'll wrap between the last * item in the last row or column and the first item in the first row or * column and vice-versa. * @default false */ wrap: boolean | Orientation; /** * **Has effect only on two-dimensional composites**. If enabled, moving up * or down when there's no next item or the next item is disabled will shift * to the item right before it. * @default false */ shift: boolean; /** * Stores the number of moves that have been performed by calling `move`, * `next`, `previous`, `up`, `down`, `first` or `last`. * @default 0 */ unstable_moves: number; /** * @default false * @private */ unstable_hasActiveWidget: boolean; /** * @default false * @private */ unstable_includesBaseElement: boolean; }; export declare type CompositeActions = unstable_IdActions & { /** * Registers a composite item. * @example * const ref = React.useRef(); * const composite = useCompositeState(); * React.useEffect(() => { * composite.registerItem({ ref, id: "id" }); * return () => composite.unregisterItem("id"); * }, []); */ registerItem: (item: Item) => void; /** * Unregisters a composite item. * @example * const ref = React.useRef(); * const composite = useCompositeState(); * React.useEffect(() => { * composite.registerItem({ ref, id: "id" }); * return () => composite.unregisterItem("id"); * }, []); */ unregisterItem: (id: string) => void; /** * Registers a composite group. * @example * const ref = React.useRef(); * const composite = useCompositeState(); * React.useEffect(() => { * composite.registerGroup({ ref, id: "id" }); * return () => composite.unregisterGroup("id"); * }, []); */ registerGroup: (group: Group) => void; /** * Unregisters a composite group. * @example * const ref = React.useRef(); * const composite = useCompositeState(); * React.useEffect(() => { * composite.registerGroup({ ref, id: "id" }); * return () => composite.unregisterGroup("id"); * }, []); */ unregisterGroup: (id: string) => void; /** * Moves focus to a given item ID. * @example * const composite = useCompositeState(); * composite.move("item-2"); // focus item 2 */ move: (id: string | null) => void; /** * Moves focus to the next item. */ next: (unstable_allTheWay?: boolean) => void; /** * Moves focus to the previous item. */ previous: (unstable_allTheWay?: boolean) => void; /** * Moves focus to the item above. */ up: (unstable_allTheWay?: boolean) => void; /** * Moves focus to the item below. */ down: (unstable_allTheWay?: boolean) => void; /** * Moves focus to the first item. */ first: () => void; /** * Moves focus to the last item. */ last: () => void; /** * Sorts the `composite.items` based on the items position in the DOM. This * is especially useful after modifying the composite items order in the DOM. * Most of the time, though, you don't need to manually call this function as * the re-ordering happens automatically. */ sort: () => void; /** * Sets `virtual`. */ unstable_setVirtual: React.Dispatch<React.SetStateAction<CompositeState["unstable_virtual"]>>; /** * Sets `rtl`. * @example * const composite = useCompositeState({ rtl: true }); * composite.setRTL(false); */ setRTL: React.Dispatch<React.SetStateAction<CompositeState["rtl"]>>; /** * Sets `orientation`. */ setOrientation: React.Dispatch<React.SetStateAction<CompositeState["orientation"]>>; /** * Sets `currentId`. This is different from `composite.move` as this only * updates the `currentId` state without moving focus. When the composite * widget gets focused by the user, the item referred by the `currentId` * state will get focus. * @example * const composite = useCompositeState({ currentId: "item-1" }); * // Updates `composite.currentId` to `item-2` * composite.setCurrentId("item-2"); */ setCurrentId: React.Dispatch<React.SetStateAction<CompositeState["currentId"]>>; /** * Sets `loop`. */ setLoop: React.Dispatch<React.SetStateAction<CompositeState["loop"]>>; /** * Sets `wrap`. */ setWrap: React.Dispatch<React.SetStateAction<CompositeState["wrap"]>>; /** * Sets `shift`. */ setShift: React.Dispatch<React.SetStateAction<CompositeState["shift"]>>; /** * Resets to initial state. * @example * // On initial render, currentId will be item-1 and loop will be true * const composite = useCompositeState({ * currentId: "item-1", * loop: true, * }); * // On next render, currentId will be item-2 and loop will be false * composite.setCurrentId("item-2"); * composite.setLoop(false); * // On next render, currentId will be item-1 and loop will be true * composite.reset(); */ reset: () => void; /** * Sets `includesBaseElement`. * @private */ unstable_setIncludesBaseElement: React.Dispatch<React.SetStateAction<CompositeState["unstable_includesBaseElement"]>>; /** * Sets `hasActiveWidget`. * @private */ unstable_setHasActiveWidget: React.Dispatch<React.SetStateAction<CompositeState["unstable_hasActiveWidget"]>>; }; export declare type CompositeInitialState = unstable_IdInitialState & Partial<Pick<CompositeState, "unstable_virtual" | "rtl" | "orientation" | "currentId" | "loop" | "wrap" | "shift" | "unstable_includesBaseElement">>; export declare type CompositeStateReturn = unstable_IdStateReturn & CompositeState & CompositeActions;