Захват клавиши табуляции в компоненте автозаполнения пользовательского интерфейса материала - PullRequest
7 голосов
/ 26 мая 2020

Вот песочница: https://codesandbox.io/s/wild-sea-h2i0m

Вот код для автозаполнения из этой песочницы:

import React from "react";
import Autocomplete from "@material-ui/lab/Autocomplete";
import Chip from "@material-ui/core/Chip";
import CloseIcon from "@material-ui/icons/Close";
import TextField from "@material-ui/core/TextField";
import { FieldProps } from "formik";

const isEmailValid = (email: string) =>
  /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);

const EmailsField = ({
  field,
  form: { errors, touched, setTouched, setFieldValue },
  ...props
}: FieldProps) => {
  const name = field.name;
  const [value, setValue] = React.useState<string[]>([]);
  const [inputValue, setInputValue] = React.useState("");

  const handleChange = (event: React.ChangeEvent<{}>, emails: string[]) => {
    setTouched({ ...touched, [name]: true });
    setValue(emails);
    event.persist();
    setFieldValue(name, emails);
  };

  const handleInputChange = (
    event: React.ChangeEvent<{}>,
    newInputValue: string
  ) => {
    const options = newInputValue.split(/[ ,]+/);
    const fieldValue = value
      .concat(options)
      .map(x => x.trim())
      .filter(x => x);

    if (options.length > 1) {
      handleChange(event, fieldValue);
    } else {
      setInputValue(newInputValue);
    }
  };

  return (
    <Autocomplete<string>
      multiple
      disableClearable={true}
      options={[]}
      freeSolo
      renderTags={(emails, getTagProps) =>
        emails.map((email, index) => (
          <Chip
            deleteIcon={<CloseIcon />}
            variant="default"
            label={email}
            color={isEmailValid(email) ? "primary" : "secondary"}
            {...getTagProps({ index })}
          />
        ))
      }
      value={value}
      inputValue={inputValue}
      onChange={handleChange}
      onInputChange={handleInputChange}
      renderInput={params => (
        <TextField
          {...params}
          name={name}
          error={touched[name] && Boolean(errors.emails)}
          helperText={touched[name] && errors.emails}
          variant="outlined"
          InputProps={{ ...params.InputProps }}
          {...props}
        />
      )}
    />
  );
};

export default EmailsField;

Я не могу ввести значение пользователя становятся единственной опцией после того, как пользователь вводит, а затем нажимает кнопку вкладки на клавиатуре, чтобы перейти к кнопке отправки.

Есть идеи, как?

1 Ответ

5 голосов
/ 24 июня 2020

Вы можете выполнить sh это, добавив обработчик для onKeyDown:

  const handleKeyDown = (event: React.KeyboardEvent) => {
    switch (event.key) {
      case "Tab": {
        if (inputValue.length > 0) {
          handleChange(event, value.concat([inputValue]));
        }
        break;
      }
      default:
    }
  };

, а затем добавив его в текстовый ввод через inputProps:

      renderInput={params => {
        params.inputProps.onKeyDown = handleKeyDown;
        return (
          <TextField
            {...params}
            name={name}
            error={touched[name] && Boolean(errors.emails)}
            helperText={touched[name] && errors.emails}
            variant="outlined"
            {...props}
          />
        );
      }}

Вот полный новый код для компонента EmailsField из вашей песочницы:

import React from "react";
import Autocomplete from "@material-ui/lab/Autocomplete";
import Chip from "@material-ui/core/Chip";
import CloseIcon from "@material-ui/icons/Close";
import TextField from "@material-ui/core/TextField";
import { FieldProps } from "formik";

const isEmailValid = (email: string) =>
  /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);

const EmailsField = ({
  field,
  form: { errors, touched, setTouched, setFieldValue },
  ...props
}: FieldProps) => {
  const name = field.name;
  const [value, setValue] = React.useState<string[]>([]);
  const [inputValue, setInputValue] = React.useState("");

  const handleChange = (event: React.ChangeEvent<{}>, emails: string[]) => {
    setTouched({ ...touched, [name]: true });
    setValue(emails);
    event.persist();
    setFieldValue(name, emails);
  };

  const handleInputChange = (
    event: React.ChangeEvent<{}>,
    newInputValue: string
  ) => {
    const options = newInputValue.split(/[ ,]+/);
    const fieldValue = value
      .concat(options)
      .map(x => x.trim())
      .filter(x => x);

    if (options.length > 1) {
      handleChange(event, fieldValue);
    } else {
      setInputValue(newInputValue);
    }
  };

  const handleKeyDown = (event: React.KeyboardEvent) => {
    switch (event.key) {
      case "Tab": {
        if (inputValue.length > 0) {
          handleChange(event, value.concat([inputValue]));
        }
        break;
      }
      default:
    }
  };
  return (
    <Autocomplete<string>
      multiple
      disableClearable={true}
      options={[]}
      freeSolo
      renderTags={(emails, getTagProps) =>
        emails.map((email, index) => (
          <Chip
            deleteIcon={<CloseIcon />}
            variant="default"
            label={email}
            color={isEmailValid(email) ? "primary" : "secondary"}
            {...getTagProps({ index })}
          />
        ))
      }
      value={value}
      inputValue={inputValue}
      onChange={handleChange}
      onInputChange={handleInputChange}
      renderInput={params => {
        params.inputProps.onKeyDown = handleKeyDown;
        return (
          <TextField
            {...params}
            name={name}
            error={touched[name] && Boolean(errors.emails)}
            helperText={touched[name] && errors.emails}
            variant="outlined"
            {...props}
          />
        );
      }}
    />
  );
};

export default EmailsField;

Edit Autocomplete

Related answer: Автозаполнение пользовательского интерфейса материала: можно ли создавать теги для событий, помимо событий Enter?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...