use-submittable.ts 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import type {
  2. CompositionEvent,
  3. } from 'react';
  4. import type React from 'react';
  5. import {
  6. useCallback, useState,
  7. } from 'react';
  8. import type { SubmittableInputProps } from './types';
  9. export const useSubmittable = (props: SubmittableInputProps): Partial<React.InputHTMLAttributes<HTMLInputElement>> => {
  10. const {
  11. value,
  12. onChange, onBlur,
  13. onCompositionStart, onCompositionEnd,
  14. onSubmit, onCancel,
  15. } = props;
  16. const [inputText, setInputText] = useState(value ?? '');
  17. const [isComposing, setComposing] = useState(false);
  18. const changeHandler = useCallback(async(e: React.ChangeEvent<HTMLInputElement>) => {
  19. const inputText = e.target.value;
  20. setInputText(inputText);
  21. onChange?.(e);
  22. }, [onChange]);
  23. const keyDownHandler = useCallback((e) => {
  24. switch (e.key) {
  25. case 'Enter':
  26. // Do nothing when composing
  27. if (isComposing) {
  28. return;
  29. }
  30. onSubmit?.(inputText.trim());
  31. break;
  32. case 'Escape':
  33. if (isComposing) {
  34. return;
  35. }
  36. onCancel?.();
  37. break;
  38. }
  39. }, [inputText, isComposing, onCancel, onSubmit]);
  40. const blurHandler = useCallback((e) => {
  41. // submit on blur
  42. onSubmit?.(inputText.trim());
  43. onBlur?.(e);
  44. }, [inputText, onSubmit, onBlur]);
  45. const compositionStartHandler = useCallback((e: CompositionEvent<HTMLInputElement>) => {
  46. setComposing(true);
  47. onCompositionStart?.(e);
  48. }, [onCompositionStart]);
  49. const compositionEndHandler = useCallback((e: CompositionEvent<HTMLInputElement>) => {
  50. setComposing(false);
  51. onCompositionEnd?.(e);
  52. }, [onCompositionEnd]);
  53. const {
  54. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  55. value: _value, onSubmit: _onSubmit, onCancel: _onCancel,
  56. ...cleanedProps
  57. } = props;
  58. return {
  59. ...cleanedProps,
  60. value: inputText,
  61. onChange: changeHandler,
  62. onKeyDown: keyDownHandler,
  63. onBlur: blurHandler,
  64. onCompositionStart: compositionStartHandler,
  65. onCompositionEnd: compositionEndHandler,
  66. };
  67. };