1 | import * as React from "react";
|
2 | import { createComponent } from "reakit-system/createComponent";
|
3 | import { createHook } from "reakit-system/createHook";
|
4 | import { ArrayValue, As, PropsWithAs } from "reakit-utils/types";
|
5 | import { useLiveRef } from "reakit-utils/useLiveRef";
|
6 | import { getDocument } from "reakit-utils/getDocument";
|
7 | import { ButtonOptions, ButtonHTMLProps, useButton } from "../Button/Button";
|
8 | import { unstable_FormStateReturn } from "./FormState";
|
9 | import { unstable_getIn } from "./utils/getIn";
|
10 | import { formatInputName } from "./__utils/formatInputName";
|
11 | import { getInputId } from "./__utils/getInputId";
|
12 | import { getPushButtonId } from "./__utils/getPushButtonId";
|
13 | import { DeepPath, DeepPathValue } from "./__utils/types";
|
14 | import { FORM_PUSH_BUTTON_KEYS } from "./__keys";
|
15 |
|
16 | export type unstable_FormPushButtonOptions<
|
17 | V,
|
18 | P extends DeepPath<V, P>
|
19 | > = ButtonOptions &
|
20 | Pick<unstable_FormStateReturn<V>, "baseId" | "values" | "push"> & {
|
21 | |
22 |
|
23 |
|
24 | name: P;
|
25 | |
26 |
|
27 |
|
28 | value: ArrayValue<DeepPathValue<V, P>>;
|
29 | };
|
30 |
|
31 | export type unstable_FormPushButtonHTMLProps = ButtonHTMLProps;
|
32 |
|
33 | export type unstable_FormPushButtonProps<
|
34 | V,
|
35 | P extends DeepPath<V, P>
|
36 | > = unstable_FormPushButtonOptions<V, P> & unstable_FormPushButtonHTMLProps;
|
37 |
|
38 | export const unstable_useFormPushButton = createHook<
|
39 | unstable_FormPushButtonOptions<any, any>,
|
40 | unstable_FormPushButtonHTMLProps
|
41 | >({
|
42 | name: "FormPushButton",
|
43 | compose: useButton,
|
44 | keys: FORM_PUSH_BUTTON_KEYS,
|
45 |
|
46 | useOptions(options, { name, value }) {
|
47 | return {
|
48 | ...options,
|
49 | name: options.name || name,
|
50 | value: options.value ?? value,
|
51 | };
|
52 | },
|
53 |
|
54 | useProps(options, { onClick: htmlOnClick, ...htmlProps }) {
|
55 | const onClickRef = useLiveRef(htmlOnClick);
|
56 |
|
57 | const onClick = React.useCallback(
|
58 | (event: React.MouseEvent) => {
|
59 | onClickRef.current?.(event);
|
60 | if (event.defaultPrevented) return;
|
61 |
|
62 | options.push?.(options.name, options.value);
|
63 |
|
64 | const { length } = unstable_getIn(options.values, options.name, []);
|
65 | const inputId = getInputId(
|
66 | `${formatInputName(options.name, "-")}-${length}`,
|
67 | options.baseId
|
68 | );
|
69 |
|
70 | if (!inputId) return;
|
71 | const element = event.currentTarget;
|
72 |
|
73 | window.requestAnimationFrame(() => {
|
74 | const selector = `[id^="${inputId}"]`;
|
75 | const document = getDocument(element);
|
76 | const input = document.querySelector<HTMLElement>(selector);
|
77 | input?.focus();
|
78 | });
|
79 | },
|
80 | [
|
81 | options.push,
|
82 | options.name,
|
83 | options.value,
|
84 | options.values,
|
85 | options.baseId,
|
86 | ]
|
87 | );
|
88 |
|
89 | return {
|
90 | id: getPushButtonId(options.name, options.baseId),
|
91 | onClick,
|
92 | ...htmlProps,
|
93 | };
|
94 | },
|
95 | }) as <V, P extends DeepPath<V, P>>(
|
96 | options: unstable_FormPushButtonOptions<V, P>,
|
97 | htmlProps?: unstable_FormPushButtonHTMLProps
|
98 | ) => unstable_FormPushButtonHTMLProps;
|
99 |
|
100 | export const unstable_FormPushButton = (createComponent({
|
101 | as: "button",
|
102 | memo: true,
|
103 | useHook: unstable_useFormPushButton,
|
104 | }) as unknown) as <V, P extends DeepPath<V, P>, T extends As = "button">(
|
105 | props: PropsWithAs<unstable_FormPushButtonOptions<V, P>, T>
|
106 | ) => JSX.Element;
|