parameter-input.tsx 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import {
  2. type ChangeEvent,
  3. type Dispatch,
  4. type SetStateAction,
  5. useState,
  6. useCallback,
  7. useMemo,
  8. useEffect,
  9. } from "react";
  10. import {
  11. type Parameter,
  12. PLACEHOLDERS,
  13. isValid,
  14. getValidationError,
  15. } from "./parameter";
  16. import { Input } from "../Input";
  17. type ParameterProps<ParameterName extends string> = {
  18. spec: Parameter<ParameterName>;
  19. value: string | undefined;
  20. setParamValues: Dispatch<
  21. SetStateAction<Partial<Record<ParameterName, string>>>
  22. >;
  23. };
  24. export const ParameterInput = <ParameterName extends string>({
  25. spec,
  26. value,
  27. setParamValues,
  28. }: ParameterProps<ParameterName>) => {
  29. const { validationError, internalValue, onChange } = useParameterInput(
  30. spec,
  31. value,
  32. setParamValues,
  33. );
  34. return (
  35. <Input
  36. validationError={validationError}
  37. label={spec.name}
  38. description={spec.description}
  39. placeholder={PLACEHOLDERS[spec.type]}
  40. required={true}
  41. value={internalValue}
  42. onChange={onChange}
  43. />
  44. );
  45. };
  46. const useParameterInput = <ParameterName extends string>(
  47. spec: Parameter<ParameterName>,
  48. value: string | undefined,
  49. setParamValues: Dispatch<
  50. SetStateAction<Partial<Record<ParameterName, string>>>
  51. >,
  52. ) => {
  53. const [internalValue, setInternalValue] = useState(value ?? "");
  54. const validationError = useMemo(
  55. () => (internalValue ? getValidationError(spec, internalValue) : undefined),
  56. [internalValue, spec],
  57. );
  58. const onChange = useCallback(
  59. (e: ChangeEvent<HTMLInputElement>) => {
  60. const value = e.target.value;
  61. setInternalValue(value);
  62. setParamValues((paramValues) => ({
  63. ...paramValues,
  64. [spec.name]: value === "" || !isValid(spec, value) ? undefined : value,
  65. }));
  66. },
  67. [setParamValues, spec],
  68. );
  69. useEffect(() => {
  70. if (value) {
  71. setInternalValue(value);
  72. }
  73. }, [value]);
  74. return { internalValue, validationError, onChange };
  75. };