1 | import * as React from "react";
|
2 | import { createComponent } from "reakit-system/createComponent";
|
3 | import { createHook } from "reakit-system/createHook";
|
4 | import { useForkRef } from "reakit-utils/useForkRef";
|
5 | import { useIsomorphicEffect } from "reakit-utils/useIsomorphicEffect";
|
6 | import { useLiveRef } from "reakit-utils/useLiveRef";
|
7 | import { warning } from "reakit-warning";
|
8 | import {
|
9 | DisclosureOptions,
|
10 | DisclosureHTMLProps,
|
11 | useDisclosure,
|
12 | } from "../Disclosure/Disclosure";
|
13 | import { DialogStateReturn } from "./DialogState";
|
14 | import { DIALOG_DISCLOSURE_KEYS } from "./__keys";
|
15 |
|
16 | export type DialogDisclosureOptions = DisclosureOptions &
|
17 | Pick<Partial<DialogStateReturn>, "unstable_disclosureRef"> &
|
18 | Pick<DialogStateReturn, "toggle">;
|
19 |
|
20 | export type DialogDisclosureHTMLProps = DisclosureHTMLProps;
|
21 |
|
22 | export type DialogDisclosureProps = DialogDisclosureOptions &
|
23 | DialogDisclosureHTMLProps;
|
24 |
|
25 | export 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 |
|
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 |
|
76 | export const DialogDisclosure = createComponent({
|
77 | as: "button",
|
78 | memo: true,
|
79 | useHook: useDialogDisclosure,
|
80 | });
|