UNPKG

2.64 kBPlain TextView Raw
1import * as React from "react";
2import { createComponent } from "reakit-system/createComponent";
3import { createHook } from "reakit-system/createHook";
4import { useForkRef } from "reakit-utils/useForkRef";
5import { useIsomorphicEffect } from "reakit-utils/useIsomorphicEffect";
6import { useLiveRef } from "reakit-utils/useLiveRef";
7import { warning } from "reakit-warning";
8import {
9 DisclosureOptions,
10 DisclosureHTMLProps,
11 useDisclosure,
12} from "../Disclosure/Disclosure";
13import { DialogStateReturn } from "./DialogState";
14import { DIALOG_DISCLOSURE_KEYS } from "./__keys";
15
16export type DialogDisclosureOptions = DisclosureOptions &
17 Pick<Partial<DialogStateReturn>, "unstable_disclosureRef"> &
18 Pick<DialogStateReturn, "toggle">;
19
20export type DialogDisclosureHTMLProps = DisclosureHTMLProps;
21
22export type DialogDisclosureProps = DialogDisclosureOptions &
23 DialogDisclosureHTMLProps;
24
25export const useDialogDisclosure = createHook<
26 DialogDisclosureOptions,
27 DialogDisclosureHTMLProps
28>({
29 name: "DialogDisclosure",
30 compose: useDisclosure,
31 keys: DIALOG_DISCLOSURE_KEYS,
32
33 useProps(options, { ref: htmlRef, onClick: htmlOnClick, ...htmlProps }) {
34 const ref = React.useRef<HTMLElement>(null);
35 const onClickRef = useLiveRef(htmlOnClick);
36 const [expanded, setExpanded] = React.useState(false);
37 const disclosureRef = options.unstable_disclosureRef;
38
39 // aria-expanded may be used for styling purposes, so we useLayoutEffect
40 useIsomorphicEffect(() => {
41 const element = ref.current;
42 warning(
43 !element,
44 "Can't determine whether the element is the current disclosure because `ref` wasn't passed to the component",
45 "See https://reakit.io/docs/dialog"
46 );
47 if (disclosureRef && !disclosureRef.current) {
48 disclosureRef.current = element;
49 }
50 const isCurrentDisclosure =
51 !disclosureRef?.current || disclosureRef.current === element;
52 setExpanded(!!options.visible && isCurrentDisclosure);
53 }, [options.visible, disclosureRef]);
54
55 const onClick = React.useCallback(
56 (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
57 onClickRef.current?.(event);
58 if (event.defaultPrevented) return;
59 if (disclosureRef) {
60 disclosureRef.current = event.currentTarget;
61 }
62 },
63 [disclosureRef]
64 );
65
66 return {
67 ref: useForkRef(ref, htmlRef),
68 "aria-haspopup": "dialog",
69 "aria-expanded": expanded,
70 onClick,
71 ...htmlProps,
72 };
73 },
74});
75
76export const DialogDisclosure = createComponent({
77 as: "button",
78 memo: true,
79 useHook: useDialogDisclosure,
80});