Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add baseId option to useRoverState and derivative hooks #494

Merged
merged 1 commit into from
Nov 14, 2019
Merged
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
2 changes: 1 addition & 1 deletion packages/reakit/src/Id/IdState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { unstable_IdContext } from "./IdProvider";

export type unstable_IdState = {
/**
* @private
* ID that will serve as a base for all the items IDs.
*/
baseId: string;
/**
Expand Down
5 changes: 4 additions & 1 deletion packages/reakit/src/Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
SystemProviderProps,
SystemProvider
} from "reakit-system/SystemProvider";
import { unstable_IdProvider as NewIdProvider } from "./Id/IdProvider";

export type ProviderProps = IdProviderProps & Partial<SystemProviderProps>;

Expand All @@ -14,7 +15,9 @@ export function Provider({
}: ProviderProps) {
return (
<IdProvider unstable_prefix={prefix}>
<SystemProvider unstable_system={system}>{children}</SystemProvider>
<NewIdProvider prefix={prefix}>
<SystemProvider unstable_system={system}>{children}</SystemProvider>
</NewIdProvider>
</IdProvider>
);
}
6 changes: 5 additions & 1 deletion packages/reakit/src/Radio/__tests__/RadioState-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import { useRadioState } from "../RadioState";
expect.addSnapshotSerializer(jestSerializerStripFunctions);

test("initial state", () => {
const { result } = renderHook(() => useRadioState());
const { result } = renderHook(() => useRadioState({ baseId: "base" }));
expect(result.current).toMatchInlineSnapshot(`
Object {
"baseId": "base",
"currentId": null,
"loop": true,
"orientation": undefined,
"state": undefined,
"stops": Array [],
"unstable_idCountRef": Object {
"current": 0,
},
"unstable_moves": 0,
"unstable_pastId": null,
}
Expand Down
41 changes: 21 additions & 20 deletions packages/reakit/src/Rover/Rover.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import * as React from "react";
import { createComponent } from "reakit-system/createComponent";
import { createHook } from "reakit-system/createHook";
import { useId } from "reakit-utils/useId";
import { createOnKeyDown } from "reakit-utils/createOnKeyDown";
import { warning } from "reakit-utils/warning";
import { mergeRefs } from "reakit-utils/mergeRefs";
import { hasFocusWithin } from "reakit-utils/hasFocusWithin";
import { useAllCallbacks } from "reakit-utils/useAllCallbacks";
import {
TabbableOptions,
TabbableHTMLProps,
useTabbable
} from "../Tabbable/Tabbable";
import {
unstable_useId,
unstable_IdOptions,
unstable_IdHTMLProps
} from "../Id/Id";
import { RoverStateReturn, useRoverState } from "./RoverState";

export type RoverOptions = TabbableOptions &
unstable_IdOptions &
Pick<Partial<RoverStateReturn>, "orientation" | "unstable_moves"> &
Pick<
RoverStateReturn,
Expand All @@ -33,13 +39,13 @@ export type RoverOptions = TabbableOptions &
stopId?: string;
};

export type RoverHTMLProps = TabbableHTMLProps;
export type RoverHTMLProps = TabbableHTMLProps & unstable_IdHTMLProps;

export type RoverProps = RoverOptions & RoverHTMLProps;

export const useRover = createHook<RoverOptions, RoverHTMLProps>({
name: "Rover",
compose: useTabbable,
compose: [useTabbable, unstable_useId],
useState: useRoverState,
keys: ["stopId"],

Expand All @@ -48,13 +54,13 @@ export const useRover = createHook<RoverOptions, RoverHTMLProps>({
{
ref: htmlRef,
tabIndex: htmlTabIndex = 0,
onFocus: htmlOnFocus,
onKeyDown: htmlOnKeyDown,
...htmlProps
}
) {
const ref = React.useRef<HTMLElement>(null);
const id = useId("rover-");
const stopId = options.stopId || htmlProps.id || id;
const stopId = options.stopId || htmlProps.id || options.id;

const trulyDisabled = options.disabled && !options.focusable;
const noFocused = options.currentId == null;
Expand All @@ -63,7 +69,7 @@ export const useRover = createHook<RoverOptions, RoverHTMLProps>({
const shouldTabIndex = focused || (isFirst && noFocused);

React.useEffect(() => {
if (trulyDisabled) return undefined;
if (trulyDisabled || !stopId) return undefined;
options.register && options.register(stopId, ref);
return () => options.unregister && options.unregister(stopId);
}, [stopId, trulyDisabled, options.register, options.unregister]);
Expand All @@ -83,20 +89,14 @@ export const useRover = createHook<RoverOptions, RoverHTMLProps>({
}
}, [focused, options.unstable_moves]);

React.useEffect(() => {
if (!ref.current) return undefined;

// this is already focused, so we move silently
const onFocus = () => options.move(stopId, true);

// https://github.com/facebook/react/issues/11387#issuecomment-524113945
ref.current.addEventListener("focus", onFocus, true);
return () => {
if (ref.current) {
ref.current.removeEventListener("focus", onFocus, true);
}
};
}, [options.move, stopId]);
const onFocus = React.useCallback(
(event: React.FocusEvent) => {
if (!stopId || !event.currentTarget.contains(event.target)) return;
// this is already focused, so we move silently
options.move(stopId, true);
},
[options.move, stopId]
);

const onKeyDown = React.useMemo(
() =>
Expand Down Expand Up @@ -132,6 +132,7 @@ export const useRover = createHook<RoverOptions, RoverHTMLProps>({
ref: mergeRefs(ref, htmlRef),
id: stopId,
tabIndex: shouldTabIndex ? htmlTabIndex : -1,
onFocus: useAllCallbacks(onFocus, htmlOnFocus),
onKeyDown,
...htmlProps
};
Expand Down
35 changes: 26 additions & 9 deletions packages/reakit/src/Rover/RoverState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@ import {
SealedInitialState,
useSealedState
} from "reakit-utils/useSealedState";
import {
unstable_IdState,
unstable_IdActions,
unstable_IdInitialState,
unstable_useIdState
} from "../Id/IdState";

type Stop = {
id: string;
ref: React.RefObject<HTMLElement>;
};

export type RoverState = {
export type RoverState = unstable_IdState & {
/**
* Defines the orientation of the rover list.
*/
Expand Down Expand Up @@ -42,7 +48,7 @@ export type RoverState = {
loop: boolean;
};

export type RoverActions = {
export type RoverActions = unstable_IdActions & {
/**
* Registers the element ID and ref in the roving tab index list.
*/
Expand Down Expand Up @@ -83,9 +89,8 @@ export type RoverActions = {
unstable_orientate: (orientation: RoverState["orientation"]) => void;
};

export type RoverInitialState = Partial<
Pick<RoverState, "orientation" | "currentId" | "loop">
>;
export type RoverInitialState = unstable_IdInitialState &
Partial<Pick<RoverState, "orientation" | "currentId" | "loop">>;

export type RoverStateReturn = RoverState & RoverActions;

Expand All @@ -103,7 +108,12 @@ type RoverAction =
orientation?: RoverState["orientation"];
};

function reducer(state: RoverState, action: RoverAction): RoverState {
type RoverReducerState = Omit<RoverState, keyof unstable_IdState>;

function reducer(
state: RoverReducerState,
action: RoverAction
): RoverReducerState {
const {
stops,
currentId,
Expand Down Expand Up @@ -253,9 +263,12 @@ function reducer(state: RoverState, action: RoverAction): RoverState {
export function useRoverState(
initialState: SealedInitialState<RoverInitialState> = {}
): RoverStateReturn {
const { orientation, currentId = null, loop = false } = useSealedState(
initialState
);
const {
orientation,
currentId = null,
loop = false,
...sealed
} = useSealedState(initialState);
const [state, dispatch] = React.useReducer(reducer, {
orientation,
stops: [],
Expand All @@ -265,7 +278,10 @@ export function useRoverState(
loop
});

const idState = unstable_useIdState(sealed);

return {
...idState,
...state,
register: React.useCallback(
(id, ref) => dispatch({ type: "register", id, ref }),
Expand All @@ -292,6 +308,7 @@ export function useRoverState(
}

const keys: Array<keyof RoverStateReturn> = [
...unstable_useIdState.__keys,
"orientation",
"stops",
"currentId",
Expand Down
8 changes: 1 addition & 7 deletions packages/reakit/src/Rover/__tests__/Rover-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@ import * as React from "react";
import { render } from "@testing-library/react";
import { Rover } from "../Rover";

jest.mock("reakit-utils/useId", () => {
return {
useId: jest.fn(() => "rover")
};
});

const props: Parameters<typeof Rover>[0] = {
stopId: "rover",
stops: [],
Expand Down Expand Up @@ -39,7 +33,7 @@ test("render", () => {

test("render without state props", () => {
// @ts-ignore
const { baseElement } = render(<Rover>rover</Rover>);
const { baseElement } = render(<Rover id="rover">rover</Rover>);
expect(baseElement).toMatchInlineSnapshot(`
<body>
<div>
Expand Down
Loading