npm doesn't support the "@" character in package names (it's used for scopes). We eventually want to move from yarn to npm, so in preparation, rename our internal packages accordingly so that they also work with npm workspaces. Methodology: No manual code changes, just automatic search replace of ``` "@/accounts => "ente-accounts "@/utils => "ente-utils ... "@ente/shared => "ente-shared ``` Then reran prettier.
117 lines
3.8 KiB
TypeScript
117 lines
3.8 KiB
TypeScript
import { Stack, TextField, type TextFieldProps } from "@mui/material";
|
|
import { FocusVisibleButton } from "ente-base/components/mui/FocusVisibleButton";
|
|
import { LoadingButton } from "ente-base/components/mui/LoadingButton";
|
|
import log from "ente-base/log";
|
|
import { useFormik } from "formik";
|
|
import { t } from "i18next";
|
|
import React from "react";
|
|
|
|
export type SingleInputFormProps = Pick<
|
|
TextFieldProps,
|
|
"label" | "placeholder" | "autoComplete" | "autoFocus" | "slotProps"
|
|
> & {
|
|
/**
|
|
* The initial value, if any, to prefill in the input.
|
|
*/
|
|
initialValue?: string;
|
|
/**
|
|
* Title for the submit button.
|
|
*/
|
|
submitButtonTitle: string;
|
|
/**
|
|
* Cancellation handler.
|
|
*
|
|
* This function is called when the user activates the cancel button in the
|
|
* form.
|
|
*/
|
|
onCancel: () => void;
|
|
/**
|
|
* Submission handler. A callback invoked when the submit button is pressed.
|
|
*
|
|
* During submission, the text input and the submit button are disabled, and
|
|
* an indeterminate progress indicator is shown.
|
|
*
|
|
* If this function rejects then a generic error helper text is shown below
|
|
* the text input, and the input (/ buttons) reenabled.
|
|
*
|
|
* @param name The current value of the text input.
|
|
*/
|
|
onSubmit: ((name: string) => void) | ((name: string) => Promise<void>);
|
|
};
|
|
|
|
/**
|
|
* A TextField and two buttons.
|
|
*
|
|
* A common requirement is taking a single textual input from the user. This is
|
|
* a form suitable for that purpose. It contains a single MUI {@link TextField}
|
|
* and two accompanying buttons; one to submit, and one to cancel.
|
|
*
|
|
* Submission is handled as an async function, during which the input is
|
|
* disabled and a loading indicator is shown. Errors during submission are shown
|
|
* as the helper text associated with the text field.
|
|
*/
|
|
export const SingleInputForm: React.FC<SingleInputFormProps> = ({
|
|
initialValue,
|
|
submitButtonTitle,
|
|
onCancel,
|
|
onSubmit,
|
|
...rest
|
|
}) => {
|
|
const formik = useFormik({
|
|
initialValues: { value: initialValue ?? "" },
|
|
onSubmit: async (values, { setFieldError }) => {
|
|
const value = values.value;
|
|
if (!value) {
|
|
setFieldError("value", t("required"));
|
|
return;
|
|
}
|
|
try {
|
|
await onSubmit(value);
|
|
} catch (e) {
|
|
log.error(`Failed to submit input ${value}`, e);
|
|
setFieldError("value", t("generic_error"));
|
|
}
|
|
},
|
|
});
|
|
|
|
// Note: [Use space as default TextField helperText]
|
|
//
|
|
// For MUI text fields that use a conditional helperText, e.g. in case of
|
|
// errors, use an space as the default helperText in the other cases to
|
|
// avoid a layout shift when the helperText is conditionally shown.
|
|
|
|
return (
|
|
<form onSubmit={formik.handleSubmit}>
|
|
<TextField
|
|
name="value"
|
|
value={formik.values.value}
|
|
onChange={formik.handleChange}
|
|
type="text"
|
|
fullWidth
|
|
margin="normal"
|
|
disabled={formik.isSubmitting}
|
|
error={!!formik.errors.value}
|
|
helperText={formik.errors.value ?? " "}
|
|
{...rest}
|
|
/>
|
|
<Stack direction="row" sx={{ gap: "12px" }}>
|
|
<FocusVisibleButton
|
|
fullWidth
|
|
color="secondary"
|
|
onClick={onCancel}
|
|
>
|
|
{t("cancel")}
|
|
</FocusVisibleButton>
|
|
<LoadingButton
|
|
fullWidth
|
|
color="primary"
|
|
type="submit"
|
|
loading={formik.isSubmitting}
|
|
>
|
|
{submitButtonTitle}
|
|
</LoadingButton>
|
|
</Stack>
|
|
</form>
|
|
);
|
|
};
|