diff --git a/src/components/form/TextField.tsx b/src/components/form/TextField.tsx index ed6b46c..d1ccf08 100644 --- a/src/components/form/TextField.tsx +++ b/src/components/form/TextField.tsx @@ -3,7 +3,7 @@ import { type TextFieldProps as MuiTextFieldProps, } from "@mui/material" import { Field, type FieldConfig, type FieldProps } from "formik" -import type { FC } from "react" +import { type FC, useState, useEffect } from "react" import { type StringSchema, type ValidateOptions } from "yup" import { schemaToFieldValidator } from "../../utils/form" @@ -23,6 +23,7 @@ export type TextFieldProps = Omit< name: string schema: StringSchema validateOptions?: ValidateOptions + dirty?: boolean } // https://formik.org/docs/examples/with-material-ui @@ -31,12 +32,16 @@ const TextField: FC = ({ schema, type = "text", required = false, + dirty = false, validateOptions, ...otherTextFieldProps }) => { + const [initialValue, setInitialValue] = useState("") + const dotPath = name.split(".") if (required) schema = schema.required() + if (dirty) schema = schema.notOneOf([initialValue], "cannot be initial value") const fieldConfig: FieldConfig = { name, @@ -44,30 +49,33 @@ const TextField: FC = ({ validate: schemaToFieldValidator(schema, validateOptions), } - return ( - - {({ form }: FieldProps) => { - const value = getNestedProperty(form.values, dotPath) - const error = getNestedProperty(form.errors, dotPath) - const touched = getNestedProperty(form.touched, dotPath) + const _Field: FC = ({ form }) => { + const initialValue = getNestedProperty(form.initialValues, dotPath) + const value = getNestedProperty(form.values, dotPath) + const error = getNestedProperty(form.errors, dotPath) + const touched = getNestedProperty(form.touched, dotPath) + + useEffect(() => { + setInitialValue(initialValue) + }, [initialValue]) + + return ( + + ) + } - return ( - - ) - }} - - ) + return {_Field} } export default TextField diff --git a/src/components/router/Navigate.tsx b/src/components/router/Navigate.tsx new file mode 100644 index 0000000..b67b2f0 --- /dev/null +++ b/src/components/router/Navigate.tsx @@ -0,0 +1,33 @@ +import { useEffect } from "react" +import { type To } from "react-router-dom" + +import { useNavigate, type NavigateOptions } from "../../hooks" + +export type NavigateProps< + Override extends "delta" | "to", + State extends Record = Record, +> = Override extends "delta" + ? { delta: number; to?: undefined } + : { delta?: undefined; to: To } & NavigateOptions + +const Navigate: { + (props: NavigateProps<"delta">): JSX.Element + = Record>( + props: NavigateProps<"to", State>, + ): JSX.Element +} = ({ + delta, + to, + ...options +}: NavigateProps<"delta"> | NavigateProps<"to">) => { + const navigate = useNavigate() + + useEffect(() => { + if (typeof delta === "number") navigate(delta) + else navigate(to, options) + }, [navigate, delta, to, options]) + + return <> +} + +export default Navigate diff --git a/src/components/router/index.tsx b/src/components/router/index.tsx index 4315bf9..3131ff2 100644 --- a/src/components/router/index.tsx +++ b/src/components/router/index.tsx @@ -8,3 +8,5 @@ export * from "./LinkListItem" export { default as LinkListItem } from "./LinkListItem" export * from "./LinkTab" export { default as LinkTab } from "./LinkTab" +export * from "./Navigate" +export { default as Navigate } from "./Navigate" diff --git a/src/hooks/router.tsx b/src/hooks/router.tsx index 7c1e6e0..f6fc359 100644 --- a/src/hooks/router.tsx +++ b/src/hooks/router.tsx @@ -5,7 +5,7 @@ import { useParams as _useParams, useSearchParams as _useSearchParams, type Location, - type NavigateOptions, + type NavigateOptions as _NavigateOptions, type Params, type To, } from "react-router-dom" @@ -21,13 +21,17 @@ import { type TryValidateSyncRT, } from "../utils/schema" +export type NavigateOptions< + State extends Record = Record, +> = Omit<_NavigateOptions, "state"> & { + state?: State & Partial + next?: boolean +} + export type Navigate = { = Record>( to: To, - options?: Omit & { - state?: State & Partial - next?: boolean - }, + options?: NavigateOptions, ): void (delta: number): void }